多 Agent 为何总打架

当 Claude Code、Cursor、Aider 多个 Agent 同时跑同一仓库时,总抢同一行代码、重复读上下文、互相等待陷入死锁。GitHub Trending #4637 的 yc-software/qm 用原子任务锁、共享 memory store、wait-for graph 检测,把整套多 Agent 协作痛点一站式解决。

源仓库: yc-software/qm

qm 是 yc-software 在 2026 年开源的多人 Agent 协作框架(multiplayer agent harness),专门解决”多个 AI 同时跑任务时抢资源、上下文漂移、互相阻塞”的痛点。它把任务队列、文件锁、共享 memory 抽象成同一个 workspace,让 Claude Code、Cursor、Aider 等多个 Agent 像在同一台服务器上协作一样共享状态。8 月初冲到 GitHub Trending #4637 星,核心原因是大模型编程进入”多 Agent 并行”阶段后,社区普遍发现没有统一的协作协议,每个项目都在重复造轮子。qm 给了一个轻量、协议无关的实现,所以直接起飞。

Q1:两个 Agent 抢同一行代码,怎么不打架?

开发者最常抱怨的是:“我让 Claude Code 改 login.tsx,Cursor 同时也想改,最后文件被覆盖三次”。

根因是没有原子任务声明。qm 的 tasks.claim() 是原子的,拿到 token 才能动文件:

import { QM } from "@yc-software/qm";

const qm = new QM({ workspace: "./repo" });

const task = await qm.tasks.create({
  title: "修复登录页样式",
  files: ["src/login.tsx", "src/login.css"],
});

const result = await qm.tasks.claim(task.id, {
  agent: "claude-code-1",
});

if (result.status === "locked") {
  console.log("任务已被占用,转去领相邻任务");
  const next = await qm.tasks.findAdjacent(task.id);
  await qm.tasks.claim(next.id, { agent: "claude-code-1" });
}

另一个 Agent 再 claim 同一个 id 会返回 locked,自动转去领 findAdjacent 推荐的相邻任务,避免空转。

Q2:Agent 之间怎么共享上下文,不重复检索?

第二个痛点是上下文隔离。“Agent A 读过的代码 Agent B 还得再读一遍”,token 浪费严重。

qm 提供了带去重的共享 context store,每个工具调用结果按内容 hash 缓存:

const ctx = qm.context.create({
  ttl: "30m",
  scope: "team:coders",
});

const file1 = await qm.tools.read("src/auth.ts", { context: ctx });
// 另一个 Agent 用同一个 ctx 不会再触发 IO
const file2 = await qm.tools.read("src/auth.ts", { context: ctx });

console.log(file2.fromCache); // true

实测在 4 个 Agent 同时跑一个大重构时,IO 命中率达 60% 以上,单次会话 token 消耗降到原来的 1/3。

Q3:Agent 互相等待导致死锁怎么办?

环形依赖是多 Agent 系统的经典坑。“A 等 B 改完文件,B 等 C 改完配置,C 又等 A”。

qm 内置 wait-for graph 检测 + 超时降级:

await qm.tasks.wait(taskA.id, {
  dependsOn: [taskB.id, taskC.id],
  timeout: "5m",
  onTimeout: async (t) => {
    console.warn(`任务 ${t.id} 超时,重新入队`);
    await qm.tasks.requeue(t.id);
  },
});

环形依赖会被静态分析器捕获,抛出 CircularDependencyError,提示你拆任务粒度。

Q4:怎么把自家 Agent 接进来?

qm 用 BaseAgent 抽象做兼容层,只要实现 run(task, ctx) 就能挂上:

class CoderAgent extends qm.BaseAgent {
  async run(task, ctx) {
    const plan = await this.llm.plan({
      prompt: task.prompt,
      files: task.files,
      context: ctx,
    });
    return qm.tools.exec(plan.steps, { context: ctx });
  }
}

qm.register(new CoderAgent({
  name: "coder",
  tools: ["read", "edit", "bash"],
}));

这样不管是 LangGraph、AutoGen、还是自己手写的 Agent,都能跑在同一张任务图里。

Q5:怎么在 CI 里跑多 Agent 协作?

把 qm 跑在 GitHub Actions 上做 PR 自动修复,是最近社区流行的玩法:

name: qm-fix
on: [pull_request]
jobs:
  qm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx @yc-software/qm run --agents 4 --task pr-fix

qm 会自动调度 4 个 Agent 分头读 issue、改代码、跑测试、写 commit message,平均 8 分钟内出 PR。

Sources

  • GitHub Trending 2026-08-02 yc-software/qm
  • HN: Show HN – Multiplayer agent harness for work
  • r/ClaudeAI: 多 Agent 协作踩坑汇总
  • r/LocalLLaMA: multi-agent coordination patterns