mirror of
https://gitverse.ru/kpa39l/hermes-auxiliary-local-models.git
synced 2026-09-29 10:05:02 +00:00
Initial commit: Hermes skill hermes-auxiliary-local-models
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# Inventory of Hermes auxiliary tasks + model routing (2026-09-04)
|
||||
|
||||
Все задачи, которые Hermes решает "в фоне" отдельно от main-модели через
|
||||
`call_llm(task=...)` (agent/auxiliary_client.py) и точки их вызова в коде.
|
||||
Использовать для решения: какую задачу направить на локальную Ollama, какую оставить на облаке.
|
||||
|
||||
## Полная карта задач
|
||||
|
||||
| Задача | Назначение / где вызывается | Требования/характер |
|
||||
|---------------------|------------------------------------------------------|----------------------------------------|
|
||||
| title_generation | Заголовки сессий (/title) | короткий вывод, мгновенно |
|
||||
| web_extract | Пересказ/извлечение из веб-страниц (web_extract) | средний вывод |
|
||||
| vision | Анализ изображений, скриншоты браузера | нужна vision-модель, приватность |
|
||||
| skills_hub | Поиск/описание скиллов в хабе (skills_hub) | короткий вывод |
|
||||
| profile_describer | Описание пользовательского профиля (profile_describer)| не hot-path, краткий вывод |
|
||||
| compression | Сжатие длинных диалогов (context_compressor) | **контекст ≥ 64K**, важна надёжность |
|
||||
| approval | Умное авто-одобрение команд, режим smart (approval.py) | безопасность, одно слово (APPROVE/DENY/ESCALATE) |
|
||||
| mcp | Обёртка MCP-серверов (tools/mcp_tool.py) | может быть сложный вывод |
|
||||
| kanban_decomposer | Декомпозиция задач каньбан в JSON (kanban_decompose.py) | длинный JSON (до max 4000 токенов) |
|
||||
| triage_specifier | Спецификация/уточнение задач каньбан (kanban_specify.py) | рабочие задачи, надёжность |
|
||||
| curator | Фоновый анализ/жизненный цикл скиллов (curator) | фоновый, но смысловой анализ |
|
||||
|
||||
## Рекомендуемое распределение (проверено, применено в конфиге)
|
||||
|
||||
**На локальную qwen3:8b-nothink (текст) / qwen3-vl:8b (vision):**
|
||||
title_generation, web_extract, vision, skills_hub, profile_describer.
|
||||
Экономит облачные токены, картинки не уходят в облако.
|
||||
|
||||
**Оставить на облаке (provider: auto / main):**
|
||||
- compression — жёсткий минимум `MINIMUM_CONTEXT_LENGTH = 64_000`, локаль (< 40K) не тянет
|
||||
- approval — безопасность, не направлять на слабую локаль
|
||||
- mcp — может требовать сложного вывода
|
||||
- kanban_decomposer — длинный JSON, локаль 8b рискует битой структурой
|
||||
- triage_specifier — рабочие задачи, надёжность
|
||||
- curator — фоновый, смысловой анализ
|
||||
|
||||
## КРИТИЧНО: session_search — НЕ auxiliary-задача
|
||||
|
||||
`session_search` НЕ имеет отдельной auxiliary-модели. Проверено резолвером:
|
||||
```
|
||||
_resolve_task_provider_model(task="session_search") # -> provider=auto model=None
|
||||
```
|
||||
Это agent-loop инструмент (наравне с todo, memory, delegate_task), он ВСЕГДА идёт на
|
||||
main-модель/auto. Настройка `auxiliary.session_search.provider` не имеет эффекта
|
||||
(её блок в конфиге имеет только extra_body/max_concurrency/timeout). Не трать время
|
||||
на попытку переключить её на локаль — это ограничение Hermes, а не наша ошибка.
|
||||
|
||||
## Настройка блока в config.yaml (вручную, НЕ hermes config set)
|
||||
|
||||
`hermes config set` не правит dict-блоки aux корректно — правь текстом:
|
||||
```yaml
|
||||
<task>:
|
||||
provider: custom
|
||||
model: qwen3:8b-nothink
|
||||
base_url: http://localhost:11434/v1
|
||||
api_key: ollama
|
||||
timeout: 60
|
||||
```
|
||||
Замена по маркеру ` <task>:` (2 пробела + имя целиком, включая последующий отступ
|
||||
в 4 пробела + пустую строку до следующей задачи). Порядок полей в существующем блоке
|
||||
в файле: provider, model, base_url, api_key, timeout, extra_body.
|
||||
|
||||
## Проверка E2E после смены модели
|
||||
|
||||
Реальный контур (не CLI, который может не подхватить ключ):
|
||||
```python
|
||||
import sys; sys.path.insert(0, "/opt/hermes/.hermes/hermes-agent")
|
||||
from agent.auxiliary_client import call_llm
|
||||
r = call_llm(task="<task>", messages=[{"role":"user","content":"<короткий промпт>"}], max_tokens=80)
|
||||
# смотри: r.model == ожидаемая модель, r.choices[0].finish_reason == "stop", content не пуст
|
||||
```
|
||||
Признак рабочей локальной модели: `finish_reason: stop` + осмысленный content.
|
||||
| r.choices[0].message.content | r.model |
|
||||
@@ -0,0 +1,79 @@
|
||||
# Qwen3-VL 8B + Ollama: разбор сессии настройки auxiliary.vision
|
||||
|
||||
Дата: 2026-08-30. Хост: RTX 5060 Ti 16 GB VRAM, Ollama в Docker (контейнер `ollama`),
|
||||
main-модель Hermes — облачная polza.ai (deepseek/deepseek-v4-flash-0731).
|
||||
|
||||
## Итог
|
||||
|
||||
`auxiliary.vision` переведён на локальную `qwen3-vl:8b`:
|
||||
- model: qwen3-vl:8b (~6.14 GB на диске, ~7.2 GB VRAM при ctx 4096/8192)
|
||||
- provider: custom, base_url: http://localhost:11434/v1, api_key: ollama
|
||||
- остальные auxiliary остались на `auto` → облачный main-провайдер
|
||||
|
||||
Проверено E2E: vision-запрос через Hermes-клиент (`resolve_provider_client`) отвечает
|
||||
"red"/"blue" на тестовых PNG.
|
||||
|
||||
## Ключевые факты о Hermes auxiliary (agent/auxiliary_client.py)
|
||||
|
||||
- Раздел конфига: `auxiliary.<task>.provider/model/base_url/api_key` в config.yaml.
|
||||
- `provider: auto` цепочка (текст): main-провайдер → OpenRouter → Nous Portal →
|
||||
custom endpoint → Anthropic → прямые провайдеры. Для vision своя цепочка:
|
||||
main-провайдер (если поддерживает vision) → OpenRouter → Nous → Anthropic →
|
||||
custom endpoint (локальные Qwen-VL/LLaVA/Pixtral).
|
||||
- `MINIMUM_CONTEXT_LENGTH = 64_000` (agent/model_metadata.py:405) — флор только для
|
||||
`compression`. Остальные задачи без флора.
|
||||
- `resolve_provider_client()` сигнатура: `explicit_base_url` / `explicit_api_key`
|
||||
(не `base_url`/`api_key` — TypeError).
|
||||
- Vision-capable локальных моделей определяется через `query_ollama_supports_vision`
|
||||
(capabilities в `/api/show`, или model_info.*.vision.block_count на старых серверах).
|
||||
|
||||
## Ошибки в процессе (транскрипт)
|
||||
|
||||
1. `HTTP 500` на `/api/chat` с картинкой 1×1 px:
|
||||
```
|
||||
panic: height:1 or width:1 must be larger than factor:32
|
||||
github.com/ollama/ollama/model/models/qwen3vl.(*ImageProcessor).SmartResize
|
||||
```
|
||||
→ Ошибка картинки, не конфигурации. Входной образ должен быть ≥ 32 px.
|
||||
2. Пустой `content` при `finish_reason: stop` на картинке 64×64 — reasoning ушёл в
|
||||
`reasoning` поле. На 256×256 ответ нормальный ("red").
|
||||
3. `hermes chat -m ... --provider custom` в CLI: "No API key found for provider 'custom'"
|
||||
— CLI-запуск не отражает auxiliary-резолв; auxiliary берётся из config.yaml напрямую.
|
||||
4. `curl ... | python3` в terminal — блокируется security scan (pipe to interpreter);
|
||||
использовать execute_code с urllib вместо пайпов.
|
||||
|
||||
## VRAM-планирование (qwen3-vl:8b, GGUF)
|
||||
|
||||
- GGUF-контекст: `qwen3vl.context_length = 262144`, layers=36, embedding=4096.
|
||||
- KV cache (f16) ≈ 2 · layers · dim · 2 · ctx · 2 bytes:
|
||||
- 32K → ~38.7 GB, 64K → ~77 GB, 128K → ~155 GB, 262K → ~309 GB.
|
||||
→ Физически полный контекст не влезает в 16 GB. Ollama грузит с num_ctx 4096 по умолчанию,
|
||||
для запросов задавать `options: {num_ctx: 8192}`.
|
||||
- Итоговое распределение: qwen3-vl 7.19 GB + bge-m3 1.21 GB = 8.4 GB занято, ~7.3 GB свободно.
|
||||
- qwen3:8b и qwen2.5-coder:14b имеют GGUF-контекст 40960/32768 (имена "-64k"/"-65k" лгут) —
|
||||
ниже 64K флора compression, поэтому compression оставлен на облаке.
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Pull в Docker
|
||||
docker exec ollama ollama pull qwen3-vl:8b
|
||||
|
||||
# Проверка caps/контекста
|
||||
curl -s http://localhost:11434/api/show -d '{"model":"qwen3-vl:8b"}' | jq '.capabilities, .model_info["qwen3vl.context_length"]'
|
||||
|
||||
# Тест vision напрямую
|
||||
curl -s http://localhost:11434/api/chat -d '{"model":"qwen3-vl:8b","messages":[{"role":"user","content":"What color?","images":["<b64>"]}],"options":{"num_ctx":8192},"stream":false}'
|
||||
|
||||
# OpenAI-совместимый путь (что использует Hermes)
|
||||
curl -s http://localhost:11434/v1/chat/completions -d '{"model":"qwen3-vl:8b","messages":[{"role":"user","content":[{"type":"text","text":"What color?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,<b64>"}}]}],"max_tokens":50}'
|
||||
|
||||
# Выгрузка из VRAM
|
||||
docker exec ollama ollama stop qwen3-vl:8b
|
||||
```
|
||||
|
||||
## Откат конфигурации
|
||||
|
||||
```bash
|
||||
hermes config set auxiliary.vision.provider auto
|
||||
hermes config set auxiliary.vision.model ""
|
||||
@@ -0,0 +1,100 @@
|
||||
# Текстовые aux на локальной Ollama (qwen3:8b) + отключение thinking
|
||||
|
||||
Дата: 2026-08-30. Продолжение `qwen3-vl-ollama-setup.md`: после vision переведены
|
||||
текстовые auxiliary-задачи (title_generation, web_extract) на локальную qwen3:8b.
|
||||
Хост: RTX 5060 Ti 16 GB VRAM, Ollama в Docker, main-модель — polza.ai.
|
||||
|
||||
## Итоговая конфигурация
|
||||
|
||||
```yaml
|
||||
auxiliary:
|
||||
vision: # qwen3-vl:8b (мультимодальная)
|
||||
provider: custom
|
||||
model: qwen3-vl:8b
|
||||
base_url: http://localhost:11434/v1
|
||||
api_key: ollama
|
||||
title_generation: # qwen3:8b (текстовая)
|
||||
provider: custom
|
||||
model: qwen3:8b
|
||||
base_url: http://localhost:11434/v1
|
||||
api_key: ollama
|
||||
extra_body:
|
||||
think: false
|
||||
web_extract: # qwen3:8b
|
||||
provider: custom
|
||||
model: qwen3:8b
|
||||
base_url: http://localhost:11434/v1
|
||||
api_key: ollama
|
||||
extra_body:
|
||||
think: false
|
||||
compression: # остаётся в облаке (нужен 64K+ контекст)
|
||||
provider: auto
|
||||
```
|
||||
|
||||
Проверено E2E через `from agent.auxiliary_client import call_llm`:
|
||||
- title_generation: "Настройка Ollama: локальные модели" — 11.3 сек (на qwen3-vl было 109 сек)
|
||||
- web_extract: нормальный пересказ — 7.5 сек
|
||||
- compression резолвится на auto → polza, не тронута
|
||||
|
||||
## Почему qwen3-vl НЕ годится для текстовых aux
|
||||
|
||||
На простой вопрос ("какой сегодня день недели?") qwen3-vl:8b сгенерила 3778 токенов
|
||||
(eval_ms 54 сек) и отвечала 64 сек. reasoning=false в ответе, но content огромный —
|
||||
модель "растекается". Для быстрых aux (заголовки, извлечение) непригодна.
|
||||
|
||||
## Ключевая находка: отключение thinking у qwen3 в Ollama
|
||||
|
||||
**ВАЖНО (2026-09-04, Ollama 0.22.1):** `think: false` через OpenAI `/v1/chat/completions` НЕ работает
|
||||
для qwen3 — модель все равно думает, content пуст, `finish: length` (reasoning съел лимит).
|
||||
Через нативный `/api/chat` + `think: false` думание выключается корректно (но Hermes ходит через /v1).
|
||||
|
||||
**Решение для Hermes/aux — собрать тег с вырезанным reasoning** (никакие опции не помогают):
|
||||
|
||||
```bash
|
||||
# 1. Получить modelfile (docker):
|
||||
docker exec ollama ollama show qwen3:8b # или GET /api/show -> поле "modelfile"
|
||||
# 2. В TEMPLATE заменить все $.IsThinkSet -> false (ветки thinking навсегда выключены)
|
||||
# 3. Собрать (переиспользует blob, без скачивания):
|
||||
docker cp /tmp/qwen3-nothink-Modelfile ollama:/root/
|
||||
docker exec ollama ollama create qwen3:8b-nothink -f /root/qwen3-nothink-Modelfile
|
||||
```
|
||||
Ключ: `$.IsThinkSet` управляет думанием (вставляет `/think`/`/no_think` в user msg и `thinking{{ .Thinking }}`
|
||||
в assistant). При `false` модель просто отвечает. Проверено: `qwen3:8b-nothink` через /v1 отвечает
|
||||
мгновенно (finish: stop), E2E через `call_llm(task=...)` в Hermes — корректный content
|
||||
(title_generation, web_extract). Оригинальный `qwen3:8b` не трогаем (откат — 1 строка в config).
|
||||
|
||||
Затем в config.yaml (вручную, т.к. `hermes config set` не правит dict extra_body; порядок полей в
|
||||
файле: provider, model, base_url, api_key, timeout, extra_body): model для
|
||||
`auxiliary.title_generation` и `auxiliary.web_extract` := `qwen3:8b-nothink`.
|
||||
|
||||
**ОПРОВЕРГНУТЫЕ способы (не работают — модель все равно генерит reasoning первыми токенами):**
|
||||
- `enable_thinking: false` в options (`/api/chat`) — таймаут
|
||||
- `enable_thinking: false` в extra_body (`/v1/chat/completions`) — content пустой
|
||||
- `/no_think` в начале user-сообщения — reasoning=True, content пустой
|
||||
- system prompt "don't think" — не помогает
|
||||
- корневой `think: false` в /v1 — НЕ работает в Ollama 0.22 (работает только native /api/chat)
|
||||
|
||||
Симптом при неотключённом thinking: **content = ''**, `usage.completion_tokens == max_tokens`
|
||||
(весь бюджет съело reasoning), время ответа большое. Диагностика: смотреть поле
|
||||
`reasoning`/`reasoning_content` в ответе.
|
||||
|
||||
## Полный список auxiliary-задач (из config.yaml)
|
||||
|
||||
vision, web_extract, compression, skills_hub, approval, mcp, title_generation,
|
||||
triage_specifier, kanban_decomposer, profile_describer, curator.
|
||||
|
||||
`session_search` — НЕ auxiliary-задача: `hermes config set auxiliary.session_search.provider`
|
||||
даёт warning "not a recognized config key" (в конфиге у неё только extra_body/max_concurrency/
|
||||
timeout). Не настраивать как auxiliary.
|
||||
|
||||
## VRAM (обе модели одновременно)
|
||||
|
||||
qwen3:8b 6.13 GB + qwen3-vl:8b 7.19 GB + bge-m3 1.21 GB ≈ 14.5 GB — влезают в 16 GB,
|
||||
переключение vision↔текст без выгрузки (keep_alive по умолчанию). При нехватке Ollama
|
||||
выгружает LRU-модель и перезагружает при следующем вызове (+5-15 сек).
|
||||
|
||||
## Нюанс `hermes config set`
|
||||
|
||||
`hermes config set auxiliary.<task>.extra_body` не пройдёт (extra_body — dict, не скаляр) —
|
||||
править YAML вручную (python+yaml.safe_dump). Остальные ключи (provider/model/base_url/
|
||||
api_key) ставятся через `hermes config set` с `--force` если ключ не в schema.
|
||||
Reference in New Issue
Block a user