第8章 会规划才值钱
前几章我们给Agent装了脑子、手脚、记性。现在Agent会思考、会干活、会查资料——但如果一个任务有10个步骤,它该先做哪个?做错了能不能自己发现并改正?这一章,我们讲Agent的"规划力"——它值钱的地方就在这。
8.1 让Agent学会"想一步、做一步"
8.1.1 光想不做和光做不想都不行
你可以让LLM直接回答:"帮我规划一个三天两夜的北京旅行"。LLM会给你一份看起来很合理的行程。
但你也可以让LLM真的去查天气、比价格、看评价——做一步,看一眼结果,再决定下一步。
第二种方式叫 ReAct(Reasoning + Acting,推理+行动)。
举个例子:用户问"北京和上海今天哪个更热?"
纯LLM回答(只有推理,没有行动):
LLM: 北京和上海的气温我没法实时获取,建议你自己查一下天气App。ReAct Agent回答(推理+行动循环):
思考:我需要分别查北京和上海的天气。
行动:调用 get_weather("北京")
观察:北京今天28度。
思考:还需要上海的天气。
行动:调用 get_weather("上海")
观察:上海今天32度。
思考:上海比北京热4度。
回答:上海今天更热,32度,比北京高4度。8.1.2 ReAct的代码逻辑
python
# ReAct Agent 的简化逻辑
def react_agent(task, tools, llm):
context = f"任务:{task}\n"
max_steps = 10
for step in range(max_steps):
# 让LLM决定下一步
response = llm.invoke(f"""{context}
你可以使用以下工具:{tools}
请决定:是继续调用工具,还是直接给出最终答案?
如果是调用工具,格式:ACTION: tool_name(params)
如果是最终答案,格式:ANSWER: 你的答案
""")
if "ANSWER:" in response:
return response.split("ANSWER:")[1].strip()
if "ACTION:" in response:
# 执行工具
action = response.split("ACTION:")[1].strip()
result = execute_tool(action)
context += f"\n执行了:{action}\n结果:{result}\n"
return "任务超时,未能完成"ReAct的核心:不是一次性把所有步骤想好再执行,而是做一步、看结果、再想下一步。就像你做饭——你不会把所有步骤都写在纸上才开火,你是边做边调整。
8.2 当"一条路走到黑"不够用的时候
8.2.1 ReAct的局限性
ReAct很好用,但它有一个问题:一旦走错方向,就很难回头。
比如Agent帮你想了一个旅行方案,执行到一半发现"第一天去的博物馆周一闭馆"。ReAct只能回头看一步——它可能改成去别的地方,但它不会想"也许我该从第一天开始重新规划"。
8.2.2 思维树:同时想多条路
思维树(Tree of Thoughts,ToT) 是一种更高级的推理方式——它不只走一条路,而是同时想好几个方案,然后挑最好的。
和ReAct的区别:
| ReAct | 思维树 | |
|---|---|---|
| 思考方式 | 一条路走到底 | 同时想多条路 |
| 适合任务 | 步骤明确的(查天气→比价→下单) | 需要创意的(写作、规划、策略) |
| 计算成本 | 低 | 高(需要多次调用LLM) |
| 纠错能力 | 看到上一步的结果调整 | 能从根上换一条思路 |
实际使用建议:大部分Agent用ReAct就够了。只有当任务本身"没有标准答案"时(比如写文章、做方案),才考虑思维树。
8.3 Agent是怎么"化整为零"的?
8.3.1 大任务拆小任务
你说"帮我安排下个月的出差",这句话背后其实有十几件事:
- 确认出差日期和目的地
- 查航班
- 订机票
- 订酒店
- 预约接送机
- 准备会议材料
- ……
Agent需要把这些"化整为零"——拆成一个个小任务,逐个完成。
任务拆解本质上就是 Prompt 工程:让LLM先列出所有子任务,再逐个执行。
python
plan_prompt = """
你是一个任务规划助手。请把以下任务拆解成3-7个可执行的子任务。
每个子任务应该具体、可独立完成。
任务:{user_task}
请用列表形式返回。
"""
user_task = "帮我安排下个月去上海的出差"
subtasks = llm.invoke(plan_prompt.format(user_task=user_task))
# 1. 确认出差日期
# 2. 查询北京到上海的航班
# 3. 筛选合适时间和价格的航班
# 4. 查询上海公司附近的酒店
# 5. 预订确认8.3.2 依赖关系:有些任务有先后顺序
拆出来的任务不是随便做的。有些有依赖关系——"订酒店"必须在"确认日期"之后。
Agent需要理解这种依赖——不然它会同时订机票和酒店,结果日期还没确认,全订错了。
处理依赖的技巧:让LLM在拆解任务时,同时标注每个子任务的"前置条件"。
子任务 - 前置条件
1. 确认日期 - 无
2. 查航班 - 子任务1
3. 订机票 - 子任务2
4. 订酒店 - 子任务18.4 Agent的"反思"能力
8.4.1 做错了要能改
Agent不是神,它也会犯错。调了错误的工具、理解错了用户意思、生成了不准确的数据——都很常见。
好的Agent不是不犯错,而是犯了错能发现并改正。
这个过程叫 Self-Reflection(自我反思)。
8.4.2 三个常见的反思场景
场景一:工具返回异常。
Agent调了 get_weather("北京"),返回 {"temp": 999}
反思模块:温度不可能999度,API可能出错了。
Agent:用备用工具 retry,或者告诉用户"暂时查不到"。场景二:LLM回答自相矛盾。
LLM回答:"北京今天晴天,适合户外运动。不过出门记得带伞。"
反思模块:晴天为什么带伞?回答有矛盾。
Agent:重新生成,或者标注"可能有误"。场景三:用户反馈。
用户:"你推荐的餐厅已经关门了。"
反思模块:用户明确指出了错误。
Agent:记录这家餐厅已关闭,下次不会再推。同时道歉并重新推荐。8.4.3 反思的实现方式
最简单的方式:多一层LLM调用,专门做"审查官"。
python
def reflect_on_result(task, result):
"""反思模块:检查Agent的输出是否合理"""
check_prompt = f"""
任务:{task}
Agent的输出:{result}
请检查以下问题:
1. 输出是否完成了任务?
2. 数据是否合理(没有明显错误)?
3. 回答是否自相矛盾?
4. 有没有更好的方式?
如果发现问题,请指出并给出修正建议。
如果没有问题,回复"通过"。
"""
return llm.invoke(check_prompt)8.5 本章小结
这一章我们讲了Agent的"规划力"——它和普通聊天机器人拉开差距的地方:
- ReAct:想一步、做一步、看结果、再调整。不把所有步骤想好再动手,而是边干边想。
- 思维树:当"一条路走到黑"不行时,同时想好几个方案再挑。创意型任务的神器。
- 任务拆解:大任务拆小任务,标注依赖关系再执行。有先有后,不瞎做。
- 反思机制:让Agent审查自己的答案。犯错不可怕,错了不能改才可怕。
✅ 知识点检查
学完这一章,试试回答这几个问题:
- [ ] ReAct 和纯LLM推理的核心区别是什么?ReAct多了一个什么循环?
- [ ] 思维树和ReAct各适合什么场景?什么时候该用ToT?
- [ ] 任务拆解时,为什么需要标注"依赖关系"?
- [ ] Agent的反思模块主要检查哪三个方面?
📚 延伸阅读
- 《ReAct: Synergizing Reasoning and Acting in Language Models》
- 《Tree of Thoughts: Deliberate Problem Solving with Large Language Models》
- LangGraph 官方教程中的 Agent 模式:https://langchain-ai.github.io/langgraph/
- 本书配套源码:关注公众号「图解AI系列」免费领取
🎯 下一章预告
第9章,一个Agent搞不定的时候——
"一个人不行?那就组个团。多Agent协作,各司其职。"

