00. 导论:Agent 不是一次 API 调用
如果你已经会调用一次大模型 API,你拥有的是一个“会回答问题的函数”。Coding Agent 要解决的是另一类问题:用户给出一个目标,系统需要反复观察环境、调用工具、解释结果、修正计划、保存进度,并在中途被用户插话、终止或恢复后继续工作。它不是更长的 prompt,而是一个围绕模型构建的运行时。
本书会带你构建一个名为 tiny-agent 的教学项目。它不会复刻任何现成产品,但会吸收成熟 Coding Agent 的关键设计:协议层和厂商 API 隔离,工具执行由 stop reason 驱动,会话以追加日志作为事实源,长对话通过压缩投影继续推进,读写文件和执行命令都经过安全边界,CLI、TUI、JSON 和 SDK 都消费同一条事件流。
你最终要做出的东西
最终项目需要具备这些能力:
- 接收用户任务并调用模型。
- 暴露
read、grep、edit、write、bash等工具。 - 根据模型的 tool use 请求执行工具,并把结果回传给模型。
- 以事件流输出模型文本、工具调用、工具进度、工具结果和 turn 结束。
- 把所有消息和非消息事件写入 JSONL 会话日志。
- 从任意会话恢复上下文,并在上下文接近窗口上限时压缩。
- 支持用户在模型运行中插入 steering 或 follow-up。
- 提供至少两种运行壳:交互式 CLI 和机器可读 JSON 模式。
- 用 faux provider 和会话回放做零成本测试。
这不是一个玩具聊天机器人。每一项能力都对应真实产品里会遇到的故障:模型生成非法工具参数、两个并行工具同时改同一个文件、流式输出中断、上下文被压缩后忘记刚读过的文件、用户中途改变目标、会话恢复后工具 schema 已经变了。教程会把这些失败模式摆在前面,而不是直接给出“最佳实践”。
读者契约
本书默认你熟悉 TypeScript、Node.js、Promise、异步迭代器、命令行和基本文件系统 API。Agent 相关概念会从 tool calling、循环、事件、会话和工具边界逐步展开。示例代码会保持在教学规模:足够表达边界,不把所有边角情况塞进一段无法阅读的代码里。
每章都有三个层次:
- 概念:为什么需要这一层。
- 结构:这一层和上下游的契约是什么。
- 检查点:读者完成后应该看到什么行为。
如果你只想学 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 是围绕模型响应构建的可恢复运行时。它的难点不在“让模型说什么”,而在“当模型要行动时,系统怎样可靠地执行、记录、反馈和继续”。