Инструмент командной строки для общения сразу с несколькими языковыми моделями —
с возможностью переключаться между провайдерами в реальном времени, сравнивать ответы
и управлять историей диалога.
⏱ 2–3 дня реализации·🐍 Python 3.11+·📦 Portfolio-ready·🔗 GitHub репозиторий
Зачем этот проект?
Модуль 01 даёт разрозненные навыки: asyncio, Pydantic, httpx, LLM API, промптинг.
Проект соединяет всё это в одну работающую систему — и закрепляет понимание того,
как эти инструменты взаимодействуют в реальном коде.
CLI-чат — это не игрушка. Разработчики постоянно сравнивают, какая модель лучше справляется
с конкретной задачей: GPT-4o или Claude? Mistral или локальный Ollama?
Иметь такой инструмент под рукой — практически необходимость.
💡
Паттерн Provider Abstraction
Ключевая идея проекта — абстракция провайдера. Один интерфейс, несколько реализаций.
Этот паттерн встречается во всех серьёзных AI-системах и станет основой для будущих модулей.
Как это выглядит в работе
╔════════════════════════════════════════════════════╗║ CLI LLM Chat · v1.0 · DataTalks.ru ║╚════════════════════════════════════════════════════╝Активный провайдер: OpenAI · gpt-4o-miniВведите /help для списка команд────────────────────────────────────────────────────you› Объясни разницу между синхронным и асинхронным кодомOpenAI› Синхронный код выполняется последовательно — каждая
операция ждёт завершения предыдущей. Асинхронный позволяет
«переключаться» между задачами во время ожидания (I/O)...
[128 токенов · 1.2 сек]you› /switch anthropic ✓ Переключено на Anthropic · claude-haiku-4-5you› А теперь ты объясни то же самоеAnthropic› Представьте официанта. Синхронный официант
принимает заказ → идёт на кухню → ждёт → возвращает блюдо.
Асинхронный принимает заказы от всех столиков, пока кухня готовит...
[143 токена · 0.9 сек]you› /compare Напиши haiku про Python ⟳ Запрашиваю у 3 провайдеров одновременно...OpenAI› Змея из кода /
Циклы вьются тихо в ночь /
Пробел — не таб
Anthropic› Отступы важны /
Исключение поймано /
Дзен побеждает
Ollama› Локальный ум спит /
Без API ключа /
Свобода в офлайн
────────────────────────────────────────────────────
Архитектура проекта
Проект строится вокруг паттерна Provider Abstraction:
абстрактный базовый класс определяет контракт, каждый провайдер реализует его по-своему.
CLI-слой и логика истории не знают, с каким провайдером работают.
100%
колёсико — масштаб · зажать и тянуть — перемещение
Ollama запускается локально и совместим с OpenAI API. Идеально для офлайн-работы
или когда не хочется тратить токены. Нужен только запущенный ollama serve.
Функциональность
⚡
Streaming в реальном времени
Ответ выводится токен за токеном, как в ChatGPT. Используется asyncio + httpx с Server-Sent Events.
🔀
Переключение провайдера
Команда /switch меняет провайдера без перезапуска. История диалога сохраняется при переходе.
⚖
Режим сравнения
/compare отправляет один промпт всем провайдерам параллельно. Помогает выбрать лучшую модель под задачу.
🗂
История диалога
Полная история передаётся в контекст модели. /clear сбрасывает, /history — показывает, /save — экспортирует в JSON/MD.
🎨
Rich-интерфейс
Цветовое кодирование по провайдеру, прогресс-индикаторы, форматирование кода и markdown в терминале.
🔒
Конфигурация через .env
API-ключи, модели по умолчанию, системный промпт — всё через Pydantic Settings. Никаких секретов в коде.
Команды CLI
Команда
Описание
Пример
/switch <provider>
Переключить активного провайдера
/switch anthropic
/model <name>
Сменить модель у текущего провайдера
/model gpt-4o
/compare <prompt>
Отправить промпт всем провайдерам параллельно
/compare Объясни рекурсию
/system <text>
Установить системный промпт для сессии
/system Ты senior Python dev
/history
Показать историю текущей сессии
/history
/clear
Очистить историю диалога
/clear
/save [filename]
Сохранить историю в JSON или Markdown
/save session.md
/providers
Показать доступные провайдеры и статус подключения
LangChain или LlamaIndex скроют детали реализации. В этом проекте мы намеренно
делаем всё руками — через httpx и официальные SDK — чтобы понять,
что происходит «под капотом». Фреймворки придут в Модуле 02.
Структура проекта
cli-llm-chat/
├── main.py# Точка входа, основной цикл CLI
├── config.py# Pydantic Settings, загрузка .env
├── commands.py# Парсер и обработчики /команд
├── history.py# Менеджер истории диалога
├── ui.py# Rich-компоненты: рендер, цвета
│
├── providers/
│ ├── base.py# ABC: LLMProvider, ChatMessage
│ ├── openai.py# OpenAI / OpenAI-совместимые API
│ ├── anthropic.py# Anthropic Messages API
│ ├── mistral.py# Mistral AI API
│ └── ollama.py# Ollama (localhost:11434)
│
├── .env.example# Шаблон конфигурации
├── pyproject.toml# Зависимости (uv/poetry)
└── README.md# Установка и использование
Ключевые решения архитектуры
1. Абстрактный базовый класс провайдера
Каждый провайдер реализует два метода: chat() для обычного запроса
и stream_chat() для стриминга. Provider Manager не знает,
с каким провайдером работает — только вызывает методы интерфейса.
2. Асинхронный стриминг через asyncio
Все провайдеры используют async for chunk in response.
Для режима сравнения (/compare) запросы запускаются параллельно
через asyncio.gather() — одновременно ко всем провайдерам.
3. Конфигурация через Pydantic Settings
Все настройки (API-ключи, модели по умолчанию, URL для Ollama)
описаны как Pydantic-модель. Загружается из .env файла автоматически.
Невалидная конфигурация — ошибка при старте, не в рантайме.
4. Неизменяемая история + форматирование под провайдера
История хранится в нейтральном формате (ChatMessage).
Каждый провайдер сам конвертирует её в нужный формат:
OpenAI ждёт {"role": "...", "content": "..."},
Anthropic — отдельный system параметр.
Что закрепляет этот проект
🧩Provider Abstraction Pattern — полиморфизм на практике, единый интерфейс для разных API
⚡Async streaming — asyncio, async generators, parallel requests через gather()
🔷Pydantic Settings — типизированная конфигурация из .env, валидация при старте
🌐httpx async клиент — SSE-стриминг, timeout, retry-логика, headers управление
🎨Rich CLI UI — Live display, Panel, Syntax highlighting, цветовые темы