
OpenAI Responses API локально: какие серверы совместимы и как проверить tools
На странице · 5 разделов
Локальный endpoint /v1/responses есть у Ollama, LM Studio, llama.cpp и vLLM, но совпадение адреса не означает полной совместимости с облачным Responses API. Начните с текстового запроса, затем отдельно проверьте ответ с function tool и сценарий продолжения диалога. В Ollama предыдущий response ID не поддерживается; возможность модели предложить инструмент ещё не означает, что приложение его выполнило.
Проверено по документации 25 сентября 2026 года. Для llama.cpp использована закреплённая Git-ревизия, для vLLM — документация релиза 0.30.0. Modelium не запускал модели, не проверял скорость и не устанавливал перечисленные серверы. Команды ниже — сценарий проверки читателем, а не наш успешный прогон.
Что именно совместимо с OpenAI Responses API?
В Responses API приложение отправляет input на /v1/responses и получает структуру output; если модель предлагает функцию, это отдельный элемент function_call с именем, аргументами и call_id. Приложение, а не модель, проверяет аргументы, выполняет разрешённое действие и передаёт function_call_output с соответствующим call_id следующим запросом s1. При многошаговой работе состояние можно вести вручную, сохраняя элементы истории, либо использовать серверный previous_response_id, если реализация его действительно поддерживает s2.
«OpenAI-compatible» не значит «всё работает одинаково». Официальная документация Ollama поддерживает POST /v1/responses, tools и streaming начиная с версии 0.13.3, но прямо исключает stateful previous_response_id и conversation s3. LM Studio описывает тот же маршрут и пример продолжения с previous_response_id s4. В закреплённом README llama.cpp endpoint есть, но запрос преобразуется в Chat Completions: это важнее названия маршрута при переносе сложного агента s5. vLLM 0.30.0 перечисляет Responses endpoints для текстовых генеративных моделей; наличие маршрута в документации не подтверждает, что ваша модель выполняет вызов инструмента s6.
Выбор по задаче: если клиент просто передаёт текст, сначала проверьте текстовый ответ на выбранном runtime. Если клиент полагается на хранение истории по previous_response_id, не подставляйте Ollama без изменения логики: там нужен клиентский учёт истории s2s3. Если нужен инструмент, тестируйте цикл «предложение → разрешённое действие → результат» на своей модели, а не только HTTP 200 s1s7. Универсальную совместимость, качество и скорость эти документы не доказывают.
Как подготовить локальный сервер, модель и железо?
Сначала выберите и установите один runtime, затем загрузите совместимую модель по инструкции самого runtime. Ollama подойдёт для простого старта; LM Studio llmster — отдельный путь для headless-сервера; llama.cpp и vLLM требуют собственного выбора формата и способа запуска. Это разные серверы: настраивайте точное имя реально установленной модели, не копируйте в запрос названия из чужого примера.
Официальные адреса тестовых endpoint: Ollama http://127.0.0.1:11434/v1/responses, LM Studio http://127.0.0.1:1234/v1/responses, llama.cpp http://127.0.0.1:8080/v1/responses; vLLM обычно использует порт сервера, который настроили при запуске s3s4s5s6. 127.0.0.1 означает машину процесса-клиента: внутри контейнера или удалённой IDE это не обязательно хост с моделью. Проверьте адрес из той же среды, где работает ваш клиент; не публикуйте API-порт в интернет ради теста.
Размер файла весов не является минимальной RAM/VRAM. Чтобы выбрать модель, оцените её фактическое размещение и контекст на своём устройстве; если серверу не хватает памяти, возьмите меньший вариант и повторите. Документация по endpoint не заменяет тест на конкретной модели, железе и версии.
Как проверить сам /v1/responses без облачного ключа?
Ниже — один тестовый запрос в уже запущенный локальный сервер. Укажите ваш URL, точный тег/ID модели и только безвредный текст. Установленный API-ключ конкретного сервера или прокси может требовать дополнительного заголовка; приведённый локальный запрос не пытается обойти настроенную аутентификацию. Ollama игнорирует заполнитель api_key у совместимого SDK на локальном сервере; это не ключ OpenAI и не обещание защиты порта s3.
# Пример для Ollama; при выборе другого runtime замените адрес и точный model ID.
export RESPONSES_URL='http://127.0.0.1:11434/v1/responses'
export MODEL='вставьте-точный-тег-из-локального-списка'
python3 - <<'PY'
import json, os, urllib.request, urllib.parse
url = os.environ['RESPONSES_URL']
model = os.environ['MODEL']
parsed = urllib.parse.urlsplit(url)
if (parsed.scheme != 'http' or parsed.hostname not in ('127.0.0.1', 'localhost')
or parsed.path != '/v1/responses' or not parsed.port or parsed.username or parsed.password
or model.startswith('вставьте-')):
raise SystemExit('Укажите локальный URL /v1/responses и существующий model ID')
payload = {'model': model, 'input': 'Ответь одним словом: готово'}
request = urllib.request.Request(url, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json'})
with urllib.request.build_opener(urllib.request.ProxyHandler({})).open(request, timeout=90) as response:
result = json.load(response)
print(json.dumps({'id': result.get('id'), 'output': result.get('output')}, ensure_ascii=False, indent=2))
PY
Критерий: HTTP 200 с JSON и содержательным ответом в output, а не только работающий порт или id. Ответ другой модели, облачного endpoint или ошибка 404/401 тест не проходят. Для SDK base_url обычно указывает на /v1, а сам SDK добавляет /responses; в сыром HTTP выше используется полный путь s3s5. Не передавайте реальные документы, ключи или данные клиентов в smoke-тест.
Как отдельно проверить tools и хранение истории?
Следующий тест использует те же RESPONSES_URL и MODEL, что в предыдущей команде. Он просит модель предложить, но не выполнить функцию над синтетическим кодом. Если runtime или конкретная модель не умеют такой ответ, скрипт завершится с ошибкой — это результат проверки, а не повод выдавать обычный текст за вызов s1s7.
python3 - <<'PY'
import json, os, urllib.request, urllib.parse
url = os.environ['RESPONSES_URL']
model = os.environ['MODEL']
parsed = urllib.parse.urlsplit(url)
if (parsed.scheme != 'http' or parsed.hostname not in ('127.0.0.1', 'localhost')
or parsed.path != '/v1/responses' or not parsed.port or parsed.username or parsed.password
or model.startswith('вставьте-')):
raise SystemExit('Нужны локальный URL /v1/responses и существующий model ID')
payload = {
'model': model,
'input': 'Вызови lookup_demo с code DEMO-01. Не придумывай результат.',
'tools': [{'type': 'function', 'name': 'lookup_demo',
'description': 'Находит только тестовый код',
'parameters': {'type': 'object', 'properties': {'code': {'type': 'string'}},
'required': ['code'], 'additionalProperties': False}}],
}
request = urllib.request.Request(url, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json'})
with urllib.request.build_opener(urllib.request.ProxyHandler({})).open(request, timeout=90) as response:
result = json.load(response)
calls = [item for item in result.get('output', []) if item.get('type') == 'function_call']
if len(calls) != 1 or calls[0].get('name') != 'lookup_demo' or not calls[0].get('call_id'):
raise SystemExit('Тест не пройден: нет одного структурного вызова lookup_demo с call_id')
args = json.loads(calls[0].get('arguments', '{}'))
if args != {'code': 'DEMO-01'}:
raise SystemExit('Тест не пройден: аргументы вызова не совпали с тестовыми')
print('Вызов предложен; call_id:', calls[0]['call_id'], '; действие НЕ выполнялось')
PY
Критерий: в структурном output ровно один function_call с именем, проверенными аргументами и call_id. Текст «я вызвал функцию» или JSON внутри обычного ответа не равен tool call s1. Этот скрипт намеренно не исполняет предложенное действие и не доказывает работоспособность полного агентного цикла. Не передавайте модели доступ к рабочей базе; полный безопасный цикл с проверкой аргументов и ответом инструмента описан отдельно s1s7.
Не делайте тест previous_response_id общим обязательным критерием для всех четырёх серверов: на Ollama это официально неподдерживаемое поле s3. В LM Studio документация показывает stateful-продолжение с ID предыдущего ответа, но пример resp_123 — заполнитель: отправлять нужно настоящий id предыдущего ответа своего сервера s4. У OpenAI есть и ручной способ передачи истории; при переносе на локальный runtime сверяйте фактическое поведение ответа, а не только подпись метода SDK s2. Для llama.cpp и vLLM здесь не утверждается одинаковая с LM Studio семантика хранения или повторного воспроизведения tool calls: их проверяют отдельно на своей версии s5s6.
Почему запрос проходит, но агент не работает?
404: сверьте порт, /v1/responses и версию runtime. В Ollama маршрут описан начиная с 0.13.3; переключение клиента на /v1/chat/completions меняет формат протокола и не считается проверкой Responses s3. Ошибка model not found: проверьте точный локальный ID, запуск модели и место выполнения клиента. Ответ без function_call: сначала отделите сетевую доступность от способности модели предложить инструмент; проверьте схему, ограничения своей модели и трассу приложения s1s7. Ошибка продолжения: не переиспользуйте previous_response_id между серверами и не передавайте его в Ollama; поддержка состояния различается s2s3s4.
Для отката остановите тестовый сервер способом своей установки и удалите только специально созданные тестовые данные после проверки пути. Если использовали настоящий документ или открыли endpoint в локальную сеть, оцените доступ отдельно: наличие локальной модели не гарантирует изоляцию. Следующий практический шаг — проверить полный цикл tool calling, включая разрешения и передачу результата модели s1s7.
Источники
- OpenAI — Function calling, официальный протокол. Получено 25.09.2026.
- OpenAI — Conversation state, способы продолжения. Получено 25.09.2026.
- Ollama — OpenAI compatibility, Responses API. Получено 25.09.2026.
- LM Studio — OpenAI-compatible Responses endpoint. Получено 25.09.2026.
- llama.cpp — llama-server README, закреплённая ревизия — revision 217f81c266a7b7c986ee3d2c58e1cccee05a0744. Получено 25.09.2026.
- vLLM 0.30.0 — OpenAI-compatible server — revision v0.30.0. Получено 25.09.2026.
- Ollama — Tool calling, цикл приложения. Получено 25.09.2026.