一口气学会 Pi Agent 系统设计:从一次 prompt 拆开 7.9 万 Star 的 Coding Agent

小糊有话说(微信转载)
📝
顺着真实调用链拆解 Pi(earendil-works/pi,79,966⭐):Agent Loop 双层循环、Steering/Follow-up 双队列、三层上下文、JSONL Session 树、两代 Compaction 协议、并行工具与文件锁、Extensions 中间件、pi-ai Provider 抽象、差分 TUI,附 3 个无需 API Key 的确定性实验与从零做 Agent 的六阶段路线图。

本文转载自微信公众号「小糊有话说」,如有侵权请联系删除。
原文链接:https://mp.weixin.qq.com/s/rrdaGxwbcncz1FE2shqWvA

最近 Pi Agent 在 GitHub 上火得很快。
很多人最早是通过
badlogic/pi-mono
认识它的,现在仓库已经迁到
earendil-works/pi
。截至 2026 年 7 月 28 日,仓库拿到了约 7.9 万个 Star 和 9700 个 Fork;npm 上的
@earendil-works/pi-coding-agent
每周下载量也超过 100 万,
0.82.1
刚在 7 月底发布。
截图 P02 · 仓库主页上的 Star、Fork 与最新版本
这波 Star 涨得确实很猛,Pi 的源码也很有意思。它既是终端里的 Coding Agent,也是一组可以单独复用的 TypeScript 包。它用很少的核心概念,把模型调用、工具执行、会话历史、终端界面和产品扩展分成了边界清楚的几层。
这篇文章就从一次 prompt 开始,顺着真实调用链拆开 Agent Loop、双队列、三层上下文、JSONL Session 树、Compaction、并行工具、Extensions、Provider 抽象和差分 TUI,最后用 3 个无需 API Key 的 TypeScript 实验把关键行为跑一遍。

先看 Pi 分开了哪些边界

先把这六个分工记住,后面读源码会顺很多:
01
Agent Loop 只管协议核心。
它负责模型、工具、消息和循环终止;CLI、会话保存、资源发现、权限策略留在上层。
02
Steering 与 follow-up 是两种不同的“用户又说了一句话”。
前者在当前任务的下一个安全边界插入,后者等当前任务本来要停时再开始。
03
历史记录、Agent 运行消息和 Provider 消息分成三层。
分层以后,分支、压缩、自定义消息和跨模型转换各自处理,互不污染。
04
Session 使用带
id/parentId
的追加日志。
分支和回退由路径选择完成,无需反复覆盖聊天数组或复制整段对话。
05
Extensions 是进程内中间件。
它能改请求、拦工具、加状态,也拥有宿主进程的完整权限,能力远远超过一个界面小插件。
06
Pi 的“极简”指核心窄、组合面宽。

0.82.1
时,上层已经同时存在
AgentSession

AgentHarness + Session
两条路径;理解迁移中的复杂度,比背一张四层架构图更重要。
图解 P03 · Agent Loop 与产品编排层的边界

1. Pi 为什么值得拆开看

很多 Agent 教程从 ReAct 伪代码开始:
Output
while not done:
response = model(messages, tools)
execute(response.toolCalls)
append(toolResults)
这段代码能解释 demo,却解释不了一个长期运行的 Coding Agent:

模型正在执行工具时,用户插话怎么办?

同一轮返回三个工具调用,是并行还是串行?

两个写文件操作撞到同一路径怎么办?

会话太长后,既要压缩又要保留精确约束,怎么表示?

从历史节点重开一条分支,旧分支是否还在?

Anthropic 会话切到 OpenAI,历史消息怎样过 Provider 边界?

项目里的
AGENTS.md
、Skills、Extensions 谁先加载?

终端每秒刷新几十次,怎样避免整屏闪烁?

“项目已信任”是否等于命令已被沙箱隔离?
Pi 把这些问题分散到几个可以观察、替换和测试的协议面。沿着一次请求走下去,就能看到每一层在什么时候接手,又在什么时候把控制权交出去。

