Архитектура Agent Lab
Agent Lab — это платформа для создания и управления ИИ-агентами на базе LangGraph, разработанная с использованием подхода Database-First. Это означает, что вся конфигурация и состояние системы хранятся в базе данных, а код определяет только логику поведения.
Принципы архитектуры
- Database-First: Вся конфигурация агентов, Flow и инструментов хранится в БД. Код определяет только поведение, но не структуру.
- Единообразие: Агенты, созданные через код и через пользовательский интерфейс, работают идентично.
- Фабричный паттерн: Все основные сущности (агенты, Flow, инструменты) создаются через соответствующие фабрики, которые загружают конфигурацию из БД (
AgentFactory,FlowFactory,ToolFactory). - Модульность: Каждый компонент системы независим и заменяем. Агенты не зависят от конкретной платформы (Telegram/WhatsApp/Web), а инструменты работают независимо от агентов.
- LangGraph-native: Активное использование современных возможностей библиотеки LangGraph для построения сложных графов состояний, управления памятью и точками восстановления (
checkpointer,GraphInterrupt,State). - Асинхронность: Вся архитектура полностью асинхронна. Используются
async/awaitдля всех операций с БД, HTTP, LLM. Все инструменты, фабрики и сервисы реализованы асинхронно. - Контекст выполнения: Использование глобального контекста (
app/core/context.py) для доступа к текущему пользователю, активной компании и переменным Flow, обеспечивая изоляцию данных и биллинг.
Ключевые компоненты
Storage (Key-Value База данных)
Низкоуровневое key-value хранилище на базе PostgreSQL, используемое для персистентности всех сущностей платформы. Доступ к данным осуществляется через стандартизированные репозитории.
Примеры ключей:
- agent:{agent_id}: Конфигурация агентов.
- flow:{flow_id}: Конфигурация Flow.
- task:{task_id}: Задачи для обработки асинхронными воркерами.
- session:{session_id}: Сессии диалогов.
- user:{user_id}: Данные пользователей.
- company:{company_id}: Данные компаний (мультитенантность).
- subdomain:{subdomain}: Маппинг поддоменов к компаниям.
- var:{key}: Глобальные и секретные переменные компании.
Расположение: app/db/database.py, app/db/repositories/*.py
Agents
Базовый строительный блок логики ИИ-бота. Агенты наследуются от BaseAgent и могут быть двух основных типов:
- ReAct-агенты: Классические реактивные агенты, основанные на промптах и использовании инструментов (tools) для принятия решений и выполнения действий.
- StateGraph-агенты: Агенты, построенные на LangGraph
StateGraph, позволяющие создавать сложную, многошаговую логику с управлением состоянием, ветвлениями и циклами.
Ключевые аспекты:
- Промпт: Основная инструкция для LLM, определяющая поведение агента.
- Инструменты: Набор функций, которые агент может вызывать для взаимодействия с внешним миром или выполнения специфических задач.
- Память: Агенты имеют доступ к полной истории диалога (через LangGraph checkpointer) и глобальным переменным Flow.
Расположение:
- app/agents/base.py: Базовый класс для всех агентов.
- app/agents/react_agent.py: Пример реализации ReAct-агента.
- app/agents/stategraph_agent.py: Пример реализации StateGraph-агента.
- app/agents/*: Директории с конкретными реализациями агентов (например, calculator, weather).
Flows
Flow — это административная обертка над одним или несколькими агентами, представляющая собой законченный сценарий или бота. Он определяет: - Entry Point Agent: Главный агент, который обрабатывает входящие запросы. - Каналы: Каналы, через которые Flow взаимодействует с пользователями (Telegram, API, Web, WhatsApp, AmoCRM). - Конфигурация: Общие настройки Flow (таймауты, количество повторов, RAG-настройки). - Переменные Flow: Переменные, доступные всем агентам внутри этого Flow.
Расположение: app/flows/flow.py
Tools
Инструменты — это асинхронные функции, которые агенты могут вызывать для выполнения конкретных действий. Они создаются с помощью специального декоратора @tool, который добавляет метаданные для биллинга и валидации.
Пример:
from app.core.tool_decorator import tool
@tool(cost=0.1, billing_name="weather_api")
async def get_weather(city: str) -> str:
"""Получить текущую погоду в указанном городе."""
# Асинхронный вызов внешнего API погоды
return f"Погода в {city}: солнечно"
Расположение: app/tools/*.py
Interfaces
Модули, ответственные за адаптацию специфичных для каждой платформы форматов сообщений к унифицированному внутреннему представлению Message, и наоборот. Это обеспечивает модульность и независимость агентов от каналов связи.
Основные интерфейсы:
- TelegramInterface: Для взаимодействия с Telegram ботами.
- WhatsAppInterface: Для интеграции с WhatsApp Business Cloud API.
- APIInterface: Для взаимодействия через REST API.
- WebInterface: Для встраиваемого веб-чата.
- AmoCRMInterface: Для интеграции с AmoCRM.
Расположение: app/interfaces/*.py
Task Processor (Воркер задач)
Асинхронный фоновый воркер, который обрабатывает задачи, поставленные в очередь (например, входящие сообщения от пользователей). Он отвечает за:
1. Извлечение задач из БД со статусом pending.
2. Инициализацию соответствующего Flow и агента из его конфигурации.
3. Запуск выполнения графа LangGraph.
4. Обработку GraphInterrupt для запроса дополнительной информации у пользователя.
5. Отправку результатов обработки обратно через соответствующий Interface.
Расположение: app/workers/task_processor.py
Billing Service
Сервис, отвечающий за учет и тарификацию использования ресурсов (LLM-токены, вызовы инструментов) на уровне каждой компании. Поддерживает различные тарифные планы и лимиты расходов.
Расположение: app/services/billing_service.py
LLM Factory
Фабрика для создания экземпляров LLM-моделей. Обеспечивает единый унифицированный API для работы с различными провайдерами (OpenAI, Anthropic, Google и др.) через OpenRouter, а также автоматический учет токенов и биллинг.
Расположение:
- app/core/llm_factory.py: Основная фабрика LLM.
- app/core/llm_billing_wrapper.py: Обертка для биллинга LLM-запросов.
Identity System
Система управления пользователями и компаниями, обеспечивающая мультитенантность и авторизацию. Включает: - User: Модель пользователя. - Company: Модель компании (рабочего пространства). - AuthProvider: Интеграция с внешними провайдерами OAuth (например, Yandex, Google). - AuthSession: Управление сессиями авторизации.
Расположение: app/identity/*.py
Поток данных
1. Создание или обновление агента/Flow
graph LR
A[Разработчик / UI] --> B{Создание/Обновление Agent/Flow в коде/UI}
B --> C[Migrator (при старте/по запросу)]
C --> D{Создание/Обновление AgentConfig/FlowConfig}
D --> E[Storage (База данных)]
2. Обработка входящего запроса
graph LR
A[Пользователь] --> B[Канал (Telegram/API/Web)]
B --> C[Interface (TelegramInterface/APIInterface/WebInterface)]
C --> D{Формирование Message}
D --> E[FlowFactory (создает Task в БД)]
E --> F[Storage (БД)]
F --> G[TaskProcessor (воркер)]
G --> H[AgentFactory (создает агента из БД)]
H --> I[Агент (LangGraph)]
I --> J{Результат обработки}
J --> K[Interface (отправляет ответ)]
K --> L[Канал] --> M[Пользователь]
3. Запрос дополнительной информации у пользователя
graph LR
A[Агент (LangGraph)] --> B{Вызов ask_user(question)}
B --> C[LangGraph (GraphInterrupt с вопросом)]
C --> D[TaskProcessor (ловит interrupt)]
D --> E[Interface (отправляет вопрос пользователю)]
E --> F[Пользователь (отвечает)]
F --> G[Interface (формирует Message с ответом)]
G --> H[TaskProcessor (возобновляет граф с ответом)]
H --> A
Миграция
Механизм автоматического сканирования кодовой базы и синхронизации конфигурации агентов и Flow с базой данных.
Процесс миграции:
1. При старте приложения Migrator сканирует директории app/agents/ и app/flows/.
2. Находит классы, наследующиеся от BaseAgent и BaseFlow.
3. Извлекает метаданные (название, промпт, инструменты, платформы) из этих классов.
4. Создает или обновляет соответствующие записи AgentConfig и FlowConfig в Storage (БД).
5. Если Flow или агент уже существуют в БД, Migrator обновляет их, сохраняя при этом пользовательские изменения (например, из UI), если они не конфликтуют с кодом.
Расположение: app/core/migrator.py
Контекст выполнения
Механизм contextvars для управления глобальным контекстом запроса в асинхронной среде. Это позволяет безопасно получать доступ к информации, специфичной для текущего запроса, без явной передачи параметров между функциями.
Использование:
from app.core.context import get_context
async def my_function():
context = get_context() # Получаем текущий контекст
user = context.user
company = context.active_company
flow_id = context.flow_id
# ... использование данных контекста
Применение: - Изоляция данных: Обеспечивает, что каждый запрос обрабатывается в своем изолированном контексте, предотвращая утечки данных между разными пользователями или компаниями. - Биллинг: Позволяет системе биллинга точно определить, кто и сколько ресурсов потребил. - Авторизация: Упрощает проверку прав доступа к ресурсам.
Расположение: app/core/context.py
Веб-интерфейс (Frontend)
Пользовательский интерфейс платформы, реализованный на FastAPI и Jinja2 с использованием HTMX для динамического обновления контента. Включает в себя следующие основные модули: - Builder: Визуальный конструктор для создания и редактирования Flow. - Bots: Управление и настройка ботов. - Store: Магазин готовых Flow. - Chats: История диалогов. - History: Детальная статистика и логи запросов. - Variables: Управление переменными. - Billing: Мониторинг расходов. - Admin: Модуль для административных задач (управление компаниями, пользователями).
Расположение: app/frontend/
База данных
Основное хранилище данных на базе PostgreSQL. Использует две основные таблицы:
1. storage: Key-value хранилище для всех конфигураций и метаданных.
2. checkpoints: Хранит состояния LangGraph для возобновляемых Flow.
Расположение: app/db/database.py, app/db/models.py
Конфигурация
Конфигурация приложения управляется через JSON файлы (conf.json, conf.local.json). Позволяет настраивать параметры базы данных, LLM-провайдеров, серверные настройки и другие параметры.
Расположение: conf.json, conf.local.json, app/core/config.py
Подробнее: Документация по конфигурации
Развертывание
Канал поддерживает гибкие варианты развертывания, включая Docker-контейнеры для изоляции и масштабирования.
Примеры:
# Запуск через Docker Compose для локальной разработки
docker-compose up -d
# Локальный запуск (требуется установленный uv)
uv run python run.py
Подробнее: Документация по развертыванию