pimenov.ai

База знаний

Anthropic SDK и Claude Agent SDK

Anthropic SDK для Python и TypeScript и Claude Agent SDK: Messages API, tool use, structured outputs, MCP, prompt caching, батчи и обработка ошибок. Практические рецепты для агентов.

Опубликовано Обновлено

Anthropic SDK — официальные библиотеки для работы с моделями Claude через API. Python и TypeScript SDK покрывают весь спектр: от простого вызова Messages API до построения агентов с инструментами, MCP-серверами и постоянной памятью. А Claude Agent SDK — отдельный продукт: обёртка над Claude Code для автономных агентов, работающих с файлами и терминалом.

📌
Для кого: разработчики, которые интегрируют Claude в свои продукты или строят ИИ-агентов. Базовое знание Python или TypeScript и понимание REST API достаточно для старта, но для продвинутых сценариев (tool use, MCP, агенты) потребуется больше.

Что входит в Anthropic SDK

Не путайте три вещи — они дополняют друг друга, но решают разные задачи:

ПакетЧто делаетКогда нужен
anthropic (Python / TS)Клиент для Messages API: генерация, стриминг, tool use, structured outputs, батчиЛюбая интеграция с Claude
anthropic[mcp] (Python extra)Клиентские MCP-хелперы (anthropic.lib.tools.mcp) для локальных серверов, resources и promptsКогда нужен локальный MCP-сервер или больше контроля, чем даёт connector
claude-agent-sdk / @anthropic-ai/claude-agent-sdkОбёртка над Claude Code: агентный цикл, инструменты (Read/Write/Bash и др.), управление контекстом и правамиАвтономные кодинг- и файловые агенты

Установка и авторизация

Python

pip install anthropic
# Клиентские MCP-хелперы (локальные серверы, resources, prompts):
pip install 'anthropic[mcp]'

TypeScript

npm install @anthropic-ai/sdk

API-ключ

Ключ получаете на console.anthropic.com. Передаётся через переменную окружения или напрямую в конструктор:

export ANTHROPIC_API_KEY=sk-ant-...
from anthropic import Anthropic

# Автоматически берёт ключ из ANTHROPIC_API_KEY
client = Anthropic()

# Или явно:
client = Anthropic(api_key="sk-ant-...")
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();
// Или: new Anthropic({ apiKey: 'sk-ant-...' })
⚠️
Безопасность: никогда не храните API-ключ в коде репозитория. Используйте переменные окружения, менеджер секретов (Vault, AWS Secrets Manager) или .env-файл, добавленный в .gitignore.

Messages API: базовый вызов

Messages API — основной интерфейс для общения с Claude. Один вызов = один запрос с историей сообщений и ответ.

from anthropic import Anthropic

client = Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system="Ты — технический ассистент. Отвечай кратко и по делу.",
    messages=[
        {"role": "user", "content": "Объясни разницу между REST и GraphQL"}
    ]
)

print(response.content[0].text)

Стриминг

Для интерактивных интерфейсов используйте стриминг — ответ приходит по частям:

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Напиши план архитектуры API"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Мультимодальность

Claude принимает изображения, PDF и другие файлы как часть сообщения:

import base64

with open("diagram.png", "rb") as f:
    image_data = base64.standard_b64encode(f.read()).decode()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": [
            {"type": "image", "source": {
                "type": "base64",
                "media_type": "image/png",
                "data": image_data
            }},
            {"type": "text", "text": "Что изображено на этой диаграмме?"}
        ]
    }]
)
💡
Совет: для PDF используйте type: "document" с source.type: "base64" и media_type: "application/pdf". Claude извлекает текст и анализирует содержимое без дополнительных библиотек.

Практические лимиты: PDF должен быть стандартным, без пароля и шифрования. Максимальный размер запроса — 32 MB, максимум страниц — 600 (для моделей с контекстом 200k — 100 страниц). Большие PDF лучше загружать через Files API и передавать в запрос file_id, чтобы не раздувать payload.


Tool use (Function calling)

Tool use позволяет Claude вызывать ваши функции — искать в базе, делать HTTP-запросы, управлять инфраструктурой. Это основа для построения агентов.