2. 别人怎么分析 Pi:两种视角,一条共同主线

在读源码前,先看两篇最有代表性的一手分析。

2.1 Mario Zechner:从”不满意什么”倒推最小产品

Pi 作者 Mario Zechner 在
What I learned building an opinionated and minimal coding agent
里跳过类图,直接从实际痛点出发:上下文被不透明地处理、Provider 差异泄漏、TUI 体验不稳定、内置功能不断变厚。
他的答案带有明确取舍:

system prompt 保持小;

核心工具保持少;

Provider 差异放进
pi-ai


TUI 用差分渲染;

MCP、plan mode、subagents 等能力不急着塞进默认核心。
它写于 2025 年,很适合用来理解 Pi 为什么保持 opinionated and minimal;到了
0.82.1
,具体运行链仍要回到当前源码确认。

2.2 Armin Ronacher:小核心的意义是让上层产品接管

Armin Ronacher 在
Pi: The Minimal Agent Within OpenClaw
中关注另一件事:Pi 可以把很多能力留给扩展,只要扩展可以持有状态、修改行为,Agent 甚至可以帮助用户继续改造 Agent。
OpenClaw 源码里也能看到 Pi 的 core/coding-agent 包。换句话说,
Pi 这个窄核心,确实能被更大的产品接过去继续搭
。至于 GitHub 热度究竟由谁推动,现有资料还给不出单一答案。

2.3 两篇分析之后,还要回到当前源码

两篇文章都抓住了“小核心、宽扩展面”,对应的版本和关注点却各不相同。要弄清
0.82.1
怎样运行,还得把设计观点落回当前源码,再用可重复的实验检查结果:
图解 P05 · 从设计动机走到完整调用链

3. 第一处容易画错的图:Pi 当前有两条上层路径

仓库根目录可以看到四个常被介绍的核心包:
包:
pi-ai
责任:
模型、Provider、认证、流式事件、消息协议
包:
pi-agent-core
责任:
Agent

agentLoop
、工具协议,以及新的 Harness/Session
包:
pi-coding-agent
责任:
官方 CLI、资源加载、Extensions、旧 SessionManager、各运行模式
包:
pi-tui
责任:
终端组件、输入、布局、差分渲染
只画这四个方框,还会漏掉
0.82.1
里两条并存的上层调用路径:
图解 P06 · 官方 CLI 的 AgentSession 路径
图解 P07 · 自定义应用的 AgentHarness 路径
这两条路径承担着不同职责:

AgentSession
是官方 CLI 的产品编排器,处理模型切换、扩展、会话、压缩、重试、bash、分支等大量能力。

AgentHarness

pi-agent-core
新的可复用编排器,拥有自己的
Session
、Storage、资源和工具上下文。

两条路径最后都会把模型—工具循环交给
Agent
/
agentLoop

后面讲 Session 时,我会把“CLI 旧路径”和“新 Harness 路径”标出来,免得两套实现看串。把它们的字段拼进同一个类,照着源码只会越看越乱。

4. 一次 prompt 到底经过了什么

把 UI 细节先折叠,一次请求的主干如下:
图解 P08 · 一次 prompt 的完整主链
这里有三个重要边界:
01
Product → Agent
:决定资源、会话、策略、模型和 UI。
02
Agent → Loop
:把状态包装成一次可执行循环,并提供队列。
03
Loop → Provider/Tool
:执行“模型响应—工具结果—继续模型”的状态机。
顺着这条链看,
Agent
就是一个 stateful wrapper:它持有消息、模型、工具、订阅者和两类待处理消息队列。低层 loop 只处理协议,无需了解 TUI 或 Session 存储。

5. Agent Loop:一个 while 为什么不够

