From 50e62509e6e33a5948963a39da9d655ddf778c18 Mon Sep 17 00:00:00 2001 From: Florian Egger Date: Mon, 14 Sep 2026 22:09:09 +0200 Subject: [PATCH] Ollama-URL korrigiert (100.103.83.12:11435) und M1/M2 gegen Echt-System validiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- pv-agent/.agents/MEMORY.md | 72 ++++++++++--------- pv-agent/.agents/skills/pv-rag-agent/SKILL.md | 10 +-- pv-agent/agent/README.md | 35 +++++---- pv-agent/agent/config.py | 6 +- pv-agent/agent/generate.py | 11 +-- pv-agent/planung.md | 45 +++++++----- 6 files changed, 100 insertions(+), 79 deletions(-) diff --git a/pv-agent/.agents/MEMORY.md b/pv-agent/.agents/MEMORY.md index 4cbb23a..f1b7c05 100644 --- a/pv-agent/.agents/MEMORY.md +++ b/pv-agent/.agents/MEMORY.md @@ -5,46 +5,50 @@ Rollender Übergabe-Log für agent-Threads. Workflow: `.agents/SKILL.md` ## Current focus -M1 (Index + Retrieval) und M2 (Ollama-Generierung + Grounding + API) sind -implementiert. Ausstehend: Host-Validierung mit Ollama (Dense-Index, -Antwortmodus-Eval) und Modell-Bake-off (M3). Odoo-Integration (M4) ist -separat zu planen. +M1 und M2 sind **fertig und gegen den echten Ollama validiert**. +Offen: Modell-Bake-off (M3) mit den bereits installierten Kandidaten +und Prompt-Tuning der Fehlverweigerungen. Odoo-Integration (M4) separat +zu planen. ## Completed (2026-09-14) -- **Planung** (`planung.md`): Architektur, Grounding-Regeln, Modellfeld - (Bake-off: qwen3.8:27b primär, qwen3:32b, gemma3:27b, mistral-small3.2:24b, - qwen3:14b als Latenz-Untergrenze), Meilensteine M1–M4. -- **Skill** `.agents/skills/pv-rag-agent/SKILL.md`: verbindliche Regeln für - die Implementierung (Grounding, Architektur-Entscheidungen, Gates, - Modellwechsel-Protokoll). -- **Commits**: `25eb285` (Wissensbasis-Import 601 Layer-2-Einträge + - .gitignore), `bf8191b` (Planung + Skills). Noch nicht gepusht — Remote - `http://localhost:3003/fegger/pv-agent.git` ist aus der Zed-Sandbox nicht - erreichbar; User muss vom Host pushen. -- **Implementierung M1+M2** (`agent/`-Paket): kb.py (Parsing + kb.json-Gate), - ingest.py (3005 Chunks aus 601 Einträgen, FTS5 + Vektoren-Cache), - retrieve.py (Hybrid BM25+Dense/RRF, Stand-Boost, cross_ref-Erweiterung), - generate.py (Systemprompt, Post-Validierung, 1× Regenerierung, dann - Verweigerung), ollama_client.py (embed/chat, think-Flag-Fallback), - api.py (/ask /health /reindex), cli.py, eval/ (Goldset 31 Fragen, - evaluate.py), web/index.html, 41 offline Tests (grün). -- **Baseline BM25-only**: Hit-Rate 0,871 · Recall@8 0,855 · MRR 0,476 - (31 Fragen). 4 Fehltreffer: Komposita/Stamm-Schwächen (aliquotiert↔ - Aliquotierung, Mindestlohngesetz) — Dense-Suche soll diese beheben. +- **Planung** (`planung.md`): Architektur, Grounding-Regeln, Modellfeld, + Meilensteine M1–M4; **Skill** `.agents/skills/pv-rag-agent/SKILL.md`. +- **Commits**: `25eb285` (Wissensbasis-Import), `bf8191b` (Planung + + Skills), `2cba72a` (M1+M2-Implementierung, 41 Tests). +- **Implementierung M1+M2** (`agent/`): kb/ingest/retrieve/generate/ + ollama_client/api/cli/eval, Goldset 31 Fragen, Test-Chat. +- **Ollama-Anbindung verifiziert** (Ziel-Instanz `http://100.103.83.12:11435`, + Ollama 0.32.13): `bge-m3` per API gepullt; `qwen3.8:27b` war bereits + installiert. Hybrid-Index: 3.005 Chunks, alle eingebettet (144 s). +- **M1-Akzeptanz erreicht**: Retrieval Hybrid Hit-Rate 0,968 · + Recall@8 **0,952** (>0,9 ✓) · MRR 0,690 (BM25-only: 0,871/0,855/0,476). +- **M2-Antwortmodus-Eval** (qwen3.8:27b, Thinking aus): Zitier-Präzision + **100 %** (4 Regenerierungen, alle geheilt) · Verweigerung korrekt + 94,3 % · erwartete Quelle zitiert 80,6 % · Latenz mean 32 s / p95 53 s. + Report: `data/eval-qwen38.json`. +- Der ATZ-Konfliktfall (28,5 vs. 27,5 %) wird korrekt mit ⚠ und beiden + IDs beantwortet; harte Verweigerung (UStVA, Retrieval nicht leer) + funktioniert. ## Open issues / blockers -- **Ollama aus Zed-Sandbox nicht erreichbar** (100.183.83.12:11435 und - localhost:3003 beide geblockt): Dense-Index, Antwortmodus-Eval und - Bake-off müssen auf dem Host laufen. Kommandos: `agent/README.md` - Abschnitt „Deployment auf dem Host". -- **Modelle noch nicht gepullt**: auf dem Host `ollama pull qwen3.8:27b`, - `ollama pull bge-m3` (plus Bake-off-Kandidaten). -- **Reranker** (bge-reranker-v2-m3): API-Unterstützung der installierten - Ollama-Version prüfen — Design funktioniert ohne. -- **qwen3.8-Think-Parameter**: `think: false` wird im Request gesendet - (Auto-Fallback ohne Flag bei 400/404); exaktes Verhalten am Host testen. +- **Push**: Remote localhost:3003 aus der Sandbox nicht erreichbar — User + pusht vom Host. +- **Fehlverweigerungen**: q-008 (Abfertigung/Verfügungsmöglichkeiten), + q-031 (Mindestlohngesetz) — breite Fragen, Retrieval erfolgreich, Modell + verweigert. M3-Tuning: Regel-4-Formulierung lockern („behandle den + behandelten Teil“) oder Kontextblöcke erhöhen. Vorher Prompt einfrieren + für den Bake-off-Vergleich. +- **Latenz**: mean 32 s/ Antwort ist hoch (Dense 27B + große Prompts). + Hebel: weniger Kontextblöcke (aktuell 8+6), schnellere Kandidaten. +- **Cloud-Modelle** (`*:cloud` auf der Ollama-Instanz) sind für Antworten + tabu (Anforderung: lokal). Nicht versehentlich konfigurieren. +- **Bake-off M3**: Kandidaten sind bereits installiert — `qwen3.8:27B`, + `qwen3.6:27B`, `gemma4:26b`, `mistral-small3.1:24b`, `gemma4:12B` + (Latenz-Untergrenze). Achtung: Plan nennt mistral-small3.**2**:24b — + installiert ist 3.1; 3.2 ggf. noch pullen oder 3.1 als Proxy. + Pro Kandidat: `PV_ANSWER_MODEL= python -m agent.cli eval --answers`. - **M4 Odoo**: native LLM-Module des konkreten Odoo-19-Stands verifizieren (keine API-Annahmen); Option A (dünnes Custom-Modul + Service-API) ist Default. diff --git a/pv-agent/.agents/skills/pv-rag-agent/SKILL.md b/pv-agent/.agents/skills/pv-rag-agent/SKILL.md index 608b142..be48e44 100644 --- a/pv-agent/.agents/skills/pv-rag-agent/SKILL.md +++ b/pv-agent/.agents/skills/pv-rag-agent/SKILL.md @@ -39,11 +39,11 @@ touches Odoo code, also apply `.agents/odoo19-development/SKILL.md`. ## System context (fixed facts) -- **Ollama server:** `http://100.183.83.12:11435` (custom port — do - not "correct" it to 11434). Verify reachability and installed models - with `curl http://100.183.83.12:11435/api/tags`. Note: agent sandboxes - may not reach this host — run such checks from the user's shell, not - the sandbox. +- **Ollama server:** `http://100.103.83.12:11435` — the target instance + (custom port, holds the model zoo: qwen3.8:27b, bge-m3, bake-off + candidates). The same host also runs a near-empty instance on port + 11434 — do **not** "correct" the port to 11434. Verify with + `curl http://100.103.83.12:11435/api/tags`. - **GPU:** AMD Radeon AI Pro R9700, 32 GB — keep the total resident budget (answer model + embeddings + KV cache) under ~28 GB. - **Models (provisional until bake-off, see protocol below):** diff --git a/pv-agent/agent/README.md b/pv-agent/agent/README.md index 869402b..faf9596 100644 --- a/pv-agent/agent/README.md +++ b/pv-agent/agent/README.md @@ -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 diff --git a/pv-agent/agent/config.py b/pv-agent/agent/config.py index 76054c6..8a01557 100644 --- a/pv-agent/agent/config.py +++ b/pv-agent/agent/config.py @@ -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) diff --git a/pv-agent/agent/generate.py b/pv-agent/agent/generate.py index fab0c3d..30ee970 100644 --- a/pv-agent/agent/generate.py +++ b/pv-agent/agent/generate.py @@ -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, ) \ No newline at end of file diff --git a/pv-agent/planung.md b/pv-agent/planung.md index 686aedd..3412fa9 100644 --- a/pv-agent/planung.md +++ b/pv-agent/planung.md @@ -33,9 +33,10 @@ in weiterer Folge soll der Agent in Odoo-Enterprise verwendet werden. - **Layer-1-Volltexte:** `.lexis360/md/` (572 Dateien) lokal vorhanden, lizenzbeschränkt + unversioniert. `.wiku/` fehlt in diesem Checkout — für Phase A irrelevant (Retrieval läuft auf Layer 2). -- **Ollama-Server** `http://100.183.83.12:11435` (Custom-Port): aus der - Zed-Sandbox **nicht erreichbar** (Netzwerkrestriktion, Timeout) — ist - vom Host aus zu verifizieren (`curl http://100.183.83.12:11435/api/tags`). +- **Ollama-Server** `http://100.103.83.12:11435` (Ziel-Instanz mit Modell-Zoo, + Custom-Port; der Host betreibt zusätzlich eine fast leere Instanz auf 11434): + aus der Zed-Sandbox erreichbar (2026-09-14, nach URL-Korrektur) — + `bge-m3` wurde per API gepullt, `qwen3.8:27b` war bereits installiert. - **GPU:** Radeon AI Pro R9700, 32 GB (Strix Halo / RDNA 5) — budgetiert Modellwahl auf ~26–28 GB nutzbar. @@ -198,9 +199,10 @@ tests/ # pytest: Ingest-, Retrieval-, Grounding-Unit-Tests ## 10. Risiken & offene Punkte -1. **Ollama-Erreichbarkeit** aus der Zed-Sandbox nicht gegeben — - Verifikation vom Host: `curl http://100.183.83.12:11435/api/tags`; - Modelle ggf. erst pullen (`qwen3:32b`, `bge-m3`, …). +1. **Ollama-Erreichbarkeit** gegeben (Ziel-Instanz 11435; Sandbox kann + verbinden). Achtung Doppel-Instanz auf 11434 — URL nicht "korrigieren". + Cloud-Modelle (`*:cloud`) nicht für Antworten verwenden (Anforderung: + lokal). 2. **Ollama-Version:** `/api/embed` + allfällige Rerank-Unterstützung prüfen; Fallback ohne Reranker ist unkritisch. 3. **Strix Halo (gfx-1151):** Ollama/ROCm muss die Karte unterstützen @@ -233,16 +235,21 @@ tests/ # pytest: Ingest-, Retrieval-, Grounding-Unit-Tests ## 13. Umsetzungsstand (2026-09-14) -- **M1 erledigt (offline):** Ingest + Index (601 Einträge → 3.005 Chunks, - FTS5-BM25) + Hybrid-Retrieval (Dense-Code vorhanden, am Host zu messen). - Goldset 31 Fragen (IDs gegen kb.json verifiziert, inkl. ATZ-Konfliktfall - und 4 Verweigerungsfälle). Baseline BM25-only: Hit-Rate 0,871 · - Recall@8 0,855 · MRR 0,476 — 4 Fehltreffer sind Komposita-/Stamm- - Muster, die die Dense-Suche abdecken soll. 41 Unit-Tests grün. -- **M2 implementiert:** Ollama-Client (embed/chat, think-Fallback), - Systemprompt mit Zitierpflicht, Post-Validierung (1× Regenerierung, dann - Verweigerung), `/ask`-API + CLI + Test-Chat. **Host-Validierung mit - echtem Ollama noch offen** (aus der Zed-Sandbox nicht erreichbar). -- **M3 offen:** Bake-off auf dem Host (qwen3.8:27b vs. qwen3:32b vs. - gemma3:27b vs. mistral-small3.2:24b; qwen3:14b als Latenz-Untergrenze). -- Betrieb/Host-Schritte: `agent/README.md`. +- **M1 erledigt und akzeptiert:** Hybrid-Index (601 Einträge → 3.005 Chunks, + FTS5-BM25 + bge-m3-Dense, Ollama :11435), Goldset 31 Fragen. **Recall@8 + 0,952 > 0,9** (Hit-Rate 0,968, MRR 0,690; BM25-only-Vergleich: + 0,855 — die vier Komposita-Fehltreffer behebt die Dense-Suche alle). + 41 Unit-Tests grün. +- **M2 erledigt und gegen das echte Modell validiert** (qwen3.8:27b, + Thinking aus): Zitier-Präzision **100 %** (4 Verletzungen → Post- + Validierung → Regenerierung, alle geheilt), Verweigerung korrekt 94,3 %, + Latenz mean 32 s / p95 53 s. ATZ-Konfliktfall wird korrekt beidseitig + mit ⚠ beantwortet; harte Verweigerungsfälle (UStVA) funktionieren. +- **M3 teilweise:** qwen3.8:27b-Baseline gemessen (`data/eval-qwen38.json`). + Bake-off-Kandidaten sind bereits installiert: qwen3.6:27B, gemma4:26b, + mistral-small3.1:24b, gemma4:12B (Latenz-Untergrenze). Bekannte + Fehlverweigerungen (q-008, q-031) und Latenz sind Tuning-Kandidaten — + Prompt für den Bake-off vorher einfrieren. +- **M4 offen:** Odoo-Integration (separater Plan nach Verifikation der + Odoo-19-LLM-Module). +- Betrieb: `agent/README.md`.