首页 › tutorials › Claude Code无头模式与Agent SDK编程实战

概述

本文系统讲解 Claude Code 三大自动化能力的原理与实战:无头模式(Headless Mode) 通过 -p 标志实现非交互式调用;Hooks 钩子系统 在工具执行前后自动触发自定义逻辑;Agent SDK 将 Claude Code 的完整能力以编程方式嵌入你自己的应用。适合已有 Claude Code 使用经验、希望将其接入 CI/CD、批量处理或构建自定义 AI Agent 的开发者。

学习目标: - 掌握 claude -p 的全部参数与输出格式控制 - 理解 5 种 Hook 事件的触发时机与配置方法 - 用 TypeScript Agent SDK 编写可编程的自主 Agent - 组合三大能力构建生产级自动化流水线

适用人群:中高级开发者、DevOps 工程师、AI 应用构建者


前置条件

项目 要求
Claude Code ≥ 2.1.x(claude --version 确认)
Node.js ≥ 18.x(Agent SDK 依赖)
TypeScript ≥ 5.x(Agent SDK 开发)
操作系统 macOS / Linux / WSL2
Claude 订阅 Max 计划或 Team/Business 计划
基础知识 熟悉 Shell 脚本、JSON 配置、npm 包管理

第一章:无头模式(Headless Mode)完全指南

1.1 什么是无头模式

无头模式让 Claude Code 脱离交互式 REPL 界面,以命令行参数驱动的方式运行。所有工具能力(文件读写、Shell 执行、搜索等)均可使用,但无人值守——输出直接打印到标准输出,适合管道串联和脚本编排。

核心标志:-p 或 --print。

1.2 基础用法

# 最简单的无头调用——输出纯文本
claude -p "解释当前项目的目录结构"

# 管道输入——将文件内容喂给 Claude
cat src/utils.ts | claude -p "为这个文件添加 JSDoc 注释"

# 捕获输出到变量
result=$(claude -p "列出所有 TODO 注释")
echo "$result"

# 输出重定向到文件
claude -p "生成 README.md 的内容" > README.md

1.3 关键参数详解

无头模式的威力来自丰富的参数组合:

参数 说明 示例
-p / --print 启用无头模式 claude -p "hello"
--output-format 输出格式:text、json、stream-json --output-format json
--max-turns 限制 Agent 循环轮次 --max-turns 5
--allowedTools 限制可用工具列表 --allowedTools "Read,Glob,Grep"
--system-prompt 自定义系统提示 --system-prompt "你是代码审查专家"
--append-system-prompt 追加系统提示 --append-system-prompt "用中文回答"
--resume 恢复指定会话 --resume session-abc123
--continue 继续最近一次会话 --continue
--model 指定模型 --model claude-sonnet-4-6
--verbose 详细输出(调试用) --verbose
--permission-mode 权限模式 --permission-mode plan

1.4 输出格式与解析

--output-format json 是自动化场景的基石。JSON 输出结构化数据,便于程序解析:

# JSON 格式输出——提取结构化结果
claude -p "分析 package.json 中的依赖版本是否过时" \
  --output-format json

# stream-json 模式——实时流式输出(适合长任务监控)
claude -p "重构整个 src 目录的 import 语句" \
  --output-format stream-json \
  --max-turns 10

JSON 输出包含的关键字段:

{
  "type": "result",
  "subtype": "success",
  "cost_usd": 0.042,
  "duration_ms": 15230,
  "duration_api_ms": 12800,
  "num_turns": 3,
  "result": "已完成所有 import 语句的重构...",
  "session_id": "sess_abc123"
}

1.5 安全沙箱:权限与工具控制

在自动化场景中,安全是第一要务。通过参数限制 Agent 的行为边界:

# 只读模式——只允许搜索和阅读,不能修改文件
claude -p "审查最近的 git commit 是否有安全漏洞" \
  --allowedTools "Read,Glob,Grep,Bash" \
  --max-turns 3

# 限制 Bash 命令范围(结合 permission-mode)
claude -p "运行测试并报告结果" \
  --permission-mode plan \
  --max-turns 5

# 预设系统提示,约束行为
claude -p "分析代码质量" \
  --system-prompt "你是一个保守的代码审查员。只报告确定的问题,不要修改任何文件。" \
  --allowedTools "Read,Glob,Grep"

1.6 常见问题与解决

问题 原因 解决方案
输出包含 ANSI 转义码 终端颜色控制字符 加 --output-format json 或设置 NO_COLOR=1
Agent 无限循环 无 turn 限制 始终设置 --max-turns
权限弹窗阻塞 工具需要授权 使用 --allowedTools 白名单 + --permission-mode
输出被截断 Token 上限 使用 --output-format stream-json 流式处理
费用失控 无成本感知 JSON 输出中检查 cost_usd 字段

第二章:Hooks 钩子系统——事件驱动的自动化

2.1 Hooks 是什么

Hooks 是 Claude Code 的"神经系统"——在特定生命周期事件发生时,自动执行你预设的 Shell 命令、HTTP 请求或 LLM 提示。不同于手动编写脚本串联,Hooks 由 Claude Code 引擎在运行时自动触发,零延迟、零遗漏。

