目标:看懂 dsh、Codex、Pi 三家 Coding Agent Harness 的实现思路,并抽出可迁移到自研 Agent 的方法论。

前置要求:了解 Agent 基本概念、工具调用与 Prompt。若关心「怎么评 Agent」,可接着读 Agent 评测体系搭建:从离线门禁到 LLM-as-a-Judge。

  本文信息来自三家官方站点与开源仓库:DeepSeek Harness、OpenAI Codex、Pi。目标不是抄说明书,而是回答两件事:它们各自怎么实现,以及哪些做法可以复用到自己的 Agent 上。

  阅读路径建议:先看第 1 节建立整体图景,再按兴趣钻进第 2 节的某一家,第 3 节把记忆 / Skill / 检索 / 多 Agent 等高频机制对照清楚,最后用第 4、5 节把方法论带走。


1. 先建立图景:Harness 到底在做什么

1.1 三个对象是谁

对象是什么官方定位一句话开源与许可
DeepSeek Harness(dsh)DeepSeek 开源的 Harness 架构与桌面 / Web 应用「一切皆插件」,可自由组合拓展 Agent 能力MIT,GitHub 开源
OpenAI Codex终端编码 Agent,并延伸到 IDE、云端、ChatGPT、桌面端把真正的工程活交给 Agent,多 Agent 并行验证CLI Apache-2.0
PiEarendil 的极简 Agent Harness「Primitives, not features」,改 Harness 适配你的工作流MIT

1.2 Harness 类比:给模型配一台「开发机」

  模型本身只是推理引擎,好比一颗很聪明的 CPU。要让它真正干活,还需要:

  • 外设:读文件、跑命令、搜索、调 API——也就是工具
  • 文件系统与工作区:它能看见哪个目录、能改哪些文件
  • 内存与调度:上下文怎么装、超了怎么压、下一步干什么
  • 外壳与权限:终端 UI、审批弹窗、沙箱边界
  • 扩展槽:插件、技能、主题、脚本入口

  这些加起来才是 Harness。三家都在做这台「开发机」,但装配哲学完全不同:

flowchart LR
    U["用户 / 脚本 / IDE"] --> H["Agent Harness"]
    H --> M["大模型 Provider"]
    H --> T["工具面:read / bash / search / tool"]
    H --> C["上下文与会话资产"]
    H --> X["扩展:插件 / 技能 / 包"]
    H --> O["观测:Trace / 日志 / 事件"]

1.3 三种装配哲学

路线代表核心主张代价
产品化工作流Codex多 Agent、云环境、PR review 开箱即用定制自由度相对低
插件运行时DSH内核是 Cordis 插件框架,能力全部可插拔要学插件模型
极简原语Pi少内置功能,多给扩展点常用能力要自己拼或装包

  后面三节分别拆开看,再合并成可复用方法论。


2. 三家各自怎么实现

2.1 DeepSeek Harness:一切皆插件的运行时

  DSH 建立在 Cordis 的「一切皆插件」架构上。官网直接给出心智模型:Harness 不是写死的 Agent,而是插件运行时 + 一套服务约定。

2.1.1 最小插件形态

  插件是导出 apply 的 TypeScript 模块,框架加载时注入上下文对象 ctx:

import type { Context } from '@deepseek-ai/cordis'

export const name = 'hello-plugin'

export function apply(ctx: Context) {
  // 在这里注册工具、监听事件、提供服务
  console.log('[hello-plugin] plugin loaded!')
}

  插件还有对象形式与类形式(Service 子类),适合需要对外提供服务的场景。

2.1.2 生命周期:Fiber 状态机

  官方文档把插件生命周期画成状态机,这是 DSH 工程感最强的部分之一:

PENDING → LOADING → ACTIVE
                 ↘ FAILED
