Skip to content

DeepSeek Harness 与 Pi 的架构拆解对比:两种 Agent Harness 哲学

摘要:从源码角度系统性对比 DeepSeek 官方的 DeepSeek Harness(dsh)与 earendil-works 的 Pi 两个开源 Agent Harness 项目。两者体量接近但架构哲学几乎处于两个极端:dsh 把"一切皆插件"做到字面意义的彻底(连 agent loop 本身都是可替换插件);Pi 走"精简 monorepo + 分层 package"路线,核心是可嵌入、可编程的 Agent 类。本文围绕会话持久化、工具执行边界、扩展点设计、安全模型四个维度拆解对比。


项目定位与基本面

维度DeepSeek Harness (dsh)Pi
仓库deepseek-ai/deepseek-harnessearendil-works/pi
Star / Fork187k+ / 20.8k95.8k / 11.9k
自我定位"Everything is a Plugin""AI agent toolkit: unified LLM API, agent loop, TUI, coding agent CLI"
底层框架Cordis(灵感来自论文《A Programming Paradigm for Spatiotemporal Composability》)五个独立 npm 包(pi-telemetry / pi-ai / pi-agent-core / pi-coding-agent / pi-tui)
安装方式npx @deepseek-ai/dsh webnpm/bun/pnpm 全局安装
阶段developer preview(README 警告会有破坏性变更)稳定迭代(v0.84.1)

关键差异:dsh 是一个大型 monorepo(12000+ commits),用 profile + bundle 组装产品形态;Pi 拆成五个可独立使用的包,pi-agent-core 可脱离 CLI 单独使用。

架构哲学:Cordis 插件树 vs 分层 package 显式契约

dsh:没有特权核心("There is no privileged core to patch")

  • 扩展方式是把插件挂到插件树旁边,注册行为是可逆的 effect,卸载时自动回撤
  • 组合单元是 profilebundle
    • bundle = 分发格式,打包 Cordis 配置行和代码,插入内容可被上层 patch
    • profile = Harness home 目录下的具名组合,列出叠加的 bundle 列表,持有 cordis.patch.yml
  • 分层:dsh-base(模型适配器/工具/持久化/沙箱审批/设置/凭证/遥测)→ dsh-web-app(浏览器应用)→ dsh-headless(无服务器 runner)
  • 任意配置可用 dsh --profile web --dump-config 打印,再用 patch 替换 —— 应用装配变成可审计、可 diff、可 dry-run 的声明式过程,对企业交付友好

Pi:显式分层,Agent 是可编程对象

  • 分层遵循关注点分离:pi-ai(LLM 调用)/ pi-agent-core(agent loop 和状态)/ pi-tui(终端渲染)/ pi-coding-agent(组装产品)
  • 核心可扩展性 = 把 Agent 做成纯粹可编程的类:构造函数接收函数式 hook(streamFnconvertToLlmtransformContextbeforeToolCall/afterToolCall),而非往全局 context 挂服务
  • 类型扩展用 TypeScript declaration merging 扩展 CustomAgentMessages

核心抽象:Turn / Step 与 Agent Loop

