OpenAI-совместимый API

samreshuuu предоставляет drop-in эндпоинт chat/completions. Если вы уже используете OpenAI SDK, поменяйте base URL и API-ключ, больше ничего.

  • Base URL: https://samreshuuu.ru/v1
  • Авторизация: ключ организации со scope chat:write (см. Аутентификацию)
  • model: хэндл агента, который отвечает, из GET /v1/models

Drop-in пример

Перед запуском любого примера задайте ключ организации в переменной окружения SAMRESHUUU_API_KEY.

python
import os from openai import OpenAI client = OpenAI( api_key=os.environ["SAMRESHUUU_API_KEY"], base_url="https://samreshuuu.ru/v1", ) resp = client.chat.completions.create( model="samreshu", messages=[{"role": "user", "content": "Дай три коротких совета, как назвать карточку товара на маркетплейсе"}], ) print(resp.choices[0].message.content)

О поле model и других полях OpenAI

model адресует агента, а не LLM. GET /v1/models перечисляет агентов, с которыми может говорить организация ключа: первым встроенный ассистент (samreshu, owned_by: "system"), затем собственные и общие агенты организации (owned_by это id организации). LLM выбирает настройка модели самого агента, запрос её не переопределяет. Каждый ответ и каждый чанк несут хэндл агента, который ответил. Хэндл, которого нет или до которого создатель ключа не дотягивается, отклоняется с 404 DATA_NOT_FOUND и param: "model", текст: «The model x does not exist or you do not have access to it. List models with GET /v1/models.»; подмены другим агентом нет, поэтому стандартный gpt-4o падает явно. Ведущий @ допускается. Эти поля OpenAI принимаются, чтобы обычные вызовы SDK работали, но не применяются: tools, tool_choice, parallel_tool_calls, temperature, top_p, max_tokens, max_completion_tokens, stop, seed, user, stream_options. Два поля, которые изменили бы форму ответа, отклоняются с 400 DATA_INVALID_PARAMETER: response_format типа json_object или json_schema и n больше 1. response_format: {"type": "text"} и n: 1 проходят.

Поля запроса

FieldTypeDescription
modelrequiredstringХэндл агента, который отвечает, id из GET /v1/models. Ведущий @ допускается.
messagesrequiredarrayСообщения чата; хотя бы одно с ролью user, иначе 400 с param: messages. Последнее сообщение пользователя задаёт текущий ход. Предыдущие сообщения user и assistant становятся историей нового разговора; у существующей сессии своя история, и предыдущие сообщения не читаются. Сообщения system, developer и tool в историю не пишутся: у агента свои инструкции и инструменты. content это строка, массив текстовых частей ({type: text или input_text, text}) или null (сообщение assistant с tool_calls). Часть с картинкой, файлом или аудио отклоняется с 400 и param: messages[i].content. name, tool_calls и tool_call_id принимаются и игнорируются.
streambooleanЕсли true, стримит фреймы OpenAI chat.completion.chunk. По умолчанию false.
session_idstring (UUID)UUID разговора, который вы генерируете сами; передавайте его же, чтобы продолжить. Опустите для нового. Разговор принадлежит агенту, с которым начат, и организации ключа: с другим model или с другого ключа он отвечает 409 DATA_CONFLICT с param: session_id. Это не поле OpenAI: в Python SDK передавайте через extra_body, в Node.js просто в теле запроса.
max_iterationsintegerЛимит цикла агента. Границы и значение по умолчанию ниже. Передаётся так же, как session_id.
tool_eventsbooleanЕсли true (вместе со stream: true), в потоке идут и именованные события инструментов, см. ниже. По умолчанию false. Поле верхнего уровня: в Python SDK передавайте через extra_body.

max_iterations принимает значения от 1 до 50, по умолчанию 25.

Последнее сообщение пользователя не длиннее 200000 символов. Более длинное отклоняется 400 DATA_INVALID_PARAMETER, и message ошибки называет лимит. Большие данные передавайте частями в несколько ходов той же сессии.

Этот ключ действует от имени всего аккаунта

Ключ со scope chat:write управляет вашими агентами так же, как рабочее пространство: агент имеет доступ ко всему реестру инструментов, включая общие подключения организации и исполнение кода. Личные кабинеты и память создателя ключа ему закрыты. Относитесь к ключу как к учётным данным аккаунта: выдавайте отдельный ключ на интеграцию, храните только на сервере и ротируйте при утечке. Режима только-для-чтения у этого эндпоинта нет.

Стриминг

Установите stream: true, чтобы получать Server-Sent Events в формате чанков OpenAI, завершаемые финальным фреймом data: [DONE]. Первый чанк несёт delta: {"role": "assistant", "content": ""}. Каждые 10 секунд приходит SSE-комментарий, начинающийся с : ping (за ним метка времени); строки, начинающиеся с :, парсер должен пропускать.

bash
data: {"id":"chatcmpl-5f1c2d3e4a6b7c8d9e0f1a2b","object":"chat.completion.chunk","created":1790000000,"model":"samreshu","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} data: {"id":"chatcmpl-5f1c2d3e4a6b7c8d9e0f1a2b","object":"chat.completion.chunk","created":1790000000,"model":"samreshu","choices":[{"index":0,"delta":{"content":"Вот"},"finish_reason":null}]} data: {"id":"chatcmpl-5f1c2d3e4a6b7c8d9e0f1a2b","object":"chat.completion.chunk","created":1790000000,"model":"samreshu","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE]