ACTIVE → UNLOADING → DISPOSED
状态含义
PENDING已声明,但所需依赖未就绪
LOADING依赖就绪,正在执行 apply
ACTIVE插件运行中
FAILEDapply 抛出异常
UNLOADING正在卸载并释放资源
DISPOSED已完全卸载

  依赖驱动的加载:声明 inject = ['tools', 'llm'] 后,框架保证服务就绪才跑 apply;若依赖的服务消失(例如提供方被替换),插件会被自动卸载,服务恢复后再加载。

  自动清理:ctx.on、ctx.tools.register、ctx.llm.registerAdapter、ctx.effect 都会被追踪。卸载时按注册逆序清理。文档还特别提醒:多个异步处置器会并发执行,有顺序依赖的清理必须写进同一个 effect 处置器里,由该处置器负责串行等待。

  嵌套与热替换:ctx.plugin() 创建子 Fiber,随父上下文递归卸载;配合 @deepseek-ai/dsh-hmr 可以改源文件即热替换——旧注册被清掉,新 apply 再跑一遍。

  例子:你写了一个「番茄时钟」插件并注册了定时器。卸载插件时定时器若不清理,会变成幽灵任务;DSH 的 ctx.effect 保证卸载即停,HMR 改代码时也不会留下旧实例的注册。

2.1.3 能力三层拆分

  对足够通用的能力(例如执行 Bash),DSH 推荐拆成三角色:

角色职责Bash 示例
Service Definition定义请求 / 结果类型与服务接口dsh-shell
Service Provider真正执行,可替换dsh-bash-local
Consumer暴露成模型可调用的工具dsh-tool-bash
dsh-shell(definition) → dsh-bash-local(provider)
         ↑                        ↑
         └──── dsh-tool-bash(consumer/tool) inject: shell

  好处很实在:换 Provider(本地 → 沙箱 → SSH)时,工具定义和 Prompt 都不用改;Provider 与 Consumer 互不依赖,可独立演进。文档也给出边界:不要预防性拆分——简单工具一个包就够。

2.1.4 产品层如何「让插件被看见」

  官网把这些工程能力做成了用户可感知的功能:

  • 创造模式:用对话让 Agent 自己写插件(示例里 5 分多钟做出番茄时钟悬浮插件并安装验证)
  • 自动化任务:定时触发,例如每周五 17:00 整理项目记录生成周报
  • Trace 视图:时间线、工具调用参数、耗时、层级,方便排查「Agent 到底干了什么」
  • 开发入口:npx @deepseek-ai/dsh web 起 Web UI,或克隆 deepseek-harness 源码安装

2.2 OpenAI Codex:同一 Agent,多种入口

  Codex 官方叙事很清楚:The same agent everywhere you code。账号打通后,同一 Agent 出现在 ChatGPT、云端、IDE、CLI、桌面端。

2.2.1 产品面:把工程工作流包起来

能力官网强调的点
真实工程任务硬 bug、复杂重构、新功能;强调少 token 出高质量结果
多 Agent 并行并行跑多个 Agent,用 computer / browser 工具验证直到满足要求
云环境续跑按仓库复用云环境,关掉笔记本任务仍继续,可换设备接上
代码审查自动 review PR、暴露 findings、回答问题,把判断留给人
插件生态GitHub、日历、Slack、Notion 等补上下文与行动权限

2.2.2 实现面:轻量 CLI + Rust 内核

  开源仓库 openai/codex 定位是 Lightweight coding agent that runs in your terminal:

  • 安装面很宽:官方安装脚本、npm、Homebrew、GitHub Release 二进制
  • 实现以 Rust(codex-rs)为主,另有 codex-cli、sdk、docs
  • 可用 ChatGPT 账号登录(Plus / Pro / Business 等套餐内含用量),也可用 API key
  • 观测上遵循 Rust 生态习惯:RUST_LOG 控日志,codex -c log_dir=... 落 TUI 日志;非交互 codex exec 默认 RUST_LOG=error 且行内打印

  例子:CI 里跑 codex exec 做批量重构时,不必另开日志文件盯盘,错误行内可见;本地排查 TUI 问题再显式开 log_dir。

2.2.3 治理细节:贡献导向「问题定义」

  Codex 的 contributing.md 写得很直白:不接受外部代码 PR,但欢迎 issue、复现步骤、日志、根因分析与设计讨论。理由是:架构上下文和路线图约束强,外部 PR 往往优先级不匹配;理解问题与权衡才是难点。

  这对自研 Harness 也是方法论:把社区输入导向「现象与约束」,把实现收敛在有全局上下文的小核心团队。


