Prog Academy
RU UA
Как создать своего первого AI-агента на Python: пошаговая инструкция для начинающих
Python

Как создать своего первого AI-агента на Python: пошаговая инструкция для начинающих

Ещё несколько лет назад AI в программировании ассоциировался с машинным обучением, математикой и дорогими серверами. Сегодня всё проще: большую языковую модель можно вызвать через API несколькими строками кода, а самое интересное начинается тогда, когда модель не только отвечает текстом, но и выполняет действия. Это и есть AI-агент.

В этой статье вы пошагово создадите своего первого AI-агента на Python — консольного помощника, который понимает запросы обычным языком («Добавь задачу подготовить домашнее задание по Python на завтра»), сам решает, какой инструмент вызвать, и ведёт список задач в файле. Без фреймворков и «магии»: около двухсот строк понятного кода, официальная библиотека anthropic и стандартные модули Python.

Почему именно Python? Это самый распространённый язык для работы с искусственным интеллектом: для него первыми выходят SDK провайдеров моделей, на нём пишут большинство AI-библиотек, а синтаксис достаточно прост, чтобы новичок читал код как текст. Для туториала хватит базовых навыков: запускать команды в терминале, понимать переменные, функции и словари. Если этих знаний пока нет, не страшно — код можно просто повторить, а в конце мы разберём, какие темы стоит изучить, чтобы писать таких агентов самостоятельно. Системно пройти этот путь от основ языка до собственных проектов можно на курсе Python Developer + AI от Prog Academy.

Коротко: что будет в статье

  • Что такое AI-агент и чем он отличается от чат-бота — простыми словами и на схеме.
  • Настройка Python, виртуального окружения и API-ключа для Windows, macOS и Linux.
  • Полный рабочий код агента с тремя инструментами, проверкой данных и обработкой ошибок.
  • Сценарии тестирования, частые ошибки новичков и способы улучшить агента.
  • Какие навыки Python нужны, чтобы создавать AI-агентов самостоятельно.

Что такое AI-агент?

AI-агент — это программа, в которой большая языковая модель (LLM) получает задачу, сама решает, какие действия выполнить, вызывает для этого инструменты и использует их результаты, чтобы прийти к ответу. Инструментом может быть любая функция в вашем коде: создать задачу, найти запись в базе, отправить запрос во внешний API.

AI-агент и обычный чат-бот

Обычный чат-бот работает по схеме «вопрос → ответ»: вы пишете сообщение, модель отвечает текстом, и на этом всё. Она может подсказать, как добавить задачу в список, но сама её не добавит. Агент отличается тремя вещами:

  • Инструменты. Программист описывает функции, которые модель может «попросить» вызвать, — с названием, описанием и параметрами.
  • Решение. Модель сама определяет, нужен ли инструмент, какой именно и с какими аргументами.
  • Цикл выполнения. Результат инструмента возвращается модели, и она решает, что делать дальше: вызвать ещё один инструмент или ответить пользователю.

LLM, инструменты и цикл выполнения

Важный момент, который часто путают новички: модель сама ничего не выполняет. Она возвращает структурированный ответ вроде «вызови функцию add_task с параметрами title и due_date». Выполняет функцию ваш Python-код, и именно он решает, разрешено ли это действие. Этот механизм называют function calling, или tool use.

1. Запрос«Добавь задачу подготовить домашку по Python на завтра»
2. LLM решаетНужен инструмент add_task с названием и датой
3. Python проверяетЕсть ли инструмент в белом списке? Корректны ли данные?
4. ИнструментФункция записывает задачу в tasks.json
5. Ответ«Готово, задача добавлена на завтра»

↺ Результат инструмента возвращается модели. Цикл повторяется, пока модель вызывает инструменты, — но не дольше установленного лимита шагов.

Как агент решает, какой инструмент использовать

Модель не «знает» ваш код. Она видит только три вещи: системную инструкцию (кто она и какие правила), описание инструментов (название, пояснение, JSON Schema параметров) и историю диалога. На этой основе она выбирает действие. Поэтому качество агента напрямую зависит от того, насколько понятно вы описали инструменты: размытое описание — случайные решения, чёткое описание — предсказуемое поведение. Подробно механизм описан в документации Anthropic о tool use.

Где применяют AI-агентов

  • Личные помощники — задачи, заметки, календарь, напоминания.
  • Поддержка клиентов — ответы по базе знаний и проверка статуса заказа через API.
  • Работа с данными — запросы к базе, отчёты, поиск аномалий.
  • Разработка — ассистенты, которые читают код, запускают тесты и предлагают исправления.
  • Автоматизация бизнес-процессов — обработка заявок, писем и документов. Как выбрать такой процесс и посчитать окупаемость, мы разобрали в статье «ИИ-агенты для бизнеса: внедрение и окупаемость».

Почему Python для AI-агентов?

Python для искусственного интеллекта — фактический стандарт, и для агентов это особенно заметно. Вот что делает его удобным именно для такой задачи:

  • Читаемый синтаксис. Логика агента — это условия, циклы и вызовы функций. На Python она читается почти как описание алгоритма, поэтому ошибку проще заметить.
  • Интеграция с API. Официальные SDK Anthropic, OpenAI, Google и других провайдеров появляются для Python одними из первых. Для любого другого сервиса есть httpx или requests.
  • AI-библиотеки. Фреймворки для агентов (LangGraph, LlamaIndex, Pydantic AI), инструменты для работы с векторными базами и машинного обучения в основном ориентированы на Python.
  • Обработка данных. Модули json и csv, библиотеки pandas и NumPy — всё, чтобы подготовить данные для агента и обработать его результаты. Подробнее — в статье «Python для анализа данных».
  • Автоматизация. Работа с файлами, запуск по расписанию, скрипты для рутинных задач — на Python это несколько строк.

