Agent 工程DeepSeek发布于 2026/10/25作者 koala已人工审核15 分钟

DeepSeek Harness 与 Pi 架构对比:为什么它们根本不在同一层

DeepSeek Harness 和 Pi 有什么区别?从 Agent Loop、插件系统、会话模型、工具权限与 Provider 分层对比两条 Agent 工程路线。

从源码看 Agent 工程的两条路线,以及它们为什么根本不在同一层

如果只看 README,DeepSeek Harness 和 Pi 很容易被归为同一类产品:都能连接模型、调用工具、操作文件、执行命令、保存会话,也都强调扩展能力。

但把源码调用链展开以后,会看到两套明显不同的工程哲学:

DeepSeek Harness 首先是一个“插件化 Agent 平台”;Pi 首先是一个“可嵌入的轻量 Agent 内核与 Coding Agent 组件集”。

它们并不是简单的竞品关系。一个很有意思的源码事实是:DeepSeek Harness 自己的多 Provider 适配器 dsh-llm-pi-ai,底层就依赖 Pi 的 pi-ai。换句话说,DeepSeek Harness 可以把 Pi 的模型接入层装进自己的插件树里。

本文基于以下源码快照分析,而不是仅依据产品文档:

DeepSeek Harness 仍明确标注为 Developer Preview,官方提示会发生兼容性破坏。本文讨论的是这个源码快照体现出来的架构,不把尚未稳定的 API 当成长期承诺。


一、Harness 到底解决什么问题

模型 API 只负责“给定消息,生成下一段内容”。一个真正能完成编码任务的 Agent,还要在模型外部补齐很多东西:

其中最小的闭环是:

模型请求 → 模型返回 Tool Call → 执行工具 → 写入 Tool Result → 再请求模型

驱动这个闭环的控制逻辑通常被称为 Agent Loop。而 Harness 一般比 Agent Loop 更大:它还需要承载会话、工具、权限、扩展、宿主接入和 UI 协议。

为了避免后面混淆,可以先建立四层概念:

层级核心问题典型内容
Model Provider如何调用不同模型鉴权、请求格式、流式协议、Reasoning、Usage
Agent Core如何让模型持续行动Agent Loop、Tool Call、上下文转换、停止条件
Agent Harness如何让 Agent 可长期运行Session、恢复、权限、审批、扩展、可观测性
Product Host如何形成具体产品Web/桌面 UI、工作空间、业务流程、插件管理

DeepSeek Harness 覆盖了从 Provider 到 Product Host 的大部分层次;Pi 则把能力拆成可以按需组合的包,重点落在 Provider、Agent Core 和 Coding Agent Runtime。

flowchart TB
  subgraph DSH[DeepSeek Harness:插件化 Agent 平台]
    DWeb[Web Client / Headless Entry]
    DProjection[Conversation Projection]
    DRuntime[Agent + Session + Tool + Approval]
    DCordis[Cordis Plugin Host]
    DProvider[LLM Adapter]
    DWeb --> DProjection --> DRuntime --> DProvider
    DCordis -.装配并管理.-> DWeb
    DCordis -.装配并管理.-> DProjection
    DCordis -.装配并管理.-> DRuntime
    DCordis -.装配并管理.-> DProvider
  end

  subgraph PI[Pi:可组合的 Agent 组件集]
    PTUI[pi-tui / RPC / SDK]
    PCoding[pi-coding-agent]
    PAgent[pi-agent-core]
    PAI[pi-ai]
    PTUI --> PCoding --> PAgent --> PAI
  end

  DProvider -.dsh-llm-pi-ai 复用.-> PAI

下面用一个贯穿案例理解两者:

用户说:“检查支付模块的失败用例,修改代码并运行测试;写文件和执行高风险命令前需要我确认。”

这个任务至少会经历一次模型请求、若干次读文件、一次写文件审批、一次测试命令,以及多轮模型继续推理。


二、DeepSeek Harness:把 Agent 产品拆成一棵插件树

2.1 它是 Web-first,但不是只有 Web UI

DeepSeek Harness 默认最显眼的入口是:

npx @deepseek-ai/dsh web

这很容易让人以为它是一个“开源 Web 聊天页面”。源码里的真实边界要大得多。

DeepSeek Harness 用 Profile 表达一套可运行的产品组合,官方自带 web 和 headless 模板:

因此 Web 只是一个宿主形态,Agent、Session、Tool、LLM、Sandbox 并不属于 React 页面本身。这个分离很重要:同一套 Runtime 可以被 Web、CLI、测试程序,甚至未来的桌面壳驱动。

2.2 Cordis:不是“支持插件”,而是“万物皆插件”

DeepSeek Harness 的架构文档直接写道:Everything is a plugin。

它底层使用 Cordis。插件向共享 Context 注册三类东西:

这里的关键不是“能额外装几个工具”,而是模型适配器、工具注册表、Session Log、Agent Loop 乃至 Web UI 本身都是插件。官方架构说明甚至强调,没有一个需要修改的“特权核心”;扩展行为的正常方式,是把新插件挂到已有插件旁边。

Profile、Bundle、Plugin Tree

DeepSeek Harness 的启动组合可以理解为三层:

  1. Profile 决定要叠加哪些 Bundle,例如 web 或 headless;
  2. Bundle 提供一组 Cordis 配置行和对应插件;
  3. 用户的 cordis.patch.yml 可以按 id 替换配置行或插入新行。
flowchart TB
  Profile[Profile: web / headless]
  Base[dsh-base Bundle]
  Mode[web-app 或 headless Bundle]
  UserPatch[Profile / Home / --patch 覆盖层]
  Tree[Cordis Plugin Tree]

  Profile --> Base
  Profile --> Mode
  Base --> Tree
  Mode --> Tree
  UserPatch --> Tree

  Tree --> Session[ctx.sessions]
  Tree --> Agent[ctx.agents / ctx.agentLoop]
  Tree --> Tools[ctx.tools]
  Tree --> LLM[ctx.llm]
  Tree --> Sandbox[ctx.sandbox]
  Tree --> Approval[ctx.approval]
  Tree --> UI[Web Client Plugins]

在 dsh-base 的默认配置中,可以直接看到 Session、Agent、LLM、JSONL 持久化、Sandbox、Approval、Permission Presets、Bash、文件工具、Skill 等插件。多 Provider 的 llm-pi-ai 也被默认挂载,只是在没有用户 Provider 配置时处于 dormant 状态。

这意味着所谓“替换某一部分”不是架构愿景,而是实际的装配机制。例如:

2.3 Agent Loop:Turn 与 Step 是两层状态机

DeepSeek Harness 对执行粒度做了清楚区分:

以“修改支付模块并运行测试”为例,第一次模型请求可能调用 read;读取结果回填后,第二次请求调用 edit;审批并修改后,第三次请求调用 bash;测试结果回填后,第四次请求才给出总结。这是一个 Turn、四个 Step。

sequenceDiagram
  participant U as User / Web
  participant A as Agent Inbox
  participant L as Agent Loop
  participant M as LLM Adapter
  participant T as Tool Pipeline
  participant S as Session Log

  U->>A: prompt / steer / queue
  L->>S: turn/start
  loop 一个 Turn 内可以有多个 Step
    L->>S: step/start + user/message
    L->>M: 组装历史、System Prompt、Tool Schema
    M-->>L: assistant/chunk*
    L->>S: assistant/chunk* + assistant/message
    opt 模型返回 Tool Call
      L->>S: tool/call
      L->>T: pre-execute → execute → post-execute
      T-->>L: Tool Result
      L->>S: tool/result
    end
    L->>S: step/end
  end
  L->>S: turn/end

源码中,agent/pre-step 可以重写或拒绝将进入模型的消息;agent/request 和 llm/stream 可以拦截请求链路;agent/turn-stopping 则是最终停止点。

这套设计带来的价值是:压缩、重试、目标继续、上下文注入等能力不必全部硬编码到循环主体里,它们可以在明确的生命周期节点上参与决策。

有一个容易踩坑的术语差异:**DeepSeek 的 Step,大致对应 Pi 事件语义里的一个 turn_start → 模型 → 工具 → turn_end;DeepSeek 的 Turn 则可能包住多个这样的 Step。**所以不能只按名字把两边的 Turn 一一对应。

2.4 Tool Pipeline:工具调用不是一个 execute() 就结束

DeepSeek Harness 的工具执行被拆成一条受控流水线:

flowchart LR
  Call[tool/call 已写入日志]
  Pre[tools/pre-execute]
  Guard[权限 Guard]
  Ask{是否需要审批}
  Approval[ctx.approval]
  Around[tools/execute]
  Body[Tool execute]
  Post[tools/post-execute]
  Final[finalizeContent]
  Result[tool/result 写入日志]

  Call --> Pre --> Guard --> Ask
  Ask -->|否| Around
  Ask -->|是| Approval -->|允许一次| Around
  Approval -->|拒绝/无人应答| Post
  Around --> Body --> Post --> Final --> Result

这里有几个工程细节值得关注:

第一,Tool Call 在执行前就被记录,因此 UI 可以先出现“等待执行”的卡片,崩溃恢复时也知道系统停在什么位置。

第二,权限与审批不是散落在每个工具里的 if。tools/pre-execute、单调 Guard、ctx.approval、Sandbox 和 tools/post-execute 共同形成治理链。

第三,审批采用 fail-closed:需要审批但没有可用回答者时,不会悄悄放行。

第四,工具最终结果经过归一化后再成为唯一的模型可见 tool/result,避免模型上下文、持久化记录和 UI 展示各有一套结果。

这也是 DeepSeek Harness 比普通 Tool Calling SDK 更像“平台”的地方:它不只解决“工具怎么调”,还解决“工具在什么权限下调、谁能拦截、怎样恢复、怎样展示”。

2.5 SessionEvent:把会话当作事件源,而不是消息数组

DeepSeek Harness 的 Session 是 append-only 的 SessionEvent 日志。核心事件包括:

它有一句非常关键的设计约束:

Model-visible means logged——只要内容会进入模型,就必须能从日志重建。

因此模型历史不是另一份独立保存的 messages[],而是通过 deriveMessages() 从 Session Log 投影出来。会话恢复、Fork、Transcript、Telemetry、持久化和 UI 重放也都基于同一条事件流。

这解决了 Agent 产品常见的“多份真相”问题:模型看到一份消息,Web 保存一份消息,工具卡片又维护另一份状态,断线恢复后彼此对不上。事件源设计把“发生过什么”固定下来,再允许不同消费者形成各自视图。

代价也很明确:事件协议需要版本治理;投影器需要兼容历史事件;原始 chunk 会增加存储体积;任何新的模型可见输入都必须先定义可持久化事件,而不能临时塞进请求。

2.6 Web UI 并不只是渲染 SDK 返回值

DeepSeek Harness 的 Web 链路同样分层。简化后如下:

Client Session.prompt()
  → API Proxy / RPC
  → Host Agent Inbox 与 Agent Loop
  → SessionEvent
  → Mux / Host Stream
  → Client Session
  → ConversationNodeAssembler
  → ConversationSnapshot / keyed views
  → React UI

浏览器侧的 Session 持有当前事件窗口、Pending Interaction、运行状态和可观察快照。ConversationNodeAssembler 不只是把 JSON 转为 JSX,而是把连续的原始事件窗口增量折叠成业务节点,再为不同 View 构建快照。

因此,同一条 SessionEvent 可以被投影为:

审批和用户提问则属于“等待人类响应的交互状态”。Host 通过带稳定 rpcId 的请求帧推送,Client 将其维护为 PendingInteraction;断线重连时,Mux 会重放仍未解决的请求。这样“审批弹窗消失了,但后台还在等”不会成为默认行为。

所以 DeepSeek 的 Web 层也有一套会话映射和状态机,而且并不薄。它负责的是客户端事件窗口、业务投影、交互态和视图扩展;Agent 执行、工具权限、持久化真相仍属于 Host Runtime。


三、Pi:把最小 Agent Loop 做成可嵌入组件

3.1 Pi 不是一个单体 CLI

Pi Monorepo 的稳定主链路分为四层:

包职责
pi-ai统一多 Provider 模型、鉴权、流式事件、Reasoning、Usage、Tool Call
pi-agent-core有状态 Agent、Agent Loop、工具执行与事件流
pi-coding-agent编码工具、Session、压缩、重试、Extension、CLI/RPC/SDK
pi-tui终端 UI 与增量渲染

这个分层使 Pi 同时具备两种身份:终端里,它是一个完整 Coding Agent;代码里,它又可以只作为 Provider 层或 Agent Core 被别的产品嵌入。

flowchart TB
  Host[你的应用 / CLI / 桌面端]
  Modes[TUI · Print/JSON · RPC · SDK]
  Coding[pi-coding-agent<br/>Session / Tools / Extension / Compaction]
  Agent[pi-agent-core<br/>Agent State / Agent Loop / Events]
  AI[pi-ai<br/>Models / Providers / Streaming / Usage]
  Vendors[Anthropic · OpenAI · Google · DeepSeek · 本地模型等]

  Host --> Modes --> Coding --> Agent --> AI --> Vendors

3.2 pi-ai:统一 Provider,不替模型做 Agent 决策

pi-ai 解决的是模型世界的差异:

多 Provider 是 Pi 很突出的现成能力,但它不是 Agent Loop 本身。**Provider Adapter 解决协议差异,Agent Loop 解决控制流。**这两个概念不能合并。

