docs(agents): задание A39 — параметры запроса для локальных профилей
Локальная модель не закрывает задачи: Hermes сообщает о таймауте 180 секунд
после четырёх вызовов и переключается на другого провайдера.
Причина измерена, а не предположена. Служба запущена с --reasoning on и
--reasoning-budget 4096, а модель выдаёт 13,4 токена в секунду. На простой
задаче рефакторинга с лимитом 1500 токенов получено:
сгенерировано 1500 токенов за 111,6 с
рассуждений 5483 символа
ответа 0 символов
Весь лимит уходит на размышления, до ответа модель не доходит. За 180 секунд
она успевает около 2400 токенов — и это тоже одни рассуждения.
Отключение рассуждений на уровне запроса проверено и работает:
reasoning_effort: none ответ за 19,5 с
chat_template_kwargs: enable_thinking=false ответ за 11,4 с
Одиннадцать секунд вместо ста одиннадцати. Серверный флаг --reasoning off
решил бы это грубо, лишив рассуждений насовсем, поэтому владелец выбрал
гибкий путь: параметры задаёт хаб, по профилю.
Задание требует не зашивать ни enable_thinking, ни reasoning_effort: набор
ключей зависит от версии llama.cpp, и это данные конфигурации, а не
константы кода. Отдельным критерием — проверка живым запросом к серверу
владельца с замером времени до и после.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f5a8fcf0fd
commit
f8b6783641
1 changed files with 142 additions and 0 deletions
142
agents/inbox/2026-08-31-A39-local-request-options.md
Normal file
142
agents/inbox/2026-08-31-A39-local-request-options.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# Задание A39: параметры запроса для локальных профилей
|
||||
|
||||
## Дата поступления
|
||||
2026-08-31
|
||||
|
||||
## База
|
||||
|
||||
Ветка ревьюера `review/a35-a37-verified` (`88d579a`) — там уже слиты A35, A36, A37 и правки ревьюера.
|
||||
|
||||
```
|
||||
git fetch origin --prune
|
||||
git checkout -b antigravity/a39-local-request-options origin/review/a35-a37-verified
|
||||
```
|
||||
|
||||
В `main` напрямую не пушить.
|
||||
|
||||
## Порядок исполнения
|
||||
|
||||
Два прохода: **Flash** реализует, **Pro** проводит аудит. Пункт **P0-5** написан для аудитора.
|
||||
|
||||
Задание небольшое и независимое: зона — только локальный адаптер и конфигурация профиля.
|
||||
|
||||
---
|
||||
|
||||
## Задача
|
||||
|
||||
Локальная модель не закрывает задачи: Hermes сообщает «Локальный 27B не закрыл задачу: таймаут 180s, 4 вызова» и переключается на другого провайдера.
|
||||
|
||||
Причина найдена и измерена, гадать не нужно.
|
||||
|
||||
## Что измерено ревьюером — заново не выяснять
|
||||
|
||||
Сервер владельца, `127.0.0.1:8081`, Qwen3.8-27B на Tesla V100. Служба запущена с `--reasoning on --reasoning-budget 4096`.
|
||||
|
||||
**Задача рефакторинга простой функции, лимит 1500 токенов:**
|
||||
|
||||
```
|
||||
сгенерировано: 1500 токенов за 111,6 с (13,4 ток/с)
|
||||
рассуждений: 5483 символа
|
||||
самого ответа: 0 символов
|
||||
```
|
||||
|
||||
Модель израсходовала весь лимит на размышления и **до ответа не дошла**. За отведённые Hermes 180 секунд она успевает около 2400 токенов — и это по-прежнему одни рассуждения. Отсюда таймаут и четыре безрезультатных вызова.
|
||||
|
||||
**Отключение рассуждений на уровне запроса — проверено, работает:**
|
||||
|
||||
```
|
||||
reasoning_effort: "none" 540 симв. рассуждений, ответ 302, 19,5 с
|
||||
chat_template_kwargs: {"enable_thinking": false} 0 рассуждений, ответ 449, 11,4 с
|
||||
```
|
||||
|
||||
**11 секунд вместо 111**, и ответ появляется. Проблема не в скорости модели, а в том, что она не доходит до ответа.
|
||||
|
||||
Серверный флаг `--reasoning off` решил бы это грубо, но лишил бы рассуждений насовсем. Владелец выбрал гибкий путь: параметры задаёт хаб, по профилю.
|
||||
|
||||
## Что уже есть
|
||||
|
||||
```
|
||||
adapters/local_adapter.py:164 payload собирается здесь; сейчас проходят
|
||||
tools, tool_choice, response_format,
|
||||
max_tokens, stream, stop
|
||||
router_config.py:13 RouterProfileConfig — места под произвольные
|
||||
параметры запроса нет
|
||||
```
|
||||
|
||||
## P0-1. Параметры запроса в профиле
|
||||
|
||||
Добавить в `RouterProfileConfig` поле для произвольных параметров, которые адаптер подмешивает в тело запроса. Например `request_options: dict`.
|
||||
|
||||
Требования:
|
||||
|
||||
1. **Ничего не зашивать.** `enable_thinking`, `reasoning_effort` и прочее — это данные в конфигурации владельца, а не константы в коде. Завтра у llama.cpp появится другой ключ, и правка кода не должна понадобиться.
|
||||
2. **Сохраняется и переживает перезапуск**, как остальные поля профиля.
|
||||
3. **Вложенные структуры поддерживаются**: `chat_template_kwargs` — это словарь внутри словаря.
|
||||
4. **Явное поле запроса не перезаписывается молча.** Если Hermes прислал `max_tokens`, параметры профиля его не затирают; при конфликте выигрывает запрос, а факт расхождения пишется в журнал.
|
||||
|
||||
## P0-2. Локальный адаптер их отправляет
|
||||
|
||||
`local_adapter.invoke` подмешивает `request_options` в тело перед отправкой.
|
||||
|
||||
Осторожно с двумя вещами:
|
||||
|
||||
- **Неизвестный параметр не должен ронять вызов.** Сервер вернёт ошибку — её надо показать как ошибку провайдера с текстом, а не как отказ маршрутизатора. Механизм разбора ошибок уже есть в `base_adapter.extract_api_error_message`.
|
||||
- **Другие провайдеры не затрагиваются.** Поле относится к локальным профилям; попадание `chat_template_kwargs` в запрос к Antigravity или Codex — дефект.
|
||||
|
||||
## P0-3. Настройка из интерфейса
|
||||
|
||||
Владелец должен задавать это без правки YAML вручную.
|
||||
|
||||
В карточке локального аккаунта — поле параметров запроса. Достаточно текстового поля с JSON и проверкой разбора: набор ключей зависит от версии llama.cpp, и выпадающий список из зашитых вариантов быстро устареет.
|
||||
|
||||
**Показать, что именно уйдёт на сервер.** И честно сказать, если параметр отклонён сервером, — с его текстом ошибки.
|
||||
|
||||
## P0-4. Умолчание для профилей владельца
|
||||
|
||||
Предложить в отчёте, но **не применять молча**: для `local-1` (27B, порт 8081) поставить
|
||||
|
||||
```json
|
||||
{"chat_template_kwargs": {"enable_thinking": false}}
|
||||
```
|
||||
|
||||
Обосновать измерением выше. Решение принимает владелец.
|
||||
|
||||
Для `local-2` (4B, порт 8082) этого не нужно: она запущена с `--reasoning off`.
|
||||
|
||||
## P0-5. Аудит вторым проходом
|
||||
|
||||
1. **Проверить на живом сервере владельца**, а не только заглушкой: запрос с `enable_thinking: false` должен вернуть ответ за десяток секунд вместо ста.
|
||||
2. **Утечка в других провайдеров** — проверить целенаправленно, что параметр уходит только в локальные.
|
||||
3. **Неизвестный ключ** не роняет вызов и показывается как ошибка провайдера.
|
||||
4. **Зашитые значения** — искать отдельно; в коде не должно быть ни `enable_thinking`, ни `reasoning_effort`.
|
||||
5. **Побочные изменения** объяснить.
|
||||
6. **Пропущенный пункт назвать пропущенным.**
|
||||
|
||||
---
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Зона: `adapters/local_adapter.py`, `router_config.py`, карточка аккаунта в вебе, тесты.
|
||||
- Серверные юниты `qwen-coder` и `qwen-compressor` не трогать: это машина владельца, он меняет их сам.
|
||||
- Правило честности без исключений.
|
||||
- Тег `v0.1.1` не создавать.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
1. Ветка в `origin` от `review/a35-a37-verified`, `git status` чист.
|
||||
2. `request_options` есть в профиле, сохраняется, переживает перезапуск, поддерживает вложенные структуры.
|
||||
3. Локальный адаптер отправляет их; **проверено живым запросом к серверу владельца** с приложенным замером времени до и после.
|
||||
4. Параметр не попадает в запросы к другим провайдерам; проверено.
|
||||
5. Неизвестный ключ даёт ошибку провайдера с текстом, а не отказ маршрутизатора.
|
||||
6. Поле настраивается из интерфейса, показывает отправляемое тело.
|
||||
7. Явные поля запроса Hermes не затираются.
|
||||
8. Ни `enable_thinking`, ни `reasoning_effort` не зашиты в коде.
|
||||
9. `ruff check .` чисто; релизный гейт не ухудшен.
|
||||
10. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`. На ветке ревьюера сейчас **508 passed, 2 skipped**.
|
||||
|
||||
## Главное
|
||||
|
||||
Локальная модель сейчас бесполезна: она не доходит до ответа за отведённое время, и Hermes от неё отказывается. Одна строка параметров превращает 111 секунд без результата в 11 секунд с ответом. Нужно, чтобы владелец задавал эту строку из хаба, а не пересобирал службу.
|
||||
|
||||
## Порядок сдачи
|
||||
Передать точный `FINAL_COMMIT_SHA`.
|
||||
Loading…
Reference in a new issue