2.3 Pi:极简核心 + 原语扩展

  Pi 的口号是 There are many agent harnesses but this one is yours。它故意不内置子 Agent、计划模式、权限弹窗、待办列表、后台 bash,而是提供原语让你拼。

2.3.1 Agent Loop 与会话树

  官网 How Pi Works 把循环写得非常干净:

  1. 用户消息进入当前活动分支
  2. 用系统提示 + 活动分支 + 工具定义 + 模型设置组请求
  3. Provider 流式返回文本与工具调用
  4. 记录响应、执行工具、记录结果——完成一轮
  5. 若还有工具结果或排队消息,再开一轮;否则结束

  Steering vs Follow-up 是产品层的关键差别:

  • Steering(Enter):当前工具结束后插入,可打断剩余工具计划
  • Follow-up(Alt+Enter):等 Agent 手头工作做完再进

  会话是树不是链:每条路径是一条分支;从历史节点继续会开出新分支;fork / clone 把选中历史拷到新会话文件。持久化为 JSONL,每条记录有 ID 并指向父节点。

  例子:修 bug 修到一半想试另一条路线,不必丢掉进度——/tree 回到分叉点再开分支,两条方案都在同一会话树里可对比。

2.3.2 上下文工程:分层、按需、可压缩

机制官方说明自研启示
AGENTS.md从 ~/.pi/agent/、父目录、当前目录加载项目指令「怎么跑测试」写进文件,别每次对话重复
SYSTEM.md / APPEND_SYSTEM.md替换或追加系统提示,项目级覆盖用户级允许按项目定制人格与约束
Skills只在系统提示里放名字 + 描述,匹配后再读全文渐进披露,保护 prompt cache
Compaction接近上下文上限时自动摘要旧消息,原记录仍在树里压缩可插拔,可换摘要模型
Prompt templatesMarkdown 模板,/name 展开高频指令产品化

  Skills 对齐 Agent Skills 规范:目录里放 SKILL.md,frontmatter 写 name / description,可捆绑脚本与参考文档。官方特别提醒:description 要写清「做什么 + 何时用」,避免 “Helps with PDFs” 这种无法路由的描述。

  配置也分层:用户级在 <agent-dir>(默认 ~/.pi/agent),项目级在 .pi/。项目信任(trust)决定是否加载项目扩展与技能——安全边界清晰。

2.3.3 四种模式,一套内核

模式用途
Interactive完整终端 TUI
Print / JSON脚本化一次性任务、事件流
RPCstdin/stdout JSONL,非 Node 宿主也能控制
TypeScript SDK嵌进自己的应用(官网举了 OpenClaw)

  官网强调:四种界面共用同一 Agent 与会话机制。这是「一核多面」的教科书写法。

2.3.4 「我们故意不做的」

  Pi 官网有一节 What we didn’t build,直接列清单:

不内置官方建议
子 Agenttmux 开多个 Pi,或装扩展 / 包
权限弹窗跑在容器里,或自己写确认流扩展
计划模式写计划文件,或装扩展
待办TODO.md 或自建
后台 bash用 tmux,可观测、可直接交互
MCP后来改为内置 MCP + Codemode,扩展仍支持

  这不是偷懒,而是产品边界:核心只保证 Loop、会话、工具、上下文;工作流形状交给生态。


3. 高频机制对照

  社区里讨论 Coding Agent 时,有几类问题几乎每次都会被问到:项目记忆怎么写、Skill 是不是就是 markdown、一轮对话怎么转起来、为什么用 grep 不用 RAG、记忆要不要上向量库、SubAgent 怎么做。下面按机制对照三家官方做法;标「解读」的是设计权衡归纳,不是官网原句。

3.1 项目记忆:指令文件比「万能 Prompt」更稳

机制DeepSeek HarnessOpenAI CodexPi
项目级长期指令工作区策略、技能配置进入运行上下文仓库说明与任务上下文(产品化封装)AGENTS.md / CLAUDE.md 等上下文文件,从代理目录、父目录、当前目录加载
系统提示定制插件可扩展提示组装由产品层托管SYSTEM.md 整段替换,APPEND_SYSTEM.md 追加
覆盖规则插件服务约定随仓库 / 任务配置项目 .pi/ 覆盖用户 <agent-dir>/,同名不合并

  Pi 官方文档把「上下文文件」和「项目配置」分得很清:AGENTS.md 一类不需要项目 trust就会被发现,而 .pi/extensions 等要在信任之后才加载。这是安全边界上的细心设计。

  例子:把「本仓库用 pnpm test,禁止改 legacy/」写进项目指令文件,比每轮对话重复交代更省 token,也更不容易被长对话冲掉。

  解读:社区常见的 CLAUDE.md / AGENTS.md 模式,本质是把团队隐性约定外置成版本可控的 markdown,让「记忆」可 review、可 diff、可随仓库走。