核心实现位于
packages/agent/src/agent-loop.ts
。删去事件和异常处理后,它更接近:
TypeScript
let pending = await getSteeringMessages();
while (true) {                         // 外层:follow-up
let hasMoreToolCalls = true;
while (hasMoreToolCalls || pending.length > 0) { // 内层:工具 + steering
appendPendingMessages(pending);
const assistant = await streamAssistantResponse(context);
const batch = await executeToolCalls(assistant.toolCalls);
appendToolResults(batch.messages);
context = (await prepareNextTurn())?.context ?? context;
if (await shouldStopAfterTurn()) return;
pending = await getSteeringMessages();
}
const followUps = await getFollowUpMessages();
if (followUps.length === 0) break;
pending = followUps;
}
图解 P09 · Agent Loop 的内外两层循环
几个很容易漏掉的细节:

Provider 因 token limit 截断了带工具参数的响应时,Pi 会跳过这些可能已损坏的参数,并把整批工具调用标成失败。

prepareNextTurn
可以替换下一轮 context、model、thinking level;它

负责终止。终止属于
shouldStopAfterTurn


turn_end
在 prepare/stop 判断之前发出,因此观察者能拿到完整本轮 assistant message 和 tool results。

loop 不直接读 UI,也不直接写 JSONL;这些都是上层责任。
截图 P10 · 真实源码里的双层 runLoop
Lab 01:用假 Provider 看完整工具闭环
examples/01-agent-loop.ts
注册一个
sum
工具,让 faux provider 第一次返回 tool call,第二次返回最终答案。
Terminal
npm install
npm run lab:loop
预期关键结果:
Output
provider calls: 2
lab 01 passed
为什么一定是两次?第一次模型只能“请求执行工具”;工具结果作为
toolResult
进入上下文后,还要再次调用模型,模型才产生面向用户的最终回答。把“调用工具”和“回答用户”混成一次,是很多手写 demo 的第一个坑。

6. 双队列:Steering 和 Follow-up 各管什么

Agent
内部维护两个
PendingMessageQueue


steer(message)
:影响正在进行的任务;

followUp(message)
:等任务自然结束后,再追加一项工作。
图解 P11 · Steering 与 follow-up 的任务边界
为什么不用一条队列加
priority

两条队列首先区分
属于哪个任务边界
,然后才体现执行顺序:

Steering 要让当前轨迹尽快改道,例如“先别改这个文件”“输出改中文”。

Follow-up 不该扰动当前轨迹,例如“做完再跑一次测试”“最后写总结”。
Agent.steer()
/
followUp()
只负责入队;何时排空由前面的双层 loop 定义。
Lab 02:在工具执行时同时插入两类消息
examples/02-steering-followup.ts
在收到
tool_execution_start
事件时同时排入 steering 和 follow-up。断言的用户消息顺序是:
Output
开始演示。
→ 先把输出改成中文。
→ 做完以后,再确认双队列都已清空。
运行:
Terminal
npm run lab:queues
这里故意用了 faux provider。不用猜真实模型会不会照做,两类消息进入上下文的先后顺序一眼就能看清。

7. 上下文要分三层:历史、运行消息与 Provider 请求

Agent 系统最常见的架构债,是把“磁盘历史”“运行时消息”“Provider 请求体”都叫
messages
,然后在同一个数组上做删除、压缩和格式兼容。
Pi 的链路可以抽象成三层:
图解 P13 · 三层上下文怎样逐步转换

7.1 持久层:保留事实和结构

这里存的不只是 user/assistant message,还可能有:

model change;

thinking level change;

tool set change;

compaction;

branch summary;

自定义 entry。
它的目标是可恢复、可分支、可审计,不要求每条都能直接发给模型。

7.2 运行层:Agent 能理解的统一消息

AgentMessage[]
可以容纳工具结果和应用自定义消息。Session 在
buildContext()
时只取当前活动分支,并把 compaction 转成
compactionSummary

7.3 Provider 层:模型最终会收到什么

每轮请求前,loop 先执行:
TypeScript
messages = await transformContext(messages);
llmMessages = await convertToLlm(messages);
transformContext → convertToLlm
这两个钩子解决不同问题:

transformContext
:本轮要不要裁剪、注入或改写 Agent 视图;

convertToLlm
:某种 AgentMessage 如何变成 Provider 接受的角色和 content blocks。
压缩上下文时可以保留原始历史;跨模型切换时也无需把 Provider 私有格式写回 Session。

8. Session 树:追加日志比覆盖数组更适合 Agent

Pi 的 CLI
SessionManager
使用 JSONL v3,每个 entry 有
id

parentId
。新 Harness Session 也保留同样的树语义,并可接不同 Storage。
假设先走了 A 分支,后来回到节点 2 改走 B:
图解 P14 · Session 追加树与活动分支
底层不必删除
3A/4A
,也不必复制
1/2
。只需要:
Output
1.parentId  = null
2.parentId  = 1
3A.parentId = 2
4A.parentId = 3A
3B.parentId = 2
4B.parentId = 3B
“当前会话”就是从 leaf 沿
parentId
回溯到 root 的一条路径,branch/rewind 也就成了树遍历问题。

8.1 Compaction:摘要与原始历史同时保留

上下文超过阈值后,Pi 会把较早的活动路径压成 summary,同时保留最近的精确消息。这里必须区分当前两代协议:
路径:
CLI
SessionManager
压缩边界:
firstKeptEntryId
指向仍需按树路径读取的第一条 entry
路径:
新 Harness
Session
压缩边界:
可把
retainedTail: AgentMessage[]
直接物化进 compaction entry
图解 P15 · 两代 Compaction 协议
retainedTail
的好处是读取上下文时可以在检查点停止向旧历史回溯;旧格式仍需通过
firstKeptEntryId
找到保留区间。官方 session-format 文档同时描述两者,
0.82.1
源码则把它们放在两条不同的 Session 路径中。
Lab 03:分支 + 自包含 Compaction
examples/03-session-tree.ts
使用新
InMemorySessionStorage

01
建立共同祖先;
02
写入旧分支;
03
moveTo(branchPoint)
后写入新分支;
04
断言 Provider context 不含旧分支;
05
追加 summary +
retainedTail

06
断言重建后只得到
compactionSummary → user

Terminal
npm run lab:session
跑完这个实验可以直接看到:
历史仍然存在

本轮模型看见什么
是两个问题。

9. 工具系统:协议、执行策略、产品操作层要分开

一个 Pi 工具至少包含:
TypeScript
const sumTool: AgentTool = {
name: “sum”,
label: “Sum”,
description: “Add two numbers.”,
parameters: Type.Object({
left: Type.Number(),
right: Type.Number(),
}),
async execute(_toolCallId, params) {
return {
content: [{ type: “text”, text: String(params.left + params.right) }],
details: {},
};
},
};
这里有三种契约:

parameters
是给模型和运行时验证共同使用的 schema;

content
会回到模型上下文;

details
给 UI、扩展或应用保存结构化信息,不必污染模型文本。
完整执行管线比
tool.execute(args)
多:
图解 P16 · 工具从调用到返回模型的管线
对应源码在
executeToolCalls
及后续 prepare/finalize 函数中。

9.1 默认并行,但”本批有一个 sequential”会整批串行

agentLoop
的选择规则是:
TypeScript
if (
config.toolExecution === “sequential” ||
toolCalls.some(call => tool(call).executionMode === “sequential”)
) {
executeBatchSequentially();
} else {
executeBatchInParallel();
}
只要本批有一个工具声明
executionMode: “sequential”
,当前 assistant message 中的整批 tool calls 都会串行。这个设计牺牲部分吞吐,换取更容易推断的批内行为。
即使并发完成顺序不同,结果仍按原始 tool-call 顺序写回消息,避免上下文因网络时序漂移。

9.2 工具并行以后,写文件竞争仍要单独处理

Coding Agent 还需要产品层约束。例如当前代码有 file mutation queue:

同一 canonical path 的修改串行;