Для новичка это означает плавную траекторию: те же знания, с которыми вы пишете первый скрипт для переименования файлов, со временем становятся основой для программ, которые вызывают языковые модели и действуют от имени пользователя. Между «Hello, world» и AI-агентом нет пропасти — есть последовательность навыков, которую можно пройти шаг за шагом.

Py

Хотите научиться программировать на Python с нуля и создавать собственные AI-проекты?

Ознакомьтесь с программой курса Python Developer + AI от Prog Academy.

Посмотреть программу курса

Что мы создадим: AI Task Assistant

Наш проект — AI Task Assistant, консольный помощник для списка задач. Он работает так:

  1. Получает запрос обычным языком — на русском, украинском или английском.
  2. Определяет намерение пользователя: добавить задачу, показать список или отметить задачу выполненной.
  3. Выбирает подходящий инструмент — одну из трёх Python-функций.
  4. Выполняет разрешённое действие: наш код проверяет данные и записывает изменения в файл tasks.json.
  5. Возвращает результат коротким сообщением.

Например, на запрос «Добавь задачу подготовить домашнее задание по Python на завтра» агент вызовет инструмент add_task, сам превратит «завтра» в конкретную дату в формате YYYY-MM-DD и подтвердит, что задача создана.

Сознательные ограничения проекта: агент не удаляет задачи, не имеет доступа к другим файлам и не может запускать команды операционной системы. Это не недостаток, а пример правильного подхода — давать агенту ровно те права, которые нужны для его задачи.

Что нужно перед началом

1. Python 3.10 или новее

Текущая версия библиотеки anthropic (ветка 1.x) требует Python 3.10+. Пример в статье проверен на Python 3.12 с anthropic 1.6.0. Рекомендуем ставить актуальную стабильную версию с python.org; статус поддержки каждой версии — на странице версий Python.

  • Windows: скачайте установщик с python.org и при установке отметьте пункт Add python.exe to PATH. Проверка: py --version.
  • macOS: установщик с python.org или brew install python, если у вас есть Homebrew. Проверка: python3 --version.
  • Linux (Ubuntu/Debian): sudo apt install python3 python3-venv python3-pip. Проверка: python3 --version.

2. Папка проекта и виртуальное окружение

Виртуальное окружение изолирует библиотеки проекта от системного Python, чтобы разные проекты не конфликтовали между собой.

macOS и Linux:

mkdir ai-task-agent
cd ai-task-agent
python3 -m venv .venv
source .venv/bin/activate

Windows (PowerShell):

mkdir ai-task-agent
cd ai-task-agent
py -m venv .venv
.venv\Scripts\Activate.ps1

Если PowerShell не даёт запустить скрипт активации, откройте обычную «Командную строку» (cmd) и выполните .venv\Scripts\activate.bat. После активации в начале строки терминала появится (.venv).

3. Установка зависимостей

Нам нужна всего одна внешняя библиотека — официальный Python SDK Anthropic. Остальное (json, datetime, pathlib) входит в стандартную библиотеку Python.

python -m pip install "anthropic>=1.6,<2"

Ограничение версии <2 защищает от несовместимых изменений в будущей мажорной версии SDK. Команда одинакова для всех систем, если виртуальное окружение активировано.

4. API-ключ

Создайте аккаунт в Claude Console и сгенерируйте ключ в разделе API Keys. Ключ — это пароль к вашему платному аккаунту: любой, кто его знает, может тратить ваши деньги.

Никогда не записывайте ключ в код

Не вставляйте API-ключ в agent.py, не отправляйте его в чаты и не загружайте на GitHub. Код получает ключ из переменной окружения — так он не попадёт в файлы проекта.

5. Переменная окружения

Задайте ключ в том же окне терминала, где будете запускать агента:

# macOS и Linux
export ANTHROPIC_API_KEY="ваш-ключ"
# Windows PowerShell
$env:ANTHROPIC_API_KEY = "ваш-ключ"
:: Windows cmd
set ANTHROPIC_API_KEY=ваш-ключ

Так переменная действует только в текущей сессии терминала: после перезапуска её нужно задать снова. Это неудобно, зато безопасно для первого проекта.

О стоимости

Запросы к API платные: оплата идёт за количество токенов (фрагментов текста) на входе и выходе. В примере используется модель claude-opus-5; на момент публикации её цена — $5 за миллион входных и $25 за миллион выходных токенов, у более дешёвых моделей цены ниже. Актуальные тарифы — на странице цен. Каждый шаг агента — отдельный запрос, и вся история диалога отправляется каждый раз заново, поэтому длинные разговоры дорожают. Для обучения установите лимит расходов в настройках аккаунта.

Пошаговая инструкция: пишем AI-агента на Python

Весь код агента находится в одном файле agent.py. Ниже он разбит на пять частей с пояснениями: вставляйте их в файл по очереди, одну за другой. Полный файл целиком — в конце раздела.

Шаг 1. Создайте проект

Если вы выполнили подготовку, у вас уже есть папка ai-task-agent с активированным окружением .venv. Откройте её в редакторе кода (например, VS Code) и создайте пустой файл agent.py. Файл tasks.json создавать не нужно: агент создаст его сам при первой записи.

Шаг 2. Установите зависимости

Проверьте, что SDK установлен именно в виртуальное окружение:

python -c "import anthropic; print(anthropic.__version__)"

Команда должна вывести номер версии, например 1.6.0. Если видите ModuleNotFoundError, окружение не активировано или библиотека установлена в другой Python — смотрите раздел «Частые ошибки».

Шаг 3. Настройте API

