Перейти к основному содержанию
LangChain — фреймворк для приложений на базе LLM: цепочки, агенты, вызов функций, структурированный вывод. На SpeShu.AI его настраивают через OpenAI-совместимый класс ChatOpenAI из пакета langchain-openai, указав адрес шлюза вместо адреса провайдера по умолчанию.
Подключение сводится к двум значениям: base_url = "https://speshu.ai/api/v1" и API-ключ. Эндпоинт /api/v1/chat/completions совместим с OpenAI Chat Completions, поэтому менять код фреймворка не нужно — достаточно задать адрес шлюза и ключ. Ключ создаётся в личном кабинете, подробности — в разделе Аутентификация.

Установка

langchain-openai даёт класс ChatOpenAI. Документация по нему верна для langchain-openai 0.2 и новее.

Настройка

Два параметра конструктора — model и base_url:
Python
api_key не передавайте литералом в коде. Если параметр не задан, класс возьмёт ключ из OPENAI_API_KEY — переменной с чужим именем, которую легко забыть при развёртывании. Читайте ключ из SPESHU_API_KEY явно.

Возьмите идентификатор модели из каталога

Идентификаторы текстовых моделей не зашивайте в код: состав каталога меняется, и зашитый в код идентификатор начинает падать с 404 model_not_found. Возьмите его из GET /api/v1/models один раз при настройке окружения:
cURL
Передавайте model=os.environ["SPESHU_MODEL"] и в остальных примерах этой страницы. Формат ответа и параметры выбора — в разделе Модели и цены.

Первый запрос

Цепочка из шаблона, модели и парсера — обычный LCEL-пайплайн:
Python

Потоковая передача

stream() возвращает итератор кусков AIMessageChunk — печатайте их подряд, без ожидания остальных:
Python
Через str(stream(...)) собирается одна строка целиком — так удобно для веб-интерфейса, который отдаёт ответ в SSE. Формат кадров, маркер [DONE] и кадр со списанием разобраны на странице Потоковая передача.

Вызов функций

Python
Описание в docstring — единственное место, где вы объясняете модели, когда вызывать инструмент. Полный цикл, включая возврат результата и tool_call_id, — на странице Вызов функций.

Структурированный вывод

Python
Результат приходит валидированным объектом, а не строкой. Форматы response_format и поведение разных моделей — на странице Структурированный вывод.

Об эмбеддингах

SpeShu.AI не отдаёт эндпоинт для эмбеддингов: /embeddings в /api/v1 нет. Класс OpenAIEmbeddings, которым LangChain делает шаг векторизации, получит 404 — и пайплайн упадёт на первом же документе. Два честных варианта: считать эмбеддинги у другого провайдера, а генерацию оставить здесь; либо обойтись без векторного поиска.
Вариант 1 — эмбеддинги у другого провайдера. Ключ и адрес эмбеддингов — отдельная конфигурация, к SpeShu.AI она отношения не имеет:
Python
Вариант 2 — без эмбеддингов. Если документы небольшие, передавайте их в контекст напрямую и пропустите векторный шаг:
Python
Лимит на размер запроса задаёт модель: при превышении придёт 422 content_too_large, и длинные документы придётся резать вручную.

Генерация медиа

LangChain не покрывает медиа-задачи: они асинхронные, с оплатой при создании и отдельным опросом статуса. Работайте с ними через httpx/requests и ждите state: "success" — порядок полей и коды ошибок разобраны в Создании задачи и Статусе задачи. Идентификаторы медиа-моделей, в отличие от текстовых, стабильны: берите их из GET /api/v1/media/models.

Типичные проблемы

Правильное значение — https://speshu.ai/api/v1. Адрес без суффикса указывает на корень сайта, где /chat/completions не существует. Проверьте переменную целиком — так видны скрытые пробелы и лишний слэш в конце.
https://speshu.ai/api/v1/ даёт путь с двойным слэшем и тот же 404. Значение должно заканчиваться ровно на /v1, без завершающего /.
Если api_key не передан в ChatOpenAI, класс читает OPENAI_API_KEY, а не SPESHU_API_KEY. Передайте ключ параметром явно.
Идентификатор устарел или скопирован с ошибкой. Возьмите его заново из GET /api/v1/models и подставьте как есть — без префикса и без обрезки. Список в коде устаревает молча.
Это не проблема векторного хранилища: эндпоинта эмбеддингов у SpeShu.AI нет. Перенесите шаг эмбеддингов к отдельному провайдеру или откажитесь от векторного поиска — оба варианта разобраны выше.
Метод stream() уже читает поток инкрементально; проблема обычно в вашем коде — строка собирается целиком перед выводом. Печатайте каждый фрагмент сразу. Разбор SSE — на странице Потоковая передача.
Полная таблица кодов и цикл повторов — на странице Ошибки, таймауты и квоты — в разделе Лимиты.

Что дальше

Начало работы

Полный маршрут от ключа до медиа-задачи

Модели и цены

Как выбрать идентификатор и на что смотреть

Вызов функций

Полный цикл вызова инструмента

Структурированный вывод

JSON Schema и валидация результата