Hooks 配置位于 settings.json(项目级 .claude/settings.json 或用户级 ~/.claude/settings.json)。

2.2 五种 Hook 事件

flowchart TD
    A[用户发送消息] --> B[SessionStart]
    B --> C[Agent 循环开始]
    C --> D{选择工具}
    D --> E[PreToolUse]
    E --> F{钩子返回}
    F -->|批准| G[执行工具]
    F -->|阻止| H[跳过工具]
    G --> I[PostToolUse]
    I --> J{还有工具?}
    J -->|是| D
    J -->|否| K[Stop]
    K --> L[Notification]

    style E fill:#ff9800,color:#fff
    style I fill:#4caf50,color:#fff
    style B fill:#2196f3,color:#fff
    style K fill:#f44336,color:#fff
    style L fill:#9c27b0,color:#fff
事件 触发时机 典型用途
PreToolUse 工具执行之前 安全检查、命令拦截、参数修改
PostToolUse 工具执行之后 自动格式化、通知发送、结果验证
Notification 任务完成时 Slack/Discord 通知、日志记录
Stop Agent 停止时 最终检查、生成报告
SessionStart 会话启动时 环境初始化、加载上下文

2.3 配置结构

在 .claude/settings.json 中添加 hooks 字段:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/pre-write-guard.py"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $CLAUDE_FILE_PATH"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/task-complete-notify.py"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK -H 'Content-type: application/json' -d '{\"text\":\"Claude Code 任务完成\"}'"
          }
        ]
      }
    ]
  }
}

2.4 Hook 的输入输出

每个 Hook 通过 stdin 接收 JSON 输入,通过 stdout 返回 JSON 输出。这是核心协议:

PreToolUse 输入(stdin):

{
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/project/src/config.ts",
    "content": "export const API_KEY = '...'"
  },
  "session_id": "sess_abc123"
}

PreToolUse 输出(stdout)——三种决策:

// 1. 批准执行(无输出或空对象)
{}

// 2. 阻止执行
{"decision": "block", "reason": "不允许写入 .env 文件"}

// 3. 修改参数后执行(仅部分工具支持)
{"decision": "approve", "patch": {"content": "// 已清理敏感信息\nexport const config = {}"}}

PostToolUse 输入(stdin):

{
  "tool_name": "Write",
  "tool_input": { "file_path": "/project/src/index.ts" },
  "tool_output": "File written successfully",
  "session_id": "sess_abc123"
}

2.5 Matcher 匹配器语法

matcher 字段控制 Hook 的触发范围:

// 匹配单个工具
"matcher": "Write"

// 匹配多个工具(管道分隔)
"matcher": "Write|Edit"

// 匹配所有工具(空字符串)
"matcher": ""

// 使用正则表达式
"matcher": "Write|Edit|NotebookEdit"

2.6 实战:5 个生产级 Hook

Hook 1:保护敏感文件

阻止 Claude 读写 .env、密钥文件等敏感资源:

#!/usr/bin/env python3
"""pre-write-guard.py — 保护敏感文件不被 Claude 修改"""
import sys, json

PROTECTED_PATTERNS = [
    '.env', '.env.local', '.env.production',
    'credentials', 'secrets', '.pem', '.key'
]

data = json.loads(sys.stdin.read())
file_path = data.get('tool_input', {}).get('file_path', '')

for pattern in PROTECTED_PATTERNS:
    if pattern in file_path:
        print(json.dumps({
            "decision": "block",
            "reason": f"安全策略:禁止修改包含 '{pattern}' 的文件"
        }))
        sys.exit(0)

# 不阻止
print(json.dumps({}))

Hook 2:自动代码格式化

每次写入/编辑后自动运行 Prettier:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

Hook 3:危险命令拦截

阻止 rm -rf、sudo 等高危 Bash 命令:

#!/usr/bin/env python3
"""pre-bash-guard.py — 拦截危险 Shell 命令"""
import sys, json, re

DANGEROUS_PATTERNS = [
    r'rm\s+-rf\s+/',
    r'sudo\s+rm',
    r'drop\s+database',
    r'DROP\s+TABLE',
    r'git\s+push\s+--force',
    r':\(\)\{.*;\};'  # fork bomb
]

data = json.loads(sys.stdin.read())
command = data.get('tool_input', {}).get('command', '')

for pattern in DANGEROUS_PATTERNS:
    if re.search(pattern, command, re.IGNORECASE):
        print(json.dumps({
            "decision": "block",
            "reason": f"安全策略:检测到危险命令模式 '{pattern}'"
        }))
        sys.exit(0)

print(json.dumps({}))

Hook 4:任务完成通知

Agent 停止时发送 Slack 通知:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/notify-slack.py"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env python3
"""notify-slack.py — 任务完成后发送 Slack 通知"""
import sys, json, urllib.request, os

# 从 Stop Hook 的 stdin 读取会话信息
data = json.loads(sys.stdin.read()) if not sys.stdin.isatty() else {}
session_id = data.get('session_id', 'unknown')

webhook_url = os.environ.get('SLACK_WEBHOOK_URL', '')
if not webhook_url:
    sys.exit(0)

payload = {
    "text": f"✅ Claude Code 任务完成 | 会话: {session_id} | 目录: {os.getcwd()}"
}

