最近在AI应用开发领域,一个由前OpenAI核心成员打造的新平台“Energy”引起了广泛关注。对于开发者而言,这不仅仅是一个新闻事件,更是一个值得深入探究的技术风向标。它预示着AI Agent(智能体)正从概念走向规模化、工程化的落地阶段。本文将从一个技术实践者的角度,深入剖析AI工作平台的核心架构、开发范式,并基于现有技术栈(如LangChain、Spring AI等),手把手带你构建一个具备“Energy”平台部分核心思想的简易AI工作流系统。无论你是想了解下一代AI应用形态,还是希望将AI Agent集成到自己的业务中,这篇文章都将提供从理论到代码的完整路径。
1. AI工作平台“Energy”的背景与核心理念
在讨论具体技术之前,我们有必要理解“Energy”这类平台出现的必然性。当前的AI开发,尤其是基于大语言模型(LLM)的应用开发,普遍面临几个痛点:
- 碎片化工具链 :数据预处理、提示工程、模型调用、记忆管理、工具调用等步骤往往需要组合多个库和自定义代码。
- 状态管理复杂 :AI Agent通常需要维护对话历史、执行状态、知识库上下文,管理这些状态并保证其一致性是个挑战。
- 协作与流程化困难 :单个提示词或简单链式调用难以应对复杂业务逻辑,需要将多个AI能力或人工节点编排成可重复、可监控的工作流。
- 生产环境部署门槛高 :如何将实验阶段的AI应用,转化为稳定、可扩展、易监控的生产级服务。
“Energy”平台的核心目标,正是为了解决这些工程化难题。它并非只是一个提供AI模型的API服务,而是一个 集成化的AI智能体开发与运行环境 。其核心理念可以概括为: 将AI能力封装成可编排、可复用、具备状态感知和工具使用能力的“工作单元”(Worker),并通过可视化的流程引擎将这些单元连接起来,共同完成复杂任务。
这类似于将传统的微服务架构思想引入AI领域。每个工作单元可以是一个LLM调用、一个代码执行器、一个数据库查询工具,甚至是一个人工审核节点。平台负责工作流的调度、状态传递、异常处理和结果持久化。
2. 技术选型与环境准备
要模拟构建一个类似的AI工作平台,我们需要选择合适的技术栈。这里我们将以Python生态为主,因为它拥有最丰富的AI和机器学习库。
核心组件与版本说明:
- 编程语言 : Python 3.9+
- AI应用框架 : LangChain 0.1.x。它是目前最流行的用于开发由LLM驱动的应用程序的框架,提供了链(Chains)、代理(Agents)、工具(Tools)等高级抽象。
-
流程编排
: 我们可以使用LangChain自身的
LangGraph库或Prefect。LangGraph更专注于基于LLM的状态机工作流,而Prefect是一个通用的工作流编排引擎。本文为贴近AI场景,选用LangGraph。 - LLM服务 : 使用OpenAI API(或兼容OpenAI API的本地模型,如通过Ollama部署的Qwen)。我们将演示如何配置。
-
向量数据库
(可选): 用于为AI Agent提供长期记忆和知识库检索能力,例如
Chroma或Weaviate。 -
Web框架
(可选): 如果需要提供HTTP API,可以使用
FastAPI。
环境搭建步骤:
-
创建并激活虚拟环境 (推荐):
python -m venv ai_platform_env source ai_platform_env/bin/activate # Linux/macOS # ai_platform_env\Scripts\activate # Windows -
安装核心依赖 : 创建一个
requirements.txt文件,内容如下:langchain==0.1.0 langchain-openai==0.0.5 langgraph==0.0.15 openai==1.12.0 python-dotenv==1.0.0 # 可选:向量数据库和Web框架 # chromadb==0.4.22 # fastapi==0.104.1 # uvicorn==0.24.0执行安装:
pip install -r requirements.txt -
配置API密钥 : 创建
.env文件来安全存储密钥, 切记不要将此类文件提交到版本控制系统 。# .env OPENAI_API_KEY=你的OpenAI_API密钥 # 如果你使用其他兼容API,如Ollama # OPENAI_API_BASE=http://localhost:11434/v1 # OPENAI_API_KEY=ollama # 可任意填写,非空即可
3. 核心概念拆解:从LangChain到AI工作流
在开始编码前,需要理解几个关键概念,它们是我们构建平台的基石。
3.1 工具(Tools)
工具是AI Agent与外界交互的扩展。一个工具本质上是一个函数,AI可以通过自然语言描述来调用它。例如:
-
search_web(query): 执行网络搜索。 -
execute_sql(sql_query): 在数据库上执行SQL。 -
send_email(to, subject, body): 发送邮件。
在LangChain中,我们可以用
@tool
装饰器轻松地将一个Python函数转化为AI可用的工具。
3.2 代理(Agents)
代理是一个具备推理能力的AI系统。它接收用户输入,决定需要调用哪些工具、以什么顺序调用,并综合所有工具的结果来生成最终回答。核心是“思考-行动-观察”的循环。
3.3 图(Graph)与状态(State)
这是
LangGraph
引入的核心概念。一个工作流被建模为一个有向图(Graph),节点(Nodes)代表执行步骤(如调用LLM、运行工具),边(Edges)代表控制流(根据上一步结果决定下一步去哪)。整个图的执行由一个共享的
State
对象驱动,它包含了所有节点需要读写的数据。
这种模型完美契合了“Energy”平台中可视化编排工作流的理念。我们可以将复杂的业务逻辑,画成一个流程图,然后用代码实现它。
4. 实战:构建一个简易的AI数据分析工作流
假设我们要构建一个工作流,其功能是: 用户用自然语言提出一个数据分析需求,AI自动编写Python代码来执行分析,运行代码,检查结果,并最终生成一个总结报告。
这个工作流包含多个“工作单元”:需求理解、代码生成、代码执行、结果验证、报告生成。让我们用
LangGraph
来实现它。
4.1 定义共享状态(State)
首先,我们需要定义在整个工作流中传递的数据结构。
# graph_state.py
from typing import TypedDict, Annotated, List, Union
import operator
from langchain_core.messages import AnyMessage
class GraphState(TypedDict):
"""
定义工作流的共享状态。
"""
# 用户原始输入的问题
question: str
# 存放对话消息历史
messages: Annotated[List[AnyMessage], operator.add]
# 由AI生成的Python代码
generated_code: str
# 代码执行后的输出(包括错误)
code_output: str
# 最终给用户的答案
final_answer: str
Annotated[List[AnyMessage], operator.add]
是一个高级用法,它告诉LangGraph,当多个节点修改
messages
字段时,应该用
+
操作符(即列表拼接)来合并更新,而不是覆盖。这非常适合维护对话历史。
4.2 创建工具(Tools)
我们需要一个安全的代码执行工具。 注意:在生产环境中,执行任意代码是极高风险操作,必须使用沙箱环境(如Docker容器、安全沙箱)进行严格隔离。 此处为演示,使用一个简单的受限执行器。
# tools.py
import langchain
from langchain.tools import tool
import subprocess
import sys
import os
@tool
def execute_python_code(code: str) -> str:
"""
在一个受限的子进程中执行一段Python代码,并返回其标准输出和错误。
警告:此示例仅用于演示,缺乏安全隔离。生产环境必须使用沙箱。
"""
try:
# 这里可以添加代码安全检查(如禁止导入某些模块)
# 例如,禁止访问网络、文件系统等(简化示例,未实现)
# if "import os" in code and "remove" in code:
# return "Error: Potentially dangerous operation detected."
# 使用subprocess在独立进程中运行代码,并设置超时
result = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True,
timeout=30, # 设置超时防止无限循环
cwd=os.path.dirname(__file__) # 指定工作目录
)
output = result.stdout
if result.stderr:
output += f"\n[Stderr]: {result.stderr}"
if result.returncode != 0:
output = f"[Process exited with code {result.returncode}]\n" + output
return output.strip() or "Code executed successfully (no output)."
except subprocess.TimeoutExpired:
return "Error: Code execution timed out (possible infinite loop)."
except Exception as e:
return f"Error during execution setup: {str(e)}"
4.3 构建工作流节点(Nodes)
我们将工作流分解为以下几个节点:
- 理解需求节点 :分析用户问题,明确需要分析的数据和期望的输出。
- 生成代码节点 :根据理解的需求,编写执行数据分析的Python代码(例如使用pandas)。
-
执行代码节点
:调用
execute_python_code工具运行生成的代码。 - 验证结果节点 :检查代码执行结果是否有错误,是否需要重试或修正。
- 生成报告节点 :基于成功的分析结果,生成一份给用户的自然语言总结。
# nodes.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from .graph_state import GraphState
from .tools import execute_python_code
import json
llm = ChatOpenAI(model="gpt-4-turbo-preview", temperature=0) # 使用更具推理能力的模型
def understand_requirement(state: GraphState):
"""节点1:理解用户的数据分析需求。"""
print("--- [节点] 理解需求 ---")
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个数据分析专家。请分析用户的问题,明确以下信息:1. 需要分析的数据是什么?(例如:一个包含销售记录的CSV文件) 2. 用户想得到什么分析结果?(例如:月度销售额趋势、Top 10产品) 如果问题中数据不明确,请进行合理假设并说明。你的输出应为纯JSON格式:{\"data_description\": \"...\", \"analysis_goal\": \"...\", \"assumptions\": \"...\"}"),
("human", "{question}")
])
chain = prompt | llm
response = chain.invoke({"question": state["question"]})
try:
analysis_plan = json.loads(response.content)
except json.JSONDecodeError:
analysis_plan = {"data_description": "未知", "analysis_goal": state["question"], "assumptions": "无法解析AI回复"}
# 将分析计划添加到消息历史中,供后续节点使用
new_message = {"role": "assistant", "content": f"需求分析结果:{analysis_plan}"}
state["messages"].append(new_message)
return state
def generate_code(state: GraphState):
"""节点2:根据分析计划生成Python代码。"""
print("--- [节点] 生成代码 ---")
# 从消息历史中提取最新的分析计划(简化处理)
last_msg = state["messages"][-1]["content"] if state["messages"] else ""
prompt = ChatPromptTemplate.from_messages([
("system", """你是一名优秀的Python数据分析工程师。请根据需求分析,生成可直接执行的Python代码。
要求:
1. 使用pandas进行数据处理(假设数据文件为`./sample_data/sales.csv`,包含`date`, `product`, `quantity`, `revenue`字段)。
2. 代码必须包含必要的导入(如`import pandas as pd`)。
3. 代码的目标是:{analysis_goal}。
4. 将最终的分析结果打印(print)出来,或计算关键指标。
5. 代码必须完整、可独立运行。
6. 如果需求不涉及绘图,则不要生成绘图代码。
只输出代码块,不要任何解释。"""),
("human", f"需求分析:{last_msg}\n请生成代码。")
])
chain = prompt | llm
response = chain.invoke({"analysis_goal": "实现用户所请求的数据分析"}) # 这里可以更精细地传递目标
generated_code = response.content.strip().strip("```python").strip("```").strip()
state["generated_code"] = generated_code
print(f"生成的代码:\n{generated_code[:200]}...") # 打印前200字符预览
return state
def execute_code(state: GraphState):
"""节点3:执行生成的代码。"""
print("--- [节点] 执行代码 ---")
code = state.get("generated_code", "")
if not code:
state["code_output"] = "错误:未生成可执行的代码。"
return state
output = execute_python_code.invoke(code)
state["code_output"] = output
print(f"代码执行输出:\n{output[:500]}...") # 打印前500字符预览
return state
def validate_and_decide(state: GraphState):
"""节点4:验证代码执行结果,并决定下一步。"""
print("--- [节点] 验证与决策 ---")
output = state["code_output"]
# 简单的验证逻辑:如果输出包含“Error”或“Traceback”,则认为执行失败
if "Error" in output or "Traceback" in output:
print("检测到执行错误,需要重新生成代码。")
# 返回的下一个节点名称是“generate_code”
return {"next_node": "generate_code", **state}
else:
print("代码执行成功,准备生成报告。")
# 返回的下一个节点名称是“generate_report”
return {"next_node": "generate_report", **state}
def generate_report(state: GraphState):
"""节点5:基于成功的结果,生成最终报告。"""
print("--- [节点] 生成最终报告 ---")
question = state["question"]
code_output = state["code_output"]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个数据分析报告撰写者。根据用户的原始问题、成功执行的代码及其输出,生成一份简洁、清晰、面向业务人员的分析报告。报告应总结关键发现,并直接回答用户的问题。"),
("human", f"用户原始问题:{question}\n\n代码执行输出:\n{code_output}\n\n请生成分析报告:")
])
chain = prompt | llm
response = chain.invoke({})
state["final_answer"] = response.content
return state
4.4 编排工作流图(Graph)
现在,我们将上述节点连接起来,定义执行路径。
# workflow_graph.py
from langgraph.graph import StateGraph, END
from .graph_state import GraphState
from .nodes import understand_requirement, generate_code, execute_code, validate_and_decide, generate_report
def build_workflow_graph():
"""构建并返回AI数据分析工作流图。"""
workflow = StateGraph(GraphState)
# 1. 添加节点
workflow.add_node("understand", understand_requirement)
workflow.add_node("generate_code", generate_code)
workflow.add_node("execute_code", execute_code)
workflow.add_node("validate", validate_and_decide)
workflow.add_node("generate_report", generate_report)
# 2. 设置入口点
workflow.set_entry_point("understand")
# 3. 添加边(定义流程)
workflow.add_edge("understand", "generate_code")
workflow.add_edge("generate_code", "execute_code")
workflow.add_edge("execute_code", "validate")
# 4. 添加条件边(根据验证结果决定流向)
# validate_and_decide 节点会返回一个包含 `next_node` 键的字典。
workflow.add_conditional_edges(
"validate",
# 这是一个路由函数,它接收节点的输出(即state),并返回下一个节点的名称。
lambda state: state.get("next_node", END),
{
"generate_code": "generate_code", # 如果需要重试,跳回生成代码节点
"generate_report": "generate_report", # 如果成功,跳转到报告节点
END: END # 也可以直接结束
}
)
workflow.add_edge("generate_report", END)
# 5. 编译图
return workflow.compile()
# 创建图实例
graph = build_workflow_graph()
4.5 运行与验证
最后,我们编写一个主程序来运行这个工作流。
# main.py
import asyncio
from workflow_graph import graph
from graph_state import GraphState
async def main():
# 模拟用户输入
user_question = "帮我分析一下上个季度的销售额趋势,并找出最畅销的三个产品。"
# 初始化状态
initial_state: GraphState = {
"question": user_question,
"messages": [], # 初始消息历史为空
"generated_code": "",
"code_output": "",
"final_answer": "",
}
print("开始执行AI数据分析工作流...")
print(f"用户问题:{user_question}")
print("-" * 50)
# 异步执行图
final_state = await graph.ainvoke(initial_state)
print("\n" + "="*50)
print("工作流执行完毕!")
print("="*50)
print(f"\n最终生成的代码:\n{final_state['generated_code']}")
print(f"\n代码执行结果:\n{final_state['code_output']}")
print(f"\n最终给用户的报告:\n{final_state['final_answer']}")
if __name__ == "__main__":
asyncio.run(main())
运行结果示例:
执行
python main.py
后,你将在控制台看到各个节点的执行日志,并最终得到生成的Python代码、代码执行输出(需要你准备一个示例的
sales.csv
文件)以及一份自然语言分析报告。
5. 常见问题与排查思路
在构建和运行此类AI工作流时,你可能会遇到以下问题:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
ModuleNotFoundError: No module named 'langchain'
| 依赖未正确安装或虚拟环境未激活。 |
1. 确认已激活虚拟环境。
2. 运行
pip install -r requirements.txt
。
|
openai.AuthenticationError
| API密钥错误或未设置。 |
1. 检查
.env
文件中的
OPENAI_API_KEY
。
2. 确保在代码中正确加载了环境变量(使用
dotenv.load_dotenv()
)。
|
| 工作流卡在某个节点无响应 | LLM API调用超时或网络问题;代码执行陷入死循环。 |
1. 为LLM调用和工具执行添加超时(timeout)机制。
2. 检查
execute_python_code
工具中的超时设置。
3. 增加日志,打印每个节点的输入输出。 |
| 生成的代码无法执行 | LLM生成的代码语法错误或依赖不存在的库(如未安装pandas)。 |
1. 在系统提示词中明确要求使用基础库或指定已安装的库。
2. 在
execute_python_code
工具中捕获更详细的错误信息。
3. 实现一个“代码修正”节点,让AI根据错误信息重新生成代码。 |
| 图的状态更新不符合预期 |
对
State
的修改方式有误,特别是
Annotated
字段。
|
1. 确保在节点函数中,是通过返回新的字典或修改后字典来更新state。
2. 对于
messages
这类列表,使用
operator.add
注解确保追加而非覆盖。
|
| 流程逻辑出现死循环 |
条件边(
conditional_edges
)的路由逻辑有误,导致在两个节点间无限循环。
|
1. 在
validate_and_decide
节点中,确保在重试次数过多后能跳出循环(例如,在state中添加
retry_count
字段)。
2. 仔细检查路由函数返回的节点名称是否与
add_conditional_edges
中定义的映射匹配。
|
6. 最佳实践与工程化建议
将上述演示项目升级为一个真正的“AI工作平台”,需要考虑以下工程化最佳实践:
-
安全性至上 :
- 代码沙箱 :绝对不要在宿主服务器上直接执行AI生成的代码。必须使用Docker容器、gVisor、Firecracker等强隔离沙箱,并严格限制资源(CPU、内存、网络、文件系统)。
- 输入输出过滤 :对用户输入和AI输出进行严格的过滤和清洗,防止注入攻击。
- 权限控制 :为不同的工具(如数据库访问、邮件发送)定义最小权限原则。
-
可观测性与调试 :
- 全链路日志 :记录每个工作流实例的完整执行轨迹,包括每个节点的输入、输出、耗时和错误信息。这对于调试复杂逻辑至关重要。
- 可视化监控 :提供仪表盘,实时监控工作流的执行状态、成功率、平均耗时等指标。
- 版本管理 :对工作流定义(图结构)、提示词模板、工具实现进行版本控制,便于回滚和协作。
-
弹性与可靠性 :
- 重试与降级 :为LLM API调用和外部工具调用设计重试机制(如指数退避)。对于非核心节点,设计降级策略。
- 异步与队列 :将工作流执行任务放入消息队列(如RabbitMQ, Redis Queue),避免HTTP请求阻塞,并实现负载均衡。
-
状态持久化
:将工作流的
State持久化到数据库(如PostgreSQL, Redis),支持长时间运行的工作流和故障恢复。
-
提示词工程与管理 :
- 模板化与参数化 :将提示词从代码中分离,存储为模板文件或数据库记录,支持动态变量注入。
- A/B测试 :建立机制,对不同版本的提示词或工作流进行效果对比测试。
- 敏感信息脱敏 :确保提示词模板中不包含API密钥、内部IP等敏感信息。
-
架构设计 :
- 微服务化 :将工作流引擎、工具服务、模型网关、监控服务等拆分为独立的微服务,提高可维护性和可扩展性。
- 插件化工具系统 :设计一套标准的工具接口(如OpenAI Function Calling格式),允许开发者轻松地注册新的工具,平台动态加载。
- 前端可视化编辑器 :提供Web界面,允许用户通过拖拽方式设计和配置工作流,而无需编写代码。这是“Energy”类平台的核心价值之一。
通过遵循这些实践,你可以构建出一个健壮、安全、易用的AI工作平台原型,从而将大语言模型的强大能力,高效、可控地融入到复杂的业务流程中去。这不仅是技术上的整合,更是对软件开发范式的一次升级。

354


被折叠的 条评论
为什么被折叠?



