拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

deepseek harness研究:多agent协作的思考、设计与实现——从递归planner到冲突治理的确定性编排

deepseek harness研究:多agent协作的思考、设计与实现——从递归planner到冲突治理的确定性编排

1. 为什么单 agent 跑到中大型任务就会崩

如果你最近在本地折腾 deepseek harness,大概率会遇到一个很具体的场景:一个任务拆成十几步,前几步还稳,跑到第五步开始上下文里全是历史 diff,模型开始"忘记"最初的需求;再往后,某一步改错了文件,后面所有步骤都建立在这个错误之上,最后你只能整个 session 重来。这不是模型不行,是单 agent 的结构性瓶颈。

deepseek harness(下称 dsh)本身提供了 subagent、agent-team、workflow 这些零件,但零件齐不等于能跑通。多 agent 协作真正难的地方在于三件事:任务怎么递归拆解、多个 agent 改同一仓库怎么不打架、以及调度本身怎么保证确定性。这篇就围绕这三条主线,给你一套可以在本地跑起来、可观测、可回滚的配置骨架,包含 config.toml 和 settings.json 的完整示例,以及验证协作链路的操作步骤。

适合谁看:已经在用 dsh 跑单 agent、想往多 agent 迁移的开发者;被上下文窗口和串行时间墙卡住的人;以及想搞清楚"递归 planner 到底怎么落地"的工程同学。下面所有配置我都按能直接复制粘贴来写,你跟着改路径就能跑。

2. 前置准备:TaoToken 接入与 dsh 环境

在讲多 agent 编排之前,得先把模型调用这条链路打通。dsh 的 subagent 支持多 provider 注册,我这边统一走 TaoToken 的 API 网关,好处是一个 key 能覆盖 planner 用的强模型和 worker 用的便宜模型,异构路由配置起来不用来回换凭证。

官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册后在控制台生成 API Key。API 基地址是 https://taotoken.net/api ,注意这个地址不带任何查询参数,直接作为 base_url 用。

拿到 key 之后,先确认你的 dsh 版本支持 subagent 注册表。在项目根目录执行:

dsh --version dsh plugin list | grep -i subagent

如果 subagent 相关插件没装,先补上。dsh 的 provider 注册走的是命名注册表,你需要在配置里显式声明每个 provider 的 base_url 和 key 环境变量名,而不是把 key 写死在文件里。

环境变量这样设(Linux/macOS):

export TAOTOKEN_API_KEY="sk-你的key" export DSH_HOME="$HOME/.dsh"

Windows PowerShell:

$env:TAOTOKEN_API_KEY="sk-你的key" $env:DSH_HOME="$env:USERPROFILE\.dsh"

这里有个容易踩的点:dsh 读取 provider 配置时,如果环境变量名拼错,它不会报"key 不存在",而是直接回退到匿名请求,然后给你一个 401。所以配完先跑一次dsh provider check确认。

3. 可复制配置:config.toml 与 settings.json 骨架

这一节是全文的核心。多 agent 协作的配置分两层:config.toml 管 provider 和编排引擎参数,settings.json 管 agent 角色、递归深度和冲突治理策略。

3.1 config.toml:provider 与确定性编排引擎

# ~/.dsh/config.toml [providers.taotoken-strong] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" model = "deepseek-reasoner" role = "planner" [providers.taotoken-fast] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" model = "deepseek-chat" role = "worker" [orchestrator] # 确定性状态机:调度逻辑写死,模型只做决策点 engine = "deterministic" state_machine = ["pending", "ready", "claimed", "in_progress", "verifying", "done", "failed", "parked"] max_concurrency = 4 attempt_ticket = true # 开启 attempt ticket,拒绝 stale 结果 stale_reject = true parked_on_hold = true [orchestrator.boundary] # 适用边界检查:低于阈值建议退回单 agent min_lines_for_multi = 5000 min_subtasks = 3 [conflict] decision_doc = ".dsh/decisions.md" arbiter_enabled = true max_conflict_per_iter = 3 # 冲突预算,超出暂停重拆 redispatch_limit = 2 # 连续两次 re-dispatch 失败转人工

这里engine = "deterministic"是关键。它意味着任务的状态迁移、依赖就绪判定、原子 claim 全部由写死的代码完成,模型只在"任务拆解、验收判断、异常仲裁"三个点介入。这样同样输入能跑出同样轨迹,可重放、可回滚。

3.2 settings.json:递归 planner 与角色定义

{ "agent_ensemble": { "recursive_planner": { "enabled": true, "root_planner": { "provider": "taotoken-strong", "writes_code": false, "owns_scope": "all", "can_spawn_subplanner": true }, "subplanner": { "provider": "taotoken-strong", "max_depth": 3, "inherit_scope": "partial" }, "worker": { "provider": "taotoken-fast", "isolated_worktree": true, "handoff_required": true, "direct_communication": false } }, "handoff": { "format": "structured", "fields": ["task_context", "completed", "artifacts", "blockers", "dependencies"], "output_dir": ".dsh/handoffs" }, "collector": { "mode": "programmatic", "allow_model_summary": false, "loss_rate_threshold": 0.10 }, "trust": { "mailbox_message_level": "semi_trusted", "tag_source": true } } }

