本教程面向有一定TypeScript基础的开发者,深入讲解如何使用Claude Agent SDK(@anthropic-ai/claude-code)将Claude Code的核心能力——文件读写、Shell执行、代码搜索、子Agent编排——嵌入你自己的应用程序中。你将从一条claude()调用出发,逐步构建出带流式输出、工具白名单、多步推理的生产级AI Agent,并掌握Headless模式、管道脚本、与Hooks联动的完整自动化链路。
适合人群:已熟悉Claude Code基本操作、希望将其能力程序化嵌入CI/CD、内部工具或SaaS产品的中高级开发者。
学习目标:
- 理解Agent SDK的架构设计与核心API
- 用TypeScript编写自定义Agent,支持流式输出与工具权限控制
- 掌握Headless模式(claude -p)在脚本和CI中的应用
- 构建一个完整的"代码审查+自动修复"Agent实战项目
| 条件 | 说明 |
|---|---|
| Node.js ≥ 18 | Agent SDK需要ESM支持 |
| TypeScript ≥ 5.0 | 推荐strict模式 |
| Claude Code ≥ v2.1.100 | 确保SDK与CLI版本兼容 |
| Claude订阅 | Pro/Max/Team均可,2026年6月15日后Agent SDK使用将有独立额度 |
| 基础Git知识 | Worktree、分支操作 |
# 验证环境
node --version # v18+
npx tsc --version # 5.0+
claude --version # 2.1.100+
Claude Agent SDK是Anthropic官方发布的TypeScript/Python库,它把Claude Code的整个Agent循环——提示解析、工具调用、上下文管理、多轮推理——封装为可编程的API。你不再需要手动拼接HTTP请求或管理对话状态,一个函数调用就能获得完整的Agent能力。
┌─────────────────────────────────────────────┐
│ 你的应用程序 │
│ ┌─────────────────────────────────────┐ │
│ │ @anthropic-ai/claude-code │ │
│ │ ┌───────────────────────────────┐ │ │
│ │ │ Claude Agent Loop │ │ │
│ │ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │
│ │ │ │ Read │ │ Bash │ │Edit │ │ │ │
│ │ │ └──────┘ └──────┘ └──────┘ │ │ │
│ │ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │
│ │ │ │ Grep │ │Glob │ │Agent │ │ │ │
│ │ │ └──────┘ └──────┘ └──────┘ │ │ │
│ │ └───────────────────────────────┘ │ │
│ └─────────────────────────────────────┘ │
│ ↕ │
│ 本地文件系统 + Git仓库 │
└─────────────────────────────────────────────┘
| API | 用途 | 返回值 |
|---|---|---|
claude() |
单次Agent调用,返回完整结果 | Promise<AgentResult> |
claudeStream() |
流式调用,逐步接收消息 | AsyncIterable<AgentEvent> |
createSession() |
创建持久化会话 | Session |
Session#sendMessage() |
在会话中继续对话 | Promise<AgentResult> |
Headless模式(claude -p)是CLI层面的非交互接口,Agent SDK是其编程层面的等价物。两者底层共享同一套Agent引擎:
flowchart TB
subgraph "用户触达方式"
CLI[claude -p 命令行]
SDK["@anthropic-ai/claude-code<br/>TypeScript SDK"]
PY["@anthropic-ai/claude-code<br/>Python SDK"]
end
subgraph "Agent引擎"
CORE[Agent Loop<br/>工具调度 · 上下文管理<br/>多轮推理 · 权限控制]
end
subgraph "工具层"
T1[文件读写]
T2[Shell执行]
T3[代码搜索]
T4[子Agent]
T5[MCP工具]
end
CLI --> CORE
SDK --> CORE
PY --> CORE
CORE --> T1 & T2 & T3 & T4 & T5
# 创建项目目录
mkdir my-claude-agent && cd my-claude-agent
# 初始化Node.js项目(ESM模式)
npm init -y
npm pkg set type="module"
# 安装依赖
npm install @anthropic-ai/claude-code
npm install -D typescript @types/node
# TypeScript配置
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
EOF
mkdir src
创建你的第一个Agent脚本:
// src/hello-agent.ts
import { claude } from "@anthropic-ai/claude-code";
const result = await claude({
prompt: "列出当前目录的文件结构,并说明每个文件的用途",
options: {
maxTurns: 3,
allowedTools: ["Read", "Glob", "Bash"],
},
});
console.log("Agent回复:");
console.log(result.text);
console.log("\n--- 统计信息 ---");
console.log(`总轮次: ${result.turns}`);
console.log(`使用的工具: ${result.toolsUsed.join(", ")}`);
console.log(`Token消耗: ${result.usage?.totalTokens}`);
# 运行
npx tsx src/hello-agent.ts
预期输出:
Agent回复:
当前目录包含以下文件:
1. package.json - Node.js项目配置文件,定义依赖和脚本
2. tsconfig.json - TypeScript编译配置
3. src/hello-agent.ts - 主Agent脚本
--- 统计信息 ---
总轮次: 2
使用的工具: Glob, Read
Token消耗: 3842
| 问题 | 原因 | 解决方案 |
|---|---|---|
MODULE_NOT_FOUND |
ESM/CJS混用 | 确保package.json设置"type": "module" |
claude: command not found |
未安装Claude Code CLI | npm install -g @anthropic-ai/claude-code |
Authentication required |
未登录 | 运行claude login完成认证 |
Tool not allowed |
工具不在白名单 | 在allowedTools中添加工具名 |
对于长时间运行的Agent任务,流式输出能让你实时展示进度:
// src/stream-agent.ts
import { claudeStream } from "@anthropic-ai/claude-code";
const stream = claudeStream({
prompt: "分析当前项目的代码质量,找出潜在问题",
options: {
maxTurns: 10,
allowedTools: ["Read", "Glob", "Grep", "Bash"],
},
});
let fullText = "";
let toolCalls = 0;
for await (const event of stream) {
switch (event.type) {
case "text":
// 实时输出Agent的文本内容
process.stdout.write(event.content);
fullText += event.content;
break;
case "tool_use":
toolCalls++;
console.log(`\n[工具调用 #${toolCalls}] ${event.tool}`);
console.log(` 参数: ${JSON.stringify(event.input).slice(0, 100)}...`);
break;
case "tool_result":
const status = event.isError ? "❌ 失败" : "✅ 完成";
console.log(` 结果: ${status}`);
break;
case "done":
console.log(`\n\n=== Agent完成 ===`);
console.log(`总文本长度: ${fullText.length} 字符`);
console.log(`工具调用次数: ${toolCalls}`);
break;
}
}
flowchart LR
subgraph "Agent事件流"
E1["session_start<br/>会话初始化"]
E2["text<br/>流式文本输出"]
E3["tool_use<br/>发起工具调用"]
E4["tool_result<br/>工具返回结果"]
E5["thinking<br/>推理中间步骤"]
E6["done<br/>Agent完成"]
E7["error<br/>错误事件"]
end
E1 --> E2
E2 --> E3
E3 --> E4
E4 --> E2
E2 --> E5
E5 --> E6
E3 --> E7
| 事件类型 | 字段 | 说明 |
|---|---|---|
text |
content |
Agent生成的文本片段 |
tool_use |
tool, input |
即将执行的工具和参数 |
tool_result |
output, isError |
工具执行结果 |
thinking |
content |
Agent的推理过程(Extended Thinking模式) |
done |
result |
Agent完成,包含完整结果 |
error |
message |
错误信息 |
当Agent需要返回结构化数据而非自由文本时,使用JSON Schema约束输出:
// src/structured-output.ts
import { claude } from "@anthropic-ai/claude-code";
interface CodeIssue {
file: string;
line: number;
severity: "error" | "warning" | "info";
message: string;
suggestion: string;
}
const CodeReviewSchema = {
type: "object",
properties: {
issues: {
type: "array",
items: {
type: "object",
properties: {
file: { type: "string" },
line: { type: "number" },
severity: {
type: "string",
enum: ["error", "warning", "info"]
},
message: { type: "string" },
suggestion: { type: "string" },
},
required: ["file", "line", "severity", "message"],
},
},
summary: { type: "string" },
score: { type: "number", minimum: 0, maximum: 10 },
},
required: ["issues", "summary", "score"],
};
const result = await claude({
prompt: `审查以下TypeScript文件的代码质量,找出所有问题:
重点检查:
1. 类型安全性
2. 错误处理
3. 性能问题
4. 代码风格`,
options: {
maxTurns: 5,
allowedTools: ["Read", "Glob"],
// 结构化输出通过提示词引导实现
},
});
// 解析结果
const jsonMatch = result.text.match(/```json\n([\s\S]*?)\n```/);
if (jsonMatch) {
const review: CodeReviewSchema = JSON.parse(jsonMatch[1]);
console.log(`代码评分: ${review.score}/10`);
console.log(`发现 ${review.issues.length} 个问题`);
review.issues.forEach((issue, i) => {
console.log(`\n[${issue.severity.toUpperCase()}] ${issue.file}:${issue.line}`);
console.log(` ${issue.message}`);
if (issue.suggestion) {
console.log(` 建议: ${issue.suggestion}`);
}
});
}
Agent SDK继承了Claude Code的完整工具集,但你可以精确控制Agent能使用哪些工具:
// src/permission-control.ts
import { claude } from "@anthropic-ai/claude-code";
// 只读模式 —— 只允许查看,不允许修改
const readOnlyResult = await claude({
prompt: "分析项目依赖关系,生成依赖图谱",
options: {
maxTurns: 5,
allowedTools: [
"Read", // 读文件
"Glob", // 文件搜索
"Grep", // 内容搜索
"Bash", // 注意:Bash可以执行任意命令
],
// Bash命令白名单(通过permissionMode控制)
permissionMode: "default", // 会弹出权限确认
},
});
// 完全自动模式 —— 信任Agent的所有操作
const fullAutoResult = await claude({
prompt: "重构src/utils目录,将所有工具函数按功能分类到子模块中",
options: {
maxTurns: 20,
allowedTools: ["Read", "Write", "Edit", "Glob", "Grep", "Bash", "Agent"],
permissionMode: "acceptEdits", // 自动接受文件编辑
},
});
| 模式 | 说明 | 适用场景 |
|---|---|---|
default |
每次敏感操作需确认 | 开发调试阶段 |
acceptEdits |
自动接受文件编辑,Shell仍需确认 | 代码重构 |
acceptAll |
自动接受所有操作 | CI/CD、无人值守 |
dontAsk |
不询问,但也不自动执行受限操作 | 最严格的安全模式 |
// src/safe-agent.ts
import { claude } from "@anthropic-ai/claude-code";
// 生产环境推荐配置
const safeConfig = {
// 1. 最小工具集原则
allowedTools: ["Read", "Glob", "Grep"] as const,
// 2. 限制最大轮次,防止失控
maxTurns: 10,
// 3. 使用strict模式
permissionMode: "dontAsk" as const,
// 4. 设置工作目录,限制Agent活动范围
cwd: "/app/workspace",
// 5. 设置超时
timeout: 300_000, // 5分钟
};
const result = await claude({
prompt: "检查workspace目录下的代码,生成安全审计报告",
options: safeConfig,
});
Agent SDK底层依赖的claude -p模式(Headless模式)是脚本集成的关键入口:
# 基础用法:单次提问
claude -p "解释这个函数的作用"
# 管道输入
cat src/index.ts | claude -p "审查这段代码"
# JSON输出格式
claude -p "列出所有TODO注释" --output-format json
# 流式JSON输出
claude -p "重构整个项目" --output-format stream-json
# 指定模型
claude -p "生成单元测试" --model claude-sonnet-4-6-20250514
# 限制工具和轮次
claude -p "分析代码" --max-turns 5 --allowedTools "Read,Glob,Grep"
# Bare模式:纯净输出,无额外标记
claude -p "生成README" --bare
#!/bin/bash
# multi-review.sh —— 批量代码审查脚本
set -e
# 审查所有最近修改的TypeScript文件
CHANGED_FILES=$(git diff --name-only HEAD~1 | grep '\.ts$')
echo "=== 开始审查 ${CHANGED_FILES} 个文件 ==="
for file in $CHANGED_FILES; do
echo ""
echo "--- 审查: $file ---"
# 使用Headless模式审查每个文件
claude -p "审查这个文件中的代码质量问题,重点关注:
1. 类型安全
2. 错误处理
3. 性能瓶颈
4. 安全漏洞
输出格式:
- 严重程度(Critical/Warning/Info)
- 行号
- 问题描述
- 修复建议" \
--allowedTools "Read,Grep" \
--max-turns 3 \
--bare \
< "$file" | tee "reviews/$(basename $file).review.md"
done
echo ""
echo "=== 所有审查完成 ==="
echo "结果保存在 reviews/ 目录"
| 维度 | claude -p (Headless) |
Agent SDK |
|---|---|---|
| 语言 | Shell/任意 | TypeScript/Python |
| 流式控制 | stream-json格式 |
for await循环 |
| 结果解析 | 需手动解析JSON/文本 | 类型化的对象 |
| 会话管理 | 无状态,每次新会话 | 支持持久化Session |
| 错误处理 | 退出码+stderr | try/catch异常 |
| 适用场景 | 快速脚本、CI/CD | 复杂应用、自定义Agent |
// src/session-agent.ts
import { createSession } from "@anthropic-ai/claude-code";
// 创建一个持久化会话
const session = await createSession({
options: {
maxTurns: 30,
allowedTools: ["Read", "Write", "Edit", "Glob", "Grep", "Bash"],
},
});
// 第一轮:理解项目
const r1 = await session.sendMessage(
"分析当前项目的整体架构,用Mermaid语法画出架构图"
);
console.log("架构分析完成:", r1.text.slice(0, 200));
// 第二轮:基于理解进行操作
const r2 = await session.sendMessage(
"基于刚才的分析,重构src/api目录,将路由按领域拆分为独立模块"
);
console.log("重构完成:", r2.text.slice(0, 200));
// 第三轮:验证
const r3 = await session.sendMessage(
"运行测试验证重构没有破坏现有功能"
);
console.log("测试结果:", r3.text.slice(0, 200));
// 关闭会话
await session.close();
stateDiagram-v2
[*] --> Created: createSession()
Created --> Active: sendMessage()
Active --> Active: 继续对话
Active --> Paused: 超时/手动暂停
Paused --> Active: sendMessage()
Active --> Closed: close()
Closed --> [*]
note right of Active
会话保持完整上下文
包括对话历史和工具调用记录
end note
长会话会消耗大量Token。Agent SDK提供了上下文管理策略:
// src/context-aware-agent.ts
import { claude } from "@anthropic-ai/claude-code";
// 策略1:限制轮次,自动压缩上下文
const result1 = await claude({
prompt: "大规模重构项目",
options: {
maxTurns: 15,
// 超过上下文窗口时自动压缩历史
contextManagement: {
strategy: "auto-compact", // 自动压缩
maxTokens: 180_000, // 上下文上限
},
},
});
// 策略2:分段处理大任务
async function processLargeCodebase(files: string[]) {
const BATCH_SIZE = 5;
const results = [];
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const batch = files.slice(i, i + BATCH_SIZE);
const result = await claude({
prompt: `分析以下文件的代码质量和依赖关系:\n${batch.join("\n")}`,
options: {
maxTurns: 8,
allowedTools: ["Read", "Grep"],
},
});
results.push({
files: batch,
analysis: result.text,
tokens: result.usage?.totalTokens,
});
console.log(`已处理 ${Math.min(i + BATCH_SIZE, files.length)}/${files.length} 文件`);
}
return results;
}
Agent SDK允许Agent在执行过程中调用子Agent(通过Agent工具),实现任务的分层委托:
// src/orchestration.ts
import { claude } from "@anthropic-ai/claude-code";
const result = await claude({
prompt: `你是一个代码审查编排器。请执行以下任务:
1. 使用子Agent分析src/api目录的安全漏洞
2. 使用子Agent分析src/utils目录的性能问题
3. 使用子Agent检查所有TypeScript文件的类型安全性
4. 汇总三个子Agent的结果,生成综合报告`,
options: {
maxTurns: 25,
allowedTools: [
"Read", "Glob", "Grep", // 基础工具
"Agent", // 允许调用子Agent
],
},
});
// src/parallel-agents.ts
import { claude } from "@anthropic-ai/claude-code";
interface ReviewResult {
dimension: string;
score: number;
findings: string[];
}
async function parallelReview(
filePath: string,
dimensions: string[]
): Promise<ReviewResult[]> {
// 并行启动多个Agent,每个负责一个审查维度
const reviews = await Promise.all(
dimensions.map(async (dim) => {
const result = await claude({
prompt: `以"${dim}"维度审查以下代码。只输出JSON格式的结果:
{"score": 数字0-10, "findings": ["问题1", "问题2"]}
文件: ${filePath}`,
options: {
maxTurns: 5,
allowedTools: ["Read", "Grep"],
},
});
// 解析Agent的JSON输出
try {
const jsonStr = result.text.match(/\{[\s\S]*\}/)?.[0];
return {
dimension: dim,
...(jsonStr ? JSON.parse(jsonStr) : { score: 0, findings: [] }),
};
} catch {
return { dimension: dim, score: 0, findings: ["解析失败"] };
}
})
);
return reviews;
}
// 使用示例
const results = await parallelReview("src/auth/login.ts", [
"安全性",
"性能",
"可维护性",
"测试覆盖",
]);
console.log("=== 综合审查结果 ===");
results.forEach((r) => {
console.log(`\n[${r.dimension}] 评分: ${r.score}/10`);
r.findings.forEach((f) => console.log(` - ${f}`));
});
flowchart TB
subgraph "主Agent进程"
MAIN[主Agent<br/>任务拆分与汇总]
end
subgraph "并行子Agent组"
A1[安全审查Agent]
A2[性能分析Agent]
A3[代码质量Agent]
A4[测试覆盖Agent]
end
subgraph "共享资源"
FS[文件系统<br/>只读访问]
end
MAIN -->|"维度1: 安全"| A1
MAIN -->|"维度2: 性能"| A2
MAIN -->|"维度3: 质量"| A3
MAIN -->|"维度4: 测试"| A4
A1 & A2 & A3 & A4 --> FS
A1 -->|"结果1"| MAIN
A2 -->|"结果2"| MAIN
A3 -->|"结果3"| MAIN
A4 -->|"结果4"| MAIN
MAIN --> REPORT[综合报告<br/>评分 + 改进建议]
当Agent通过SDK执行工具时,你配置在settings.json中的Hooks同样会触发。这为Agent操作增加了审计和安全防护层:
// .claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "node scripts/validate-command.js",
"description": "验证Shell命令安全性"
}
],
"PostToolUse": [
{
"matcher": "Edit",
"command": "node scripts/post-edit-lint.js",
"description": "编辑后自动运行lint"
}
],
"Stop": [
{
"command": "node scripts/on-complete.js",
"description": "Agent完成后发送通知"
}
]
}
}
// scripts/validate-command.js
// PreToolUse Hook: 拦截危险命令
const input = JSON.parse(process.argv[2] || "{}");
const toolInput = input.tool_input || {};
const command = toolInput.command || "";
// 危险命令黑名单
const BLOCKED_PATTERNS = [
/rm\s+-rf\s+\//, // 递归删除根目录
/DROP\s+TABLE/i, // SQL注入
/:\s*\(\)\s*\{/, // Fork bomb
/curl\s+.*\|\s*sh/, // 远程脚本执行
/>\/dev\/sd/, // 直接写磁盘
];
const blocked = BLOCKED_PATTERNS.some(p => p.test(command));
if (blocked) {
// 输出JSON拒绝结果
console.log(JSON.stringify({
decision: "block",
reason: `命令被安全策略拦截: ${command.slice(0, 50)}...`
}));
process.exit(0);
}
// 允许执行
console.log(JSON.stringify({ decision: "allow" }));
process.exit(0);
// scripts/post-edit-lint.js
// PostToolUse Hook: 文件编辑后自动格式化
const input = JSON.parse(process.argv[2] || "{}");
const filePath = input.tool_input?.file_path || "";
const { execSync } = require("child_process");
// 根据文件类型执行格式化
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) {
try {
execSync(`npx prettier --write "${filePath}"`, { stdio: "pipe" });
console.log(JSON.stringify({
message: `✅ 已格式化: ${filePath}`
}));
} catch (e) {
console.log(JSON.stringify({
message: `⚠️ 格式化失败: ${e.message}`
}));
}
} else if (filePath.endsWith(".py")) {
try {
execSync(`black "${filePath}"`, { stdio: "pipe" });
console.log(JSON.stringify({
message: `✅ 已格式化: ${filePath}`
}));
} catch (e) {
console.log(JSON.stringify({
message: `⚠️ 格式化失败`
}));
}
}
code-review-agent/
├── package.json
├── tsconfig.json
├── .claude/
│ └── settings.json # Hooks配置
├── src/
│ ├── index.ts # 主入口
│ ├── reviewer.ts # 审查逻辑
│ ├── fixer.ts # 自动修复
│ ├── reporter.ts # 报告生成
│ └── types.ts # 类型定义
└── scripts/
├── validate-cmd.js # Hook: 命令验证
└── notify.js # Hook: 完成通知
// src/types.ts
export interface ReviewIssue {
file: string;
line: number;
column?: number;
severity: "critical" | "warning" | "info";
category: "security" | "performance" | "bug" | "style" | "type-safety";
title: string;
description: string;
fix?: string; // 建议的修复代码
confidence: number; // 0-1
}
export interface ReviewReport {
timestamp: string;
filesReviewed: number;
totalIssues: number;
criticalCount: number;
warningCount: number;
score: number; // 0-100
issues: ReviewIssue[];
autoFixed: number;
summary: string;
}
export interface AgentConfig {
maxTurns: number;
parallelReviews: number;
autoFix: boolean;
severityThreshold: "critical" | "warning" | "info";
outputFormat: "json" | "markdown" | "html";
}
// src/reviewer.ts
import { claude } from "@anthropic-ai/claude-code";
import type { ReviewIssue, AgentConfig } from "./types.js";
export class CodeReviewer {
private config: AgentConfig;
constructor(config: Partial<AgentConfig> = {}) {
this.config = {
maxTurns: 10,
parallelReviews: 3,
autoFix: false,
severityThreshold: "warning",
outputFormat: "markdown",
...config,
};
}
async reviewFiles(files: string[]): Promise<ReviewIssue[]> {
// 将文件分批并行审查
const batches = this.chunkArray(files, this.config.parallelReviews);
const allIssues: ReviewIssue[] = [];
for (const batch of batches) {
const batchIssues = await Promise.all(
batch.map((file) => this.reviewSingleFile(file))
);
allIssues.push(...batchIssues.flat());
}
// 按严重程度排序
const severityOrder = { critical: 0, warning: 1, info: 2 };
allIssues.sort(
(a, b) => severityOrder[a.severity] - severityOrder[b.severity]
);
return allIssues;
}
private async reviewSingleFile(filePath: string): Promise<ReviewIssue[]> {
const result = await claude({
prompt: `你是一个专业的代码审查专家。请仔细审查文件 ${filePath}。
审查维度:
1. **安全漏洞**: SQL注入、XSS、CSRF、硬编码密钥、不安全的反序列化
2. **性能问题**: N+1查询、内存泄漏、不必要的同步操作、大数据处理
3. **Bug风险**: 空指针、竞态条件、边界条件、资源泄露
4. **类型安全**: any类型滥用、类型断言、缺少泛型约束
5. **代码风格**: 命名规范、函数长度、圈复杂度
对每个问题输出JSON格式:
{
"line": 行号,
"severity": "critical"|"warning"|"info",
"category": 分类,
"title": 问题标题,
"description": 详细描述,
"fix": "修复代码(如果有明确修复方案)",
"confidence": 0.0到1.0
}
最终输出JSON数组:[问题1, 问题2, ...]`,
options: {
maxTurns: this.config.maxTurns,
allowedTools: ["Read", "Grep"],
},
});
return this.parseIssues(result.text, filePath);
}
private parseIssues(text: string, filePath: string): ReviewIssue[] {
try {
const jsonMatch = text.match(/\[[\s\S]*\]/);
if (!jsonMatch) return [];
const issues = JSON.parse(jsonMatch[0]);
return issues.map((issue: any) => ({
...issue,
file: filePath,
}));
} catch {
console.error(`解析审查结果失败: ${filePath}`);
return [];
}
}
private chunkArray<T>(arr: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
}
// src/fixer.ts
import { claude } from "@anthropic-ai/claude-code";
import type { ReviewIssue } from "./types.js";
export class AutoFixer {
async fixIssues(issues: ReviewIssue[]): Promise<number> {
// 只修复有明确修复方案且置信度高的issues
const fixable = issues.filter(
(i) => i.fix && i.confidence >= 0.8 && i.severity !== "critical"
);
let fixedCount = 0;
// 按文件分组
const byFile = new Map<string, ReviewIssue[]>();
for (const issue of fixable) {
const list = byFile.get(issue.file) || [];
list.push(issue);
byFile.set(issue.file, list);
}
// 逐文件修复
for (const [file, fileIssues] of byFile) {
console.log(`修复 ${file} 中的 ${fileIssues.length} 个问题...`);
const issueList = fileIssues
.map((i) => `- 第${i.line}行 [${i.severity}] ${i.title}\n 修复: ${i.fix}`)
.join("\n");
const result = await claude({
prompt: `请修复文件 ${file} 中的以下问题:
${issueList}
要求:
1. 保持代码风格一致
2. 不改变非相关代码
3. 修复后确保语法正确
4. 如果修复可能引入新问题,跳过该修复`,
options: {
maxTurns: 15,
allowedTools: ["Read", "Edit", "Bash"],
permissionMode: "acceptEdits",
},
});
// 验证修复
const verifyResult = await claude({
prompt: `验证文件 ${file} 的修复是否正确:
1. 检查语法是否正确
2. 确认问题是否已解决
3. 检查是否引入了新问题`,
options: {
maxTurns: 3,
allowedTools: ["Read", "Bash"],
},
});
if (verifyResult.text.includes("修复正确") ||
verifyResult.text.includes("no errors")) {
fixedCount += fileIssues.length;
console.log(` ✅ 修复成功`);
} else {
console.log(` ⚠️ 修复可能有问题,建议人工确认`);
}
}
return fixedCount;
}
}
// src/reporter.ts
import type { ReviewReport, ReviewIssue } from "./types.js";
export class Reporter {
generateMarkdownReport(
issues: ReviewIssue[],
filesReviewed: number,
autoFixed: number
): string {
const critical = issues.filter((i) => i.severity === "critical");
const warnings = issues.filter((i) => i.severity === "warning");
const info = issues.filter((i) => i.severity === "info");
const score = Math.max(
0,
100 - critical.length * 15 - warnings.length * 5 - info.length * 1
);
let report = `# 🔍 代码审查报告\n\n`;
report += `**审查时间**: ${new Date().toISOString()}\n`;
report += `**审查文件数**: ${filesReviewed}\n`;
report += `**代码评分**: ${score}/100\n\n`;
report += `## 📊 问题统计\n\n`;
report += `| 严重程度 | 数量 |\n|----------|------|\n`;
report += `| 🔴 Critical | ${critical.length} |\n`;
report += `| 🟡 Warning | ${warnings.length} |\n`;
report += `| 🔵 Info | ${info.length} |\n`;
report += `| **总计** | **${issues.length}** |\n\n`;
if (autoFixed > 0) {
report += `## 🔧 自动修复\n\n`;
report += `已自动修复 **${autoFixed}** 个问题。\n\n`;
}
if (critical.length > 0) {
report += `## 🔴 严重问题\n\n`;
critical.forEach((issue) => {
report += `### ${issue.file}:${issue.line}\n`;
report += `**${issue.title}** [${issue.category}]\n\n`;
report += `${issue.description}\n\n`;
if (issue.fix) {
report += `> 💡 建议: ${issue.fix}\n\n`;
}
});
}
if (warnings.length > 0) {
report += `## 🟡 警告\n\n`;
warnings.forEach((issue) => {
report += `- **${issue.file}:${issue.line}** — ${issue.title}\n`;
});
report += `\n`;
}
return report;
}
}
// src/index.ts
import { CodeReviewer } from "./reviewer.js";
import { AutoFixer } from "./fixer.js";
import { Reporter } from "./reporter.js";
import type { AgentConfig } from "./types.js";
async function main() {
const config: AgentConfig = {
maxTurns: 10,
parallelReviews: 3,
autoFix: process.argv.includes("--fix"),
severityThreshold: "warning",
outputFormat: "markdown",
};
// 获取待审查的文件列表
const { execSync } = await import("child_process");
const changedFiles = execSync(
'git diff --name-only HEAD~1 -- "*.ts" "*.tsx" "*.js" "*.jsx"',
{ encoding: "utf-8" }
).trim().split("\n").filter(Boolean);
if (changedFiles.length === 0) {
console.log("没有发现变更的代码文件");
return;
}
console.log(`📋 发现 ${changedFiles.length} 个变更文件`);
console.log(`📄 文件列表: ${changedFiles.join(", ")}`);
console.log(`🔧 自动修复: ${config.autoFix ? "开启" : "关闭"}\n`);
// 执行审查
const reviewer = new CodeReviewer(config);
const issues = await reviewer.reviewFiles(changedFiles);
// 可选:自动修复
let autoFixed = 0;
if (config.autoFix) {
const fixer = new AutoFixer();
autoFixed = await fixer.fixIssues(issues);
}
// 生成报告
const reporter = new Reporter();
const report = reporter.generateMarkdownReport(
issues,
changedFiles.length,
autoFixed
);
console.log(report);
}
main().catch(console.error);
# 只审查不修复
npx tsx src/index.ts
# 审查并自动修复
npx tsx src/index.ts --fix
# 审查特定分支的变更
git diff main..feature/auth --name-only -- "*.ts" | npx tsx src/index.ts
flowchart TB
START[Git Push / PR 创建] --> DIFF[获取变更文件列表]
DIFF --> FILTER[过滤代码文件<br/>.ts .tsx .js .jsx]
FILTER --> PARALLEL[并行审查Agent]
subgraph "并行审查"
direction LR
PA1[安全审查<br/>Agent 1]
PA2[性能审查<br/>Agent 2]
PA3[质量审查<br/>Agent 3]
end
PARALLEL --> PA1 & PA2 & PA3
PA1 & PA2 & PA3 --> MERGE[合并审查结果]
MERGE --> SCORE[计算代码评分]
SCORE --> CHECK{是否需要<br/>自动修复?}
CHECK -->|是 --fix| FIX[AutoFixer Agent<br/>修复并验证]
CHECK -->|否| REPORT[生成Markdown报告]
FIX --> REPORT
REPORT --> OUTPUT[输出到终端 / 文件]
style CHECK fill:#f9f,stroke:#333
style FIX fill:#bfb,stroke:#333
style OUTPUT fill:#bbf,stroke:#333
// src/budget-manager.ts
import { claude } from "@anthropic-ai/claude-code";
class BudgetManager {
private totalBudget: number;
private spent: number = 0;
constructor(maxTokens: number = 500_000) {
this.totalBudget = maxTokens;
}
remaining(): number {
return Math.max(0, this.totalBudget - this.spent);
}
async runAgent(prompt: string, maxTurns: number = 5): Promise<any> {
if (this.remaining() < 10_000) {
throw new Error(`Token预算不足: 剩余 ${this.remaining()}`);
}
const result = await claude({
prompt,
options: { maxTurns },
});
// 累计消耗
if (result.usage?.totalTokens) {
this.spent += result.usage.totalTokens;
}
console.log(`本次消耗: ${result.usage?.totalTokens}, 剩余预算: ${this.remaining()}`);
return result;
}
}
// 使用
const budget = new BudgetManager(1_000_000); // 100万Token预算
const result = await budget.runAgent("审查所有代码");
// src/resilient-agent.ts
async function resilientAgentCall(
prompt: string,
maxRetries: number = 3
): Promise<any> {
let lastError: Error | null = null;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await claude({
prompt,
options: { maxTurns: 10 },
});
return result;
} catch (error: any) {
lastError = error;
if (error.message?.includes("rate limit")) {
const delay = Math.min(1000 * Math.pow(2, attempt), 30_000);
console.log(`速率限制,${delay}ms后重试 (${attempt}/${maxRetries})`);
await new Promise((r) => setTimeout(r, delay));
} else if (error.message?.includes("context window")) {
// 上下文溢出,减少轮次重试
console.log(`上下文溢出,减少任务复杂度后重试`);
const result = await claude({
prompt: prompt.slice(0, 2000), // 截断提示
options: { maxTurns: 3 },
});
return result;
} else {
throw error; // 不可重试的错误直接抛出
}
}
}
throw lastError;
}
从2026年6月15日起,Anthropic将Agent SDK和claude -p的使用量从交互式额度中分离,改为独立的月度Agent SDK额度。关键影响:
| 项目 | 变更前 | 变更后 |
|---|---|---|
| Agent SDK调用 | 消耗交互式额度 | 独立的Agent SDK月度额度 |
claude -p |
消耗交互式额度 | 独立的Agent SDK月度额度 |
| 交互式Claude Code | 不受影响 | 不受影响 |
| 额度重置 | 按订阅周期 | 按月重置 |
生产环境中建议通过result.usage字段持续监控Token消耗,避免超出额度。
训练营适用性评估:
| 维度 | 评估 |
|---|---|
| 适合训练营类型 | AI工程训练营、Agent开发进阶营、DevOps自动化训练营 |
| 学员基础要求 | TypeScript中级、Claude Code基本操作经验、Node.js项目经验 |
| 预计教学时长 | 6-8小时(含实操) |
| 实操比重 | 70%实操 + 30%讲解 |
| 硬件要求 | 每人一台开发机,安装Node.js 18+和Claude Code |
| 产出物 | 可运行的代码审查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 等场景全覆盖。
