序言:如果你还在用if-else判断用户意图,然后手动调用不同API,这篇文章能让你少写一半代码。
一、从"流水线工人"到"项目经理"
上个月,我帮朋友做了一个智能助手Demo。需求听起来很普通:用户问天气,就调天气API;用户问数学题,就调计算器;用户问新闻,就调搜索引擎。
我一开始用Chain的思路写。代码大概长这样:
python
if "天气" in user_input:
result = weather_api(user_input)
elif "计算" in user_input or "等于" in user_input:
result = calculator(user_input)
elif "新闻" in user_input:
result = search_engine(user_input)
else:
result = llm.chat(user_input)
写了三天,覆盖了大概二十种意图。第四天,用户问了一句:"帮我查一下明天北京气温,然后算一下华氏度是多少。"
我当场傻眼。
这句话包含两个任务:先查天气,再算温度转换。而且用户没明确说"查天气",而是说"查一下气温"------我的if-else匹配不到。更麻烦的是,查完天气后的结果要传给计算器,两个工具之间需要数据传递。
那一刻我突然意识到:Chain的思路在这里行不通了。
Chain是什么?Chain是流水线。你设计好步骤A→B→C,输入进去,按固定顺序执行,输出结果。它像工厂里的流水线工人,每个工位只做一件事,但流程是死的,不会变。
Agent是什么?Agent是项目经理。你给它一个目标,它自己分析需要哪些资源、按什么顺序调用、中间结果怎么处理。它像一个人类助理,收到"帮我订一张明天去上海的机票,要早班机,然后帮我查一下上海明天的天气",自己会拆解任务、调用工具、整合结果。
Chain是人推流程,Agent是AI推流程。 这个区别,决定了它们各自适合什么场景。
二、ReAct:Agent的"思考-行动-观察"循环
Agent之所以能自主决策,背后依赖的是一个叫ReAct的框架。ReAct是Reasoning(推理)和Acting(行动)的缩写,它的核心逻辑可以用一个循环概括:
Thought → Action → Observation → Thought → Action → Observation → ... → Final Answer

