TIM-1EARCHIVE TERMINAL // 2026

NTE-012经验笔记CLASS · PUBLIC

让几个 Agent 一起干活,难的不是多开几个窗口

我把本地给几个 CLI 用的任务管理层抽出核心,开源成了 TaskDock:任务有固定身份,执行结束和验收分开,后继任务要显式启动。这篇讲它能做什么、怎么用不调用模型的 demo 跑通、怎么接上自己的 CLI,也会分清公开仓库里有的和我本地另外接的。文末附一份任务简报模板。

DATE
2026.10.23
UPDATED
2026.10.23
READ
5 MIN
LENGTH
2,065 字
CONTENTS · 目录(7)
  1. 去哪拿,拿到的是什么
  2. 先跑一个不调用模型的 demo
  3. 一个任务怎么走完
  4. 接上你自己的 CLI
  5. 我本地实际跑过什么
  6. 共享工作区的规矩
  7. 任务简报模板

同时开几个 CLI,让不同的模型各干一部分,这件事不难。难的是收尾。窗口里显示任务已经结束,可去找它该交的文件,常常发现文件不在、不全,或者写到了别的地方。到这一步,那句“已完成”什么也证明不了。

为了管住这种情况,我在本地做了一层任务管理,叫 agent-tasks。后来我把其中的核心控制器抽了出来,开源成 TaskDock。

去哪拿,拿到的是什么

TaskDock 是一个面向 agent CLI 的小型任务控制器,核心是三个 Rust 文件。它负责持久保存任务和会话、监管进程,并通过 MCP 暴露四个工具。跑什么任务、用哪个后端和模型、结果能不能接受,都由调用它的主控 Agent 决定。

它不包含任何模型厂商的 SDK,不带凭据,没有模型路由,也没有现成的多渠道适配器。你要接哪个 CLI,就自己写一个适配器,或者让你的 coding agent 照着 ADAPTER.md 来写。目前只支持 Windows。

公开仓库和我本地的环境,区别在这里:

公开的 TaskDock我本地的环境
任务存储、进程监管、四个 MCP 工具有有,是同一套核心
CLI 适配器只有一个 echo 示例接了几个日常在用的 CLI,适配器是我自己写的,不在公开仓库里
登录、凭据、模型选择不包含,属于你自己的集成沿用各 CLI 自己的登录和配置
测试仓库自带的测试用假 worker另外做过真实小任务验证和假 CLI 压测(见后文)

先跑一个不调用模型的 demo

前提是 Windows、Rust 1.89+、Python 3.10+。在仓库目录里运行:

powershell
cargo build --release --locked
python examples/demo.py --binary target/release/taskdock.exe

demo 会在仓库外新建一个状态目录,注册 echo 适配器,然后走完一遍流程:提交任务,检查重复提交会不会被识别,续接一个合成会话,读回两轮结果,最后接受结果。成功时打印 PASS 和状态目录的位置。

echo 适配器只是把输入原样返回,没有模型,也没有对话记忆。demo 跑通,只能说明任务流程和状态机工作正常,不代表任何模型能力。

要接进自己的 MCP 客户端,用二进制的绝对路径,再加上 demo 打印出来的状态目录:

json
{
  "mcpServers": {
    "taskdock": {
      "command": "C:/path/to/taskdock.exe",
      "args": ["--home", "C:/path/to/state", "serve"]
    }
  }
}

接好以后,主控能用这四个工具:

工具作用
agent_backends列出已配置的适配器
agent_submit保存任务,条件满足时启动;同 ID、同输入重复提交不会生成第二份
agent_query列出和查看任务,读结果和事件,或者等待(读取不会消耗结果)
agent_control启动、续接、取消、接受,或者核对一轮执行

默认走 stdio。仓库里还有一个可选的 HTTP 网关,只面向单用户,第一次用建议先从 stdio 开始。

一个任务怎么走完

示意图:主控决策、TaskDock 记录、适配器执行、completed、主控核对、accepted、显式启动后继任务;旁支为 unknown 时先查原任务

示意图 · TaskDock 的任务生命周期,用来说明流程,不是测试结果。

