手把手教你用 Claude Agent SDK 构建你的第一个AI代码审查员

03827542419502f3774f045ac210ac26.png

1. 简介:开启你的AI代理构建之旅

1.1 欢迎语与目标

欢迎来到AI代理构建的世界!如果你曾对能够自主分析代码、运行命令、甚至修复错误的AI感到好奇,那么本教程就是为你量身打造的。我们的目标清晰而具体:从零开始,一步步构建一个可以分析代码库、发现潜在问题并提供专业反馈的AI代码审查代理(Code Review Agent)。

本教程专为初学者设计,你不需要任何AI代理开发经验。只要跟着我们的步骤,你就能亲手创造出第一个属于自己的实用AI工具。

1.2 什么是 Claude Agent SDK?为什么它如此强大?

简单来说,Claude Agent SDK 是著名AI助手 Claude Code 背后的核心引擎。它是一个强大的工具库,让你能够轻松地构建、测试和部署自己的AI代理。

为了让你更直观地理解SDK的优势,让我们对比一下使用原生API和使用Agent SDK构建代理的区别:

特性 使用原生API 使用Agent SDK
循环管理 开发者需要手动编写循环逻辑,不断调用模型、检查工具使用、返回结果,过程繁琐。 SDK自动处理整个代理循环,你只需关注业务逻辑。
工具执行 需要自己实现所有工具(如文件读取、网络搜索)的调用和结果处理。 内置了一系列即开即用的强大工具(文件操作、Shell命令、网络搜索等)。
代码简洁性 代码冗长,需要管理大量的状态和API调用细节。 代码极其简洁,几行代码就能启动一个强大的代理会​​话。

下面的代码片段生动地展示了这种简洁性带来的巨大差异:

// 使用原生API:你需要手动管理整个循环
let response = await client.messages.create({...});
while (response.stop_reason === "tool_use") {
  const result = yourToolExecutor(response.tool_use);
  response = await client.messages.create({ tool_result: result, ... });
}

// 使用Agent SDK:Claude 会为你处理好一切
for await (const message of query({ prompt: "修复 auth.py 中的错误" })) {
  console.log(message); // Claude 会自动读取文件、发现错误并修改代码
}

它为何如此强大?内置的工具集是关键。 Agent SDK 的一个核心优势在于它为你处理了所有繁琐的底层逻辑,让你能够将精力完全集中在定义代理的目标和功能上。它自带一套强大的预置工具,极大地加快了开发速度,让你不必从零开始实现常见的文件和命令行操作。

  • Read Write Edit: 强大的文件系统操作能力。

  • Glob / Grep: 像专业的开发者一样查找文件和搜索代码内容。

  • Bash: 赋予代理执行终端命令的能力。

  • WebSearch / WebFetch: 让代理能够上网搜索信息和获取网页内容。

核心理念:消息流 (The Core Idea: The Message Stream)

在深入编写代码之前,理解SDK的核心工作方式至关重要:异步消息流。你可以把代理的整个工作过程想象成一个持续不断的事件流。从代理启动、思考、调用工具,到最终给出答案,每一步都会通过这个流发送一条消息。

我们之后会用 for await...of 循环来监听这个流。理解不同类型的消息是掌握SDK的关键:

  • system: 这类消息通常在会话开始时出现,告诉你一些初始化信息,比如唯一的会话ID或可用的工具列表。

  • assistant: 这是最重要的消息类型之一,它包含了Claude的“思考过程”——它的文本回复、它决定使用哪个工具的调用请求等。

  • result: 当代理完成所有任务(或失败)时,会发送一条 result 消息。这条消息包含了最终的状态(如 success)、总成本,以及我们后面会用到的结构化输出。

提前理解这个概念,会让你在看到第一个代码示例时豁然开朗。

1.3 我们将要构建什么?

在本教程中,我们将构建一个代码审查代理,它具备以下三个核心功能:

  • 分析代码:能够深入代码库,分析其中的错误、安全漏洞和性能问题。

  • 自主操作:能够像人类工程师一样,自主地使用工具读取文件和搜索代码。

  • 结构化反馈:能够提供格式清晰、可供程序直接使用的结构化审查报告。