3.2 Skill:markdown 是载体,「路由描述」才是关键

  Pi 对 Skill 的官方说明很完整(并遵循 Agent Skills 规范):

  • Skill = 目录 + SKILL.md + 可选脚本 / 参考文档 / 资源
  • 启动时只把 name + description + path 放进系统提示
  • 任务匹配后才读取全文——这就是按需加载
  • description 必须同时写清「做什么」和「何时用」;“Helps with PDFs” 这种无法路由
  • /skill:name 可强制加载;disable-model-invocation: true 则只允许显式调用

  DSH 侧对应的是「技能 / 插件」进运行时:官网演示里创造模式会加载 cordis-plugin-development 这类技能再动手写插件。三家共性是:细节不进默认上下文,只进路由信息。

  例子:PDF 技能若把转换脚本、格式表全部塞进系统提示,每次对话都在付税;做成 Skill 后,只有真要处理 PDF 的那一轮才付出这部分上下文成本。

  解读:Skill 不是「多几个 md 文件」,而是渐进披露加描述即路由。英文常说 progressive disclosure。写 Skill 时最该打磨的是 description,不是正文文笔。

3.3 主循环与 Compact:一轮 Query 是怎么跑完的

  Pi 的 How Pi Works 把循环写得最白:

用户消息入分支
  → 组请求(系统提示 + 活动分支 + 工具定义 + 模型设置)
  → Provider 流式返回(文本 / 工具调用)
  → 记录响应,执行工具,记录结果   (完成一轮)
  → 若仍有工具结果或排队消息 → 再开一轮
  → 否则结束

  Compact(压缩)在接近上下文上限时触发:用摘要条目替代旧消息去组后续请求,原会话树节点仍保留。Pi 允许扩展替换压缩策略(按主题、按代码感知摘要、换摘要模型)。

  例子:一个 40 轮的重构会话,前 25 轮的中间 diff 调用可以被压成「已把 auth 模块迁到新接口」的摘要;你仍能在 /tree 里翻回原始工具调用去对证。

  解读:Compact 的产品要求不是「压得狠」,而是 压完仍可审计。评测上同理——没有可回放历史,Bad Case 归因会断链。

3.4 代码检索:工具式 grep / read,而不是先建 RAG

  三家在公开材料里呈现的都是工具面检索:读文件、列目录、grep、跑命令(DSH 的 Trace 示例里就有 bash / read / grep)。官网并未把「向量检索」作为默认代码召回主路径。

  解读(设计权衡,非官网原句):

维度grep / read 工具式向量 RAG
新鲜度即时反映工作区改动要重新嵌入
可解释性命中哪一行很清楚相似命中难解释
冷启动零索引成本要建库、选切分
适合大库内精确跳转、追符号跨仓语义问答、模糊意图

  Coding 场景里 「精确找定义 / 改错文件」压过「语义随便聊聊」,所以成熟 Harness 多半把 grep / glob / read 做成一等工具,RAG 作为可选扩展而非地基。

  例子:要改 UserService 的鉴权分支,grep -n "class UserService" 两秒定位;先问向量库「用户服务相关文件」反而可能返回一堆相似却错误的候选。

3.5 记忆:文件与会话树优先,向量库不是默认项

  Pi 的持久状态主要是:会话 JSONL 树 + 配置与指令文件 + 扩展可注入的长期记忆(官方明确扩展可做 RAG 或 long-term memory,但不是内核默认)。DSH 有 Trace 与工作区;Codex 有云任务与仓库上下文。

  解读:Coding Agent 的「记忆」优先满足三件事——可版本管理、可分享复现、可精确回放。这三件事 markdown / JSONL / git 都擅长,向量库擅长的是模糊召回,却带来更新策略与幻觉检索问题。所以社区常见答案是:短期靠上下文,长期靠文件,模糊检索才考虑向量。

