首页 › tutorials › 批量并行Agent:--bare横扫多仓库

第4轮 · Agent模式与自动化专题。本文聚焦一个被反复问到却少有人讲透的场景:当你不是要跑一个 Agent,而是要同时跑几十上百个独立 Agent——扫描一批仓库、给一批文档逐个生成摘要、给一批 API 接口逐个写测试——该用什么姿势。答案是 --bare 确定性模式 + --json-schema 结构化输出 + 外部并发工具三层组合。

一、概述

本教程面向已经写过单条 claude -p 命令、想把 Claude Code 从"按一次回车跑一个任务"升级为"批量吞吐一条流水线"的开发者。学完你将掌握:为什么批量场景必须用 --bare 而非普通 -p;如何用 --json-schema 保证每条结果的字段稳定可聚合;如何用 total_cost_usd 做令牌预算护栏;如何用 GNU parallel / xargs 控制外部并发;以及如何把上百条结构化结果聚合成一份统一报告。整篇围绕一个可运行实战:批量扫描多仓库的安全隐患与许可证,生成统一 Markdown 报告。

二、前置条件

三、核心机制:批量场景为什么必须上 --bare

普通 claude -p 会加载一次完整交互会话的上下文:工作目录与 ~/.claude 里的 hooks、skills、plugins、MCP 服务器、auto memory、CLAUDE.md 全部生效。单条调用无伤大雅,但在批量场景里这是灾难的根源——

风险 普通 -p 的表现 --bare 的表现
团队成员机器差异 A 同学的 ~/.claude 装了某 hook,B 同学没有,同一脚本结果不一致 跳过所有本地 hook/skill/plugin/MCP/CLAUDE.md,结果只取决于你显式传入的 flag
启动开销 每个 worker 都加载 MCP、扫描 skills,几十并发时启动延迟被放大 跳过自动发现,冷启动更快
误触发副作用 项目 .mcp.json 里的服务器在 CI 上连不上,整个批次卡权限提示 从不读取它们,只承认你 --mcp-config 指定的

官方文档明确建议:--bare 是脚本与 SDK 调用的推荐模式,未来会成为 -p 的默认行为。批量任务的第一条铁律就是——

claude --bare -p "你的任务" --allowedTools "Read"

--bare 下 Claude 默认只拥有 Bash、文件读、文件写三类工具,其它一切上下文都要显式传入:

想加载 用哪个 flag
追加系统提示 --append-system-prompt 或 --append-system-prompt-file
配置项 --settings <file-or-json>
MCP 服务器 --mcp-config <file-or-json>
自定义 subagent --agents <json>
插件 --plugin-dir <path> 或 --plugin-url <url>

注意:--bare 会跳过 OAuth 和 keychain 读取,认证必须来自 ANTHROPIC_API_KEY 或 --settings 里的 apiKeyHelper。

四、步骤一:让单条结果稳定可聚合——--json-schema

批量的命门是"每条结果字段必须一致",否则后续聚合无从下手。--output-format json 返回的 result 是自由文本,但叠加 --json-schema 后,结构化结果会落在 structured_output 字段,严格遵循你给的 schema:

# finding-schema.json
{
  "type": "object",
  "properties": {
    "repo": { "type": "string" },
    "risk_level": { "type": "string", "enum": ["low", "medium", "high", "critical"] },
    "findings": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "category": { "type": "string", "enum": ["secret", "license", "dependency", "config"] },
          "file": { "type": "string" },
          "severity": { "type": "string", "enum": ["info", "warn", "error"] },
          "detail": { "type": "string" }
        },
        "required": ["category", "severity", "detail"]
      }
    },
    "license": { "type": "string" }
  },
  "required": ["repo", "risk_level", "findings"]
}

单条调用:

claude --bare -p "$(cat prompt.txt)" \
  --allowedTools "Read,Bash(grep:*),Bash(git log:*)" \
  --output-format json \
  --json-schema @finding-schema.json \
  --permission-mode dontAsk \
  --max-turns 20 \
  | jq '.structured_output'

要点解析:

五、步骤二:成本与重试的可见性