不同文件可以并行。
这类约束不该塞进通用
agentLoop
,因为数据库事务、远程部署、浏览器操作各有自己的冲突键。通用核心只提供并发协议,产品层定义资源锁。

9.3 Operations / ExecutionEnv 是可测试性的来源

如果工具内部到处直接调用
fs

spawn

process.cwd()
,测试和嵌入都会变难。Pi 的两条上层路径分别有 operations adapters 或
ExecutionEnv/ToolContext
,把文件、进程、路径等能力显式交给工具。
工程上可以把它理解成:
Output
Tool = Schema + Pure decision + Injected side-effect adapter
它不会自动提供安全隔离,但能让 mock、远程执行和策略拦截有明确入口。

10. Context Files、Skills、Extensions:名字相近,运行时地位不同

三者都会影响 Agent,只是进入系统的位置和拥有的权限各不相同。
机制:
AGENTS.md
/
CLAUDE.md
进入系统的方式:
文本进入 system prompt 上下文
主要用途:
项目约定与长期指令
权限:
文本本身不执行代码
机制:
Skills
进入系统的方式:
先暴露名称/描述,需要时再读完整内容
主要用途:
渐进披露的领域工作流
权限:
取决于随后调用的工具
机制:
Extensions
进入系统的方式:
注册进程内事件处理器、工具、命令、UI
主要用途:
改行为、持有状态、接外部系统
权限:
宿主进程完整权限
10.1 Context files 的当前遍历顺序
loadProjectContextFiles()
先读全局 agentDir,然后从文件系统根到 cwd 按祖先顺序追加 context files。遍历范围会越过 Git root,一直覆盖到文件系统祖先目录。
10.2 Skills 怎样省上下文:按需加载
系统提示词不必塞入所有领域知识,只先告诉模型“有哪些 Skill、分别做什么”。模型判断需要时,再读取完整说明和关联资源。
这套机制节省的是 token 和注意力预算;权限仍由随后调用的工具和运行环境决定:
Output
Discover cheaply → Select deliberately → Load details on demand
10.3 Extensions 是事件总线上的中间件
典型生命周期可以压缩成:
图解 P17 · Extensions 的关键生命周期
实际还有消息、header 等更细事件。架构重点是:

tool_call
可在执行前阻断;多个 handler 中第一个明确阻断者生效;

tool_result
可被后续 handler 继续加工;

扩展可以加工具、命令、快捷键、UI,也可以保留跨事件状态。
这类钩子很适合放产品策略,完整的安全隔离仍要交给沙箱。只靠正则识别高风险 shell 命令,漏掉等价写法很容易。仓库里也就没有放一段看起来能直接复制、实际边界却兜不住的“安全代码”。

11. pi-ai:统一调用协议,保留模型差异

pi-ai
:统一调用协议,保留模型差异
Provider 抽象负责统一下面这些调用协议:

模型元数据;

API Key / OAuth 获取;

请求参数;

流式事件;

text / thinking / toolCall content blocks;

usage、stop reason、错误;

各家 wire protocol 与统一消息之间的转换。
图解 P18 · pi-ai 统一调用协议
Provider 应该负责“怎样可靠地调用这个模型”,上层 Agent 负责“为什么现在要调用、上下文放什么、拿到 tool call 后怎么办”。
这层分离还有一个实际收益:Session 保存统一的语义消息,切换模型时再为目标 Provider 转换,避免把上一家 API 的私有请求体永久写入历史。
但 Provider 抽象无法抹平:

工具调用质量差异;

reasoning/thinking 语义差异;

system/developer role 支持差异;

上下文窗口与缓存策略;

对历史 thinking block 的限制。
能切模型,说明协议已经接通;不同模型能不能给出同等质量的结果,还得单独验证。

12. TUI:流式 Agent 为什么不能每次 console.log