Определение инструментов

tools = [{
    "name": "search_knowledge_base",
    "description": "Поиск по внутренней базе знаний компании",
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Поисковый запрос"
            },
            "limit": {
                "type": "integer",
                "description": "Максимальное количество результатов",
                "default": 5
            }
        },
        "required": ["query"]
    }
}]

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "Найди нашу политику отпусков"}]
)

Цикл вызова инструментов

Claude возвращает tool_use блок с именем функции и параметрами. Вы выполняете функцию и возвращаете результат:

import json

def handle_tool_calls(response):
    """Возвращает assistant-сообщение и все tool_result-сообщения."""
    tool_results = []

    # Важно: assistant-сообщение добавляем один раз,
    # даже если Claude запросил несколько инструментов за ход.
    messages = [{
        "role": "assistant",
        "content": response.content
    }]

    for block in response.content:
        if block.type == "tool_use":
            result = execute_function(block.name, block.input)
            tool_results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": json.dumps(result)
            })

    if tool_results:
        messages.append({
            "role": "user",
            "content": tool_results
        })

    return messages

# Агентный цикл: повторяем, пока Claude не перестанет вызывать инструменты
max_iterations = 10
iterations = 0

while response.stop_reason == "tool_use" and iterations < max_iterations:
    all_messages.extend(handle_tool_calls(response))
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        tools=tools,
        messages=all_messages
    )
    iterations += 1
📌
Ключевая мысль: tool use — это не просто «вызов функций». Это паттерн, при котором модель сама решает, какой инструмент вызвать и с какими параметрами, на основе контекста разговора. Описание инструмента в description критически важно для качества выбора.

Structured outputs

Когда нужно получить от Claude структурированный ответ (JSON с определённой схемой), используйте tool use как «форму ответа». Инструмент при этом может ничего не выполнять — он просто описывает структуру данных, которую Claude должен вернуть.

Через tool use (рекомендуется)

Определите «инструмент», который на самом деле описывает схему ответа:

tools = [{
    "name": "extract_entities",
    "description": "Извлечь сущности из текста и вернуть строго структурированный JSON",
    "input_schema": {
        "type": "object",
        "properties": {
            "persons": {"type": "array", "items": {"type": "string"}},
            "companies": {"type": "array", "items": {"type": "string"}},
            "dates": {"type": "array", "items": {"type": "string"}}
        },
        "required": ["persons", "companies", "dates"]
    },
    "strict": True
}]

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "tool", "name": "extract_entities"},
    messages=[{"role": "user", "content": text_to_analyze}]
)

# Результат — аргументы вызванного инструмента
entities = response.content[0].input

tool_choice заставляет Claude вызвать конкретный инструмент. Если нужно максимально строгое соответствие схеме, добавляйте strict: true в определение инструмента. Это снижает риск «почти JSON», лишних полей или не того типа данных.


Prompt caching

Если в каждый запрос уходит большой неизменный блок — системный промпт, документация, схема инструментов, RAG-документы, длинная история диалога — его можно кэшировать. Claude не пересчитывает закэшированный префикс, а берёт готовый: это дешевле и быстрее.

По умолчанию кэш живёт 5 минут и бесплатно продлевается при каждом попадании. Если 5 минут мало, можно включить 1-hour cache через ttl: "1h", но запись такого кэша стоит дороже. Сейчас поддерживается тип кэша ephemeral.

Явный cache breakpoint

Кэш можно включить меткой cache_control на нужном блоке:

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "<большой постоянный контекст: инструкции, справочник, схемы данных>",
            "cache_control": {"type": "ephemeral"},
        }
    ],
    messages=[{"role": "user", "content": "Вопрос по этому контексту"}],
)

# usage показывает, сколько токенов записано в кэш и прочитано из него
print(response.usage.cache_creation_input_tokens)
print(response.usage.cache_read_input_tokens)

Automatic caching

Если не хочется вручную расставлять breakpoints, можно включить автоматическое кэширование на уровне запроса:

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    cache_control={"type": "ephemeral"},
    system="Ты — ассистент, который работает с большим повторяющимся контекстом.",
    messages=[
        {"role": "user", "content": "Первый вопрос"},
        {"role": "assistant", "content": "Ответ"},
        {"role": "user", "content": "Следующий вопрос"}
    ],
)

