docs: add model profiles, evaluation rubric, and CLAUDE.md
KI_TOOLS_PROFILES.md records what each local GGUF is actually for, based on the model cards: ornith is a purpose-built agentic coding model, Carnice targets agent runtimes, Qwopus is reasoning plus vision, and the two HauhauCS models are abliterated — an axis about refusals, not literary quality. It also maps which models the local mmproj.gguf fits (the Qwen3.6-35B-A3B based ones, not ornith). Capability and benchmark claims are attributed to their authors, not asserted. EVAL_RUBRIC.md separates what a script can measure from what needs reading, and warns that a passing test suite only proves the code satisfies its own tests. CHANGELOG covers the mmproj feature, the --print-effective-config fix, and the new tooling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6f2f8aff6c
commit
bee6a71de0
4 changed files with 406 additions and 0 deletions
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -11,11 +11,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Per-profile chat streaming and chat-request timeouts: `stream`, `read_timeout`
|
- Per-profile chat streaming and chat-request timeouts: `stream`, `read_timeout`
|
||||||
and `connect_timeout` are now resolvable in `[default]`/`[model.<profile>]`
|
and `connect_timeout` are now resolvable in `[default]`/`[model.<profile>]`
|
||||||
(CLI `--stream`/`--read-timeout`/`--connect-timeout` still override).
|
(CLI `--stream`/`--read-timeout`/`--connect-timeout` still override).
|
||||||
|
- Multimodal support: `mmproj` and `mmproj_offload` config keys (CLI `--mmproj`,
|
||||||
|
`--no-mmproj-offload`) pass a vision projector to the server. The path resolves
|
||||||
|
under `hf_home` like `model_path`, and a configured-but-missing projector now
|
||||||
|
fails with exit code 3 — for `--change` before the running container is removed.
|
||||||
|
- `docs/KI_TOOLS_PROFILES.md`: which local model suits which task, plus mmproj
|
||||||
|
compatibility per base model.
|
||||||
|
- `docs/EVAL_RUBRIC.md` and `scripts/eval_prompt_tests.py`: scoring rubric and an
|
||||||
|
evaluator for the manual prompt-test archive that measures length compliance and
|
||||||
|
**executes** the model-generated code against its own pytest suite.
|
||||||
|
- `scripts/run_prompt_suite.sh`: runs a prompt domain against a running profile and
|
||||||
|
stores the outputs under the archive's naming convention.
|
||||||
|
- `[model.qwen35base]` profile: the non-abliterated Qwen3.6-35B-A3B (bartowski
|
||||||
|
imatrix Q4_K_M) as a control for the abliteration comparison. Inherits sampling,
|
||||||
|
`ctx_size` and cache types from `[default]`; only model, container, port and GPU
|
||||||
|
differ, so it runs alongside the production server.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- The chat request now honors the configured `(connect, read)` timeout instead
|
- The chat request now honors the configured `(connect, read)` timeout instead
|
||||||
of a hard-coded 30 s; the default `read_timeout` is 600 s so slow reasoning
|
of a hard-coded 30 s; the default `read_timeout` is 600 s so slow reasoning
|
||||||
models are no longer cut off mid-generation.
|
models are no longer cut off mid-generation.
|
||||||
|
- **Breaking:** `--print-effective-config` is now an action in the mutually
|
||||||
|
exclusive action group instead of a flag, and it skips the `docker_available()`
|
||||||
|
check. `--print-effective-config --start` is therefore an argparse error
|
||||||
|
(exit 2) rather than a config dump followed by a real container start.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `--print-effective-config` combined with an action silently performed that
|
||||||
|
action. Documented as a diagnostic command (README, installation guide, manual),
|
||||||
|
`--print-effective-config --config … --start` printed the resolved config and
|
||||||
|
then ran `do_start()`, replacing a running container with the `[default]` model.
|
||||||
|
|
||||||
## [0.1.0] - 2026-07-07
|
## [0.1.0] - 2026-07-07
|
||||||
|
|
||||||
|
|
|
||||||
104
CLAUDE.md
Normal file
104
CLAUDE.md
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -e ".[dev]" # dev install
|
||||||
|
scripts/check.sh # full local CI gate (ruff + mypy + pytest) — mirrors .forgejo/workflows/ci.yml
|
||||||
|
python -m pytest -q # tests
|
||||||
|
python -m pytest tests/test_prompt_urls.py -q # one file
|
||||||
|
python -m pytest tests/test_actions.py::test_do_start -q # one test
|
||||||
|
ruff check src/ tests/ build_archive.py
|
||||||
|
mypy # config in pyproject.toml (files = src/llamacppctl)
|
||||||
|
```
|
||||||
|
|
||||||
|
Always use `python -m pytest`, never the `pytest` console script: the test modules do
|
||||||
|
`from tests.test_docker_ops import ...`, which needs the repo root on `sys.path`.
|
||||||
|
|
||||||
|
`git config core.hooksPath .githooks` (once per clone) enables the pre-push hook that runs
|
||||||
|
`scripts/check.sh`. CI runs on Python 3.10 and 3.12; `requires-python = ">=3.10"`.
|
||||||
|
|
||||||
|
Other entry points:
|
||||||
|
- `python3 build_archive.py` — builds and self-verifies `llamacppctl-installable.tar.gz`
|
||||||
|
(has its own required-file manifest; adding a top-level file that must ship means updating it).
|
||||||
|
- `SMOKE_GPU=1 scripts/smoke.sh` — opt-in end-to-end test against a real Docker + GPU + GGUF model.
|
||||||
|
Not part of the pytest suite.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
A single CLI (`llamacppctl`) that starts/checks/stops/switches llama.cpp servers running as Docker
|
||||||
|
containers, plus a security-hardened input layer for system/user prompts from text, file, or URL.
|
||||||
|
|
||||||
|
`main.py` is a thin pipeline: parse (`cli.build_parser`) → validate (`cli.validate_args`) →
|
||||||
|
`docker_available()` → resolve prompt sources (`prompt_io`) → resolve config
|
||||||
|
(`config.resolve_effective_config`) → dispatch to `actions.do_*`.
|
||||||
|
|
||||||
|
Layering is deliberate and must be preserved — it keeps the security-critical input validation
|
||||||
|
independently testable from orchestration:
|
||||||
|
- `prompt_io.py` knows nothing about argparse; it works only with `PromptSource` + `InputPolicy`.
|
||||||
|
- `config.py` knows nothing about Docker or HTTP.
|
||||||
|
- `docker_ops.py` / `http_ops.py` know nothing about CLI semantics.
|
||||||
|
- `actions.py` orchestrates; `schema.py` holds the shared dataclasses (`ServerConfig`,
|
||||||
|
`PromptConfig`, `ChatReply`, `CheckResult`).
|
||||||
|
|
||||||
|
Two cross-module couplings to know about:
|
||||||
|
- `main._resolve_prompts()` stashes loaded prompts on the argparse namespace as
|
||||||
|
`args._resolved_system_prompt` / `args._resolved_user_prompt`; `config.py` picks them up there.
|
||||||
|
- `main.run()` calls `docker_available()` *before* config resolution, so `--dry-run` still
|
||||||
|
needs a reachable Docker daemon. Only `--print-effective-config` skips that check — it is a
|
||||||
|
standalone action in the mutually-exclusive group, never a modifier, so it cannot start
|
||||||
|
anything.
|
||||||
|
|
||||||
|
### Config resolution
|
||||||
|
|
||||||
|
INI file (`llama.cpp.config`, template in `llama.cpp.config.example`), lowest to highest priority:
|
||||||
|
builtin defaults (`config.builtin_defaults()`) → `[default]` → `[model.<profile>]` (via `--profile`)
|
||||||
|
→ CLI overrides. `[prompt.<name>]` sections resolve separately and only supply a *fallback* system
|
||||||
|
prompt — an explicit `-s`/`--system-file`/`--system-url` always wins.
|
||||||
|
|
||||||
|
`container_name` is mandatory (empty → `ConfigError`). It is the only identity anchor: Docker
|
||||||
|
`--name`, the `--stop`/`--check` target, and the derived lock path
|
||||||
|
`/tmp/llamacppctl.<container_name>.lock`. Profiles meant to run in parallel need distinct
|
||||||
|
`container_name` *and* `host_port`, otherwise a second `--start` silently replaces the first
|
||||||
|
container.
|
||||||
|
|
||||||
|
`max_tokens` / `chat_temperature` / `connect_timeout` / `read_timeout` affect only the chat request
|
||||||
|
(`--chat` and the reply printed after `--start`), never the container.
|
||||||
|
|
||||||
|
### Exit codes (`actions.py`)
|
||||||
|
|
||||||
|
`0` ok · `1` general/config/prompt error · `2` argparse validation · `3` model path missing ·
|
||||||
|
`4` docker error · `5` HTTP not ready (also `--check` failing) · `6` lock busy.
|
||||||
|
`--check` is meant to be scriptable; keep those codes stable.
|
||||||
|
|
||||||
|
## Invariants worth not breaking
|
||||||
|
|
||||||
|
- All Docker calls go through `subprocess.run()` with **argument lists** — never `shell=True`,
|
||||||
|
never composed shell strings.
|
||||||
|
- The port publishes to `127.0.0.1` by default (`docker_ops._port_publish()`); the llama.cpp
|
||||||
|
OpenAI endpoint is unauthenticated unless `api_key` is set. `--expose` binds all interfaces.
|
||||||
|
- Every HTTP request in `prompt_io` — including each redirect hop — passes `validate_url_target()`:
|
||||||
|
HTTPS-only, no IP literals, no embedded credentials, no `localhost`, all resolved addresses
|
||||||
|
classified (private/loopback/link-local/multicast/reserved/unspecified → reject), metadata IP
|
||||||
|
`169.254.169.254` blocked. `_pin_dns()` then restricts `getaddrinfo` to the already-validated IPs
|
||||||
|
for the duration of the request, closing the TOCTOU/DNS-rebinding window. Size limits are enforced
|
||||||
|
both from `Content-Length` and while streaming.
|
||||||
|
- Escape hatches (`--allow-private-url`, `--allow-insecure-http`, `--allow-ip-host`,
|
||||||
|
`--allow-symlinks`, `--follow-redirects`, `--allow-html-input`) are opt-in and off by default.
|
||||||
|
`--allow-private-url` and `--url-allow-host` are mutually exclusive.
|
||||||
|
- `--start` and `--change` hold an exclusive non-blocking `fcntl.flock`; `--change` validates the
|
||||||
|
model path *before* removing the running container. `--dry-run` takes no lock and touches nothing.
|
||||||
|
|
||||||
|
Tests mock `subprocess` and `requests` (and DNS resolution for the SSRF cases); nothing in the
|
||||||
|
pytest suite requires Docker or the network.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Docs, comments in `docs/`, and the example prompts are in German; source code, docstrings, and
|
||||||
|
commit subjects are in English. Commits follow Conventional Commits (`feat(chat):`, `docs(prompts):`).
|
||||||
|
- Line length 100, `from __future__ import annotations` in every module, `py.typed` is shipped —
|
||||||
|
keep annotations complete enough for `mypy` to pass.
|
||||||
|
- Behavior changes should be reflected in `man/llamacppctl.1`, `CHANGELOG.md`, and — for security-
|
||||||
|
relevant ones — `docs/SECURITY_AND_OPERATIONS.md`.
|
||||||
108
docs/EVAL_RUBRIC.md
Normal file
108
docs/EVAL_RUBRIC.md
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
# Bewertungsrubrik für Modell-Prompt-Tests
|
||||||
|
|
||||||
|
Zweck: Modellwechsel (anderes Modell, andere Quantisierung, `Balanced` statt
|
||||||
|
`Aggressive`, MTP, KV-Cache-Einstellungen) sollen an **Zahlen** entschieden
|
||||||
|
werden, nicht an Bauchgefühl. Ohne Vorher-Nachher-Messung ist nicht feststellbar,
|
||||||
|
ob eine Änderung verbessert oder verschlechtert hat.
|
||||||
|
|
||||||
|
Grundlage sind die Läufe unter `~/llamacppctl_prompt_tests/` gegen die Prompts in
|
||||||
|
`example_user_prompts/`. Modelleignung siehe [`KI_TOOLS_PROFILES.md`](KI_TOOLS_PROFILES.md).
|
||||||
|
|
||||||
|
## Zwei Ebenen
|
||||||
|
|
||||||
|
**Objektiv** — von `scripts/eval_prompt_tests.py` automatisch gemessen, keine
|
||||||
|
Meinung nötig:
|
||||||
|
|
||||||
|
| Metrik | Domäne | Bedeutung |
|
||||||
|
|---|---|---|
|
||||||
|
| Wortzahl, Abweichung vom Ziel | prosa, reden | Der Prompt nennt ein Ziel („etwa 1200 Wörtern"). |
|
||||||
|
| Trunkierungsverdacht | alle | Text endet ohne Satzzeichen → Budget zu klein. |
|
||||||
|
| Tests laufen durch | coding | Der generierte Code wird **wirklich ausgeführt**. |
|
||||||
|
| Anteil bestandener Tests | coding | `passed / (passed + failed)`. |
|
||||||
|
|
||||||
|
**Subjektiv** — von Hand oder per LLM-Judge, Skala 1–5. Die Anker unten sind
|
||||||
|
bewusst so formuliert, dass 3 „brauchbar, aber mit Mängeln" bedeutet; ein
|
||||||
|
durchschnittlich guter Text landet nicht automatisch bei 4.
|
||||||
|
|
||||||
|
## Skala
|
||||||
|
|
||||||
|
| Punkte | Bedeutung |
|
||||||
|
|---|---|
|
||||||
|
| 5 | Kriterium durchgängig erfüllt; kein Eingriff nötig. |
|
||||||
|
| 4 | Erfüllt, mit einzelnen Schwächen, die den Gesamteindruck nicht tragen. |
|
||||||
|
| 3 | Brauchbar, aber erkennbare Mängel; Überarbeitung nötig. |
|
||||||
|
| 2 | Kriterium überwiegend verfehlt; Grundgerüst vorhanden. |
|
||||||
|
| 1 | Verfehlt. |
|
||||||
|
|
||||||
|
## Prosa
|
||||||
|
|
||||||
|
1. **Show, don't tell** — Innenleben ausschließlich über Handlung, Gegenstand,
|
||||||
|
Wahrnehmung. *1 = benannte Gefühle („sie war traurig"); 5 = kein einziges
|
||||||
|
benanntes Gefühl, Zustand trotzdem eindeutig.*
|
||||||
|
2. **Schlussbild** — konkretes, bedeutungstragendes Bild statt Moral oder
|
||||||
|
Zusammenfassung. *1 = explizite Lehre; 5 = Bild, das die Geschichte trägt.*
|
||||||
|
3. **Ton- und Registertreue** — hält die geforderte Tonlage (z. B. „nüchtern,
|
||||||
|
ohne Pathos") über den gesamten Text.
|
||||||
|
4. **Sprachliche Präzision** — konkrete Substantive, keine Füllattribute, keine
|
||||||
|
Klischees.
|
||||||
|
5. **Komposition** — Aufbau trägt; kein Leerlauf, kein abrupter Abbruch.
|
||||||
|
6. **Sprachrichtigkeit (Deutsch)** — Grammatik, Kasus, Idiomatik. *Eigener
|
||||||
|
Punkt, weil abliterierte, primär englisch trainierte Modelle hier auffällig
|
||||||
|
sind.*
|
||||||
|
|
||||||
|
## Reden
|
||||||
|
|
||||||
|
1. **Argumentative Substanz** — trägt der Gedankengang, oder reiht er Behauptungen?
|
||||||
|
2. **Vorweggenommene Einwände** — wird der stärkste Gegeneinwand benannt und
|
||||||
|
beantwortet, nicht der schwächste?
|
||||||
|
3. **Benannte Zielkonflikte** — werden echte Interessengegensätze offen
|
||||||
|
ausgesprochen statt harmonisiert?
|
||||||
|
4. **Rhetorische Mittel** — bewusst und sparsam eingesetzt (Trikolon, Anapher,
|
||||||
|
Antithese), nicht dekorativ.
|
||||||
|
5. **Adressatenbezug** — Sprache, Beispiele und Anrede passen zum Publikum.
|
||||||
|
6. **Sprachrichtigkeit (Deutsch)** — siehe oben.
|
||||||
|
|
||||||
|
## Coding
|
||||||
|
|
||||||
|
1. **Korrektheit** — *primär aus dem automatischen Testlauf.* Ein Modul, dessen
|
||||||
|
eigene Tests durchfallen, kann in diesem Kriterium nicht über 2 kommen.
|
||||||
|
2. **Anforderungsabdeckung** — sind alle Punkte des Prompts umgesetzt?
|
||||||
|
3. **Fehlerbehandlung** — die im Prompt geforderten Fehlerfälle, sauber getrennt.
|
||||||
|
4. **Testqualität** — decken die Tests die genannten Fälle ab, und sind sie
|
||||||
|
konsistent zum eigenen Code (richtiger Exception-Typ, Fixtures erfüllen das
|
||||||
|
Schema)?
|
||||||
|
5. **Keine Halluzinationen** — keine erfundenen APIs, Signaturen,
|
||||||
|
Framework-Aussagen oder Benchmark-Messwerte. *Automatisch nicht prüfbar;
|
||||||
|
erfundene Messwerte sind in den bisherigen Läufen wiederholt aufgetreten.*
|
||||||
|
6. **Lesbarkeit** — Benennung, Struktur, Kommentardichte.
|
||||||
|
|
||||||
|
## Durchführung
|
||||||
|
|
||||||
|
- **Blind bewerten.** Die Modellzuordnung steckt im Dateinamen; beim Scoren
|
||||||
|
ausblenden (`scripts/eval_prompt_tests.py --anonymize` schreibt anonymisierte
|
||||||
|
Kopien mit Zufalls-IDs und eine Auflösungstabelle).
|
||||||
|
- **Ein Kriterium über alle Texte**, nicht ein Text über alle Kriterien. Das
|
||||||
|
hält den Maßstab konstant.
|
||||||
|
- **LLM-Judge:** möglich gegen den lokalen Server, aber der Judge darf **nicht**
|
||||||
|
das bewertete Modell sein. Ein Modell bewertet seine eigenen Texte zu gut.
|
||||||
|
Der Judge ersetzt die menschliche Stichprobe nicht — mindestens 20 % der Texte
|
||||||
|
gegenlesen und die Übereinstimmung prüfen.
|
||||||
|
- **Mindestens zwei Läufe pro Zelle**, weil bei `temp > 0` ein Einzellauf wenig
|
||||||
|
aussagt. Für Coding-Vergleiche `--seed` fixieren.
|
||||||
|
|
||||||
|
## Was die Zahlen nicht sagen
|
||||||
|
|
||||||
|
Ein bestandener Testlauf beweist, dass der Code *seine eigenen* Tests besteht —
|
||||||
|
nicht, dass er korrekt ist. Wenn Modell und Test aus derselben Halluzination
|
||||||
|
stammen, sind beide konsistent falsch. Kriterium 4 (Testqualität) ist deshalb
|
||||||
|
nicht redundant zu Kriterium 1, sondern dessen Korrektiv.
|
||||||
|
|
||||||
|
## Sicherheitshinweis
|
||||||
|
|
||||||
|
`scripts/eval_prompt_tests.py` führt **modellgenerierten Code aus**. Das ist der
|
||||||
|
Sinn der Übung, aber es ist Codeausführung aus einer nicht vertrauenswürdigen
|
||||||
|
Quelle. Der Runner arbeitet in einem temporären Verzeichnis, erzwingt ein
|
||||||
|
Zeitlimit und verweigert den Start als `root`. Er bietet **keine** Netz- oder
|
||||||
|
Dateisystem-Isolation. Wer die Läufe auf einem Rechner mit Produktionsdaten
|
||||||
|
auswertet, sollte `--no-exec` verwenden oder das Skript in einem Container
|
||||||
|
starten.
|
||||||
169
docs/KI_TOOLS_PROFILES.md
Normal file
169
docs/KI_TOOLS_PROFILES.md
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
# Modellprofile — Eignung der lokalen GGUF-Modelle
|
||||||
|
|
||||||
|
Dieses Dokument beschreibt, **wofür** sich die Modelle unter
|
||||||
|
`$HF_HOME/models/qwen3/` jeweils eignen, unabhängig von den Beispiel-Prompts in
|
||||||
|
`example_system_prompts/`. Grundlage sind die Modellkarten auf Hugging Face
|
||||||
|
(Stand Juli 2026) sowie die eigenen Testläufe unter `~/llamacppctl_prompt_tests/`.
|
||||||
|
|
||||||
|
> Die Angaben zu Fähigkeiten und Benchmarks stammen, wo nicht anders vermerkt,
|
||||||
|
> **von den Modellautoren selbst** und sind nicht unabhängig verifiziert.
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
| Datei | Profil | Basis | Primäre Eignung |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `ornith-1.0-35b-Q4_K_M.gguf` | `ornith35b` | Qwen3.5-MoE | Agentisches Coding |
|
||||||
|
| `Carnice-Qwen3.6-MoE-35B-A3B-Q4_K_M.gguf` | `carnice` | Qwen3.6-35B-A3B | Agenten-/Tool-Calling-Workflows |
|
||||||
|
| `Qwopus3.6-35B-A3B-v1-Q4_K_M.gguf` | `qwopus` | Qwen3.6-35B-A3B | Reasoning, Vision, Tool-Calling |
|
||||||
|
| `Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf` | `[default]` | Qwen3.6-35B-A3B | Kreatives Schreiben ohne Verweigerungen |
|
||||||
|
| `Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf` | `qwen27b` | Qwen3.6-27B (dense) | Wie oben, kleinerer VRAM-Bedarf |
|
||||||
|
| `mmproj.gguf` | — | Qwen3.6-35B-A3B | Vision-Projektor (kein eigenständiges Modell) |
|
||||||
|
|
||||||
|
Alle 35B-A3B-Modelle sind MoE mit **3 B aktiven Parametern** pro Token: hoher
|
||||||
|
Durchsatz bei 21 GB VRAM-Bedarf. Das 27B ist dense — langsamer pro Token, aber
|
||||||
|
nur ~15 GB.
|
||||||
|
|
||||||
|
## Ornith-1.0-35B — agentisches Coding
|
||||||
|
|
||||||
|
Quelle: [`deepreinforce-ai/Ornith-1.0-35B-GGUF`](https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B-GGUF) (MIT)
|
||||||
|
|
||||||
|
Ein dediziertes Coding-Modell aus einer selbstverbessernden Modellfamilie. Das
|
||||||
|
Trainings-Framework erzeugt per RL nicht nur Lösungs-Rollouts, sondern optimiert
|
||||||
|
auch das treibende Scaffold gemeinsam mit ihnen. Beworben mit SOTA unter
|
||||||
|
vergleichbar großen Open-Source-Modellen auf Terminal-Bench 2.1, SWE-Bench,
|
||||||
|
NL2Repo und OpenClaw. Reasoning-Modell: die Assistant-Antwort beginnt mit einem
|
||||||
|
`<think>`-Block.
|
||||||
|
|
||||||
|
**Einsetzen für:** Code-Generierung, Refactoring, Repo-weite Aufgaben,
|
||||||
|
Agenten-Loops mit Tool-Calls.
|
||||||
|
**Nicht einsetzen für:** Prosa und Reden — dafür ist das Sampling im Profil
|
||||||
|
(`temp = 0.20`) bewusst deterministisch gewählt.
|
||||||
|
|
||||||
|
Beachte: Basis ist **Qwen3.5**-MoE (`qwen3_5_moe`), nicht 3.6. Die lokale
|
||||||
|
`mmproj.gguf` passt deshalb *nicht* zu diesem Modell.
|
||||||
|
|
||||||
|
## Carnice-Qwen3.6-MoE-35B-A3B — Agenten-Workflows
|
||||||
|
|
||||||
|
Quelle: [`samuelcardillo/Carnice-Qwen3.6-MoE-35B-A3B`](https://huggingface.co/samuelcardillo/Carnice-Qwen3.6-MoE-35B-A3B)
|
||||||
|
|
||||||
|
QLoRA-Finetune von Qwen3.6-35B-A3B, trainiert auf echten Execution-Traces der
|
||||||
|
Hermes-Agent-Runtime. Das erklärte Ziel ist, dem Modell die konkreten
|
||||||
|
Konversationsmuster beizubringen, die ein Agenten-Runtime erwartet — nicht
|
||||||
|
generisches Reasoning.
|
||||||
|
|
||||||
|
**Einsetzen für:** Tool-Calling-Pipelines, Agenten-Orchestrierung (z. B. n8n),
|
||||||
|
strukturierte Mehrschritt-Abläufe.
|
||||||
|
|
||||||
|
## Qwopus3.6-35B-A3B-v1 — Reasoning + Vision
|
||||||
|
|
||||||
|
Quelle: [`Jackrong/Qwopus3.6-35B-A3B-v1`](https://huggingface.co/Jackrong/Qwopus3.6-35B-A3B-v1)
|
||||||
|
|
||||||
|
Reasoning-verstärkter Finetune, dreistufiges SFT mit progressiv steigender
|
||||||
|
Reasoning-Komplexität. Unterstützt Vision und Tool-Calling.
|
||||||
|
|
||||||
|
**Einsetzen für:** Aufgaben mit langer Gedankenkette, multimodale Eingaben.
|
||||||
|
**Vorbehalt:** Der Autor kennzeichnet das Modell ausdrücklich als experimentell,
|
||||||
|
ohne vollständige Performance- oder Sicherheitsevaluation.
|
||||||
|
|
||||||
|
Für reines Coding gibt es die separate Variante
|
||||||
|
[`Qwopus3.6-35B-A3B-Coder-MTP`](https://huggingface.co/Jackrong/Qwopus3.6-35B-A3B-Coder-MTP-GGUF)
|
||||||
|
(thinking-off, 62,4 % auf einem 300-Fall-SWE-Bench-Lauf) — lokal nicht vorhanden.
|
||||||
|
|
||||||
|
## HauhauCS Uncensored (35B-A3B und 27B) — kreatives Schreiben
|
||||||
|
|
||||||
|
Quellen: [35B-A3B](https://huggingface.co/HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive),
|
||||||
|
[27B](https://huggingface.co/HauhauCS/Qwen3.6-27B-Uncensored-HauhauCS-Aggressive)
|
||||||
|
|
||||||
|
**Abliterierte** Modelle: keine neuen Fähigkeiten, entfernte Verweigerungen
|
||||||
|
(Modellkarte: „0/465 Refusals"). Alle Quants mit imatrix erzeugt. Beide sind
|
||||||
|
multimodal.
|
||||||
|
|
||||||
|
**Einsetzen für:** Prosa, Reden, Dialog, Rollenspiel — Themen, bei denen ein
|
||||||
|
aligntes Modell abbricht.
|
||||||
|
**Nicht einsetzen für:** Coding. Eigene Testläufe zeigen wiederkehrend Tests, die
|
||||||
|
inkonsistent zum selbst erzeugten Schema sind, erfundene Framework-Aussagen und
|
||||||
|
Benchmarks mit erfundenen Messwerten.
|
||||||
|
|
||||||
|
Zwei Punkte, die in der aktuellen Konfiguration relevant sind:
|
||||||
|
|
||||||
|
1. Die Karte des 27B empfiehlt selbst, dass **99,9 % der Nutzer die
|
||||||
|
`Balanced`-Variante** nehmen sollten statt `Aggressive`. Beide erreichen
|
||||||
|
dieselbe Refusal-Rate; `Balanced` bietet zusätzlich stabileres Sampling für
|
||||||
|
agentic coding, Tool-Use und Reasoning. `Aggressive` spart lediglich
|
||||||
|
Vorreden. Aktuell sind beide lokalen HauhauCS-Modelle `Aggressive`.
|
||||||
|
2. Die Behauptungen „lossless" und „zero capability loss" stammen vom Autor der
|
||||||
|
Modellkarte. Abliteration kostet in aller Regel *etwas* Fähigkeit.
|
||||||
|
|
||||||
|
## Empirische Befunde (eigene Läufe)
|
||||||
|
|
||||||
|
Getestet gegen das Default-Modell (HauhauCS 35B-A3B), Reasoning aktiv, ctx 262144:
|
||||||
|
|
||||||
|
- **Längenvorgaben werden nicht präzise getroffen** (−27 % bis +26 % über sechs
|
||||||
|
Läufe). Länge als Spanne vorgeben oder im zweiten Turn nachjustieren.
|
||||||
|
- **Reasoning frisst das Antwortbudget.** Bei `--max-tokens 10000` endeten
|
||||||
|
schwere Aufgaben in `finish_reason=length`. Für Prosa/Reden/Dialog
|
||||||
|
`--max-tokens` ≥ 16000 wählen.
|
||||||
|
- **`--chat` ohne `--stream`** läuft bei langem Output in den Read-Timeout.
|
||||||
|
Immer `--stream` verwenden (jeder Token setzt den Timeout zurück).
|
||||||
|
- **Coding: Struktur gut, Korrektheit unzuverlässig.** Generierten Code und
|
||||||
|
generierte Tests immer wirklich ausführen.
|
||||||
|
|
||||||
|
Rohdaten: `~/llamacppctl_prompt_tests/`.
|
||||||
|
|
||||||
|
## Vision (mmproj)
|
||||||
|
|
||||||
|
Die lokale `mmproj.gguf` (902 MB) ist der Vision-Encoder des **Basismodells
|
||||||
|
Qwen3.6-35B-A3B** (aus dem unsloth-Repo). GGUF-Metadaten:
|
||||||
|
|
||||||
|
```
|
||||||
|
general.architecture = clip
|
||||||
|
general.name = Qwen3.6 35B A3B
|
||||||
|
clip.projector_type = qwen3vl_merger
|
||||||
|
clip.has_vision_encoder
|
||||||
|
```
|
||||||
|
|
||||||
|
Ein mmproj ist kein eigenständiges Modell, sondern projiziert Bild-Embeddings in
|
||||||
|
den Textmodell-Raum. Er muss zum Vision-Tower der jeweiligen Basis passen.
|
||||||
|
|
||||||
|
| Modell | mmproj.gguf passt? |
|
||||||
|
|---|---|
|
||||||
|
| HauhauCS 35B-A3B | ja (Basis Qwen3.6-35B-A3B) |
|
||||||
|
| Qwopus3.6-35B-A3B | ja (dieselbe Basis) |
|
||||||
|
| Carnice-Qwen3.6-MoE-35B-A3B | ja (dieselbe Basis) |
|
||||||
|
| `ornith-1.0-35b` | **nein** — Basis Qwen3.5-MoE, eigener Projektor nötig |
|
||||||
|
| HauhauCS 27B (dense) | **nein** — anderer Vision-Encoder |
|
||||||
|
|
||||||
|
Verwendung über `llamacppctl` (siehe `[model.vision]` in `llama.cpp.config`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
llamacppctl --start --config llama.cpp.config --profile vision
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Profil setzt `mmproj = models/qwen3/mmproj.gguf`; der Pfad wird — wie
|
||||||
|
`model_path` — relativ zu `hf_home` aufgelöst und als `--mmproj` an den
|
||||||
|
llama.cpp-Server durchgereicht. Der Projektor wird standardmäßig auf die GPU
|
||||||
|
ausgelagert; `mmproj_offload = false` bzw. `--no-mmproj-offload` verhindert das,
|
||||||
|
wenn der VRAM knapp ist.
|
||||||
|
|
||||||
|
Bilder gehen anschließend über den OpenAI-kompatiblen Endpunkt
|
||||||
|
`/v1/chat/completions` als `image_url`-Content-Part. `llamacppctl --chat` sendet
|
||||||
|
derzeit nur Text; für Bild-Requests den Endpunkt direkt ansprechen.
|
||||||
|
|
||||||
|
## MTP / Speculative Decoding (nicht lokal vorhanden)
|
||||||
|
|
||||||
|
Für Ornith, Carnice und Qwopus existieren **MTP-Quants** mit eingebettetem
|
||||||
|
Multi-Token-Prediction-Head. Mit hinreichend aktuellem llama.cpp erlauben sie
|
||||||
|
self-speculative Decoding ohne separates Draft-Modell (`--draft-mtp`);
|
||||||
|
Community-Berichte nennen etwa doppelten Decode-Durchsatz bei ~2,5 % größerer
|
||||||
|
Datei. Die im pyproject gepinnte Image-Version muss das unterstützen.
|
||||||
|
|
||||||
|
## Quellen
|
||||||
|
|
||||||
|
- <https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B-GGUF>
|
||||||
|
- <https://huggingface.co/SC117/Ornith-1.0-35B-MTP-APEX-GGUF>
|
||||||
|
- <https://huggingface.co/samuelcardillo/Carnice-Qwen3.6-MoE-35B-A3B>
|
||||||
|
- <https://huggingface.co/Jackrong/Qwopus3.6-35B-A3B-v1>
|
||||||
|
- <https://huggingface.co/Jackrong/Qwopus3.6-35B-A3B-Coder-MTP-GGUF>
|
||||||
|
- <https://huggingface.co/HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive>
|
||||||
|
- <https://huggingface.co/HauhauCS/Qwen3.6-27B-Uncensored-HauhauCS-Aggressive>
|
||||||
|
- <https://github.com/ggml-org/llama.cpp/blob/master/docs/multimodal.md>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue