Skip to content

ZCode 与 DeepSeek Harness:工作台、运行时与 Agent 工程 ​

想做一个自己的 Agent 产品时,读成熟的开源项目是很好的学习方式。但读源码也很容易“误读”:把 ACK 当成任务完成,把会话恢复当成操作可以重放,把“只读工具”当成“整个 Agent 只读”。这些误读一旦被带进自己的产品,就会变成真实的 bug 和安全问题。

这篇对比两个开源项目:

  • 研究一个完整的编程工作台怎么搭,重点看 ZCode;
  • 研究 Agent 运行能力怎么组合和替换,重点看 DeepSeek Harness。

两者都包含模型调用、工具、会话和用户界面,不能简单理解成“一个只有界面、一个只有循环”。

读完这篇你会

  • 说清两个项目各自的代码组织方式和阅读重点
  • 理解“状态归谁所有”“写意图与读视图分离”“实时事件与已提交事实”这些设计
  • 避开读源码时最容易出现的几种误读
  • 知道开发业务 Agent 时分别可以借鉴什么

核对范围

本文依据官方仓库做静态分析,核对日期为 2026-10-23:

  • ZCode:提交 3c5b227,根包版本为 3.16.2;
  • DeepSeek Harness:提交 687f282,版本为 0.2.1-rc.2。

两个版本号属于各自的分发体系,不能据此比较成熟度。本次没有安装、运行这两个项目,也没有调用模型;文中没有速度、成本或任务成功率的实测排名。开发预览、发行功能和平台支持范围,以各自的快照和后续官方说明为准。

1. 原理:整车和可换零件的动力平台 ​

打个比方:

  • ZCode 像一辆整车:桌面端、Web 端、服务端、共享界面、Agent 命令行和运行时都在同一个仓库里。读它时,可以沿着“用户的一次操作怎样变成任务,结果又怎样回到界面”追踪完整的产品链路。ZCode 仓库说明
  • Harness 像一个可以更换零件的动力平台:用 Cordis 把模型适配、工具注册、会话日志和默认的 Agent 循环组织成插件,再通过 profile 和 bundle 组合出 Web、headless、SDK、ACP 等不同入口。读它时,重点追踪“一项能力由谁定义、由谁提供、被哪些工具使用”。Harness 架构说明
比较角度ZCodeDeepSeek Harness
源码主线工作台、宿主服务和 Agent 协议的协作插件服务、事件和运行组合
主要入口桌面、Web、TUI 和非交互 CLIWeb、headless、SDK、ACP 等 profile
会话展示CLI 的权威投影,经协议送到客户端会话事件日志及其投影
扩展切入点技能、命令、Hooks、MCP、UI PluginCordis 插件、服务提供方、工具和事件
读源码时首先问状态归谁?跨进程怎样恢复?能力怎样组合、替换和卸载?

这张表说的是阅读重点,不是互斥的功能清单:ZCode 的 Agent 运行时同样开源;Harness 也有自己的 Web 应用和客户端扩展。

2. 沿一次任务,看 ZCode 怎么分层 ​

以桌面工作台为例,主链路可以简化为:

text
用户输入与界面草稿
  → UI 服务接口
  → 窗口作用域的 Host Process
  → 工作区对应的 zcode app-server --stdio
  → Agent、模型与工具执行
  → CLI 会话投影
  → snapshot / delta
  → 界面呈现

界面不负责启动和管理 Agent 子进程,也不直接解析 stdio 数据帧。桌面 Host 负责协议连接和进程管理;一个窗口可以承载多个工作区,每个工作区对应自己的聊天 CLI 进程;远端工作区通过相应的 Remote Host 连接执行环境。当前集成说明

这种拆分最值得学习的是明确了每种状态归谁所有:

状态归属
会话正文、阶段、队列、待处理的交互、用量CLI 的权威投影
草稿、滚动位置、焦点、面板展开客户端
置顶、归档、分组等列表组织状态宿主索引

如果把这些全塞进一个前端 store,断线恢复和多端同步时就越来越难判断“哪个才是真的”。状态所有权

对业务产品的启发:界面可以乐观地显示“正在发送”,但不能自己宣布“模型已启动”“工具已完成”“数据已保存”。最终状态要由执行方确认后再回到界面。

3. ZCode 怎样处理命令和会话恢复 ​