req = urllib.request.Request(
    webhook_url,
    data=json.dumps(payload).encode(),
    headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)

Hook 5:Git 自动暂存

每次文件修改后自动 git add:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "git add \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

2.7 Hook 类型扩展

除了 command 类型,Hooks 还支持:

// HTTP Hook —— 调用远程 API
{
  "type": "command",
  "command": "curl -s -X POST http://localhost:8080/hook -d @-"
}

// Agent SDK 中的 LLM Hook(编程接口)
// 在 Agent SDK 中可以使用 prompt 类型 Hook,
// 让另一个 LLM 判断是否允许操作

2.8 Hook 调试技巧

# 1. 使用 --verbose 查看 Hook 执行详情
claude -p "测试 hook" --verbose

# 2. 在 Hook 脚本中写调试日志
# 在 Python 脚本中:
import logging
logging.basicConfig(filename='/tmp/claude-hooks.log', level=logging.DEBUG)

# 3. 检查 Hook 退出码
# 退出码 0 = 正常(不阻止)
# 退出码 2 = 阻止操作

# 4. 测试单个 Hook 脚本
echo '{"tool_name":"Write","tool_input":{"file_path":"test.ts"}}' | python3 scripts/pre-write-guard.py

第三章:Agent SDK——编程式 AI Agent

3.1 从 CLI 到 SDK

Agent SDK 是 Claude Code 能力的编程接口。claude -p 适合简单脚本,当你需要构建多步骤、有状态、可编排的 Agent 应用时,Agent SDK 是正确选择。

graph LR
    A[你的应用] --> B[Agent SDK]
    B --> C[Claude Code 引擎]
    C --> D[文件系统]
    C --> E[Shell 命令]
    C --> F[搜索工具]
    C --> G[MCP 服务器]

    style B fill:#ff6b35,color:#fff
    style C fill:#2d3436,color:#fff

3.2 安装与初始化

# 创建项目
mkdir my-agent && cd my-agent
npm init -y

# 安装 Agent SDK
npm install @anthropic-ai/claude-agent-sdk

# TypeScript 支持
npm install -D typescript @types/node
npx tsc --init

3.3 核心概念:query() 函数

query() 是 Agent SDK 的核心——一次调用就是一个完整的 Agent 循环:

// basic-agent.ts
import { query } from '@anthropic-ai/claude-agent-sdk';

async function main() {
  const result = await query({
    prompt: '分析当前项目的依赖关系,找出过时的包',
    options: {
      // 限制工具(安全沙箱)
      allowedTools: ['Read', 'Glob', 'Grep', 'Bash'],
      // 最大循环轮次
      maxTurns: 5,
      // 自定义系统提示
      systemPrompt: '你是一个保守的依赖分析专家。只报告,不修改。',
    },
  });

  console.log('Agent 结果:', result);
  console.log('消耗轮次:', result.numTurns);
  console.log('花费:', result.costUsd);
}

main().catch(console.error);

3.4 消息与对话循环

构建多轮对话 Agent:

// multi-turn-agent.ts
import { query, type Message } from '@anthropic-ai/claude-agent-sdk';

async function reviewAndFix() {
  // 第一步:代码审查
  const reviewResult = await query({
    prompt: '审查 src/ 目录下的所有 TypeScript 文件,找出 bug',
    options: {
      allowedTools: ['Read', 'Glob', 'Grep'],
      maxTurns: 5,
    },
  });

  console.log('📋 审查发现:');
  console.log(reviewResult.result);

  // 第二步:基于审查结果自动修复
  const fixResult = await query({
    prompt: `根据以下审查结果修复所有 bug:\n\n${reviewResult.result}`,
    options: {
      allowedTools: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep'],
      maxTurns: 10,
      systemPrompt: '修复时保持最小改动原则,每个修复添加注释说明原因。',
    },
  });

  console.log('🔧 修复完成:', fixResult.result);

  // 第三步:运行测试验证
  const testResult = await query({
    prompt: '运行项目测试,确认修复没有引入新问题',
    options: {
      allowedTools: ['Bash', 'Read'],
      maxTurns: 3,
    },
  });

  console.log('✅ 测试结果:', testResult.result);
}

reviewAndFix().catch(console.error);

3.5 会话管理

利用会话持久化实现跨调用上下文保持:

// session-agent.ts
import { query } from '@anthropic-ai/claude-agent-sdk';

async function progressiveDevelopment() {
  // 第一次调用——获取 session_id
  const step1 = await query({
    prompt: '阅读 package.json 和 tsconfig.json,理解项目结构',
    options: { maxTurns: 3 },
  });

  const sessionId = step1.sessionId;
  console.log(`会话已建立: ${sessionId}`);

  // 继续同一会话——Claude 记得上文
  const step2 = await query({
    prompt: '基于你对项目的理解,为 src/utils.ts 编写单元测试',
    options: {
      maxTurns: 8,
      continue: sessionId,  // 继续指定会话
    },
  });

  console.log('测试已生成:', step2.result);

  // 再次继续——三步同上下文
  const step3 = await query({
    prompt: '运行刚生成的测试,修复任何失败的用例',
    options: {
      maxTurns: 10,
      continue: sessionId,
    },
  });

  console.log('最终结果:', step3.result);
}

