LangGraph AI Agent编排框架:从零构建智能工作流实战指南
在实际 AI 应用开发中,单个大语言模型(LLM)往往难以独立完成复杂任务。真正的挑战在于如何将多个 LLM、工具调用、状态管理和条件判断串联成一个稳定、可控的智能工作流。LangGraph 正是为解决这类问题而生的 AI Agent 编排框架,它基于有向图结构,让开发者能够以代码方式定义和管理复杂的多步骤推理流程。
本文将以零基础视角,从 LangGraph 的核心概念入手,逐步搭建一个可运行的智能体(Agent),并深入讲解其状态管理、节点编排、条件路由等关键机制。无论你是希望了解 AI Agent 开发基础,还是需要在生产环境中部署可靠的多步推理系统,都能通过本文获得可复现的实践路径。
1. LangGraph 核心概念:为什么需要图编排
在传统 LangChain 中,Chain 提供了线性的任务串联能力,但对于需要循环、分支或动态调整流程的场景,Chain 的表达能力就显得不足。例如,一个客服 Agent 可能需要先理解用户意图,然后根据意图决定调用知识库检索、转人工或直接回答,甚至在某些条件下需要多次追问用户以澄清需求。这类场景正是 LangGraph 的设计目标。
LangGraph 将工作流抽象为有向图(Directed Graph),图中包含两种核心元素:节点(Node)和边(Edge)。节点代表一个执行单元(如调用 LLM、运行工具),边定义了节点之间的流转条件。通过这种模型,可以直观地描述多步、循环、条件判断等复杂逻辑。
与 LangChain 的主要区别在于:
- LangChain 更适合线性、确定性的管道(Pipeline),例如文档加载 -> 分割 -> 向量化 -> 检索 -> 生成回答。
- LangGraph 专为非线性、有状态、多代理(Multi-Agent)协作的工作流设计,例如模拟辩论、游戏对战、复杂决策等场景。
下面通过一个最小示例快速建立直观理解。假设我们要构建一个简易的对话 Agent,它根据用户输入决定直接回答或调用搜索工具:
from langgraph.graph import Graph
from langchain_core.messages import HumanMessage, AIMessage
# 定义两个节点:一个负责生成回答,一个负责调用搜索
def generate_response(state):
return {"messages": [AIMessage(content="这是直接回答的内容")]}
def search_tool(state):
return {"messages": [AIMessage(content="这是搜索后的结果")]}
# 创建图结构
graph = Graph()
graph.add_node("generate", generate_response)
graph.add_node("search", search_tool)
graph.set_entry_point("generate")
# 定义条件路由:如果用户输入包含"搜索"则跳转到搜索节点
def route_condition(state):
last_message = state["messages"][-1]
if "搜索" in last_message.content:
return "search"
return "generate"
graph.add_conditional_edges("generate", route_condition, {"search": "search", "generate": "generate"})
graph.add_edge("search", "generate")
graph.set_finish_point("generate")
# 编译并运行
app = graph.compile()
result = app.invoke({"messages": [HumanMessage(content="我想搜索天气预报")]})
这个示例虽然简单,但已经包含了图编排的核心要素。接下来我们将从环境准备开始,逐步构建一个功能完整的 AI Agent。
2. 环境准备与依赖配置
LangGraph 目前主要支持 Python 环境。建议使用 Python 3.8 或更高版本,以避免兼容性问题。
2.1 创建虚拟环境
使用虚拟环境可以隔离项目依赖,避免版本冲突:
# 创建项目目录
mkdir langgraph-agent-tutorial
cd langgraph-agent-tutorial
# 创建虚拟环境(可选,但强烈推荐)
python -m venv venv
# 激活虚拟环境
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activate
2.2 安装核心依赖
LangGraph 的安装包根据功能需求有所区分。基础版包含图编排核心功能,完整版则额外集成 LangChain 生态工具:
# 安装 LangGraph 基础版
pip install langgraph
# 如果需要使用 LangChain 工具集,安装完整版
pip install "langgraph[all]"
# 常用辅助库
pip install python-dotenv # 环境变量管理
2.3 配置大模型访问权限
LangGraph 本身不提供 LLM,需要接入第三方模型服务。以下以 OpenAI 和 Ollama(本地部署)为例:
OpenAI API 配置 :
- 获取 API Key:访问 OpenAI Platform 创建 API Key。
- 在项目根目录创建
.env文件:
# .env 文件内容
OPENAI_API_KEY=你的实际API密钥
- 在代码中加载配置:
from dotenv import load_dotenv
import os
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
Ollama 本地模型配置 :
如果你希望使用本地部署的模型,可以安装 Ollama:
# 安装 Ollama(参考 https://ollama.ai/)
curl -fsSL https://ollama.ai/install.sh | sh
# 拉取常用模型(如 Llama 3.1)
ollama pull llama3.1
# 验证模型运行
ollama run llama3.1
2.4 验证环境
创建一个简单的验证脚本,确保所有组件正常工作:
# test_environment.py
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
# 测试 OpenAI 连接
llm = ChatOpenAI(model="gpt-3.5-turbo", api_key=os.getenv("OPENAI_API_KEY"))
response = llm.invoke("请用一句话回答:LangGraph 的主要作用是什么?")
print("OpenAI 连接测试:", response.content)
# 测试 LangGraph 导入
from langgraph.graph import Graph
print("LangGraph 导入成功")
运行此脚本应能正常输出模型回答和导入成功信息。如果遇到 API 连接错误,请检查网络环境、API Key 配置和余额状态。
3. 构建第一个 LangGraph Agent:对话助手
现在我们将构建一个具备工具调用能力的对话助手。这个 Agent 能够根据用户问题决定是否需要查询网络信息,并组织最终回答。
3.1 定义状态结构
LangGraph 使用状态(State)对象在节点间传递数据。我们首先定义状态的结构:
from typing import Dict, Any, List, Annotated
import operator
from langchain_core.messages import BaseMessage, HumanMessage
from langgraph.graph import StateGraph, END
# 定义状态类型
class AgentState(TypedDict):
messages: Annotated[List[BaseMessage], operator.add] # 自动累加消息
needs_search: bool # 是否需要搜索
search_result: str # 搜索结果
这里使用了 Annotated 和 operator.add 来自动处理消息列表的追加操作,避免手动合并。
3.2 创建工具节点
工具节点负责执行具体操作,如调用搜索引擎、查询数据库等。以下模拟一个搜索工具:
import requests
def search_web(query: str) -> str:
"""模拟网络搜索功能"""
# 实际项目中可替换为真实搜索引擎 API
print(f"执行搜索: {query}")
# 这里返回模拟结果
return f"关于'{query}'的搜索结果:当前天气晴,温度25℃"
def tool_node(state: AgentState) -> Dict[str, Any]:
"""工具调用节点"""
last_message = state["messages"][-1]
# 提取搜索关键词(实际项目可用LLM提取)
search_query = last_message.content
# 执行搜索
result = search_web(search_query)
return {
"messages": [HumanMessage(content=f"搜索结果: {result}")],
"search_result": result
}
3.3 创建LLM决策节点
这个节点负责分析用户输入,决定下一步行动:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
# 初始化LLM
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
def llm_decision_node(state: AgentState) -> Dict[str, Any]:
"""LLM决策节点:判断是否需要搜索"""
# 构建决策提示词
prompt = ChatPromptTemplate.from_messages([
("system", """你是一个助手,需要判断用户问题是否需要实时信息。
如果问题涉及实时数据、最新事件或需要最新信息,回答"需要搜索"。
如果问题是一般性、常识性或不需要最新信息,回答"直接回答"。
只返回"需要搜索"或"直接回答",不要额外解释。"""),
("human", "{question}")
])
last_message = state["messages"][-1]
chain = prompt | llm
decision = chain.invoke({"question": last_message.content})
needs_search = "需要搜索" in decision.content
return {"needs_search": needs_search}
3.4 创建回答生成节点
基于决策结果和可用信息生成最终回答:
def response_node(state: AgentState) -> Dict[str, Any]:
"""回答生成节点"""
messages = state["messages"]
has_search_result = state.get("search_result")
if has_search_result:
# 结合搜索结果生成回答
prompt = ChatPromptTemplate.from_messages([
("system", "请根据以下搜索结果和对话历史回答用户问题。"),
*messages[:-1],
("human", f"搜索结果: {has_search_result}\n用户问题: {messages[-1].content}")
])
else:
# 直接基于对话历史回答
prompt = ChatPromptTemplate.from_messages([
("system", "请直接回答用户问题。"),
*messages
])
chain = prompt | llm
response = chain.invoke({})
return {"messages": [response]}
3.5 构建图工作流
将各个节点连接成完整的工作流:
def create_agent_workflow() -> StateGraph:
"""创建Agent工作流"""
# 创建图构建器
workflow = StateGraph(AgentState)
# 添加节点
workflow.add_node("llm_decision", llm_decision_node)
workflow.add_node("tool_call", tool_node)
workflow.add_node("generate_response", response_node)
# 设置入口点
workflow.set_entry_point("llm_decision")
# 定义条件路由
def route_after_decision(state: AgentState) -> str:
if state.get("needs_search"):
return "tool_call"
return "generate_response"
workflow.add_conditional_edges(
"llm_decision",
route_after_decision,
{
"tool_call": "tool_call",
"generate_response": "generate_response"
}
)
# 连接边
workflow.add_edge("tool_call", "generate_response")
workflow.add_edge("generate_response", END)
return workflow.compile()
# 编译Agent
agent = create_agent_workflow()
3.6 测试运行
现在可以测试这个完整的 Agent:
# 测试不需要搜索的问题
result1 = agent.invoke({
"messages": [HumanMessage(content="Python是什么编程语言?")]
})
print("测试1 - 一般问题:")
print(result1["messages"][-1].content)
# 测试需要搜索的问题
result2 = agent.invoke({
"messages": [HumanMessage(content="今天北京的天气怎么样?")]
})
print("\n测试2 - 需要实时信息的问题:")
print(result2["messages"][-1].content)
这个基础 Agent 已经具备了决策、工具调用和回答生成的完整能力。在实际项目中,你可以根据需要扩展更多工具和决策逻辑。
4. 高级特性:状态管理、持久化与多Agent协作
4.1 深入理解状态管理
LangGraph 的状态管理是其核心优势之一。上面的示例使用了简单的字典状态,但在复杂场景中可能需要更精细的控制。
自定义状态更新器 :
from typing import Sequence
def update_messages(existing: Sequence[BaseMessage], new: Sequence[BaseMessage]) -> Sequence[BaseMessage]:
"""自定义消息更新逻辑"""
# 过滤掉系统消息,只保留用户和AI消息
filtered_existing = [msg for msg in existing if msg.type in ["human", "ai"]]
return [*filtered_existing, *new]
class AdvancedAgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], update_messages]
conversation_id: str
turn_count: int
user_intent: str
状态检查点 :
def should_create_checkpoint(state: AdvancedAgentState) -> bool:
"""决定何时创建状态检查点"""
return state["turn_count"] % 5 == 0 # 每5轮对话创建检查点
4.2 工作流持久化
对于长时间运行或需要恢复的 Agent,持久化是必备功能:
import pickle
from datetime import datetime
def save_workflow_state(agent, state: dict, filepath: str):
"""保存工作流状态"""
checkpoint = {
"timestamp": datetime.now().isoformat(),
"state": state,
"agent_config": agent.get_graph().to_json()
}
with open(filepath, 'wb') as f:
pickle.dump(checkpoint, f)
def load_workflow_state(filepath: str) -> dict:
"""加载工作流状态"""
with open(filepath, 'rb') as f:
checkpoint = pickle.load(f)
return checkpoint["state"]
# 使用示例
current_state = agent.get_state() # 获取当前状态
save_workflow_state(agent, current_state, "checkpoint.pkl")
# 恢复状态
loaded_state = load_workflow_state("checkpoint.pkl")
agent.invoke(loaded_state) # 从检查点继续执行
4.3 多Agent协作系统
LangGraph 真正强大的地方在于构建多Agent系统。以下是一个简单的双Agent协作示例:
class MultiAgentState(TypedDict):
messages: Annotated[List[BaseMessage], operator.add]
current_agent: str # 当前活跃的Agent
specialist_type: str # 专家类型
def create_specialist_agent(role: str, expertise: str):
"""创建专业Agent"""
def specialist_node(state: MultiAgentState):
prompt = ChatPromptTemplate.from_messages([
("system", f"你是{role},擅长{expertise}。请基于你的专业知识回答问题。"),
*state["messages"]
])
response = (prompt | llm).invoke({})
return {"messages": [response]}
return specialist_node
def coordinator_agent(state: MultiAgentState):
"""协调员Agent:决定由哪个专家处理"""
question = state["messages"][-1].content
prompt = ChatPromptTemplate.from_messages([
("system", """根据用户问题判断需要哪个领域的专家:
- 如果涉及技术、编程,选择"技术专家"
- 如果涉及商业、市场,选择"商业专家"
- 如果是通用问题,选择"通用助手"
只返回专家类型。"""),
("human", question)
])
decision = (prompt | llm).invoke({})
specialist_type = decision.content.strip()
return {
"current_agent": specialist_type,
"specialist_type": specialist_type
}
# 构建多Agent工作流
def create_multi_agent_system():
workflow = StateGraph(MultiAgentState)
# 添加节点
workflow.add_node("coordinator", coordinator_agent)
workflow.add_node("tech_specialist", create_specialist_agent("技术专家", "编程、算法、系统设计"))
workflow.add_node("business_specialist", create_specialist_agent("商业专家", "市场分析、商业模式、战略规划"))
workflow.add_node("general_assistant", create_specialist_agent("通用助手", "日常问题解答"))
workflow.set_entry_point("coordinator")
# 动态路由到不同专家
def route_to_specialist(state: MultiAgentState):
specialist_type = state["specialist_type"]
return {
"技术专家": "tech_specialist",
"商业专家": "business_specialist",
"通用助手": "general_assistant"
}.get(specialist_type, "general_assistant")
workflow.add_conditional_edges(
"coordinator",
route_to_specialist,
{
"tech_specialist": "tech_specialist",
"business_specialist": "business_specialist",
"general_assistant": "general_assistant"
}
)
workflow.add_edge("tech_specialist", END)
workflow.add_edge("business_specialist", END)
workflow.add_edge("general_assistant", END)
return workflow.compile()
multi_agent = create_multi_agent_system()
这种架构允许构建复杂的专家系统,每个 Agent 专注于特定领域,由协调员动态分配任务。
5. 生产环境部署与优化建议
5.1 性能优化策略
异步执行 :
import asyncio
async def process_concurrent_requests(requests: List[str], agent):
"""并发处理多个请求"""
tasks = [agent.ainvoke({"messages": [HumanMessage(content=req)]}) for req in requests]
results = await asyncio.gather(*tasks)
return results
# 使用示例
async def main():
requests = ["问题1", "问题2", "问题3"]
results = await process_concurrent_requests(requests, agent)
for result in results:
print(result["messages"][-1].content)
# asyncio.run(main())
缓存机制 :
from functools import lru_cache
from langchain.cache import InMemoryCache
from langchain.globals import set_llm_cache
# 启用LLM缓存
set_llm_cache(InMemoryCache())
# 自定义工具结果缓存
@lru_cache(maxsize=100)
def cached_search_web(query: str) -> str:
return search_web(query)
5.2 监控与日志
完善的监控是生产系统的生命线:
import logging
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('agent_operations.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger("langgraph_agent")
def instrumented_node(node_func):
"""为节点添加监控装饰器"""
def wrapper(state: dict):
start_time = datetime.now()
logger.info(f"开始执行节点: {node_func.__name__}")
try:
result = node_func(state)
duration = (datetime.now() - start_time).total_seconds()
logger.info(f"节点执行成功: {node_func.__name__}, 耗时: {duration:.2f}s")
return result
except Exception as e:
logger.error(f"节点执行失败: {node_func.__name__}, 错误: {str(e)}")
raise
return wrapper
# 使用监控装饰器
@instrumented_node
def monitored_decision_node(state: AgentState):
return llm_decision_node(state)
5.3 错误处理与重试机制
节点级错误处理 :
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
def robust_llm_call(prompt):
"""带重试的LLM调用"""
return llm.invoke(prompt)
def error_handling_node(state: AgentState):
"""具备错误处理能力的节点"""
try:
return llm_decision_node(state)
except Exception as e:
logger.error(f"决策节点失败: {e}")
# 返回降级响应
return {
"messages": [AIMessage(content="系统暂时繁忙,请稍后重试")],
"needs_search": False
}
5.4 安全与权限控制
输入验证 :
import re
def validate_user_input(message: str) -> bool:
"""验证用户输入安全性"""
# 检查长度
if len(message) > 1000:
return False
# 检查潜在危险模式
dangerous_patterns = [
r"系统命令.*执行",
r"文件.*删除",
r"数据库.*清空"
]
for pattern in dangerous_patterns:
if re.search(pattern, message, re.IGNORECASE):
return False
return True
def safe_invoke(agent, user_input: str):
"""安全的Agent调用封装"""
if not validate_user_input(user_input):
return {"messages": [AIMessage(content="输入内容不符合安全要求")]}
return agent.invoke({"messages": [HumanMessage(content=user_input)]})
6. 常见问题排查与调试技巧
6.1 典型错误场景及解决方案
| 问题现象 | 可能原因 | 检查点 | 解决方案 |
|---|---|---|---|
| 图编译失败 | 节点未正确定义或连接 | 检查节点名称拼写、边连接顺序 | 使用 graph.get_graph().print_ascii() 可视化图结构 |
| 状态更新异常 | 状态注解类型不匹配 | 验证 Annotated 注解的正确性 |
确保使用 operator.add 或自定义更新函数 |
| LLM调用超时 | API密钥错误、网络问题 | 检查API密钥、网络连接 | 配置超时参数、添加重试机制 |
| 工具调用失败 | 工具函数参数不匹配 | 验证工具输入输出格式 | 添加类型注解和参数验证 |
| 内存使用过高 | 状态累积过大 | 监控状态对象大小 | 定期清理历史消息、实现检查点机制 |
6.2 调试工具与技术
可视化工作流 :
def visualize_workflow(agent):
"""生成工作流可视化"""
graph = agent.get_graph()
# 打印ASCII图示
print("工作流结构:")
graph.print_ascii()
# 生成Mermaid图(需支持的环境)
try:
mermaid_code = graph.get_graph().draw_mermaid()
print("\nMermaid 图代码:")
print(mermaid_code)
except:
print("Mermaid 可视化不可用")
# 使用示例
visualize_workflow(agent)
状态检查工具 :
def debug_state_transition(initial_state, agent, max_steps=10):
"""逐步调试状态转换"""
current_state = initial_state
step = 0
while step < max_steps:
print(f"\n--- 步骤 {step} ---")
print("当前状态:", {k: v for k, v in current_state.items() if k != 'messages'})
print("最新消息:", current_state['messages'][-1].content if current_state['messages'] else "无")
try:
next_state = agent.invoke(current_state)
if next_state == current_state:
print("状态稳定,可能到达终点")
break
current_state = next_state
step += 1
except Exception as e:
print(f"执行错误: {e}")
break
return current_state
6.3 性能分析工具
import cProfile
import pstats
from io import StringIO
def profile_agent_performance(agent, test_input, output_file='profile_results.txt'):
"""分析Agent性能瓶颈"""
profiler = cProfile.Profile()
def run_agent():
return agent.invoke({"messages": [HumanMessage(content=test_input)]})
profiler.enable()
result = run_agent()
profiler.disable()
# 保存分析结果
s = StringIO()
ps = pstats.Stats(profiler, stream=s).sort_stats('cumulative')
ps.print_stats()
with open(output_file, 'w') as f:
f.write(s.getvalue())
print(f"性能分析结果已保存到: {output_file}")
return result
7. 扩展学习路径与最佳实践
7.1 渐进式学习路线
-
基础掌握 (1-2周):
- 理解图编排概念
- 掌握状态管理机制
- 构建简单对话Agent
-
中级应用 (2-4周):
- 集成真实工具(API、数据库)
- 实现复杂条件逻辑
- 添加持久化支持
-
高级架构 (1-2月):
- 设计多Agent系统
- 优化性能与可靠性
- 部署生产环境
7.2 项目实践建议
从小开始,迭代开发 :
- 第一版:实现核心工作流,硬编码简单逻辑
- 第二版:添加工具集成,完善错误处理
- 第三版:引入LLM决策,实现动态路由
- 第四版:添加监控、缓存、安全机制
测试策略 :
import pytest
def test_agent_decision_logic():
"""测试Agent决策逻辑"""
agent = create_agent_workflow()
# 测试需要搜索的场景
result = agent.invoke({"messages": [HumanMessage(content="今天天气如何?")]})
assert "搜索" in str(result) or "天气" in str(result)
# 测试直接回答的场景
result = agent.invoke({"messages": [HumanMessage(content="什么是Python?")]})
assert "编程" in str(result) or "语言" in str(result)
def test_error_handling():
"""测试错误处理"""
agent = create_agent_workflow()
# 测试空输入
result = agent.invoke({"messages": [HumanMessage(content="")]})
assert len(result["messages"]) > 0
7.3 生产环境检查清单
在将 LangGraph Agent 部署到生产环境前,确保完成以下检查:
- [ ] 环境变量配置正确(API密钥、数据库连接等)
- [ ] 错误处理机制完备(网络异常、API限制等)
- [ ] 日志系统就绪(操作日志、错误日志、性能日志)
- [ ] 监控告警配置(响应时间、错误率、资源使用)
- [ ] 安全措施到位(输入验证、权限控制、数据脱敏)
- [ ] 性能测试通过(并发能力、内存使用、响应时间)
- [ ] 备份恢复方案(状态持久化、检查点机制)
- [ ] 文档更新完成(API文档、运维手册、故障处理流程)
LangGraph 为复杂 AI Agent 开发提供了强大的编排能力,但真正的挑战在于如何将技术能力转化为稳定可靠的业务价值。建议从具体业务场景出发,先解决一个小而具体的问题,再逐步扩展能力边界。每个成功的 Agent 系统都是通过不断迭代、测试和优化逐步成熟的。
更多推荐


所有评论(0)