ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LangGraph实战指南:从零构建具备ReAct循环的多功能AI智能体

2026/8/6 5:06:02 拓冰建站 浏览量
LangGraph实战指南:从零构建具备ReAct循环的多功能AI智能体 在实际项目中当我们需要构建一个能够处理复杂决策流程、管理状态并协调多个工具或LLM调用的AI应用时简单的链式调用往往捉襟见肘。LangGraph应运而生它基于LangChain但引入了图Graph的概念将应用流程建模为状态机特别适合构建具备循环、分支和持久化能力的智能体Agent。与传统的线性链相比LangGraph让你能清晰地定义智能体的“思考-行动-观察”循环处理多轮对话甚至构建包含多个子智能体的复杂系统。本文面向有一定Python和LangChain基础的开发者旨在提供一个从零开始的LangGraph实战指南。我们将首先厘清LangGraph的核心概念然后通过一个完整的智能体项目带你完成环境搭建、图定义、状态管理、工具集成到最终部署验证的全过程。你将学会如何构建一个能够理解用户意图、自主选择工具并执行任务的智能体并掌握生产环境中常见的配置、调试与优化技巧。1. 理解LangGraph从链到图的智能体范式演进在深入代码之前必须理解LangGraph解决的核心问题及其与LangChain的关系。这决定了你是否能正确使用它而非仅仅套用模板。1.1 LangChain与LangGraph的定位差异LangChain是一个用于开发由语言模型驱动的应用程序的框架它提供了大量的组件如模型I/O、检索、记忆和标准接口并通过“链”Chain将这些组件串联起来执行任务。链通常是线性的或具有简单分支。然而许多复杂的AI应用特别是智能体其行为更像一个有状态的工作流。例如一个智能体可能需要接收用户问题 - 决定调用搜索工具 - 解析搜索结果 - 根据结果决定是回答用户还是继续搜索。这个过程包含循环、条件判断和状态维护用传统的链式结构描述会非常笨拙且难以维护。LangGraph就是为了弥补这一缺口而生。它建立在LangChain之上允许开发者将应用流程定义为一个图Graph。图中的节点代表一个执行单元如调用LLM、运行工具边代表执行路径。最关键的是它引入了状态State的概念在整个图执行过程中一个共享的状态对象会在节点间传递和修改这完美契合了智能体需要记忆历史、管理上下文的需求。简单来说LangChain提供了构建AI应用所需的“砖块”模型、工具、记忆等和粘合剂链。LangGraph提供了设计并运行复杂“蓝图”有状态、可循环、可分支的工作流的能力特别擅长构建智能体。1.2 LangGraph的核心三要素State、Node、Edge理解这三个概念是构建任何LangGraph应用的基础。1. 状态State状态是一个类似字典Dict的对象它包含了工作流执行过程中需要传递和更新的所有数据。你可以把它想象成智能体的“工作记忆”。通常我们会用一个TypedDict或Pydantic模型来定义状态的模式Schema确保类型安全。 一个典型的智能体状态可能包含from typing import TypedDict, List, Annotated import operator class AgentState(TypedDict): # 用户输入的问题 input: str # 智能体生成的思考、决策或工具调用 agent_outcome: dict # 工具执行后返回的结果列表 tool_outputs: List[str] # 对话历史记录 chat_history: List[str]在LangGraph中状态是不可变的。每个节点接收当前状态并返回一个包含要更新字段的字典。框架会自动将这些更新应用到新状态上。2. 节点Node节点是图中的一个执行步骤它是一个函数。这个函数接收当前状态作为唯一参数并返回一个字典指明要更新状态的哪些部分。 节点可以执行任何操作调用LLM、运行工具、进行条件判断、操作数据等。def call_llm(state: AgentState): # 从状态中获取输入和历史 messages construct_messages(state[“input”], state[“chat_history”]) # 调用LLM response llm.invoke(messages) # 返回要更新的状态部分 return {“agent_outcome”: response.content}3. 边Edge边定义了节点之间的流转逻辑。它决定了在一个节点执行完毕后接下来应该执行哪个节点。边可以是条件边Conditional Edge根据当前状态的值如LLM的输出是“Final Answer”还是“Tool Call”决定下一个节点。固定边始终指向下一个节点。通过组合节点和边你就定义了一个可能包含循环例如从“行动”节点回到“思考”节点和分支的决策流程图。1.3 智能体的通用工作流ReAct模式LangGraph非常适合实现经典的智能体框架如ReActReason Act。一个基础的ReAct智能体工作流在图中的体现通常是代理节点Agent Node接收状态包含用户问题和历史调用LLM。LLM被提示去“思考”并决定下一步是直接回答还是调用某个工具。其输出包含思考和工具调用请求被写入状态。工具调用判断边检查agent_outcome。如果LLM决定调用工具则流向“工具节点”如果决定最终回答则流向“结束节点”。工具节点Tool Node解析LLM输出的工具调用参数执行对应的工具函数如搜索、计算、查询数据库将结果写入状态如tool_outputs。循环边从工具节点返回到代理节点将工具执行结果作为新的上下文让LLM进行下一轮“思考”。结束节点当LLM给出最终答案时流程结束将答案返回给用户。这个循环过程正是智能体“自主”完成任务的核心而LangGraph让这一过程的代码表达变得异常清晰。2. 环境准备与项目初始化我们将构建一个具备网络搜索和计算能力的多功能智能体。首先确保你的开发环境就绪。2.1 环境与依赖配置建议使用Python 3.10或更高版本。创建一个新的虚拟环境是良好的实践。# 创建并激活虚拟环境以conda为例 conda create -n langgraph-agent python3.10 conda activate langgraph-agent # 使用pip安装核心依赖 pip install langgraph langchain langchain-openailanggraph: 核心框架。langchain: 提供基础组件LLM、工具、提示模板等。langchain-openai: 使用OpenAI模型的官方集成包。重要版本说明LangGraph和LangChain生态迭代较快依赖冲突是常见问题。如果遇到ImportError请尝试固定核心库版本。# 一个相对稳定的版本组合示例请根据实际情况调整 pip install “langgraph0.0.52” “langchain0.1.0” “langchain-openai0.0.5”你还需要一个LLM的API密钥。本文以OpenAI GPT模型为例。请将你的API密钥设置为环境变量。# 在Linux/macOS的终端中 export OPENAI_API_KEY“your-api-key-here” # 在Windows的PowerShell中 $env:OPENAI_API_KEY“your-api-key-here”注意永远不要将API密钥硬编码在代码中提交到版本控制系统。使用环境变量或安全的密钥管理服务。2.2 项目结构规划一个清晰的目录结构有助于管理复杂的智能体项目。建议如下your_agent_project/ ├── agents/ # 存放不同智能体的图定义 │ ├── __init__.py │ └── reakt_agent.py # 我们的主智能体 ├── tools/ # 自定义工具集 │ ├── __init__.py │ ├── calculator.py │ └── web_search.py ├── schemas/ # 状态和数据的Pydantic/TypedDict模型 │ └── state.py ├── prompts/ # 提示词模板 │ └── agent_prompt.py ├── config.py # 配置文件API密钥、模型选择等 ├── main.py # 应用入口用于测试和运行 └── requirements.txt # 项目依赖现在在项目根目录下创建requirements.txt文件并写入核心依赖langgraph0.0.50 langchain0.1.0 langchain-openai0.0.5 python-dotenv1.0.0 # 用于加载.env文件3. 构建一个多功能ReAct智能体我们将按照“定义状态 - 创建工具 - 构建提示 - 实现节点 - 组装成图”的顺序一步步构建智能体。3.1 定义智能体状态State Schema在schemas/state.py中我们定义智能体工作流的状态结构。使用TypedDict和Annotated来自langgraph.graph来声明哪些字段应由图形自动归约reduce。# schemas/state.py from typing import TypedDict, List, Annotated, Union from langchain_core.messages import BaseMessage import operator class AgentState(TypedDict): 智能体工作流的状态定义。 # 用户的最新输入 messages: Annotated[List[BaseMessage], operator.add] # 智能体的“思考”过程或最终答案字符串 agent_thoughts: str # 工具执行的结果列表 tool_outputs: Annotated[List[str], operator.add] # 一个标志位指示是否应该继续执行 should_continue: bool关键解释messages: 这是一个消息列表包含用户输入、AI回复和工具执行结果。Annotated[List[BaseMessage], operator.add]是LangGraph的魔法所在。它告诉框架当多个节点返回对messages字段的更新时不要替换而是使用operator.add即列表的操作来合并它们。这确保了对话历史的累积。agent_thoughts: 存储LLM每一步的“思考”内容便于调试和观察智能体推理过程。tool_outputs: 存储每次工具调用的结果同样使用归约操作进行累积。should_continue: 一个布尔标志控制工作流是否应该继续循环。当LLM给出最终答案时我们将其设为False。3.2 创建自定义工具Tools工具是智能体与外界交互的“手”和“脚”。在tools/目录下创建两个简单工具。1. 计算器工具 (tools/calculator.py)# tools/calculator.py from langchain.tools import tool import math tool def calculator(expression: str) - str: 执行一个数学表达式计算。支持 , -, *, /, **, sqrt等。 例如calculator(“(3 5) * 2”) 返回 16。 try: # 警告在生产环境中直接eval有安全风险此处仅用于演示。 # 应考虑使用更安全的表达式解析库如 ast.literal_eval 或 numexpr。 result eval(expression, {“__builtins__”: None}, {“math”: math}) return f”计算结果: {result}” except Exception as e: return f”计算错误: {e}”2. 网络搜索工具 (tools/web_search.py)为了演示我们使用一个模拟的搜索工具。在实际项目中你可以集成Serper API、Tavily Search或Google Custom Search API。# tools/web_search.py from langchain.tools import tool import random import time tool def web_search(query: str) - str: 执行一次网络搜索。输入是一个搜索查询字符串。 # 模拟网络延迟 time.sleep(0.5) # 模拟返回一些搜索结果 mock_results [ f”关于{query}的最新文章指出该技术正在快速发展。”, f”根据百科{query}是一种重要的方法论。”, f”论坛讨论显示用户对{query}的看法褒贬不一。” ] return f”搜索 ‘{query}’ 的结果\n” “\n”.join(mock_results[:2]) # 返回前两条安全警告calculator工具中的eval()函数在生产环境中是极度危险的因为它允许执行任意代码。这里仅用于概念演示。真实场景必须使用安全的数学表达式解析库如ast.literal_eval处理简单字面量或numexpr、sympy等并对输入进行严格的验证和清理。3.3 构建智能体提示词Prompt提示词是智能体的“大脑”指导LLM如何思考、决策和格式化输出。在prompts/agent_prompt.py中定义。# prompts/agent_prompt.py from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder # 系统提示定义智能体的角色和能力 SYSTEM_PROMPT “””你是一个乐于助人的AI助手可以调用工具来帮助用户解决问题。 你可以使用的工具有 - web_search: 当用户询问需要最新或外部知识的问题时使用。 - calculator: 当用户提出数学计算问题时使用。 请严格按以下格式回应 **Thought思考**: 你需要先思考用户的问题并决定是否需要使用工具以及使用哪个工具。 **Action行动**: 如果你决定使用工具请输出 Action: tool_name并在下一行提供 Action Input: tool_input。工具输入必须是字符串。 **Final Answer最终答案**: 如果你有足够信息回答用户或者用户问题不需要工具请输出 Final Answer: 你的回答。 记住Action 和 Final Answer 只能二选一。 “”” # 构建提示模板。MessagesPlaceholder 用于动态插入对话历史messages AGENT_PROMPT ChatPromptTemplate.from_messages([ (“system”, SYSTEM_PROMPT), MessagesPlaceholder(variable_name“messages”), # 这里将注入状态中的 messages (“human”, “{input}”), # 用户的最新输入也可以通过状态传递 ])这个提示模板的关键在于它预留了messages的位置这使我们能够将完整的对话历史包含之前的工具调用和结果传递给LLM实现多轮交互和上下文感知。3.4 实现图节点与边逻辑现在在agents/react_agent.py中组装智能体的核心逻辑。第一步导入与初始化# agents/react_agent.py from typing import Literal from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, END from langgraph.prebuilt import ToolExecutor, ToolInvocation import json # 导入之前定义的模块 from schemas.state import AgentState from prompts.agent_prompt import AGENT_PROMPT from tools.calculator import calculator from tools.web_search import web_search # 1. 初始化LLM llm ChatOpenAI(model“gpt-3.5-turbo”, temperature0) # 使用gpt-3.5-turbo温度设为0使输出更确定 # 2. 绑定工具到LLM tools [calculator, web_search] llm_with_tools llm.bind_tools(tools) # 3. 创建工具执行器 tool_executor ToolExecutor(tools)第二步定义代理节点Agent Node这个节点负责调用LLM让LLM根据当前状态历史对话和最新输入进行思考并决定下一步。def agent_node(state: AgentState): 调用LLM获取其思考、行动或最终答案。 # 1. 构建输入给提示模板的数据。我们需要从状态中提取最新的用户消息。 # 假设最后一条消息是用户输入。 last_message state[“messages”][-1] if isinstance(last_message, dict) and ‘input’ in last_message: user_input last_message[‘input’] else: # 或者从消息内容中提取 user_input last_message.content if hasattr(last_message, ‘content’) else str(last_message) # 2. 调用提示模板和LLM prompt_input {“messages”: state[“messages”], “input”: user_input} messages AGENT_PROMPT.invoke(prompt_input) response llm_with_tools.invoke(messages) # 3. 将LLM的响应作为新的AI消息添加到历史中 new_messages state[“messages”] [response] # 4. 解析响应判断是工具调用还是最终答案 # 检查响应中是否有工具调用 if response.tool_calls: # LLM决定调用工具 tool_name response.tool_calls[0][‘name’] tool_input response.tool_calls[0][‘args’] agent_thoughts f”Agent decides to use tool: {tool_name} with input {tool_input}” should_continue True else: # LLM给出了最终答案 agent_thoughts f”Agent gives final answer: {response.content}” should_continue False # 5. 返回状态更新 return { “messages”: new_messages, # 更新消息历史 “agent_thoughts”: agent_thoughts, # 记录思考过程 “should_continue”: should_continue # 更新继续标志 }第三步定义工具节点Tool Node这个节点执行代理节点所请求的工具调用并将结果格式化后存入状态。def tool_node(state: AgentState): 执行代理节点请求的工具调用。 # 1. 从最新的AI消息中获取工具调用信息 last_message state[“messages”][-1] if not hasattr(last_message, ‘tool_calls’) or not last_message.tool_calls: # 如果没有工具调用直接返回 return {“tool_outputs”: [“No tool to execute.”]} # 2. 遍历所有工具调用通常一次一个 tool_outputs [] for tool_call in last_message.tool_calls: # 构建工具调用对象 action ToolInvocation( tooltool_call[‘name’], tool_inputtool_call[‘args’] ) # 3. 执行工具 output tool_executor.invoke(action) tool_outputs.append(str(output)) # 将结果转为字符串存储 # 4. 将工具执行结果也构造为一个消息添加到历史中供下一轮LLM参考 # 这是一个简化处理LangGraph有更优雅的方式如使用ToolMessage result_message f”Tool execution results: {‘; ‘.join(tool_outputs)}” # 5. 返回状态更新 return { “tool_outputs”: tool_outputs, # 累积工具输出 “messages”: state[“messages”] [{“role”: “tool”, “content”: result_message}] # 添加工具结果消息 }第四步定义路由逻辑Conditional Edge这是一个关键函数它检查should_continue标志决定图是继续循环调用工具还是结束。def should_continue(state: AgentState) - Literal[“tools”, “__end__”]: 根据状态决定下一个节点。 if state.get(“should_continue”, True): return “tools” # 继续执行工具节点 else: return END # 结束图执行3.5 组装成图并编译将节点和边连接起来形成一个完整的工作流图。# 1. 创建状态图指定状态模式 workflow StateGraph(AgentState) # 2. 添加节点 workflow.add_node(“agent”, agent_node) # “代理”节点 workflow.add_node(“tools”, tool_node) # “工具”节点 # 3. 设置入口点 workflow.set_entry_point(“agent”) # 4. 添加边 # 从“agent”节点出来根据should_continue函数的返回值决定去向 workflow.add_conditional_edges( “agent”, should_continue, # 路由判断函数 { “tools”: “tools”, # 如果返回”tools”则前往”tools”节点 END: END # 如果返回”__end__”则结束 } ) # 从“tools”节点出来固定返回“agent”节点形成“思考-行动”循环 workflow.add_edge(“tools”, “agent”) # 5. 编译图得到可执行对象 app workflow.compile()至此一个具备ReAct循环的多功能智能体图就构建完成了。app对象就是我们的智能体它可以被调用并传入初始状态。4. 运行、验证与调试让我们编写一个主程序来测试这个智能体并观察其内部状态流转。4.1 创建测试入口在项目根目录创建main.py。# main.py import asyncio from langchain_core.messages import HumanMessage from agents.reakt_agent import app # 导入我们编译好的图应用 from schemas.state import AgentState async def run_agent(query: str): 运行智能体并打印其执行步骤。 print(f”\n 用户查询: {query} “) # 1. 构建初始状态 initial_state: AgentState { “messages”: [HumanMessage(contentquery)], # 初始消息是用户输入 “agent_thoughts”: “”, “tool_outputs”: [], “should_continue”: True, } # 2. 以流式事件的方式运行图方便观察每一步 async for event in app.astream_events(initial_state, version“v1”): kind event[“event”] node event.get(“name”, “N/A”) if kind “on_chain_start” and node “agent”: print(f”\n[Agent Node] 开始思考...”) elif kind “on_chain_end” and node “agent”: thoughts event[“data”][“output”].get(“agent_thoughts”, “”) print(f”[Agent Node] 思考完成: {thoughts}”) elif kind “on_chain_start” and node “tools”: print(f”[Tool Node] 开始执行工具...”) elif kind “on_chain_end” and node “tools”: outputs event[“data”][“output”].get(“tool_outputs”, []) print(f”[Tool Node] 工具执行结果: {outputs}”) elif kind “on_graph_end”: final_state event[“data”][“output”] final_message final_state[“messages”][-1] if hasattr(final_message, ‘content’): answer final_message.content else: answer str(final_message) print(f”\n 最终答案 \n{answer}”) if __name__ “__main__”: # 测试不同场景 test_queries [ “计算一下 (15 27) * 3 等于多少”, “搜索一下最近关于大语言模型发展的新闻。”, “你好请介绍一下你自己。” # 不需要工具的问题 ] for query in test_queries: asyncio.run(run_agent(query))4.2 执行与结果分析运行python main.py你应该能看到类似以下的输出清晰地展示了智能体的内部决策过程 用户查询: 计算一下 (15 27) * 3 等于多少 [Agent Node] 开始思考... [Agent Node] 思考完成: Agent decides to use tool: calculator with input {expression: (15 27) * 3} [Tool Node] 开始执行工具... [Tool Node] 工具执行结果: [计算结果: 126] [Agent Node] 开始思考... [Agent Node] 思考完成: Agent gives final answer: Final Answer: (15 27) * 3 的计算结果是 126。 最终答案 Final Answer: (15 27) * 3 的计算结果是 126。 用户查询: 搜索一下最近关于大语言模型发展的新闻。 [Agent Node] 开始思考... [Agent Node] 思考完成: Agent decides to use tool: web_search with input {query: 大语言模型 发展 最新新闻} [Tool Node] 开始执行工具... [Tool Node] 工具执行结果: [搜索 大语言模型 发展 最新新闻 的结果\n关于大语言模型 发展 最新新闻的最新文章指出该技术正在快速发展。\n根据百科大语言模型 发展 最新新闻是一种重要的方法论。] [Agent Node] 开始思考... [Agent Node] 思考完成: Agent gives final answer: Final Answer: 根据搜索大语言模型技术目前正处于快速发展阶段相关的最新文章和讨论很多... 最终答案 Final Answer: 根据搜索大语言模型技术目前正处于快速发展阶段...通过输出你可以看到智能体完整的“思考-行动-观察-再思考”的循环。对于计算问题它调用一次工具后得到答案对于搜索问题它调用工具获取信息后合成最终答案对于简单问候它直接给出最终答案不调用工具。4.3 状态可视化与调试LangGraph提供了强大的可视化功能对于理解复杂工作流至关重要。在main.py中添加# 在main.py中添加 from IPython.display import Image, display # 注意此方法通常在Jupyter Notebook中效果最佳 try: # 将图结构导出为PNG图片 image_data app.get_graph().draw_mermaid_png() with open(“agent_workflow.png”, “wb”) as f: f.write(image_data) print(“工作流图已保存为 ‘agent_workflow.png’。”) except Exception as e: print(f”无法生成图片请确保已安装 pygraphviz 或 mermaid CLI: {e}”) # 打印文本表示 print(app.get_graph().draw_ascii())生成的图会清晰显示agent和tools两个节点以及它们之间的条件边和循环边直观呈现了ReAct模式。5. 生产环境进阶配置与常见问题排查将智能体从演示环境推向生产需要考虑更多因素。5.1 配置管理、日志与监控1. 集中化配置创建config.py或使用.env文件管理所有配置。# config.py import os from dotenv import load_dotenv load_dotenv() # 从 .env 文件加载环境变量 class Config: OPENAI_API_KEY os.getenv(“OPENAI_API_KEY”) OPENAI_BASE_URL os.getenv(“OPENAI_BASE_URL”, “https://api.openai.com/v1”) # 支持代理 LLM_MODEL os.getenv(“LLM_MODEL”, “gpt-3.5-turbo”) LLM_TEMPERATURE float(os.getenv(“LLM_TEMPERATURE”, “0”)) # 其他配置如工具API密钥、数据库连接等在代码中从Config类读取配置。2. 结构化日志使用logging模块记录智能体的关键决策、工具调用和错误。import logging logging.basicConfig(levellogging.INFO, format‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’) logger logging.getLogger(__name__) # 在agent_node和tool_node中关键位置添加日志 logger.info(f”Agent decided to call tool: {tool_name}”) logger.error(f”Tool execution failed: {e}”, exc_infoTrue)3. 性能与成本监控Token消耗使用LangChain的CallbackHandler如LangChainTracer或直接解析LLM响应中的usage字段监控每次调用的token数。执行时间记录每个节点尤其是LLM调用和网络工具的执行耗时。循环次数监控should_continue的循环次数防止因LLM逻辑错误导致无限循环。可以设置最大循环次数在状态中添加iteration字段并在每次循环时递增达到阈值后强制结束。5.2 常见问题与排查路径以下是构建LangGraph智能体时最常见的几个“坑”及其解决方案。问题现象可能原因检查与排查步骤解决方案智能体陷入无限循环1. LLM始终输出工具调用指令不输出Final Answer。2. 路由逻辑should_continue判断有误。1. 打印每一轮agent_thoughts观察LLM输出。2. 检查提示词是否清晰定义了Final Answer的格式。3. 检查should_continue函数是否正确解析了LLM输出。1. 优化提示词强化“何时停止”的指令。2. 在状态中增加iteration计数器达到上限如10次后强制返回END。3. 使用更强大的模型如GPT-4可能决策更准确。工具调用格式错误1. LLM输出的工具调用参数不符合工具函数签名。2.bind_tools未正确绑定或工具描述不清。1. 查看response.tool_calls的内容检查name和args。2. 确认工具函数的参数名和类型是否清晰。1. 在工具函数的docstring中提供极其清晰的示例。2. 使用Pydantic模型定义工具输入LLM绑定后格式更规范。3. 在提示词中提供工具调用的精确示例。状态更新不符合预期1. 状态字段的归约操作Annotated使用错误。2. 节点返回的更新字典键名与状态定义不匹配。1. 在关键节点打印输入和输出的状态。2. 检查TypedDict定义和节点返回值类型。1. 确保列表类型字段如messages使用了operator.add进行归约。2. 使用Pydantic的BaseModel代替TypedDict可以利用其验证功能。3. 仔细核对节点返回字典的键。图编译或执行报错1. 节点函数签名不正确必须接收state并返回dict。2. 图中存在未连接的节点或循环依赖。1. 阅读完整的错误堆栈信息。2. 使用app.get_graph().draw_ascii()检查图结构。1. 确保所有节点函数都接受一个参数状态。2. 确保每个节点都有入边和出边起始节点和结束节点除外。3. 检查add_conditional_edges和add_edge的节点名称拼写。LLM响应慢或超时1. 网络问题或API限流。2. 提示词过长导致处理时间增加。1. 检查网络连接和API状态。2. 监控单次请求的token数量。1. 配置合理的超时时间如ChatOpenAI(request_timeout30)。2. 对长对话历史进行摘要或截断减少上下文长度。3. 考虑使用流式响应stream改善用户体验。5.3 安全与最佳实践工具输入验证与清理永远不要信任来自LLM的输入直接用于敏感操作如数据库查询、系统命令。在工具函数内部进行严格的参数验证、类型转换和输入清理。对于计算器使用安全的数学库。权限控制为智能体设定明确的权限边界。哪些工具可以调用哪些数据可以访问应有明确的配置。审计日志记录所有用户输入、LLM决策、工具调用及结果用于追溯、分析和模型改进。设置超时与中断为整个图执行或单个LLM调用设置超时防止长时间挂起。提供用户可中断的机制。版本化与回滚将提示词、图定义、工具集进行版本控制。任何变更都应先经过测试并准备好快速回滚方案。使用检查点Checkpoint实现持久化LangGraph支持检查点可以将执行中的状态持久化到数据库实现长时运行工作流的暂停与恢复。这对于处理耗时任务至关重要。6. 扩展方向从单智能体到复杂系统掌握了基础智能体构建后你可以探索更强大的模式多智能体协作创建多个具有不同专长的智能体如“研究员”、“写手”、“评审员”让它们通过共享状态或消息队列进行协作。这可以通过创建多个子图并在一个主图中协调它们来实现。集成长期记忆将状态中的chat_history或关键信息持久化到向量数据库如Chroma, Pinecone或传统数据库中使智能体在多次会话中记住用户偏好和历史。集成外部知识库RAG在agent_node之前添加一个“检索”节点从你的私有文档库中检索相关信息并将其作为上下文注入到提示词中让智能体基于专属知识回答问题。子图Subgraph封装复杂逻辑将一组相关的节点和边封装成一个子图作为更高层级图的一个节点。这有助于管理复杂度实现模块化。人工介入Human-in-the-loop在图的某些边设置条件当置信度低或涉及关键决策时流转到一个“等待人工审核”节点待人工输入后再继续执行。构建智能体的过程是一个持续迭代和优化的过程。从定义一个清晰的状态开始逐步添加可靠的工具精心设计提示词并通过可视化和日志密切观察其决策流程你就能打造出真正强大、可控且有用的AI智能体应用。