Headless 与脚本化
本教程共 34 篇 · 第 29 篇 · 更新于 2026-07-26 · 约 8 分钟阅读
29. Headless 与脚本化
本节目标:学会用
-p打印模式把 Claude Code 当命令行工具用,掌握管道组合、结构化输出、无人值守配置,并了解 Agent SDK 怎么把 Claude Code 嵌进你自己的程序。
什么是 Headless 模式
前面那么多章,Claude Code 都是交互式跑的:你敲一句、它回一句。但很多时候你想把它塞进脚本里自动跑,比如 CI 里审查代码、定时任务里汇总日志、构建失败时自动分析原因。
这就需要 Headless(无头)模式。说白了,就是不让 Claude 开那个交互界面,直接给它一个提示,让它干完活把结果吐出来,然后退出。
Agent SDK 给了你和 Claude Code 一样的工具、agent 循环和上下文管理。它既能当 CLI 用(就是 claude -p),也能当 Python、TypeScript 包用,做完整的编程控制。
这章主要讲 CLI 这条路(claude -p),SDK 包的部分最后简单提一下。
-p 打印模式基本用法
给 claude 加个 -p(或 --print)标志,就是非交互模式。所有 CLI 选项都能配合 -p 用:
claude -p "What does the auth module do?"
它跑完直接打印结果,然后退出,不会停下来等你。
跟交互模式一样,-p 默认会加载工作目录或 ~/.claude 里配的 hooks、skills、plugins、MCP 服务器和 CLAUDE.md。这在本地用没问题,但在 CI 里可能就不想要这些「个人配置」干扰。
—bare 裸模式
加 --bare 跳过所有自动发现,启动更快,结果更可控:
claude --bare -p "Summarize this file" --allowedTools "Read"
裸模式下,队友 ~/.claude 里的 hook、项目 .mcp.json 里的 MCP 服务器都不会跑,只有你显式传的标志才生效。这在 CI 里特别重要,能保证每台机器上结果一致。
裸模式下 Claude 还是能用 Bash、文件读写和文件编辑工具。需要啥上下文,用标志传进去:
| 要加载的东西 | 用的标志 |
|---|---|
| 系统提示补充 | --append-system-prompt、--append-system-prompt-file |
| 设置 | --settings <file-or-json> |
| MCP 服务器 | --mcp-config <file-or-json> |
| 自定义 agents | --agents <json> |
| 插件 | --plugin-dir <path>、--plugin-url <url> |
Note
--bare是脚本和 SDK 调用的推荐模式,未来版本会成为-p的默认行为。裸模式会跳过 OAuth 和钥匙链读取,认证必须来自ANTHROPIC_API_KEY环境变量或--settings里的apiKeyHelper。
管道组合
非交互模式会读 stdin,所以你能像用任何 Unix 工具一样,把数据管道喂给它,再把结果重定向出去。
这个例子把构建错误日志喂给 Claude,让它分析根因,结果写进文件:
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt
也可以塞进 package.json 的脚本里,把 Claude 当项目专用的 linter。下面这个脚本把针对 main 的 diff 喂给 Claude,让它挑拼写错误:
{
"scripts": {
"lint:claude": "git diff main | claude -p \"you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next.\""
}
}
管道传 diff 的好处是:Claude 不需要 Bash 权限去读文件,权限更干净。
Warning从 v2.1.128 起,管道 stdin 上限 10MB。超了会报错退出。内容太大就写进文件,在提示里引用文件路径,别硬管道。
结构化输出
三种输出格式
用 --output-format 控制返回方式:
text(默认):纯文本json:结构化 JSON,包含结果、会话 ID 和元数据stream-json:换行符分隔的 JSON,用于实时流式传输
要 JSON 格式很简单:
claude -p "Summarize this project" --output-format json
JSON 里除了文本结果(result 字段),还带 total_cost_usd 和按模型的成本分解,方便脚本跟踪每次调用的花费。
JSON Schema 约束输出
想让输出严格符合某个结构?用 --output-format json 配合 --json-schema 和 JSON Schema 定义。结构化结果在 structured_output 字段里。
这个例子从 auth.py 提取函数名,返回字符串数组:
claude -p "Extract the main function names from auth.py" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'
配合 jq 工具解析特别顺手:
# 提取纯文本结果
claude -p "Summarize this project" --output-format json | jq -r '.result'
# 提取结构化输出
claude -p "Extract function names from auth.py" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
| jq '.structured_output'
Tip如果
--json-schema的值不是合法 JSON Schema,Claude 会报错退出。注意它接受format关键字(比如"format": "email"),但只当注释看,不强制校验。
流式输出
想实时看到 Claude 一个字一个字吐出来,用 stream-json 配合 --verbose 和 --include-partial-messages:
claude -p "Explain recursion" --output-format stream-json --verbose --include-partial-messages
每一行是一个 JSON 事件对象。流的最后一行是 result 消息,包含最终文本、成本和会话元数据。
只想要流式文本,用 jq 过滤一下:
claude -p "Write a poem" --output-format stream-json --verbose --include-partial-messages | \
jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
流里还有 system/init(会话启动,报告模型、工具、插件)、system/api_retry(API 重试)等事件,方便你做进度展示或退避逻辑。
无人值守的关键配置
让 Claude 自己跑,最怕两件事:一是它停下来问你要权限,二是它无限循环烧钱。下面这几个配置专门解决这些。
自动批准工具
用 --allowedTools 让 Claude 用某些工具时不弹权限提示:
claude -p "Run the test suite and fix any failures" \
--allowedTools "Bash,Read,Edit"
这个例子让它跑测试、修失败,Bash 命令和读写文件都不用问。
工具名还能带参数规则。比如只想让它跑 git 相关命令:
claude -p "Look at my staged changes and create an appropriate commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"
Bash(git diff *) 里的 * 是前缀匹配,注意 * 前面要有空格,不然 git diff* 会连 git diff-index 也匹配上。
权限模式
不想一个个列工具,用 --permission-mode 设个基线:
acceptEdits:自动批准写文件,还有mkdir、touch、mv、cp这些常见文件命令,但网络请求和其他 shell 命令还得单独批准dontAsk:拒绝所有不在permissions.allow规则或只读命令集里的东西,适合锁死的 CI
claude -p "Apply the lint fixes" --permission-mode acceptEdits
继续会话
非交互模式也能延续之前的对话。--continue 接最近的,--resume 接指定会话 ID:
# 第一次请求
claude -p "Review this codebase for performance issues"
# 继续最近的对话
claude -p "Now focus on the database queries" --continue
claude -p "Generate a summary of all issues found" --continue
跑多个对话时,先抓会话 ID 再精确恢复:
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"
Note会话 ID 的查找范围限定在当前项目目录及其 git worktrees。两个命令要从同一目录跑才能找到对应会话。
自定义系统提示
--append-system-prompt 在保留 Claude Code 默认行为的基础上加指令。这个例子把 PR diff 喂给 Claude,让它当安全工程师审查漏洞:
gh pr diff "$1" | claude -p \
--append-system-prompt "You are a security engineer. Review for vulnerabilities." \
--output-format json
想完全替换默认提示,用 --system-prompt,但一般不推荐,因为会丢掉 Claude Code 内置的那些工具使用规则。
Agent SDK 概览
上面讲的都是 CLI(claude -p)这条线。如果你想要更深的编程控制,比如结构化输出回调、工具批准回调、原生消息对象,就该上 Agent SDK 的 Python 或 TypeScript 包了。
它是什么
Agent SDK 把驱动 Claude Code 的工具、agent 循环和上下文管理,开放成了可编程的库。简单说,就是把 Claude Code 当一个库来用,嵌进你自己的应用、CI 流水线或自动化脚本里。
内置能力包括:
- 文件读写、终端命令、代码编辑、Web 搜索等内置工具
- 钩子(Hook):在工具调用前后执行自定义逻辑
- 子代理(Subagent):把大任务拆开并行交给独立 agent
- MCP 服务器:连数据库、浏览器、外部 API
- 权限控制:精细控制 agent 能干啥、啥时候要审批
- 会话管理:保持上下文的多轮对话
安装
TypeScript:
npm install @anthropic-ai/claude-agent-sdk
TypeScript SDK 会把当前平台的 Claude Code 二进制文件当可选依赖一起打包,不用单独装 Claude Code。
Python:
# 用 pip
pip install claude-agent-sdk
# 或用 uv(推荐)
uv add claude-agent-sdk
Python 包也会自动带上 Claude Code CLI,默认用打包的 CLI。想用系统装的或指定版本,传 ClaudeAgentOptions(cli_path="/path/to/claude")。
配置 API Key
从 Claude Console 拿到 API Key,设成环境变量:
export ANTHROPIC_API_KEY=your-api-key-here
SDK 也支持第三方云:Amazon Bedrock(CLAUDE_CODE_USE_BEDROCK=1)、Google Cloud 的 Agent Platform(CLAUDE_CODE_USE_VERTEX=1)、Microsoft Foundry(CLAUDE_CODE_USE_FOUNDRY=1)。
Warning除非事先获得 Anthropic 批准,第三方开发者不许在基于 Agent SDK 构建的产品里提供 claude.ai 登录或速率限制。老老实实用 API Key 认证。
一个简单例子
Python 版,让 agent 列出当前目录的文件:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
async for message in query(
prompt="What files are in this directory?",
options=ClaudeAgentOptions(),
):
print(message)
asyncio.run(main())
TypeScript 版类似,调 query 函数,传 prompt 和 options,异步遍历消息流。
什么时候用哪个
简单总结一下选型:
- 临时跑一下、写脚本:直接
claude -p,够用 - CI 里要可控、要可复现:
claude --bare -p,加--allowedTools和权限模式 - 要嵌进自己的程序、做复杂编排:上 Agent SDK 的 Python 或 TypeScript 包
不管哪条路,核心都是把 Claude Code 的能力从「你盯着它干」变成「它自己干完汇报」。这是从「AI 助手」走向「AI 自动化」的关键一步。