Почему простые LLM-агенты не работают в продакшене
Если вы уже пробовали создавать AI-агентов на базе простых промптов или наивного RAG, то наверняка столкнулись с классическими проблемами: агент "галлюцинирует", теряет контекст в длинных диалогах, не умеет планировать сложные задачи и восстанавливаться после ошибок. Эта проблема особенно хорошо знакома тем, кто читал нашу статью "Production-ready AI-агент с нуля".
Ключевая ошибка: Разработчики пытаются запихнуть всю логику в один промпт. В результате получается монстр, который плохо масштабируется, тяжело отлаживается и не поддаётся контролю.
Современный AI-агент — это не просто "умный промпт". Это сложная система, состоящая из нескольких компонентов, каждый из которых решает свою задачу. В этой статье мы разберём архитектурный паттерн, который используют ведущие компании для создания продакшен-готовых агентов.
Архитектура современного AI-агента
В основе любой серьёзной агентной системы лежит три фундаментальных компонента:
| Компонент | Роль | Примеры технологий |
|---|---|---|
| Planner (Планировщик) | Разбивает цель на подзадачи, выбирает стратегию | Chain of Thought, Tree of Thoughts, ReAct |
| Executor (Исполнитель) | Выполняет конкретные действия, использует инструменты | MCP, LangChain Tools, AutoGen |
| Stateful Memory (Память с состоянием) | Хранит контекст, историю, знания | Vector DB, SQLite, Redis, Chroma |
1 Planner: мозг агента, который думает наперёд
Планировщик — это компонент, который отвечает на вопрос "Как решить эту задачу?". В отличие от простых LLM, которые пытаются сразу дать ответ, планировщик разбивает сложную цель на последовательность простых шагов.
Пример простого планировщика на Python:
class Planner:
def __init__(self, llm):
self.llm = llm
def create_plan(self, goal: str, available_tools: list) -> dict:
"""Создаёт план достижения цели"""
prompt = f"""
Цель: {goal}
Доступные инструменты: {', '.join(available_tools)}
Разбей цель на последовательность шагов.
Каждый шаг должен:
1. Быть конкретным и выполнимым
2. Использовать только доступные инструменты
3. Иметь чёткий критерий успеха
Ответ в формате JSON:
{{
"steps": [
{{"action": "название действия", "tool": "инструмент", "params": {{}}}}
]
}}
"""
response = self.llm.generate(prompt)
return json.loads(response)
2 Executor: руки агента, которые делают работу
Исполнитель получает план от планировщика и выполняет его шаг за шагом. Ключевая особенность хорошего исполнителя — умение работать с инструментами (tools) и обрабатывать ошибки.
Современный стандарт для работы с инструментами — MCP (Model Context Protocol). Это открытый протокол, который позволяет безопасно подключать внешние инструменты к LLM. В отличие от самописных интеграций, MCP обеспечивает:
- Единый интерфейс для всех инструментов
- Безопасное выполнение (инструменты работают в изолированной среде)
- Автоматическую документацию и обнаружение
- Поддержку streaming и асинхронных операций
class Executor:
def __init__(self, tools_registry):
self.tools = tools_registry
self.memory = [] # История выполнения
def execute_step(self, step: dict) -> dict:
"""Выполняет один шаг плана"""
try:
tool_name = step["tool"]
params = step["params"]
if tool_name not in self.tools:
return {
"status": "error",
"error": f"Инструмент {tool_name} не найден"
}
# Выполняем инструмент через MCP
result = self.tools[tool_name].execute(params)
# Сохраняем в память
self.memory.append({
"step": step,
"result": result,
"timestamp": datetime.now()
})
return {
"status": "success",
"result": result
}
except Exception as e:
# Восстановление после ошибки
return {
"status": "error",
"error": str(e),
"suggestion": self._suggest_recovery(step, e)
}
3 Stateful Memory: долговременная память агента
Самая критичная часть архитектуры — память. Как мы писали в статье "Agent Skills: как заставить ИИ-агента не тупить", контекстное окно LLM ограничено, и агент "забывает" всё, что не помещается в текущий контекст.
Stateful Memory решает эту проблему, предоставляя несколько типов памяти:
- Краткосрочная память — текущий диалог и контекст выполнения
- Долгосрочная память — векторная база знаний, документы, инструкции
- Процедурная память — история выполненных действий и их результатов
- Рабочая память — промежуточные вычисления и состояния
class StatefulMemory:
def __init__(self):
self.short_term = [] # Ограниченный размер
self.long_term = ChromaVectorStore() # Vector DB
self.procedural = SQLiteStore() # SQLite для структурированных данных
def remember(self, key: str, query: str, limit: int = 5) -> list:
"""Извлекает релевантные воспоминания"""
# Ищем в долгосрочной памяти (векторный поиск)
vector_results = self.long_term.similarity_search(query, k=limit)
# Ищем в процедурной памяти (SQL запрос)
procedural_results = self.procedural.query(
"SELECT * FROM memories WHERE key LIKE ?",
[f"%{key}%"]
)
# Объединяем и ранжируем
return self._rank_and_merge(vector_results, procedural_results)
def learn(self, experience: dict):
"""Сохраняет новый опыт"""
# Сохраняем в краткосрочную память
self.short_term.append(experience)
# Если опыт важен — сохраняем в долгосрочную
if self._is_important(experience):
self.long_term.add(
text=experience["summary"],
metadata=experience["metadata"]
)
# Сохраняем в процедурную память
self.procedural.insert("memories", experience)
Полная архитектура: как компоненты взаимодействуют
Теперь соберём все компоненты в единую систему. Современный агент работает в цикле наблюдение-планирование-действие-рефлексия:
class ModernAIAgent:
def __init__(self, llm, tools, memory_config):
self.planner = Planner(llm)
self.executor = Executor(tools)
self.memory = StatefulMemory(**memory_config)
self.max_iterations = 10
def run(self, goal: str) -> dict:
"""Основной цикл выполнения агента"""
# 1. Загружаем релевантный контекст из памяти
context = self.memory.remember("similar_goals", goal)
# 2. Создаём начальный план
available_tools = list(self.executor.tools.keys())
plan = self.planner.create_plan(goal, available_tools, context)
results = []
# 3. Цикл выполнения
for iteration in range(self.max_iterations):
for step in plan["steps"]:
# Выполняем шаг
result = self.executor.execute_step(step)
# Сохраняем результат
results.append(result)
# Если ошибка — перепланируем
if result["status"] == "error":
new_plan = self.planner.replan(
goal,
current_state=results,
error=result["error"]
)
plan = new_plan
break
# Рефлексия: анализируем результат
reflection = self._reflect_on_result(result, step)
if reflection["needs_adjustment"]:
plan = self._adjust_plan(plan, reflection)
# Проверяем, достигнута ли цель
if self._goal_achieved(results, goal):
break
# 4. Сохраняем опыт в память
self.memory.learn({
"goal": goal,
"results": results,
"success": self._goal_achieved(results, goal),
"summary": self._generate_summary(goal, results)
})
return {
"success": self._goal_achieved(results, goal),
"results": results,
"iterations": iteration + 1
}
Практические рекомендации по реализации
Выбор моделей для разных компонентов
Не используйте одну и ту же модель для всех задач! Планировщик нуждается в моделях с сильным reasoning, исполнитель — в моделях, которые хорошо следуют инструкциям. Обратите внимание на топ-5 open-source моделей для агентов.
| Компонент | Рекомендуемые модели | Почему |
|---|---|---|
| Planner | Claude 3.5 Sonnet, GPT-4o, DeepSeek Coder | Сильное reasoning, умение разбивать задачи |
| Executor | Gemini Flash, Llama 3.1 8B, Mixtral | Быстрое выполнение, точное следование инструкциям |
| Reflection | GPT-4, Claude 3 Opus | Глубокий анализ, критическое мышление |
Реализация MCP-инструментов
MCP (Model Context Protocol) — это будущее работы с инструментами. Вот как создать простой MCP-сервер:
# mcp_server.py
from mcp import Server, StdioServerTransport
import asyncio
class CalculatorTool:
@staticmethod
def add(a: float, b: float) -> float:
return a + b
@staticmethod
def multiply(a: float, b: float) -> float:
return a * b
async def main():
# Создаём сервер MCP
server = Server("calculator-server")
# Регистрируем инструменты
@server.list_tools()
async def handle_list_tools():
return [
{
"name": "add",
"description": "Складывает два числа",
"inputSchema": {
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
}
}
},
{
"name": "multiply",
"description": "Умножает два числа",
"inputSchema": {
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
}
}
}
]
# Запускаем сервер
async with StdioServerTransport() as transport:
await server.run(transport)
if __name__ == "__main__":
asyncio.run(main())
Распространённые ошибки и как их избежать
Ошибка 1: Слишком сложный план
Планировщик генерирует план из 50 шагов для простой задачи. Решение: Ограничивайте максимальное количество шагов, добавьте проверку сложности плана.
Ошибка 2: Бесконечные циклы
Агент зацикливается на одном шаге. Решение: Добавьте счётчик итераций и механизм принудительного выхода.
Ошибка 3: Переполнение памяти
Stateful memory растёт бесконечно. Решение: Реализуйте механизм забывания, приоритетное хранение, компрессию старых воспоминаний.
Ошибка 4: Небезопасные инструменты
Агент получает доступ к опасным операциям. Решение: Используйте MCP с sandbox-режимом, добавляйте approval-шаги для критических операций.
Продвинутые техники
Иерархическое планирование
Для очень сложных задач используйте иерархическое планирование: высокоуровневый планировщик разбивает задачу на подзадачи, каждая подзадача обрабатывается своим специализированным агентом. Это похоже на то, как работают AI-агенты как сотрудники в организации.
Мультимодальная память
Современные агенты должны работать не только с текстом. Добавьте в Stateful Memory поддержку:
- Векторные эмбеддинги изображений
- Транскрипты аудио и видео
- Структурированные данные (JSON, таблицы)
- Временные ряды и метрики
Обучение на опыте (Learning from Experience)
Лучшие агенты учатся на своих ошибках. Реализуйте механизм, который:
- Анализирует неудачные выполнения
- Извлекает уроки ("не использовать инструмент X в ситуации Y")
- Обновляет инструкции и промпты планировщика
- Создаёт шаблоны для похожих задач в будущем
Заключение
Проектирование современного AI-агента — это не магия, а инженерная дисциплина. Разделение ответственности на planner, executor и stateful memory позволяет создавать системы, которые:
- Масштабируются — можно улучшать каждый компонент независимо
- Надёжны — ошибки в одном шаге не ломают всю систему
- Обучаемы — агент накапливает опыт и становится умнее
- Контролируемы — вы всегда понимаете, что делает агент и почему
Следующий шаг после освоения базовой архитектуры — изучение продвинутых тем: распределённые агенты, мультиагентные системы, reinforcement learning для оптимизации поведения. Если вы хотите углубиться в тему, рекомендую бесплатный курс по разработке AI-агентов.