console.log
流式响应、spinner、tool progress、图片和多行编辑器会持续变化。如果每次都重画全屏,终端容易闪烁、滚动、错位。
pi-tui
保存上一帧渲染行,与新帧比较:
01
没变化:只更新硬件光标;
02
变化发生在旧 viewport 之上:完整重绘;
03
否则:只清除并重画变化区间;
04
更新放进 CSI 2026 synchronized output,尽量原子显示。
图解 P19 · TUI 差分渲染决策
差分渲染源码
中还能看到 Kitty images 对变化区间和保留行数的影响。
Agent UI 要处理持续变化的语义状态。底层发出语义事件,TUI 再决定怎样呈现,模型层就不会被终端控制码、刷新策略和布局状态反向污染。

13. 安全边界:Project Trust 与 Sandbox 各管一层

Pi 官方 README 写得很直接:默认没有内置 permission system。需要隔离时,可以使用 Gondolin、Docker 或 OpenShell。当前 project trust 主要控制项目本地扩展、包和设置等资源何时加载。
图解 P20 · Project Trust 与真正沙箱的边界
必须分清:

Project trust
:输入与项目资源加载决策;

Extension policy
:应用层允许/阻断某类行为;

OS/container sandbox
:真正限制文件、网络、进程能力。
官方
Security 文档
还指出,
AGENTS.md
/
CLAUDE.md
context files 默认不因拒绝 trust 而全部消失,除非关闭 context loading。拒绝 trust 后,部分项目文本仍可能进入上下文。
截图 P21 · Project Trust 控制资源加载,官方同时提醒它并非 Sandbox
给企业 Agent 增加安全能力时,至少要分别回答:
01
哪些文本可以进入上下文?
02
哪些代码/扩展可以在宿主进程加载?
03
哪些工具调用需要策略审批?
04
即使策略失效,操作系统还限制了什么?
05
谁能看到完整审计记录?
把这五问压成一个
isTrusted: boolean
,迟早会出边界事故。

14. 三个实验怎样一起跑

环境要求:Node.js

=22.19.0

Terminal
git clone https://github.com/uiuing/pi-agent-system-design.git
cd pi-agent-system-design
npm ci
npm test
脚本:
命令:
npm run lab:loop
验证内容:
tool call → tool result → 第二次模型调用
命令:
npm run lab:queues
验证内容:
steering / follow-up 的进入顺序和 3 个 turn
命令:
npm run lab:session
验证内容:
Session 分支选择与 retainedTail compaction
命令:
npm run typecheck
验证内容:
三个示例的类型检查
命令:
npm run audit:prod
验证内容:
检查运行时依赖的已知安全问题
命令:
npm test
验证内容:
类型检查与三个确定性实验
三个实验都用了 faux provider,目的很简单:先把模型随机性拿掉,让 loop、队列和 session 的行为可以稳定复现。真正值得看的,是它们串起来后的主线:模型怎样调用工具,用户插话怎样进入下一轮,会话又怎样在分支和压缩后重建上下文。
等理解协议后,再把
faux.getModel()
和 stream function 换成真实 Provider 就完成了模型接入,Agent Loop 的协议保持不变。

15. 如果自己从零做一个 Agent,建议按这个顺序

不要第一天就做完整 TUI、插件市场和多 Agent。可以按六个可验收阶段推进:
15.1 先完成确定性 Loop

统一 assistant text / toolCall / toolResult;

tool call schema 校验;

明确 stop reason;

用假 Provider 测两轮闭环;

token 截断时禁止执行不完整参数。
验收:一条无网络测试能稳定复现
model → tool → model

15.2 再加事件,让 UI 只订阅公开状态

message start/update/end;

tool start/update/end;

turn start/end;

agent start/end/settled。
验收:CLI、Web UI、日志记录器只订阅事件,不修改 loop 私有变量。
15.3 把插话语义做成两条队列

steering 明确在 turn 边界注入;

follow-up 明确在任务停止点注入;

定义一次排空一条还是全部;

abort 与队列清空分别处理。
验收:像 Lab 02 一样,不靠计时猜测也能断言顺序。
15.4 持久化使用追加树