1.4 技术栈一览

我们将使用以下现代且强大的技术栈来完成本次构建:

  • 运行时 (Runtime): Claude Code CLI - 这是Agent SDK的官方运行环境。

  • SDK: @anthropic-ai/claude-agent-sdk - 我们的核心工具库。

  • 语言 (Language): TypeScript - 提供强大的类型安全,让代码更健壮。

  • 模型 (Model): Claude Opus 4.5 - Anthropic最强大的模型之一,具备卓越的推理能力。

理论知识已经足够,现在让我们卷起袖子,开始搭建我们的开发环境吧!

2. 准备工作:搭建你的开发环境

2.1 必备前提

在开始之前,请确保你的电脑上已经准备好以下两样东西:

  1. Node.js: 你需要 18+ 或更高的版本。

  2. Anthropic API 密钥: 这是让你的代理能够调用Claude模型的“通行证”。你可以在 Anthropic 控制台 免费获取。

2.2 环境设置分步指南

我们将通过三个简单的步骤来完成所有设置。

  1. 第一步:安装 Claude Code CLI

  2. Claude Code CLI 是Agent SDK的运行环境。打开你的终端,输入以下命令进行全局安装:

  3. 安装完成后,运行 claude 命令,并按照提示完成身份验证。

  4. 第二步:创建项目并安装依赖

  5. 接下来,让我们为代码审查代理创建一个专属的项目目录,并安装所有必需的依赖包。

    • @anthropic-ai/claude-agent-sdk 是我们的主角——核心SDK。

    • typescript, @types/node, tsx 是帮助我们编写和运行TypeScript代码的开发工具。

  6. 第三步:设置你的 API 密钥

  7. 这是至关重要的一步。执行以下命令,将你的Anthropic API密钥设置为环境变量。SDK会自动读取这个变量来进行API调用。

  8. 注意: 请将 your-api-key 替换为你自己真实的API密钥。

太棒了!你的开发环境已经准备就绪。现在,让我们来编写并运行第一个简单的AI代理,感受一下SDK的魔力。

3. 第一个代理程序:小试牛刀

3.1 创建你的第一个代理文件

在你的项目目录 code-review-agent 中,创建一个名为 agent.ts 的新文件,并将以下代码粘贴进去:

import { query } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  for await (const message of query({
    prompt: "What files are in this directory?",
    options: {
      model: "opus",
      allowedTools: ["Glob", "Read"],
      maxTurns: 250
    }
  })) {
    if (message.type === "assistant") {
      for (const block of message.message.content) {
        if ("text" in block) {
          console.log(block.text);
        }
      }
    }
    if (message.type === "result") {
      console.log("\nDone:", message.subtype);
    }
  }
}

main();

3.2 代码逐行解析

这段代码虽然简短,但包含了与代理交互的核心要素。让我们来逐一解析:

  • import { query }: 这是我们从SDK中导入的核心函数,它是所有代理交互的入口点。

  • query() 函数: 这个函数负责启动一个代理会话。我们向它传递初始指令和配置。

  • prompt 参数: 这是我们给代理下达的初始指令。在这里,我们让它“找出当前目录下的所有文件”。

  • options 对象: 这个对象用于配置代理的行为。

    • model: 指定我们希望使用的Claude模型。"opus" 是 Anthropic 最强大模型家族的别名 (对于生产环境或需要可复现结果的场景,你可能会使用更具体的版本名称,如 claude-opus-4-5-20251101)。

    • allowedTools: 一个数组,定义了允许代理使用的工具集。这里我们只允许它使用 Glob(按模式查找文件)和 Read(读取文件内容)。

    • maxTurns: 代理在放弃任务前,可以与工具进行交互的最大回合数。

  • for await...of 循环: 这是一个异步循环,它会持续从我们之前讨论过的“消息流”中接收消息。代理在工作过程中的每一步(思考、使用工具、回复)都会产生一条消息。

  • if (message.type === "assistant"): 我们在这里从消息流中筛选出类型为 assistant 的消息,这些消息包含了Claude的文本回复。然后我们将其打印到控制台。