3.3 pi-agent-core:核心就是一个清晰的双层循环

Pi 的 packages/agent/src/agent-loop.ts 很适合用来理解 Agent Loop,因为控制流相对直接。

它包含两个循环:

flowchart TD
  Start[接收 Prompt,写入 Context]
  Model[调用 streamFn 请求模型]
  Stream[发出 message_start / update / end]
  Calls{Assistant 是否包含 Tool Call}
  Tools[校验并执行工具<br/>顺序或并行]
  Results[Tool Result 写回 Context]
  StopHook{shouldStopAfterTurn?}
  Steering{有 Steering 消息?}
  Follow{有 Follow-up 消息?}
  End[agent_end]

  Start --> Model --> Stream --> Calls
  Calls -->|有| Tools --> Results --> StopHook
  Calls -->|无| StopHook
  StopHook -->|是| End
  StopHook -->|否| Steering
  Steering -->|有| Model
  Steering -->|无| Follow
  Follow -->|有| Model
  Follow -->|无| End

一个 Tool Call 的处理过程也很规整:

  1. 根据名称查找工具;
  2. prepareArguments 预处理参数;
  3. 按 Tool Schema 校验参数;
  4. 调用 beforeToolCall,允许扩展阻断;
  5. 执行 Tool;
  6. 调用 afterToolCall,允许改写结果;
  7. 发出 tool_execution_end;
  8. 生成标准 ToolResultMessage 并放回上下文。

同一条 Assistant Message 中的多个工具可以顺序执行,也可以并行执行。并行模式仍按模型原始顺序生成 Tool Result Message,保证回填上下文的顺序稳定。

Pi 还专门防御了一类细节问题:如果模型因为输出 Token 上限而截断,可能留下“碰巧可以解析但参数不完整”的 Tool Call。Pi 会把这批 Tool Call 全部标为失败,而不是冒险执行。

3.4 AgentMessage 与模型消息分离

Pi 允许应用定义自有 AgentMessage。但模型只认识标准的 User、Assistant 和 Tool Result,所以每次请求前会经过:

AgentMessage[]
  → transformContext()
  → AgentMessage[]
  → convertToLlm()
  → 标准 Message[]
  → Provider

transformContext 可以做裁剪、压缩或上下文注入;convertToLlm 可以过滤纯 UI 消息,或把业务消息转换成模型可见格式。

这是很实用的边界:会话里可以存在比模型消息更多的业务信息,但只有经过显式投影的内容才进入模型。

与 DeepSeek 相比,Pi 稳定主链路更偏“消息与状态对象驱动”,而不是把所有运行事实先统一为一份跨宿主的 SessionEvent 协议。

3.5 pi-coding-agent:在 Agent Core 上补齐产品能力

pi-agent-core 只提供通用循环。真正让 Pi 成为 Coding Agent 的是 pi-coding-agent:

这说明 Pi 的价值不只是那几十行循环,而是围绕小内核形成了一套可嵌入的编码 Agent 运行时。

3.6 JSONL 会话树:天然支持分支

Pi 的 Session 也使用 JSONL,但结构与 DeepSeek 的顺序事件日志不同。

每个 Entry 有 id 和 parentId,所有 Entry 在一个文件里构成树;当前 leaf 指向正在使用的分支。追加消息就是在当前 leaf 下增加子节点,跳转历史节点后继续工作则形成新分支。

因此 Pi 可以自然支持:

DeepSeek 更强调“完整执行事件可以重放和投影视图”,Pi 更强调“对话 Entry 的树形导航和轻量本地持久化”。两者都用 JSONL,不代表数据模型相同。

3.7 Extension:足够实用,但不是 Cordis 式“万物皆插件”

Pi Extension 可以注册:

这已经是很强的扩展机制,而且 TypeScript 文件可以通过 Jiti 直接加载。对于个人工作流或团队 Coding Agent,它比重量级插件平台更容易上手。

但 Pi 的 Extension 主要围绕 pi-coding-agent 预设的扩展点工作。AgentSession、Session Manager、TUI 等仍然是明确的核心对象;它不像 Cordis 那样把 Agent Loop、Session 服务、LLM 服务和 UI 组件全部放进同一种可装卸插件模型。

可以简化为一句话:

Pi 是“小内核 + 丰富扩展点”;DeepSeek Harness 是“插件容器 + 由插件组成的产品”。

3.8 权限边界:Project Trust 不等于运行时 Sandbox

