
如果你是刚开始接触 Agent 开发大概率遇到过这种场景一段“模型调用工具”的示例代码能跑通但一旦任务变成“先查天气、再查航班、最后形成建议”Agent 就会乱掉或者答案看起来合理却说不清它中间到底调用了几次工具、为什么这么调用。项目标题里的langchain-6-9不用纠结是版本号还是课程目录编号真正值得搞清楚的是LangChain Agent 从接收用户输入到最终返回结果中间到底发生了什么。只有把执行流程拆解清楚你才能真正控制 Agent而不是靠运气调 Prompt。先给一个判断LangChain Agent 的核心不是“给模型加 tool”这个静态动作而是一个循环调度机制。模型每一步只负责“决策”真正执行外部动作的是工具而把这些环节串起来的是一套明确的执行框架。理解并掌控这个循环是后续 Agent 开发、调试、面试和生产落地的基础。文章会从基础概念讲到完整工作流再给一个最小可运行示例最后补充 LangGraph、常见报错排查和工程建议。建议收藏后跟着代码跑一遍。1. 这篇文章真正要解决的问题搜索“langchain agent 执行流程”的人通常不是想知道 Agent 的定义而是遇到了下面这些具体问题为什么我的 Agent 有时候调用工具有时候不调用Agent 和普通的大模型 Function Calling 到底有什么区别一次任务中 Agent 可以调用多少次工具谁来决定停下来agent_scratchpad、intermediate_steps、AgentAction、AgentFinish分别是什么既然已经有了 AgentExecutor为什么社区又在推荐 LangGraph面试官问“Agent 的执行流程”应该怎么回答这些问题背后都指向同一个核心你需要对大模型、工具、执行器三者的协作顺序有确定性理解。这篇文章不打算讲太多 Agent 理论而是直接拆执行链路然后给你一份能跑通的代码再通过代码运行结果反推内部机制。适合以下读者刚学 LangChain想搞懂 Agent 而不是停留在“会调 API”已经在项目里使用 AgentExecutor但遇到迭代次数超限、解析失败、工具参数错误等问题准备 Agent 方向面试需要系统梳理执行流程从传统链路Prompt LLM转向 Agent 开发想建立正确的抽象认知。读完之后你应该能回答三个问题一次 Agent 调用经历了哪些阶段中间状态存储在哪里怎么调整执行过程来规避常见坑。2. 基础概念Agent、Tool、LLM、AgentExecutor2.1 一句大白话理解 AgentAgent 可以理解为“大模型 工具 循环决策”的组合。普通 LLM 调用是“输入文本 - 输出文本”模型没有能力查数据库、调接口、执行代码。LangChain Agent 做的事情是让模型在每一步决定“下一步做什么”如果需要外部信息就调用工具拿到工具结果后再判断是继续调用工具还是整理结果回答用户。所以 Agent 不是单个模型请求而是一连串模型请求和工具调用的循环。2.2 四个核心角色概念作用类比LLM负责理解任务、生成决策是“大脑”项目负责人Tool负责执行具体动作比如查天气、搜索、执行 SQL一线执行员工Agent负责组织 Prompt、解析模型输出、决定调用哪个工具中间协调层AgentExecutor负责驱动“思考 - 行动 - 观察”的循环直到完成项目进度盯办人在实际代码里create_openai_tools_agent会创建一个 AgentAgentExecutor再把这个 Agent 和工具列表组合成可执行对象。很多初学者把 AgentExecutor 误认为“Agent”严格来说它是执行器不是决策器。2.3 它和普通 Function Calling 的区别Function Calling 是模型能力的一种模型可以根据用户问题输出一个函数名和参数比如get_weather(city北京)。但模型只输出一次调用不会自己拿着结果继续推理。Agent 的差异在于模型可以连续多轮输出工具调用每一轮工具结果都会作为文本回填到下一轮 Prompt 中当模型认为信息足够时才输出最终回答。换句话说Recursive 循环 中间状态维护是 Agent 执行流程的关键。3. 核心执行流程拆解从用户输入到最终回答不管用经典的AgentExecutor还是新的LangGraphAgent 的底层流程都遵循下面这个模式3.1 一次完整 Agent 调用的 8 个阶段阶段发生了什么关键数据1. 接收输入用户提交 Queryinput2. 组装 Prompt把 System Prompt、历史对话、用户输入、之前中间步骤组成新 Promptagent_scratchpad3. 模型决策LLM 输出“动作”或“最终答案”AgentAction或AgentFinish4. 输出解析Agent 解析模型返回的文本或结构化输出解析后的 Action5. 工具调用根据 Action 选择并执行工具tool.run(tool_input)6. 生成观察工具返回结果字符串称为 ObservationObservation7. 状态回填把(AgentAction, Observation)追加到中间步骤intermediate_steps8. 循环判断如果是AgentFinish则结束否则回到第 2 步max_iterations输入 - 格式化 Prompt - LLM 决策 - 解析输出 - 调用工具 - 得到 Observation - 追加中间状态 - 继续循环 - 直到 AgentFinish3.2AgentAction和AgentFinish这两个类是整个执行流程的“出口信号”。AgentAction(toolget_weather, tool_input{city: 北京}, log...)表示模型决定调用工具。AgentFinish(return_values{output: 今天晴适合出门}, log...)表示模型认为可以结束直接返回答案。执行器拿到AgentAction就调用工具拿到AgentFinish就退出循环。理解这一点后再看intermediate_steps就很简单了它就是一个(AgentAction, Observation)的列表记录整条决策链。3.3 常见 Agent 范式LangChain 里的 Agent 不只有一种范式。面试和实际开发中常提的有范式思路适合场景ReAct每一轮输出 Thought / Action / Observation需要逐步推理的工具调用OpenAI Tools使用原生 Function Calling 结构化调用依赖 OpenAI、通义、智谱等大模型平台Plan-and-Execute先规划一个多步计划再逐步执行复杂任务、可拆解业务Conversational在 ReAct 基础上增加对话记忆需要多轮聊天 工具大多数 LangChain 入门示例使用的create_openai_tools_agent本质上是“OpenAI Tools 风格 ReAct 循环”的组合。LangChain 中 Agent 可以用不同范式关键是模型能力是否匹配以及工具描述是否足够清晰。4. 环境准备与最小示例下面用一个最小可运行示例把“执行流程”变成可见的日志和中间步骤。4.1 安装依赖pip install langchain langchain-openai python-dotenv如果你的环境还没有配置OPENAI_API_KEY可以通过环境变量或.env文件设置export OPENAI_API_KEY你的_api_key本文使用 OpenAI 兼容接口的ChatOpenAI。如果你使用其他模型平台可以把模型类和地址换成平台对应的 LangChain 集成执行流程思路不变。4.2 编写最小 Agent# 文件路径agent_demo.py import os from dotenv import load_dotenv from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.tools import tool from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_openai import ChatOpenAI load_dotenv() tool def get_weather(city: str) - str: 查询某个城市的天气。参数 city 是城市名例如“北京”。 # 演示用生产环境请接入真实天气服务 return f{city} 当前晴温度 26 度 tools [get_weather] llm ChatOpenAI(modelgpt-4o-mini, temperature0) prompt ChatPromptTemplate.from_messages( [ (system, 你是一个友好的助手。请使用提供的工具回答问题。), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ] ) agent create_openai_tools_agent(llm, tools, prompt) agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, return_intermediate_stepsTrue, max_iterations5, ) if __name__ __main__: result agent_executor.invoke({input: 北京今天适合出门吗需要先查一下天气。}) print(\n 中间步骤 ) for i, (action, observation) in enumerate(result[intermediate_steps], 1): print(f第{i}步工具{action.tool}参数{action.tool_input}观测{observation}) print(\n 最终回答 ) print(result[output])这段代码里有两个关键点agent_scratchpad是模型之前产生的 Action 和 Observation 的载体必须放在 Prompt 中否则执行器无法回填中间状态。return_intermediate_stepsTrue会让我们拿到(AgentAction, Observation)列表这是观察执行流程的直接入口。4.3 运行与验证python agent_demo.py正常执行时verboseTrue会在控制台输出内部决策过程。你可能会看到类似内容 Entering new AgentExecutor chain... Invoking: get_weather with {city: 北京} 北京 当前晴温度 26 度 Finished chain. 中间步骤 第1步工具get_weather参数{city: 北京}观测北京 当前晴温度 26 度 最终回答 北京当前晴天适合出门。这里的“中间步骤”就是 Agent 完整执行链路的直接证据模型先决定调用天气工具拿到观测后再根据观测生成最终回答。如果你的模型没有调用工具直接返回了答案需要先检查工具描述是否清晰、System Prompt 是否要求它使用工具以及模型本身是否支持 Function Calling。5. 通过 intermediate_steps 理解执行流程的细节真实项目里Agent 不会只调用一次工具。一次复杂的任务可能包括搜索资料 - 调用计算器 - 查询数据库 - 汇总答案。intermediate_steps会按执行顺序记录每一步for i, (action, observation) in enumerate(result[intermediate_steps], 1): print(f第{i}步工具{action.tool}) print(f参数{action.tool_input}) print(f模型日志{action.log}) print(f观察结果{observation}) print(---)如果 Agent 第一次调用search第二次调用calculate那么你会在intermediate_steps中看到两条记录。这个列表也是排错的核心依据你可以拿到模型的第一步决策、工具返回、第二步决策全程可回放。这里真正容易踩坑的地方是action.log和observation都可能很长。尤其是在接数据库、读文件、调用外部 API 时工具返回大段文本会迅速占用上下文窗口。后面章节会讲怎么控制。6. LangGraph 与新一代执行流程6.1 为什么 LangChain 社区转向 LangGraphAgentExecutor把执行循环封装成了一个黑盒。它方便但不够灵活。比如你想在“模型决策之后”插入一个人工确认环节或者在工具执行前做权限检查用AgentExecutor很难自然实现。LangGraph 把执行流程显式建模为一张图agent节点负责让模型决策tools节点负责执行工具条件边根据模型输出决定继续调用工具还是结束State保存 messages 和中间状态代替intermediate_steps。因此LangGraph 和 LangChain 的关系不是替代而是编排层升级LangChain 提供模型、提示词、工具集成LangGraph 提供可控的“执行流程编排”。6.2 AgentExecutor 与 LangGraph 执行流对比对比维度经典 AgentExecutorLangGraph 执行流执行逻辑内部循环黑盒显式图结构节点和边清晰中间状态intermediate_steps列表全局State通常是 messages 列表人工介入难可在任意节点之间插入中断多 Agent 编排吃力容易官方建议适合学习和简单业务新项目更推荐从当前官方文档和社区趋势看新项目可以优先考虑 LangGraph但学习AgentExecutor对理解核心执行流程仍然非常有效。6.3 LangGraph 最小示例安装依赖pip install langgraph然后用create_react_agent快速创建一个执行图# 文件路径langgraph_demo.py from dotenv import load_dotenv from langchain.tools import tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent load_dotenv() tool def get_weather(city: str) - str: 查询某个城市的天气。参数 city 是城市名例如“北京”。 return f{city} 当前晴温度 26 度 llm ChatOpenAI(modelgpt-4o-mini, temperature0) app create_react_agent(llm, [get_weather]) result app.invoke({messages: [(user, 北京今天适合出门吗)]}) for message in result[messages]: print(f{message.type}: {message.content})在这个示例里create_react_agent内部构建了一张图result[messages]保存了完整调用链用户消息、模型行动、工具结果、最终回答。它比intermediate_steps更直观因为每一步都作为消息保存在状态里。7. 常见问题与排查思路在实际开发里Agent 跑不起来或者结果不对大多不是模型问题而是执行流程中的某一环出错。问题现象可能原因排查方式解决方案Agent 返回 “provider did not respond in time”模型服务或 Agent 执行服务响应超时看服务方状态页、检查请求日志设置更大的超时时间检查模型服务可用性增加重试报错Could not parse LLM output模型输出不符合 Action 格式打开verboseTrue查看原始输出改用 Function Calling 类 Agent或优化输出解析器达到最大迭代次数后停止任务太复杂或工具没有提供足够信息检查intermediate_steps是否在重复同一工具增加max_iterations优化工具描述让工具返回更结构化工具参数乱码或缺少字段工具函数签名不明确模型猜错了参数打印模型输出的tool_input给工具函数写清楚 docstring尽量使用 pydantic 定义入参结构Observation 太长导致上下文爆炸工具返回大段文本或日志查看工具返回内容长度在工具内部截断、聚合、只返回关键信息和摘要模型不调用工具直接回答Prompt 没有强调使用工具或工具列表太多看模型输出是否直接是答案System Prompt 中明确要求减少无用工具给工具加示例工具执行报错但没有被捕获工具内部抛异常执行器中断查看工具日志在工具内部捕获异常并返回错误字符串而不是直接抛出这里特别想强调一个认知Agent 的“下一步”不是代码写死的而是模型根据当前状态生成的。所以排查时不要只盯着模型要检查工具返回的 Observation 是否能让模型做正确判断。如果工具返回“查询失败”模型很可能继续重试同一个工具直到迭代上限。8. 最佳实践与工程建议8.1 工具设计决定执行上限工具是 Agent 感知外部世界的窗口。工具描述写得越清晰模型越不会用错。工具名必须动词开头例如search_news、get_user_orderdocstring 要写清楚参数含义和返回值样例工具返回值尽量精简返回结构化文本或 JSON工具内部要做异常兜底避免让模型看到异常堆栈。# 不推荐 def tool_a(s: str) - str: return query(s) # 推荐 tool def get_user_order(user_id: str) - str: 根据用户 ID 查询最近一笔订单。 参数 user_id 是用户唯一标识例如 U12345。 返回 JSON 字符串{order_id: ..., status: ...} try: data query_order(user_id) return json.dumps(data, ensure_asciiFalse) except Exception as exc: return f查询失败{exc}8.2 限制迭代避免失控成本生产环境一定要设置max_iterations防止模型陷入死循环或疯狂调用工具。对于 AgentExecutorAgentExecutor( agentagent, toolstools, max_iterations5, early_stopping_methodgenerate, )对于 LangGraph可以通过recursion_limit控制app.invoke( {messages: [(user, 帮我分析这个日志)]}, config{recursion_limit: 10}, )同时建议给工具调用加计数器或日志。如果某个用户在短时间内触发大量工具调用需要监测是否有异常请求。8.3 日志与可观测性不要只依赖最终答案判断 Agent 是否正确。建议至少记录用户原始输入intermediate_steps或 LangGraph 的messages每次工具调用的耗时和返回长度模型 token 消耗是否达到迭代上限。这些日志既是排查依据也是后续评估 Prompt 和工具质量的数据来源。8.4 安全边界与最小权限如果你的 Agent 可以操作数据库、删除文件、发消息必须遵守最小权限原则。不要用高权限账号执行 Agent 工具涉及删除、写入等危险操作增加人工审批节点工具入参要做校验和过滤生产环境变更前必须先备份并确保有回滚方案。尤其在使用 LangGraph 时可以通过 “human-in-the-loop” 在工具执行前暂停图让用户确认后再继续。这是 AgentExecutor 不太好做、LangGraph 天生适合做的事情。8.5 记忆与上下文控制Agent 的记忆不应该无限增长。对话历史、中间步骤、工具返回值都会占用上下文。工程上更推荐使用 LangGraph 的Checkpointer持久化消息对历史消息做滑动窗口截断对工具 Observation 做摘要避免把大日志、大文件全文塞给模型。一句话总结上下文长度是 Agent 的稀缺资源不要让工具返回垃圾占据窗口。9. 总结与应用建议这篇内容真正想讲清楚的是 LangChain Agent 的执行流程模型负责决策工具负责执行执行器负责循环每一步的决策和观察都会作为下一轮的输入直到模型输出AgentFinish。从实践角度看建议你按这个顺序往下推进先跑通上面的最小示例打开verboseTrue观察每一轮输出给 Agent 加第二个工具让它在一次任务中连续调用多个工具感受intermediate_steps的变化改造一版 LangGraph 示例把执行图显式画出来加深理解再学习 Agent 记忆、RAG 接入、MCP 工具协议、Skill 封装和多 Agent 编排。Agent 开发走到后面拼的并不是谁能把 Prompt 写得更漂亮而是谁能把“模型决策 工具执行 状态管理 安全边界”这套循环控制得更稳。先把执行流程看透后面学 LangGraph、MCP、多 Agent 都会轻松很多。如果你正在准备面试建议把“从输入到输出经历了哪些阶段”和“中间状态存在哪里”这两个问题作为主线讲清楚基本就能覆盖大多数 Agent 执行流程的问题。