【AI Coding】5-Pi Agent Harness:一个极简终端编码Harness的解构
- [Pi Agent Harness:一个极简终端编码 Harness 的解构](#Pi Agent Harness:一个极简终端编码 Harness 的解构)
-
- [一、先问一个问题:为什么编码 Agent 需要一个"框架"?](#一、先问一个问题:为什么编码 Agent 需要一个"框架"?)
- [二、Pi 是什么:一个"极简终端编码 Harness"的自我定义](#二、Pi 是什么:一个"极简终端编码 Harness"的自我定义)
-
- [2.1 官方定位一句话](#2.1 官方定位一句话)
- [2.2 项目结构与规模](#2.2 项目结构与规模)
- [2.3 运行形态:不止"终端交互"](#2.3 运行形态:不止"终端交互")
- [三、小内核如何跑起来:四个默认工具 + 上下文管理](#三、小内核如何跑起来:四个默认工具 + 上下文管理)
- 四、扩展层:不改内核,怎么长出我们想要的能力
-
- [4.1 四类可定制资源](#4.1 四类可定制资源)
- [4.2 Extension:一个真实例子](#4.2 Extension:一个真实例子)
- [4.3 Skill:直接吃 Claude Code / Codex 生态](#4.3 Skill:直接吃 Claude Code / Codex 生态)
- [五、反内置哲学:不做权限弹窗、不做 MCP、不做子 Agent](#五、反内置哲学:不做权限弹窗、不做 MCP、不做子 Agent)
-
- [5.1 六个"没有"](#5.1 六个"没有")
- [5.2 为什么"不做"反而是设计](#5.2 为什么"不做"反而是设计)
- [六、生态图景:Harness 正在变成一个"可换件"](#六、生态图景:Harness 正在变成一个"可换件")
-
- [6.1 Pi 生态里的三个样本](#6.1 Pi 生态里的三个样本)
- [6.2 Harness 概念的扩散:DeepSeek Harness](#6.2 Harness 概念的扩散:DeepSeek Harness)
- [七、动手:从零跑起 Pi,并在十分钟内验证 Harness 的价值](#七、动手:从零跑起 Pi,并在十分钟内验证 Harness 的价值)
-
- [Step 1 安装](#Step 1 安装)
- [Step 2 验证 Context 文件加载](#Step 2 验证 Context 文件加载)
- [Step 3 导入已有 Skill](#Step 3 导入已有 Skill)
- [Step 4 加一个扩展做路径保护](#Step 4 加一个扩展做路径保护)
- [八、结论:我们该怎样理解 Harness?](#八、结论:我们该怎样理解 Harness?)
- 参考资料
Pi Agent Harness:一个极简终端编码 Harness 的解构
前四篇 我们依次解决了四个问题:上下文演化、Skill 体系设计、Skill 精准触发、多 Agent 协同与成本边界。
本篇切入一个更高频的问题:当 Claude Code、Codex、Cursor、OpenCode、Pi 这些终端编码工具摆在一起,我们到底在选择什么?答案是 Harness ------模型之外的整套运行框架。
本文以 2025 年 8 月诞生、至今仍保持"极简内核"定位的 Pi Agent Harness(作者 Mario Zechner / badlogic,MIT 协议)为主线,拆解 Harness 的职责边界、Pi 的设计取舍,以及"模型换着用、工具链不变"的工程化意义。
一、先问一个问题:为什么编码 Agent 需要一个"框架"?
我们回到第一性原理。单把模型接上终端,会发生什么?
- 模型第一次调用时看到的是一个裸文件系统。它不知道项目该往哪里写代码,不知道测试怎么跑,不知道哪些目录碰不得。
- 一个"知识渊博但双手空空"的模型,和一个"能读文件、能改文件、能执行命令"的模型,是两种完全不同的产品。差距不在模型,而在模型和操作系统之间的那层胶水。
- 这层胶水要回答的具体问题包括:模型能不能调用工具、用哪几个工具、工具结果如何进入上下文、对话历史存在哪、上下文满了怎么办、读写操作要不要经过批准。
这层胶水,业界现在称之为 Harness(运行框架/挽具)。它的核心矛盾在于方向完全相反的两个诉求:
| 诉求 | 表现 |
|---|---|
| 开箱即用 | 装完就能干活,默认能力覆盖多数任务 |
| 可塑性 | 换模型、加工具、改交互,不修改内核源码也能做到 |
Claude Code、Codex、Cursor 的处理方式,是在各自编辑器/CLI 生态里把 Harness 做厚;而 Pi 选择了另一条路:把内核压到最小,把扩展做成一等公民。
我们之前提到过"从 rules 到 skills、再到 harness"的演化(见系列第 0 篇)。Pi 恰好是这个演化链条里最典型的样本:它不推销任何"全家桶",而是提供一个可以拼装的最小骨架。
二、Pi 是什么:一个"极简终端编码 Harness"的自我定义
2.1 官方定位一句话
Pi 的官方仓库对自己的定义非常明确(pi-mono README):
Pi is a minimal terminal coding harness. adapt pi to our workflows, not the other way around, without having to fork and modify pi internals.
把它翻成工程语言就是三件事:
- Harness,不是模型,也不是 IDE。它不训练模型、不替我们决定编辑器,只负责"让一个通用模型在一个真实项目里安全地干活"。
- 适配工作流的是使用者,不是反过来 。Pi 不搞"功能全家桶",默认只给四个工具:
read、write、edit、bash,加上可选的grep、find、ls(Quickstart 文档)。 - 不改内核也能扩展。扩展方式是 TypeScript Extension、Skill、Prompt Template、Theme 四类资源,可以打包成 Pi Package 用 npm 或 git 分发。
2.2 项目结构与规模
Pi 是一个 monorepo,包结构本身就是"Harness 该拆成几块"的标准答案(pi-mono README):
| 包 | 职责 |
|---|---|
@earendil-works/pi-ai |
统一多提供商 LLM API(OpenAI / Anthropic / Google / Bedrock / 国产各家等 20+ 家) |
@earendil-works/pi-agent-core |
Agent 运行时:工具调用 + 状态管理 |
@earendil-works/pi-coding-agent |
交互式编码 Agent CLI(终端 TUI) |
@earendil-works/pi-tui |
终端 UI 库(差分渲染) |
@earendil-works/pi-telemetry |
厂商中立遥测契约 |
这五个包回答的问题分别是:怎么连模型(pi-ai)、怎么跑 Agent 循环(pi-agent-core)、怎么和人类交互(pi-coding-agent + pi-tui)、怎么观察它(pi-telemetry)。Harness 的职责可以被拆成这四层,这是我们在其他工具里看不到的清晰分层。
2.3 运行形态:不止"终端交互"
Pi 有四种运行形态,这决定了它能被嵌入任何地方(coding-agent README):
| 形态 | 命令/方式 | 适用 |
|---|---|---|
| 交互模式 | pi |
日常在项目里对话干活 |
| 打印/JSON 模式 | pi -p "..." / --mode json |
一次性提问、脚本化调用、CI 里做检查 |
| RPC 模式 | --mode rpc |
通过 stdin/stdout JSONL 协议被 IDE、其他程序嵌入 |
| SDK 嵌入 | AgentSession |
Node/TS 应用里直接内嵌 Agent 会话 |
RPC 模式是 Pi 作为 Harness 最有说服力的一点:它不要求使用者"用它的界面",而是把 Agent 会话当作一个可以编程控制的子进程对象暴露出来(RPC 文档)。对做企业级 Agent 平台的团队来说,这意味着 Pi 可以成为底座,而不是一个孤立玩具。
三、小内核如何跑起来:四个默认工具 + 上下文管理
3.1 极简的默认工具集
Pi 默认给模型的四个工具,恰好覆盖编码 Agent 的最小闭环(Quickstart 文档):
| 工具 | 能力 | 备注 |
|---|---|---|
read |
读文件 | 只读,安全 |
write |
创建/覆盖文件 | 写操作 |
edit |
打补丁改文件 | 写操作 |
bash |
执行 shell 命令 | 最高风险 |
反直觉点:工具越少,模型越不容易选错。我们在系列第 3 篇讲过"工具超过 15 个模型会陷入选择困难",Pi 把默认集压到 4 个,等于直接把这类问题挡在设计层面。需要更多能力时,用 Skill / Extension 按需加,而不是一开始全塞给模型。
3.2 上下文来源:AGENTS.md 分层加载
Pi 启动时会按层加载上下文文件(Quickstart 文档):
~/.pi/agent/AGENTS.md # 全局指令
父目录逐级向上的 AGENTS.md / CLAUDE.md
当前目录的 AGENTS.md / CLAUDE.md
AGENTS.override.md # 存在时替换同目录 AGENTS.md/CLAUDE.md
这套设计解决了两个实际问题:一是项目约定(跑什么检查、不能动哪个目录)可以直接放进仓库随代码走;二是它兼容已有的 Claude Code 生态文件(CLAUDE.md),迁移成本低。
3.3 会话管理:JSONL + 树状分支
Pi 的会话以 JSONL 文件存在 ~/.pi/agent/sessions/,按工作目录组织(Sessions 文档)。每个会话是一棵树,不是一条线:
| 能力 | 命令 | 场景 |
|---|---|---|
| 继续最近会话 | pi -c |
早上接着昨晚的活 |
| 浏览历史会话 | pi -r |
找回上周做过的任务 |
| 从历史点分支 | /fork、/tree |
"换个思路重来",保留原分支 |
| 克隆当前分支 | /clone |
在副本上尝试方案,不动主线 |
树状存取是 Harness 层解决"上下文探路成本"的关键:试错不再是不可逆的,想回到某个决策点,从那个节点再分一条路即可。
3.4 压缩:上下文满了以后发生什么
Pi 的自动压缩机制是"可被审计"的(Compaction 文档),触发条件是一个明确的公式:
contextTokens > contextWindow - reserveTokens
默认 reserveTokens 为 16384(给模型留响应空间);触发后从最新消息往回找,保留最近约 20k token(keepRecentTokens 默认值),更老的部分交给模型生成结构化摘要,存成一条 CompactionEntry(带 firstKeptEntryId 锚点),后续请求用"摘要 + 保留消息"重建上下文。
这个过程和我们的老熟人"上下文衰减"(系列第 0 篇)正面相遇:压缩不是简单截断,而是把老信息转成摘要、把文件操作追踪累积保留,让模型"忘了细节但记得结论"。
四、扩展层:不改内核,怎么长出我们想要的能力
4.1 四类可定制资源
Pi 把"改行为"的入口收敛成四类(coding-agent README):
| 资源 | 是什么 | 什么时候用 |
|---|---|---|
| Extension | TypeScript 模块,可注册工具/命令/事件钩子 | 要动运行逻辑:权限闸门、git 检查点、路径保护 |
| Skill | 目录 + SKILL.md,按需加载的能力包 |
复用 Claude Code / Codex 生态的 Skill |
| Prompt Template | 从斜杠命令展开的复用提示词 | 把常用提问固化成 /review、/deploy |
| Theme | 终端主题 | 界面观感 |
4.2 Extension:一个真实例子
官方文档给的权限闸门例子,直接演示了 Extension 如何拦截危险命令(Extensions 文档):
typescript
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
// 监听工具调用事件,拦截 rm -rf / sudo
pi.on("tool_call", async (event, ctx) => {
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
const ok = await ctx.ui.confirm("危险操作", "允许 rm -rf 吗");
if (!ok) return { block: true, reason: "Blocked by user" };
}
});
// 注册一个自定义工具
pi.registerTool({
name: "greet",
description: "向指定姓名打招呼",
parameters: Type.Object({ name: Type.String() }),
async execute(toolCallId, params) {
return { content: [{ type: "text", text: `Hello, ${params.name}` }] };
},
});
}
这段代码的三层含义:
- 能力即钩子 :
tool_call事件是所有安全策略的接入点,不 fork 源码就能加权限控制。 - 工具即函数 :
registerTool让任何 TypeScript 能力(内部服务、DB、CI)变成模型可调用的工具,签名就是参数 Schema。 - 信任边界自建:Pi 默认不给任何权限弹窗,但允许使用者用 Extension 自建审批流------要不要批准、怎么批准,由项目自己定。
4.3 Skill:直接吃 Claude Code / Codex 生态
Pi 的 Skill 机制遵循 Agent Skills 规范(agentskills.io),并且可以在设置里直接导入其他 Harness 的 Skill 目录(Skills 文档):
json
{
"skills": ["~/.claude/skills", "~/.codex/skills"]
}
一个 Skill 的标准结构是:
my-skill/
├── SKILL.md # frontmatter(name+description) + 使用说明
├── scripts/ # 辅助脚本
└── references/ # 按需加载的详细文档
加载机制是渐进式披露:启动时只把每个 Skill 的 name/description 放进系统提示,任务匹配时才让模型用 read 读完整 SKILL.md。这正是我们在系列第 2 篇讲的机制,Pi 直接采用同款协议。
这就是 Harness 生态的价值:Skill 不再绑定某个工具,
~/.claude/skills里的资产在 Pi 下直接复用。对个人来说,等于一次沉淀、到处可用。
五、反内置哲学:不做权限弹窗、不做 MCP、不做子 Agent
5.1 六个"没有"
Pi 的 Philosophy 部分列了一串"我们刻意不做"(coding-agent README):
| 不做 | 替代方案 |
|---|---|
| MCP | 用 CLI 工具 + Skill,或者用 Extension 自己加 MCP 支持 |
| 子 Agent | 用 tmux 起多个 Pi 实例,或用 Extension 自建 |
| 权限弹窗 | 容器化,或用 Extension 自建确认流 |
| Plan 模式 | 把计划写进文件,或用 Extension 实现 |
| 内置 Todo | 用 TODO.md 文件 |
| 后台 bash | 用 tmux,全程可见可交互 |
5.2 为什么"不做"反而是设计
这六个"没有"不是因为偷懒,而是三个明确判断:
- 内核最小化才能活下来。每内置一个功能,就多一层"使用者以为的默认"和"实际行为"的偏差,也就多一个被模型误用的面。
- 权限是组织问题,不是通用问题 。个人项目、开源仓库、企业合规的审批粒度完全不同,统一弹窗要么烦人要么漏风。Pi 的默认是"以启动进程的用户权限运行",需要边界时用容器(Gondolin / Docker / OpenShell 三套方案,Containerization 文档)做隔离。
- 工具间消息的不信任原则。我们在系列第 3 篇引过 OWASP 数据:73% 的部署容易受 Agent 通信通道注入攻击。Pi 把"Agent 间消息"直接从默认能力里拿掉,等于默认避开了整类攻击面。
需要指出的是,这套哲学有代价:新手第一次上手会觉得"这也缺那也缺"。Pi 的补偿是把扩展成本压到最低------官方文档里大量出现"问 Pi 让它再写一个 Extension",即用模型本身来补齐能力。
六、生态图景:Harness 正在变成一个"可换件"
6.1 Pi 生态里的三个样本
Pi 的仓库图谱展示了 Harness 的三种演化方向(均在 GitHub 上可查):
| 项目 | 关系 | 方向 |
|---|---|---|
| oh-my-pi (omp) | Pi 的 fork 分支 | 把内核做厚:60+ 提供商、31 个内置工具、LSP/DAP、浏览器、子 Agent |
| pie | Pi 的 Rust 移植 | 把内核做硬:原生性能 + 触发器/定时任务/有状态循环 |
| omnigent | 元 Harness(meta-harness) | 同时编排 Claude Code、Codex、Cursor、Pi,按任务切换 Harness |
| PI-Desktop | 基于 Pi 的桌面封装 | 把 Harness 包进本地优先的桌面应用,插件化扩展 |
这组项目说明一个问题:Harness 开始像 IDE 一样,成为可以"换件"的中间层。omnigent 的定位尤其直接------它把 Pi 与 Claude Code、Codex、Cursor 并列对待,用同一套策略层做沙箱、预算、审批。模型可以变,Harness 也可以变,但治理层不变,这正是企业最想要的组合方式。
6.2 Harness 概念的扩散:DeepSeek Harness
2026 年 8 月 13 日的技术动态日报里,我们记录过一个信号:DeepSeek 的更新日志提到"DeepSeek Harness 极简模式(即将发布)",当时的判断是"模型 + Harness 组合可能复刻 DeepSeek 时刻"(2026年8月13日_技术动态日报)。
把这一条和 Pi 放在一起看,就能发现行业的共识正在形成:模型厂商不再只发布 API,开始发布自己附带的运行框架。区别在于,DeepSeek Harness 是模型厂商想垂直整合到底,Pi 是开源的通用底座------前者绑定自家模型,后者对模型中立。对开发者来说,中立的 Harness 意味着不会被单一厂商锁死,模型的定价和能力的竞争红利都能享受。
七、动手:从零跑起 Pi,并在十分钟内验证 Harness 的价值
我们不追求全面,只验证三件事:能装、能连模型、能扩展。
Step 1 安装
bash
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
--ignore-scripts 关闭依赖生命周期脚本,降低供应链风险------这也呼应了官方把 npm 依赖当成"需要审查的代码"的工程纪律。macOS/Linux 也可以用 curl -fsSL https://pi.dev/install.sh | sh。
Step 2 验证 Context 文件加载
在项目根目录放一个 AGENTS.md:
markdown
# 项目约定
- 改完代码必须运行 npm run check
- 不要修改生产迁移脚本
- 回复保持简洁
启动 pi,问它"这个项目怎么跑测试",如果它引用了 npm run check,说明上下文注入链路正常工作。
Step 3 导入已有 Skill
json
// .pi/settings.json
{
"skills": ["~/.claude/skills", "~/.codex/skills"],
"enableSkillCommands": true
}
重启后 /skill: 命令能看到已存在的 Skill,验证跨 Harness 复用。
Step 4 加一个扩展做路径保护
在 ~/.pi/agent/extensions/ 放一个 .ts 文件,拦截对 .env 的写入:
typescript
pi.on("tool_call", async (event, ctx) => {
if (event.toolName === "edit" || event.toolName === "write") {
if (String(event.input.path ?? "").includes(".env")) {
return { block: true, reason: "Protect .env from edits" };
}
}
});
这一步验证的是"能力即代码":安全策略不是配置项,而是 TypeScript 模块,进 git、可测试、可协作。
验收标准不是"模型答得多好",而是这套骨架能不能被团队改造成自己的形状。十分钟内做到"模型任意换、Safety 自定义、Skill 复用存量资产",Pi 作为 Harness 的价值就成立了。
八、结论:我们该怎样理解 Harness?
把本篇的线索收拢成四个结论:
- Harness 是 AI Coding 的"工程题",不是"模型题"。同一批模型换一套骨架,生产率和风险完全不同。评估编码工具,先看它怎么管工具、上下文、权限、会话,再看模型列表有多长。
- Pi 提供了一种可复用的极简范本。五个包的分层(AI 接入 / Agent 循环 / 交互 / TUI / 遥测)、四个默认工具、树状 JSONL 会话、可审计压缩、TypeScript 扩展,任何团队自建 Agent 底座时都值得逐条对照。
- 生态正在把 Harness 变成可换件。omnigent 把 Pi 和 Claude Code、Codex 并列治理,DeepSeek 在发布自家 Harness------方向相反但都说明 Harness 正在成为基础设施层。
- 适用边界 :Pi 适合愿意自己拼装、已有 Claude Code/Codex Skill 资产、或需要把 Agent 嵌入自有系统的团队;不适合想要"开箱即用全家桶"、依赖子 Agent/Plan 模式/权限弹窗开箱即用的场景。选择 Harness 的标准不是功能数量,而是它能不能按使用者的形状生长。
参考资料
- badlogic/pi-mono(GitHub)
- Pi 官方文档 pi.dev/docs/latest
- pi-coding-agent README(含 Philosophy)
- Mario Zechner: What if you don't need MCP(2025-11-02)
- Mario Zechner: pi-coding-agent 设计说明(2025-11-30)
- oh-my-pi(GitHub)
- pie:Pi 的 Rust 移植(GitHub)
- omnigent:元 Harness(GitHub)
- PI-Desktop(GitHub)
- awesome-cli-coding-agents(GitHub)
- 技术动态日报 · 2026年8月13日(DeepSeek Harness 信号)