3.6 多 Agent / SubAgent:产品分叉最明显的一块

产品官方立场代价与收益
Pi明确不内置 SubAgent;建议 tmux 多开、自写扩展或装包核心极简;并行自己编排
DSH产品页列有「智能体团队(实验性)」、子智能体能力在试验期,接口可能变
Codex官网强调并行多 Agent,并用工具验证结果开箱即用的编排;自由度相对低

  例子:三个独立重构子任务——Codex 路线是直接派多个 Agent 并行;Pi 路线是三个终端各开 pi,或自己写一个 subagent 扩展;DSH 路线是等智能体团队插件成熟再上。

  解读:SubAgent 本质是 调度问题(谁派活、结果怎么合、失败怎么回滚),不是「多开模型调用」这么简单。没有明确的任务边界与验收标准时,多 Agent 往往只是放大混乱。


4. 可复用的方法论

  三家摊开对照,可以抽出七条几乎通用的做法。每条都配一个「自研怎么落」的例子。

3.1 Agent Loop 是地基,事件语义要设计

  共同循环:收消息 → 组上下文 → 调模型 → 执行工具 → 决定是否继续。差别在事件语义:Pi 把 steering / follow-up 写进协议;DSH 用 Fiber 生命周期管理插件侧的循环附件。

  例子:用户在改代码中途说「先补个单测」。Loop 若不支持插队,只能干等整轮跑完;支持 steering 的 Harness 在当前工具结束后插入指令,体验完全不同。

3.2 上下文工程要「可控地装、可预测地压」

  不是 Prompt 越长越好,而是分层与按需:

  • 项目指令进文件(AGENTS.md 一类)
  • 重知识进 Skills,描述先上车、正文按需加载
  • 超限走 compaction,且原始历史可回放
  • 扩展可注入 / 过滤上下文

  例子:大仓库里把「测试怎么跑、目录约定、禁止改动清单」写进项目指令文件,比在对话里反复交代更省 token,也更稳定。

3.3 工具面稳定,实现可替换

  DSH 的 Definition / Provider / Consumer,和 Pi「工具 + 扩展注册」是同一思想:模型只看见稳定工具面。

  例子:开发期用本地 shell,上线换沙箱 Provider,工具名与参数不变,Prompt 与评测集不用改版。

3.4 扩展点设计优于功能堆砌

要问的问题含义
哪些必须内置?Loop、会话、工具执行、基础安全边界
哪些必须可拆?具体工作流、UI、领域技能、模型提供方
哪些干脆不做?学 Pi 的 What we didn’t build,写进文档

  例子:团队要「需求评审模式」。不必改内核——做一个扩展:固定提示词 + 检查清单工具 + 专用输出格式,打成包给全员装。

3.5 会话是资产,不是聊天记录

  Pi 的树状分支、导出分享;Codex 的云任务接续;DSH 的 Trace 回放,都在说:可恢复、可分支、可审计的历史,才能支撑长任务与事后归因。这和评测侧「Trace 要能复现 Bad Case」是同一条地基。

3.6 一种核心,多种界面

  TUI / CLI / RPC / SDK / 云端共用内核(Pi 明文如此,Codex 是多端同一 Agent)。自研应避免「UI 一套、脚本再一套」的双内核分裂。

flowchart TD
    A["Agent 内核<br/>Loop + 会话 + 工具 + 上下文"] --> B["交互 TUI / IDE"]
    A --> C["print / JSON 脚本"]
    A --> D["RPC / SDK 嵌入"]
    A --> E["云端长任务 / 多 Agent"]
    A --> F["Trace / 审计"]

3.7 插件生命周期与安全边界要一次想清

  DSH 的 Fiber 状态机 + 自动清理,Pi 的 project trust + 进程权限模型,都是在回答同一批问题:

  • 卸载会不会泄漏定时器 / 监听 / 连接?
  • 项目里的扩展能不能偷偷改文件?
  • 热替换会不会留下旧注册?

  例子:插件注册了全局快捷键却在卸载时忘记注销,用户换插件后快捷键「鬼打墙」——没有生命周期约定,这类 bug 会反复出现。


5. 对照速查

