ByteNoteByteNote
DeepSeek Harness goal 子系统解析
字

字节笔记本

2026年10月6日 · 约 6 分钟读完

DeepSeek Harness goal 子系统解析

API中转
¥120

DeepSeek Harness(缩写 dsh)是 DeepSeek AI 在 GitHub 上开源的 agent harness,MIT 协议,目前处于开发者预览阶段,架构口号是「一切皆插件」,底层由 Cordis 框架驱动。它的 goal 子系统回答一个很具体的问题:用户把一句目标交给 harness 之后,这个目标本身以什么形态存在。站内此前有一篇文章从运行实录角度拆过它的多轮表现,本文换到设计层,依据仓库 docs/subsystems 下的 goal 文档与 packages/goal 的源码注释,看一组类型定义加一条事件流,如何把「同会话目标」做成可审计、可回放的状态机。

goal 生命周期:四种持久阶段与进程内激活分离

一、四种持久阶段,修订号只进不退

目标的身份由两部分组成:一个品牌化的 GoalId,加一个正整数修订号。二者合成 GoalRef,语义是比较并交换:调用方每次修改都必须指明自己看到的是第几版,服务端只在修订号对得上时接受变更,每次获准的持久变更都会把修订号加一。并发场景下谁拿着旧版本号来改,都会被直接拒绝,不存在静默覆盖。

目标处在什么阶段,由四种持久状态表达:active、paused、blocked、complete。其中 blocked 是唯一的「因问题而停止」状态,并且必须携带阻塞原因:一半是给机器看的稳定代码,采用小写 kebab-case,供策略路由;另一半是自由文本说明,同时给人读和给模型读。阻塞原因字段只在 blocked 阶段存在,其他阶段一律缺席,系统里不存在「停了却不知道为什么」的中间态。

快照类型 GoalSnapshot 把上述内容收拢成完整持久状态:目标原文 objective、当前阶段 phase、可选的阻塞原因,以及一个总轮次上限 maxGoalRounds。快照之上还有一层投影 GoalView,额外带出已开始的最大轮次、创建与最近变更的时间戳,以及一个永不落盘的 activation 字段。

这里藏着整套设计里最关键的一条分界:持久阶段回答「目标发生了什么」,随会话日志持久化;进程内的激活状态回答「续跑消费方现在能不能再开一轮」,只活在当前进程。因此暂停一个目标和撤销它的续跑授权是两个动作:disarm 只摘掉进程内的激活标记,不改持久阶段,也不动修订号,生命周期管理方会在卸载驱动前先调它;之后再要恢复,需要人授权一次 resume,重新记录激活边。

二、一次变更一条事件,清除也留墓碑

goal 的每次变更都对应一条持久的 goal/change 会话事件,载荷非此即彼:要么是变更后的完整快照,要么是清除操作的墓碑。墓碑不是把记录抹掉,而是记下被清除目标的引用和清除时间,引用里的修订号恰好是被清除快照的下一版。生命周期状态只从这些事件严格折叠推导,收件箱里的其他变更影响不了 goal 状态,这保证任何时刻重放会话日志,都能折出同一个目标状态。

goal/change 事件流:快照或墓碑,严格折叠与回放校验

回放也不是照单全收。续跑消费方会给每个获准的用户消息轮次打上标注:一个正数且连续的轮次编号,加上当时的修订号;只有这些获准的用户消息事件能推进轮次计数。回放遇到五类输入直接拒绝:轮次非正数、编号有缺口、修订号陈旧、目标已处于停止阶段、轮次超出上限。换句话说,伪造的轮次、跳号的历史、基于旧版本的变更,都活不过回放这一关。

三、创建、编辑与通知的边界

创建请求只有两个字段:目标原文,加一个可选的轮次上限。这个可省字段被刻意设计成区分两种情况:调用方没写,与调用方写了但交给部署配置解析,create() 在内部处理后者,而不是在请求层偷偷填默认值。编辑则是局部替换,运行时校验器要求至少提供一个字段,不给空编辑留口子。

每条变更通知都携带获准的操作类型和确切修订号;清除通知不带目标快照,只有墓碑信息。通知派发还有两条纪律:监听器的失败被就地隔离,不会反过来影响已经提交的变更;派发按作用域过滤,注册在某个 agent 上的监听器,只会收到那个 agent 的 goal/changed 事件。

四、服务接口一览

GoalService 的可调用面覆盖九个操作:get 读取当前目标;create 创建并激活,规则是只有 complete 阶段的目标能被新目标替换,其余阶段必须先清除或恢复;edit 改目标原文或轮次上限而不动阶段;pause 暂停并撤销自动续跑;resume 恢复一个已停止的目标,或在会话重启后重新武装仍在进行的目标,前提是轮次预算还有余量;complete 标记完成并解除武装;block 标记阻塞并写入策略给定的原因;clear 清除当前目标但保留墓碑和历史;disarm 只摘进程内的激活标记。所有写操作都强制校验确切的活跃 agent 身份与修订号,跨进程、跨身份的越权修改无处落脚。

这套设计的好处可以归成三句话:状态机封死了模糊地带,事件流保证了审计与回放,比较并交换的修订号给多路并发修改提供了统一的仲裁规则。对一个要长期无人值守跑任务的 harness 来说,目标不漂移、变更可追责,正是这套类型契约要买的东西。项目在 GitHub 上以 MIT 协议开源,目标子系统的类型定义在仓库 packages/goal/goal/src/types.ts,服务实现入口在 packages/goal/goal/src/index.ts。

相关文章

分享: