☰
多智能体协作新范式:DeepSeek Harness集成Codex与Claude Code实战
2026/10/16 11:04:39 网站建设 项目流程

一眼看到这次更新的标题,我先是愣了一下——把 Codex、Claude Code 直接做成官方插件,这不再是"自己改造工具链"的玩法,而是把多个编程代理放进同一个调度框架里当子智能体用。我前阵子刚把一批并行任务从单代理切到多代理协作,天天跟工作区冲突、上下文串味、推理过程不可审计这些破事较劲,所以这次版本里"Git 工作树"和"思考翻译"这两个功能一出现,我就知道它们解决的是什么级别的痛点。这篇文章就打算以我自己的接入过程为主线,讲讲这几个更新背后的设计逻辑、配置方法、以及我在实测里踩到的坑。

1. 这次更新的核心变化:从适配器到官方插件

1.1 官方插件列表打开的局面

DeepSeek Harness 的插件机制过去更像一套协议规范——它在文档里定义了"子智能体应该如何暴露能力、如何接收任务、如何回报结果",但具体到 Codex 和 Claude Code,官方并不直接维护对应的接入实现。所以以前要么用社区维护的第三方适配器,要么按自己的习惯写桥接脚本,每次版本升级都可能面临兼容性断裂的问题。这次把它们收进官方插件列表,最大的意义不是省了几个配置文件,而是有了一个真正受控的接入路径:插件生命周期、任务分派、隔离边界都由 Harness 统一管理,不再依赖外部脚本在各种状态之间"碰运气"。

装上官方插件之后,我的一个明显感受是整个调度层的基础能力被前置了。以前我自己写子智能体调度时,需要考虑从哪个工作目录启动进程、环境变量怎么传、会话是否需要保活、结果怎么收集,这些细节零散分布在脚本的各个角落;现在 Harness 把这些都收敛成标准化的插件接口,我只需要告诉调度器"这个子任务交给 Codex 处理、那个子任务交给 Claude Code 处理",其余的事情交给框架。

1.2 与自写适配器相比的差异

自写适配器在项目早期确实是必经之路,特别是当目标代理工具还没有稳定的对外接口时,手动管理非常正常。但一旦任务量级上来,自写方案的问题会集中爆发。我从实际对比中总结出几个主要差异:

  • 接口稳定性:官方插件跟随 Harness 主版本同步测试,而自写脚本往往要自己处理接口变化,升级时经常出现"昨天能用今天不能用"的情况。
  • 隔离边界:官方插件的每个子智能体都有独立的配置域,错误不至于让整个调度崩溃;自写脚本很容易因为一个异常状态污染全局上下文。
  • 资源回收:子智能体进程的清理、临时文件的删除、环境变量的还原,框架层会统一处理,自写时这些都要自己兜底。

另外值得注意的还有一点,官方插件不是在"替换"具体的代理工具,而是在代理工具之上多了一层统一的调度视图。Codex 与 Claude Code 仍然保留自己的提示词格式、上下文窗口管理和输出风格,Harness 做的事情是让它们在一个共享的任务模型中协作。这个"共享任务模型"正是整个多子智能体编排的核心,接下来我会展开讲讲它到底怎么组织工作。

2. 多子智能体并行的组织逻辑:调度器、协议归一化与任务委派

2.1 为什么不能直接"各跑各的"

很多第一次接触"多子智能体"的人会以为,只要同时开几个 Codex、几个 Claude Code 的会话,把任务往里面一丢就完事了。实际操作下来会发现完全不是这样:每个代理都在自己的会话里保持独立上下文,如果任务之间有关联——比如 A 代理改了公共库的接口,B 代理还在按旧接口写消费端——它们之间完全没有感知,合并代码时就是一场灾难。

这就是 Harness 这类编排层存在的意义。它做的事本质上是一个代理间的消息总线:每个子智能体不直接感知其他子智能体的会话内容,而是通过一个统一的调度器做任务分派和状态同步。调度器掌握了任务的依赖关系,知道哪些任务可以并行,哪些必须等待前置任务完成。没有这一层,并行度越高,最终的冲突率也越高。

2.2 Codex/Claude Code子智能体的统一抽象层

这次两个官方插件都实现了同一个子智能体接口,这个接口的核心定义其实很精简,关键就三件事:

  • 接收任务上下文(包括任务描述、目标文件路径、约束条件)
  • 执行并产生变更(通过文件系统操作、代码生成、命令执行等形式)
  • 回报变更及自检结论(说明改了什么、为什么这么改、自己做了哪些验证)

说白了,Harness 对"子智能体"的抽象是围绕变更集来建立的,而不是围绕对话来建立的。这一步设计对我理解整个系统帮助很大。过去我习惯把代理当成"对话对象",给它喂指令、看它回复;而在 Harness 的模型里,子智能体更像一个工作单元——给它输入边界和产出标准,最终要拿到的是可审查的差异,而不是一堆聊天文本。

Codex 插件和 Claude Code 插件在实现上有差异,但暴露给调度器的接口是一致的。Codex 更擅长动作执行、修改集合明确的任务,Claude Code 在需要深度理解长上下文、中大型重构的场景表现更好。我通常在代码生成和单文件改动时交给 Codex,把跨模块的架构级调整交给 Claude Code,这样各用其长。

2.3 任务分配与上下文传递的边界

在实际配置时,任务分配的关键不是"给哪个代理",而是"传递多少上下文"。每个模型都有上下文窗口限制,一次性把整个仓库的描述打包进去会浪费大量 token,子智能体反而抓不住重点。我的做法是在任务描述里写清楚三件事:目标文件/目录、当前状态、验收标准。目标不明确的超大任务,先在调度层拆成若干子任务,再分别下发给对应代理。

上下文传递容易出问题的地方在"隐含依赖"。比如任务描述里写了"参考 utils.py 里的工具函数",但子智能体的工作目录里实际没有 utils.py,或者多个代理同时改动同一个公共文件,这些都会造成实际执行的偏差。我后来给自己定了一条规则:任务下发前,由调度器检查依赖文件在当前分支的状态,确保子智能体拿到的上下文与仓库当前状态一致。

3. Git工作树:并行开发不再互相踩工作区

3.1 为什么默认工作区不适合并行子智能体

先说一个我在并行子智能体实践初期最痛的感受:如果你只有一个 Git 工作区,多个子智能体同时写代码,它们面对的是同一份文件快照。A 代理改了一个文件,B 代理基于旧内容继续改,等 B 改完,提交时要么冲突、要么把 A 的改动覆盖掉。真正高效的并行,是不同子智能体在物理隔离的目录里工作,各自基于独立的分支状态展开,最后再统一合并。

Git 工作树(worktree)正是解决这个问题的原生机制。它允许同一个仓库同时检出多个工作目录,每个目录绑定不同的分支,且在同一仓库对象库的基础上共享历史。这意味着子智能体彼此之间不会看到对方的未提交改动,各自的中间状态也不会污染彼此的判断。

3.2 worktree接管流程与配置示例

这次 Harness 更新里对 Git 工作树的接管做得比较到位——它不再只是"建议用户自己建 worktree",而是在为每个子智能体创建执行环境时,自动完成工作树的新建、分支绑定和任务结束后的回收。

实际操作时,一个典型的流程是:调度器为子任务创建一个新的 worktree,指向一个新的功能分支;子智能体在这个隔离目录里执行修改;任务完成后,Harness 将变更提交到该分支、推送到远端,然后清理这个 worktree。

我自己在配置里使用了类似这样的命令行序列(可以参考):

# 在主仓库中为子任务创建一个新工作树 git worktree add ../subtask-0421 -b feat/parallel-module-0421 # 在这个工作树内执行子智能体任务 cd ../subtask-0421 && codex "refactor helper functions in src/utils.py" # 任务完成后合并变更 git -C ../subtask-0421 add . git -C ../subtask-0421 commit -m "feat: apply parallel module changes" git worktree remove ../subtask-0421

这套流程里,主仓库的工作区始终保持干净,只有合并分支时才需要真正接触。这样的好处是,如果子智能体的产出质量不合格,我直接在独立分支上丢弃即可,完全不影响主线的稳定性。

3.3 分支生命周期管理与垃圾回收

Git 工作树用上之后,分支管理变成了新的痛点。尤其是并行任务多时,几乎每个任务都会产生一个分支加一个 worktree,如果不及时清理,仓库会迅速被几十个孤立分支和目录占满,而且容易留下大量工作树引用导致git worktree prune都救不回来。

建议把分支生命周期形成一个明确闭环:

  1. 任务创建时,自动生成带任务 ID 的分支名
  2. 任务合入后,立刻执行git branch -d清理本地分支并删除对应 worktree
  3. 定期对远程分支做巡检,确认已合入的分支可以安全移除