Убедитесь, что переменная ANTHROPIC_API_KEY задана в текущем терминале. SDK автоматически читает ключ именно из неё, поэтому в коде достаточно написать anthropic.Anthropic() — без паролей в тексте программы. Дополнительно наш main() проверяет переменную перед стартом и понятно сообщает, если её нет.

Шаг 4. Подключите языковую модель

Первая часть файла — импорты и настройки. MODEL — название модели, MAX_TOKENS — максимальная длина одного ответа, MAX_STEPS — предохранитель, который не даст агенту бесконечно вызывать инструменты.

"""AI Task Assistant — первый AI-агент на Python.

Агент получает запрос на естественном языке, сам решает, какой инструмент вызвать,
выполняет разрешённое действие со списком задач и возвращает результат.
"""

import json
import os
import sys
from datetime import date
from pathlib import Path

import anthropic

MODEL = "claude-opus-5"
MAX_TOKENS = 16000
MAX_STEPS = 5  # сколько раз подряд агент может вызывать инструменты за один запрос
TASKS_FILE = Path(__file__).with_name("tasks.json")

Шаг 5. Определите инструмент для управления задачами

Инструменты — это обычные Python-функции. Обратите внимание: каждая функция сама проверяет входные данные. Модель может ошибиться с форматом даты или передать пустое название, поэтому доверять её аргументам без проверки нельзя. Функции выбрасывают ValueError с понятным пояснением — позже этот текст вернётся модели, и она сможет исправиться.

# ---------- 1. Хранилище: обычный JSON-файл рядом со скриптом ----------

def load_tasks() -> list[dict]:
    if not TASKS_FILE.exists():
        return []
    return json.loads(TASKS_FILE.read_text(encoding="utf-8"))


def save_tasks(tasks: list[dict]) -> None:
    TASKS_FILE.write_text(
        json.dumps(tasks, ensure_ascii=False, indent=2), encoding="utf-8"
    )


# ---------- 2. Инструменты: обычные Python-функции с проверкой данных ----------

def add_task(title: str, due_date: str | None = None) -> dict:
    """Создаёт задачу. due_date — строка YYYY-MM-DD или None."""
    if not isinstance(title, str) or not title.strip():
        raise ValueError("Название задачи не может быть пустым.")
    title = title.strip()
    if len(title) > 200:
        raise ValueError("Название задачи слишком длинное: максимум 200 символов.")
    if due_date is not None:
        try:
            due_date = date.fromisoformat(due_date).isoformat()
        except (TypeError, ValueError):
            raise ValueError("Дата должна быть в формате YYYY-MM-DD.") from None

    tasks = load_tasks()
    task = {
        "id": max((t["id"] for t in tasks), default=0) + 1,
        "title": title,
        "due_date": due_date,
        "done": False,
    }
    tasks.append(task)
    save_tasks(tasks)
    return task


def list_tasks() -> list[dict]:
    """Возвращает все задачи."""
    return load_tasks()


def complete_task(task_id: int) -> dict:
    """Отмечает задачу выполненной."""
    if not isinstance(task_id, int) or isinstance(task_id, bool):
        raise ValueError("task_id должен быть целым числом.")
    tasks = load_tasks()
    for task in tasks:
        if task["id"] == task_id:
            task["done"] = True
            save_tasks(tasks)
            return task
    raise ValueError(f"Задача с id={task_id} не найдена.")


# Белый список: агент может вызывать ТОЛЬКО эти функции и ничего больше.
TOOL_FUNCTIONS = {
    "add_task": add_task,
    "list_tasks": list_tasks,
    "complete_task": complete_task,
}

Словарь TOOL_FUNCTIONS — это белый список: агент может вызвать только эти три функции. Даже если модель «придумает» инструмент вроде run_shell, код его не найдёт и ничего не выполнит.

Дальше описываем инструменты для модели: название, пояснение, когда их использовать, и JSON Schema параметров. Параметр "strict": True включает строгий режим, в котором аргументы модели гарантированно соответствуют схеме. Там же — системная инструкция: в ней мы сообщаем модели сегодняшнюю дату (иначе она не сможет посчитать «завтра») и объясняем, как вести себя с неясными и неподдерживаемыми запросами.

# ---------- 3. Описание инструментов для модели (JSON Schema) ----------

TOOLS = [
    {
        "name": "add_task",
        "description": (
            "Добавляет новую задачу в список пользователя. Используй, когда "
            "пользователь просит что-то добавить, запомнить или напомнить."
        ),
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {
                    "type": "string",
                    "description": "Короткое название задачи, до 200 символов.",
                },
                "due_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Дедлайн в формате YYYY-MM-DD, если пользователь его назвал.",
                },
            },
            "required": ["title"],
            "additionalProperties": False,
        },
    },
    {
        "name": "list_tasks",
        "description": "Возвращает все задачи пользователя с id, дедлайном и статусом.",
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {},
            "additionalProperties": False,
        },
    },
    {
        "name": "complete_task",
        "description": (
            "Отмечает задачу выполненной по её id. Если id неизвестен, "
            "сначала вызови list_tasks."
        ),
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {
                "task_id": {"type": "integer", "description": "id задачи."},
            },
            "required": ["task_id"],
            "additionalProperties": False,
        },
    },
]


def system_prompt() -> str:
    today = date.today()
    return (
        "Ты — помощник, который управляет списком задач пользователя. "
        f"Сегодня {today.isoformat()} ({today.strftime('%A')}). "
        "Для работы с задачами используй только предоставленные инструменты. "
        "Относительные даты («завтра», «в пятницу») переводи в формат YYYY-MM-DD. "
        "Если из запроса непонятно, какую именно задачу создать, задай один "
        "уточняющий вопрос и ничего не создавай. Если пользователь просит "
        "о том, чего твои инструменты не умеют, честно скажи об этом. "
        "Отвечай коротко, на языке пользователя."
    )

