telegram-cli-bot/AI_PROVIDER_ARCHITECTURE.md

9.2 KiB
Raw Blame History

AI Provider Architecture v0.7.1

Обзор

Начиная с версии 0.7.1 бот использует универсальный интерфейс для всех AI-провайдеров. Это позволяет любому AI-провайдеру работать с инструментами (SSH, DDGS, RSS, Cron) одинаковым образом.

Архитектура

┌─────────────────────────────────────────────────────────┐
│                   Bot (bot.py)                          │
│                                                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │          AIProviderManager                      │   │
│  │  ┌─────────────┐  ┌──────────────────┐         │   │
│  │  │  QwenCode   │  │  GigaChat        │  ...    │   │
│  │  │  Provider   │  │  Provider        │         │   │
│  │  └──────┬──────┘  └────────┬─────────┘         │   │
│  │         │                  │                    │   │
│  │         └──────────┬───────┘                    │   │
│  │                    │                            │   │
│  │         ┌──────────▼──────────┐                 │   │
│  │         │  BaseAIProvider     │                 │   │
│  │         │  (Protocol)         │                 │   │
│  │         └──────────┬──────────┘                 │   │
│  └────────────────────┼────────────────────────────┘   │
│                       │                                 │
│         ┌─────────────┴──────────────┐                 │
│         │      Tools Registry        │                 │
│         │  ┌──────┐ ┌─────┐ ┌────┐  │                 │
│         │  │ SSH  │ │DDGS │ │RSS │  │                 │
│         │  └──────┘ └─────┘ └────┘  │                 │
│         └────────────────────────────┘                 │
└─────────────────────────────────────────────────────────┘

Ключевые компоненты

1. BaseAIProvider (bot/base_ai_provider.py)

Базовый протокол для всех AI-провайдеров:

class BaseAIProvider(ABC):
    @property
    def provider_name(self) -> str: ...
    
    @property
    def supports_tools(self) -> bool: ...
    
    @property
    def supports_streaming(self) -> bool: ...
    
    async def chat(...) -> ProviderResponse: ...
    
    async def process_with_tools(...) -> ProviderResponse: ...

Ключевая особенность: Метод process_with_tools реализует универсальный цикл:

  1. Отправить запрос провайдеру
  2. Распарсить вызовы инструментов
  3. Выполнить инструменты
  4. Отправить результаты обратно
  5. Повторить пока не будет финального ответа

2. QwenCodeProvider (bot/providers/qwen_provider.py)

Адаптер для Qwen Code CLI:

  • Нативная поддержка инструментов через stream-json
  • Потоковый вывод (on_chunk callback)
  • Парсинг tool calls из JSON ответа

3. GigaChatProvider (bot/providers/gigachat_provider.py)

Адаптер для GigaChat API:

  • Эмуляция инструментов через текстовые блоки
  • Парсинг ```tool {...} ``` из текста
  • Автоматическое формирование tool prompt

4. AIProviderManager (bot/ai_provider_manager.py)

Управление провайдерами:

  • Переключение между провайдерами
  • Единый реестр инструментов для всех
  • Маршрутизация запросов

Как это работает

Сценарий 1: Qwen Code

# Пользователь: "проверь нагрузку на сервере"

1. AIProviderManager получает запрос
2. Вызывает QwenCodeProvider.process_with_tools()
3. Qwen возвращает:
   {
     "content": "Проверяю нагрузку...",
     "tool_calls": [{"name": "ssh_tool", "args": {"command": "uptime"}}]
   }
4. AIProviderManager выполняет ssh_tool.execute()
5. Результат возвращается Qwen для финального ответа

Сценарий 2: GigaChat

# Пользователь: "найди новости про Python"

1. AIProviderManager получает запрос
2. Вызывает GigaChatProvider.process_with_tools()
3. GigaChat возвращает текст:
   "Ищу новости...
   ```tool
   {"name": "ddgs_tool", "arguments": {"query": "Python news 2026"}}
   ```"
4. GigaChatProvider._parse_tool_calls() извлекает вызов
5. AIProviderManager выполняет ddgs_tool.execute()
6. Результат возвращается GigaChat для продолжения

Добавление нового провайдера

Чтобы добавить новый AI-провайдер (например, OpenAI):

# bot/providers/openai_provider.py

from bot.base_ai_provider import BaseAIProvider, ProviderResponse, AIMessage, ToolCall

class OpenAIProvider(BaseAIProvider):
    @property
    def provider_name(self) -> str:
        return "OpenAI"
    
    @property
    def supports_tools(self) -> bool:
        return True  # Или False если не поддерживает
    
    @property
    def supports_streaming(self) -> bool:
        return True
    
    async def chat(...) -> ProviderResponse:
        # Реализация через OpenAI API
        ...

Затем зарегистрировать в AIProviderManager._init_providers():

from bot.providers.openai_provider import OpenAIProvider
self._providers[AIProvider.OPENAI.value] = OpenAIAI(api_key=...)

Преимущества архитектуры

Преимущество Описание
Единый интерфейс Все провайдеры работают одинаково
Инструменты для всех Любой провайдер может использовать SSH, DDGS, RSS, Cron
Легкое расширение Новый провайдер = один класс
Совместимость Старый код продолжает работать
Гибкость Можно переключаться на лету

Настройка

Для Qwen Code

# Требуется установленный qwen-code CLI
npm install -g @anthropic-ai/qwen-code

Для GigaChat

Добавьте в .env:

GIGACHAT_CLIENT_ID=ваш-client-id-uuid
GIGACHAT_CLIENT_SECRET=ваш-client-secret
GIGACHAT_SCOPE=GIGACHAT_API_PERS

Переключение провайдера

/ai qwen      # Переключиться на Qwen Code
/ai gigachat  # Переключиться на GigaChat
/ai           # Показать текущего провайдера

Статус провайдеров

Провайдер Инструменты Стриминг Статус
Qwen Code Нативно Готов
GigaChat Эмуляция Готов
OpenAI Нативно 🔜 Скоро
YandexGPT Эмуляция 🔜 Скоро

Миграция с v0.5.x

Старый код:

# Прямой вызов qwen_manager
result = await qwen_manager.run_task(...)

Новый код:

# Через AIProviderManager
result = await ai_provider_manager.execute_request(
    provider_id="qwen",
    user_id=user_id,
    prompt="запрос"
)

Будущие улучшения

  • Поддержка OpenAI Provider
  • YandexGPT Provider
  • Автоматический выбор провайдера по типу задачи
  • Балансировка нагрузки между провайдерами
  • Кэширование ответов
  • Fallback при ошибке провайдера

Версия: 0.7.1 Дата: 2026-02-26