现在你可以同时运行 10 个 AI 编程智能体。给每个一个 issue,指向一个共享的 beads 数据库,让它们工作。智能体创建子任务、提交发现的 bug、更新状态、完成后关闭 issue。真正有生产力。
直到某些东西被阻塞。
当人类被阻塞时,会说出来。在 Slack 里说、在站会上提、走到同事桌前。智能体不会做任何这些。智能体遇到无法解决的依赖时,要么默默停滞,要么开始绕路,而绕路往往制造更多问题。三个智能体可能卡在同一个未解决的上游任务上,而你直到四个小时后好奇为什么什么都没交付时才会知道。
这就是智能体开发中的分类问题。不是"如何开更好的站会",而是"如何看到一群不会抱怨的自主工作者中什么卡住了"。这里分享的是我们在构建 Beadbox 过程中学到的经验。Beadbox 是 beads 的实时仪表盘,它让你实时看到智能体在做什么、被什么阻塞、以及什么刚变为可用。
直接跳到你关心的部分:
- 智能体如何创建阻塞链 -- 智能体工作特有的模式
- 自动化依赖检测 -- 在阻塞形成时就捕获
- CLI 优先的分类工作流 -- 可脚本化、智能体可执行
- 实时了解智能体工作 -- 在阻塞发生的瞬间就看到
- 评估分类工具 -- 该看什么
- Supervisor 循环 -- 我们如何日常运行 10+ 智能体
智能体如何创建阻塞链
智能体产生依赖问题的方式和人类团队不同。理解这些失败模式很重要,因为对应的分类响应也不同。
智能体不会预先建模依赖。 人类架构师会将功能分解为任务并思考顺序。编程智能体接到任务后开始工作,在实现过程中发现需要一些尚不存在的东西。它可能会为那个依赖创建新 issue。可能会试图内联构建并制造混乱。也可能直接停止。除非你在监视 issue 数据库,否则这些结果都不可见。
智能体工作速度快于依赖图更新。 智能体 3 关闭了智能体 7 正在等待的任务,但智能体 7 不知道,因为它在 10 分钟前就检查过阻塞情况了。而此时智能体 7 仍然空闲或在做优先级更低的事。解除阻塞已经发生了,但信息没有传播。
并行分解产生循环依赖。 当多个智能体同时分解工作时,可能创建出单个智能体看不到的循环。智能体 1 创建任务 A 依赖任务 B。智能体 2 创建任务 B 依赖任务 C。智能体 3 创建任务 C 依赖任务 A。每个依赖在局部看都合理。循环只有从上方才能看到。
资源争用是隐形的。 两个智能体都需要修改同一个文件,或都需要 staging 环境,或都需要同一个共享库处于稳定状态。没有依赖被提交,因为两个智能体都不知道对方的存在。它们都变慢了,但都不报告原因。
共同点是:智能体产生阻塞的速度快于它们报告阻塞的速度。supervisor(你)需要自动浮现阻塞的工具,而不是等别人举旗的工具。
自动化依赖检测
解决方案是在创建任务时就产生明确的、可查询的依赖数据,并持续检查。以下是使用 beads 的实际操作。beads 是我们运行智能体集群所使用的 Git 原生 issue 追踪器。
智能体在创建任务时记录依赖:
# 智能体创建任务,发现需要一个不存在的 API
API_TASK=$(bd create \
--title "Implement /api/v2/orders endpoint" \
--type task --priority 2 --json | jq -r '.id')
# 智能体创建自己的任务并声明依赖
UI_TASK=$(bd create \
--title "Build order history page" \
--type task --priority 2 --json | jq -r '.id')
bd dep add "$UI_TASK" "$API_TASK"
那个 bd dep add 只是一个 CLI 调用。任何 AI 编程智能体(Claude Code、Cursor、Copilot Workspace)都能执行它。不需要 API 客户端库,不需要认证流程。依赖现在是结构化数据,任何其他智能体或脚本都能查询。
循环检测自动运行:
# beads 检查整个依赖图的循环
bd dep cycles
# 存在循环时的输出:
# CYCLE DETECTED: beads-a1b -> beads-c3d -> beads-e5f -> beads-a1b
在 5,000 条依赖的图上,这大约需要 ~70ms。作为 post-commit hook 或 5 分钟 cron 运行。当三个智能体独立创建了一个依赖循环时,你在几分钟内就能发现,而不是几小时后当三个都停滞时才知道。
一条命令浮现所有阻塞任务:
bd blocked --json | jq -r '.[] |
"BLOCKED: \(.id) \(.title)\n waiting on: \(.blocked_by | join(", "))\n assignee: \(.owner // "unassigned")\n"'
输出:
BLOCKED: beads-x7q Build order history page
waiting on: beads-m2k Implement /api/v2/orders endpoint
assignee: agent-3
BLOCKED: beads-r4p Deploy staging environment
waiting on: beads-j9w Fix Docker build, beads-n1c Update TLS certificates
assignee: agent-7
现在你知道智能体 3 和智能体 7 卡住了,卡在什么上,以及需要做什么来解除阻塞。整个查询在 10K issue 数据库上只需 30ms。
通过分支命名约定检测被阻塞的 PR:
#!/bin/bash
# blocked-prs.sh: find PRs whose dependencies haven't merged
for pr in $(gh pr list --json number,headRefName --jq '.[].headRefName'); do
ISSUE_ID=$(echo "$pr" | grep -oE 'beads-[a-z0-9]+')
[ -z "$ISSUE_ID" ] && continue
BLOCKERS=$(bd show "$ISSUE_ID" --json | jq -r '.blocked_by[]' 2>/dev/null)
for blocker in $BLOCKERS; do
BLOCKER_STATUS=$(bd show "$blocker" --json | jq -r '.status')
if [ "$BLOCKER_STATUS" != "closed" ]; then
echo "PR ($pr) blocked: $ISSUE_ID waiting on $blocker ($BLOCKER_STATUS)"
fi
done
done
二十行 shell。在本地运行,读取本地数据,告诉你智能体的哪些 PR 还不能合并以及原因。
CLI 优先的分类工作流
智能体工作流中的分类不是会议。它是一个循环运行的脚本。supervisor(人类或智能体)查看什么卡住了,对每个项目做出决策。
这是我们实际运行的分类脚本:
#!/bin/bash
# triage.sh: agentic fleet blocker triage
echo "========================================="
echo "TRIAGE REPORT: $(date +%Y-%m-%d %H:%M)"
echo "========================================="
# 1. 什么被阻塞了?
echo -e "\n--- BLOCKED TASKS ---"
bd blocked --json | jq -r '.[] |
"[\(.priority)] \(.id) \(.title)
blocked by: \(.blocked_by | join(", "))
assignee: \(.owner // "unassigned")\n"'
# 2. 有什么可以给智能体认领的?
echo -e "\n--- READY (unblocked, open) ---"
bd ready --json | jq -r '.[] |
"[\(.priority)] \(.id) \(.title) (\(.owner // "unassigned"))"'
# 3. 哪些智能体变安静了?
echo -e "\n--- STALE IN-PROGRESS (no update in 2h) ---"
CUTOFF=$(date -v-2H +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -d '2 hours ago' --iso-8601=seconds)
bd list --status=in_progress --json | jq -r --arg cutoff "$CUTOFF" '.[] |
select(.updated_at < $cutoff) |
"STALE: \(.id) \(.title) (last update: \(.updated_at), assignee: \(.owner // "unknown"))"'
# 4. 依赖健康度
echo -e "\n--- DEPENDENCY CYCLES ---"
bd dep cycles 2>&1 || echo "No cycles detected."
echo -e "\n--- FLEET STATS ---"
bd stats
对人类团队来说,"停滞"意味着 48 小时没有更新。对智能体来说,一个 in-progress 任务 2 小时的沉默就是警示信号。要么智能体卡住了没汇报,要么它崩溃了。无论哪种情况,你都需要去看。
每个阻塞项的决策树:
- 其他智能体能解除阻塞吗? 提升阻塞任务的优先级,分配可用智能体。
- 依赖是虚假的吗? 智能体有时在规划阶段会声明过于保守的依赖。如果阻塞不是真实的,移除它:
bd dep remove beads-x7q beads-m2k(移除 x7q 对 m2k 的依赖,立即解除 x7q 的阻塞)。 - 工作可以拆分吗? 让被阻塞的智能体做不需要依赖的部分。为剩余部分创建后续任务。
- 是外部阻塞吗? 只有人类能解决的事情(API key、设计决策、权限授予)。标记它,记录预期解决时间,把智能体重新分配到其他就绪工作。
选项 2 在智能体工作中经常发生。它们根据规划时对代码库的理解来建模依赖。一旦实现开始,工作的真实形态往往显示那些依赖中有一半是不必要的。
实时了解智能体工作
每 30 分钟运行一次分类脚本会留下空白。当智能体工作很快时,两次检查之间会发生很多事。问题变成:你能实时看到阻塞的形成吗?
Beadbox 是这样做的:
beads 数据库位于你文件系统的 .beads/ 目录中。智能体运行的每个 bd update、bd create 或 bd close 都会写入该目录。Beadbox 用 fs.watch() 监听它,并在毫秒内通过 WebSocket 推送变化到 UI。
实际效果:智能体 5 在终端运行 bd update beads-x7q --status=closed。Beadbox 面板立即显示该任务为已关闭,任何之前被它阻塞的任务都亮起为新可用。你看到级联效应,不需要运行任何命令。
这很重要,因为智能体工作会产生突发。一个智能体可能在 90 秒内关闭三个任务,每个解除不同下游工作的阻塞。30 秒刷新间隔的轮询式面板会显示令人困惑的中间状态。亚秒级传播让你在全貌发生时就看到它。
如果你不使用 Beadbox,文件系统监听仍然有效:
# Watch the beads database for changes, alert on new blocks
# Note: fswatch fires on every write. In production you'd debounce this
# (e.g., sleep 2 after each trigger) to avoid noise during burst writes.
fswatch -o .beads/ | while read; do
BLOCKED_COUNT=$(bd blocked --json | jq length)
if [ "$BLOCKED_COUNT" -gt 0 ]; then
echo "$(date): $BLOCKED_COUNT tasks currently blocked"
# Pipe to ntfy, Slack webhook, or any notification system
fi
done
用 CI 闭环:
# In your CI post-build step: auto-close the issue when the build passes
if [ "$BUILD_STATUS" = "success" ]; then
ISSUE_ID=$(echo "$BRANCH_NAME" | grep -oE 'beads-[a-z0-9]+')
if [ -n "$ISSUE_ID" ]; then
bd update "$ISSUE_ID" --status=closed
bd comments add "$ISSUE_ID" --author ci \
"Build passed. Commit: $COMMIT_SHA. Closing automatically."
fi
fi
当 CI 关闭那个 issue 时,所有被它阻塞的任务都解除阻塞。如果智能体在监听 bd ready 寻找新工作,它会自动认领已解除阻塞的任务。常规解除阻塞不需要人工介入。
这就是追踪状态的工具和传播状态的工具之间的区别。大多数项目管理软件做前者:你更新一张卡片,卡片变色。传播意味着下游效应(解除阻塞依赖者、浮现可用工作、更新进度汇总)自动发生,不需要任何人点击任何东西。
评估智能体工作流的分类工具
如果你在为管理智能体集群挑选工具,需求和人类团队不同。
必须有:智能体可调用的 CLI。 如果你的 issue 追踪器只有 Web UI,智能体用不了。它们需要能运行 shell 命令。bd create、bd update、bd blocked 都是单行命令,任何编程智能体都知道怎么执行。REST API 也行,但需要 auth token、HTTP 客户端和错误处理。Unix 管道更简单。
必须有:可查询的依赖图。 "Blocked"作为状态标签对自动化没用。你需要将"A 依赖 B"作为结构化数据,这样脚本可以遍历图、检测循环、计算什么就绪了。
必须有:亚秒级本地读取。 当智能体查询可用工作时,响应时间很重要。每次查询 2 秒的 API 往返,乘以 10 个智能体每分钟轮询一次,会产生可测量的开销。beads 在 10K issue 数据库上返回 bd ready 结果只需 30ms,因为一切都在本地。
锦上添花:实时变更传播。 如果智能体每小时提交和解决 50 个 issue,你需要看到状态随变化而变,而不是等刷新间隔。
红旗:"AI 驱动的阻塞检测"。 声称通过分析 issue 描述来检测阻塞的工具会产生误报,并遗漏那些从未被写下来的真实阻塞。明确的 bd dep add 声明优于推断。
红旗:需要浏览器才能分类的工具。 通过 Web UI 解除一个任务的阻塞需要 5-15 秒的点击。通过 CLI,bd dep remove 只需 18ms。在 50 个阻塞任务上,那就是 1 分钟对 12 分钟。当你在监督快速移动的智能体时,分类速度就是你的瓶颈。
常见工具如何处理阻塞
| 能力 | Jira | Linear | GitHub Issues | beads + Beadbox |
|---|---|---|---|---|
| 依赖追踪 | 插件 (Advanced Roadmaps) | Relations (部分) | Tasklist 引用 | 一等公民 bd dep add |
| 自动设置阻塞状态 | 手动 | 手动 | 手动 | 从依赖自动推断 |
| 循环检测 | 无 | 无 | 无 | 内置 (bd dep cycles) |
| 智能体可用的 CLI | Jira CLI (第三方) | Linear CLI (有限) | gh (无依赖功能) |
完整 (bd blocked, bd ready) |
| 实时传播 | Webhook (服务端) | Webhook (服务端) | Webhook (服务端) | fs.watch (亚秒级,本地) |
| 离线/本地工作 | 否 | 否 | 否 | 是 (嵌入模式) |
| 智能体可脚本化 | API + auth tokens | API + auth tokens | gh CLI |
bd CLI (Unix 管道) |
Supervisor 循环
这是我们每天管理 10+ AI 智能体在同一项目上的工作流:
-
智能体在创建任务时声明依赖。 每个有前置条件的
bd create立即跟一个bd dep add。每个任务只是一个额外的 CLI 调用。 -
Supervisor 智能体每 30 分钟运行
bd blocked。 如果有新的阻塞,它要么自己解决(重新排优先级、重新分配),要么通知人类。 -
Beadbox 运行在人类的屏幕上。 面板实时显示完整的依赖图,高亮被阻塞的任务。大多数时候,自动化处理常规解除阻塞。当它无法处理时(外部依赖、架构决策、权限授予),人类立即看到问题并介入。
-
停滞任务被积极标记。 一个智能体如果 2 小时没有更新其 in-progress 任务,要么卡住了要么崩溃了。supervisor 检查并要么提醒智能体、重新分配工作,或进行调查。
-
虚假依赖被持续清理。 智能体在规划阶段过度声明依赖。随着实现揭示工作的真实形态,supervisor(或智能体自己)移除那些被证明不必要的依赖。干净的图才是有用的图。
底层原则:智能体速度快但不具备自我感知。它们不知道其他智能体在做什么,不注意阻塞何时解除,被卡住时也不抱怨。supervisor 的职责是成为连接所有这一切的神经系统。结构化的依赖数据,自动查询并可视化呈现,是让这一切成为可能的关键。
Beadbox 在 beta 期间免费。 它让你实时看到智能体在做什么、什么被阻塞、以及什么刚变为可用。
brew tap beadbox/cask && brew install --cask beadbox