Шаг 6. Реализуйте цикл агента

Это сердце программы. Функция run_tool безопасно выполняет инструмент, который выбрала модель, и превращает результат или ошибку в текст. Функция run_agent реализует цикл со схемы выше:

  1. Отправляем модели историю диалога, системную инструкцию и описание инструментов.
  2. Если модель отказалась отвечать (refusal) или ответ оборвался из-за лимита (max_tokens), останавливаемся с ошибкой.
  3. Если модель хочет вызвать инструменты (stop_reason == "tool_use"), выполняем каждый и возвращаем все результаты одним сообщением с теми же tool_use_id.
  4. Если инструменты больше не нужны, возвращаем текстовый ответ пользователю.
# ---------- 4. Выполнение инструмента, который выбрала модель ----------

def run_tool(name: str, tool_input: dict) -> tuple[str, bool]:
    """Возвращает (результат в виде текста, произошла ли ошибка)."""
    func = TOOL_FUNCTIONS.get(name)
    if func is None:
        return f"Неизвестный инструмент: {name}", True
    try:
        result = func(**tool_input)
    except (TypeError, ValueError) as error:
        return f"Ошибка: {error}", True
    return json.dumps(result, ensure_ascii=False), False


class AgentError(Exception):
    """Агент не смог завершить запрос."""


# ---------- 5. Цикл агента: модель -> инструмент -> модель -> ... ----------

def run_agent(client: anthropic.Anthropic, messages: list) -> str:
    for _ in range(MAX_STEPS):
        response = client.messages.create(
            model=MODEL,
            max_tokens=MAX_TOKENS,
            system=system_prompt(),
            tools=TOOLS,
            messages=messages,
        )

        if response.stop_reason == "refusal":
            raise AgentError("Модель отказалась выполнять этот запрос.")
        if response.stop_reason == "max_tokens":
            raise AgentError("Ответ оборвался: увеличьте MAX_TOKENS.")

        # Сохраняем ответ модели полностью — вместе с блоками tool_use.
        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason != "tool_use":
            return "".join(b.text for b in response.content if b.type == "text")

        tool_results = []
        for block in response.content:
            if block.type != "tool_use":
                continue
            print(f"  [инструмент] {block.name} {json.dumps(block.input, ensure_ascii=False)}")
            content, is_error = run_tool(block.name, block.input)
            tool_results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": content,
                "is_error": is_error,
            })
        # Все результаты инструментов возвращаем одним сообщением.
        messages.append({"role": "user", "content": tool_results})

    raise AgentError(f"Агент не справился за {MAX_STEPS} шагов.")

Ошибки инструментов не останавливают программу: они возвращаются модели с пометкой is_error: True. Получив сообщение «Дата должна быть в формате YYYY-MM-DD», модель может повторить вызов с правильной датой или уточнить дату у пользователя.

Шаг 7. Запустите приложение

Последняя часть — диалог в терминале. История сообщений хранится в списке messages, поэтому агент помнит контекст в пределах сессии. Ошибки API обрабатываются отдельно: неверный ключ и несуществующая модель завершают программу с пояснением, а временные сбои только убирают неудачный шаг из истории, чтобы диалог можно было продолжить.

# ---------- 6. Диалог в терминале ----------

def main() -> None:
    if not os.environ.get("ANTHROPIC_API_KEY"):
        sys.exit("Не найден ANTHROPIC_API_KEY. Задайте переменную окружения и запустите снова.")

    client = anthropic.Anthropic()  # ключ берётся из переменной окружения
    messages: list = []
    print("AI Task Assistant. Напишите запрос или «выход», чтобы завершить.")

    while True:
        try:
            user_input = input("\nВы: ").strip()
        except (EOFError, KeyboardInterrupt):
            break
        if user_input.lower() in {"выход", "exit", "quit"}:
            break
        if not user_input:
            continue

        start = len(messages)
        messages.append({"role": "user", "content": user_input})
        try:
            answer = run_agent(client, messages)
        except anthropic.AuthenticationError:
            sys.exit("Неверный API-ключ. Проверьте ANTHROPIC_API_KEY.")
        except anthropic.NotFoundError:
            sys.exit(f"Модель {MODEL} не найдена. Проверьте значение MODEL.")
        except (AgentError, anthropic.APIError) as error:
            # Неудачный шаг убираем из истории, чтобы диалог можно было продолжить.
            del messages[start:]
            answer = f"Не удалось выполнить запрос: {error}"
        print(f"Агент: {answer}")


if __name__ == "__main__":
    main()

Сохраните файл и запустите агента:

python agent.py
Полный код agent.py одним файлом
"""AI Task Assistant — первый AI-агент на Python.

Агент получает запрос на естественном языке, сам решает, какой инструмент вызвать,
выполняет разрешённое действие со списком задач и возвращает результат.
"""

import json
import os
import sys
from datetime import date
from pathlib import Path

import anthropic

MODEL = "claude-opus-5"
MAX_TOKENS = 16000
MAX_STEPS = 5  # сколько раз подряд агент может вызывать инструменты за один запрос
TASKS_FILE = Path(__file__).with_name("tasks.json")


# ---------- 1. Хранилище: обычный JSON-файл рядом со скриптом ----------

def load_tasks() -> list[dict]:
    if not TASKS_FILE.exists():
        return []
    return json.loads(TASKS_FILE.read_text(encoding="utf-8"))


def save_tasks(tasks: list[dict]) -> None:
    TASKS_FILE.write_text(
        json.dumps(tasks, ensure_ascii=False, indent=2), encoding="utf-8"
    )


# ---------- 2. Инструменты: обычные Python-функции с проверкой данных ----------

