Создание AI-агента на Python и Claude API: туториал
Пошаговый туториал по созданию AI-агента с нуля на Python и Claude Agent SDK — от установки до рабочего агента с инструментами.
Зачем строить AI-агента вместо простого чат-бота
Чат-бот отвечает на вопрос и ждёт следующего. Агент — думает, планирует и действует самостоятельно: вызывает функции, обрабатывает результаты, уточняет данные и доводит задачу до конца без вашего участия.
Разница не в мощности модели, а в архитектуре: агент работает в цикле «наблюдение → мышление → действие», пока не достигнет цели или не исчерпает лимит шагов.
В апреле 2026 года Anthropic запустила Claude Agent SDK — официальный инструментарий для построения агентов на Python и TypeScript. Он даёт вам тот же механизм, на котором работает Claude Code, но полностью под вашим контролем. Именно его мы и разберём в этом туториале.
Агент — это не просто умный чат-бот. Это автономная программа, которая решает задачу, а не просто отвечает на вопрос.
Часть 1. Подготовка: модели, цены и настройка окружения
Выбор модели
Прежде чем писать код, выберите модель под задачу:
| Модель | Input ($/1M токенов) | Output ($/1M токенов) | Когда использовать |
|---|---|---|---|
| claude-haiku-4-5 | $1 | $5 | Быстрые задачи, высокий объём |
| claude-sonnet-4-6 | $3 | $15 | Балансирует скорость и качество |
| claude-opus-4-6 | $5 | $25 | Сложные многошаговые рассуждения |
Для прототипа агента оптимален claude-sonnet-4-6 — он умный и не разорит бюджет. Опус подключайте только если Sonnet не справляется с логикой задачи.
Установка
# Python 3.10+ обязателен
pip install anthropic claude-agent-sdk
# Создайте файл .env в корне проекта
ANTHROPIC_API_KEY=sk-ant-...
Ключ получите на console.anthropic.com. Никогда не кладите его в код напрямую — только через переменные окружения.
.env в git. Добавьте его в .gitignore прямо сейчас, до первого коммита.Часть 2. Архитектура агента: как устроен агентный цикл
Прежде чем писать код — разберитесь, что происходит под капотом.
graph TD
A[Задача пользователя] --> B[Агент: системный промпт + задача]
B --> C{Claude думает}
C -->|Нужен инструмент| D[Вызов tool]
D --> E[Инструмент выполняется]
E --> F[Результат → Claude]
F --> C
C -->|Ответ готов| G[Финальный ответ]
G --> H[Пользователь]
Ключевые элементы:
- Системный промпт — инструкции агента: кто он, что умеет, каким правилам следует.
- Инструменты (tools) — Python-функции, которые Claude может вызывать: поиск в сети, работа с файлами, запросы к API.
- Агентный цикл — бесконечный цикл, пока Claude не ответит без вызова инструментов.
- История сообщений — контекст всего разговора, который SDK ведёт за вас.
В отличие от сырого Anthropic Python SDK, где вам пришлось бы реализовывать этот цикл вручную, Claude Agent SDK берёт оркестрацию на себя.
Часть 3. Первый агент: минимальный рабочий пример
Создадим агента, который умеет искать информацию и считать математику.
import asyncio
import os
from dotenv import load_dotenv
from claude_agent_sdk import ClaudeSDKClient, tool
load_dotenv()
# Определяем инструменты — простые async-функции
@tool("calculate", "Вычисляет математическое выражение", {"expression": str})
async def calculate(args: dict) -> dict:
"""Безопасное вычисление арифметики."""
expression = args["expression"]
# Только цифры и базовые операторы — никакого eval с произвольным кодом
allowed = set("0123456789+-*/()., ")
if not all(c in allowed for c in expression):
return {"content": [{"type": "text", "text": "Недопустимые символы в выражении"}]}
try:
result = eval(expression) # noqa: S307 — проверено выше
return {"content": [{"type": "text", "text": str(result)}]}
except Exception as e:
return {"content": [{"type": "text", "text": f"Ошибка: {e}"}]}
@tool("get_current_date", "Возвращает текущую дату", {})
async def get_current_date(args: dict) -> dict:
from datetime import datetime
return {"content": [{"type": "text", "text": datetime.now().strftime("%Y-%m-%d")}]}
# Создаём клиент с системным промптом
client = ClaudeSDKClient(
model="claude-sonnet-4-6",
system_prompt="""Ты — умный ассистент с доступом к калькулятору и дате.
Когда нужно что-то посчитать — используй инструмент calculate.
Всегда отвечай на русском языке.""",
tools=[calculate, get_current_date],
)
async def main():
print("Агент запущен. Введите 'выход' для завершения.\n")
while True:
user_input = input("Вы: ").strip()
if user_input.lower() in ("выход", "exit", "quit"):
break
print("Агент: ", end="", flush=True)
async for message in client.query(user_input):
if message.type == "text":
print(message.text, end="", flush=True)
print() # Перевод строки после ответа
if __name__ == "__main__":
asyncio.run(main())
Запустите и попробуйте: «Посчитай 1337 * 42» или «Какой сегодня день?» — агент вызовет нужный инструмент и вернёт ответ.
asyncio). Это позволяет стримить ответы токен за токеном и параллельно вызывать несколько инструментов. Если ваше приложение синхронное — используйте asyncio.run() как точку входа.Часть 4. Реальный агент: работа с внешними API и файлами
Минимальный пример хорош для старта, но реальный агент обычно работает с внешними данными. Добавим инструменты для HTTP-запросов и работы с файлами.
import aiohttp
import aiofiles
from pathlib import Path
@tool(
"fetch_url",
"Загружает содержимое веб-страницы по URL",
{"url": str, "max_chars": int}
)
async def fetch_url(args: dict) -> dict:
url = args["url"]
max_chars = args.get("max_chars", 2000)
# Базовая защита от SSRF — блокируем внутренние адреса
if any(blocked in url for blocked in ["localhost", "127.0.0.1", "0.0.0.0", "169.254"]):
return {"content": [{"type": "text", "text": "Доступ к внутренним адресам запрещён"}]}
try:
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
text = await resp.text()
return {"content": [{"type": "text", "text": text[:max_chars]}]}
except Exception as e:
return {"content": [{"type": "text", "text": f"Ошибка загрузки: {e}"}]}
@tool(
"write_file",
"Сохраняет текст в файл (только в папке ./output/)",
{"filename": str, "content": str}
)
async def write_file(args: dict) -> dict:
# Ограничиваем запись только в безопасную директорию
output_dir = Path("./output")
output_dir.mkdir(exist_ok=True)
# Нормализуем путь и проверяем, что он внутри output/
target = (output_dir / args["filename"]).resolve()
if not str(target).startswith(str(output_dir.resolve())):
return {"content": [{"type": "text", "text": "Запись за пределами output/ запрещена"}]}
async with aiofiles.open(target, "w", encoding="utf-8") as f:
await f.write(args["content"])
return {"content": [{"type": "text", "text": f"Файл сохранён: {target}"}]}
resolve(), ограничивайте URL-запросы, не допускайте произвольного выполнения кода. Инструмент без валидации — уязвимость.Пример сессии с файловым агентом
Вы: Зайди на httpbin.org/json, извлеки данные и сохрани в файл result.json
Агент: [вызывает fetch_url → читает JSON → вызывает write_file]
Готово! Данные с httpbin.org/json сохранены в ./output/result.json
Часть 5. Архитектурные паттерны и масштабирование
Когда базовый агент работает, встают вопросы архитектуры. Вот проверенные паттерны:
Многоагентная система (оркестратор + исполнители)
# Оркестратор делегирует задачи специализированным агентам
orchestrator = ClaudeSDKClient(
model="claude-opus-4-6", # Сильная модель для планирования
system_prompt="Ты менеджер. Декомпозируй задачу и вызывай специализированных агентов.",
tools=[call_search_agent, call_writer_agent, call_analyst_agent],
)
# Исполнители используют более дешёвую модель
search_agent = ClaudeSDKClient(
model="claude-haiku-4-5", # Быстро и дёшево для поиска
system_prompt="Ты специалист по поиску информации.",
tools=[fetch_url, search_web],
)
Сравнение подходов к построению агентов
| Критерий | Сырой Anthropic SDK | Claude Agent SDK | Сторонние фреймворки |
|---|---|---|---|
| Контроль над циклом | Полный | Средний | Ограниченный |
| Скорость старта | Медленная | Быстрая | Быстрая |
| Debugging | Просто | Просто | Сложно |
| Инструменты | Своя реализация | Встроенные + кастомные | Зависит от фреймворка |
| Стабильность | Высокая | Высокая | Варьируется |
| Подходит для | Специфических задач | Большинства проектов | Быстрых прототипов |
Персистентность и долгосрочная память
Claude Agent SDK ведёт историю разговора внутри сессии, но не между запусками. Для долгосрочной памяти добавьте сохранение контекста:
import json
from pathlib import Path
def save_session(session_id: str, messages: list):
path = Path(f"./sessions/{session_id}.json")
path.parent.mkdir(exist_ok=True)
path.write_text(json.dumps(messages, ensure_ascii=False, indent=2))
def load_session(session_id: str) -> list:
path = Path(f"./sessions/{session_id}.json")
if path.exists():
return json.loads(path.read_text())
return []
# При инициализации клиента передайте историю
client = ClaudeSDKClient(
model="claude-sonnet-4-6",
system_prompt="...",
initial_messages=load_session("user_123"),
)
Заключение
Вы прошли путь от «что такое агент» до рабочего Python-кода с реальными инструментами. Ключевые выводы:
- Claude Agent SDK значительно упрощает построение агентов по сравнению с ручной реализацией агентного цикла.
- Безопасность инструментов — ваша ответственность. Валидируйте все входные данные, ограничивайте доступ к файловой системе и сети.
- Начинайте с claude-sonnet-4-6 — он покрывает 90% задач по разумной цене.
- Prompt caching может сократить расходы в 5–10 раз для агентов с длинными системными промптами.
- Многоагентные системы — следующий уровень: оркестратор на Opus, исполнители на Haiku.
Следующий шаг — добавьте реальные инструменты под вашу задачу: поиск по векторной базе (RAG), работу с почтой или интеграцию с вашим бизнес-API. Архитектура агента одинакова — меняются только инструменты.
Источники
- https://platform.claude.com/docs/en/agent-sdk/overview
- https://platform.claude.com/docs/en/agent-sdk/quickstart
- https://platform.claude.com/docs/en/agent-sdk/python
- https://platform.claude.com/docs/en/about-claude/models/overview
- https://platform.claude.com/docs/en/about-claude/pricing
- https://github.com/anthropics/claude-agent-sdk-python