从零构建 Coding Agent
English

00. 导论:Agent 不是一次 API 调用

如果你已经会调用一次大模型 API,你拥有的是一个“会回答问题的函数”。Coding Agent 要解决的是另一类问题:用户给出一个目标,系统需要反复观察环境、调用工具、解释结果、修正计划、保存进度,并在中途被用户插话、终止或恢复后继续工作。它不是更长的 prompt,而是一个围绕模型构建的运行时。

本书会带你构建一个名为 tiny-agent 的教学项目。它不会复刻任何现成产品,但会吸收成熟 Coding Agent 的关键设计:协议层和厂商 API 隔离,工具执行由 stop reason 驱动,会话以追加日志作为事实源,长对话通过压缩投影继续推进,读写文件和执行命令都经过安全边界,CLI、TUI、JSON 和 SDK 都消费同一条事件流。

你最终要做出的东西

最终项目需要具备这些能力:

  • 接收用户任务并调用模型。
  • 暴露 readgrepeditwritebash 等工具。
  • 根据模型的 tool use 请求执行工具,并把结果回传给模型。
  • 以事件流输出模型文本、工具调用、工具进度、工具结果和 turn 结束。
  • 把所有消息和非消息事件写入 JSONL 会话日志。
  • 从任意会话恢复上下文,并在上下文接近窗口上限时压缩。
  • 支持用户在模型运行中插入 steering 或 follow-up。
  • 提供至少两种运行壳:交互式 CLI 和机器可读 JSON 模式。
  • 用 faux provider 和会话回放做零成本测试。

这不是一个玩具聊天机器人。每一项能力都对应真实产品里会遇到的故障:模型生成非法工具参数、两个并行工具同时改同一个文件、流式输出中断、上下文被压缩后忘记刚读过的文件、用户中途改变目标、会话恢复后工具 schema 已经变了。教程会把这些失败模式摆在前面,而不是直接给出“最佳实践”。

读者契约

本书默认你熟悉 TypeScript、Node.js、Promise、异步迭代器、命令行和基本文件系统 API。Agent 相关概念会从 tool calling、循环、事件、会话和工具边界逐步展开。示例代码会保持在教学规模:足够表达边界,不把所有边角情况塞进一段无法阅读的代码里。

每章都有三个层次:

  1. 概念:为什么需要这一层。
  2. 结构:这一层和上下游的契约是什么。
  3. 检查点:读者完成后应该看到什么行为。

如果你只想学 prompt 技巧,本书不合适。如果你想知道一个真正能替你改代码的系统怎样被拆成协议、循环、工具、状态、权限、界面和扩展,本书就是为这个目标写的。

成本与测试策略

Agent 开发不能把每次测试都变成真实模型调用。原因有三个:费用不可控,输出不可重复,失败时很难判断是模型问题还是运行时问题。所以本书从一开始就引入 faux provider。它不是 mock 一个函数返回字符串,而是脚本化返回完整 assistant 消息、tool use、usage 和 stop reason。这样你可以用录制好的响应测试 agent loop、工具错误回传、压缩、恢复和 UI 事件。

真实模型只用于少量端到端检查。默认开发流程应该是:

  • 单元测试用 faux provider。
  • 集成测试用会话回放。
  • 少量 smoke test 调真实模型。
  • 成本统计进入每次 assistant 消息的 usage 字段。

这条纪律会贯穿全书。没有可重复测试的 Agent 很快会变成一个靠感觉调参的黑盒。

核心心智模型

可以把 Coding Agent 看成下面这条数据流:

user goal
  -> context builder
  -> provider adapter
  -> model response
  -> stop reason
  -> tool executor
  -> tool result
  -> session log
  -> next context projection

其中最重要的分离是“日志”和“上下文”。日志是事实源,记录发生过什么;上下文是投影,只是当前准备发给模型的那一部分。压缩、分支、恢复、UI 渲染、扩展记录都应该建立在日志上,而不是反过来把当前 prompt 当成系统状态。

本章检查点

读完这一章后,你应该能用一句话说明 Agent 和一次 LLM API 调用的区别:Agent 是围绕模型响应构建的可恢复运行时。它的难点不在“让模型说什么”,而在“当模型要行动时,系统怎样可靠地执行、记录、反馈和继续”。