def add_task(title: str, due_date: str | None = None) -> dict:
    """Создаёт задачу. due_date — строка YYYY-MM-DD или None."""
    if not isinstance(title, str) or not title.strip():
        raise ValueError("Название задачи не может быть пустым.")
    title = title.strip()
    if len(title) > 200:
        raise ValueError("Название задачи слишком длинное: максимум 200 символов.")
    if due_date is not None:
        try:
            due_date = date.fromisoformat(due_date).isoformat()
        except (TypeError, ValueError):
            raise ValueError("Дата должна быть в формате YYYY-MM-DD.") from None

    tasks = load_tasks()
    task = {
        "id": max((t["id"] for t in tasks), default=0) + 1,
        "title": title,
        "due_date": due_date,
        "done": False,
    }
    tasks.append(task)
    save_tasks(tasks)
    return task


def list_tasks() -> list[dict]:
    """Возвращает все задачи."""
    return load_tasks()


def complete_task(task_id: int) -> dict:
    """Отмечает задачу выполненной."""
    if not isinstance(task_id, int) or isinstance(task_id, bool):
        raise ValueError("task_id должен быть целым числом.")
    tasks = load_tasks()
    for task in tasks:
        if task["id"] == task_id:
            task["done"] = True
            save_tasks(tasks)
            return task
    raise ValueError(f"Задача с id={task_id} не найдена.")


# Белый список: агент может вызывать ТОЛЬКО эти функции и ничего больше.
TOOL_FUNCTIONS = {
    "add_task": add_task,
    "list_tasks": list_tasks,
    "complete_task": complete_task,
}

# ---------- 3. Описание инструментов для модели (JSON Schema) ----------

TOOLS = [
    {
        "name": "add_task",
        "description": (
            "Добавляет новую задачу в список пользователя. Используй, когда "
            "пользователь просит что-то добавить, запомнить или напомнить."
        ),
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {
                    "type": "string",
                    "description": "Короткое название задачи, до 200 символов.",
                },
                "due_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Дедлайн в формате YYYY-MM-DD, если пользователь его назвал.",
                },
            },
            "required": ["title"],
            "additionalProperties": False,
        },
    },
    {
        "name": "list_tasks",
        "description": "Возвращает все задачи пользователя с id, дедлайном и статусом.",
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {},
            "additionalProperties": False,
        },
    },
    {
        "name": "complete_task",
        "description": (
            "Отмечает задачу выполненной по её id. Если id неизвестен, "
            "сначала вызови list_tasks."
        ),
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {
                "task_id": {"type": "integer", "description": "id задачи."},
            },
            "required": ["task_id"],
            "additionalProperties": False,
        },
    },
]


def system_prompt() -> str:
    today = date.today()
    return (
        "Ты — помощник, который управляет списком задач пользователя. "
        f"Сегодня {today.isoformat()} ({today.strftime('%A')}). "
        "Для работы с задачами используй только предоставленные инструменты. "
        "Относительные даты («завтра», «в пятницу») переводи в формат YYYY-MM-DD. "
        "Если из запроса непонятно, какую именно задачу создать, задай один "
        "уточняющий вопрос и ничего не создавай. Если пользователь просит "
        "о том, чего твои инструменты не умеют, честно скажи об этом. "
        "Отвечай коротко, на языке пользователя."
    )


# ---------- 4. Выполнение инструмента, который выбрала модель ----------

def run_tool(name: str, tool_input: dict) -> tuple[str, bool]:
    """Возвращает (результат в виде текста, произошла ли ошибка)."""
    func = TOOL_FUNCTIONS.get(name)
    if func is None:
        return f"Неизвестный инструмент: {name}", True
    try:
        result = func(**tool_input)
    except (TypeError, ValueError) as error:
        return f"Ошибка: {error}", True
    return json.dumps(result, ensure_ascii=False), False


class AgentError(Exception):
    """Агент не смог завершить запрос."""


# ---------- 5. Цикл агента: модель -> инструмент -> модель -> ... ----------

def run_agent(client: anthropic.Anthropic, messages: list) -> str:
    for _ in range(MAX_STEPS):
        response = client.messages.create(
            model=MODEL,
            max_tokens=MAX_TOKENS,
            system=system_prompt(),
            tools=TOOLS,
            messages=messages,
        )

        if response.stop_reason == "refusal":
            raise AgentError("Модель отказалась выполнять этот запрос.")
        if response.stop_reason == "max_tokens":
            raise AgentError("Ответ оборвался: увеличьте MAX_TOKENS.")

        # Сохраняем ответ модели полностью — вместе с блоками tool_use.
        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason != "tool_use":
            return "".join(b.text for b in response.content if b.type == "text")

        tool_results = []
        for block in response.content:
            if block.type != "tool_use":
                continue
            print(f"  [инструмент] {block.name} {json.dumps(block.input, ensure_ascii=False)}")
            content, is_error = run_tool(block.name, block.input)
            tool_results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": content,
                "is_error": is_error,
            })
        # Все результаты инструментов возвращаем одним сообщением.
        messages.append({"role": "user", "content": tool_results})

    raise AgentError(f"Агент не справился за {MAX_STEPS} шагов.")


# ---------- 6. Диалог в терминале ----------

def main() -> None:
    if not os.environ.get("ANTHROPIC_API_KEY"):
        sys.exit("Не найден ANTHROPIC_API_KEY. Задайте переменную окружения и запустите снова.")

    client = anthropic.Anthropic()  # ключ берётся из переменной окружения
    messages: list = []
    print("AI Task Assistant. Напишите запрос или «выход», чтобы завершить.")

    while True:
        try:
            user_input = input("\nВы: ").strip()
        except (EOFError, KeyboardInterrupt):
            break
        if user_input.lower() in {"выход", "exit", "quit"}:
            break
        if not user_input:
            continue

        start = len(messages)
        messages.append({"role": "user", "content": user_input})
        try:
            answer = run_agent(client, messages)
        except anthropic.AuthenticationError:
            sys.exit("Неверный API-ключ. Проверьте ANTHROPIC_API_KEY.")
        except anthropic.NotFoundError:
            sys.exit(f"Модель {MODEL} не найдена. Проверьте значение MODEL.")
        except (AgentError, anthropic.APIError) as error:
            # Неудачный шаг убираем из истории, чтобы диалог можно было продолжить.
            del messages[start:]
            answer = f"Не удалось выполнить запрос: {error}"
        print(f"Агент: {answer}")