progressiveDevelopment().catch(console.error);

3.6 Agent SDK 中的 Hooks

在编程接口中,Hooks 通过回调函数实现,比 JSON 配置更灵活:

// sdk-hooks-agent.ts
import { query, type HookContext } from '@anthropic-ai/claude-agent-sdk';

async function agentWithHooks() {
  const result = await query({
    prompt: '重构 src/ 目录下的代码',
    options: {
      maxTurns: 10,
      hooks: {
        // 工具执行前——安全检查
        PreToolUse: async (ctx: HookContext) => {
          if (ctx.toolName === 'Bash') {
            const cmd = ctx.toolInput.command as string;
            if (cmd.includes('rm -rf') || cmd.includes('sudo')) {
              return {
                decision: 'block' as const,
                reason: '安全策略:禁止执行危险命令',
              };
            }
          }
          if (ctx.toolName === 'Write' || ctx.toolName === 'Edit') {
            const filePath = ctx.toolInput.file_path as string;
            if (filePath.includes('.env')) {
              return {
                decision: 'block' as const,
                reason: '安全策略:禁止修改环境配置文件',
              };
            }
          }
          return { decision: 'approve' as const };
        },

        // 工具执行后——自动格式化
        PostToolUse: async (ctx: HookContext) => {
          if (ctx.toolName === 'Write' || ctx.toolName === 'Edit') {
            const filePath = ctx.toolInput.file_path as string;
            if (filePath.endsWith('.ts') || filePath.endsWith('.js')) {
              // 在此处触发格式化
              console.log(`[Hook] 自动格式化: ${filePath}`);
            }
          }
        },

        // 任务完成——通知
        Stop: async (ctx: any) => {
          console.log(`[Hook] Agent 已停止,共 ${ctx.numTurns} 轮`);
        },
      },
    },
  });

  return result;
}

agentWithHooks().catch(console.error);

3.7 MCP 服务器集成

Agent SDK 原生支持连接 MCP 服务器,扩展工具能力:

// mcp-agent.ts
import { query } from '@anthropic-ai/claude-agent-sdk';

async function agentWithMCP() {
  const result = await query({
    prompt: '查询 GitHub 上 anthropics 组织的最近 10 个 issue',
    options: {
      maxTurns: 8,
      mcpServers: {
        // 连接 GitHub MCP 服务器
        github: {
          command: 'npx',
          args: ['-y', '@modelcontextprotocol/server-github'],
          env: {
            GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_TOKEN!,
          },
        },
        // 连接文件系统 MCP 服务器
        filesystem: {
          command: 'npx',
          args: ['-y', '@modelcontextprotocol/server-filesystem', '/workspace'],
        },
      },
    },
  });

  console.log(result.result);
}

agentWithMCP().catch(console.error);

第四章:批量任务与流水线编排

4.1 /batch 命令

Claude Code 内置的 /batch 命令用于大规模代码变更——对多个文件应用相同的转换逻辑,比逐个文件调用快最多 10 倍:

# 交互式使用 /batch
# 在 Claude Code REPL 中输入:
> /batch "为所有 src/**/*.ts 文件添加 @author 注释"

4.2 Shell 脚本批量处理

结合 claude -p 的经典批量处理模式:

#!/bin/bash
# batch-add-tests.sh —— 批量为所有模块生成测试

set -euo pipefail

FILES=$(find src -name "*.ts" -not -name "*.test.ts" -not -path "*/node_modules/*")

TOTAL=$(echo "$FILES" | wc -l)
CURRENT=0

for file in $FILES; do
  CURRENT=$((CURRENT + 1))
  echo "[$CURRENT/$TOTAL] 处理: $file"

  # 为每个文件生成测试
  claude -p "为以下文件编写完整的单元测试:$(cat $file)" \
    --output-format json \
    --max-turns 5 \
    --allowedTools "Read,Write,Glob,Grep" \
    > "/tmp/test-result-$(basename $file).json"

  # 检查是否成功
  if command -v jq &>/dev/null; then
    STATUS=$(jq -r '.subtype' "/tmp/test-result-$(basename $file).json" 2>/dev/null || echo "unknown")
    echo "  状态: $STATUS"
  fi
done

echo "✅ 批量处理完成!共处理 $TOTAL 个文件"

4.3 Python 批处理框架

对于更复杂的批量任务,Python 提供更好的并发控制和错误处理:

#!/usr/bin/env python3
"""batch_processor.py —— Claude Code 批处理框架"""

import subprocess
import json
import os
import sys
import time
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed

def run_claude_task(prompt: str, cwd: str, max_turns: int = 5) -> dict:
    """执行单个 Claude Code 无头任务"""
    cmd = [
        'claude', '-p', prompt,
        '--output-format', 'json',
        '--max-turns', str(max_turns),
    ]

    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            cwd=cwd,
            timeout=300,  # 5分钟超时
        )

        # 解析 JSON 输出
        try:
            return json.loads(result.stdout)
        except json.JSONDecodeError:
            return {
                'subtype': 'error',
                'result': result.stdout,
                'stderr': result.stderr,
            }
    except subprocess.TimeoutExpired:
        return {'subtype': 'error', 'result': '任务超时'}
    except Exception as e:
        return {'subtype': 'error', 'result': str(e)}