3.3 运行并观察结果

在你的终端中,运行以下命令:

npx tsx agent.ts

你会看到,Claude接收到指令后,会决定使用 Glob 工具来列出当前目录下的文件,最后以一段文本的形式告诉你它找到了哪些文件。

现在你已经成功运行了一个简单的代理,它能够使用工具并与你交流。接下来,让我们在这个基础上构建一个更强大、更具实际用途的代码审查代理。

4. 构建核心功能:一个真正的代码审查代理

4.1 创建代码审查代理文件

让我们创建一个新文件 review-agent.ts,并填入以下更专业的代码:

import { query } from "@anthropic-ai/claude-agent-sdk";

async function reviewCode(directory: string) {
  console.log(`\n🔍 Starting code review for: ${directory}\n`);

  for await (const message of query({
    prompt: `Review the code in ${directory} for:
1. Bugs and potential crashes
2. Security vulnerabilities
3. Performance issues
4. Code quality improvements
Be specific about file names and line numbers.`,
    options: {
      model: "opus",
      allowedTools: ["Read", "Glob", "Grep"],
      permissionMode: "bypassPermissions",
      maxTurns: 250
    }
  })) {
    // 实时显示Claude的分析过程
    if (message.type === "assistant") {
      for (const block of message.message.content) {
        if ("text" in block) {
          console.log(block.text);
        } else if ("name" in block) {
          console.log(`\n📁 Using ${block.name}...`);
        }
      }
    }

    // 显示任务完成状态
    if (message.type === "result") {
      if (message.subtype === "success") {
        console.log(`\n✅ Review complete! Cost: $${message.total_cost_usd.toFixed(4)}`);
      } else {
        console.log(`\n❌ Review failed: ${message.subtype}`);
      }
    }
  }
}

// 开始审查当前目录
reviewCode(".");

4.2 代码升级解析

与上一个简单的代理相比,这段代码有了显著的升级:

  • 更复杂的 prompt: 我们不再是简单地提问,而是通过一个有序列表,向代理下达了一个非常具体且复杂的审查任务,涵盖了错误、漏洞、性能和代码质量四个方面。

  • 新的工具集 allowedTools: 我们为代理配备了审查代码所需的核心工具组合。这模拟了人类开发者的思考过程:首先,代理使用 Glob 来找到所有相关的源文件(就像查看文件树一样)。然后,它使用 Read 来打开并理解每个文件的内容。最后,如果需要查找特定模式(如一个被弃用的函数名),它会使用 Grep 来在整个代码库中进行搜索。

  • 新的选项 permissionMode: 你可能会想:“在开发过程中,如果每次代理尝试读取文件都得手动批准,这会打断我的流程。” 为了解决这个问题,SDK提供了一个便捷的选项 permissionMode: "bypassPermissions"。它告诉SDK自动批准所有读取文件的操作,让流程更加顺畅。

  • 更丰富的日志输出: 代码现在不仅打印Claude的文本回复,还会打印出它正在使用哪个工具 (Using Glob...),这让代理的工作过程变得更加透明,便于我们观察和调试。

4.3 创建一个用于测试的“问题”文件

为了验证我们的代理是否有效,我们需要给它一些“有问题”的代码来审查。在项目根目录下创建一个名为 example.ts 的新文件,并粘贴以下代码:

function processUsers(users: any) {
  for (let i = 0; i <= users.length; i++) { // 越界错误
    console.log(users[i].name.toUpperCase()); // 未进行空值检查
  }
}

function connectToDb(password: string) {
  const connectionString = `postgres://admin:${password}@localhost/db`;
  console.log("Connecting with:", connectionString); // 记录敏感数据
}

async function fetchData(url) { // 缺少类型注解
  const response = await fetch(url);
  return response.json(); // 缺少错误处理
}

这段代码中故意留下了几个常见问题:

  • 越界错误:for 循环的条件 i <= users.length 会导致访问一个不存在的数组元素。

  • 空值引用:如果 users[i] 为 null 或 undefined,users[i].name 将导致程序崩溃。

  • 敏感数据泄露:将包含密码的数据库连接字符串直接打印到日志中,这是一个严重的安全漏洞。

  • 类型和错误处理缺失:函数参数没有类型注解,fetch 调用也没有任何错误处理逻辑。

