Ollama-URL korrigiert (100.103.83.12:11435) und M1/M2 gegen Echt-System validiert

Der Host betreibt zwei Ollama-Instanzen: 11434 (fast leer, 0.16.2) und
11435 (Ziel-Instanz, 0.32.13, Modell-Zoo) — Port nicht mehr auf 11434
'korrigieren' (Dokumentation + Skill + Config-Default angepasst).

Validierung gegen das echte System: bge-m3 per API gepullt, Hybrid-Index
(3005 Chunks, 100 % eingebettet, 144 s), M1-Akzeptanz erreicht (Recall@8
0,952 > 0,9; Hit-Rate 0,968). Antwortmodus-Eval mit qwen3.8:27b (Thinking
verifiziert aus): Zitier-Präzision 100 % (4 Regenerierungen), Verweigerung
korrekt 94,3 %, Latenz mean 32 s. ATZ-Konfliktfall korrekt beide Werte
mit Warnung. generate.py: sources enthaelt jetzt nur zitierte Quellen;
Systemprompt ohne redundante Quellenzeile.

Bake-off-Feld (M3) bereits installiert: qwen3.6:27B, gemma4:26b,
mistral-small3.1:24b, gemma4:12B.
This commit is contained in:
2026-09-14 22:09:09 +02:00
parent 2cba72aeb0
commit b6a6f5b788
6 changed files with 100 additions and 79 deletions
+21 -14
View File
@@ -49,7 +49,7 @@ python -m agent.cli serve # http://127.0.0.1:8080 (/ask, /health, /r
| Variable | Default | Bedeutung |
|---|---|---|
| `OLLAMA_URL` | `http://100.183.83.12:11435` | Ollama-Server (Custom-Port!) |
| `OLLAMA_URL` | `http://100.103.83.12:11435` | Ollama-Server (Ziel-Instanz; der Host betreibt zusätzlich eine fast leere Instanz auf 11434 — nicht "korrigieren") |
| `PV_ANSWER_MODEL` | `qwen3.8:27b` | Antwortmodell (provisorisch bis Bake-off M3) |
| `PV_EMBED_MODEL` | `bge-m3` | Embedding-Modell |
| `PV_DB_PATH` | `data/index.db` | SQLite-Index |
@@ -62,25 +62,32 @@ python -m agent.cli serve # http://127.0.0.1:8080 (/ask, /health, /r
## Deployment auf dem Host (Ollama-Maschine)
```bash
# Modelle einmalig pullen
ollama pull qwen3.8:27b
ollama pull bge-m3
curl http://100.183.83.12:11435/api/tags # Erreichbarkeit + Modelle
# Ollama-Ziel-Instanz prüfen (Custom-Port! Achtung: auf dem Host läuft
# zusätzlich eine fast leere Instanz auf 11434 — nicht verwexseln)
curl http://100.103.83.12:11435/api/tags # qwen3.8:27b, bge-m3, Bake-off-Feld installiert
# Vollständiger Index (BM25 + Dense) — danach eval, Ziel: Recall@8 > 0,9
# Vollständiger Index (BM25 + Dense)
python -m agent.cli ingest
python -m agent.cli eval
python -m agent.cli eval --answers # Zitier-Präzision, Verweigerungen, Latenz
python -m agent.cli eval --answers --json-out data/eval-report.json # Zitier-Präzision, Verweigerungen, Latenz
```
## Baseline (2026-09-14, BM25-only, ohne Dense)
## Baseline (2026-09-14, Hybrid BM25 + bge-m3, Ollama :11435)
Goldset (31 Fragen, `agent/eval/goldset.yaml`): Hit-Rate 0,871 ·
Recall@8 0,855 · MRR 0,476. Die vier Fehltreffer sind klassische
BM25-Schwächen (Komposita: „aliquotiert"↔„Aliquotierung";
„Mindestlohngesetz") — genau die Fälle, die die Dense-Suche abdecken soll.
Hybrid-Messung auf dem Host aussteht (Ollama aus der Zed-Sandbox nicht
erreichbar).
**Retrieval** (Goldset, 31 Fragen): Hit-Rate 0,968 · **Recall@8 0,952** ·
MRR 0,690 — M1-Ziel >0,9 erreicht (BM25-only war 0,855; die vier
BM25-Fehltreffer behebt die Dense-Suche alle).
**Antworten** (qwen3.8:27b, Thinking aus, Temperatur 0,1): **Zitier-Präzision
100 %** (4 Zitierverletzungen wurden von der Post-Validierung abgefangen und
regeneriert) · Verweigerung korrekt 94,3 % · erwartete Quelle zitiert 80,6 %
· Latenz mean 32 s / p95 53 s.
Bekannte Fehlverweigerungen: q-008 (Abfertigung Verfügungsmöglichkeiten),
q-031 (Mindestlohngesetz) — breite Fragen, Retrieval erfolgreich, Modell
verweigert trotzdem (sicheres Versagensmuster; M3-Prompt-Tuning-Kandidat).
Latenz-Hebel für M3: weniger Kontextblöcke, schnellere Kandidaten
(gemma4:12B, MoE).
## Dateien
+4 -2
View File
@@ -37,8 +37,10 @@ class Config:
kb_dir: str = "wissensbasis"
db_path: str = "data/index.db"
# Ollama (Custom-Port 11435 — nicht "korrigieren", s. Skill)
ollama_url: str = "http://100.183.83.12:11435"
# Ollama — Ziel-Instanz ist Port 11435 (Custom-Port, mit Modell-Zoo).
# Auf demselben Host läuft auch eine Instanz auf 11434 (fast leer) —
# NICHT auf 11434 "korrigieren", s. Skill.
ollama_url: str = "http://100.103.83.12:11435"
embed_model: str = "bge-m3"
answer_model: str = "qwen3.8:27b" # provisorisch bis Bake-off (M3)
+6 -5
View File
@@ -38,8 +38,7 @@ Verbindliche Regeln:
5. Widersprechen sich Kontextblöcke, nenne beide Werte mit ihren IDs und
kennzeichne den Widerspruch mit ⚠. Löse Widersprüche niemals stillschweigend auf.
6. Nenne Paragraphen und Gesetze nur, wenn ein Kontextblock sie nennt.
7. Antworte auf Deutsch, prägnant (Stichpunkte, wo sinnvoll), und füge am
Ende eine Zeile „Quellen:“ mit den verwendeten IDs (ID — Titel, Stand) an.
7. Antworte auf Deutsch und prägnant (Stichpunkte, wo sinnvoll).
Verletze Regel 2 oder Regel 4 niemals — im Zweifel verweigere die Antwort."""
@@ -123,14 +122,15 @@ def answer_question(
if own_retriever:
retriever.close()
def finish(answer, refused, verified, citations, regenerations=0, draft=None):
def finish(answer, refused, verified, citations, regenerations=0,
draft=None, sources=None):
return {
"question": question,
"answer": answer,
"refused": refused,
"verified": verified,
"citations": citations,
"sources": _source_rows(results),
"sources": sources if sources is not None else _source_rows(results),
"n_context": len(results),
"model": cfg.answer_model,
"regenerations": regenerations,
@@ -197,6 +197,7 @@ def answer_question(
citations=[],
regenerations=regenerations,
draft=retry,
sources=[],
)
citations = sorted(set(CITE_RE.findall(final)))
@@ -214,5 +215,5 @@ def answer_question(
]
return finish(
final, refused=refused, verified=not violations,
citations=citations, regenerations=regenerations,
citations=citations, regenerations=regenerations, sources=sources,
)