def batch_process(
    tasks: list[dict],
    max_workers: int = 3,
    delay_seconds: float = 2.0,
):
    """并发执行批量任务"""
    results = []

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {}
        for i, task in enumerate(tasks):
            future = executor.submit(
                run_claude_task,
                task['prompt'],
                task.get('cwd', os.getcwd()),
                task.get('max_turns', 5),
            )
            futures[future] = (i, task)
            time.sleep(delay_seconds)  # 避免并发冲击

        for future in as_completed(futures):
            idx, task = futures[future]
            result = future.result()
            results.append({
                'index': idx,
                'task': task['prompt'][:80],
                'status': result.get('subtype', 'unknown'),
                'cost': result.get('cost_usd', 0),
                'turns': result.get('num_turns', 0),
            })

            print(f"[{idx+1}/{len(tasks)}] "
                  f"状态: {result.get('subtype', '?')} | "
                  f"费用: ${result.get('cost_usd', 0):.4f}")

    # 输出汇总报告
    total_cost = sum(r['cost'] for r in results)
    success_count = sum(1 for r in results if r['status'] == 'success')

    print(f"\n{'='*60}")
    print(f"批量处理完成")
    print(f"总任务: {len(tasks)}")
    print(f"成功: {success_count} | 失败: {len(tasks) - success_count}")
    print(f"总费用: ${total_cost:.4f}")
    print(f"{'='*60}")

    return results

# 使用示例
if __name__ == '__main__':
    tasks = [
        {'prompt': '审查 src/auth.ts 的安全性', 'cwd': '/my-project'},
        {'prompt': '审查 src/api.ts 的安全性', 'cwd': '/my-project'},
        {'prompt': '审查 src/db.ts 的安全性', 'cwd': '/my-project'},
        {'prompt': '审查 src/utils.ts 的安全性', 'cwd': '/my-project'},
    ]

    batch_process(tasks, max_workers=2, delay_seconds=3.0)

4.4 会话链:复杂任务的多步编排

利用 --continue 实现多步 Agent 流水线:

#!/bin/bash
# pipeline.sh —— 多步自动化流水线

PROJECT_DIR="/path/to/project"
cd "$PROJECT_DIR"

echo "🚀 启动自动化流水线..."

# 步骤 1:代码审查
echo "📋 步骤 1/4: 代码审查..."
STEP1=$(claude -p "审查 git diff HEAD~5 的所有变更,列出安全问题和 bug" \
  --allowedTools "Read,Bash,Glob,Grep" \
  --max-turns 5 \
  --output-format json)

SESSION_ID=$(echo "$STEP1" | jq -r '.session_id')
REVIEW_TEXT=$(echo "$STEP1" | jq -r '.result')
echo "审查完成,会话: $SESSION_ID"

# 步骤 2:自动修复(继续同一会话)
echo "🔧 步骤 2/4: 自动修复..."
claude -p "根据审查结果修复所有严重问题: $REVIEW_TEXT" \
  --continue "$SESSION_ID" \
  --max-turns 10 \
  --output-format json

# 步骤 3:运行测试
echo "🧪 步骤 3/4: 运行测试..."
claude -p "运行所有测试并报告结果" \
  --continue "$SESSION_ID" \
  --allowedTools "Bash,Read" \
  --max-turns 5 \
  --output-format json

# 步骤 4:生成变更报告
echo "📊 步骤 4/4: 生成报告..."
claude -p "总结本次所有变更,生成变更日志" \
  --continue "$SESSION_ID" \
  --max-turns 3 \
  --output-format text

echo "✅ 流水线完成!"

4.5 完整工作流架构

flowchart TB
    subgraph 触发层
        T1[Git Push Hook]
        T2[CI/CD Pipeline]
        T3[Cron 定时任务]
        T4[手动触发]
    end

    subgraph 编排层
        O1[Shell 脚本]
        O2[Python 框架]
        O3[Agent SDK]
    end

    subgraph 执行层
        E1[claude -p 无头模式]
        E2[Hooks 安全守卫]
        E3[会话管理]
    end

    subgraph 输出层
        R1[JSON 结构化结果]
        R2[Git Diff 变更]
        R3[Slack 通知]
        R4[测试报告]
    end

    T1 --> O1
    T2 --> O2
    T3 --> O1
    T4 --> O3

    O1 --> E1
    O2 --> E1
    O3 --> E1

    E1 --> E2
    E2 --> E3

    E3 --> R1
    E3 --> R2
    E1 --> R3
    E1 --> R4

    style 触发层 fill:#e3f2fd
    style 编排层 fill:#fff3e0
    style 执行层 fill:#e8f5e9
    style 输出层 fill:#fce4ec

第五章:实战项目——代码质量自动守护系统

5.1 项目目标

构建一个完整的自动化系统,在每次 Git Push 时自动执行:代码审查 → 安全扫描 → 自动修复 → 测试验证 → 通知汇报。

5.2 项目结构