События инструментов (opt-in)

Передайте tool_events: true, чтобы получать события samreshuuu.tool, чередующиеся со стандартными чанками. Они приходят именованными SSE-событиями (event: samreshuuu.tool). Официальные SDK OpenAI не фильтруют события по имени и отдают такие кадры как чанки без choices, поэтому пропускайте их в цикле (if not chunk.choices: continue). В Node.js SDK читайте их только через for await по create({ stream: true }) или собственным SSE-парсером: хелперы .stream() и runTools ждут в каждом кадре чанк и ломаются на этих событиях. Когда поле выключено, в потоке только чанки.

bash
event: samreshuuu.tool data: {"type":"tool_started","tool_id":"call_7Hq2mXc9LpR4tVb1NsK8eW3d","tool_name":"connector_execute","iteration":1,"label":"Вызов сервиса"} event: samreshuuu.tool data: {"type":"tool_completed","tool_id":"call_7Hq2mXc9LpR4tVb1NsK8eW3d","tool_name":"connector_execute","iteration":1,"success":true,"duration_ms":842,"label":"Вызов сервиса"}

tool_started несёт type, tool_id, tool_name, iteration и label (отображаемое имя инструмента); tool_completed добавляет success и duration_ms. tool_id связывает два события одного вызова. Вызов, на который ответ дан без запуска (повтор, отвеченный прежним результатом хода, вызов, отклонённый до запуска), присылает только tool_completed. Служебный инструмент завершения хода в этих событиях не появляется.

Ошибка посреди потока

Когда поток уже начался, статус ответа уже 200, поэтому сбой приходит последним чанком, который несёт объект error вместо choices: {"type":"error","error":{"type","code","message","param"},"request_id"}. Python-клиент openai поднимает его как APIError, после него поток закрывает data: [DONE]; собственный SSE-парсер должен проверять error в каждом data: до чтения choices.

bash
data: {"type":"error","error":{"type":"overloaded_error","code":"LLM_PROVIDER_UNAVAILABLE","message":"The model is temporarily unavailable. Please try again in a few minutes.","param":null},"request_id":"3f6c1b2a-8d4e-4f7a-9b0c-5e2d1a7c9f84"}

Отличия от OpenAI

  • Эндпоинты: только POST /v1/chat/completions и GET /v1/models. responses, embeddings и completions нет.
  • Длительность: ход агента может длиться долго, до 1800 секунд. Без стрима соединение всё это время молчит: поднимите timeout клиента заметно выше значения по умолчанию в OpenAI SDK или включите stream: true и опирайтесь на ping. Со стримом держите timeout чтения выше интервала ping, а общий timeout запроса выше предела хода: клиент, который сдаётся через две минуты, обрывает долгую сверку на середине, а обрыв соединения останавливает ход.
  • usage: приходит только в ответе без стрима. В стриме чанка с usage нет.
  • finish_reason: stop. Сбой после начала потока приходит чанком error (см. выше), а не значением finish_reason.
  • Обрыв соединения останавливает ход. Если закрыть поток посреди ответа, агент остановится, и ход запишется как остановленный, а не как сбой; продолжайте в той же сессии.
  • Отказ до старта хода это HTTP-ошибка, тело которой тот же объект error: 402 DATA_USAGE_QUOTA_EXCEEDED при исчерпанном недельном лимите, 429 при превышении частоты, 403 без scope chat:write, 404 для неизвестного model, 409 для session_id другого агента или ключа, 409 SESSION_BUSY пока в этом разговоре идёт другой ход (повторите после него; со stream: true тоже до открытия потока), 400 для отклонённого поля, 422 для тела, не прошедшего схему. См. Ошибки и лимиты.
  • Склейка чанков может отличаться от сохранённого ответа: агент иногда переписывает текст по ходу. Авторитетный текст отдаёт ответ без стрима.

Многоходовые диалоги

Сгенерируйте UUID и передавайте его как session_id во всех запросах разговора с тем же model. Ответ id сессии не возвращает, поэтому храните его у себя.

Частые вопросы

Что нужно поменять, чтобы использовать OpenAI SDK с samreshuuu?

Только base URL (https://samreshuuu.ru/v1) и API-ключ. Существующий код chat.completions работает без изменений, если model называет агента, а ключу нужен scope chat:write.

Что передавать в параметре model?

Хэндл агента, который должен ответить, из списка GET /v1/models (встроенный ассистент это samreshu). LLM выбирает настройка модели самого агента. Неизвестный или недоступный хэндл отклоняется с 404 DATA_NOT_FOUND, подмены нет. Параметры сэмплинга вроде temperature и max_tokens принимаются для совместимости, но не применяются; response_format json_object или json_schema и n больше 1 отклоняются с 400 DATA_INVALID_PARAMETER.

Как сохранять контекст между запросами?

Сгенерируйте UUID на своей стороне и передавайте его как session_id в каждом вызове. Ответ id сессии не возвращает: без session_id каждый вызов начинает новый разговор.

Что может API-ключ со scope chat:write?

Он управляет агентами вашей организации так же, как рабочее пространство, с доступом ко всему реестру инструментов, включая подключённые кабинеты и исполнение кода. Режима «только чтение» нет: относитесь к ключу как к учётным данным аккаунта, храните на сервере и меняйте при утечке.

Была ли страница полезна?