Автоматический режим сам ставит cache breakpoint на последний кэшируемый блок и двигает его вперёд по мере роста диалога.

💡
Когда окупается: длинный системный промпт, набор инструментов, большой RAG-контекст, повторяющаяся документация или пакетная обработка по одному шаблону. На коротких разовых запросах смысла нет: у кэша есть минимальная длина префикса. Если cache_creation_input_tokens и cache_read_input_tokens равны нулю, значит запрос не был закэширован — часто потому, что префикс слишком короткий.

Батчевая обработка (Message Batches)

Когда ответы не нужны в реальном времени — массовая суммаризация, рерайт, перевод, разметка, извлечение данных — используйте Message Batches API. Запросы обрабатываются асинхронно, а токены стоят на 50% дешевле стандартного Messages API.

Один batch ограничен 100 000 запросов или 256 MB — что наступит раньше. Большинство batch-задач завершается меньше чем за час, но техническое окно обработки — до 24 часов. Если batch не успел обработаться за 24 часа, необработанные запросы получают статус expired. Результаты доступны 29 дней после создания batch.

batch = client.messages.batches.create(
    requests=[
        {
            "custom_id": "post-1",
            "params": {
                "model": "claude-sonnet-4-6",
                "max_tokens": 1024,
                "messages": [{"role": "user", "content": "Суммаризируй текст..."}],
            },
        },
        # ... до 100 000 запросов в одном батче
    ]
)
print(batch.id, batch.processing_status)

# Когда батч завершится — забираем результаты по custom_id
for entry in client.messages.batches.results(batch.id):
    print(entry.custom_id, entry.result)
📌
Ключевая мысль: custom_id — ваш способ сопоставить ответ с исходной задачей. Результаты приходят без гарантии порядка, поэтому без custom_id их не разложить обратно.

Перед большим batch сначала прогоните один обычный Messages API-запрос с той же структурой. Так вы поймаете ошибки схемы до того, как отправите тысячи задач в очередь.


Обработка ошибок и ретраи

Сеть моргает, прилетают лимиты (429), конфликты (409), таймауты и серверные ошибки. SDK уже умеет ретраить часть таких случаев с экспоненциальной задержкой.

По умолчанию Anthropic SDK делает 2 ретрая для connection errors, 408, 409, 429 и 500+. Это можно настроить через max_retries. Таймаут по умолчанию — 10 минут, но для интерактивных продуктов обычно лучше поставить короче и использовать стриминг.

import anthropic

# Глобально: число ретраев и таймаут
client = anthropic.Anthropic(max_retries=5, timeout=30.0)

try:
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Привет"}],
    )
except anthropic.RateLimitError:
    # 429 — превышен лимит или acceleration limit, повторить позже
    ...
except anthropic.APIStatusError as e:
    # Прочие ошибки API: есть код и тело ответа
    print(e.status_code, e.response)
except anthropic.APIConnectionError:
    # Проблема с сетью или соединением
    ...
⚠️
Не глушите ошибки молча. Всё, что долетело до except, — это уже исчерпанные попытки. Логируйте status_code, тип ошибки и тело ответа.

Отдельно обрабатывайте 529 overloaded_error: это временная перегрузка API. Обычно здесь нужен backoff, fallback на другую модель или постановка задачи в очередь.


MCP (Model Context Protocol)

MCP — открытый протокол для подключения внешних инструментов и источников данных к моделям (файлы, GitHub, Notion, Slack, PostgreSQL и десятки других). С Claude его подключают двумя способами.

Актуальная версия MCP connector требует beta-заголовок mcp-client-2025-11-20. Старый формат mcp-client-2025-04-04 и конфигурация инструментов внутри mcp_servers.tool_configuration считаются устаревшими. Сейчас сервер описывается в mcp_servers, а доступные инструменты включаются отдельно через tools: [{ "type": "mcp_toolset", ... }].

Способ 1. MCP connector — прямо из Messages API

