第14章:Agent SDK 开发实战

概述

Claude Agent SDK 是 Anthropic 提供的官方开发工具包,它让你能够构建自定义的 AI Agent,将 Claude 的能力嵌入到自己的应用和工作流中。与直接调用 Claude API 不同,Agent SDK 提供了工具定义、对话管理、上下文维护等高级抽象,让你可以专注于业务逻辑而非基础设施。本章将从基础概念到实战项目,全面讲解 Agent SDK 的使用。

Claude Agent SDK 核心概念

Agent 架构模型

Agent SDK 的核心是一个事件驱动的循环架构,Agent 接收用户输入,决定使用哪些工具,执行工具调用,并将结果整合到回复中。

用户输入 → Agent 推理 → 工具选择 → 工具执行 → 结果整合 → 输出
              ↑                                    │
              └────────── 循环直到完成 ──────────────┘

核心组件

组件职责类比
Agent顶层协调器,管理整个交互流程项目经理
Tool可执行的功能单元,Agent 可以调用团队成员
Context对话状态和上下文存储项目白板
Middleware请求/响应处理中间件流程审批
Memory长期记忆存储和管理档案室

SDK 安装与初始化

环境准备

# 创建项目目录
mkdir my-code-review-agent
cd my-code-review-agent

# 初始化项目
npm init -y

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

# 安装 TypeScript 支持
npm install -D typescript @types/node ts-node

# 创建 tsconfig.json
npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext

基础初始化代码

// src/index.ts
import { Agent } from "@anthropic-ai/agent-sdk";

// 初始化 Agent 实例
const agent = new Agent({
  name: "code-reviewer",
  model: "claude-sonnet-4-20250514",
  apiKey: process.env.ANTHROPIC_API_KEY,
  systemPrompt: `你是一个专业的代码审查助手。
你的职责是:
1. 检查代码质量和安全性
2. 发现潜在的性能问题
3. 提供改进建议
4. 确保代码风格一致性

请使用中文输出审查结果,并在每个问题上标注严重级别。`,
});

// 启动交互会话
async function main() {
  const response = await agent.run(
    "请审查下面的 React 组件代码..."
  );
  console.log(response.text);
}

main().catch(console.error);

构建自定义 Agent

定义工具

工具是 Agent 能力的核心,它让 Agent 能够与外部系统交互。

// src/tools.ts
import { Tool } from "@anthropic-ai/agent-sdk";
import fs from "fs/promises";

// 工具一:文件读取工具
const readFileTool: Tool = {
  name: "read_file",
  description: "读取项目中的源代码文件",
  parameters: {
    type: "object",
    properties: {
      filePath: {
        type: "string",
        description: "文件路径,相对于项目根目录",
      },
    },
    required: ["filePath"],
  },
  execute: async ({ filePath }: { filePath: string }) => {
    try {
      const content = await fs.readFile(filePath, "utf-8");
      return { success: true, content };
    } catch (error) {
      return { success: false, error: `无法读取文件: ${error}` };
    }
  },
};

