Команда AI for Devs подготовила перевод подробного практического гайда по Claude Agent SDK. В статье разбирается, как устроены современные AI-агенты на практике: управление контекстом, инструменты, сабагенты, разрешения, структурированный вывод и продакшен-паттерны.
Если вы пользовались Claude Code, вы уже видели, на что на самом деле способен AI-агент: читать файлы, выполнять команды, редактировать код, самостоятельно определять шаги для выполнения задачи.
И вы знаете, что он не просто помогает писать код — он берёт ответственность за проблему и последовательно решает её так, как это сделал бы вдумчивый инженер.
Claude Agent SDK — это тот же самый движок, но теперь вы можете направить его на любую задачу по своему выбору и без лишних усилий создавать собственных агентов.
Это инфраструктура, лежащая в основе Claude Code, вынесенная в виде библиотеки. Вы получаете агентный цикл, встроенные инструменты, управление контекстом — по сути, всё то, что иначе пришлось бы реализовывать самостоятельно.
В этом руководстве мы с нуля создадим агента для код-ревью. В итоге у вас получится инструмент, который умеет анализировать кодовую базу, находить баги и проблемы безопасности и возвращать структурированную обратную связь.
Но что ещё важнее — вы разберётесь, как работает SDK, и сможете собрать именно того агента, который нужен вам на практике.
Наш агент для код-ревью будет уметь:
Анализировать кодовую базу на наличие багов и проблем безопасности;
Автономно читать файлы и искать по коду;
Предоставлять структурированную, практичную обратную связь;
Отслеживать собственный прогресс в процессе работы.
Runtime — Claude Code CLI
SDK — @anthropic-ai/claude-agent-sdk
Язык — TypeScript
Модель — Claude Opus 4.5
Если вы уже строили агентов на «сыром» API, то знаете этот паттерн: вызываете модель, проверяете, хочет ли она использовать инструмент, выполняете инструмент, передаёте результат обратно — и повторяете цикл до завершения задачи. При работе над чем-то более-менее сложным это быстро начинает утомлять.
SDK берёт этот цикл на себя:
// Without the SDK: You manage the loop 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, ... }); } // With the SDK: Claude manages it for await (const message of query({ prompt: "Fix the bug in auth.py" })) { console.log(message); // Claude reads files, finds bugs, edits code }
Кроме того, вы сразу получаете готовые инструменты:
Read — чтение любых файлов в рабочей директории
Write — создание новых файлов
Edit — точечное редактирование существующих файлов
Bash — выполнение команд в терминале
Glob — поиск файлов по шаблону
Grep — поиск по содержимому файлов с помощью регулярных выражений
WebSearch — поиск в интернете
WebFetch — загрузка и парсинг веб-страниц
Ничего из этого не нужно реализовывать самостоятельно.
Установленный Node.js версии 18 или выше
API-ключ Anthropic (получить его можно здесь)
Agent SDK использует Claude Code в качестве среды выполнения:
npm install -g @anthropic-ai/claude-code
После установки запустите claude в терминале и следуйте подсказкам для аутентификации.
mkdir code-review-agent && cd code-review-agent npm init -y npm install @anthropic-ai/claude-agent-sdk npm install -D typescript @types/node tsx
export ANTHROPIC_API_KEY=your-api-key
Создайте файл 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();
Запустите его:
npx tsx agent.ts
Claude воспользуется инструментом Glob, чтобы получить список файлов, и сообщит, что ему удалось найти.
Функция query() возвращает асинхронный генератор, который стримит сообщения по мере работы Claude. Вот ключевые типы сообщений:
for await (const message of query({ prompt: "..." })) { switch (message.type) { case "system": // Session initialization info if (message.subtype === "init") { console.log("Session ID:", message.session_id); console.log("Available tools:", message.tools); } break; case "assistant": // Claude's responses and tool calls for (const block of message.message.content) { if ("text" in block) { console.log("Claude:", block.text); } else if ("name" in block) { console.log("Tool call:", block.name); } } break; case "result": // Final result console.log("Status:", message.subtype); // "success" or error type console.log("Cost:", message.total_cost_usd); break; } }
Теперь соберём что-то действительно полезное. Создайте файл 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", // Auto-approve read operations maxTurns: 250 } })) { // Show Claude's analysis as it happens 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}...`); } } } // Show completion status 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}`); } } } } // Review the current directory reviewCode(".");
Создайте файл с намеренно допущенными проблемами. Создайте example.ts:
function processUsers(users: any) { for (let i = 0; i <= users.length; i++) { // Off-by-one error console.log(users[i].name.toUpperCase()); // No null check } } function connectToDb(password: string) { const connectionString = `postgres://admin:${password}@localhost/db`; console.log("Connecting with:", connectionString); // Logging sensitive data } async function fetchData(url) { // Missing type annotation const response = await fetch(url); return response.json(); // No error handling }
Запустите ревью:
npx tsx review-agent.ts
Claude найдёт баги, проблемы безопасности и предложит варианты исправлений.
Для программного использования вам понадобится структурированный результат. SDK поддерживает вывод в формате JSON 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\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(".");
Обработка разрешений
По умолчанию SDK запрашивает подтверждение перед выполнением инструментов. Это поведение можно настроить.
Режимы разрешений
options: { // Standard mode - prompts for approval permissionMode: "default", // Auto-approve file edits permissionMode: "acceptEdits", // No prompts (use with caution) permissionMode: "bypassPermissions" }
Для более тонкого контроля используйте canUseTool:
options: { canUseTool: async (toolName, input) => { // Allow all read operations if (["Read", "Glob", "Grep"].includes(toolName)) { return { behavior: "allow", updatedInput: input }; } // Block writes to certain files if (toolName === "Write" && input.file_path?.includes(".env")) { return { behavior: "deny", message: "Cannot modify .env files" }; } // Allow everything else return { behavior: "allow", updatedInput: input }; } }
Создание сабагентов
Для сложных задач можно создавать специализированных сабагентов:
import { query, AgentDefinition } from "@anthropic-ai/claude-agent-sdk"; async function comprehensiveReview(directory: string) { for await (const message of query({ prompt: `Perform a comprehensive code review of ${directory}. Use the security-reviewer for security issues and test-analyzer for test coverage.`, options: { model: "opus", allowedTools: ["Read", "Glob", "Grep", "Task"], // Task enables subagents permissionMode: "bypassPermissions", maxTurns: 250, agents: { "security-reviewer": { description: "Security specialist for vulnerability detection", prompt: `You are a security expert. Focus on: - SQL injection, XSS, CSRF vulnerabilities - Exposed credentials and secrets - Insecure data handling - Authentication/authorization issues`, tools: ["Read", "Grep", "Glob"], model: "sonnet" } as AgentDefinition, "test-analyzer": { description: "Test coverage and quality analyzer", prompt: `You are a testing expert. Analyze: - Test coverage gaps - Missing edge cases - Test quality and reliability - Suggestions for additional tests`, tools: ["Read", "Grep", "Glob"], model: "haiku" // Use faster model for simpler analysis } as AgentDefinition } } })) { if (message.type === "assistant") { for (const block of message.message.content) { if ("text" in block) { console.log(block.text); } else if ("name" in block && block.name === "Task") { console.log(`\n🤖 Delegating to: ${(block.input as any).subagent_type}`); } } } } } comprehensiveReview(".");
Управление сессиями
Для многошаговых диалогов можно сохранять и возобновлять сессии:
import { query } from "@anthropic-ai/claude-agent-sdk"; async function interactiveReview() { let sessionId: string | undefined; // Initial review for await (const message of query({ prompt: "Review this codebase and identify the top 3 issues", options: { model: "opus", allowedTools: ["Read", "Glob", "Grep"], permissionMode: "bypassPermissions", maxTurns: 250 } })) { if (message.type === "system" && message.subtype === "init") { sessionId = message.session_id; } // ... handle messages } // Follow-up question using same session if (sessionId) { for await (const message of query({ prompt: "Now show me how to fix the most critical issue", options: { resume: sessionId, // Continue the conversation allowedTools: ["Read", "Glob", "Grep"], maxTurns: 250 } })) { // Claude remembers the previous context } } }
Использование хуков
Хуки позволяют перехватывать и настраивать поведение агента:
import { query, HookCallback, PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk"; const auditLogger: HookCallback = async (input, toolUseId, { signal }) => { if (input.hook_event_name === "PreToolUse") { const preInput = input as PreToolUseHookInput; console.log(`[AUDIT] ${new Date().toISOString()} - ${preInput.tool_name}`); } return {}; // Allow the operation }; const blockDangerousCommands: HookCallback = async (input, toolUseId, { signal }) => { if (input.hook_event_name === "PreToolUse") { const preInput = input as PreToolUseHookInput; if (preInput.tool_name === "Bash") { const command = (preInput.tool_input as any).command || ""; if (command.includes("rm -rf") || command.includes("sudo")) { return { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: "Dangerous command blocked" } }; } } } return {}; }; for await (const message of query({ prompt: "Clean up temporary files", options: { model: "opus", allowedTools: ["Bash", "Glob"], maxTurns: 250, hooks: { PreToolUse: [ { hooks: [auditLogger] }, { matcher: "Bash", hooks: [blockDangerousCommands] } ] } } })) { // ... }
Расширяйте возможности Claude с помощью собственных инструментов, используя Model Context Protocol:
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk"; import { z } from "zod"; // Create a custom tool const customServer = createSdkMcpServer({ name: "code-metrics", version: "1.0.0", tools: [ tool( "analyze_complexity", "Calculate cyclomatic complexity for a file", { filePath: z.string().describe("Path to the file to analyze") }, async (args) => { // Your complexity analysis logic here const complexity = Math.floor(Math.random() * 20) + 1; // Placeholder return { content: [{ type: "text", text: `Cyclomatic complexity for ${args.filePath}: ${complexity}` }] }; } ) ] }); // Use streaming input for MCP servers async function* generateMessages() { yield { type: "user" as const, message: { role: "user" as const, content: "Analyze the complexity of main.ts" } }; } for await (const message of query({ prompt: generateMessages(), options: { model: "opus", mcpServers: { "code-metrics": customServer }, allowedTools: ["Read", "mcp__code-metrics__analyze_complexity"], maxTurns: 250 } })) { // ... }
Отслеживание стоимости
Для биллинга можно отслеживать расходы на API:
for await (const message of query({ prompt: "..." })) { if (message.type === "result" && message.subtype === "success") { console.log("Total cost:", message.total_cost_usd); console.log("Token usage:", message.usage); // Per-model breakdown (useful with subagents) for (const [model, usage] of Object.entries(message.modelUsage)) { console.log(`${model}: $${usage.costUSD.toFixed(4)}`); } } }
Ниже — готовый к использованию агент, который объединяет всё рассмотренное ранее:
import { query, AgentDefinition } from "@anthropic-ai/claude-agent-sdk"; interface ReviewResult { issues: Array<{ severity: "low" | "medium" | "high" | "critical"; category: "bug" | "security" | "performance" | "style"; file: string; line?: number; description: string; suggestion?: string; }>; summary: string; overallScore: number; } 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 runCodeReview(directory: string): Promise<ReviewResult | null> { console.log(`\n${"=".repeat(50)}`); console.log(`🔍 Code Review Agent`); console.log(`📁 Directory: ${directory}`); console.log(`${"=".repeat(50)}\n`); let result: ReviewResult | null = null; for await (const message of query({ prompt: `Perform a thorough code review of ${directory}. Analyze all source files for: 1. Bugs and potential runtime errors 2. Security vulnerabilities 3. Performance issues 4. Code quality and maintainability Be specific with file paths and line numbers where possible.`, options: { model: "opus", allowedTools: ["Read", "Glob", "Grep", "Task"], permissionMode: "bypassPermissions", maxTurns: 250, outputFormat: { type: "json_schema", schema: reviewSchema }, agents: { "security-scanner": { description: "Deep security analysis for vulnerabilities", prompt: `You are a security expert. Scan for: - Injection vulnerabilities (SQL, XSS, command injection) - Authentication and authorization flaws - Sensitive data exposure - Insecure dependencies`, tools: ["Read", "Grep", "Glob"], model: "sonnet" } as AgentDefinition } } })) { // Progress updates if (message.type === "assistant") { for (const block of message.message.content) { if ("name" in block) { if (block.name === "Task") { console.log(`🤖 Delegating to: ${(block.input as any).subagent_type}`); } else { console.log(`📂 ${block.name}: ${getToolSummary(block)}`); } } } } // Final result if (message.type === "result") { if (message.subtype === "success" && message.structured_output) { result = message.structured_output as ReviewResult; console.log(`\n✅ Review complete! Cost: $${message.total_cost_usd.toFixed(4)}`); } else { console.log(`\n❌ Review failed: ${message.subtype}`); } } } return result; } function getToolSummary(block: any): string { const input = block.input || {}; switch (block.name) { case "Read": return input.file_path || "file"; case "Glob": return input.pattern || "pattern"; case "Grep": return `"${input.pattern}" in ${input.path || "."}`; default: return ""; } } function printResults(result: ReviewResult) { console.log(`\n${"=".repeat(50)}`); console.log(`📊 REVIEW RESULTS`); console.log(`${"=".repeat(50)}\n`); console.log(`Score: ${result.overallScore}/100`); console.log(`Issues Found: ${result.issues.length}\n`); console.log(`Summary: ${result.summary}\n`); const byCategory = { critical: result.issues.filter(i => i.severity === "critical"), high: result.issues.filter(i => i.severity === "high"), medium: result.issues.filter(i => i.severity === "medium"), low: result.issues.filter(i => i.severity === "low") }; for (const [severity, issues] of Object.entries(byCategory)) { if (issues.length === 0) continue; const icon = severity === "critical" ? "🔴" : severity === "high" ? "🟠" : severity === "medium" ? "🟡" : "🟢"; console.log(`\n${icon} ${severity.toUpperCase()} (${issues.length})`); console.log("-".repeat(30)); for (const issue of issues) { const location = issue.line ? `${issue.file}:${issue.line}` : issue.file; console.log(`\n[${issue.category}] ${location}`); console.log(` ${issue.description}`); if (issue.suggestion) { console.log(` 💡 ${issue.suggestion}`); } } } } // Run the review async function main() { const directory = process.argv[2] || "."; const result = await runCodeReview(directory); if (result) { printResults(result); } } main().catch(console.error);
Запуск:
npx tsx review-agent.ts ./src
Агент для код-ревью покрывает базовые вещи: query(), allowedTools, структурированный вывод, сабагенты и управление разрешениями.
Если хочется копнуть глубже, есть куда развиваться.
Дополнительные возможности
Чекпоинты файлов — отслеживание изменений файлов и откат к предыдущим версиям
Skills — упаковка переиспользуемых возможностей
Продакшен-развёртывание
Хостинг — развёртывание в контейнерах и CI/CD
Безопасное развёртывание — sandboxing и управление учётными данными
Полная справка
Reference по TypeScript SDK
Reference по Python SDK
Это руководство описывает версию SDK V1. Версия V2 сейчас находится в разработке.
Друзья! Эту статью подготовила команда ТГК «AI for Devs» — канала, где мы рассказываем про AI-ассистентов, плагины для IDE, делимся практическими кейсами и свежими новостями из мира ИИ. Подписывайтесь, чтобы быть в курсе и ничего не упустить!
Источник