Самый простой путь: подключиться к удалённому MCP-серверу по URL без отдельного MCP-клиента. Серверы перечисляются в mcp_servers, а какие инструменты включить — в tools через объект mcp_toolset. Нужен beta-заголовок.

import anthropic
client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Какие инструменты тебе доступны?"}],
    mcp_servers=[
        {
            "type": "url",
            "url": "https://example-server.modelcontextprotocol.io/sse",
            "name": "example-mcp",
            "authorization_token": "YOUR_OAUTH_TOKEN",  # если сервер требует авторизацию
        }
    ],
    tools=[{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}],
    betas=["mcp-client-2025-11-20"],
)
⚠️
Connector работает только с удалёнными серверами по https и видит только инструменты — resources и prompts не поддерживаются. Beta-заголовок версионируется (mcp-client-2025-11-20 сменил устаревший mcp-client-2025-04-04), держите его в конфиге, а не зашитым в код.

Способ 2. Клиентские MCP-хелперы

Когда нужен локальный сервер (stdio), а также resources и prompts или больше контроля над соединением — берите клиентские хелперы. В Python это anthropic.lib.tools.mcp из pip install anthropic[mcp], в TypeScript — @anthropic-ai/sdk/helpers/beta/mcp вместе с toolRunner.

КритерийMCP connectorКлиентские хелперы
Где живёт серверУдалённый, по httpsЛокальный (stdio) или удалённый
Что доступноТолько инструментыИнструменты, resources, prompts
СложностьОдин вызов APIСвой MCP-клиент в коде
⚖️
Trade-off: MCP убирает кастомные интеграции под каждый сервис, но добавляет зависимость от стороннего сервера. Для критичных продакшен-сценариев проверяйте надёжность сервера и держите fallback на прямые вызовы инструментов.

Claude Agent SDK

Это отдельный продукт, не путать с пакетом anthropic. Claude Agent SDK (раньше — Claude Code SDK) — обёртка над Claude Code: он даёт тот же агентный цикл, набор встроенных инструментов (Read, Write, Edit, Bash, веб-поиск) и управление контекстом и правами, что и Claude Code, но программно. CLI Claude Code бандлится прямо в пакет.

Установка:

# Python (требуется Python 3.10+)
pip install claude-agent-sdk

# TypeScript
npm install @anthropic-ai/claude-agent-sdk

Точка входа — асинхронный генератор query(prompt, options), который стримит сообщения агента:

import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock

async def main():
    options = ClaudeAgentOptions(
        system_prompt="Ты — аккуратный инженер. Чини баг минимальными правками.",
        allowed_tools=["Read", "Edit", "Bash"],  # авто-одобрение этих инструментов
        permission_mode="acceptEdits",            # автопринятие правок файлов
    )
    async for message in query(prompt="Найди и почини баг в auth.py", options=options):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)

anyio.run(main)

Для интерактивных диалогов и собственных инструментов есть ClaudeSDKClient. Кастомный инструмент — это Python-функция с декоратором @tool, собранная в in-process MCP-сервер через create_sdk_mcp_server:

from claude_agent_sdk import tool, create_sdk_mcp_server, ClaudeAgentOptions, ClaudeSDKClient

@tool("greet", "Поприветствовать пользователя", {"name": str})
async def greet(args):
    return {"content": [{"type": "text", "text": f"Привет, {args['name']}!"}]}

server = create_sdk_mcp_server(name="my-tools", version="1.0.0", tools=[greet])

options = ClaudeAgentOptions(
    mcp_servers={"tools": server},
    allowed_tools=["mcp__tools__greet"],  # имя инструмента: mcp__<сервер>__<тул>
)
📌
Когда что брать: Messages API + tool use — когда нужен свой цикл и полный контроль над логикой. Claude Agent SDK — когда нужен автономный агент, работающий с файлами и терминалом (правки кода, запуск команд, разбор репозитория). Это не универсальный оркестратор «агентов поддержки», он заточен под среду Claude Code.

Важная деталь: allowed_tools в Agent SDK — это авто-одобрение инструментов, а не жёсткое ограничение. Если нужно запретить опасные действия, используйте disallowed_tools, permission_mode, sandbox и собственные permission callbacks.


Практический пример: Telegram-бот + Notion

Связка Claude + Telegram + Notion через SDK — рабочий паттерн для персонального ассистента:

from anthropic import Anthropic
from telegram import Update
from telegram.ext import Application, MessageHandler, filters
import notion_client

client = Anthropic()
notion = notion_client.Client(auth="ntn_...")

tools = [
    {
        "name": "search_notion",
        "description": "Поиск по базе знаний в Notion",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"}
            },
            "required": ["query"]
        }
    },
    {
        "name": "create_notion_page",
        "description": "Создать страницу в Notion",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "content": {"type": "string"}
            },
            "required": ["title", "content"]
        }
    }
]

async def handle_message(update: Update, context):
    user_message = update.message.text
    
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        tools=tools,
        messages=[{"role": "user", "content": user_message}]
    )
    
    # Обрабатываем tool calls...
    await update.message.reply_text(final_response)

Этот скелет расширяется: добавляете историю сообщений для контекста, обработку ошибок, rate limiting и новые инструменты.


Сценарии применения

  • RAG-системы. Messages API + tool use для поиска по базе знаний и генерации ответов с источниками.
  • Извлечение данных. Structured outputs для парсинга документов, извлечения сущностей и классификации.
  • Агенты поддержки. Messages API + tool use: поиск в базе, создание тикетов и передача оператору в собственном агентном цикле.
  • Контент-пайплайны. Батчевый API для массовой обработки: суммаризация, рерайт, перевод.
  • Персональные ассистенты. Telegram/Slack-боты с инструментами для Notion, календаря и почты через MCP.

Антипаттерны

  • Не использовать стриминг в интерактивных сценариях. Пользователь ждёт 10–30 секунд без обратной связи — плохой UX.
  • Описывать инструменты без подробных descriptions. Claude выбирает инструмент по описанию. Пустое описание = случайный выбор.
  • Передавать весь контекст в каждом запросе. Токены стоят денег. Суммаризируйте длинную историю, используйте prompt caching.
  • Игнорировать ошибки API. Rate limit (429), серверные ошибки (500) — обрабатывайте с экспоненциальным backoff. SDK делает это автоматически для стандартных случаев.
  • Путать Messages API и Claude Agent SDK. Messages API — когда нужен свой цикл и полный контроль. Claude Agent SDK — это обёртка над Claude Code для автономных агентов с доступом к файлам и терминалу, а не универсальный оркестратор.
  • Хардкодить имя модели. Anthropic регулярно обновляет и выводит модели из эксплуатации. Вынесите имя в конфиг или переменную окружения, чтобы заменить модель без правок по всему коду.

Чеклист интеграции

Установлен SDK (pip install anthropic или npm install @anthropic-ai/sdk)
API-ключ хранится в переменной окружения, не в коде
Выбрана актуальная модель под задачу: Haiku для массовых задач, Sonnet для баланса, Opus для сложных
Имя модели вынесено в конфиг, а не зашито в код
Настроен стриминг для интерактивных интерфейсов
Инструменты описаны с подробными descriptions и примерами
Для structured outputs используется tool_choice, а при строгих схемах — strict: true
Реализована обработка ошибок, ретраи, backoff для 429 и 529
Для агентных сценариев: определён максимальный цикл вызовов (защита от бесконечных loops)
Для Claude Agent SDK: allowed_tools не считается security boundary; опасные действия закрыты через disallowed_tools, permissions и sandbox
Для MCP: используется актуальный beta-заголовок mcp-client-2025-11-20
Для MCP: проверена надёжность MCP-серверов и есть fallback
Для Batch API: учтены лимиты 100 000 запросов / 256 MB / 24 часа
Для PDF: учтены лимиты 32 MB, 600 страниц и отсутствие пароля
Настроено логирование запросов и ответов для отладки
Prompt caching включён для повторяющихся системных промптов, инструментов или RAG-контекста

Полезные ссылки


По теме

Если строите продукт на Claude и хотите разобраться с архитектурой агентов или выбором между Messages API и Claude Agent SDK — пишите в Telegram @pimenov