// 工具二:代码分析工具
const analyzeCodeTool: Tool = {
  name: "analyze_complexity",
  description: "分析代码的圈复杂度",
  parameters: {
    type: "object",
    properties: {
      code: {
        type: "string",
        description: "要分析的源代码",
      },
    },
    required: ["code"],
  },
  execute: async ({ code }: { code: string }) => {
    const patterns = [
      /ifs*(/g, /elses/g, /fors*(/g,
      /whiles*(/g, /switchs*(/g, /&&/g,
      /||/g, /?/g, /catchs*(/g,
    ];

    let score = 0;
    const details: Record<string, number> = {};
    for (const pattern of patterns) {
      const matches = code.match(pattern);
      if (matches) {
        const key = pattern.source;
        details[key] = matches.length;
        score += matches.length;
      }
    }

    return {
      complexity_score: score,
      details,
      risk_level: score > 20 ? "high" : score > 10 ? "medium" : "low",
      suggestion:
        score > 20
          ? "建议将复杂函数拆分为多个小函数"
          : "代码复杂度在可接受范围内",
    };
  },
};

// 工具三:Git 历史查询工具
const gitHistoryTool: Tool = {
  name: "git_history",
  description: "查询指定文件的 Git 提交历史",
  parameters: {
    type: "object",
    properties: {
      filePath: {
        type: "string",
        description: "文件路径",
      },
      maxCount: {
        type: "number",
        description: "最大返回提交数",
        default: 10,
      },
    },
    required: ["filePath"],
  },
  execute: async ({
    filePath,
    maxCount = 10,
  }: {
    filePath: string;
    maxCount: number;
  }) => {
    const { execSync } = await import("child_process");
    try {
      const output = execSync(
        `git log --oneline -n ${maxCount} -- "${filePath}"`,
        { encoding: "utf-8" }
      );
      const commits = output
        .trim()
        .split("\n")
        .filter(Boolean)
        .map((line) => {
          const [hash, ...msg] = line.split(" ");
          return { hash, message: msg.join(" ") };
        });
      return { success: true, commits };
    } catch (error) {
      return { success: false, error: `Git 命令执行失败: ${error}` };
    }
  },
};

组装完整的 Agent

// src/agent.ts
import { Agent } from "@anthropic-ai/agent-sdk";
import {
  readFileTool,
  analyzeCodeTool,
  gitHistoryTool,
} from "./tools.js";

export function createCodeReviewAgent(): Agent {
  return new Agent({
    name: "code-review-bot",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
    maxTokens: 4096,
    temperature: 0.3, // 低温度确保审查结果稳定

    tools: [readFileTool, analyzeCodeTool, gitHistoryTool],

    systemPrompt: `你是一个专业的代码审查机器人。

工作流程:
1. 首先使用 read_file 读取目标文件
2. 使用 analyze_complexity 分析代码复杂度
3. 使用 git_history 查看文件的修改历史
4. 综合以上信息,给出全面的审查报告

审查报告格式:
- 🔴 严重问题:安全漏洞、数据泄露风险等
- 🟡 警告:性能问题、代码异味
- 🔵 建议:代码风格、可读性改进
- ✅ 亮点:值得表扬的优秀实现

输出要求:
- 每个问题标注行号
- 给出具体的修改建议和示例代码
- 按严重程度排序
- 使用中文输出`,

    // 对话管理配置
    conversation: {
      maxTurns: 50,
      persistence: true,
      storage: "file",
      storagePath: "./data/conversations",
    },
  });
}

Agent 与 API 直接调用的差异

了解 Agent SDK 和直接 API 调用的区别,有助于在项目中做出正确的技术选型。

对比维度Agent SDK直接 API 调用
工具调用内置工具定义和自动执行需要手动解析 tool_use
对话管理自动维护上下文窗口手动管理消息历史
重试逻辑内置指数退避重试需要自行实现
流式输出原生支持需要额外配置
中间件支持请求/响应拦截无内置支持
记忆管理内置短期/长期记忆需自行实现向量存储
并发控制内置请求队列需自行实现限流
调试工具内置日志和追踪
定制灵活度中等(符合最佳实践)最高(完全控制)
开发效率

实战:用 SDK 构建一个代码审查机器人

完整实现

// src/main.ts
import { createCodeReviewAgent } from "./agent.js";
import fs from "fs/promises";

interface ReviewRequest {
  targetDir: string;
  filePattern?: string;
  strictMode?: boolean;
}

interface ReviewReport {
  summary: {
    filesReviewed: number;
    criticalIssues: number;
    warnings: number;
    suggestions: number;
  };
  details: Array<{
    file: string;
    issues: Array<{
      type: "critical" | "warning" | "suggestion";
      line?: number;
      message: string;
      suggestion?: string;
    }>;
    highlights: string[];
  }>;
  score: number;
}

class CodeReviewBot {
  private agent;
  private report: ReviewReport = {
    summary: { filesReviewed: 0, criticalIssues: 0, warnings: 0, suggestions: 0 },
    details: [],
    score: 100,
  };

  constructor() {
    this.agent = createCodeReviewAgent();
  }

  async reviewProject(request: ReviewRequest): Promise<ReviewReport> {
    const pattern = request.filePattern || "**/*.{ts,tsx,js,jsx}";
    const { globSync } = await import("glob");
    const files = globSync(pattern, { cwd: request.targetDir });

    console.log(`📁 发现 ${files.length} 个待审查文件`);

    for (const file of files.slice(0, 20)) {
      // 限制最多审查 20 个文件
      console.log(`🔍 正在审查: ${file}`);
      const fileReview = await this.reviewFile(file, request.targetDir);
      this.report.details.push(fileReview);

      this.report.summary.filesReviewed++;
      for (const issue of fileReview.issues) {
        if (issue.type === "critical") this.report.summary.criticalIssues++;
        else if (issue.type === "warning") this.report.summary.warnings++;
        else this.report.summary.suggestions++;
      }
    }

    // 计算总体评分
    this.report.score = Math.max(
      0,
      100 -
        this.report.summary.criticalIssues * 10 -
        this.report.summary.warnings * 3 -
        this.report.summary.suggestions * 1
    );

    await this.saveReport();
    return this.report;
  }

  private async reviewFile(
    file: string,
    targetDir: string
  ): Promise<ReviewReport["details"][0]> {
    const filePath = `${targetDir}/${file}`;
    const content = await fs.readFile(filePath, "utf-8");

    const response = await this.agent.run(
      `请审查以下文件,关注安全性、性能、代码质量:\n\n${content}`
    );

    return {
      file: filePath,
      issues: response.text.match(/🔴|🟡|🔵/g)?.map((marker) => ({
        type: marker === "🔴" ? "critical" : marker === "🟡" ? "warning" : "suggestion",
        message: "请查看完整审查报告",
      })) || [],
      highlights: [],
    };
  }

  private async saveReport(): Promise<void> {
    await fs.mkdir("./reports", { recursive: true });
    const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
    await fs.writeFile(
      `./reports/review-${timestamp}.json`,
      JSON.stringify(this.report, null, 2)
    );
    console.log(`📊 报告已保存: reports/review-${timestamp}.json`);
  }
}

// 启动审查机器人
async function main() {
  const bot = new CodeReviewBot();
  const report = await bot.reviewProject({
    targetDir: process.argv[2] || ".",
    filePattern: "src/**/*.{ts,tsx}",
    strictMode: true,
  });

  console.log(`
  ╔═══════════════════════════╗
  ║   代码审查报告摘要         ║
  ╠═══════════════════════════╣
  ║ 审查文件: ${report.summary.filesReviewed.toString().padEnd(12)} ║
  ║ 严重问题: ${report.summary.criticalIssues.toString().padEnd(12)} ║
  ║ 警告:     ${report.summary.warnings.toString().padEnd(12)} ║
  ║ 建议:     ${report.summary.suggestions.toString().padEnd(12)} ║
  ║ 综合评分: ${report.score.toString().padEnd(12)} ║
  ╚═══════════════════════════╝
  `);
}

main().catch(console.error);

SDK 配置优化

模型选择策略

// src/config.ts
import { AgentConfig } from "@anthropic-ai/agent-sdk";

export function getOptimizedConfig(taskType: string): Partial<AgentConfig> {
  const configs: Record<string, Partial<AgentConfig>> = {
    // 代码审查:需要高准确性,使用 Sonnet
    "code-review": {
      model: "claude-sonnet-4-20250514",
      temperature: 0.2,
      maxTokens: 8192,
      systemPrompt: "你是一个严谨的代码审查员...",
    },
    // 创意任务:需要多样性,使用 Sonnet 较高温度
    "creative": {
      model: "claude-sonnet-4-20250514",
      temperature: 0.8,
      maxTokens: 4096,
    },
    // 批量处理:使用 Haiku 降低成本
    "batch-processing": {
      model: "claude-haiku-4-20250514",
      temperature: 0.1,
      maxTokens: 2048,
    },
    // 复杂推理:使用 Opus 应对高难度任务
    "complex-reasoning": {
      model: "claude-opus-4-20250514",
      temperature: 0.3,
      maxTokens: 16384,
      thinking: {
        type: "enabled",
        budgetTokens: 8192,
      },
    },
  };

  return configs[taskType] || configs["code-review"];
}

Token 管理策略

// Token 预算管理
const tokenBudgets = {
  // 每个会话的 Token 预算
  perSession: {
    maxInputTokens: 64000,
    maxOutputTokens: 16384,
    warningThreshold: 0.8, // 达到 80% 时发出警告
  },
  // 上下文窗口压缩策略
  compression: {
    enabled: true,
    strategy: "summarize_oldest",
    keepRecentTurns: 10,
    summaryInterval: 20, // 每 20 轮对话压缩一次
  },
};

本章小结

通过本章的学习,你掌握了 Claude Agent SDK 的核心概念和完整开发流程:

  • 理解 Agent 架构中各个组件的职责
  • 学会安装 SDK 并完成初始化配置
  • 掌握工具定义的最佳实践
  • 了解 Agent SDK 与直接 API 调用的适用场景
  • 能够构建具备复杂交互能力的自定义 Agent
  • 学会根据任务类型优化模型和 Token 配置

Agent SDK 将 AI 能力从"单次问答"提升到了"持续协作"的层次,让 Claude 能够在复杂的业务场景中发挥更大的价值。