第 2 章 · Agent Loop 与任务规划

05 · 实战:第一个多步骤任务

用一个真实的多步骤任务演示升级后的 agent 如何工作:创建计划、按步骤执行、展示 ReAct 循环的完整运转过程。

从问答到执行

第 1 章的 agent 只能回答问题——搜一下、读一下、给出答案。现在它有了 Agent Loop、ReAct 模式、Todo 机制和退出条件,可以处理更复杂的任务了。

这一节用一个真实任务走一遍完整流程,看看升级后的 agent 怎么工作。

Todo 机制的运转原理

在进入实战之前,先理解 Todo 机制在代码层面是怎么运转的。三个关键组件协作:

TodoManager(src/todo.ts——计划管理器。每次 runAgent 创建一个新实例,维护一个 items 数组。步骤通过 createItems() 创建(自增 ID,初始 pending),通过 updateStatus() 更新状态。

create_todos 工具(src/tools/create-todos.ts——工厂函数创建,通过闭包捕获 TodoManager。模型调用时传入步骤描述列表,工具调用 todoManager.createItems() 批量创建。

update_todo 工具(src/tools/update-todo.ts——同样通过闭包捕获 TodoManager。模型每开始一步标记 running,完成标记 completed,失败标记 failed。注意状态不可回退——pending 不在允许列表中。

create_todos({ items: ["步骤A", "步骤B"] })
  → TodoManager.createItems()
  → TodoItem { id: "1", description: "步骤A", status: "pending" }
  → TodoItem { id: "2", description: "步骤B", status: "pending" }
  → 返回: "已创建 2 个步骤: ..."

update_todo({ id: "1", status: "running" })
  → TodoManager.updateStatus("1", "running")
  → 返回: "步骤 #1 → running\n执行计划: ..."

agent.ts 中的提前退出:
  → todoManager.allCompleted()
  → items.length > 0 && every(item => item.status === "completed")
  → 满足且模型不再请求工具 → 直接返回,省 token

实战任务:分析项目工具的参数定义

给 agent 一个需要多步分析的任务:

> 帮我找出这个项目中所有工具的参数定义,对比它们是否一致,然后给出一份工具清单和改进建议

第一轮:模型分析任务,创建计划

模型判断这是复杂任务,调用 create_todos

工具调用: create_todos({
  items: [
    "搜索项目中所有工具定义的位置",
    "读取各个工具的参数定义",
    "对比分析工具参数的一致性",
    "生成工具清单和改进建议报告"
  ]
})

工具返回:
已创建 4 个步骤:
执行计划:
  [ ] #1 搜索项目中所有工具定义的位置
  [ ] #2 读取各个工具的参数定义
  [ ] #3 对比分析工具参数的一致性
  [ ] #4 生成工具清单和改进建议报告

模型先规划再动手。每个步骤有明确的 ID 和状态,方便后续跟踪。

第二轮:搜索工具位置,标记步骤 1 为 running

工具调用: update_todo({ id: "1", status: "running" })
工具调用: search({ query: "Tool" })

工具返回 (search): 找到 src/tools/ 下多个文件中的 Tool 类型引用

模型标记步骤 1 开始执行,同时搜索关键词定位工具文件。这就是 ReAct 模式——Reason(分析需要搜索)→ Act(调用 search)→ Observe(看到搜索结果)。

第三轮:逐个读取工具文件

工具调用: update_todo({ id: "1", status: "completed" })
工具调用: update_todo({ id: "2", status: "running" })
工具调用: read_file({ path: "src/tools/search.ts" })
工具调用: read_file({ path: "src/tools/read-file.ts" })
工具调用: read_file({ path: "src/tools/create-todos.ts" })
工具调用: read_file({ path: "src/tools/update-todo.ts" })

模型一口气读了四个工具文件。每次工具调用都是一轮 ReAct 循环:模型看到上一次的结果,决定下一步做什么。

第四轮:完成分析,给出结果

工具调用: update_todo({ id: "2", status: "completed" })
工具调用: update_todo({ id: "3", status: "completed" })
工具调用: update_todo({ id: "4", status: "running" })

模型对比了四个工具的参数定义后,发现几个不一致的地方,然后给出清单和建议。最终标记步骤 4 完成。

终端中的输出

> 帮我找出这个项目中所有工具的参数定义,对比一致性,给出改进建议

--- 执行计划 ---
  [x] #1 搜索项目中所有工具定义的位置
  [x] #2 读取各个工具的参数定义
  [x] #3 对比分析工具参数的一致性
  [x] #4 生成工具清单和改进建议报告
----------------

[模型的完整分析和建议]

[模型调用: 16次 | 工具调用: 24次]

模型有时会"过度规划"

上面的实际运行中,模型创建了 24 个步骤(远超最初的 4 个),包括很多修改代码的具体步骤。这导致了迭代上限被触发(15 次循环不够用)。

这是一个重要的观察:Todo 机制是引导模型行为的工具,但模型自己决定创建多少步骤。 如果模型过度拆分任务,可能在迭代上限内完不成。

目前没有自动机制来约束步骤数量。这在后续章节可以通过系统提示词的优化来改善——比如告诉模型"步骤不超过 5 个"。

简单问题不走计划

对比一下:如果问"入口文件在哪",模型会判断这是简单问题,直接用搜索和读文件工具回答,不创建计划。

系统提示词中的这段引导让模型能区分两种情况:

对于复杂任务,先用 create_todos 工具创建执行计划,然后按步骤执行。
...
对于简单问题,可以直接使用搜索和读文件工具回答,不需要创建计划。

这一章的代码结构

完成第 2 章后,项目结构变为:

mini-coding-agent/
├── src/
│   ├── types.ts            # 类型定义(新增 TodoItem, AgentStats, AgentResult)
│   ├── model.ts            # 模型层(不变)
│   ├── todo.ts             # Todo 管理器(新增)
│   ├── agent.ts            # Agent Loop(升级:ReAct + 计划 + 统计)
│   ├── main.ts             # CLI 入口(升级:显示计划和统计)
│   └── tools/
│       ├── search.ts       # 搜索工具(不变)
│       ├── read-file.ts    # 读文件工具(不变)
│       ├── create-todos.ts # 创建计划工具(新增)
│       └── update-todo.ts  # 更新步骤状态工具(新增)
├── test/
│   ├── agent.test.ts       # Agent 测试(升级)
│   ├── model.test.ts       # 模型测试(不变)
│   ├── todo.test.ts        # Todo 管理器测试(新增)
│   └── tools/
│       ├── search.test.ts       # 搜索工具测试(不变)
│       ├── read-file.test.ts    # 读文件工具测试(不变)
│       ├── create-todos.test.ts # 创建计划测试(新增)
│       └── update-todo.test.ts  # 更新步骤测试(新增)
├── package.json
└── tsconfig.json

这一章做了什么

回顾第 2 章的成果:

  • Agent Loop 升级:从简单的 5 轮上限进化为结构化的执行循环,支持可配置的迭代上限
  • ReAct 模式:模型在循环中持续推理(Reason)、执行(Act)、观察(Observe)
  • Todo 机制:模型通过 create_todos 创建计划、通过 update_todo 跟踪步骤状态,完成时自动检测并提前退出
  • 退出条件:正常完成(模型不再调工具)、计划完成(allCompleted())、达到上限三种停止条件
  • 执行统计AgentStats 跟踪模型调用次数、工具调用次数和是否触及上限
  • Repair Loop:工具失败时错误信息回传给模型,模型自行调整策略

从第 1 章的"能回答问题",到第 2 章的"能规划并执行多步骤任务",agent 的能力上了一个台阶。下一章开始建设工具系统——让 agent 有更多"手脚"可以使用。

登录以继续阅读

解锁完整文档、代码示例及更多高级功能。

立即登录

On this page