01|总览与心智模型:一个 coding agent 到底在循环什么
在写任何代码之前,先把一件事想透:Agent 和"聊天机器人"的本质区别是什么?
聊天机器人是 输入 → 输出 的一次性映射:你问一句,它答一句,结束。而 Agent 是一个循环:它能调用工具、观察结果、根据结果决定下一步,直到任务真正完成才停下。区别不在模型多强,而在外面那层循环。
一、Agent 的本质:大脑 + 手 + 记忆
任何一个编码 Agent,剥掉 UI 和工程细节,都只剩三样东西:
| 组件 | 作用 | 在 Pi 里 | 在我们的 nano 里 |
|---|---|---|---|
| 大脑 | 一个会"思考 + 决定调哪个工具"的 LLM | pi-ai | llm.ts |
| 手 | 一组能改变世界的工具(读写文件、跑命令) | read/write/edit/bash | tools.ts |
| 记忆 | 记录到目前为止发生的一切,喂给大脑做下一步判断 | JSONL 会话树 | session.ts |
大脑本身不能做任何事——它只会输出文字。是"循环"赋予了它手脚:把模型的输出解析成"它想调用某个工具",真正去执行,再把执行结果作为新的记忆喂回去。
二、核心心智模型:tool-use 循环
主流 Agent(包括 Pi、Claude Code、Cursor)都跑同一个循环,学术上叫 ReAct(Reasoning + Acting),工程上就是 tool-use loop:
关键点有三个,后面每一章都会回到它们:
- "带上完整历史":每一轮都把之前所有消息(用户、模型、工具结果)一起发给模型。模型本身无状态,记忆全靠我们在外面维护——这就是为什么"会话存储"是 Agent 的灵魂(第 5 章)。
- "模型自己决定停不停":循环的退出条件不是我们写死的步数,而是模型这一轮没有再要求调工具,意味着它认为任务做完了。
- "工具结果回灌":工具执行的输出(哪怕是报错)必须结构化地塞回历史,模型才能据此纠错。Agent 的"自我修复"能力就来自这里。
用伪代码写出来,整个 Agent 不到 20 行:
messages = [system_prompt, user_request]
loop:
response = LLM(messages) # 大脑思考
messages.append(response)
if response 没有 tool_calls: # 模型觉得做完了
return response.text # 退出
for call in response.tool_calls: # 模型要用手
result = run_tool(call) # 真正执行
messages.append(result) # 结果变成新记忆这 20 行就是 Agent 的全部精髓。 本系列剩下的内容,全是在给这 20 行加上:稳定的 LLM 接口、可靠的工具、能回溯的记忆、能压缩的上下文、能确认的安全边界。
三、Pi 的四层,对应我们要造的东西
Pi 把上面这套拆成四层包。我们复刻时不需要做到生产级,但结构要对齐,这样你读完能直接去看 Pi 源码:
为什么要分层而不是写成一大坨?因为每一层的"变化原因"不同:
- 换模型供应商,只动
pi-ai; - 改循环策略(比如加重试、加并行工具),只动
pi-agent-core; - 加一个新工具,只动工具层;
- 换 UI(终端换成网页),只动最上层。
这就是软件工程里的"单一职责"。Agent 框架的复杂度不在算法,而在如何把这些关注点干净地切开。
四、我们要造的 nano
整个系列我们会造一个叫 nano 的 mini coding agent,目标是:
在终端里输入一句话(比如"把
utils.ts里所有var换成const"),它能自己读文件、改文件、必要时跑命令验证,并把过程和结果显示出来;会话能存盘、能回溯。
技术选型:
- 语言:TypeScript(贴合 Pi 原生),用
tsx直接跑.ts,不折腾构建。关键模块给 Python 对照。 - 模型接口:以 OpenAI 兼容协议为基准(OpenAI、DeepSeek、本地 Ollama、vLLM 都兼容它),因为 tool-calling 的事实标准就是这套。第 2 章会把它抽象掉,换 Anthropic 也只改一层。
- 零重框架:除了官方 SDK,不引入 LangChain 之类的编排库——我们就是要看清底层。
项目骨架(后面逐章填充):
nano/
├── llm.ts # 第 2 章:LLM 通信层
├── agent.ts # 第 3 章:Agent Loop
├── tools.ts # 第 4 章:工具系统
├── session.ts # 第 5–7 章:会话树 + 上下文压缩
├── cli.ts # 第 8 章:终端 UI
└── index.ts # 入口,把以上拼起来初始化:
mkdir nano && cd nano
npm init -y
npm install openai # 仅用它的类型与 HTTP 客户端
npm install -D typescript @types/node tsxPython 同学
全程你都可以用 Python 跟着走。对照项目结构一样:llm.py / agent.py / tools.py / session.py / cli.py,依赖换成 pip install openai。每章涉及核心逻辑处我都会给出 Python 版片段。
小结
- Agent = 大脑(LLM)+ 手(工具)+ 记忆(会话),被一个循环串起来。
- 循环的三个要害:每轮带上完整历史、由模型自己决定停止、把工具结果回灌。
- 框架的复杂度在于分层切分关注点,不在算法。Pi 用四层做到了极简,我们对齐它造
nano。
去源码里看什么
- Pi 仓库:
github.com/badlogic/pi-mono,先看 README 里的 packages 列表,建立"四层"的整体印象。 - 下一章我们开始写第一层——02|LLM 通信层,把"调模型"这件事变成一个稳定、可替换的接口。

评论功能暂未开放
还没有评论
快来发表第一条评论吧