claude-guardian/
├── .claude/
│   ├── settings.json          # Hooks 配置
│   └── CLAUDE.md              # 项目上下文
├── scripts/
│   ├── pre-push-guard.py      # PreToolUse Hook
│   ├── auto-format.py         # PostToolUse Hook
│   ├── notify.py              # Notification Hook
│   └── pipeline.sh            # 主流水线脚本
├── package.json
└── tsconfig.json

5.3 Hooks 配置

// .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/pre-push-guard.py"
          }
        ]
      },
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/pre-push-guard.py"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/auto-format.py"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/notify.py"
          }
        ]
      }
    ]
  },
  "permissions": {
    "allow": [
      "Bash(npm test)",
      "Bash(git diff*)",
      "Bash(npx prettier*)",
      "Read",
      "Write",
      "Edit",
      "Glob",
      "Grep"
    ]
  }
}

5.4 安全守卫 Hook

#!/usr/bin/env python3
"""scripts/pre-push-guard.py — 统一安全守卫"""
import sys, json, re, os

BLOCKED_FILE_PATTERNS = [
    r'\.env($|\.)', r'credentials', r'\.pem$', r'\.key$',
    r'id_rsa', r'id_ed25519', r'secrets?\.json'
]

DANGEROUS_COMMANDS = [
    r'rm\s+-rf\s+/(?!\w)', r'sudo\s+', r'chmod\s+777',
    r'git\s+push\s+--force', r'drop\s+database',
    r'>\s*/dev/sd', r'mkfs', r'dd\s+if=',
]

def check_file_path(file_path: str) -> dict | None:
    for pattern in BLOCKED_FILE_PATTERNS:
        if re.search(pattern, file_path, re.IGNORECASE):
            return {
                "decision": "block",
                "reason": f"⛔ 安全策略:禁止访问匹配 '{pattern}' 的文件"
            }
    return None

def check_command(command: str) -> dict | None:
    for pattern in DANGEROUS_COMMANDS:
        if re.search(pattern, command, re.IGNORECASE):
            return {
                "decision": "block",
                "reason": f"⛔ 安全策略:检测到危险命令模式"
            }
    return None

def main():
    data = json.loads(sys.stdin.read())
    tool_name = data.get('tool_name', '')
    tool_input = data.get('tool_input', {})

    # 检查文件路径类工具
    if tool_name in ('Write', 'Edit', 'Read'):
        file_path = tool_input.get('file_path', '')
        result = check_file_path(file_path)
        if result:
            print(json.dumps(result))
            return

    # 检查 Bash 命令
    if tool_name == 'Bash':
        command = tool_input.get('command', '')
        result = check_command(command)
        if result:
            print(json.dumps(result))
            return

    # 默认放行
    print(json.dumps({}))

if __name__ == '__main__':
    main()

5.5 自动格式化 Hook

#!/usr/bin/env python3
"""scripts/auto-format.py — 文件写入后自动格式化"""
import sys, json, subprocess, os

def main():
    data = json.loads(sys.stdin.read())
    tool_name = data.get('tool_name', '')
    tool_input = data.get('tool_input', {})
    file_path = tool_input.get('file_path', '')

    if not file_path:
        return

    ext = os.path.splitext(file_path)[1]

    # TypeScript / JavaScript → Prettier
    if ext in ('.ts', '.tsx', '.js', '.jsx'):
        subprocess.run(
            ['npx', 'prettier', '--write', file_path],
            capture_output=True, timeout=30
        )

    # Python → Black
    elif ext == '.py':
        subprocess.run(
            ['black', file_path],
            capture_output=True, timeout=30
        )

    # Go → gofmt
    elif ext == '.go':
        subprocess.run(
            ['gofmt', '-w', file_path],
            capture_output=True, timeout=30
        )

if __name__ == '__main__':
    main()

5.6 主流水线脚本

#!/bin/bash
# scripts/pipeline.sh — 代码质量守护流水线
set -euo pipefail

PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"

LOG_FILE="/tmp/claude-guardian-$(date +%Y%m%d-%H%M%S).log"
log() { echo "[$(date '+%H:%M:%S')] $1" | tee -a "$LOG_FILE"; }

log "🚀 启动代码质量守护流水线"

# ========== 阶段 1: 差异分析 ==========
log "📋 阶段 1/4: 分析变更..."
DIFF_SUMMARY=$(claude -p "分析 git diff HEAD~1 的变更,分类为:功能修改、测试修改、配置修改、文档修改。输出 JSON 格式。" \
  --allowedTools "Bash,Read,Glob,Grep" \
  --max-turns 3 \
  --output-format json)
SESSION=$(echo "$DIFF_SUMMARY" | jq -r '.session_id')
log "   会话: $SESSION"

# ========== 阶段 2: 安全审查 ==========
log "🔒 阶段 2/4: 安全审查..."
SEC_REVIEW=$(claude -p "对本次变更进行安全审查:SQL注入、XSS、硬编码密钥、不安全的依赖。输出问题列表和严重等级。" \
  --continue "$SESSION" \
  --allowedTools "Bash,Read,Glob,Grep" \
  --max-turns 5 \
  --output-format json)

SEC_ISSUES=$(echo "$SEC_REVIEW" | jq -r '.result' | grep -c "严重\|high\|critical" || echo "0")
if [ "$SEC_ISSUES" -gt 0 ]; then
  log "⚠️  发现 $SEC_ISSUES 个严重安全问题!"