if __name__ == "__main__":
    main()

Шаг 8. Проверьте результат

После запуска агент ждёт запрос. Попробуйте, например, «Добавь задачу подготовить домашнее задание по Python на завтра». В терминале появится строка с инструментом, который выбрала модель, — что-то вроде [инструмент] add_task {"title": "Подготовить домашнее задание по Python", "due_date": "…"} с завтрашней датой, — а затем короткое подтверждение. Точная формулировка названия задачи и ответа зависит от модели и может отличаться. Откройте tasks.json: там должна быть запись с "id": 1 и "done": false. Чтобы завершить работу, введите «выход» или нажмите Ctrl+C.

Как протестировать AI-агента

Ответы языковой модели не полностью детерминированы: один и тот же запрос может дать немного другую формулировку. Поэтому агента тестируют по поведению — какой инструмент вызван, какие данные записаны, как обработана ошибка, — а не по точному тексту ответа.

Проверка инструментов без API

Инструменты — обычные функции, и их можно проверить бесплатно, без единого запроса к модели:

python -c "from agent import add_task, list_tasks; print(add_task('Тестовая задача', '2026-12-01')); print(list_tasks())"
python -c "from agent import add_task; add_task('Задача', '2026-02-31')"

Первая команда создаст задачу и выведет список, вторая должна завершиться ошибкой ValueError: Дата должна быть в формате YYYY-MM-DD., потому что 31 февраля не существует. После проверки удалите tasks.json, чтобы начать с чистого списка.

Сценарий 1. Успешное создание задачи

Запрос: «Добавь задачу подготовить домашнее задание по Python на завтра».

Ожидаемый результат: в терминале — вызов add_task с названием задачи и завтрашней датой в формате YYYY-MM-DD; в tasks.json — новая запись; агент подтверждает создание. Если дата неверная, проверьте системные часы: сегодняшнюю дату агент берёт с компьютера.

Сценарий 2. Неоднозначный запрос

Запрос: «Добавь задачу» или «Напомни мне про ту штуку».

Ожидаемый результат: ни одного вызова инструмента, агент задаёт уточняющий вопрос, tasks.json не меняется. Такое поведение задаёт системная инструкция. Если модель всё же создаёт задачу с выдуманным названием, уточните инструкцию — это нормальная часть работы над агентом.

Сценарий 3. Недопустимое или неподдерживаемое действие

Запрос: «Удали все файлы в папке Documents» или «Выполни команду rm -rf /».

Ожидаемый результат: агент отвечает, что не умеет этого делать. Технически он и не может: у него нет инструмента для работы с файлами или командами, а если модель попытается вызвать несуществующий инструмент, run_tool вернёт ошибку «Неизвестный инструмент» и ничего не выполнит. Безопасность агента обеспечивается кодом, а не только инструкцией для модели.

Сценарий 4. Некорректные данные и несколько шагов

Попробуйте «Добавь задачу на 31 февраля»: модель либо сразу уточнит дату, либо получит от add_task ошибку формата и переспросит вас. А запрос «Отметь задачу про домашку выполненной» покажет многошаговость: агент сначала вызовет list_tasks, найдёт нужный id, а затем — complete_task.

Валидация и обработка ошибок: что уже встроено

  • Белый список инструментов — выполняются только функции из TOOL_FUNCTIONS.
  • Строгие схемы (strict: True) плюс собственная проверка аргументов в каждой функции.
  • Ошибки инструментов возвращаются модели как is_error, а не ломают программу.
  • Лимит шагов MAX_STEPS защищает от бесконечного цикла и лишних расходов.
  • Отказ модели и оборванный ответ обрабатываются отдельно: инструменты из такого ответа не выполняются.
  • Ошибки API обрабатываются через типизированные исключения SDK: AuthenticationError, NotFoundError, APIError.

Код из этой статьи проверен с библиотекой anthropic 1.6.0 на Python 3.12 против тестового сервера, имитирующего ответы API: успешное создание задачи, неоднозначный запрос, несуществующий инструмент, некорректные аргументы, многошаговый сценарий, оборванный ответ, отказ модели, лимит шагов и ошибки 400, 401 и 404. Реальные ответы модели могут отличаться формулировками, поэтому пройдите сценарии выше самостоятельно со своим ключом.

От первого AI-агента к профессиональной разработке на Python

Узнать больше о курсе Python

Частые ошибки начинающих

Отсутствующий или неверный API-ключ

Сообщение «Не найден ANTHROPIC_API_KEY» означает, что переменная задана в другом окне терминала или пропала после перезапуска. Задайте её снова в том же окне, где запускаете agent.py. Сообщение «Неверный API-ключ» (ошибка 401) — ключ скопирован с ошибкой, с пробелом или уже удалён в Console.

Проблемы с установкой зависимостей

  • ModuleNotFoundError: No module named 'anthropic' — окружение не активировано или библиотека установлена в другой интерпретатор. Активируйте .venv и устанавливайте через python -m pip, а не просто pip: так пакет гарантированно попадёт в тот Python, которым вы запускаете скрипт.
  • ERROR: No matching distribution found for anthropic… — устаревшая версия Python. Текущая ветка SDK требует Python 3.10+.
  • На Linux python3 -m venv сообщает об отсутствии ensurepip — установите пакет python3-venv.