4.4 运行你的代码审查员

一切准备就绪!现在,让我们启动代码审查代理:

npx tsx review-agent.ts

观察你的终端输出。你会看到Claude开始分析,并实时打印出它对 example.ts 文件中每一个问题的发现,包括具体的文件名、行号以及详细的修复建议。

做得好!你的代理现在已经可以像一个初级工程师一样找出代码中的问题了。但为了让审查结果更易于被其他程序使用,我们需要让它输出结构化的数据,比如JSON格式。

5. 升级代理:输出结构化数据

5.1 为什么需要结构化输出?

人类可以轻松理解自由格式的文本,但对于计算机程序来说,处理这些文本非常困难。如果审查结果是结构化的(如JSON格式),我们就可以轻松地将其集成到CI/CD流程、生成报告或在仪表盘上展示。

5.2 定义输出格式:JSON Schema

为了告诉Claude我们想要的输出格式,我们需要定义一个“模板”,这个模板就是 JSON Schema。它精确地描述了JSON对象应该包含哪些字段、每个字段的类型是什么,就像一份合同一样,确保代理返回的数据是我们期望的样子。

const reviewSchema = {
  type: "object",
  properties: {
    issues: {
      type: "array",
      items: {
        type: "object",
        properties: {
          severity: { type: "string", enum: ["low", "medium", "high", "critical"] },
          category: { type: "string", enum: ["bug", "security", "performance", "style"] },
          file: { type: "string" },
          line: { type: "number" },
          description: { type: "string" },
          suggestion: { type: "string" }
        },
        required: ["severity", "category", "file", "description"]
      }
    },
    summary: { type: "string" },
    overallScore: { type: "number" }
  },
  required: ["issues", "summary", "overallScore"]
};

这个Schema告诉Claude,最终的输出必须是一个包含 issues 数组、summary 字符串和 overallScore 数字的对象。同时,它还详细定义了issues数组中每个问题对象的结构。

5.3 编写输出结构化数据的代理

现在,我们可以修改 review-agent.ts 文件(或创建一个新文件)来使用这个Schema。以下是完整代码:

import { query } from "@anthropic-ai/claude-agent-sdk";

const reviewSchema = {
  type: "object",
  properties: {
    issues: {
      type: "array",
      items: {
        type: "object",
        properties: {
          severity: { type: "string", enum: ["low", "medium", "high", "critical"] },
          category: { type: "string", enum: ["bug", "security", "performance", "style"] },
          file: { type: "string" },
          line: { type: "number" },
          description: { type: "string" },
          suggestion: { type: "string" }
        },
        required: ["severity", "category", "file", "description"]
      }
    },
    summary: { type: "string" },
    overallScore: { type: "number" }
  },
  required: ["issues", "summary", "overallScore"]
};

async function reviewCodeStructured(directory: string) {
  for await (const message of query({
    prompt: `Review the code in ${directory}. Identify all issues.`,
    options: {
      model: "opus",
      allowedTools: ["Read", "Glob", "Grep"],
      permissionMode: "bypassPermissions",
      maxTurns: 250,
      outputFormat: {
        type: "json_schema",
        schema: reviewSchema
      }
    }
  })) {
    if (message.type === "result" && message.subtype === "success") {
      const review = message.structured_output as {
        issues: Array<{
          severity: string;
          category: string;
          file: string;
          line?: number;
          description: string;
          suggestion?: string;
        }>;
        summary: string;
        overallScore: number;
      };

      console.log(`\n📊 Code Review Results`);
      console.log(`✅ Review complete! Cost: $${message.total_cost_usd.toFixed(4)}\n`);
      console.log(`Score: ${review.overallScore}/100`);
      console.log(`Summary: ${review.summary}\n`);

      for (const issue of review.issues) {
        const icon = issue.severity === "critical" ? "🔴" :
                     issue.severity === "high"    ? "🟠" :
                     issue.severity === "medium"  ? "🟡" : "🟢";
        console.log(`${icon} [${issue.category.toUpperCase()}] ${issue.file}${issue.line ? `:${issue.line}` : ""}`);
        console.log(` ${issue.description}`);
        if (issue.suggestion) {
          console.log(` 💡 ${issue.suggestion}`);
        }
        console.log();
      }
    }
  }
}

