Новая статья про перевод aux-задач Hermes на локальные модели и отключение thinking у Qwen3

This commit is contained in:
2026-08-30 12:08:10 +00:00
parent 54617de53f
commit f47f82fda1
2 changed files with 224 additions and 0 deletions
@@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 400" width="100%" height="auto">
<rect width="1200" height="400" fill="#0a0c10"/>
<!-- Hexagon pattern -->
<g stroke="#1a2332" stroke-width="1" fill="none" opacity="0.5">
<polygon points="100,100 130,80 160,100 160,140 130,160 100,140"/>
<polygon points="250,100 280,80 310,100 310,140 280,160 250,140"/>
<polygon points="400,100 430,80 460,100 460,140 430,160 400,140"/>
<polygon points="550,100 580,80 610,100 610,140 580,160 550,140"/>
<polygon points="700,100 730,80 760,100 760,140 730,160 700,140"/>
<polygon points="850,100 880,80 910,100 910,140 880,160 850,140"/>
<polygon points="1000,100 1030,80 1060,100 1060,140 1030,160 1000,140"/>
<polygon points="175,160 205,140 235,160 235,200 205,220 175,200"/>
<polygon points="325,160 355,140 385,160 385,200 355,220 325,200"/>
<polygon points="475,160 505,140 535,160 535,200 505,220 475,200"/>
<polygon points="625,160 655,140 685,160 685,200 655,220 625,200"/>
<polygon points="775,160 805,140 835,160 835,200 805,220 775,200"/>
<polygon points="925,160 955,140 985,160 985,200 955,220 925,200"/>
<polygon points="1075,160 1105,140 1135,160 1135,200 1105,220 1075,200"/>
</g>
<!-- Center text -->
<text x="600" y="175" font-family="monospace" font-size="36" fill="#58a6ff" text-anchor="middle" font-weight="bold">
Локальные aux-модели Hermes
</text>
<text x="600" y="215" font-family="monospace" font-size="20" fill="#8b949e" text-anchor="middle">
qwen3-vl · qwen3 · think:false · Ollama
</text>
<!-- Decor line -->
<line x1="200" y1="250" x2="1000" y2="250" stroke="#30363d" stroke-width="1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,191 @@
---
date: '2026-08-30T12:00:00+03:00'
lastmod: '2026-08-30T12:00:00+03:00'
draft: false
title: 'Как я перевёл aux-задачи Hermes на локальные модели: экономия токенов и отключение режима размышлений у Qwen3'
slug: 'local-aux-models-hermes-qwen3'
description: 'Рассказываю, как выбрал модель для вспомогательных (auxiliary) задач агента Hermes, перевёл vision и текстовые задачи на локальную Ollama, сэкономил токены облачного провайдера и допилил отключение режима размышлений (thinking) у Qwen3.'
categories:
- 'AI'
- 'DevOps'
tags:
- 'hermes'
- 'ollama'
- 'qwen3'
- 'llm'
- 'aux'
- 'vision'
- 'локальные-модели'
- 'экономия-токенов'
keywords:
- 'hermes'
- 'ollama'
- 'qwen3'
- 'qwen3-vl'
- 'auxiliary'
- 'thinking'
- 'reasoning'
- 'локальная модель'
- 'экономия токенов'
cover:
image: "hero.svg"
alt: "Локальные aux-модели Hermes: qwen3-vl и qwen3"
---
# Как я перевёл aux-задачи Hermes на локальные модели
У меня на домашнем сервере живёт агент [Hermes](https://hermes-agent.nousresearch.com) — он ведёт блог, следит за сертификатами, ходит в мессенджеры и выполняет кучу мелких, но важных задач. Основную модель он берёт в облаке (провайдер polza.ai, 131K контекст), а для вспомогательных задач — генерации заголовков, извлечения текста из веб-страниц, описания картинок (vision) и сжатия контекста — у него есть отдельный механизм **auxiliary**. По умолчанию все aux-задачи тоже резолвятся в облако, а значит — тратят токены и деньги.
На сервере стоит видеокарта **RTX 5060 Ti 16 GB** (да, та самая, про которую я писал в статье про зависание Ubuntu при загрузке). Раз есть GPU — почему бы не увести aux-задачи на локальные модели? Приватность, скорость, ноль затрат на API. Рассказываю, как выбирал модель, как настраивал и какой грабли встретил при отключении режима размышлений (thinking) у Qwen3.
## Что такое auxiliary-задачи в Hermes
Hermes — агент с модульной архитектурой. Кроме основной модели (которая думает и пишет ответы), он вызывает **вспомогательные (auxiliary) задачи** через отдельный клиент — `auxiliary_client.py`. В моей версии их несколько:
| Задача | Что делает | Порог контекста |
|---|---|---|
| `vision` | Описывает картинки, читает скриншоты | нет |
| `title_generation` | Генерирует заголовки диалогов | нет |
| `web_extract` | Извлекает текст из веб-страниц | нет |
| `compression` | Сжимает историю диалога (context compaction) | **64K жёсткий минимум** |
| `skills_hub`, `approval`, `mcp` и др. | Служебные | нет |
Ключевой момент: **только `compression` требует большого контекста (64K)**. Это жёсткое требование самого Hermes — для сжатия истории ему нужна модель, которая видит весь диалог. Локальные GGUF-модели до 64K не дотягивают (проверил: qwen3-8b упирается в 40960 токенов контекста, qwen2.5-coder-14b — в 32768; теги «64k/65k» в названиях моделей — маркетинг, реальный контекст меньше). Поэтому **compression я оставил в облаке**, а вот все остальные aux-задачи — кандидаты на локализацию.
## Выбор модели
Критерии были простые:
1. Модель должна уметь **vision** (для `vision`-задачи).
2. Должна влезать в 16 GB VRAM вместе с эмбеддинг-моделью `bge-m3` и основной текст-моделью.
3. Должна быстро отвечать — aux-задачи вызываются часто, ждать минуту утомительно.
4. Желательно уметь закрыть и текстовые задачи (генерация заголовков, извлечение текста) — чтобы не гонять облако вообще.
Я поставил [qwen3-vl:8b](https://ollama.com/library/qwen3-vl) — мультимодальную модель Qwen 8B с поддержкой vision. Она весит ~6.1 GB, контекст 262K (но KV cache на полный контекст — ~309 GB, так что реально держу `num_ctx=8192`). Проверил через `/api/show` — у неё есть capability `vision`, значит Hermes её увидит как vision-модель.
**Важный нюанс про qwen3-vl:** она великолепно описывает картинки (проверено E2E — отвечает «red»/«blue» на цветные картинки за 1-10 секунд), но для текстовых задач она... слишком умная. На простой вопрос «какой сегодня день недели» она генерирует 3778 токенов рассуждений и отвечает через 64 секунды! Это потому, что qwen3-модели по умолчанию включён режим reasoning/thinking. Для заголовков и извлечения текста это неприемлемо.
Поэтому я взял **две модели**:
- `qwen3-vl:8b` — для vision (картинки);
- `qwen3:8b` — для текстовых aux (title_generation, web_extract), с принудительно отключённым thinking.
## Настройка
Hermes поддерживает per-task конфигурацию auxiliary-задач в `config.yaml`. Формат:
```yaml
auxiliary:
vision:
provider: custom
model: qwen3-vl:8b
base_url: http://localhost:11434/v1
api_key: ollama
title_generation:
provider: custom
model: qwen3:8b
base_url: http://localhost:11434/v1
api_key: ollama
extra_body:
think: false
web_extract:
provider: custom
model: qwen3:8b
base_url: http://localhost:11434/v1
api_key: ollama
extra_body:
think: false
```
Настройка через CLI:
```bash
hermes config set auxiliary.vision.provider custom
hermes config set auxiliary.vision.model qwen3-vl:8b
hermes config set auxiliary.vision.base_url http://localhost:11434/v1
hermes config set auxiliary.vision.api_key ollama
# и так для каждой задачи
```
Пара важных граблей:
- **`api_key` обязан быть непустым.** В коде Hermes пустой `api_key` означает «унаследовать ключ основного провайдера» — и тогда он попытается сходить в polza.ai с локальной моделью. Я поставил заглушку `ollama` (Ollama её не проверяет).
- **Ollama надо форматировать через OpenAI-совместимый эндпоинт** `/v1/chat/completions` — именно так Hermes ходит в локальные модели.
- **Для qwen3-vl держать `num_ctx` небольшим** (я использую 8192), иначе Ollama пытается зарезервировать KV cache под весь 262K контекст — это ~309 GB, runner падает с EOF.
## Допиливание отключения режима размышлений (thinking)
Самая интересная часть. Qwen3-модели (и qwen3, и qwen3-vl) по умолчанию генерируют **скрытый поток рассуждений (thinking/reasoning)** перед ответом. Для aux-задач это означает:
- Заголовок генерируется 64 секунды вместо 3-5.
- При ограниченном `max_tokens` ответ вообще **пустой** — весь бюджет съедает thinking, до `content` дело не доходит.
Я перепробовал несколько способов отключить thinking, и вот что выяснилось:
### Что НЕ работает (в Ollama)
| Способ | Результат |
|---|---|
| `/no_think` в начале сообщения | Не работает — модель всё равно думает |
| `enable_thinking: false` в `extra_body` | Не работает |
| `thinking: {type: disabled}` (как в OpenAI API Qwen) | Не работает — content пустой, reasoning продолжается |
| `system: "Не думай"` | Не работает |
Я проверил chat template модели — там есть команды `/think` и `/no_think`, но они не активируются в Ollama (флаг `IsThinkSet` не выставляется).
### Что работает
**Единственный рабочий способ — корневой параметр `think: false` в теле запроса:**
```bash
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{"role": "user", "content": "Привет!"}],
"think": false
}'
```
Ответ приходит через **0.7 секунды** (вместо 64!), `reasoning=false`, `content` заполнен. Именно эту опцию я и прописал в `extra_body` конфига Hermes:
```yaml
extra_body:
think: false
```
В коде Hermes `extra_body` уходит в корень JSON-тела запроса — как раз туда, куда Ollama ждёт параметр `think`.
### Проверка E2E
После настройки прогнал реальные вызовы через вспомогательный клиент Hermes (`call_llm`):
| Задача | Время | Результат |
|---|---|---|
| `title_generation` | 11.3 сек | «Настройка Ollama: локальные модели» |
| `web_extract` | 7.5 сек | Извлёк главную мысль |
| `vision` (картинка 256x256) | 7.6 сек | «blue» |
## VRAM и память
На RTX 5060 Ti 16 GB в памяти держатся одновременно:
- `qwen3-vl:8b` — ~7.2 GB (vision)
- `qwen3:8b` — ~6.1 GB (текст)
- `bge-m3` — ~1.2 GB (эмбеддинги)
Итого ~14.5 GB — влезает с запасом, и переключение vision↔текст происходит без выгрузки модели. Проверено через `/api/ps`: после текстового вызова в памяти остаются обе модели.
## Итог
- **Vision** полностью локальный — картинки описываются на сервере, в облако не уходят.
- **Текстовые aux** (заголовки, извлечение текста) — локальные, быстрые, бесплатные.
- **Compression** остался в облаке — ему нужен контекст 64K, который локально не влезает.
- Облачные токены тратятся только на основную модель и сжатие контекста — экономия существенная.
Самое ценное знание, которым делюсь: **если вы используете Qwen3 в Ollama для вспомогательных задач — не забудьте `think: false`**. Это превращает задумчивую модель, которая час думает над заголовком, в мгновенного исполнителя. И помните: `/no_think`, `enable_thinking` и `thinking: disabled` — в Ollama не работают, работает только корневой `think: false`.
---
*Полезные ссылки: [Hermes Agent](https://hermes-agent.nousresearch.com) · [Ollama qwen3-vl](https://ollama.com/library/qwen3-vl) · [Ollama qwen3](https://ollama.com/library/qwen3)*