维度DeepSeek HarnessOpenAI CodexPi
定位插件化 Harness + 桌面 / Web产品化编码工作流极简可塑 Harness
扩展模型Cordis 插件,一切皆插件插件接外部工具扩展 / 技能 / 模板 / 包
生命周期Fiber 状态机 + 自动清理 + HMR随产品发布节奏扩展在进程内加载,trust 控制
会话工作区 + Trace 时间线云任务跨设备续跑JSONL 树,可分支可分享
上下文工作区策略、技能、环境快照云环境 + 插件补上下文分层文件 + Skills 渐进加载 + compaction
多 Agent子智能体(实验性)官网强调并行多 Agent不内置,用 tmux / 扩展
项目记忆工作区策略 + 技能配置仓库 / 任务上下文AGENTS.md / SYSTEM.md 分层
代码检索Trace 中可见 read / grep 等本地仓库工具链工具式检索;RAG 由扩展可选
模型DeepSeek 及可配置提供方OpenAI / ChatGPT 账号15+ 提供方,会话内切换
观测Trace 视图(工具调用、耗时)RUST_LOG / log_dir会话导出、事件流
治理开源 + 社区插件主题不收外部代码 PR,收 issue 分析贡献门禁 + AGENTS.md 仓库规范
典型用户要桌面应用 + 插件生态要开箱即用工程流要极致可控

6. 落到自研:可执行 Checklist

6.1 内核

  • Agent Loop 是否区分 steering 与 follow-up?
  • 工具执行失败、超时、中断,是否有明确事件?
  • 会话是否可分支、可恢复、可导出,足以复现一次任务?
  • 是否一套内核同时服务交互与自动化?
  • 工具面是否稳定,底层实现能否替换?

6.2 上下文

  • 是否分层:系统指令 / 项目指令 / 技能按需 / 压缩策略?
  • 重知识是否走「描述进提示、正文按需」的渐进披露?
  • 压缩后原始消息是否仍可追溯?
  • 项目记忆是否外置成可 diff 的 markdown,而不是堆在每轮对话里?

6.3 扩展与安全

  • 扩展能否注册工具、命令、事件,而无需改内核?
  • 卸载 / 热替换是否自动清理注册与资源?
  • 项目级扩展是否经信任决策后再加载?
  • 产品边界是否写清「不做什么」?

6.4 检索、记忆与多 Agent

  • 代码定位是否以 grep / read / glob 等工具为主,RAG 只作补充?
  • 长期记忆是否优先文件与会话树,需要模糊召回时再上向量?
  • 若做 SubAgent:任务边界、结果合并、失败回滚是否定义清楚?
  • 日志 / Trace 是否能回答「Agent 那一步看见了什么、调了什么」?
  • 多入口(UI / 脚本 / SDK)是否共用同一 Agent 语义?

7. 一句话总结

Harness 的竞争力不在多包几个功能,而在于:Loop 是否干净、上下文是否可控、能力是否可换、历史是否可追溯、生命周期是否无泄漏。

Codex 证明「产品化工作流」可以规模化交付;DSH 证明「插件运行时」能支撑生态与热替换;Pi 证明「少做功能、多给原语」也能成为完整方法论。自研时不必三选一,但必须想清楚两件事:扩展缝(seam)划在哪,以及哪些坚决不做。


8. 参考资料

来源链接本文用到的要点
DeepSeek Harness 产品页deepseek.com/harness定位、创造模式、自动化任务、Trace
DeepSeek Harness 文档deepseek-harness.github.io插件模型、Fiber 生命周期、三层拆分
deepseek-harness 仓库github.com/deepseek-ai/deepseek-harness安装、源码结构
OpenAI Codex 产品页openai.com/codex多端、多 Agent、云环境、PR review
openai/codex 仓库github.com/openai/codexCLI、Rust 实现、安装与日志、贡献策略
Pi 官网pi.dev产品主张、不做什么、扩展与包
Pi 文档pi.dev/docs/latestHow Pi Works、配置、Skills
Earendilearendil.comPi 1.0 / Pi Durable 发布说明

  若你更关心 Agent 上线后的质量门禁与 LLM-as-a-Judge,可继续阅读 Agent 评测体系搭建:从离线门禁到 LLM-as-a-Judge。