reviewCodeStructured(".");

这里的关键改动有两处:

  1. options 中的 outputFormat: 我们在 options 对象中新增了 outputFormat 字段,并将我们定义的 reviewSchema 传递给它。这明确地告诉代理,最终结果必须符合这个Schema。

  2. 处理 result 消息: 这也揭示了 assistant 和 result 消息类型的核心区别:assistant 流展示的是代理的过程(它的思考和工具使用),而最终的、经过验证的、符合Schema的产品则只在任务结束时的 result 消息中交付一次。我们通过 message.structured_output 来访问这个JSON对象。

你现在得到的不仅仅是文本,而是一个可以被其他系统集成的、机器可读的专业审查报告。这就是将AI代理融入自动化工作流程的关键一步。

再次运行 npx tsx review-agent.ts,你将看到一个格式精美、结构清晰的专业代码审查报告!

恭喜你!你已经成功构建了一个功能强大且能输出专业审查报告的AI代码审查代理。你掌握了SDK的核心用法,是时候看看未来还有哪些更酷的功能等待你去探索了。

6. 总结与下一步

6.1 你已经掌握的核心技能

通过本教程,你已经从零开始,掌握了构建一个AI代理所需的核心技能:

  • 环境设置: 如何安装CLI、创建项目和配置API密钥。

  • 发起代理查询: 如何使用核心的 query() 函数启动代理并与之交互。

  • 配置代理行为: 如何通过 options 对象来指定模型、授权工具和设置权限模式。

  • 处理实时消息: 如何从异步消息流中获取代理的思考过程(assistant 消息)和最终结果(result 消息)。

  • 实现结构化输出: 如何利用JSON Schema来获得格式统一、可供程序直接使用的数据。

6.2 深入探索:未来学习路径

你刚刚构建的代理仅仅是一个开始。Claude Agent SDK 提供了更多强大的功能,可以帮助你构建更复杂的应用。以下是一些值得你深入探索的方向:

  • 子代理 (Subagents): 当任务变得异常复杂时怎么办?你可以将一个庞大的任务分解给多个专门的子代理来协同处理,就像一个团队一样。了解更多

  • 自定义工具 (Custom Tools): 如果你想让代理与你自己的API或数据库交互呢?通过创建自定义工具,你可以赋予代理与任何系统对话的能力。了解更多

  • 会话管理 (Session Management): 如果希望代理能记住你们上次的对话,并在下一次继续呢?会话管理是构建能维持上下文的多轮对话代理的关键。了解更多

  • 钩子 (Hooks): 如何在代理执行的关键节点(如使用工具前)注入自定义逻辑?钩子机制让你能实现精细的日志记录、安全检查或行为修改。了解更多

  • 成本追踪 (Cost Tracking): 如何精确地知道每次代理运行花费了多少钱?SDK内置的成本追踪功能可以清晰地告诉你每一次调用的Token用量和费用。了解更多

  • 文件检查点 (File Checkpointing): 允许代理修改文件总让人有点担心。这个功能让代理的所有文件修改都可被追踪,甚至可以一键恢复到修改前的状态。了解更多

  • 技能 (Skills): 如何将一套工具和指令打包成可复用的能力?技能让你能创建标准化的、可插拔的功能模块。了解更多

  • 生产部署 (Production Deployment): 当你准备好将代理投入真实世界时,如何安全、可靠地部署它?这里有关于容器化、CI/CD和安全沙箱的最佳实践。了解更多

值得注意的是,本指南涵盖的是SDK的V1版本。V2版本目前正在积极开发中。请保持关注,因为工具链在不断进化。

你已经迈出了最重要的一步。现在,世界充满了等待被解决的问题,而你拥有了创造解决方案的强大工具。继续探索,不断创造,看看你能用AI代理构建出怎样令人惊叹的应用吧!