fi

# ========== 阶段 3: 测试验证 ==========
log "🧪 阶段 3/4: 运行测试..."
TEST_RESULT=$(claude -p "运行项目测试套件。如果有测试失败,分析原因并尝试修复,然后重新运行。" \
  --continue "$SESSION" \
  --allowedTools "Bash,Read,Write,Edit,Glob,Grep" \
  --max-turns 8 \
  --output-format json)

TEST_STATUS=$(echo "$TEST_RESULT" | jq -r '.subtype')
log "   测试状态: $TEST_STATUS"

# ========== 阶段 4: 生成报告 ==========
log "📊 阶段 4/4: 生成报告..."
REPORT=$(claude -p "基于以上所有分析,生成一份结构化的代码质量报告,包含:变更摘要、安全发现、测试结果、改进建议。" \
  --continue "$SESSION" \
  --max-turns 3 \
  --output-format text)

echo "$REPORT" > "$PROJECT_DIR/quality-report-$(date +%Y%m%d).md"
log "✅ 报告已生成: quality-report-$(date +%Y%m%d).md"

# 输出汇总
TOTAL_COST=$(echo "$DIFF_SUMMARY $SEC_REVIEW $TEST_RESULT" | jq -s '[.[].cost_usd // 0] | add')
log "💰 总费用: \$$TOTAL_COST"
log "🏁 流水线完成!"

5.7 Git Pre-push 集成

将流水线接入 Git Hook,实现 Push 前自动检查:

#!/bin/bash
# .git/hooks/pre-push —— Push 前自动质量检查
echo "🔍 执行 Claude Code 质量检查..."

# 快速检查(不超过 2 分钟)
RESULT=$(claude -p "快速检查即将 push 的 commit:是否有明显的安全漏洞或语法错误?" \
  --allowedTools "Bash,Read,Glob,Grep" \
  --max-turns 3 \
  --output-format json)

STATUS=$(echo "$RESULT" | jq -r '.subtype')

if [ "$STATUS" = "success" ]; then
  echo "✅ 检查通过,允许 Push"
  exit 0
else
  echo "❌ 检查未通过:"
  echo "$RESULT" | jq -r '.result'
  echo ""
  read -p "是否仍要 Push?(y/N) " -n 1 -r
  echo
  [[ $REPLY =~ ^[Yy]$ ]] && exit 0 || exit 1
fi

第六章:高级模式与最佳实践

6.1 成本控制策略

# 1. 分级模型策略——简单任务用快模型
claude -p "格式化这个文件" \
  --model claude-haiku-4-5-20251001 \
  --max-turns 1

# 复杂任务用强模型
claude -p "重构认证模块,支持 OAuth2.0" \
  --model claude-opus-4-8 \
  --max-turns 15

# 2. 设置 max-turns 防止无限循环
# 简单查询: 1-3 轮
# 代码审查: 3-5 轮
# 重构任务: 5-10 轮
# 大规模变更: 10-20 轮

# 3. 使用只读工具降低风险和成本
claude -p "分析代码" --allowedTools "Read,Glob,Grep"

6.2 错误处理与重试

# retry-agent.py —— 带重试的 Claude Code 调用
import subprocess, json, time

def claude_with_retry(prompt: str, max_retries: int = 3, **kwargs) -> dict:
    """带指数退避重试的 Claude Code 调用"""
    cmd = ['claude', '-p', prompt, '--output-format', 'json']

    if 'max_turns' in kwargs:
        cmd.extend(['--max-turns', str(kwargs['max_turns'])])
    if 'allowed_tools' in kwargs:
        cmd.extend(['--allowedTools', ','.join(kwargs['allowed_tools'])])
    if 'model' in kwargs:
        cmd.extend(['--model', kwargs['model']])

    for attempt in range(max_retries):
        try:
            result = subprocess.run(
                cmd, capture_output=True, text=True, timeout=600
            )
            data = json.loads(result.stdout)

            if data.get('subtype') == 'success':
                return data
            else:
                print(f"尝试 {attempt+1} 失败: {data.get('result', '')[:100]}")

        except subprocess.TimeoutExpired:
            print(f"尝试 {attempt+1} 超时")
        except json.JSONDecodeError as e:
            print(f"尝试 {attempt+1} JSON 解析失败: {e}")

        if attempt < max_retries - 1:
            wait = 2 ** attempt  # 指数退避: 1s, 2s, 4s
            print(f"等待 {wait}s 后重试...")
            time.sleep(wait)

    raise RuntimeError(f"任务在 {max_retries} 次尝试后仍然失败")

# 使用
result = claude_with_retry(
    "审查并修复 src/api.ts 中的安全问题",
    max_retries=3,
    max_turns=8,
    allowed_tools=["Read", "Write", "Edit", "Bash", "Glob", "Grep"]
)

6.3 并行 Agent 编排

使用 Agent SDK 构建并行 Agent 系统:

// parallel-agents.ts
import { query } from '@anthropic-ai/claude-agent-sdk';

interface TaskResult {
  task: string;
  status: string;
  result: string;
  cost: number;
}

