Команда AI for Devs подготовила перевод подробного практического гайда по Claude Agent SDK. В статье разбирается, как устроены современные AI-агенты на практике: управление контекстом, инструменты, сабагенты, разрешения, структурированный вывод и продакшен-паттерны.
Если вы пользовались Claude Code, вы уже видели, на что на самом деле способен AI-агент: читать файлы, выполнять команды, редактировать код, самостоятельно определять шаги для выполнения задачи.
И вы знаете, что он не просто помогает писать код — он берёт ответственность за проблему и последовательно решает её так, как это сделал бы вдумчивый инженер.
Claude Agent SDK — это тот же самый движок, но теперь вы можете направить его на любую задачу по своему выбору и без лишних усилий создавать собственных агентов.
Это инфраструктура, лежащая в основе Claude Code, вынесенная в виде библиотеки. Вы получаете агентный цикл, встроенные инструменты, управление контекстом — по сути, всё то, что иначе пришлось бы реализовывать самостоятельно.
В этом руководстве мы с нуля создадим агента для код-ревью. В итоге у вас получится инструмент, который умеет анализировать кодовую базу, находить баги и проблемы безопасности и возвращать структурированную обратную связь.
Но что ещё важнее — вы разберётесь, как работает SDK, и сможете собрать именно того агента, который нужен вам на практике.
Что мы будем делать
Наш агент для код-ревью будет уметь:
Анализировать кодовую базу на наличие багов и проблем безопасности;
Автономно читать файлы и искать по коду;
Предоставлять структурированную, практичную обратную связь;
Отслеживать собственный прогресс в процессе работы.
Стек
Runtime — Claude Code CLI
Язык — TypeScript
Модель — Claude Opus 4.5
Что даёт SDK
Если вы уже строили агентов на «сыром» 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 (получить его можно здесь)
Начало работы
Шаг 1: Установка Claude Code CLI
Agent SDK использует Claude Code в качестве среды выполнения:
npm install -g @anthropic-ai/claude-codeПосле установки запустите claude в терминале и следуйте подсказкам для аутентификации.
Шаг 2: Создание проекта
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Шаг 3: Установка API-ключа
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.tsClaude воспользуется инструментом 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.tsClaude найдёт баги, проблемы безопасности и предложит варианты исправлений.
Добавление структурированного вывода
Для программного использования вам понадобится структурированный результат. 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] }
]
}
}
})) {
// ...
}Добавление пользовательских инструментов с помощью MCP
Расширяйте возможности 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 и управление учётными данными
Полная справка
Это руководство описывает версию SDK V1. Версия V2 сейчас находится в разработке.
Русскоязычное сообщество про AI в разработке

Друзья! Эту статью подготовила команда ТГК «AI for Devs» — канала, где мы рассказываем про AI-ассистентов, плагины для IDE, делимся практическими кейсами и свежими новостями из мира ИИ. Подписывайтесь, чтобы быть в курсе и ничего не упустить!
