⚙ Проект модуля 01

CLI-чат с несколькими LLM-провайдерами

Инструмент командной строки для общения сразу с несколькими языковыми моделями — с возможностью переключаться между провайдерами в реальном времени, сравнивать ответы и управлять историей диалога.

⏱ 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-5 you › А теперь ты объясни то же самое Anthropic Представьте официанта. Синхронный официант принимает заказ → идёт на кухню → ждёт → возвращает блюдо. Асинхронный принимает заказы от всех столиков, пока кухня готовит... [143 токена · 0.9 сек] you › /compare Напиши haiku про Python ⟳ Запрашиваю у 3 провайдеров одновременно... OpenAI Змея из кода / Циклы вьются тихо в ночь / Пробел — не таб Anthropic Отступы важны / Исключение поймано / Дзен побеждает Ollama Локальный ум спит / Без API ключа / Свобода в офлайн ────────────────────────────────────────────────────

Архитектура проекта

Проект строится вокруг паттерна Provider Abstraction: абстрактный базовый класс определяет контракт, каждый провайдер реализует его по-своему. CLI-слой и логика истории не знают, с каким провайдером работают.

100%
колёсико — масштаб  ·  зажать и тянуть — перемещение
CLI CORE ABSTRACT PROVIDERS TRANSPORT EXTERNAL 👤 Пользователь Terminal · stdin / stdout stdin Rich output main.py CLI Loop · asyncio commands.py Command Parser ui.py Rich · Live Display /cmd render r/w message + history /switch history.py Chat History · messages[] Provider Manager в составе main.py active_provider · switch() config.py Pydantic Settings .env API keys get_provider() providers/base.py — LLMProvider (ABC) chat() · stream_chat() · name · model implements openai.py gpt-4o · gpt-4o-mini anthropic.py claude-sonnet · haiku mistral.py mistral-large · small ollama.py local · any model httpx AsyncClient SSE Streaming · asyncio.gather() для /compare OpenAI API api.openai.com Anthropic API api.anthropic.com Mistral API api.mistral.ai Ollama localhost:11434 streaming response ↑ запрос / данные ответ / стриминг команда /switch конфигурация

Поддерживаемые провайдеры

OpenAI Cloud
gpt-4o
gpt-4o-mini
gpt-3.5-turbo
Anthropic Cloud
claude-opus-4-6
claude-sonnet-4-6
claude-haiku-4-5
Mistral Cloud
mistral-large
mistral-small
codestral
Ollama Local
llama3.2
qwen2.5
gemma3 (любая модель)
🔌
Ollama — без API-ключа
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 Показать доступные провайдеры и статус подключения /providers
/tokens Показать статистику использования токенов /tokens
/help Список всех команд с описаниями /help
/exit Завершить сессию /exit

Технический стек

🐍 Python 3.11+ ⚡ asyncio 🌐 httpx 🔷 pydantic-settings 🎨 rich 🔑 python-dotenv 📡 SSE streaming 🖥 openai SDK 🖥 anthropic SDK
📌
Почему не использовать готовые LLM-фреймворки?
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, цветовые темы
🗂 Структура Python-проекта — пакеты, pyproject.toml, ABC, dependency injection
🔑 Работа с LLM API — OpenAI, Anthropic, Mistral, Ollama — форматы запросов и ответов
🛡 Обработка ошибок API — rate limits, timeout, недоступный провайдер без падения приложения

Часть 2: Реализация проекта

Пишем код с нуля — от архитектуры до готового инструмента. Отдельный GitHub-репозиторий, полный разбор каждого файла.

Скоро →