学习 Claude Code 的代码

9 阅读6分钟

想深入学习 Claude Code 的代码,确实需要一个从“会用”到“看懂”再到“能改”的过程。我帮你梳理了一份“三步走”学习路线,包含了可直接操作的示例,希望能帮你加速这个过程。

一、环境搭建

bash

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

# 2. 设置 API Key
export ANTHROPIC_API_KEY="your-api-key-here"

验证安装是否成功:

javascript

// test-setup.js
import { query } from "@anthropic-ai/claude-agent-sdk";

async function testSetup() {
  for await (const msg of query({
    prompt: "Say 'Hello, I am ready to work'",
    options: { maxTurns: 1 }
  })) {
    if (msg.type === "result") {
      console.log(msg.result);
    }
  }
}

testSetup();

运行 node test-setup.js,看到输出就说明环境配置好了

二、核心概念:Agent 循环

Agent 循环是 AI Agent 的核心——它反复执行“思考 → 调用工具 → 观察结果 → 继续思考”的过程。

2.1 最简 Agent 循环

javascript

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

// 自定义工具:读取文件
const customTools = [{
  name: "read_file",
  description: "读取指定路径的文件内容",
  inputSchema: {
    type: "object",
    properties: {
      path: { type: "string", description: "文件路径" }
    },
    required: ["path"]
  },
  handler: async (args) => {
    const content = await fs.readFile(args.path, 'utf-8');
    return { content };
  }
}];

async function basicAgent() {
  const response = await query({
    prompt: `请读取 package.json 文件,然后告诉我项目的名称和版本`,
    options: {
      maxTurns: 5,                    // 最多5轮对话
      tools: customTools,             // 注册自定义工具
      permissionMode: "acceptEdits",  // 自动批准操作
    }
  });

  for await (const message of response) {
    if (message.type === "assistant") {
      console.log("Agent 思考:", message.message.content);
    }
    if (message.type === "result") {
      console.log("最终结果:", message.result);
    }
  }
}

basicAgent();

2.2 理解流式响应

Agent SDK 使用异步生成器,可以实时看到 Agent 的每一步操作:

javascript

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

async function streamingAgent() {
  const response = await query({
    prompt: "列出当前目录下所有 .js 文件",
    options: { maxTurns: 3 }
  });

  for await (const msg of response) {
    switch (msg.type) {
      case "system":
        console.log("🔧 系统初始化:", msg.subtype);
        break;
      case "assistant":
        console.log("🤖 Agent:", msg.message.content);
        break;
      case "user":
        console.log("👤 工具返回:", msg.message.content);
        break;
      case "result":
        console.log("✅ 完成:", msg.result);
        break;
    }
  }
}

三、工具系统设计

工具是 Agent 能力的核心。SDK 支持三种定义工具的方式

3.1 方式一:函数式工具(最简单)

javascript

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

const tools = [{
  name: "calculate",
  description: "执行数学计算",
  inputSchema: {
    type: "object",
    properties: {
      expression: { type: "string", description: "数学表达式,如 '2 + 3 * 4'" }
    },
    required: ["expression"]
  },
  handler: async (args) => {
    // 安全地计算表达式(生产环境建议用 math.js 等库)
    const result = eval(args.expression);
    return { result };
  }
}];

async function calculatorAgent() {
  const response = await query({
    prompt: "请计算 (15 + 27) * 3 的结果",
    options: { tools, maxTurns: 2 }
  });

  for await (const msg of response) {
    if (msg.type === "result") console.log(msg.result);
  }
}

3.2 方式二:MCP 服务器集成(生产级)

MCP (Model Context Protocol) 是连接外部工具的标准协议

javascript

import { query } from "@anthropic-ai/claude-agent-sdk";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

async function mcpAgent() {
  // 创建一个 MCP 客户端连接到本地服务器
  const transport = new StdioClientTransport({
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
  });
  
  const mcpClient = new Client({
    name: "my-agent-client",
    version: "1.0.0"
  });
  
  await mcpClient.connect(transport);
  
  // 获取 MCP 服务器提供的工具
  const { tools: mcpTools } = await mcpClient.listTools();
  
  const response = await query({
    prompt: "请在 /tmp 目录下创建一个名为 test.txt 的文件",
    options: {
      mcpClients: [mcpClient],  // 传入 MCP 客户端
      maxTurns: 3
    }
  });
  
  for await (const msg of response) {
    if (msg.type === "result") console.log(msg.result);
  }
}

3.3 方式三:使用 Composio 快速接入工具生态

Composio 提供了 850+ 应用的 MCP 服务器,无需自己搭建

bash

# 通过 Rube 添加 MCP 服务器
claude mcp add composio --transport http \
  "https://mcp.composio.dev/sse?apiKey=YOUR_API_KEY"

javascript

// 然后在代码中直接使用
import { query } from "@anthropic-ai/claude-agent-sdk";

async function composioAgent() {
  const response = await query({
    prompt: "从我的 GitHub 仓库列表中找到最近更新的项目",
    options: {
      // MCP 服务器已在 Claude Code 配置中注册,会自动加载
      maxTurns: 5
    }
  });
  
  for await (const msg of response) {
    if (msg.type === "result") console.log(msg.result);
  }
}

四、权限与安全机制

生产环境必须控制 Agent 的权限

4.1 权限模式

javascript

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

async function secureAgent() {
  const response = await query({
    prompt: "删除 node_modules 文件夹",
    options: {
      permissionMode: "ask",  // 每次操作都需要确认
      // 可选值:
      // - "default": 默认行为,危险操作需确认
      // - "acceptEdits": 自动接受文件编辑,适合开发环境
      // - "bypassPermissions": 完全跳过权限检查(危险!)
      maxTurns: 3
    }
  });
  
  for await (const msg of response) {
    if (msg.type === "permission_request") {
      console.log("⚠️ 需要权限:", msg);
      // 在这里可以实现审批逻辑
    }
    if (msg.type === "result") console.log(msg.result);
  }
}

4.2 细粒度权限控制

javascript

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

const permissions = {
  // 文件操作:只允许 src 目录
  canRead: (path) => path.startsWith('./src'),
  canWrite: (path) => path.startsWith('./src'),
  
  // Bash 命令:黑名单
  canRun: (command) => {
    const blocked = ['rm -rf', 'sudo', 'curl'];
    return !blocked.some(b => command.includes(b));
  },
  
  // 网络:只允许特定域名
  canFetch: (url) => url.includes('api.github.com')
};

async function fineGrainedAgent() {
  const response = await query({
    prompt: "读取 src/index.js 并统计代码行数",
    options: {
      canUseTool: async (toolName, input) => {
        if (toolName === "Read" && !permissions.canRead(input.file_path)) {
          return false;  // 拒绝读取
        }
        if (toolName === "Bash" && !permissions.canRun(input.command)) {
          return false;  // 拒绝执行危险命令
        }
        return true;  // 允许
      },
      permissionMode: "acceptEdits"
    }
  });
  
  for await (const msg of response) {
    if (msg.type === "result") console.log(msg.result);
  }
}

五、多代理协作架构

5.1 使用 Sub-Agents 并行处理

Claude Code 支持启动子 Agent 并行执行任务

javascript

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

async function parallelAgents() {
  // 主 Agent 负责分发任务
  const response = await query({
    prompt: `
      请同时启动多个子 Agent,分别分析以下文件:
      1. package.json
      2. README.md
      3. src/index.js
      
      每个子 Agent 应该专注于一个文件,然后汇总结果。
      使用 sub-agents 来并行完成。
    `,
    options: {
      maxTurns: 10,
      // 启用子 Agent 模式
      settingSources: ["project"]
    }
  });
  
  for await (const msg of response) {
    if (msg.type === "subagent_start") {
      console.log(`🚀 启动子 Agent: ${msg.agentName}`);
    }
    if (msg.type === "subagent_result") {
      console.log(`📋 子 Agent ${msg.agentName} 完成:`, msg.result);
    }
    if (msg.type === "result") {
      console.log("🎯 最终汇总:", msg.result);
    }
  }
}

5.2 使用 clnode 实现 Agent 间通信

开源项目 clnode 解决了 Claude Code 子 Agent 之间无法直接通信的问题

bash

# 安装 clnode
npx clnode init .

# 启动 Web UI 监控
npx clnode start

它会自动创建共享内存层,让不同 Agent 之间可以交换信息。

六、上下文管理的实战方案

6.1 使用 CLAUDE.md 持久化上下文

在项目根目录创建 CLAUDE.md,Claude Code 每次启动都会自动读取

markdown

# 项目上下文

## 技术栈
- Node.js 22+
- TypeScript 5.0+
- Express.js

## 常用命令
- 开发: npm run dev
- 测试: npm test
- 构建: npm run build

## 代码规范
- 使用 ESLint + Prettier
- 提交格式: feat|fix|docs(scope): message

## 关键文件位置
- 入口: src/index.ts
- 路由: src/routes/
- 工具函数: src/utils/

6.2 动态上下文注入

javascript

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