--output-format json 的载荷自带 total_cost_usd 和按模型的成本拆分,这是做批量预算护栏的关键数据源——脚本调用方无需翻用量后台就能逐条记账:

claude --bare -p "..." --output-format json --json-schema @s.json | \
  jq '{cost: .total_cost_usd, session: .session_id, out: .structured_output}'

重试发生在网络层时,普通 text 模式下你什么都看不到;切到 stream-json 却能捕获 system/api_retry 事件,字段如下:

字段 含义
attempt 当前重试次数,从 1 起
max_retries 允许的总重试次数
retry_delay_ms 距下次重试的毫秒数
error_status HTTP 状态码,连接错误时为 null
error 错误类别:rate_limit / overloaded / billing_error / authentication_failed / server_error / max_output_tokens 等

实战中,用这段一行命令把重试情况落到日志,便于事后定位是限流还是账单问题:

claude --bare -p "..." --output-format stream-json --verbose \
  | jq -rc 'select(.type=="system" and .subtype=="api_retry")' >> retries.log

旁支知识点:system/init 事件会汇报本会话加载的 model/tools/MCP/plugins,以及 plugin_errors。批量场景里可以用它做 CI 准入校验——"插件没加载成功就让流水线失败"。

六、步骤三:用外部并发工具横扫

到这里单条调用已经稳定、可计费、可重试。批量的最后一步是把"一条"变成"一片"。关键认知:每个 claude -p 进程是独立会话,彼此无共享状态,因此并发不是靠 Claude 内部,而是靠 shell 层工具。

方案 A:xargs -P(零依赖,最简)

mkdir -p out
cat repos.txt | xargs -P 4 -I{} ./analyze-one.sh {}

-P 4 表示 4 路并发,-I{} 把每行仓库地址替换进脚本参数。机器上没有 GNU parallel 时的首选。

方案 B:GNU parallel(推荐,控制力更强)

mkdir -p out
parallel -j 4 --bar --joblog parallel.log --resume-failed \
  ./analyze-one.sh ::: $(cat repos.txt)

并发度怎么定

并发瓶颈几乎永远是模型侧配额而非本机 CPU。若你用的是 Claude Pro/Max 订阅(按 5 小时/每周窗口限流),并发开太高会瞬间打满窗口、整批被限流;若用 API 计费,则看 RPS/TPM 限额。经验起点是 -j 4,观察 system/api_retry 里的 rate_limit 频率,频繁出现就降并发,几乎不出现才缓慢上调。

七、实战案例:多仓库安全与许可证扫描流水线

把前面四步串成一个完整项目。目录结构:

batch-scan/
├── repos.txt              # 每行一个 git 仓库地址
├── prompt.txt             # 统一提示词
├── finding-schema.json    # 结构化输出 schema
├── analyze-one.sh         # 单仓库分析脚本
├── run-batch.sh           # 并发编排入口
└── aggregate.sh           # 结果聚合脚本

prompt.txt(提示词只描述任务,结构由 schema 约束):

你是仓库安全审计员。对当前仓库做一次轻量审计:
1. 扫描疑似硬编码密钥(secret);
2. 读取 LICENSE 或 package.json 的 license 字段;
3. 检查依赖清单里是否有已知高危或停维包;
4. 检查配置文件里是否有调试模式开启等配置风险。
按给定 schema 输出,findings 为空数组也要返回,risk_level 按最严重项定级。

analyze-one.sh(单仓库,一个 in 一个 out):

#!/usr/bin/env bash
set -euo pipefail
repo="$1"
name="$(basename "$repo" .git)"
work="$(mktemp -d)"
out="out/${name}.json"

git clone --depth 1 --quiet "$repo" "$work" 2>/dev/null || { echo "clone-fail: $repo" >&2; exit 2; }

( cd "$work" && claude --bare -p "$(cat "$OLDPWD/prompt.txt")" \
    --allowedTools "Read,Bash(grep:*),Bash(git log:*),Bash(ls:*)" \
    --output-format json \
    --json-schema @"$OLDPWD/finding-schema.json" \
    --permission-mode dontAsk \
    --max-turns 25 ) > "$out"