ZCode 当前的 V4 协议把写意图和读视图分开:

  • 客户端发送 command(写意图),执行侧裁决后返回 ACK;
  • 会话内容通过 topic 的 snapshot(快照)和 delta(增量)同步(读视图);
  • 命令带有稳定的 commandId,部分操作还要求版本基线,重试时复用原来的标识;
  • 客户端按序号连续应用增量,发现缺口时重新订阅,获取一个可以收敛的完整视图。

当前协议、命令 schema

这里有两个非常容易误读的地方:

  1. ACK 不等于任务完成。accepted 只表示命令被接受了;最终展示以权威会话投影为准,不能一收到 ACK 就显示“文件修改成功”。
  2. 恢复记录不等于恢复执行。协议文档明确区分了“输入登记”和“持久执行队列”:CLI 重启后,尚未开始执行的已接收输入会变为丢弃状态,由用户确认是否重新发送。会话恢复也不会让外部服务或工作区自动回到历史时刻。协议队列语义、CLI 会话说明

同样,Agent 协议层面的命令去重,不能代替业务层面的事务。工具向外部服务创建文档、提交订单、发布内容时,还需要目标业务自己提供幂等和结果查询能力。

4. Harness 怎样把同一个闭环做成可替换的能力 ​

text
profile / bundle 决定插件组合
  → 模型适配、工具、会话和执行策略就绪
  → Agent 组装上下文并调用模型
  → 工具请求进入校验与策略管线
  → 执行工具,记录结果
  → 继续模型请求或结束任务

Cordis 提供依赖注入、类型化事件和作用域生命周期。工具、模型适配器、会话持久化都可以单独扩展,注册随插件作用域一起释放。需要替换文件访问方式、模型提供方或工具策略的产品,这种边界设计很值得研究。插件与能力边界

它还区分了执行中的实时事件和已经提交的会话事实:流式片段用于界面即时显示,完整的消息或失败的尝试在结算后才写入会话日志,再由日志投影出模型的历史。进程在结算前突然中断时,不保证每个临时片段都已经持久化。会话日志与实时流

值得借鉴的是“执行事实先有明确归属,再派生出界面和模型上下文”。但不能进一步推断为“日志恢复后,所有工具动作都能自动重做”。

5. 扩展工具和扩展界面,是两项不同的工作 ​

两个项目都支持“插件”,但这个词覆盖的层次不一样。

ZCode:普通插件可以分发技能、自定义命令、Hook 和 MCP 服务;UI Plugin 再增加可交互的页面,页面通过 MCP Apps 与宿主通信,业务数据由插件服务管理。当前官方说明把交互面板的范围限定在 Desktop 本地工作区;Web、手机和远端工作区只保留普通的工具记录。不能因为插件名相同,就认为交互界面在所有地方都可用。插件指南、UI Plugin 能力与平台边界

Harness:工具定义把“模型传入的参数”“规范的返回值”和“给模型看的呈现”分开,并提供执行前策略、最终拒绝 guard 和执行包装等扩展点。宿主工具和客户端展示各有自己的契约,给工具加一个返回值,不等于已经接入了业务页面。工具执行管线

比如开发“检索笔记”能力时:鉴权、范围和结果结构先放在业务服务里,再包装成工具;检索进度、引用卡片、预览对比和保存按钮,要在实际的客户端里实现。模型工具、页面接口、业务保存接口,各有各的调用方。

6. 权限和数据边界:按实际入口判断 ​

最需要比较的不是“弹几次确认框”,而是谁执行、谁授权、数据发给谁。

ZCode:权限默认值随入口变化。当前非交互的 --prompt 在没有显式指定模式时采用 yolo,常规工具操作可能不会提示;交互工具、独立的 Plan 状态和 Hook 等各有自己的规则。plan 也不是操作系统级别的只读沙箱。CLI 权限说明、非交互默认模式源码

Harness:权限取决于完整的插件组合、执行策略和底层提供方。自己新增一个只读工具,不代表 profile 中原有的文件修改和命令执行能力也被关闭。官方明确把当前版本标为开发预览,不能仅依赖它的沙箱或审批机制处理不可信的任务。Harness 安全说明

需要核对的边界对开发者的实际影响
执行位置本地窗口、Web 服务、SSH 主机、容器可能对应不同的账号和文件权限
模型请求界面在本地运行、会话保存在本地,不代表模型请求只在本地处理
插件与 Hook安装、连接、启动、执行工具是不同阶段,审批范围不能混为一谈
会话和诊断日志可能包含代码、提示词和工具结果,需要明确访问权限和保留期限