async function contextAwareAgent() {
  // 动态读取项目信息作为上下文
  const packageJson = JSON.parse(await fs.readFile('package.json', 'utf-8'));
  const readme = await fs.readFile('README.md', 'utf-8').catch(() => '');
  
  const response = await query({
    prompt: `
      基于以下项目信息,帮我添加一个新的 API 端点:
      
      ## 项目信息
      - 项目名: ${packageJson.name}
      - 框架: ${packageJson.dependencies?.express ? 'Express' : '未知'}
      
      ## 项目说明
      ${readme.slice(0, 1000)}
      
      ## 任务
      添加一个 GET /health 端点,返回服务状态
    `,
    options: {
      maxTurns: 5,
      permissionMode: "acceptEdits"
    }
  });
  
  for await (const msg of response) {
    if (msg.type === "result") console.log(msg.result);
  }
}

6.3 会话持久化与恢复

javascript

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

async function persistentSession() {
  let sessionId = null;
  
  // 第一轮对话
  const response1 = await query({
    prompt: "分析当前项目的代码结构",
    options: { maxTurns: 3 }
  });
  
  for await (const msg of response1) {
    if (msg.type === "system" && msg.subtype === "init") {
      sessionId = msg.session_id;  // 保存会话 ID
    }
    if (msg.type === "result") {
      console.log("第一轮结果:", msg.result);
    }
  }
  
  // 使用相同的 session_id 继续对话
  const response2 = await query({
    prompt: "基于刚才的分析,建议如何进行重构?",
    options: {
      resumeSessionId: sessionId,  // 恢复之前的会话
      maxTurns: 5
    }
  });
  
  for await (const msg of response2) {
    if (msg.type === "result") console.log("第二轮结果:", msg.result);
  }
}

七、完整实战:代码审查 Agent

把上面的知识整合起来,实现一个生产级的代码审查 Agent:

javascript

import { query } from "@anthropic-ai/claude-agent-sdk";
import { exec } from 'child_process';
import { promisify } from 'util';
import fs from 'fs/promises';

const execAsync = promisify(exec);

// 定义审查工具
const reviewTools = [{
  name: "run_linter",
  description: "运行 ESLint 检查代码规范",
  inputSchema: { type: "object", properties: {}, required: [] },
  handler: async () => {
    try {
      const { stdout } = await execAsync('npx eslint . --format json');
      return JSON.parse(stdout);
    } catch (error) {
      return { errors: error.stdout ? JSON.parse(error.stdout) : [] };
    }
  }
}, {
  name: "run_tests",
  description: "运行单元测试",
  inputSchema: { type: "object", properties: {}, required: [] },
  handler: async () => {
    const { stdout } = await execAsync('npm test -- --json --outputFile=test-results.json');
    const results = JSON.parse(await fs.readFile('test-results.json', 'utf-8'));
    return { passed: results.numPassedTests, failed: results.numFailedTests };
  }
}];

async function codeReviewAgent() {
  const response = await query({
    prompt: `
      请对当前代码仓库进行完整审查:
      
      1. 运行 linter 检查代码规范问题
      2. 运行测试套件
      3. 分析 src/ 目录下的代码质量
      4. 生成一份包含以下内容的审查报告:
         - 代码规范问题汇总
         - 测试覆盖率评估
         - 潜在的性能问题
         - 改进建议
    `,
    options: {
      tools: reviewTools,
      maxTurns: 10,
      permissionMode: "acceptEdits"
    }
  });
  
  for await (const msg of response) {
    switch (msg.type) {
      case "assistant":
        console.log("🔍 审查中:", msg.message.content);
        break;
      case "tool_call":
        console.log(`🛠️ 调用工具: ${msg.name}`);
        break;
      case "result":
        // 保存审查报告
        await fs.writeFile('review-report.md', msg.result);
        console.log("✅ 审查完成,报告已保存到 review-report.md");
        break;
    }
  }
}

codeReviewAgent();

八、学习路线总结

阶段目标代码量时间
1跑通最简示例10 行30 分钟
2理解流式响应和工具系统50 行2 小时
3实现自定义工具100 行半天
4集成 MCP 服务器150 行1 天
5构建多 Agent 协作300+ 行3 天

下一步建议

  1. 先把最简示例跑通,确认环境正常
  2. 修改 prompt,让它做你真正想做的事情
  3. 加一个自定义工具(比如读取特定配置文件)
  4. 尝试用 Composio 快速接入 GitHub/Gmail 等工具

如果你愿意,可以告诉我你想用 Agent 具体做什么,我帮你写一个可以直接运行的完整代码。