Неверная конфигурация модели

Ошибка 404 с сообщением «Модель … не найдена» означает опечатку в названии модели или модель, которую уже вывели из обращения. Актуальные идентификаторы — в обзоре моделей. Ошибка 400 обычно означает некорректный запрос или проблему с аккаунтом, например недостаточный баланс, — текст ошибки подскажет причину.

Ошибки при выполнении инструментов

Если вы добавляете собственные инструменты, помните: run_tool перехватывает только TypeError и ValueError. Другие исключения, например PermissionError при записи файла, остановят программу. Это сознательное решение: неожиданную ошибку лучше увидеть сразу, чем незаметно передать модели. Когда поймёте причину, обработайте её явно.

Избыточные права

Самая опасная ошибка — дать агенту «универсальный» инструмент: выполнение команд терминала, eval() для произвольного кода или доступ ко всей файловой системе. Модель может ошибиться, а текст, который она обрабатывает, может содержать вредоносные инструкции (так называемая prompt injection). Правило простое: каждый инструмент делает одно узкое действие, проверяет свои аргументы, а необратимые операции требуют подтверждения человека.

Расходы на API

Расходы растут незаметно: каждый шаг цикла — отдельный платный запрос, а история диалога с каждым сообщением становится длиннее. Следите за расходами в Console, установите лимит, не увеличивайте MAX_STEPS без необходимости и перезапускайте агента, чтобы начать диалог с чистой историей.

Как улучшить агента

  • Дополнительные инструменты. Редактирование задачи, приоритеты, фильтр по дате. Каждый новый инструмент — функция с проверкой данных плюс описание в TOOLS. Понадобится: функции, словари, работа с датами.
  • Постоянное хранилище. Вместо JSON-файла — база SQLite через встроенный модуль sqlite3, чтобы задачи не повреждались и быстро искались. Понадобится: основы SQL и работы с базами данных.
  • Интеграции с внешними API. Календарь, почта, Telegram-бот, который присылает напоминания. Понадобится: API, HTTP-запросы, JSON, аутентификация.
  • Логирование. Модуль logging вместо print: записывать каждый вызов инструмента, аргументы и ошибки, чтобы разбираться, что именно сделал агент. Понадобится: стандартная библиотека, декораторы.
  • Безопасность. Минимальные права, проверка всех аргументов, лимиты на количество действий, отдельные учётные записи с ограниченным доступом для интеграций. Понадобится: обработка исключений, понимание аутентификации.
  • Подтверждение человеком для чувствительных действий. Например, инструмент delete_task, который перед удалением спрашивает «Удалить задачу 3? (y/n)» и выполняется только после «y». Этот подход называют human-in-the-loop. Понадобится: условия и управление потоком программы.

Когда инструментов станет больше, стоит посмотреть на готовые решения: tool runner в SDK Anthropic берёт цикл агента на себя, а протокол MCP позволяет подключать к агенту готовые интеграции. Но именно цикл, написанный своими руками, даёт понимание того, что происходит внутри любого фреймворка. Более широкий обзор AI-инструментов для разработчиков — в статье «AI-инструменты для программистов».

Посмотрите на код ещё раз: в нём нет ничего «искусственно-интеллектуального», кроме одного вызова client.messages.create. Всё остальное — обычное программирование на Python. Именно поэтому умение программировать на Python с нуля важнее знания конкретного AI-фреймворка: фреймворки меняются каждый год, а основы остаются.

НавыкГде он в нашем агентеКогда нужен
Переменные и типы данныхНастройки MODEL, MAX_STEPS, поля задачиСразу
ФункцииКаждый инструмент, run_tool, run_agentСразу
Условные операторыПроверка stop_reason и входных данныхСразу
ЦиклыЦикл агента и диалог в терминалеСразу
Списки и словариИстория messages, TOOLS, белый список инструментовСразу
Работа с файламиЧтение и запись tasks.jsonСразу
JSONСхемы инструментов, хранение задач, результаты для моделиСразу
Обработка ошибокtry/except, ValueError, исключения APIСразу
HTTP-запросы и APIВызов модели (SDK делает HTTP-запрос за вас)Для интеграций с другими сервисами
ООПКласс AgentError, объект клиента SDKДля больших агентов и фреймворков
Асинхронное программированиеВ этом агенте не используетсяДля параллельных запросов и веб-сервисов

Как эти темы ложатся на программу курса Python в Prog Academy:

  • Python Start — переменные и приведение типов, условные и булевы операторы, циклы, списки, строки, словари, функции и передача параметров, чтение и запись файлов. Это всё, что нужно, чтобы читать код нашего агента.
  • Python для Data Analytics — чтение и запись JSON и CSV, *args и **kwargs, декораторы (в том числе для логирования), введение в ООП, обработка исключений (try…except, else, finally), базы данных и основы SQL.
  • Python + Django (бонус) — ООП и наследование, модули, работа с исключениями, Django, запросы и ответы, работа с базами данных, авторизация и безопасность — фундамент, чтобы превратить агента в веб-сервис.
  • AI Start — практическое использование ChatGPT и Claude, промпты для разработчиков.

Асинхронного программирования в перечне тем курса нет: его обычно изучают позже, когда агент превращается в веб-сервис со многими пользователями.

Где учить Python с нуля?

Сегодня AI-ассистент сгенерирует похожий код за минуту. Зачем тогда учить язык? Потому что скопировать код и понимать код — разные навыки. Когда агент ведёт себя не так, как ожидалось, — записывает не ту дату, зацикливается, падает с исключением, — нужно прочитать трассировку ошибки, найти место, где данные изменились, и понять, виновата модель или ваш код. AI-сгенерированный код часто выглядит убедительно, но содержит неочевидные ошибки: пропущенную проверку аргументов, опасный eval(), неправильную работу с историей сообщений. Заметить их может только тот, кто знает основы.

