第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_CODE_PRINT_BG_WAIT_CEILING_MS 均在此版本稳定)。ANTHROPIC_API_KEY 环境变量或 apiKeyHelper,避免 OAuth/keychain 在无人值守环境卡住。jq(结构化解析必备)、GNU parallel(sudo apt install parallel 或 brew install parallel)、git。--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'
要点解析:
--permission-mode dontAsk:批量任务不能有任何交互式权限提示。dontAsk 会拒绝一切不在 permissions.allow 规则或只读命令集内的操作——CI 锁定环境首选。若你确实要 Agent 写文件,改用 acceptEdits(自动批准写文件及 mkdir/touch/mv/cp 等常见文件系统命令,但网络请求、其它 shell 命令仍需 --allowedTools 明示)。--max-turns 20:给 Agent 兜底,防止某个仓库陷入反复搜索的死循环烧光预算。--allowedTools 用 Bash(grep:*) 这种带前缀的细粒度写法,比放开整个 Bash 工具安全得多。--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 层工具。
xargs -P(零依赖,最简)mkdir -p out
cat repos.txt | xargs -P 4 -I{} ./analyze-one.sh {}
-P 4 表示 4 路并发,-I{} 把每行仓库地址替换进脚本参数。机器上没有 GNU parallel 时的首选。
mkdir -p out
parallel -j 4 --bar --joblog parallel.log --resume-failed \
./analyze-one.sh ::: $(cat repos.txt)
-j 4:并发度,与你的 API 配额挂钩。--bar:进度条,跑几十上百个时心理负担小很多。--joblog parallel.log:每个任务的退出码、耗时一目了然。--resume-failed:只重跑上次失败的,这是批量的省命功能。并发瓶颈几乎永远是模型侧配额而非本机 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
required 是否覆盖所有聚合用到的字段,并在 prompt 里明示"无内容也要返回空数组/默认值"。system/api_retry 的 error 频繁出现 rate_limit,立刻降 -j,别硬扛。--max-turns 兜底;同时把每库成本写到 cost.tsv,异常高成本就是异常信号的红旗。-p 的 stdin 上限 10MB,超限会以非零状态退出。批量时不要 cat 巨大文件 | claude,改成在 prompt 里引用文件路径让 Agent 自己读。claude -p 收尾后约 5 秒优雅期会终止它启动的后台 Bash 任务;后台 subagent/workflow 默认最多等 10 分钟(CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS 可调,设 0 为无限)。--bare,被某台机器的 ~/.claude 配置污染了。回归 --bare 是第一排查动作。--bare + --json-schema + 并发 思路在 SDK 里对应结构化输出与并发批处理 API。--output-format stream-json 的完整事件谱:system/init、system/api_retry、plugin_install 等,是构建自定义编排看板的数据底座。/agents 与 --agents):把"审计员"固化成一个可复用角色,批量时通过 --agents 注入,比每次靠 prompt 描述更稳。--resume / --continue:单仓库分析被打断时按 session 续跑,与批量的 --resume-failed 是不同层级的"续命"。claude -p 与基础 shell 经验。--bare"、能否用 --json-schema 让结果稳定聚合、能否用 parallel --resume-failed 设计可重复执行的流水线、能否用 total_cost_usd 做预算护栏。--bare 推荐态、--output-format/--json-schema、system/api_retry、后台任务优雅期与 CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS 的权威说明。print.ts、StructuredIO、runHeadless 源码层面拆解非交互输出管线与会话生命周期,索引日期 2026-04-30。--print 标志、管道输入、CI/CD 自动化与脚本编排的实战范例集合。[!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 等场景全覆盖。