# 落一条成本账
jq -r --arg n "$name" '[ $n, (.total_cost_usd // 0) ] | @tsv' "$out" >> cost.tsv
echo "ok: $name"

run-batch.sh(编排入口,可重复执行、只补失败项):

#!/usr/bin/env bash
set -euo pipefail
mkdir -p out
: > cost.tsv
export ANTHROPIC_API_KEY  # 确保 --bare 认证可用
parallel -j 4 --bar --joblog parallel.log --resume-failed \
  ./analyze-one.sh ::: "$(cat repos.txt)"
./aggregate.sh

aggregate.sh(把上百份 JSON 聚合成一份人类可读报告):

#!/usr/bin/env bash
set -euo pipefail
{
  echo "# 多仓库审计报告"
  echo
  echo "扫描仓库数:$(ls out/*.json | wc -l)"
  echo "总成本(USD):$(awk -F'\t' '{s+=$2} END{printf "%.4f", s}' cost.tsv)"
  echo
  echo "## 风险概览"
  for f in out/*.json; do
    jq -r '"- **\(.structured_output.repo)** —— \(.structured_output.risk_level) | 许可证: \(.structured_output.license // "未声明") | 发现: \(.structured_output.findings|length) 项"' "$f"
  done
  echo
  echo "## 高危项明细(severity=error)"
  for f in out/*.json; do
    jq -r '.structured_output.findings[] | select(.severity=="error") | "- [\(.category)] \(.file // "-"): \(.detail)"' "$f"
  done
} > REPORT.md
echo "报告已生成: REPORT.md"

一次运行的效果:30 个仓库以 4 路并发跑完,out/ 下每库一份 JSON,cost.tsv 逐条记账,parallel.log 记录退出码与耗时,最终 REPORT.md 汇总风险等级、许可证、高危明细与总成本。某库失败?直接再跑一遍 run-batch.sh,--resume-failed 只补它一个,已成功的绝不重跑、不重复计费。

八、流程全景

flowchart TD
    A[repos.txt 仓库清单] --> B[run-batch.sh]
    B --> C{GNU parallel -j 4}
    C -->|worker 1| D1[analyze-one.sh]
    C -->|worker 2| D2[analyze-one.sh]
    C -->|worker N| DN[analyze-one.sh]
    D1 --> E1[git clone --depth1]
    D2 --> E2[git clone --depth1]
    DN --> EN[git clone --depth1]
    E1 --> F1["claude --bare -p<br/>--json-schema<br/>--permission-mode dontAsk"]
    E2 --> F2["claude --bare -p<br/>--json-schema<br/>--permission-mode dontAsk"]
    EN --> FN["claude --bare -p<br/>--json-schema<br/>--permission-mode dontAsk"]
    F1 --> G1["out/repo1.json<br/>含 structured_output + total_cost_usd"]
    F2 --> G2["out/repo2.json"]
    FN --> GN["out/repoN.json"]
    G1 & G2 & GN --> H[aggregate.sh + jq]
    H --> I[REPORT.md 统一报告]
    F1 -.system/api_retry.-> R[(retries.log)]
    C -.退出码/耗时.-> L[(parallel.log)]
    L -.失败项.->|resume-failed 重跑| B

九、常见坑与对策

十、延伸阅读

训练营适用性评估

参考来源

  1. Run Claude Code programmatically — Claude Code 官方文档 — --bare 推荐态、--output-format/--json-schema、system/api_retry、后台任务优雅期与 CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS 的权威说明。
  2. CLI Output & Headless Mode — DeepWiki (kdxsydq/ClaudeCode) — 从 print.ts、StructuredIO、runHeadless 源码层面拆解非交互输出管线与会话生命周期,索引日期 2026-04-30。
  3. Claude Code Headless Mode: Non-Interactive & CI Usage (2026) — --print 标志、管道输入、CI/CD 自动化与脚本编排的实战范例集合。
  4. Claude Code CLI: The Complete Guide — Hooks, MCP, Skills — CLI flag 全景参考,含会话管理、模型选择、输出格式的横向对照。
  5. Claude Code CLI: Commands, Flags & Terminal Guide (2026) — 终端命令、flag 与管道用法的速查手册,适合作为批量脚本编写时的查表来源。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入