async function runParallelAgents(): Promise<TaskResult[]> {
  const tasks = [
    {
      task: '安全性审查',
      prompt: '审查项目中所有认证相关代码的安全漏洞',
      tools: ['Read', 'Glob', 'Grep'] as const,
    },
    {
      task: '性能分析',
      prompt: '分析项目中的性能瓶颈和优化机会',
      tools: ['Read', 'Glob', 'Grep', 'Bash'] as const,
    },
    {
      task: '代码质量',
      prompt: '评估代码质量:重复代码、过长函数、圈复杂度',
      tools: ['Read', 'Glob', 'Grep'] as const,
    },
    {
      task: '依赖审查',
      prompt: '检查 package.json 中的依赖是否有已知漏洞或废弃包',
      tools: ['Read', 'Bash', 'Glob'] as const,
    },
  ];

  // 并行执行所有任务
  const results = await Promise.all(
    tasks.map(async (task) => {
      try {
        const result = await query({
          prompt: task.prompt,
          options: {
            allowedTools: [...task.tools],
            maxTurns: 5,
            systemPrompt: '输出简洁的结构化报告。',
          },
        });

        return {
          task: task.task,
          status: 'success',
          result: (result as any).result || '',
          cost: (result as any).costUsd || 0,
        };
      } catch (error: any) {
        return {
          task: task.task,
          status: 'error',
          result: error.message,
          cost: 0,
        };
      }
    })
  );

  // 汇总报告
  const totalCost = results.reduce((sum, r) => sum + r.cost, 0);
  console.log(`\n${'='.repeat(60)}`);
  console.log('并行 Agent 执行完毕');
  console.log(`总费用: $${totalCost.toFixed(4)}`);
  console.log(`${'='.repeat(60)}\n`);

  for (const r of results) {
    console.log(`【${r.task}】${r.status === 'success' ? '✅' : '❌'}`);
    console.log(r.result.substring(0, 200) + '...\n');
  }

  return results;
}

runParallelAgents().catch(console.error);

6.4 无头模式速查表

# ===== 基础调用 =====
claude -p "提示文本"                          # 最简调用
cat file.txt | claude -p "分析这段代码"         # 管道输入

# ===== 输出控制 =====
claude -p "..." --output-format json          # JSON 结构化输出
claude -p "..." --output-format stream-json   # 流式 JSON
claude -p "..." --output-format text          # 纯文本(默认)

# ===== 安全控制 =====
claude -p "..." --allowedTools "Read,Glob"    # 只读工具白名单
claude -p "..." --max-turns 5                 # 限制循环轮次
claude -p "..." --permission-mode plan        # 计划模式(不执行)

# ===== 会话管理 =====
claude -p "..." --continue                    # 继续最近会话
claude -p "..." --resume SESSION_ID           # 恢复指定会话

# ===== 模型选择 =====
claude -p "..." --model claude-opus-4-8       # Opus(最强)
claude -p "..." --model claude-sonnet-4-6     # Sonnet(平衡)
claude -p "..." --model claude-haiku-4-5-20251001  # Haiku(最快)

# ===== 提示词控制 =====
claude -p "..." --system-prompt "..."         # 自定义系统提示
claude -p "..." --append-system-prompt "..."  # 追加系统提示

常见问题 FAQ

问题 答案
-p 模式和交互模式费用一样吗? 是的,计费标准相同。但可通过 --max-turns 和 --model 控制成本
Hook 脚本超时怎么办? 默认超时 60 秒,确保脚本快速返回;长时间任务建议异步处理
Agent SDK 能在浏览器运行吗? 不能,Agent SDK 需要 Node.js 运行时和文件系统访问
并行调用有速率限制吗? 有,Anthropic API 有 RPM/TPM 限制,建议并发 ≤ 3-5
如何在 Docker 中使用无头模式? 安装 Claude Code CLI,设置 ANTHROPIC_API_KEY 环境变量即可
--continue 的会话有效期? 会话存储在本地 .claude/ 目录,除非手动清理,长期有效

参考来源

  1. Run Claude Code programmatically - Claude Code Docs — Anthropic 官方无头模式文档,涵盖 -p 标志全部参数
  2. Hooks reference - Claude Code Docs — 官方 Hook 事件参考,包含完整 JSON Schema 定义
  3. Automate actions with hooks - Claude Code Docs — 官方 Hook 实践指南与示例
  4. Agent SDK overview - Claude Code Docs — Agent SDK 架构概述与核心概念
  5. Agent SDK reference - TypeScript — TypeScript Agent SDK 完整 API 参考
  6. Claude Code Batch Processing Guide - SmartScope — /batch 命令与无头批量处理实战
  7. Claude Agent SDK TypeScript - GitHub — 官方 TypeScript Agent SDK 源码与示例
  8. Claude Code Hooks Complete Guide - AI Org — 20+ 个可直接使用的 Hook 配置示例

训练营适用性评估:本教程适合 进阶训练营(Day 2-3),学员应已有 Claude Code 基础使用经验。建议教学时长 4-5 小时(含实操),其中无头模式 1h、Hooks 1.5h、Agent SDK 1.5h、综合实战 1h。可配合提供预配置的项目模板,让学员专注在 Hook 脚本编写和 Agent 编排上。

[!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学通信知识星球海报-扫码加入