Полное руководство по разработке AI Agent: создаём интеллектуального агента на Python с нуля (2026)
Кратко
- Ключевая способность AI Agent — Function Calling (вызов инструментов) — позволяет большой языковой модели не только говорить, но и действовать
- В этой статье мы с нуля реализуем полноценного AI Agent: запрос погоды + поиск по базе данных + вычисления, с готовым к запуску кодом на Python
- Рассмотрены реализации Tool Use для OpenAI, Claude и Gemini — код можно использовать как есть
- Ключевые аспекты продакшена: обработка ошибок, многошаговые вызовы инструментов, параллельные вызовы, защита безопасности — всё в одной статье
Содержание
- Что такое AI Agent? Эволюция от ChatBot к интеллектуальному агенту
- Ключевой принцип: как работает Function Calling
- Подготовка окружения и создание проекта
- Первый Agent: помощник по погоде
- Продвинутый уровень: интеллектуальный Agent с несколькими инструментами
- Сравнение Function Calling трёх основных моделей
- Лучшие практики для продакшена
- Часто задаваемые вопросы (FAQ)
- Итоги и план действий
- Справочные материалы
Что такое AI Agent? Эволюция от ChatBot к интеллектуальному агенту
В 2026 году AI Agent эволюционировал из «чат-бота, умеющего вызывать инструменты» в «непрерывно работающую программную систему». Зрелый Agent способен:
- Самостоятельно планировать многошаговые задачи и разбивать их на подзадачи
- Вызывать внешние инструменты для получения данных в реальном времени, работы с базами данных, выполнения кода
- Поддерживать долговременную память, запоминая предпочтения пользователя и контекст между сессиями
- Взаимодействовать с другими агентами, формируя мультиагентные системы для решения сложных задач
| Параметр | Традиционный ChatBot | AI Agent |
|---|---|---|
| Формат вывода | Только текст | Текст + вызовы инструментов + структурированные данные |
| Источник информации | Только обучающие данные | Обучающие данные + API в реальном времени + базы данных |
| Исполнительные способности | Нет | Выполнение кода, вызов API, работа с файлами |
| Сложность задач | Одношаговые вопросы-ответы | Многошаговое планирование и исполнение |
| Управление состоянием | Без состояния или краткосрочный контекст | Долговременная память + управление сессиями |
Это не концептуальное различие — это разница между тем, может ли он реально выполнять работу за вас или нет.
Ключевой принцип: как работает Function Calling
Function Calling (также называемый Tool Use / Tool Calling) — это основной двигатель AI Agent. Его работу можно описать одной фразой:
Модель решает, какой инструмент вызвать и с какими параметрами; ваш код выполняет инструмент; результат возвращается модели.
Полный Agent Loop работает следующим образом:

Ввод пользователя → Рассуждение модели → Нужен инструмент?
├─ Нет → Прямой ответ пользователю
└─ Да → Вывод инструкции вызова инструмента
↓
Код разработчика выполняет инструмент
↓
Результат возвращается модели
↓
Модель продолжает рассуждение (может снова вызвать инструмент)
↓
Финальный ответ пользователю
Каждая реализация Function Calling требует трёх ключевых компонентов:
- Определение инструмента (Tool Schema): описание инструмента в формате JSON Schema — название, назначение и параметры
- Слой исполнения (Execution Layer): ваш код, который фактически выполняет логику инструмента
- Интеграция результата (Result Integration): передача результата выполнения обратно модели для продолжения рассуждения
Подготовка окружения и создание проекта
Установка зависимостей
pip install openai httpx
Нам нужен только один SDK — openai — потому что все основные модели (GPT, Claude, Gemini, DeepSeek, Qwen) совместимы с протоколом OpenAI API. Один код — множество моделей.
Настройка API
from openai import OpenAI
# Используем OpenAI-совместимый интерфейс для доступа к 50+ моделям
client = OpenAI(
api_key="your-api-key",
base_url="https://api.ofox.ai/v1" # API-шлюз-агрегатор, низкая задержка из Китая
)
Подсказка: если вы используете официальный API OpenAI напрямую, замените
base_urlнаhttps://api.openai.com/v1. Логика кода остаётся абсолютно неизменной.
Первый Agent: помощник по погоде
Начнём с самого классического примера — AI Agent, который умеет узнавать погоду.
Шаг 1: Определение инструмента
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Получить текущую погоду в указанном городе, включая температуру, влажность и погодные условия",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Название города, например 'Москва', 'Токио', 'London'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Единица измерения температуры, по умолчанию — градусы Цельсия"
}
},
"required": ["city"]
}
}
}
]
Ключевой момент: поле description крайне важно — модель принимает решение о вызове инструмента на основе описания. Чем точнее описание, тем правильнее решения модели.
Шаг 2: Реализация функции инструмента
import httpx
import json
def get_weather(city: str, unit: str = "celsius") -> str:
"""Вызов API погоды для получения данных в реальном времени"""
# Здесь используем wttr.in для примера; в продакшене рекомендуется платный API погоды
resp = httpx.get(f"https://wttr.in/{city}?format=j1", timeout=10)
data = resp.json()
current = data["current_condition"][0]
temp = current["temp_C"] if unit == "celsius" else current["temp_F"]
unit_label = "°C" if unit == "celsius" else "°F"
return json.dumps({
"city": city,
"temperature": f"{temp}{unit_label}",
"humidity": f"{current['humidity']}%",
"description": current["weatherDesc"][0]["value"],
"wind": f"{current['windspeedKmph']} km/h"
}, ensure_ascii=False)
Шаг 3: Реализация Agent Loop
import json
# Таблица маппинга функций инструментов
TOOL_FUNCTIONS = {
"get_weather": get_weather,
}
def run_agent(user_message: str):
"""Запуск Agent: отправка сообщения → обработка вызовов инструментов → возврат результата"""
messages = [
{"role": "system", "content": "Ты умный помощник по погоде. Отвечай на вопросы о погоде на естественном языке."},
{"role": "user", "content": user_message}
]
while True:
# 1. Вызов модели
response = client.chat.completions.create(
model="gpt-4.1-mini", # Можно заменить на claude-sonnet-4.5, gemini-2.5-flash и др.
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
messages.append(msg)
# 2. Если нет вызовов инструментов — модель уже дала финальный ответ
if not msg.tool_calls:
return msg.content
# 3. Выполнение каждого вызова инструмента
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"Вызов инструмента: {func_name}({func_args})")
# Выполнение функции инструмента
result = TOOL_FUNCTIONS[func_name](**func_args)
# Возврат результата модели
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
# Тест
answer = run_agent("Где сейчас теплее — в Москве или в Токио?")
print(answer)
Пример работы:
Вызов инструмента: get_weather({"city": "Москва"})
Вызов инструмента: get_weather({"city": "Токио"})
Сейчас в Москве 18°C, а в Токио 15°C — в Москве на 3 градуса теплее.
В Москве ясно, в Токио облачно — оба города подходят для прогулки.
Обратите внимание: модель автоматически решила сделать два запроса погоды, а затем сравнила и проанализировала результаты. В этом и заключается магия Agent — он не просто передаёт данные, а рассуждает.
Продвинутый уровень: интеллектуальный Agent с несколькими инструментами
В реальных сценариях Agent обычно координирует несколько инструментов. Давайте создадим более сложного помощника — с погодой, поиском по базе данных и вычислениями.
Определение нескольких инструментов
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Получить текущую погоду в указанном городе",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "Название города"}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "search_database",
"description": "Поиск в базе данных товаров, возвращает список подходящих товаров",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Ключевое слово для поиска"},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "food", "books"],
"description": "Категория товара"
},
"max_results": {
"type": "integer",
"description": "Максимальное количество результатов, по умолчанию 5"
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "Выполнение математических вычислений: четыре арифметических действия, проценты, конвертация валют и т.д.",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Математическое выражение, например '100 * 0.85' или '1999 * 3 + 500'"
}
},
"required": ["expression"]
}
}
}
]
Реализация функций инструментов
def search_database(query: str, category: str = None, max_results: int = 5) -> str:
"""Имитация поиска по базе данных (в реальном проекте — подключение к настоящей БД)"""
# Демо-данные
products = [
{"name": "MacBook Pro 16", "price": 18999, "category": "electronics", "stock": 50},
{"name": "iPhone 16 Pro", "price": 8999, "category": "electronics", "stock": 200},
{"name": "AirPods Pro 3", "price": 1899, "category": "electronics", "stock": 500},
{"name": "Руководство по Python", "price": 89, "category": "books", "stock": 1000},
]
results = [p for p in products if query.lower() in p["name"].lower()
or (category and p["category"] == category)]
return json.dumps(results[:max_results], ensure_ascii=False)
def calculate(expression: str) -> str:
"""Безопасные математические вычисления (допускаются только числа и базовые операторы)"""
import ast
import operator
# Безопасная альтернатива выполнению произвольных выражений
allowed_operators = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Mod: operator.mod,
ast.Pow: operator.pow,
ast.USub: operator.neg,
}
def safe_compute(node):
if isinstance(node, ast.Expression):
return safe_compute(node.body)
elif isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
return node.value
elif isinstance(node, ast.BinOp) and type(node.op) in allowed_operators:
left = safe_compute(node.left)
right = safe_compute(node.right)
return allowed_operators[type(node.op)](left, right)
elif isinstance(node, ast.UnaryOp) and type(node.op) in allowed_operators:
return allowed_operators[type(node.op)](safe_compute(node.operand))
else:
raise ValueError(f"Неподдерживаемое выражение")
try:
tree = ast.parse(expression, mode="eval")
result = safe_compute(tree)
return json.dumps({"expression": expression, "result": result})
except Exception as e:
return json.dumps({"error": str(e)})
# Обновление маппинга инструментов
TOOL_FUNCTIONS = {
"get_weather": get_weather,
"search_database": search_database,
"calculate": calculate,
}
Практика: координация нескольких инструментов
answer = run_agent("Найди устройства Apple в категории электроники и посчитай, сколько будет стоить MacBook Pro и AirPods вместе")
print(answer)
Вызов инструмента: search_database({"query": "Mac", "category": "electronics"})
Вызов инструмента: search_database({"query": "AirPods", "category": "electronics"})
Вызов инструмента: calculate({"expression": "18999 + 1899"})
Найдены два устройства Apple:
- MacBook Pro 16: 18 999 руб. (на складе 50 шт.)
- AirPods Pro 3: 1 899 руб. (на складе 500 шт.)
Итого за оба устройства: **20 898 руб.** Если нужно оформить заказ или узнать подробнее о конфигурации — пишите.
Модель автоматически организовала три вызова инструментов: два поиска + одно вычисление. Такая координация нескольких инструментов — это ключевая ценность Agent.
Сравнение Function Calling трёх основных моделей
В 2026 году ведущие модели имеют свои сильные стороны в Function Calling. Вот сравнение на основе реальных тестов:
| Параметр сравнения | GPT-5.x серия | Claude Opus/Sonnet 4.x | Gemini 3.1 Pro |
|---|---|---|---|
| Точность Tool Use | 5/5 | 5/5 | 5/5 |
| Параллельные вызовы | Поддержка | Поддержка | Поддержка (лучше всех) |
| Вызов после сложного рассуждения | Сильно | Лучше всех | Сильно |
| Tool Use с длинным контекстом | 128K | 200K | 2M (с отрывом) |
| Протокол API | Нативный OpenAI | Совместим с OpenAI | Совместим с OpenAI |
| Прямой доступ из Китая | Нужен шлюз-агрегатор | Нужен шлюз-агрегатор | Нужен шлюз-агрегатор |
Различия на уровне кода
Хорошая новость: если вы используете OpenAI-совместимый интерфейс, код для всех трёх моделей абсолютно одинаковый — нужно лишь менять параметр model:
# GPT-5.4
response = client.chat.completions.create(model="gpt-5.4", messages=messages, tools=tools)
# Claude Sonnet 4.6
response = client.chat.completions.create(model="claude-sonnet-4.6", messages=messages, tools=tools)
# Gemini 3.1 Pro
response = client.chat.completions.create(model="gemini-3.1-pro", messages=messages, tools=tools)
Через API-шлюз-агрегатор (например, Ofox) вы можете одним API Key и base_url вызывать все модели, переключаясь в коде в любой момент, без необходимости управлять множеством ключей.
Рекомендации по выбору модели
- Универсальная разработка Agent: GPT-4.1-mini или Claude Sonnet 4.6 (лучшее соотношение цена/качество)
- Agent для сложных рассуждений: Claude Opus 4.6 или Gemini 3.1 Pro
- Обработка сверхдлинных документов: Gemini 3.1 Pro (контекст 2M)
- Ограниченный бюджет: DeepSeek V3 или GPT-4.1-nano
Лучшие практики для продакшена
От демо до продакшена — есть несколько ключевых задач, которые нужно решить.
1. Обработка ошибок и повторные попытки
def run_agent_production(user_message: str, max_rounds: int = 10):
"""Продакшен-уровень Agent Loop с обработкой ошибок и лимитом итераций"""
messages = [
{"role": "system", "content": "Ты умный помощник. Если вызов инструмента завершился ошибкой, сообщи пользователю причину и предложи альтернативу."},
{"role": "user", "content": user_message}
]
for round_num in range(max_rounds):
try:
response = client.chat.completions.create(
model="gpt-4.1-mini",
messages=messages,
tools=tools,
tool_choice="auto",
timeout=30
)
except Exception as e:
return f"Ошибка вызова API: {e}"
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
try:
func_args = json.loads(tool_call.function.arguments)
func = TOOL_FUNCTIONS.get(func_name)
if not func:
result = json.dumps({"error": f"Неизвестный инструмент: {func_name}"})
else:
result = func(**func_args)
except json.JSONDecodeError:
result = json.dumps({"error": "Ошибка разбора параметров"})
except Exception as e:
result = json.dumps({"error": f"Ошибка выполнения инструмента: {str(e)}"})
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "Agent достиг максимального числа итераций. Упростите запрос и попробуйте снова."
2. Защита безопасности
Agent может вызывать инструменты, а значит — создавать побочные эффекты. Обязательно обеспечьте защиту:
# Контроль прав доступа к инструментам
TOOL_PERMISSIONS = {
"get_weather": {"level": "read", "rate_limit": 60}, # Только чтение, 60 раз/мин
"search_database": {"level": "read", "rate_limit": 30}, # Только чтение
"calculate": {"level": "compute", "rate_limit": 100}, # Вычисления
"send_email": {"level": "write", "require_confirm": True}, # Запись — нужно подтверждение
"delete_record": {"level": "dangerous", "require_confirm": True}, # Опасная операция — нужно подтверждение
}
def execute_tool_safely(func_name: str, func_args: dict) -> str:
"""Безопасное выполнение инструмента с проверкой прав"""
perm = TOOL_PERMISSIONS.get(func_name)
if not perm:
return json.dumps({"error": "Неавторизованный инструмент"})
# Опасные операции требуют подтверждения человеком (в продакшене — интеграция с системой согласования)
if perm.get("require_confirm"):
print(f"Внимание! Операция повышенного риска: {func_name}({func_args})")
# В веб-приложении можно показать диалог подтверждения
# confirm = await get_user_confirmation(func_name, func_args)
return json.dumps({"error": "Эта операция требует подтверждения — запрос на согласование отправлен"})
return TOOL_FUNCTIONS[func_name](**func_args)
3. Потоковый вывод + вызовы инструментов
В продакшене потоковый вывод значительно улучшает пользовательский опыт:
def run_agent_streaming(user_message: str):
"""Agent с потоковым выводом"""
messages = [
{"role": "system", "content": "Ты умный помощник."},
{"role": "user", "content": user_message}
]
while True:
stream = client.chat.completions.create(
model="gpt-4.1-mini",
messages=messages,
tools=tools,
stream=True
)
tool_calls_buffer = {}
content_buffer = ""
for chunk in stream:
delta = chunk.choices[0].delta
# Текстовый контент: вывод в реальном времени
if delta.content:
print(delta.content, end="", flush=True)
content_buffer += delta.content
# Вызовы инструментов: сбор полной информации о вызове
if delta.tool_calls:
for tc in delta.tool_calls:
idx = tc.index
if idx not in tool_calls_buffer:
tool_calls_buffer[idx] = {
"id": tc.id or "",
"name": "",
"arguments": ""
}
if tc.id:
tool_calls_buffer[idx]["id"] = tc.id
if tc.function and tc.function.name:
tool_calls_buffer[idx]["name"] = tc.function.name
if tc.function and tc.function.arguments:
tool_calls_buffer[idx]["arguments"] += tc.function.arguments
# Если нет вызовов инструментов — возвращаем текст
if not tool_calls_buffer:
print() # Перенос строки
return content_buffer
# Выполнение вызовов инструментов и добавление результатов в messages (логика та же)
assistant_msg = {"role": "assistant", "content": content_buffer or None, "tool_calls": []}
for idx in sorted(tool_calls_buffer.keys()):
tc = tool_calls_buffer[idx]
assistant_msg["tool_calls"].append({
"id": tc["id"],
"type": "function",
"function": {"name": tc["name"], "arguments": tc["arguments"]}
})
messages.append(assistant_msg)
for idx in sorted(tool_calls_buffer.keys()):
tc = tool_calls_buffer[idx]
func_args = json.loads(tc["arguments"])
result = TOOL_FUNCTIONS[tc["name"]](**func_args)
messages.append({
"role": "tool",
"tool_call_id": tc["id"],
"content": result
})
4. Управление памятью диалога
Долго работающий Agent нуждается в управлении контекстным окном:
def manage_context(messages: list, max_tokens: int = 8000) -> list:
"""Управление контекстным окном: сохранение системного промпта и последних сообщений"""
# Грубая оценка числа токенов (для кириллицы ~2-3 токена/слово)
estimated_tokens = sum(len(m.get("content", "") or "") * 1.5 for m in messages)
if estimated_tokens <= max_tokens:
return messages
# Сохраняем системные сообщения и последние сообщения диалога
system_msgs = [m for m in messages if m.get("role") == "system"]
other_msgs = [m for m in messages if m.get("role") != "system"]
# Сохраняем начиная с последних сообщений
kept = []
current_tokens = sum(len(m.get("content", "") or "") * 1.5 for m in system_msgs)
for msg in reversed(other_msgs):
msg_tokens = len(msg.get("content", "") or "") * 1.5
if current_tokens + msg_tokens > max_tokens:
break
kept.insert(0, msg)
current_tokens += msg_tokens
return system_msgs + kept
Часто задаваемые вопросы (FAQ)
В: Нужен ли GPU для разработки AI Agent?
О: Нет. Разработка AI Agent — это чисто инженерная задача. Вы вызываете большие модели в облаке через API, а локально нужен лишь обычный компьютер и среда Python. Вычислительные ресурсы для инференса предоставляет провайдер API.
В: Сколько инструментов оптимально для одного AI Agent?
О: Рекомендуется 5-15 инструментов. Слишком мало — ограниченные возможности; слишком много — снижается точность выбора модели. Если нужно больше возможностей, лучше разделить на несколько специализированных агентов.
В: Как валидировать параметры Function Calling?
О: Рекомендуется использовать Pydantic. Определите параметры инструмента как Pydantic Model — автоматическая генерация JSON Schema и валидация ввода:
from pydantic import BaseModel, Field
class WeatherParams(BaseModel):
city: str = Field(description="Название города")
unit: str = Field(default="celsius", description="Единица измерения температуры")
# Автоматическая генерация JSON Schema
schema = WeatherParams.model_json_schema()
В: Сколько стоит один вызов API для AI Agent?
О: Для GPT-4.1-mini: ввод $0.4/млн токенов, вывод $1.6/млн токенов. Типичный диалог Agent (с 2-3 вызовами инструментов) потребляет около 2000-5000 токенов, стоимость ~$0.001-$0.005. Через платформу-агрегатор API обычно можно получить ещё более выгодные цены.
В: Как отладить Function Calling? Что делать, если модель не вызывает инструмент?
О: Три направления проверки: 1) Описание инструмента должно быть чётким — модель решает на основе описания; 2) В system prompt явно укажите, какие инструменты доступны; 3) Используйте tool_choice={"type": "function", "function": {"name": "xxx"}} для принудительного вызова конкретного инструмента при тестировании.
Итоги и план действий
Разработка AI Agent в 2026 году — это уже не передовая технология с высоким порогом входа, а инженерный навык, которым должен владеть каждый разработчик.
Три шага для немедленного старта:
- Запустите первого Agent: скопируйте код примера с погодой из этой статьи, подставьте свой API Key — через 5 минут всё заработает
- Подключите свои бизнес-инструменты: оберните запросы к базе данных и сторонним API вашего проекта в функции инструментов
- Разверните в продакшене: добавьте обработку ошибок, контроль доступа и управление памятью диалога
Если вам нужно быстро подключить несколько моделей для тестирования, какая лучше подходит для вашего Agent-сценария, попробуйте Ofox.ai — один API Key для вызова GPT, Claude, Gemini, DeepSeek и других 50+ моделей, совместимость с OpenAI SDK, узлы ускорения в Китае на Alibaba Cloud / Volcano Cloud, бесплатный баланс при регистрации.
Справочные материалы
- OpenAI Function Calling — официальная документация
- Anthropic Tool Use — документация
- Google Gemini Function Calling — руководство
- OpenAI Agents SDK
- Claude Agent SDK — обзор
- Composio: полное руководство по Tool Calling
- Datawhale: создание интеллектуального агента с нуля
- Ofox.ai — документация для разработчиков