dsh 的 turn/step 状态机

  • step = 一次模型请求 + 触发的工具调用;turn = 零到多个 step(第一个输入被 claim 时打开,无事"欠着"时关闭)
  • turn/*step/*user/messageassistant/*tool/*durable session events(写日志、可重放);agent/pre-stepllm/streamtools/*waterfall 事件(监听器必须调用 next() 传递,可短路/改写);agent/turn-stoppingserial 事件(纯投票)
  • "model-visible means logged" 不变式:任何进入模型请求的内容必须能从 session log 重建,运行时断言校验 —— 审计留痕刚需级别的设计

Pi 的 runLoop:显式队列语义

  • 五步循环:Context Transformation → LLM Streaming → Tool Execution → Steering Check → Graceful Stop
  • EventStream<AgentEvent> 对外暴露事件(turn_startmessage_update 携带流式 delta 等)—— 更接近"UI 渲染友好"的事件模型
  • 独有的 steering / follow-up 概念:steering 注入到"下一次 LLM 调用之前"(用户插话立即生效),follow-up 注入到"loop 本该退出之后"(自动化触发器让 loop 继续跑)

工具执行:并行策略与终止语义

  • Pi:默认 "parallel" —— 工具顺序准备(校验参数、跑 beforeToolCall),被允许的工具并发执行;最终写入 transcript 的 toolResult 顺序永远与 assistant 请求的原始顺序一致(正确性保证);terminate: true一批所有工具都要求终止才跳过后续 LLM 调用
  • dshtools/pre-execute → execute → post-execute 三段瀑布管线;turn 收尾由 agent/turn-stopping + tool result 的 concludesTurn 字段控制 —— "Data decides, so listener order cannot change the outcome"(数据决定,监听器顺序不改变结果)

会话持久化与状态管理

dsh:事件溯源是唯一真相源

  • Session 是 append-only 的 SessionEvent 日志;LLM 可见历史由 deriveMessages() 从日志派生,不单独存
  • 事件带 seq(单调递增)、timetypedatasourceEventSeqs
  • 事件种类封闭为十二种(turn/step 起止、user/assistant/tool 消息、steering、todo、request/header)
  • SessionPersistence 支持 JSONL 与 SQLite 后端;session/flush 是 checkpoint,支持 fork(子 agent、历史分支的底层支撑)

Pi:JsonlSessionRepo + 分支树 + 显式压缩管线

  • 会话持久化到 JSONL(JsonlSessionRepo 原子 append-only),树状结构存储,支持分支、fork、自动上下文压缩
  • AgentHarness(dsh 无直接对应物,概念类似 orchestration layer)把状态显式切成四类:Harness Config / Turn Snapshot / Session / Pending Session Writes(在 save point 统一 flush)
  • Result<T, E> 模式处理可预期失败(文件系统/shell 操作),比裸抛异常利于精细错误处理
  • Compaction 是独立子系统(split-turn compaction),上下文裁剪问题给了工程化、模块化的答案

对企业级交付:两者都满足"崩溃恢复、会话可重放",但 dsh 的 "model-visible means logged" 运行时断言把审计完整性做成框架级强制检查 —— 监管敏感行业加分项。

事件系统与扩展点设计

dsh:三个事件域 × 三种派发模式

  • 三个域:Session events(durable,写日志)/ Agent events(携带活 Agent 对象,观察或拦截进行中工作)/ Capability events(fs/*tools/*telemetry/*,把策略和适配器挂到 seam)
  • 三种派发:waterfall(可短路改写)/ serial(纯投票)/ emit(普通广播)
  • scope-filtered dispatch:事件签名带 this: Scoped<Agent>,注册在某 agent 作用域的监听器只收到该 agent 事件 —— 多租户/多子 agent 刚需
  • 文档专门用表格回答"新功能挂在哪个扩展点"(16 种诉求对应明确 ctx.xxx 服务)

Pi:Extension System + Hooks,运行时更轻

  • jiti 动态加载 TS 扩展文件,ExtensionAPI 生命周期,可注册自定义工具、slash 命令、provider
  • 扩展点更贴近"给函数式 hook 传参数"(transformContext / beforeToolCall / afterToolCall / convertToLlm)
  • 取舍:dsh 插件树任何层级(含 agent loop 本身)都可整体替换,代价是概念多、上手陡峭(官方建议用 agent 读代码库);Pi hook 模型大多数定制场景更直接,但替换 loop 调度逻辑的空间更小

LLM Provider 抽象层

  • dsh:消息词表(Message/ContentBlock/StreamChunk)和 provider 适配器 seam 都在 packages/llmctx.llm 是 context key;ContentBlockMapMessageSourceMapFinishReasonMap 遵循 "…Map → derived-union" 扩展模式(declaration merging 加新变体,编译期保证 switch 覆盖所有分支)
  • Pi:独立发布 pi-ai 包,核心是 Models runtime(隔离的 provider 集合 + 显式 auth 解析 + CredentialStore),streamSimple 是常用流式入口;处理 prompt caching、thinking/reasoning block、跨供应商能力交接、Provider.refreshModels 动态发现
  • Pi 内置 llama.cpp router(原生支持本地模型 /llama),dsh 无开箱即用支持但理论上可注册新 ctx.llm adapter

部署形态与运行模式

  • dsh:profile 驱动 —— web(浏览器应用)/ headless(一次性 runner),"重装配、轻代码"
  • Pi:四种代码路径 —— Interactive(TUI,差分渲染、grapheme-aware 多行编辑器、Kitty graphics)/ Print-JSON / RPC(JSON-RPC 2.0 over stdin/stdout,协议文档特别强调按 \n 严格切分 JSONL,不要用 Node readline 等按 Unicode 分隔符切分的读取器)/ SDK(createAgentSessionRuntime() 嵌入自己的应用)

安全与权限模型:两个项目最大分野

  • dsh:沙箱与审批策略是 dsh-base 标配能力(与模型适配器、工具、持久化并列);ctx.sandbox 是可替换 backend,消费者 spawn 进程前用沙箱包装 argv —— 安全边界是框架一等公民
  • Pi:README 明说 "Pi does not include a built-in permission system... by default it runs with the permissions of the user and process that launched it"。官方给出三种隔离方案:Gondolin extension(本体留宿主机,工具和 ! 命令路由进 Linux 微 VM)/ Docker 容器 / OpenShell 沙箱

责任划分哲学不同:dsh 内建安全边界(开箱即用有默认防护,代价是框架复杂度和攻击面变大);Pi 把问题推给部署方(代码路径更短、TCB 更小、更容易审计,但默认状态下"以启动进程身份不受限执行")。对接触客户生产环境的 agent 部署,显式沙箱与审批策略是第一票否决项

工程治理与供应链

  • Pi:供应链加固投入大 —— 直接依赖精确版本锁定(.npmrcsave-exact=truemin-release-age=2 防供应链投毒)、lockfile 唯一真相源 + pre-commit 拦截、CI 用 npm ci --ignore-scripts、定期 npm audit + audit signatures、发布带 shrinkwrap 锁定传递依赖;新贡献者 PR 默认自动关闭(防御 AI 刷 PR)
  • dsh:治理侧重点在架构文档 —— docs/subsystems/core.md 单份 1070 行/55.6KB,由 scripts/gen-cordis-catalog.ts 生成、CI 校验防漂移("文档即代码产物",适合鼓励用 agent 探索代码库的项目)

对比速览表

维度DeepSeek Harness (dsh)Pi
底层范式Cordis 插件树,一切皆插件分层 npm package + 函数式 hook
核心可扩展单元Service Definition / Provider / Consumer 的 capability seamAgentOptions 里的 hook 函数
组合机制profile + bundle + 分层 patch无声明式组合层,靠代码组装
会话持久化append-only SessionEvent 日志,deriveMessages() 派生JsonlSessionRepo,树状分支 + 独立压缩子系统
类型扩展…Map → derived-union + declaration mergingCustomAgentMessages 声明合并
事件模型三域 × 三种派发模式,scope-filtered单一 EventStream,UI 渲染导向
工具执行pre-execute→execute→post-execute 瀑布管线并行(默认)/顺序,顺序保证写回
状态管理无显式 harness 层,状态即日志AgentHarness 显式四分 + Result<T,E>
安全模型框架内建 ctx.sandbox、审批策略无内置权限系统,要求外部容器化
部署形态profile 驱动(web / headless)代码路径驱动(interactive / print / RPC / SDK)
供应链治理详尽、CI 校验的架构文档严格依赖锁定与审计流水线
上手曲线陡峭,官方建议用 agent 读代码库相对平缓,五个包职责清晰

两种哲学对企业级 agent 交付的启示

"一切皆插件"和"分层 package + 显式契约"不是谁更先进,而是对应两种不同的产品生命周期假设

  • dsh 的彻底插件化暗示它想成为长期演化、被大量第三方生态包围的平台 —— 连 agent loop 都能换,预期未来有人拿它做完全不同形态的产品。企业定制几乎总能通过写新 patch/bundle 满足(不用 fork 项目),但接手成本高(要搞清 profile/bundle 树)
  • Pi 的克制是判断"大多数团队真正需要的定制用几个 hook 就能覆盖"—— 把复杂度让渡给外部生态,核心保持干净。对把 agent 能力嵌入已有企业系统(边界清晰、审计范围可控)更友好

一句话总结:先问客户要的是一个可以无限装配的平台(选 dsh),还是一个边界清晰、易于审计的组件(选 Pi)。选错了哲学,之后的每次客户定制都会变成与框架设计倾向的拉锯战。

参考资料

注:文中源码与架构描述均来自两个项目公开的 README 与 docs/ 架构文档,截至 2026 年 8 月。

关联词条