图里最关键的是 completed 和 accepted 之间那一步。completed 只说明这一轮执行正常结束了;主控去核对实际产物,文件在不在、内容对不对,确认没问题后再显式标记 accepted,这才算验收通过。核对不过,就在同一个会话里续接一轮,让它接着改。

依赖也是按验收来算的。下游任务依赖的是上游最新一轮被接受的结果,不是“跑完了”的结果。就算依赖都满足了,排队中的任务也不会自己开始,要由主控显式 start。TaskDock 没有后台调度队列,不会替你决定下一步做什么。

图右边的旁支同样重要。如果监管中断,或者远端执行有没有成功无法确认,任务会进入 unknown。这时要做的是先查原来那个任务、核对清楚再决定,绝不要换一个新 ID 重新提交来绕开这种不确定。不然同一份工作可能被跑两遍,产物也会混在一起。

还有几条具体规则:

  • 每个控制操作都要带上 expected_run,针对旧轮次的操作会被拒绝。
  • 续接会话时开新的一轮,并带上唯一的 request_id。后端、模型、工作目录和选项沿用原来的设置,重复的请求号不会触发再次生成。这只是 TaskDock 这一层的去重,外部工具的所有副作用并不因此都只发生一次。
  • “取消请求已发出”和“任务确实已经停止”要分开确认。

接上你自己的 CLI

README 里给了一段可以直接交给 coding agent 的请求,大意是:读 AGENTS.md 和 ADAPTER.md,为你选定的 CLI 和具体模型写一个适配器;使用这个 CLI 当前版本文档里写明的非交互接口,保留它原生的会话 ID 用于续接,显式处理权限、取消和失败;先用假事件测试,再做一次有边界的真实运行;凭据和本机配置不放进仓库,也不为了迁就适配器去改核心协议。

适配器用什么语言写都可以,Python 只是示例的选择。登录、模型发现、远程传输、worktree 管理和 CLI 的权限策略,都属于你自己的集成。

这里要分清三层,不然容易混:

plain
skill ── 规则:什么时候委派、简报怎么写、怎么验收
MCP   ── 接口:TaskDock 提供的四个工具
CLI   ── 执行:真正调用模型的命令行程序,用它自己的登录和配置

只装一个 skill,不会凭空多出工具,也不会替你登录任何服务。真正调用模型的,始终是你已经装好、已经登录的 CLI。MCP 的基本概念可以看官方的架构说明。

TaskDock 不是安全沙箱。适配器以你的系统账号权限运行,状态目录和日志里可能有提示词、输出和路径,所以状态目录要放在私密的位置,不要纳入版本控制,也只把可信的工作交给可信的适配器。

我本地实际跑过什么

下面这些验证是在我本地的 agent-tasks 上做的,用的是我自己写的那几个 CLI 适配器。TaskDock 就是从这套环境里抽出来的核心。

10 月 22 日的测试分两部分。一部分是真实的小任务,覆盖了多个 CLI 的读取、会话续接、文件产物,以及通过 MCP 调度。另一部分是用假 CLI 跑的 25 分钟持续压测,测取消、超时和去重,这部分没有调用任何模型。

所以能说的是:流程在小任务上跑通了,压测下状态机的行为也符合预期。它还没有经历过大量真实模型的协作;我也没有在同一个项目上做过对照,证明它能省钱、提速或提高质量。

共享工作区的规矩

几个参与者在同一个仓库里干活时,看到某个文件被改了,不能凭印象断定是谁覆盖了谁。先看 diff,再查是谁改的,用事实说话。

交接时讲清楚三件事:工具在哪,输入是什么格式,对方能写哪些文件。能各自独立产出的部分就并行;耦合紧的部分只留一个负责人,慢一点也值得。

任务简报模板

委派任务时,可以用下面这份模板,复制过去就能用:

plain
目标:这次要交付什么,一句话说清
材料:需要读的文件、文档、上游任务的产物
允许改动:可以新建或修改的文件和目录
禁止改动:不能碰的文件、配置,以及他人负责的部分
验收:怎样算完成——要有哪些文件、要通过哪些检查
返回:产物文件清单 + 未完成项和原因

“返回”里的未完成项最常被漏掉,偏偏也最有用。有了它,主控验收时就知道该去哪里找缺口,不用对着一句“已完成”去猜。这也正好对应 completed 和 accepted 之间的那一步。