ZCode 的 NOTICE.md 具体说明了官方模型网关转发、本地日志、远端环境中配置和凭据的同步等行为,说明数据最终流向哪里,要沿着实际的请求链去判断。其开源的 Computer Use 包是不可用的占位实现,不能把官方产品演示的能力当作开源构建已经提供的功能。ZCode 执行、数据与发行边界

许可方面,ZCode 第一方代码采用 Apache-2.0,Harness 采用 MIT;依赖、原生组件和资源仍需分别核对对应的声明。ZCode 许可说明、Harness LICENSE

7. 读源码时最容易误读的几件事 ​

容易误读成实际上带进自己产品的后果
收到 ACK = 任务完成ACK 只表示命令被接受界面显示“已完成”,实际还在执行或已经失败
会话能恢复 = 操作能重放未开始执行的输入会被丢弃,外部世界不会回到过去重启后自动重放写操作,造成重复提交
协议命令去重 = 业务写入幂等协议去重只管协议层外部系统里出现重复的订单或文档
新增了只读工具 = Agent 只读profile 里原有的写入、执行能力仍然存在以为安全,实际 Agent 可以改文件、执行命令
plan 模式 = 只读沙箱不是操作系统级别的隔离在不可信任务上放松了警惕
本地界面 = 数据不出本机模型请求可能经过外部网关敏感代码和数据被发送到了外部
同名插件 = 处处可用交互面板只在特定环境可用在不支持的端上功能缺失
退出码 0 / 最后说“已完成” = 成功只说明进程正常结束没有核对实际产物,问题被带到下游

8. 开发笔记 Agent 时,可以分别借鉴什么 ​

下面是结合上述源码边界给出的工程建议,不是两个官方项目已经为笔记系统实现的功能。

向 ZCode 借鉴客户端和运行时的分工:让服务端成为任务状态的权威,前端只维护输入、视图和待确认的动作;为任务、工具调用和用户的采纳操作分别建立标识。断线重连时获取可以恢复的状态,而不是让前端根据聊天文字猜测任务是否完成。

向 Harness 借鉴受限的能力组合:把搜索和读取拆成两个工具,由可信的任务上下文提供用户身份、知识库范围和预算,模型只填写必要的参数。需要更换模型或检索实现时,尽量保持业务契约稳定,减少客户端的跟随修改。

业务保存继续交给笔记系统:Agent 返回带来源版本的候选稿,用户预览后选择插入或另存;保存时检查目标版本、权限和格式。“来源资料过期”“目标被并发修改”“保存结果不确定”是三种不同的情况。会话恢复和工具循环都不能绕过这些业务边界。

text
选定资料范围
  → search_notes / read_note
  → 带来源的候选稿
  → 用户预览并选择采纳方式
  → 业务保存检查版本,适配层补齐操作去重
  → 确认本次提交结果

采纳操作的持久去重属于需要补齐的适配能力,不能从现有会话协议推断出业务写入已经幂等。如果目标是给已有的 Vue 产品增加这个能力,可以先做受限工具和候选稿适配,再接入自己的预览和保存页面,不必一开始就复制完整的编程工作台。详细案例见 AI Agent 开发实战:检索笔记、预览采纳与保存。

9. 怎样比较实际效果 ​

源码分析能说明架构和实现边界,但回答不了“哪一个在你的任务上更快、更省、更可靠”。需要做性能或选型结论时,用同一组脱敏任务,固定模型、工具权限、资料、版本和预算,再记录这些证据:

评估项检查依据
完成质量答案和来源、代码差异、业务约束和实际产物
执行成本模型请求次数、工具调用次数、总耗时、实际用量
失败处理无结果、工具被拒绝、取消、超时、断线恢复
副作用控制越界请求是否被拒绝,重复请求是否产生重复写入
客户端一致性迟到的事件、重连时的缺口、已确认的状态能否正确收敛

不同入口、权限模式和插件组合要分别记录。先验证固定任务的完整过程,再决定你需要的是一个完整的工作台、一个可组合的运行时,还是一条更简单的“检索 + 生成”流水线。

检查清单 ​

  • [ ] 读源码时分清“当前已有的能力”和“自己的推断”
  • [ ] 自己的产品里,每种状态都有明确的所有者
  • [ ] 界面只展示执行方确认过的最终状态
  • [ ] 会话恢复不会自动重放写操作,业务写入有自己的幂等
  • [ ] 按完整的插件组合和实际入口评估权限,而不是只看自己写的工具
  • [ ] 沿实际请求链确认数据会被发送到哪里
  • [ ] 用固定任务和完整证据比较方案,而不是只看最后一句“已完成”

延伸阅读 ​

为复用而记录,为理解而整理。