这个循环听起来抽象,但拆解一下就很清晰。
Thought:模型在"想什么"
当Agent收到用户的问题,它不会直接回答,而是先输出一段"内心独白"------也就是Thought。这段Thought是模型对自己当前处境的分析。
比如用户问:"明天北京气温多少华氏度?"
模型的Thought可能是:"用户想知道北京明天的气温,并且要以华氏度为单位。我需要先查询北京明天的气温(摄氏度),然后再把摄氏度转换成华氏度。第一步,调用天气API获取北京明天的气温。"
Thought的价值在于:它把模型的推理过程外化了。 你不需要写if-else,模型自己判断该做什么。
Action:模型决定"做什么"
想清楚之后,模型输出Action。Action包含两个部分:工具名称(Action)和输入参数(Action Input)。
接上例,模型会输出:
Action: weather_api
Action Input: 北京明天
AgentExecutor接收到这个Action,就会去调用对应的工具函数,把"北京明天"传进去。
Observation:工具返回"看到了什么"
工具执行完后,返回结果给模型。这个结果叫Observation。
比如天气API返回:"北京明天晴,气温15-25摄氏度。"
模型收到Observation后,进入下一轮循环:
新的Thought:"我已经拿到了北京明天的气温,是15-25摄氏度。用户要的是华氏度,所以我需要把摄氏度转换成华氏度。取中间值20摄氏度进行转换。华氏度 = 摄氏度 × 9/5 + 32 = 20 × 1.8 + 32 = 68华氏度。"
新的Action:
Action: calculator
Action Input: 20 * 9 / 5 + 32
新的Observation:"68"
Final Thought:"我已经得到了最终答案。北京明天气温约20摄氏度,换算成华氏度是68°F。"
Final Answer:"北京明天气温约68华氏度(20摄氏度)。"
这就是ReAct的完整循环。它不是一次性给出答案,而是让模型像人类一样,一步一步地思考、行动、观察、再思考,直到问题解决。
三、实战:给Agent配备三件"武器"
理解了原理,我们来动手搭一个。给Agent配备三个工具:搜索引擎、计算器、天气查询。然后扔给它一个复合问题,看它怎么自主拆解。
第一步:定义工具
每个工具都是一个Python函数,用@tool装饰器包装,让LangChain能识别它。
python
from langchain.tools import tool
@tool
def search_engine(query: str) -> str:
"""用于搜索互联网上的实时信息,比如新闻、百科、最新事件。
当用户问到你不知道的、需要最新数据的问题时,使用这个工具。"""
# 实际项目中这里调百度/谷歌/Bing API
return f"搜索结果:关于'{query}'的最新信息是......"
@tool
def calculator(expression: str) -> str:
"""用于执行数学计算。输入应该是一个合法的数学表达式,
比如 '3 * 5 + 2'、'100 / 4'、'2 ** 10'。"""
try:
return str(eval(expression))
except:
return "计算出错,请检查表达式格式"
@tool
def weather_api(city: str) -> str:
"""用于查询指定城市的天气信息。输入应该是城市名称,
比如 '北京'、'上海'、'纽约'。"""
# 实际项目中这里调天气API
weather_data = {
"北京": "明天晴,15-25°C",
"上海": "明天多云,18-26°C",
"纽约": "明天雨,10-15°C"
}
return weather_data.get(city, "暂不支持该城市天气查询")
注意每个工具的docstring(函数说明)。 Agent靠这些说明来决定什么时候调用哪个工具。说明写得越清晰,Agent的决策越准确。
第二步:创建Agent
python
from langchain.agents import create_react_agent, AgentExecutor
from langchain_openai import ChatOpenAI
from langchain import hub
# 加载ReAct的Prompt模板
prompt = hub.pull("hwchase17/react")
# 初始化模型
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# 工具列表
tools = [search_engine, calculator, weather_api]
# 创建ReAct Agent
agent = create_react_agent(llm, tools, prompt)
# 用AgentExecutor包装,负责执行循环
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 打印每步的Thought/Action/Observation
max_iterations=5, # 最多循环5次,防死循环
handle_parsing_errors=True # 解析出错时自动重试
)
第三步:运行复合需求
python
result = agent_executor.invoke({
"input": "帮我查一下明天北京气温,然后算一下华氏度是多少"
})
print(result["output"])
如果开了verbose=True,你会在控制台看到Agent的完整思考过程:
> Entering new AgentExecutor chain...
Thought: 用户想知道北京明天的气温,并且要求换算成华氏度。
我需要分两步:先查询北京明天的气温,再把摄氏度转成华氏度。
Action: weather_api
Action Input: 北京
Observation: 明天晴,15-25°C
Thought: 我已经拿到了北京明天的气温范围15-25°C。
为了换算成华氏度,我取中间值20°C进行计算。
华氏度 = 20 * 9 / 5 + 32
Action: calculator
Action Input: 20 * 9 / 5 + 32
Observation: 68.0
Thought: 我已经得到了最终答案。
Final Answer: 北京明天气温约68华氏度(对应20摄氏度,实际范围15-25°C即59-77°F)。
> Finished chain.
注意Agent的自主行为:
- 它自己判断出需要先查天气,而不是直接计算;
- 它从天气结果中提取了温度数值;
- 它自己决定取中间值20°C进行换算;
- 它主动调用计算器执行公式;
- 最后整合信息,给出完整答案。
整个过程,你没有写一行if-else,没有手动传递中间结果,没有硬编码任务顺序。Agent自己把活干完了。
四、AgentExecutor:幕后指挥官
Agent能自主决策,但谁来控制这个"思考-行动"的循环?答案是AgentExecutor。
AgentExecutor是LangChain中负责运行Agent的核心组件。它的工作逻辑可以概括为:
- 把用户问题和工具说明拼成Prompt,发给LLM;
- LLM返回Thought + Action;
- AgentExecutor解析Action,调用对应工具;
- 工具返回Observation,拼进历史记录;
- 把更新后的历史再次发给LLM,进入下一轮;
- 直到LLM输出Final Answer,或者达到终止条件。
这个循环看似简单,但生产环境中有两个坑必须处理。
坑一:无限循环
如果模型"钻牛角尖",一直在同一个工具上反复调用,循环就永远结束不了。比如查询天气失败后,模型不断重试,陷入死循环。
解决方案:max_iterations
python
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=5 # 最多执行5轮,超限强制终止
)
max_iterations是AgentExecutor的保险丝。无论模型多么执着,5轮之后强制结束,避免资源耗尽。
坑二:输出格式错乱
LLM偶尔不按ReAct格式输出。比如它可能输出:
Thought: 我需要查询天气
好的,我来帮您查询一下,请稍等...
Action: weather_api
Action Input: 北京
中间那句"好的,我来帮您查询一下"是多余的废话,导致AgentExecutor解析Action时失败,直接抛异常崩溃。
解决方案:handle_parsing_errors
python
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
handle_parsing_errors=True # 解析错误时,把错误信息反馈给LLM,让它重新生成
)
当设置为True时,AgentExecutor不会直接崩溃,而是把解析错误包装成一条Observation回传给模型:"你的输出格式不对,请严格按照Thought/Action/Action Input的格式输出。"模型收到反馈后,通常会修正格式,重新生成正确的Action。
这个参数在生产环境必须开启。开发阶段可以关掉,方便看到原始报错;但上线后,没有它,一次格式错乱就能让整个服务500错误。
其他关键参数
- verbose :开发时设为
True,打印每轮Thought/Action/Observation,方便调试;上线后设为False,减少日志噪音。 - return_intermediate_steps :设为
True时,返回结果会包含每轮的工具调用详情,适合做审计日志;平时不需要。 - early_stopping_method:当达到max_iterations但还没拿到Final Answer时,是强制返回提示语("force"),还是让模型基于已有信息生成一个最终答案("generate")。推荐用"generate",体验更好。
五、Agent不是万能药:它适合什么,不适合什么
写到这里,有必要泼一盆冷水。Agent很酷,但不是所有场景都适合。
适合用Agent的场景:
- 任务步骤不确定,需要根据中间结果动态调整。比如"查天气→算温度→根据温度推荐穿衣",中间每一步都可能影响下一步。
- 需要调用多个不同类型的工具,且调用顺序不固定。比如客服机器人,可能涉及查订单、算退款、搜知识库、发邮件,顺序完全取决于用户问题。
- 问题本身需要多轮推理才能解决。比如"某公司去年营收增长20%,今年Q1营收是去年的1.2倍,请计算今年Q1相比前年同期的增长率",需要拆解成多个计算步骤。
不适合用Agent的场景:
- 流程完全固定的任务。比如"翻译→润色→输出",用Chain更稳定、更快、成本更低。Agent的自主决策在这里是多余的,反而增加了不确定性。
- 对延迟极度敏感的场景。Agent每轮循环都要调一次LLM,一个复杂任务可能调3-5次,延迟是Chain的3-5倍。
- 对确定性要求极高的场景。比如金融交易、医疗诊断,一步错步步错,不适合让模型自主决策。
一句话总结:Chain是"按剧本演戏",Agent是"即兴发挥"。剧本好的戏,别让它即兴。
六、写在最后:从"调API"到"搭团队"
写完这个Demo,我对Agent最大的感受是:它改变了我和AI的关系。
以前用Chain,我是导演,AI是演员。我写好剧本,AI按台词念。剧本越细,效果越可控,但灵活性越差。
现在用Agent,我是老板,AI是项目经理。我定目标、配资源(工具),AI自己排计划、调资源、交结果。我只需要在关键节点验收,在出问题时兜底。
这种转变,和当年从"手写汇编"到"用高级语言"、从"单体应用"到"微服务"的演进很像------不是人在退化,而是人在进化到更高的抽象层。
当然,Agent目前还不完美。它偶尔会选错工具,偶尔会在循环里打转,偶尔会把简单问题复杂化。但这些问题,随着模型能力的提升和框架的成熟,正在快速改善。LangChain 1.0已经把ReAct循环标准化成了create_agent一个函数,10行代码就能搭一个生产级Agent。
如果你还在用if-else手动分发用户意图,不妨试试Agent。让它自己决定该调用什么工具,你会发现:代码少了,灵活性高了,AI真的开始像"智能体"而不是"应答机"了。