两个字段值得单独说。writes_code: false强制 root planner 不碰实现,它的上下文只装设计决策,不被底层细节填满;direct_communication: false让 worker 之间零直接通信,所有协调走 orchestrator 和 handoff 文件,这是避免上下文碎片化的关键。

3.3 决策文档与 handoff 模板

决策文档放在.dsh/decisions.md,防止两个 planner 各实现一套概念(脑裂)。模板:

# 设计决策记录 ## D-001 数据层选型 - 决策:使用 SQLite 而非 JSON 文件 - 理由:需要事务保证并发写一致性 - 影响范围:storage 模块全部 - 拍板人:root-planner

handoff 文件由 worker 产出,结构固定:

{ "task_id": "T-007", "attempt_id": "a3f9c2", "completed": "实现 storage 模块的写入接口", "artifacts": ["src/storage/writer.ts"], "blockers": [], "dependencies": ["T-005"] }

4. 验证请求:跑通多 agent 协作链路

配置写完,得验证它真的在协作,而不是你以为它在协作。分三步。

4.1 验证 provider 连通与模型路由

先确认两个 provider 都能通,并且路由到了不同模型:

dsh provider check --provider taotoken-strong dsh provider check --provider taotoken-fast

预期输出里会显示实际命中的 model 名。如果两个都返回同一个模型,说明 role 映射没生效,检查 config.toml 里role字段拼写。

4.2 验证递归 planner 拓扑

用一个中等任务触发递归拆解,观察是否派生了 subplanner:

dsh run --task "为项目添加用户认证模块" --profile multi-agent --dry-run

--dry-run只做规划不执行,输出会打印任务树。你应该看到 root planner 下挂了 2 到 3 个 subplanner,每个 subplanner 下再挂 worker。如果只有一层,说明can_spawn_subplanner没打开,或者任务规模没到min_subtasks阈值。

4.3 验证程序化收答案与交接丢失率

正式跑一次,然后看 collector 的报告:

dsh run --task "为项目添加用户认证模块" --profile multi-agent dsh report --metric handoff-loss

关键看两个数:最终汇总是不是由脚本拼接生成(报告里collector.mode应为programmatic),以及交接丢失率是否低于 10%。丢失率的算法是子任务输出字段的覆盖率,如果某个 worker 的 handoff 缺了artifacts字段,这个任务就算丢失。

成功的结果长这样:

[orchestrator] state: pending -> ready -> claimed -> in_progress -> verifying -> done [collector] mode=programmatic, tasks=7, loss_rate=0.04 [conflict] conflicts=1, resolved_by=arbiter, redispatch=0

看到loss_rate=0.04就说明程序化收答案生效了,没有让协调模型重读报告再总结。

5. 本篇常见错排查

多 agent 跑不起来,八成是下面几个问题。

报错stale attempt rejected频繁出现:这是 attempt ticket 在正常工作,说明有任务被转派后旧 worker 还在提交结果。检查是不是max_concurrency设太大导致任务被反复抢占,降到 3 或 4 试试。

worker 之间互相覆盖文件:说明isolated_worktree没生效。每个 worker 必须独占一个 git worktree 和 feature 分支,配置里isolated_worktree: true只是声明,你还需要确认 dsh 的 worktree 插件已加载。执行dsh plugin list | grep worktree核对。

递归深度超过限制报assertSubagentMaxDepth:这是保护机制,max_depth: 3意味着 root 之下最多三层。如果你的任务确实需要更深,别直接调大,先想想是不是拆解粒度太细,把可以合并的子任务合掉。

冲突数暴涨到几十个:max_conflict_per_iter没起作用,或者决策文档没被 planner 读取。确认.dsh/decisions.md路径在 config.toml 里配对,并且 arbiter 已启用。冲突预算超出时任务应该自动 parked 而不是继续跑。

汇总结果和子任务对不上:检查allow_model_summary是不是被误设为 true。一旦让模型做汇总,就等于在最后一环塞了个有损压缩器,交接丢失率会立刻飙上去。

6. 把编排链路固定下来

跑通一次不算数,多 agent 协作的价值在于可重复。我的做法是把上面这套配置连同决策文档、handoff 目录一起纳入版本控制,每次任务开始前用dsh run --profile multi-agent --replay-check验证状态机轨迹和上次一致。确定性编排的意义就在这:同样输入,同样轨迹,出了问题能回滚到任意一个状态。

如果你想把 planner 换成更强的模型、worker 保持便宜,直接在 config.toml 里改 provider 的 model 字段就行,异构路由的经济性就体现在这——真正需要前沿智能的时刻其实很少,拆解和设计决策用强模型,实现用便宜模型完全够。模型对话和 coding-plan 的入口在 https://taotoken.net/api ,接入文档和 API Keys 管理在控制台里,配好之后这套骨架就能长期跑下去。

返回列表