ARTICLE DETAIL

建站实战干货

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

Agent 多步推理(Plan-Execute)完整实战教程:央行降准投资决策案例与代码实现

2026/8/14 7:21:13 拓冰建站 浏览量
Agent 多步推理(Plan-Execute)完整实战教程:央行降准投资决策案例与代码实现 摘要本文通过央行降准投资决策的真实案例完整讲解 Agent 多步推理Plan-Execute 模式的原理与 Python 代码实现。当问题需要串行依赖链计算流入→查询影响→计算配比→查询龙头股时Function Calling 的并发调用模式无法胜任需要 Plan-Execute 循环逐步骤执行。文中提供可复制的核心循环代码、搜索重试与计数器兜底代码包含三个实测案例和 15 组系统测试数据以及两种致命 Bug 的修复方案。适合 Agent 开发、LangGraph 多步推理、大模型应用工程化的开发者阅读。 ## 一、问题背景Function Calling 的盲区 上一篇我们实现了 Function Calling——模型自主选择工具并并发调用。但真实业务里很多问题的步骤之间是有依赖关系的。 以央行降准为例问降准释放 8000 亿25% 流入股市2000 亿怎么配置 100 万账户完整推理链是Step1 计算流入股市的资金量 → Step2 查询降准利好哪些板块 → Step3 按板块计算配置比例 → Step4 查询各板块龙头股。每一步都依赖前一步的输出Step3 要等 Step1 和 Step2 的结果Step4 要等 Step3 定下板块。 这种串行依赖链Function Calling 做不了——它假设所有工具调用独立可并发一次性把工具全调出来没有先后顺序前面的结果还没出来后面的参数根本填不上。这是 7 月初我在 Agent 第 3 课遇到的核心问题也是 Plan-Execute 模式存在的理由。 ## 二、核心思路Plan-Execute 模式 Plan-Execute先规划后执行的核心循环只有五步Plan 列出步骤 → Action 调用一个工具 → Observe 接收结果 → 重复直到所有步骤完成 → Final Answer。 工程实现上有三个关键约束全部来自真实踩坑 1. 每次只做一步绝不在一步里输出完整答案 2. 搜索不到就换关键词重试但最多试 2 次 3. 同一工具连续无产出 ≥3 次代码层强制中断 这三个约束是后面所有代码的灵魂多步推理的难点从来不是让模型想清楚而是让模型在失控的时候被拉回来。 ## 三、完整代码实现 ### 3.1 核心循环 python class PlanExecuteAgent: def __init__(self, llm, tools, max_steps8): self.llm llm self.tools tools # {calculator: fn, search: fn} self.max_steps max_steps self.step_results {} self.tool_call_counts {} # 计数器同一工具调用次数 def run(self, question): steps self.plan(question) # Plan拆出步骤列表 for _ in range(self.max_steps): step self.next_step(steps) # 每次只做一步 if step is None: break # 触发强制收尾 result self.action(step) # Action调用一个工具 self.observe(step, result) # Observe记录结果 if self.all_done(steps): break return self.final_answer(question, steps) def action(self, step): tool, args step[tool], step[args] # 代码层兜底同一工具 3 次未产出有效结果 → 中断 self.tool_call_counts[tool] self.tool_call_counts.get(tool, 0) 1 if self.tool_call_counts[tool] 3: return {status: aborted, reason: 同工具重试超上限} return self.tools[tool](**args) ### 3.2 搜索重试最多 2 次 python def search_with_retry(keyword, max_retry2): for attempt in range(max_retry): result knowledge_base.search(keyword) if result: return result keyword rewrite_keyword(keyword) # 换关键词再试 return None # 搜不到就放弃不硬搜 ### 3.3 强制收尾搜到了也不许继续搜 python def next_step(self, steps): done [s for s in steps if s[done]] # 已有有效结果且总调用次数 4 → 强制 Final Answer if done and sum(self.tool_call_counts.values()) 4: return None for step in steps: if not step[done]: return step return None 三段代码加起来不到 60 行但它们解决的是多步推理最核心的工程问题LLM 不给你任何承诺你只能用代码给它兜底。 ### 3.4 完整运行示例 python def main(): agent PlanExecuteAgent(llmllm, tools{ calculator: calculate, search: search_with_retry, }, max_steps8) question 降准释放8000亿25%流入股市2000亿怎么配置100万账户 answer agent.run(question) print(answer) if __name__ __main__: main() main 里把工具注册进 PlanExecuteAgent传入问题即可运行。运行日志会打印每一步的 Plan当前步骤、Action工具名和参数、Observe工具结果直到 Final Answer。这套骨架是我 7 月 11 日在 Agent 第 3 课上跑通的第一版之后所有案例都在这套代码上改配置复现。 ## 四、实测案例详解 测试环境说明模型为 DeepSeek 的 deepseek-chat工具集为计算器 知识库检索知识库内容为模拟经济数据板块利好、龙头股、历史政策影响检索失败返回未找到。三个案例在同一套代码上跑唯一变化的是 max_steps 和问题本身保证对比有效。 ### 案例1降准投资分析max_steps 的影响 max_steps3 时失败Agent 在查A 股总市值上浪费了 3 次搜索步数耗尽还没走到配置环节。max_steps8 时成功输出配置银行 25 万 地产 20 万 券商 15 万 消费 30 万 现金 10 万。同样的模型、同样的 prompt只改 max_steps结果从失败变成功——步数预算本身就是一种控制手段。 ### 案例2a单步问题最讽刺的失败 降准利好哪些板块只需要一步Agent 却搜了 4 次降准定义 → 降准利好 → 降准银行 → 降准券商。搜到结果后它不认为够了继续扩展搜索最终超过 max_steps 被截断。这个案例说明模型没有够了的概念它只会沿着相关性继续扩散。 ### 案例2b多步依赖链完美走通 2000 亿分给银行地产各多少 龙头股计算流入 → 计算分配 → 查银行龙头 → 查地产龙头4 步依赖链一次走通输出 800 亿 龙头列表。串行依赖链在步数充足、工具定义清晰时模型可以稳定完成。 ### 补充摸底15 组系统测试 7 月 15 日做了一轮更系统的摸底测试15 组场景包括正常延误、延误但天气正常、根本没延误、航班数据缺失、API 故意故障。测试结果 | 场景 | 结果 | |------|------| | 正常延误且天气相关5 组 | 5/5 通过 ✅ | | 根本没延误3 组 | 1/3 通过 ⚠️ | | 数据缺失2 组 | 1/2 勉强可用 ⚠️ | | API 故意故障2 组 | 0/2 不可用 ❌ | 结论非常清晰Agent 在信息完整且符合训练分布时表现好一旦出现异常就不可预测。做真实业务不是做 demo——异常和缺失才是真实的日常。 摸底过程中有一个值得记录的细节Agent 对着空结果反复查了 6 次日志里 6 条一模一样的 tool_call最后被 LangGraph 的 recursion_limit 强行掐断。这直观地说明Agent 没有刚才已经试过了没用这层意识每一步推理都是独立的概率采样第 3 步和第 6 步之间不存在任何记忆。这也是为什么计数器必须放在代码层——模型的自我认知靠不住。 ## 五、两种致命 Bug 与修复 两个 Bug 在日志里非常典型搜不到不停是连续 3 条未找到的 search 调用关键词从总市值换到沪深300再换到中国股市搜到了不停是已经拿到银行、地产、券商的结果后继续搜银行、券商、地产、消费。前者是负向证据下执着后者是正向证据下贪婪模型缺少统一的停止判断——所以解法必须双管齐下负向靠计数器中断正向靠结果 调用上限强制收尾。 | Bug | 现象 | 根因 | 解法 | |-----|------|------|------| | 搜不到不停 | 连搜 3 次总市值沪深300中国股市 | Prompt 没告诉模型怎么放弃 | 代码层计数器同一工具 ≥3 次 → 中断 | | 搜到了不停 | 搜了银行、券商、地产、消费 | 模型觉得信息量永远不够 | 已有有效结果 调用 ≥4 次 → 强制 Final Answer | 两个 Bug 都是停不下来解法都在代码层不在 prompt 层。 ## 六、为什么 Prompt 修不好循环 我在 System Prompt 里加过未找到最多试 2 次就停效果案例 1 从连搜 5 次降到 2 次有效但案例 2a 依然搜了 4 次——因为它的失败模式不是未找到规则根本不触发。 LLM 不是编译器Prompt 是概率引导不是确定性指令。正确架构是两层并用Prompt 负责引导策略代码层负责兜底执行。7 月 5 日我给 Agent 的 State 加了 search_attempt_count 计数器8 行代码比任何 prompt 调优都可靠。 ## 七、常见问题FAQ 1. max_steps 设置多少合适从任务的最长依赖链出发加 2-3 步余量。案例中 4 步依赖链max_steps8 稳定。 2. 计数器放在代码层会不会限制模型能力会但这是故意的。控制优先于能力先保证不失控再逐步放开。 3. 单步问题和多步问题需要分开处理吗建议分开单步问题直接走工具选择多步问题走 Plan-Execute避免模型在简单问题上过度搜索。 4. 和 LangGraph 的关系本文循环逻辑是 LangGraph StateGraph 的手写简化版LangGraph 提供节点编排、状态管理和断点恢复工程上更完整。 5. 模型搜到了不停有没有 prompt 方案可以加已有结果时停止搜索的提示但只能降低概率不能保证代码层强制收尾才是底线。 6. 多步推理和 Function Calling 能混用吗能推荐组合先用 Function Calling 处理单步工具选择再用 Plan-Execute 编排有依赖关系的步骤序列这也是生产 Agent 的常见架构。 7. 步数预算怎么动态调整可以按任务复杂度分级简单任务给 4 步中等 8 步复杂任务 12 步并配合人工确认。动态预算比固定值更省 token但需要先积累各类任务的步数分布数据。 ## 八、总结 多步推理 Plan-then-Execute。和 Function Calling 的本质区别FC 是并发独立调用多步推理是串行依赖链。核心挑战不是推理能力是控制——生产环境必须代码层计数器兜底Prompt 只能引导不能保证。 迁移锚点空保 AI 化场景队员问下周五我执勤帮我准备推理链是查值班表 → 查航班 → 查规程 → 查风险每一步依赖前一步输出——同一个 Plan-Execute 循环换一套工具定义就能复用。 最后说一个选型建议如果你的任务只是查一下、算一下用 Function Calling 就够了如果任务存在明确的步骤依赖才需要 Plan-Execute。判断标准很简单——把任务拆成步骤看下一步是不是必须等上一步的结果。是就走多步推理不是别过度设计。 下一篇预告Agent Memory——当对话超过 128K Token 怎么办