这里有个细节值得提醒:git worktree remove需要确保目标目录已经没有未提交的改动,如果子智能体在异常退出时留下残留文件,移除命令会报错。Harness 这次在回收逻辑里加了强制清理选项,但我仍然倾向于先检查状态再清理,避免误删有效产物。

4. 思考翻译:把推理过程变成可审计的产出

4.1 这件事想解决什么问题

"思考翻译"这个名字第一次出现在更新日志里时,我并没太看懂。直到看到释出的说明才知道,它针对的是多子智能体协作里一个很容易被忽略的问题:不同模型的推理过程是完全异构的。Codex 在任务执行过程中产生的中间思考链,Claude Code 是看不懂的,反之亦然。当子智能体需要协作完成一个复杂任务时,如果只交换最终的改动结果,中间那些关键决策依据就丢失了。

思考翻译要做的事情,是把模型的原始推理轨迹(对应英文是 reasoning trace)转换成一个更通用、可读性更高的中间表示——比如结构化的"目标、约束、决策点、影响范围"列表。经过翻译后的思考内容,其他子智能体可以直接使用,人工审查时也更容易判断它的决策是否合理。这一步看上去是对文本的加工,但实际上解决的是多代理协作中的语义互通问题,相当于给每个代理配了一个通用翻译器,让它们不在同一个"思考语言"下也能对齐目标。

4.2 翻译层的工作方式

我给这个功能配置了输出摘要模式和详细模式两种:摘要模式上下文消耗小,适合简单任务把关;详细模式会保留决策路径,适合需要做深度审计的复杂任务。Harness 会把翻译后的上下文作为下一阶段子智能体的参考上下文传入,相当于把前一个代理的"经验"沉淀给后续代理,而不是让后一个代理从零开始理解。

举个例子,我在做一次跨模块重构任务时,Codex 子智能体先分析了模块之间的依赖关系,并做出了"公共接口保持不变、内部实现替换"的决策。如果没有思考翻译,Claude Code 后续对接时只能看到已经改完的代码,可能会误判改动原因;打开翻译后,决策依据和影响范围在后续任务开始时就已经就位,后续代理就能沿着同样的约束条件推进,而不至于推翻前序设计。

4.3 什么时候建议关掉

思考翻译不是每个任务都需要开。经过几轮实测,我的建议是:小任务、类型安全改动比较机械的场景,直接关掉翻译,让子智能体专注于产出;复杂任务、涉及多步骤决策链或者需要多代理协作的,打开翻译的收益明显大于开销。

延迟也是要接受的现实。翻译一次推理轨迹少说要增加几十秒的运行时间,尤其是任务本身内容丰富、轨迹较长的时候。如果任务是大量小改动的批量执行,整体耗时会影响并行度带来的收益;在跑比较长的流水线任务时,我通常把它和 Git 工作树配合使用:并行阶段关闭、串行审查阶段打开,均衡体验。

5. 从配置到跑通:一个完整的接入示例

5.1 插件目录与注册表结构

在接入这次更新时,最核心的是认清"安装插件"和"注册插件"的关系:安装只是把插件代码放进 Harness 的插件目录,注册才是让调度器真正认识它。以默认示例为例,一个插件被识别的前提是存在一个符合规范的注册文件。它负责描述插件的能力元数据,比如支持的命令、可代理的模型列表、默认资源限制。

# config/plugins.yaml 示例片段,非完整配置 plugins: - name: harness-codex-adapter enabled: true executable: /usr/local/bin/harness-codex env: API_KEY_ENV: "CODEX_API_KEY" WORKTREE_ROOT: "/var/opt/harness/worktrees" - name: harness-claude-adapter enabled: true executable: /usr/local/bin/harness-claude env: API_KEY_ENV: "ANTHROPIC_API_KEY" WORKTREE_ROOT: "/var/opt/harness/worktrees"

这里WORKTREE_ROOT是我在接入时额外注释的一个路径:它规定了所有 Git 工作树默认创建在统一目录下,便于集中管理。我建议在初始配置时就把工作树根目录规划好,放在一个独立挂载点或至少同一磁盘分区的目录下,这样后续做容量分析和清理都比较方便。

5.2 配置核心字段的说明

我基于实际测试梳理了配置里比较关键的一组字段,方便参照:

字段作用我的建议值
enabled是否启用插件先全部启用,再逐个关闭不需要的
executable子智能体实际可执行程序的路径指向经过测试确认的绝对路径
max_parallel_tasks该插件允许的最大并行任务数从 1 开始,逐步增加到稳定值
timeout_secs子智能体单任务超时先给一个较大的值,统计基线后再收紧
record_thoughts是否开启思考翻译复杂任务开,简单任务关
worktree.enabled是否使用隔离工作树默认开,除非单代理场景

max_parallel_tasks的设定有一个值得注意的点:并行数的上限不是越高越好,它同时受本机算力、API 配额和上下文窗口共同制约。一开始就开过高,很容易把 API 配额打满,任务大面积超时。

5.3 一个从任务分派到合并的完整流程

下面是我实际跑通过的一个流程,用一次"同时开发两个独立功能模块"的任务来说明。先建立任务描述文件,再用harness run一键分派,最后在主分支合并两个功能的变更。

# 任务描述:features.yaml tasks: - id: "task-424" plugin: "harness-codex-adapter" description: "实现用户偏好设置模块的序列化存储" target: "src/preferences.py" constraints: "保持旧有模块的接口签名不变" - id: "task-425" plugin: "harness-claude-adapter" description: "重构用户登录流程的会话管理部分" target: "src/session.py" constraints: "使用现有的加密模块,不引入新的外部依赖"

执行命令非常简单:

harness run --config features.yaml --worktree-isolation on

整个流程中,Harness 依次做了这样几件事:解析任务、为每个任务创建独立 worktree、在各自的 worktree 中启动对应的子智能体、等待任务完成、提交每个分支、把分支合入主分支。我在这个过程中特意检查了主工作区,始终没有出现未提交的临时改动,说明隔离逻辑是有效的。

6. 实测踩到的坑与调优建议

6.1 子智能体"假完成"问题

第一批并行任务跑完,我注意到一个有趣的现象:部分子智能体自己宣称任务完成,但实际上产出的代码却没有经过充分的类型检查,甚至出现测试失败。工作树机制让提交的内容在物理上隔离了,但在语义上并不能保证完成质量。

我的应对方法是加入一个"验证门槛"环节:在任务产出进入合并前,让另一个子智能体做一次交叉验证,用独立的视角检查提交中明显的问题。上次实验中 Codex 改了一个功能函数,单个测试用例通过,交叉验证却发现它在另一个引用场景里没有覆盖边界条件——这个错误在纯工作树隔离下是发现不了的,交叉验证很好地补上了这层保障。

6.2 思考翻译的延迟开销

开启思考翻译后,我注意到任务的平均完成时间比关闭时长了大约三成。这个开销主要体现在推理轨迹的解析与重新格式化阶段,它们本身需要调用模型做一次额外处理。对于不依赖长篇推理、只涉及单文件改动的任务来说,这个开销是纯浪费。

因此我的建议是分层配置:把并行任务中工作量较小的任务模型放在关闭思考翻译的优先级上,把复杂的、需要后续依赖的任务模型放在开启位置。这样既能保证关键任务的决策可审计,又不会拖累并行吞吐量。

6.3 并行工作树的冲突率实测

实测下来,两个子智能体并行改同一个文件的情况不多,但改不同文件仍然会在合并时产生同步问题——比如 A 改了一个工具函数,而 B 正好引用了它旧版本的行为。虽然 Git 层面没有冲突标记,但合并后的代码在集成测试阶段可能出现隐性错误。

要缓解这类问题,最有效的还是任务切割层面的努力:尽量按模块边界划分任务,不要按工作目录来划分。让一个任务只负责一个内聚的模块,让另一个任务负责完全不相邻的部分,两个子智能体集成的概率才会真正下降。

6.4 资源限制与线程控制

最后说一个很容易踩的坑:并行子智能体的资源占用。一开始我用很激进的max_parallel_tasks配置跑了 8 个任务,结果本机负载迅速飙升,部分子智能体开始超时,API 配额也快速耗尽。后来我把这个值逐步往下调,最终稳定在一个相对保守的水平上,情况才好转。

我推荐的做法是先以最小并行数跑通流程,使用--dry-run或日志观察模式确认没有资源问题,再逐步加大批量。同时,为每个插件配置合理的超时时间,如果一个任务在均值的两倍时间内没有完成,基本可以判定执行过程卡死了,需要人工介入而不是无限等待。

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

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

立即咨询