DeepSeek Harness 工作流能力裁剪提案解读:收缩到被实际使用的前台核心(foreground core)
2026/9/20 21:14:55 网站建设 项目流程
  • 人工智能
  • AI Agent
  • Agent 框架
  • DeepSeek

【免费下载链接】deepseek-harness

DeepSeek Harness: Everything is a Plugin.

项目地址:https://gitcode.com/gh_mirrors/de/deepseek-harness
点击查看免费下载

导读

本文围绕 DeepSeek Harness 仓库中一份被否决(rejected)的设计提案展开:将 workflow 能力从"执行 + 未被消费的进度观测系统"收缩为"只保留被实际使用的前台核心"。提案提出删除六个workflow/*事件、phase()/log()钩子、run id 与元数据快照、宿主侧liveAgents配对账本、WorkflowStartRequest.signal以及WorkflowError.fatal布尔分支。读者可以通过本文理解 workflow 模块的真实架构(脚本执行、子代理编排、worker 隔离、取消与结构化结果),掌握其公开契约中哪些部分被生产环境消费、哪些仅存在于测试,以及"以消费者为准"的接口精简方法论。文末还给出提案的替代方案、验收标准与风险,帮助读者判断此类收缩是否值得在自己的项目中推行。

提案原文:.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md(另附中文版)。仓库为只读镜像,文中所有路径均为仓库根目录相对路径,仅作查看与理解使用。


一、提案背景:workflow 能力中"未被消费的观测系统"

1.1 什么是 workflow 能力

在 DeepSeek Harness 中,workflow 是一个通过 JavaScript 编排脚本驱动子代理大规模并行的前台执行能力。模型面向的工具是workflow(注册于 packages/workflow/tool-workflow/src/index.ts),底层引擎契约是WorkflowEngine服务(packages/workflow/workflow/src/index.ts),默认实现是 worker-thread 引擎(packages/workflow/workflow-worker-thread/src/host.ts)。

一个典型的 workflow 调用形态是:

ctx.workflowEngine.start({ script: ` const results = await parallel([ () => agent('审计文件 A', { schema }), () => agent('审计文件 B', { schema }), ]) return results `, meta: { name: 'audit', description: '批量审计' }, parent, })

脚本体内可用agent(prompt, opts)parallel(thunks)pipeline(items, ...stages)phase(title)log(message)等钩子,以及args全局输入。

1.2 提案指出的核心问题

提案开篇陈述了问题的实质:workflow 的进度观测体系是"零消费者"的

  1. 六个workflow/*事件无生产监听者。事件定义于 packages/workflow/workflow/src/index.ts:

    • workflow/start:运行开始(id + meta 快照);
    • workflow/phase:脚本调用phase(title)
    • workflow/log:脚本调用log(message)
    • workflow/agent-start:一次agent()调用建立了子代理运行;
    • workflow/agent-end:一次agent()调用结束(含 outcome);
    • workflow/end:运行结束(stopReason、error、agentsStarted,刻意不含返回值)。

    提案明确写到:No production listener subscribes to any of the six workflow/* events; listeners exist only in workflow tests.(生产环境没有任何监听者订阅这六个事件,监听者只存在于 workflow 测试中)。

  2. 观测词汇无法服务其唯一预设的未来所有者WorkflowRunInfo只含{id, meta},没有父代理(parent agent)、会话(session)或工具调用身份;模型面向的工具也不暴露 run id。这意味着一个全局 ACP 监听者无法把事件路由到正确的客户端会话。meta.phases从未被读取,phase(title)不校验它,phase 的detail/model与 agent 的label/phase只喂给事件,whenToUse被校验和复制但从不渲染或选择。

  3. phase()log()跨 worker 边界传输却无接收者。在 packages/workflow/workflow-worker-thread/src/protocol.ts 中,worker→host 消息枚举包含PhaseLog两种"观测叙述"消息,payload 分别携带{title}{message}。既然无人订阅,这两条通道就是纯开销。

  4. 存活句柄重复事件时代的数据WorkflowRun.id没有非事件消费者;工具读取run.meta.name只是为了渲染一个它本就拥有(args.meta.name)的值。

  5. 取消有两条公开通道WorkflowStartRequest.signal被传给 worker 宿主,同时唯一的生产调用方又把同一个 signal 桥接到run.cancel()。由于start()在控制权让出前就返回了 run,不存在需要"请求时取消"的就绪窗口,重复的 signal 只是增加了宿主的监听/解除(disarm)状态,而没有闭合任何竞态。

  6. WorkflowError.fatal是同样的投机分支的缩影。所有生产构造都是 fatal,fatal: false只存在于测试中,且组合器已经用instanceof区分 workflow 失败。

二、源码证据:workflow 的公开契约全景

为了让读者理解提案在"砍什么",本节先还原被裁剪对象的全貌。所有类型集中在 packages/workflow/workflow/src/types.ts 与 packages/workflow/workflow/src/runtime-types.ts。

2.1 请求 / 运行 / 结果三件套

WorkflowStartRequest(runtime-types.ts)包含:

字段类型说明
scriptstring纯 JS 脚本体(允许顶层 await,以return <json>结尾)
metaWorkflowMeta身份块(名称、描述、whenToUsephases
argsunknown?原样暴露给脚本的args全局
subagentProviderstring?子代理提供方覆盖
maxTotalAgentsnumber?每次运行的总子代理上限
parentAgent运行代表其执行的代理(每个子代理的父代理)
signalAbortSignal?中止即取消运行(提案建议移除)

WorkflowRun(runtime-types.ts)当前暴露:

  • id: WorkflowRunId(提案建议移除);
  • meta: WorkflowMeta(提案建议移除);
  • result: Promise<WorkflowResult>(永不 reject);
  • cancel(reason?)
  • dispose(): Promise<void>(幂等,等待脚本与子代理安静下来)。

提案将句柄收缩为resultcancel()dispose()三项。

WorkflowResult(types.ts)包含value(脚本返回值,宿主域 JSON 数据)、stopReasoncompleted/cancelled/error闭联合)、error?agentsStarted(整个生命周期接受的agent()调用次数)。

2.2 六事件之外:worker 协议中的观测消息

protocol.ts 定义 worker→host 消息:

  • ready:握手;
  • phase/log:观测叙述(提案建议删除);
  • agent-start/agent-end:观测生命周期(提案建议删除);
  • child-start/child-dispose:子代理 RPC;
  • result:运行终态。

host→worker 消息为gocancelchild-startedchild-start-errorchild-settledchild-failedchild-disposed。可以看到,一旦移除 phase/log/agent 生命周期,wire 协议将只剩下握手、RPC 与终态,协议本身是"带判别联合的闭合枚举,接收方用assertNever穷尽"。

2.3 工具端:唯一的生产消费者其实是"记录器"

在 tool-workflow/src/index.ts 中,createWorkflowRecorder在工具插件内订阅workflow/agent-startworkflow/agent-end,把活跃运行投射到父会话(Session),追加tool-workflow/run-starttool-workflow/agent-starttool-workflow/agent-endtool-workflow/run-end四条会话事件,供会话轨迹(trajectory)展示。

值得注意的细节是:

  • 该记录器只消费两个workflow/*事件(agent-start/agent-end),不消费phaselog
  • 它的消费依赖info.idactiveMap 中查找会话——这正是提案所说的"run id 仅用于关联通知";
  • 记录失败会被try/catch包含并降级为日志警告(renderRecordingError),绝不影响工具执行。

换句话说,提案所说的"唯一生产消费者"并非不存在,而是:(a) 它只消费事件族的一个子集;(b) 它依赖的事件载荷(run id、label、phase、childId)本身不具备可路由的归属信息(父代理/会话/工具调用身份),未来若要做全局进度 UI,仍必须重设计事件契约。

三、提案核心:保留被使用的执行核心,删除事件时代的全部附属

3.1 保留清单(exercised core)

提案明确列出要保留的"被锻炼过的核心":

  • agent(prompt, { schema, model })
  • parallelpipeline
  • args
  • 并发/代理上限(concurrency/agent caps);
  • 取消(cancellation);
  • 有界释放(bounded disposal);
  • 结构化结果(structured results);
  • worker 隔离(worker isolation);
  • 前台工具收集(foreground tool collection)。

这些正是 tool-workflow/src/index.ts 工具描述中面向模型暴露的 DSL:agent/parallel/pipeline/phase/log/args,其中phaselog恰好是被划入删除区的两个。

3.2 删除清单(detailed removals)

  1. 全部workflow/*事件及其"仅事件型"的 info/outcome 类型:

    • WorkflowRunInfo(types.ts);
    • WorkflowAgentInfo/WorkflowAgentEndInfo(types.ts);
    • WorkflowResultInfo(types.ts);
    • WorkflowEventName联合与emitWorkflowEvent分发方法(index.ts)。
  2. phase()log()钩子、agent 的label/phase选项、phase 声明(meta.phases)、whenToUse,以及对应的 worker 消息(Phase/Log/AgentStart/AgentEnd)与宿主观测器。

  3. workflow 元数据收缩到工具实际使用的名字run.meta.name是工具渲染卡片标题所需,但该值工具本就通过args.meta.name拥有,因此从运行句柄上移除 id/meta 快照。

  4. 仅用于事件的 run id / meta 快照与宿主合成的 agent 结束账本(liveAgents,见 host.ts)。

  5. WorkflowRun收缩为resultcancel()dispose()

  6. 移除WorkflowStartRequest.signal与 worker 宿主的 input-signal 监听/解除(disarm)状态,保留调用方自有桥接(从它的 abort signal 到run.cancel())。当前工具实现正是这样做的:在 tool-workflow/src/index.ts 中exec.signal.addEventListener('abort', onAbort, { once: true })直接调用run.cancel('parent step aborted'),并在finally中移除监听——这就是提案所说的"caller-owned bridge"。

  7. WorkflowError收敛为单一 fatal 错误类,去掉布尔模式与isFatalWorkflowError()辅助函数(index.ts)。

3.3 连带更新范围

提案要求同步修订:已实现的 dynamic-workflow Agent Note、seam/tool/worker 的 README、工具 schema、生成的目录(catalogs)与包图、worker 类型等价记录、单元测试,以及 workflow 快照/头部 fixtures。这反映出该仓库"文档与代码强同步"的工程纪律——包图、模块图、翻译配对、快照均由脚本生成并有校验(如 scripts/verify-doc-refs.ts、scripts/verify-package-invariants.ts)。

四、替代方案:为什么不保留观测词汇给未来的 UI

提案认真权衡了"为未来的 UI 保留预构建的观测词汇"这一替代路径:

  • 有利面:当前形状与 Claude Code 的 dynamic-workflow 元数据相似,且宿主刻意把每个转发的 agent 开始与"worker 端结束或合成终止结束"配对(balanced lifecycles),保留可获得"形状兼容性",未来做进度 UI 时不必从零设计。
  • 不利面:现有载荷缺少可路由的归属信息——没有父代理、会话或工具调用身份,仅凭"平衡的生命周期"无法让命名的 ACP 所有者(全局监听者)在不重新设计的情况下变得可用。因此"平衡生命周期"并不能挽救该契约。

结论:移除会放弃"按形状兼容",使进度 UI 变成一项全新设计任务;但保留也救不了它。这是一个"沉没成本 vs 长期负债"的经典取舍,提案选择前者。

五、验收标准与风险:收缩的边界条件

5.1 验收标准

  • workflow 公开契约只保留有生产消费者的执行、取消、结果、释放四类契约;
  • 不存在任何 workflow 事件、phase/log 协议消息、run-id 生成器、进度专用元数据、宿主配对账本或 fatal 模式分支;
  • 运行句柄没有 id/meta 回显;同步start()返回后取消只有持有者一条通道
  • parallel/pipeline 行为、上限、取消静止(quiescence)、worker 包含、结构化输出与模型面向的 workflow 场景保留测试覆盖
  • typecheck、覆盖率、快照、文档同步、模块图校验、构建与卫生(hygiene)全部通过。

注意验收标准里"取消静止"与"worker 包含"两条——它们对应 host 中liveAgents账本与 worker 消息准入屏障(host.ts)所保障的语义:第一次死亡信号关闭消息准入,并在宽限期内合成缺失的 agent-end,保证每个已开始 agent 恰好有一个 end。

5.2 风险清单

  • 编译可见的收缩:这是对 workflow DSL、事件分类、句柄与 start request 的编译级收缩,是 API 破坏性变更;
  • 现有调用方必须瘦身:凡是提供描述性元数据的 workflow 调用、使用phase/log/label 的脚本必须缩减;
  • 编程调用方自行桥接:程序化调用方需要把自己的 abort 源桥接到返回的句柄上(这与工具当前做法一致,见上文 3.2 第 6 点);
  • 未来观察者需新契约:未来若要加进度观察,必须新增"归属关系更佳"的事件契约;
  • 执行语义不变:让 workflow 有用的执行语义(DSL、上限、取消、隔离、结构化结果)不受影响。

六、这份提案对工程实践的启示

  1. "以消费者为准"的接口治理WorkflowRunInfo无归属、phase/log无接收者、fatal: false仅测试存在——这些"死面"都被精确地指认出来。判断接口去留的标准不是"未来可能有用",而是"现在谁在消费"。
  2. 重复通道是负债。同一个 abort signal 既进宿主又由调用方桥接,run.meta.nameargs.meta.name重复——提案揭示"双通道"往往不闭合竞态,只是增加状态与解除逻辑。
  3. 事件载荷必须可路由。想让事件体系服务未来的全局消费者,事件必须携带父代理/会话/工具调用身份,否则"平衡生命周期"只是形似。
  4. 收缩是编译级、全链路的事件。类型、协议、README、schema、生成目录、快照、测试都要联动更新——这正是大型 monorepo 中"删除"比"新增"更难的原因。

结语

这份被否决的提案最终没有落地(status: rejected——进度观测被视为有意的观察 API,应通过消费者使其有用,而非删除),但它完整呈现了 DeepSeek Harness workflow 模块的边界:执行核心(脚本 DSL、子代理编排、worker 隔离、取消、结构化结果)是真实资产,事件时代的观测词汇则是无主负债。对于想深入理解该模块的读者,建议从 packages/workflow/workflow/src/types.ts、packages/workflow/workflow/src/index.ts、packages/workflow/workflow-worker-thread/src/protocol.ts 与 packages/workflow/tool-workflow/src/index.ts 四条路径入手,即可完整还原"引擎契约 → wire 协议 → 模型工具"三层结构。若你正在设计自己的多代理编排 API,本提案的删除清单与验收标准可作为"最小可用契约"的对照模板。

  • 人工智能
  • AI Agent
  • Agent 框架
  • DeepSeek

【免费下载链接】deepseek-harness

DeepSeek Harness: Everything is a Plugin.

项目地址:https://gitcode.com/gh_mirrors/de/deepseek-harness
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询