Pi 1.3.0:学习路线
这门课的目标:不是背 Pi 的 API,也不是通读每一行源码,而是建立一套能迁移到任何 Agent 项目的完整心智模型——知道一个 Agent 为什么这样分层、上下文如何流动、工具如何被安全执行、系统如何扩展和演进。
适合谁:会一点 TypeScript、能在命令行运行项目,但还没有系统理解 Agent 的读者。
源码目录:
$PI_SRC,固定在 v1.3.0(71023aec)。 开发区:$PI_DEV,跟上游开发线时使用;阶段 1–8 不需要改这里。 总览:先读介绍与整体架构,把本清单当路线图,再按阶段读详解。
一、先建立总图:Agent 到底是什么
跳转到“一、先建立总图:Agent 到底是什么”一句话:Agent 是一个会“反复做决定”的程序。 它把用户目标、历史记录、系统提示和工具说明交给模型;模型决定是回答,还是调用工具;工具结果回到上下文后,模型再决定下一步,直到任务完成。
用户或程序 │ ▼入口层:TUI / print / JSON / RPC / SDK │ 输入和输出 ▼应用层:会话编排、工具、扩展、资源、模型选择 │ 把“这次要做什么”整理成一次运行 ▼引擎层:循环(问模型 ↔ 执行工具) │ 统一格式的请求 ▼模型供应商:Anthropic / OpenAI / Google / …旁边还有一份持续写入的会话账本。它记录发生过什么;下一次请求前,系统会从当前活动分支重建一份“模型可见的对话历史”,也就是投影。
Agent 的七个功能块
跳转到“Agent 的七个功能块”任何 coding agent 都可以拆成七块。学习 Pi,就是看这七块如何互相配合:
| 功能块 | 要回答的问题 | Pi 中的主要位置 | 对应阶段 |
|---|---|---|---|
| 循环 | 何时问模型、执行工具、继续或停止? | packages/agent |
2 |
| 上下文 | 每次到底给模型看什么? | 会话树、投影、压缩、系统提示词 | 3 |
| 工具 | 模型能对世界做什么?如何校验和执行? | packages/coding-agent/src/core/tools |
4 |
| 模型接入 | 如何统一不同厂商的 API 和凭据? | packages/ai |
5 |
| 扩展 | 新能力如何在不改核心的情况下长出来? | 扩展、技能、MCP、codemode | 6 |
| 界面 | 同一引擎如何同时服务人、脚本和程序? | TUI / print / JSON / RPC / SDK | 7 |
| 工程 | 如何让改动可靠、可测试、可发布? | 测试、check、构建、发布流程 | 8 |
三条贯穿全系统的纵线
跳转到“三条贯穿全系统的纵线”除了七块,还要一直带着这三个问题:
- 事件是怎么流动的? 模型增量、工具状态、消息落盘都通过事件通知外部;界面只是事件的消费者。
- 信任边界在哪里? 工具和扩展以 Pi 进程的系统权限运行;项目信任和容器决定“它能碰什么”。
- 成本从哪里来? 历史、工具结果、技能说明都会占上下文;压缩、截断和懒加载都是在控制成本和质量。
二、整门课只围绕一条主线:一次请求的旅程
跳转到“二、整门课只围绕一条主线:一次请求的旅程”后面每一章都在拆这条线中的一段:
输入 → 入口层交给 AgentSession → 检查命令、展开模板、排队、认证 → 准备一次运行:压缩检查、扩展钩子、起始消息 → Agent 循环:重建上下文 → 请求模型 → 执行工具 → 再请求 → 消息与工具结果写入会话树 → agent_end:底层循环结束 → agent_settled:没有自动工作,真正空闲你需要能随时回答四个问题:
- 这次请求从哪里进来? 界面、脚本还是外部程序?
- 模型这次看到什么? 当前活动分支经过压缩和投影后得到的内容。
- 模型做了什么? 只回答,还是调用工具?工具结果如何回到上下文?
- 系统何时真正停止?
agent_end和agent_settled不是一回事。
能沿着这条线解释每个部件,才算真正理解 Agent;只记住文件名不算。
三、怎么学:每章都走同一个五步循环
跳转到“三、怎么学:每章都走同一个五步循环”第 1 步:先用自己的话回答本章问题
跳转到“第 1 步:先用自己的话回答本章问题”比如阶段 3 的问题不是“会话文件有哪些字段”,而是:
模型本身不记事,Pi 为什么还能连续对话?每次到底发什么给它?
先写下你的直觉答案,再去读材料。带着问题读,比从目录开始读有效得多。
第 2 步:画一张图
跳转到“第 2 步:画一张图”每一章至少产出一张图:请求流、循环状态机、树与投影、工具生命周期、扩展点、接口选型。图不必漂亮,但必须能让你不看代码讲出关系。
第 3 步:到代码里验证
跳转到“第 3 步:到代码里验证”只追本章相关的路径,不要从仓库根目录开始通读。每个概念都要落到一个具体对象或函数:
- 循环:
runLoop、turn_start、turn_end - 上下文:会话 entry、活动分支、压缩、投影、
convertToLlm - 工具:工具定义、参数校验、执行、结果回填
- 模型:
Model、StreamFunction、provider 适配器 - 扩展:贡献点、事件钩子、资源加载
- 界面:事件流、JSONL、RPC、SDK
第 4 步:做一个小实验
跳转到“第 4 步:做一个小实验”每章都要有一个能跑或能验证的动作:用 JSON 看一次事件、写一个最小循环、从会话树推导一次上下文、写一个工具、配一个模型、写一个扩展、跑一次接口、改一个测试。
第 5 步:讲回来
跳转到“第 5 步:讲回来”合上文档,用 3–5 分钟讲给“三个月后的自己”听。讲不清的地方,就是下一轮要回去补的地方。
学习的敌人不是难,而是只读不验证、只记名词不建模型、只跟着步骤走却不问为什么。 这门课用“问题 → 图 → 代码 → 实验 → 复述”反复拆掉这三个坏习惯。
四、阶段路线:每一阶段只解决一个大问题
跳转到“四、阶段路线:每一阶段只解决一个大问题”阶段 0 · 先让系统真实跑起来【准备】
跳转到“阶段 0 · 先让系统真实跑起来【准备】”问题:源码版能不能在本机完整工作?
你要得到:能运行交互模式和非交互模式;知道版本、模型数据和基本目录。
产出:一次成功的 -p 任务,一次成功的交互对话。
为什么先做:没有真实行为,后面的所有概念都会变成纸上谈兵。
阶段 1 · 系统地图:一条请求如何穿过 Pi【核心】
跳转到“阶段 1 · 系统地图:一条请求如何穿过 Pi【核心】”问题:Pi 有哪些层?谁把输入交给谁?事件如何返回?
你要得到:能用一张图讲清「界面 → AgentSession → 循环 → 模型/工具 → 会话账本」。
产出:包依赖图 + 请求时序图 + 一段 JSON 事件观察记录。
关键区别:agent 是循环引擎,coding-agent 是完整产品;AgentSession 管运行,SessionManager 管账本。
阶段 2 · 循环:Agent 如何从一次回答变成多轮行动【核心】
跳转到“阶段 2 · 循环:Agent 如何从一次回答变成多轮行动【核心】”问题:turn 的边界在哪里?有工具结果时为什么自动继续?中途插话和停止怎么处理? 你要得到:画出包含 steer、follow-up、abort 的循环状态机;写出一个最小 agent loop。 产出:状态机图 + 最小循环代码 + 两条事件轨迹的对照。 核心认识:模型请求无状态;工具结果必须作为新消息回到上下文,循环才有“下一步”。
阶段 3 · 上下文:模型每次到底看到什么【核心】
跳转到“阶段 3 · 上下文:模型每次到底看到什么【核心】”问题:对话如何存成树?压缩、投影和模型消息是什么关系? 你要得到:能从一棵会话树推导出下一次请求的上下文,并解释为什么压缩不删除原文。 产出:一份「会话树 → 活动分支 → 压缩 → 投影 → 模型消息」的推导练习。 关键区别:会话树保存事实,压缩记录一段摘要,投影是每次请求临时生成的可视历史。
阶段 4 · 工具:模型如何影响真实世界【核心】
跳转到“阶段 4 · 工具:模型如何影响真实世界【核心】”问题:工具如何暴露、校验、执行和回填?怎样防止一次工具调用毁掉工作区? 你要得到:讲清工具生命周期;理解参数校验、执行方式、输出截断、结果回填和人类可观测性的分工。 产出:一个可用的自定义工具 + 一份工具风险清单。 核心认识:工具是 Agent 的手脚,也是最大的风险边界;错误应成为可回填的结果,而不是让会话崩溃。
阶段 5 · 模型接入:如何把不同厂商变成一套接口【进阶】
跳转到“阶段 5 · 模型接入:如何把不同厂商变成一套接口【进阶】”问题:OpenAI、Anthropic、Google 的协议差异被谁吸收?模型能力、价格和凭据从哪里来? 你要得到:画清 provider → 模型目录 → 认证 → 统一流式事件的关系;能配置一个自定义模型或 provider。 产出:一张「厂商事件 → 统一事件」对照表 + 一次自定义 provider 配置。 核心认识:协议不等于厂商;很多厂商可以复用同一种 API 协议,循环不应该知道厂商细节。
阶段 6 · 扩展:能力如何在不改核心的情况下长出来【进阶】
跳转到“阶段 6 · 扩展:能力如何在不改核心的情况下长出来【进阶】”问题:工具、命令、渲染器、技能、MCP 和 codemode 分别在哪一层扩展?什么时候该进核心,什么时候该做扩展? 你要得到:能按需求选择扩展点;理解技能按需加载、MCP 外部工具和 codemode 沙箱的定位。 产出:一个扩展或技能,并说明它为什么不应该直接改核心。 核心认识:核心稳定,能力向外生长;扩展不是“附加功能”,而是产品架构的一部分。
阶段 7 · 界面:同一引擎如何服务人、脚本和程序【进阶】
跳转到“阶段 7 · 界面:同一引擎如何服务人、脚本和程序【进阶】”问题:TUI、print、JSON、RPC、SDK 有什么区别?什么时候该用哪一种? 你要得到:能根据“人看、脚本取结果、程序看过程、程序双向控制、进程内嵌入”做选型。 产出:一个 JSON 事件处理脚本 + 一个 SDK 或 RPC 最小客户端。 核心认识:引擎不依赖界面;所有形态共享同一套会话和事件,只是输入输出方式不同。
阶段 8 · 工程:如何让改动可信、可持续【核心】
跳转到“阶段 8 · 工程:如何让改动可信、可持续【核心】”问题:一个 Agent 项目怎样测试、检查和发布,才能让改动不破坏原有行为?
你要得到:理解 faux provider、测试隔离、npm run check 的关卡和发布边界。
产出:一次带测试的规范小改动,或一份可复现的验证记录。
核心认识:Agent 的输出不确定,但工程系统必须确定;测试要把模型替换成可控的假实现。
阶段 9 · 综合重建:把七块组装成自己的 Agent【实战】
跳转到“阶段 9 · 综合重建:把七块组装成自己的 Agent【实战】”问题:如果从零设计一个 Agent,你会怎样组合循环、上下文、工具、模型、接口和工程? 你要得到:不再依赖 Pi 的文件名,能独立画出自己的设计并解释取舍。 产出:一个 mini agent + 一份设计说明 + 一次可复现的端到端请求追踪。 核心认识:真正的掌握不是“看懂 Pi”,而是能把同样的结构迁移到另一个项目。
五、推荐节奏与路线
跳转到“五、推荐节奏与路线”完整路线建议 6–8 周,每周 8–10 小时。时间是估算,不是考核标准;能讲清、能验证比赶进度重要。
| 周次 | 主线 | 阶段 |
|---|---|---|
| 第 1 周 | 跑起来 → 系统地图 → 循环 | 0、1、2 |
| 第 2 周 | 循环收尾 → 上下文 | 2、3 |
| 第 3 周 | 工具 | 4 |
| 第 4 周 | 模型接入 → 扩展 | 5、6 |
| 第 5 周 | 界面与集成 | 7 |
| 第 5–6 周(穿插) | 工程化 | 8 |
| 第 6–8 周 | 综合实战与毕业验收 | 9 |
三种走法
跳转到“三种走法”- 最小路线:0 → 1 → 2 → 3 → 4 → 8 → 9。先获得独立写出最小 Agent 的能力。
- 完整路线:0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9。适合想系统掌握平台化能力的人。
- 生产化路线:在完整路线基础上重点加强 4、6、8,并读选修区的 telemetry、durable、env。
如果时间不够,不要跳过阶段 1–4 的“理解 + 小实验”;可以暂时不深挖 TUI 内部、chord 和 durable。
六、最终毕业设计:做一个 mini agent
跳转到“六、最终毕业设计:做一个 mini agent”阶段 9 的核心不是再做几道散题,而是把前面的知识重新组装。最低要求如下:
- 一个循环:支持模型回复、工具调用、工具结果回到上下文、自然停止和中止;
- 一份会话记录:至少能保存消息、工具结果和一次压缩摘要;能解释树/分支/活动路径;
- 一次上下文投影:能从活动路径生成模型消息,压缩后仍保留原文;
- 两个工具:一个只读工具、一个会产生副作用的工具,并说明校验和风险;
- 一个模型适配:至少接入一个 provider,能处理流式文本和错误;
- 一个界面:CLI 或 JSON 事件输出,至少能从外部观察执行过程;
- 一份追踪记录:导出一次完整请求的事件序列,能解释消息、工具和停止原因;
- 一组测试:用假模型测循环、工具和错误路径;
- 一份设计说明:画出七块结构,解释三个关键取舍。
如果你能不看 Pi 源码完成这套设计,并解释为什么每个部件存在,这门课的目标就达到了。
七、核心术语小抄
跳转到“七、核心术语小抄”| 术语 | 一句话解释 |
|---|---|
| Agent | 由模型反复做决定、调用工具并维护上下文的程序 |
| Run | 从一次输入开始,到系统确认没有自动工作为止的一整段执行 |
| Turn | 一次模型回复及其要求的工具执行,是循环中的一轮 |
| Session | 一次可持续对话的持久化记录,本质上是一棵 entry 树 |
| Entry | 会话文件中的一条记录,有 id 和 parentId |
| Branch | 从根节点到某个叶子的连续路径;一个会话可以有多条 |
| Leaf | 当前活动分支的末端,决定下一次从哪里继续 |
| Projection | 从活动分支计算出的、模型可见的对话历史 |
| Compaction | 把旧历史概括成摘要并追加到树中的操作 |
| Context | 本次请求真正发给模型的全部内容 |
| Tool call | 模型请求执行一个工具及其参数 |
| Provider | 某家模型厂商或某种模型服务的接入实现 |
| Extension | 在进程内注册工具、命令、钩子、渲染等能力的模块 |
| Event | 执行过程中的状态通知,如增量文本、工具开始/结束、消息落盘 |
八、文档地图
跳转到“八、文档地图”| 文档 | 作用 |
|---|---|
| 介绍与整体架构 | 先读的总览:七块、分层、请求旅程、设计取舍 |
| 阶段 0 | 环境搭建与两种基础用法 |
| 阶段 1 | 包依赖、实体词、请求全生命周期 |
| 阶段 2 | 循环、turn、steering / follow-up / abort、最小循环 |
| 阶段 3 | 会话树、投影、压缩、系统提示词、分支 |
| 阶段 4 | 工具生命周期、安全、截断、回填、自定义工具 |
| 阶段 5 | 模型接入、provider、凭据、模型目录 |
| 阶段 6 | 扩展、技能、MCP、codemode、打包 |
| 阶段 7 | TUI、print、JSON、RPC、SDK 与集成 |
| 阶段 8 | 测试、检查流水线、构建和发布 |
| 阶段 9 | 完整 mini agent、测试、设计说明与毕业验收 |
| 选修区 | telemetry、durable、env、chord、evals 的按需入口 |
使用顺序:总览读两遍 → 当前阶段清单 → 阶段详解 → 做实验 → 回到总图复述。不要从文档目录顺序硬读所有源码。
九、环境与常用命令
跳转到“九、环境与常用命令”源码目录固定在 $PI_SRC。在 PowerShell 中:
cd $PI_SRCnpm install --ignore-scriptsnpm run hydrate:model-data.\pi-test.ps1 --version.\pi-test.ps1 -p "总结这个仓库的目录结构".\pi-test.ps1观察事件流时:
.\pi-test.ps1 --mode json "读一下 package.json 的前 20 行"需要 JSONL 事件时,优先把它重定向到文件,再逐行解析;不要用普通文本日志污染 stdout 事件流。
十、学习进度表
跳转到“十、学习进度表”- 阶段 0:能运行两种形态,知道学习区版本
- 阶段 1:能脱稿画系统图和请求时序图
- 阶段 2:能写出最小循环并解释三个插口
- 阶段 3:能从会话树推导一次模型上下文
- 阶段 4:能写出并验证一个自定义工具
- 阶段 5:能配置一个模型适配并解释统一事件
- 阶段 6:能写一个扩展或技能并说明其边界
- 阶段 7:能选择并跑通一种外部集成形态
- 阶段 8:能完成一次带测试的规范改动
- 阶段 9:能独立设计和解释一个 mini agent
基于 Pi v1.3.0(71023aec,2026-10-15)重写 · 学习区路径已按当前目录校正