DeepSeek Harness 系列(一):从 Agent 工程化现状看核心设计
现在很多 Agent 项目看起来都很热闹:模型能调用工具,能读文件,能跑命令,能生成计划,也能接一个 Web UI。真正落到工程里,难点往往不在“能不能调一次模型”,而在这些能力能不能被组合、替换、审计、恢复,并且在出问题时有明确边界。
DeepSeek Harness 值得看的地方正在这里。它不是只提供一个聊天页面,也不是把一堆工具硬塞进固定循环里。按照当前公开源码快照中的 README 与架构文档,它处于开发者预览阶段,并明确提示未来可能有破坏性变更;这意味着它还不是一个可以无脑押注的稳定平台,但它展示了一套很值得学习的 Agent Harness 设计。
一句话说:DeepSeek Harness 把 Agent 产品拆成 Cordis 插件树。模型适配器、工具注册表、会话日志、Agent Loop、权限策略、Web 表层、headless runner,都不是特权内核的一部分,而是挂在同一个运行时上下文里的插件能力。
先区分三个概念
读 DeepSeek Harness 之前,最好先把三个词放稳。
| 概念 | 在本文中的含义 |
|---|---|
| DeepSeek 模型 | 大语言模型提供方,负责生成文本、推理和工具调用意图。 |
| DeepSeek Harness | 让 Agent 使用模型、工具、会话、权限、UI 和扩展插件的工程框架。 |
| Cordis | DeepSeek Harness 底层使用的 TypeScript 插件运行时。 |
这三者的关系可以画成这样。
DeepSeek Harness 的名字容易让人误会,好像它只服务 DeepSeek 模型。源码里实际不是这样。dsh-llm 定义的是提供方无关的 LLM 运行时,适配器通过 ctx.llm.registerAdapter() 注册路由。DeepSeek 官方适配器只是其中一个实现;自定义 OpenAI 兼容端点、其他提供方目录、企业网关,都可以从同一个模型适配器边界接入。
它想解决的不是 Demo 问题
一个简单 Agent Demo 可以这样写:
用户输入 -> 拼提示词 -> 调模型 -> 执行工具 -> 把结果再发给模型这条链路能跑,但它对真实工程太薄了。
真实工程会继续问这些问题:
- 模型看到的上下文能不能从日志重建?
- 工具执行前能不能走权限、审批、沙箱和审计?
- Web UI 和自动化协议是不是复用同一套 Agent 状态?
- 一个工具、模型适配器或策略插件能不能替换,而不是改循环?
- 任务中断后,哪些结果已经发生,哪些只是模型意图?
- 企业业务接入时,怎么避免 Agent 直接绕过业务边界?
DeepSeek Harness 的核心设计,就是把这些问题前置到架构里。
核心设计理念:运行时可组合
Harness 建在 Cordis 上。Cordis 的基本单位是插件,插件向共享 Context 贡献服务、监听事件、注册工具、安装副作用,并在卸载时清理这些副作用。
这个选择带来一个重要结果:Harness 的功能不是从一个巨大的主类里扩出来的,而是由插件组合出来的。
源码架构文档里给出的组合顺序是:先应用 profile 声明的 bundle,再应用 profile 自己的 cordis.patch.yml,然后是 home 级 patch,最后是 CLI --patch。patch 不是深度合并,而是按稳定 id 替换整条配置,或插入新配置项。
这套机制很克制。它要求扩展者明确地说:“我要替换哪一行配置,或者插入哪一个插件。” 代价是配置时需要重述完整字段;收益是最终运行树可以被 dsh --profile web --dump-config 打印出来,运行时真相不藏在隐式合并里。
一切皆插件,但不是一切都随便
“一切皆插件”听起来容易滑向松散。DeepSeek Harness 没有只靠插件自由发挥,它给关键能力设置了稳定的服务边界。
| 能力 | 运行时服务 | 解决的问题 |
|---|---|---|
| 会话日志 | ctx.sessions | 记录持久事实,派生模型历史,支持回放和 fork。 |
| 系统提示词 | ctx.systemPrompt | 组装提示词段、工具 schema 和上下文。 |
| 工具执行 | ctx.tools | 注册工具,执行权限、沙箱、结果处理和展示投影。 |
| Agent 注册 | ctx.agents | 创建、恢复、驱动和管理活跃 Agent。 |
| Agent 循环 | ctx.agentLoop | 实现默认“模型请求 + 工具执行 + 下一步”的循环。 |
| 模型调用 | ctx.llm | 注册模型适配器,统一流式输出协议。 |
这些服务边界让插件之间通过 ctx.<key> 协作,而不是互相导入实现类。比如一个权限插件不需要知道 Bash 工具、文件系统工具、MCP 工具各自怎么写,它只需要拦截 tools/pre-execute;一个 UI 插件不需要知道 Agent Loop 内部状态机,它监听 session/event 渲染即可。
Agent 的运行事实来自事件日志
Harness 最重要的工程纪律之一是:模型可见的内容必须能从会话日志重建。
这不是一句漂亮话。源码中的 dsh-session 把 Session 定义为仅追加事件日志,模型历史由 deriveMessages() 从日志的 surface 投影派生。用户消息、助手消息、工具结果会进入模型历史;助手 token 分片、轮次边界、用量和审计事件留在日志里,用于回放、UI、遥测和恢复。
这个设计的价值很实际:当 Agent 出错、重试、被取消、被 fork、被 Web UI 回放时,系统不需要猜模型之前到底看过什么。只要日志是权威的,模型历史、页面展示和审计线索都可以从同一份事实投影出来。
工具是能力,不是任意函数
很多 Agent 框架把工具理解成“给模型一个函数列表”。Harness 的工具模型更接近一条受管执行流水线。
这条流水线把几个责任拆开:
- 工具定义负责参数 schema、规范 JSON 输出、模型可见渲染和 UI 展示投影。
- 策略插件负责允许、拒绝、审批、超时、重试、指标和结果改写。
- Agent Loop 负责按模型顺序记录结果,并决定是否进入下一步。
- Session 负责把最终模型可见结果变成持久事实。
这意味着企业接入业务能力时,不应该把“查数据库、补偿任务、发通知”写成模型能随意拼 SQL 的大口子。更合理的方式是写成受约束的工具:参数明确、输出结构化、写操作走审批、结果可审计。
Web 与 Headless 是同一棵树的不同表层
DeepSeek Harness 同时提供 web 和 headless profile。两者不是两套独立产品,而是在 dsh-base 之上叠不同 bundle。
这个分层很关键。基础能力不被 Web UI 绑死,Web 只是一个表层;Headless 也不需要复制一套工具、模型和会话逻辑。以后如果要接企业内部协议、自动化平台或自己的控制台,正确方向是做新的表层插件,而不是 fork 掉 Agent Loop。
它的能力边界
按源码文档,DeepSeek Harness 当前已经把很多 Agent 工程能力放进了可组合边界里:
| 能力 | 架构位置 |
|---|---|
| 多模型提供方 | ctx.llm 适配器注册与模型目录。 |
| 工具调用 | ctx.tools.register() 与统一执行流水线。 |
| Code Mode | 工具通过生成 SDK 暴露给 run_code,中间值不进入对话。 |
| 权限与审批 | tools/pre-execute、守卫、approval 服务和沙箱。 |
| 会话持久化 | 监听 session/event,在 session/flush 做持久屏障。 |
| Web UI | 监听会话事件流渲染,通过 Agent API 发送输入。 |
| subagent | 通过 ctx.subagents provider 与工具暴露委派能力。 |
| 定时任务 | 插件注册调度工具,定时触发时 followup() 或 inject()。 |
| 插件热重载 | Cordis effect 和 Loader/HMR 共同支撑重载与清理。 |
这些能力有一个共同点:它们都尽量挂在事件和服务边界上,而不是侵入默认循环。默认循环只做它必须做的事:领取输入、组装请求、调用模型、执行工具、记录事件、判断是否继续。
需要冷静看的部分
当前版本仍处在开发者预览阶段,博客里不应该把它写成成熟平台。几个风险需要提前看见:
- API、配置和事件词汇可能变化。
- patch 替换整条配置,覆盖时要重述需要保留的字段。
- 插件系统要求作者遵守 effect、inject、schema、输出值等纪律;绕过纪律会破坏可组合性。
- 企业业务接入时,权限、审计、数据脱敏和幂等仍要由业务插件设计,Harness 不会替你自动理解业务风险。
- Headless、Web、SDK、业务协议都应复用同一套会话和工具边界;复制逻辑很容易制造事实漂移。
所以我更愿意把 DeepSeek Harness 看成一个值得学习和试点的 Agent 工程框架,而不是一个马上替换所有内部平台的答案。
小结
DeepSeek Harness 的吸引力不在“它又做了一个 Agent UI”,而在它把 Agent 工程化问题拆成了可组合的运行时能力:模型适配、工具执行、会话日志、权限策略、UI 表层、业务扩展,都能在 Cordis 插件树里找到自己的位置。
如果你只想跑一个 Demo,它可能显得重。但如果你关心 Agent 如何进入真实工程:如何审计、如何扩展、如何恢复、如何接业务、如何不把模型权限放飞,那么它的设计就很值得往下读。
下一篇会进入核心架构:Profile/Bundle 怎么组装,Agent 轮次怎么跑,工具流水线和会话日志为什么是整个系统的骨架。
