Logo Craft Homelab Docs Контакты Telegram
AI-агенты: архитектура — Planning, tools, memory
Wed Jan 07 2026

AI-агенты: архитектура

Архитектура AI-агентов — это не эволюция чат-ботов, а фундаментальное усложнение системы. Разработчики, пытающиеся “вклеить” LLM в существующий кодbase, получают непредсказуемые поведения в продакшене. Ключевая проблема: агенты требуют параллельного управления тремя асинхронными контурами: планированием, инструментами и памятью. Без жесткого разделения контуров вы получаете “спагетти” из промптов, где LLM одновременно пытается решить задачу, выбрать инструмент и вспомнить контекст.

Архитектурные контуры: железные правила

Любой продакшен-агент строится вокруг трех независимых контуров, работающих через event-driven шину. Попытка объединить их в одном промпте приведет к коллапсу.

Контур планирования: за пределами LLM

Планирование — это не вызов llm.invoke(). Это управление гипотезами и оценкой решений в отдельном слое. Два рабочих паттерна:

  • ReAct (Reason+Act): Цикл “гипотеза → действие → наблюдение”. Проблема: экспоненциальный рост шагов при сложных задачах. Для 10 задач агент генерирует до 10! комбинаций.
  • Tree of Thoughts (ToT): Параллельная оценка веток с ранней остановкой. Требует 5-10x больше вычислений, но дает детерминированные пути.
# Упрощенный ToT-планировщик (без векторизации)
class TreeOfThoughts:
    def __init__(self, llm, max_depth=3):
        self.llm = llm
        self.max_depth = max_depth
    
    def generate_branches(self, task: str, depth: int) -> List[str]:
        # Генерация гипотез с ограничением глубины
        if depth >= self.max_depth:
            return []
        prompt = f"Разложи задачу '{task}' на {depth+1} шага. Верни JSON: {{'steps': [...]}}"
        return json.loads(self.llm.invoke(prompt))["steps"]

    def evaluate_branch(self, branch: str) -> float:
        # Оценка гипотезы через LLM
        prompt = f"Оцени качество плана: '{branch}' (от 0 до 1)"
        return float(self.llm.invoke(prompt))

# Trade-off: ToT увеличивает задержку на 2-5 секунд, но снижает ошибки планирования на 40%

Контур инструментов: нейро-API мост

Инструменты — это не просто функции, а конвертированные в JSON API с жесткими контрактами. Основные ошибки:

  • Абстрактные описания: “Добавить в БД” без схемы → LLM генерирует невалидные данные.
  • Отсутствие retry-логики: Временные падения API приводят к сбою всей цепочки.
# Инструмент с idempotent retry и валидацией
from pydantic import BaseModel, Field
from tenacity import retry, stop_after_attempt, wait_exponential

class UserAction(BaseModel):
    user_id: str = Field(..., regex="^[a-f0-9]{24}$")
    action: Literal["add", "remove"]

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=4, max=10)
)
def db_tool(user_action: UserAction) -> str:
    # Критично: validate() выбросит ValidationError при неверном формате
    try:
        return db.execute(user_action.model_dump())
    except DeadlockError:
        raise  # Не перехватываем системные ошибки
    except Exception:
        return "RETRY"  # Специальный код для LLM

# Trade-off: Валидация добавляет 50-200мс задержки, но экономит 90% времени на исправление ошибок

Контур памяти: трехуровневая архитектура

Память агентов — это не просто ConversationBufferMemory. Три независимых слоя:

  1. Контекстное окно: До 128K токенов для диалога.
  2. Векторная память: Embeddings для долгосрочных правил.
  3. Сессионное хранилище: Данные пользователя (Redis/Mongo).
# Класс памяти с изоляцией сессий
class AgentMemory:
    def __init__(self):
        self.context = {}  # user_id: ConversationBufferMemory
        self.vector_store = FAISS.from_texts([...], embeddings)
        self.sessions = Redis()  # user_id: session_data
    
    def get_context(self, user_id: str) -> str:
        # Возврат контекста + релевантных правил из вектора
        rules = self.vector_store.similarity_search(user_id)
        return self.context[user_id].buffer + "\n".join(rules)

# Trade-off: Векторное хранилище увеличивает RAM на 1-5GB на 1000 агентов, но снижает "галлюцинации" на 60%

Мультиагентные системы: координация без deadlock

Для сложных задач используем распределенные агенты. Ключевые паттерны:

  • Master-Agent: Планирование через POMDP (Partially Observable Markov Decision Process).
  • Peer-to-Peer: Обмен сообщениями через Kafka/RabbitMQ.
graph TD
    A[Master-Agent] --> B[POMDP Planner]
    B --> C[Worker1]
    B --> D[Worker2]
    C --> E[API1]
    D --> F[API2]
    E -->|Event| G[State Store]
    F -->|Event| G

# Trade-off: Peer-to-Peer отказоустойчивее, но увеличивает сложность на 200% для 5+ агентов

Узкие места, которые убьют систему в продакшене

  1. Latency: Цепочки ReAct приводят к 10+ секундам задержки. Решение: кеширование результатов инструментов с TTL 5 минут.
  2. Cost: ToT с 3 ветками увеличивает стоимость вызова в 7x. Требует dynamic scaling based on task complexity.
  3. State Bleed: “Утечка контекста” между пользователями при общей памяти. Решение: обязательная изоляция по user_id.
  4. Debug Hell: Невозможно воспроизвести шаги принятия решений. Решение: logging всех промптов в ClickHouse с метками времени.

Когда использовать, а когда — нет

Использовать если:

  • Задачи требуют многошагового планирования (анализ финансовых отчетов).
  • Интеграция с 10+ API с разными схемами ответов.
  • Система должна адаптироваться к долгосрочным изменениям (например, изменения в правилах).

Не использовать если:

  • Простой FAQ-бот (лучше RAG).
  • Детерминированные задачи (калькулятор, поиск по БД).
  • Бюджет на API < $1000/месяц для 1000+ запросов.

AI-агенты — это не волшебная палочка, а дорогостоящий инженерный инструмент. Начните с ReAct для POC, добавляйте инструменты только при реальной необходимости, а мультиагентные системы проектируйте через event-driven архитектуры. Иначе получите черную дыру, которая сожжет ваш API-лимит и взорвется при первой нагрузке.