Pi README 明确说明:Pi 不内置限制文件系统、进程、网络或凭据访问的权限系统,默认继承启动它的用户与进程权限。需要强隔离时,应使用容器、微型虚拟机或外部 Sandbox。

Pi 有 Project Trust,用于决定是否加载项目本地设置、扩展和资源;但它解决的是“是否信任项目代码”,不等于每一次文件写入或命令执行的细粒度审批。

这与 DeepSeek Harness 默认组合中的 Sandbox、Approval、Permission Presets 有明显差异。

3.9 注意:Pi 新增的 AgentHarness 仍是演进中脚手架

当前 Pi 源码里已经出现新的 packages/agent/src/harness/agent-harness.ts,接口设计包含 durable Session、Lane、Run、Resume、Queue、Hook、Watch 等概念,看起来是在向更完整、可恢复的 Harness API 演进。

但在本文所用 commit 中,prompt、compact、resume、steer、watch 等大量关键方法仍返回 HarnessNotImplemented,恢复已有记录也尚未实现。

因此评估 Pi 时必须区分两件事:

不能因为仓库中出现了 AgentHarness 类,就把规划中的接口当成已经可以替换生产 Runtime 的成熟实现。


四、本质差异:一个在设计“平台”,一个在设计“内核”

维度DeepSeek HarnessPi
首要定位插件化 Agent 平台可嵌入 Agent 内核 + Coding Agent
核心抽象Cordis Context、Service、Event、Effect、Plugin TreeModel、Agent、Agent Loop、AgentSession、Extension
组合方式Profile + Bundle + Patch,几乎所有模块均为插件分层 npm 包 + Coding Agent 扩展点
Agent 循环Turn 包含 0~多个 Step,生命周期扩展点细双层循环直接清晰,Steering/Follow-up 内建
会话真相append-only SessionEvent,模型历史与 UI 均从日志派生JSONL Entry 树,活动 leaf 决定上下文分支
UIWeb Client Runtime 也插件化,事件组装为 Conversation Node/View以 TUI 为主,也提供 JSON、RPC、SDK 嵌入方式
工具治理Pre/Guard/Approval/Execute/Post/Sandbox 完整流水线before/after hooks、顺序/并行执行;隔离交给外部环境
多 Provider自有 DeepSeek Adapter,也可通过 llm-pi-ai 使用 Pipi-ai 是核心优势,Provider 范围广
插件强度可替换基础服务和 Loop,支持可逆生命周期擅长扩展 Tool、Provider、命令、事件和 TUI
学习与改造成本高,概念和组合机制较重低到中,适合先嵌入再扩展
当前成熟度提醒Developer Preview,明确会 breaking change稳定主链路可用;新 durable AgentHarness 尚未完成

如果用建筑作比喻:

因此,问“DeepSeek Harness 和 Pi 哪个更好”并不完整。更好的问题是:

我们缺的是一个可控的 Agent Loop,还是一个能持续装配多类 Agent 产品的插件宿主?


五、一个容易被忽略的事实:DeepSeek Harness 正在使用 Pi

DeepSeek Harness 的 @deepseek-ai/dsh-llm-pi-ai 包依赖:

"@earendil-works/pi-ai": "^0.82.1"

在默认 dsh-base Bundle 里,这个插件以 dormant 状态挂载;当用户在设置中配置 Provider Profile 时,它动态注册相应模型路由。

这揭示了两者最真实的关系:

DeepSeek Harness
  负责插件装配、Agent 生命周期、SessionEvent、工具治理、Web 投影
        ↓
  dsh-llm-pi-ai Adapter
        ↓
Pi pi-ai
  负责多 Provider、模型目录、鉴权和流式协议

所以“用 DeepSeek 还是用 Pi”可能是假二选一。一个合理系统完全可以同时借用两者处在不同层级的能力。


结语:我们要靠近的是思想,不是仓库形状

DeepSeek Harness 最有价值的地方,不是它恰好有一个 Web UI,而是它把 Agent 产品理解为可组合的插件树,并用 SessionEvent 和 Projection 连接 Runtime 与界面。

Pi 最有价值的地方,也不只是原生支持很多 Provider,而是它把模型访问、Agent Loop、Coding Agent 产品能力拆成不同包,让宿主可以只拿自己需要的层。


源码索引

DeepSeek Harness

Pi

参考资料

  1. https://github.com/deepseek-ai/deepseek-harness/tree/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e
  2. https://github.com/badlogic/pi-mono/tree/ccfe79ed238674f760c986e3a61493aab794000a

Continue Reading

相关推荐

继续阅读同一工具与主题下的实战内容。