Несколько советов, как обучение Python для начинающих превратить в реальные навыки:

  • Пишите код руками. Даже этот туториал полезнее набрать, чем скопировать: ошибки при наборе учат больше, чем правильный код.
  • Делайте практические задания. Чтение теории даёт ощущение понимания, а задачи показывают, настоящее ли оно. Особенно ценна обратная связь: опытный человек увидит в вашем коде то, чего не заметите вы.
  • Двигайтесь от упражнений к проектам. Сначала отдельные задачи на циклы и словари, потом маленькие скрипты для себя (переименовать файлы, посчитать расходы), потом программы с API, как наш агент, и наконец — проект для портфолио.
  • Используйте AI как наставника, а не как замену. Просите объяснить ошибку или незнакомую конструкцию, но решения пишите сами.

Чтобы попробовать без обязательств, начните с бесплатного курса Python или подборки книг по Python для начинающих. Если нужен системный путь, курсы Python с нуля в Prog Academy сочетают теорию, практику с преподавателем, домашние задания с обратной связью и дипломный проект. Программа курса Python Developer + AI аккредитована в ЕС, рассчитана на новичков без технического образования, длится 4,5 месяца и проходит онлайн — в группе или индивидуально. Отдельный модуль AI Start учит использовать AI-инструменты в работе разработчика.

Посмотреть программу курса Python →

Частые вопросы

Можно ли создать AI-агента без знания Python?

Простого агента можно собрать без кода в no-code платформах вроде n8n: там модель подключается к инструментам визуально — об этом подходе мы писали в полном руководстве по AI Automation. Но как только нужна собственная логика, проверка данных, интеграция с системой без готового коннектора или контроль безопасности, понадобится код. Скопировать готовый пример можно и без знаний, но исправить ошибку или изменить поведение агента без понимания Python не получится.

Сложно ли выучить Python новичку?

Python считают одним из самых удобных языков для старта: синтаксис короткий и читаемый, а первые программы работают уже в первый день. Сложность растёт постепенно — от переменных и циклов к функциям, работе с файлами, обработке ошибок и ООП. Главное — регулярная практика, а не количество прочитанной теории.

Сколько времени нужно, чтобы выучить Python?

Зависит от цели и регулярности занятий. Чтобы понимать код, как в этой статье, нужны основы: переменные, условия, циклы, функции, словари, файлы, JSON и обработка ошибок. Для работы разработчиком добавляются ООП, базы данных, фреймворки и проекты. Для ориентира: полная программа курса Python в Prog Academy рассчитана на 4,5 месяца.

Нужно ли знать машинное обучение, чтобы создавать AI-агентов?

Нет. Агент в этой статье использует готовую языковую модель через API — её не нужно обучать. Нужны навыки обычного программиста: вызывать API, работать с JSON, писать функции, проверять входные данные и обрабатывать ошибки. Машинное обучение понадобится, если вы захотите обучать или дообучать собственные модели.

Можно ли создать AI-агента бесплатно?

Python, библиотека anthropic и весь код из этой статьи бесплатны. Платные запросы к API языковой модели — оплата идёт за количество токенов. Для учебных экспериментов это обычно небольшие суммы, но стоит установить лимит расходов в аккаунте. Альтернатива — локальные открытые модели, но им нужен мощный компьютер и другая настройка.

Чем AI-агент отличается от чат-бота?

Чат-бот отвечает текстом на сообщения. AI-агент получает цель, сам решает, какой инструмент вызвать, выполняет действие (например, создаёт задачу или делает запрос к API), видит результат и решает, что делать дальше. Модель внутри может быть той же — разница в доступе к инструментам и цикле выполнения.

Какие библиотеки Python используют для AI-агентов?

Для простого агента достаточно официального SDK провайдера модели — например, anthropic, как в этой статье. Для более сложных систем используют фреймворки: LangChain и LangGraph, LlamaIndex, Pydantic AI, Claude Agent SDK или OpenAI Agents SDK. Рядом обычно работают pydantic для проверки данных, httpx или requests для HTTP-запросов и стандартные модули json, logging и sqlite3.

Где выучить Python с нуля?

Начать можно с бесплатного курса Python от Prog Academy и книг для начинающих, а для системного обучения с преподавателем, проверкой домашних заданий и проектом для портфолио — пройти курс Python Developer + AI, где программа ведёт от основ языка к ООП, базам данных и Django.

Заключение

Вы создали полноценного, хоть и маленького AI-агента: он понимает запросы обычным языком, сам выбирает один из трёх инструментов, выполняет только разрешённые действия, проверяет данные, обрабатывает ошибки и не может выйти за пределы своего белого списка. Главное, что стоит вынести из этого туториала: AI-агент — это обычная Python-программа, в которой решение «что сделать дальше» принимает языковая модель, а контроль остаётся за вашим кодом.

Следующие практические шаги: добавьте инструмент delete_task с подтверждением человеком, перенесите задачи в SQLite, замените print на logging и сохраните проект в Git — как начать, рассказывает статья «Git для начинающих». Каждое такое улучшение упирается в основы языка: функции, исключения, работу с данными, ООП.

Py

Готовы изучать Python системно?

Курс Python Developer + AI от Prog Academy — программа, аккредитованная в ЕС: от первой программы и основ языка к ООП, базам данных, Django и AI-инструментам для разработчика. Практические задания с проверкой преподавателя, проект для портфолио, онлайн в группе или индивидуально.

Узнать больше о курсе Python

Контакт

Записаться на консультацию

Укажите актуальный номер, мы позвоним в любую страну :)