entry 有稳定 id、parentId、timestamp;

当前 leaf 单独记录;

buildContext 只构建活动路径;

分支不删除旧历史;

migration 有明确版本号。
验收:回到祖先重开分支后,两条路径都可恢复。
15.5 把上下文压缩设计成协议

summary 与保留尾部有独立字段;

精确约束不要只依赖摘要;

压缩前后的 token 计数可审计;

新格式做自包含 checkpoint;

旧格式读取路径有兼容测试。
验收:连续两次压缩后,当前请求和关键约束仍能稳定重建。
15.6 最后才扩展 Provider、Extensions 和 TUI

Provider 只处理模型调用差异;

Extension 事件明确先后、冲突和错误策略;

高风险能力放进可隔离的执行环境;

TUI 根据语义事件做差分渲染;

上层编排只有一个明确主路径,迁移期则写清兼容边界。
验收:核心 loop 的测试不需要启动终端、不需要真实文件系统、也不需要真实 API。

16. 哪些 Pi 设计值得抄,哪些不能照抄

值得抄
01
核心 loop 不知道产品 UI。
02
运行消息与 Provider 消息分层。
03
双队列把交互语义写进协议。
04
追加 Session 树保留历史与分支。
05
工具 content/details 分离。
06
假 Provider 让核心行为可确定测试。
07
差分 TUI 消费事件,而不侵入模型循环。
照抄前要补齐的边界
01
工具数量少,权限风险依然可能很大。
02
扩展能力再强,默认产品仍要补上验证、审批和审计。
03
Provider 接口统一以后,模型之间仍然存在语义和效果差异。
04
工具支持并行以后,文件、数据库和远程资源仍会发生冲突。
05
JSONL 格式看起来简单,分支、压缩、自定义 entry 仍需要版本和兼容测试。
06
核心保持极简,整个代码库依然会承担迁移和产品编排的复杂度。当前双上层路径就是一个现实例子。
拆完这一圈,我最想带走的是 Pi 对边界的处理:
把模型循环做窄,把上下文协议写清,把产品选择留在上层,同时让每一层都能独立测试。

17. 源码阅读地图

按这条顺序读,比从仓库根目录漫游更快:
01
packages/agent/src/agent-loop.ts
— 先理解内外循环、上下文转换和工具执行。
02
packages/agent/src/agent.ts
— 看 stateful wrapper 和双队列怎样接入 loop。
03
packages/coding-agent/src/core/agent-session.ts
— 看官方 CLI 如何编排会话、模型、扩展、压缩和重试。
04
packages/agent/src/harness/agent-harness.ts
— 对比新的可复用 Harness 路径。
05
packages/coding-agent/src/core/session-manager.ts

packages/agent/src/harness/session/session.ts
— 对比两代 Session/Compaction。
06
packages/coding-agent/src/core/extensions
— 看事件类型、runner 和冲突规则。
07
packages/tui/src/tui.ts
— 最后看差分渲染,避免被 UI 细节打断主线。

参考资料

Pi official repository, documentation and npm package|GitHub: earendil-works/pi|npm: @earendil-works/pi-coding-agent
What I learned building an opinionated and minimal coding agent|Mario Zechner
Pi: The Minimal Agent Within OpenClaw|Armin Ronacher
OpenClaw official repository|GitHub: openclaw/openclaw
Pi Security|Pi Documentation

  • 标题: 一口气学会 Pi Agent 系统设计:从一次 prompt 拆开 7.9 万 Star 的 Coding Agent
  • 作者: 小糊有话说(微信转载)
  • 创建于 : 2026-07-29 16:00:00
  • 更新于 : 2026-07-29 15:33:18
  • 链接: https://blog.lxiol.cn/2026/07/29/pi-agent-system-design/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
目录
一口气学会 Pi Agent 系统设计:从一次 prompt 拆开 7.9 万 Star 的 Coding Agent