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.
8.6 KiB
name, description, disable-model-invocation
| name | description | disable-model-invocation |
|---|---|---|
| pv-rag-agent | Build and maintain the local RAG agent for Austrian payroll (Personalverrechnung) that answers strictly from the curated Wissensbasis (wissensbasis/, Layer 2, 601 entries). Covers the RAG service pipeline (ingest, hybrid retrieval, generation, grounding, eval), Ollama integration (server, models, VRAM budget), the binding grounding and citation rules, the model bake-off protocol, and the later Odoo Enterprise integration. Use for any work on the agent/ package, retrieval quality, prompts, the goldset/eval suite, Ollama model choice, or the Odoo chat module. Combine with wissensbasis/SKILL.md whenever Wissensbasis content changes. | false |
PV RAG Agent (Wissensbasis-Copilot)
Implementation skill for the payroll knowledge agent planned in
planung.md. That file holds the full plan (architecture, milestones
M1–M4, decision points); this skill records the rules a thread must
respect while implementing it.
Scope & applicability
Use this skill for all work on:
- the RAG service (
agent/package: ingest, retrieve, generate, api, cli, eval) and its index (data/index.db); - prompts, grounding checks, citation formatting, refusal behaviour;
- Ollama model configuration, embedding/reranker setup, server connectivity;
- the eval goldset and any retrieval/prompt/model change;
- the later Odoo Enterprise chat module (Phase B).
When work touches the Wissensbasis itself (new batches, frontmatter,
curation), also apply .agents/wissensbasis/SKILL.md. When work
touches Odoo code, also apply .agents/odoo19-development/SKILL.md.
System context (fixed facts)
- 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 withcurl 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):
- answer model:
qwen3.8:27b(Q4, ~18 GB, 256K context) — newest Qwen generation (verified on the Ollama library 2026-09); thinking is on by default — disable per request for RAG latency (library documents per-request disabling plusreasoning_effort/preserve_thinking; verify the exact Ollama API option when implementing); vision exists but stays unused; - fallback / known quantity:
qwen3:32b(Q4_K_M, ~20 GB), thinking mode off; - further bake-off candidates:
gemma3:27b,mistral-small3.2:24b(24B, ~15 GB, 128K context; European vendor, expected strong German — user hypothesis, verify in the bake-off; no thinking mode),qwen3:14b(latency floor),qwen3:30b-a3b(MoE, throughput); - embeddings:
bge-m3via/api/embed(multilingual, German); - optional reranker:
bge-reranker-v2-m3— verify the installed Ollama version's rerank API before building on it; the design must work without reranking (fallback: hybrid score only).
- answer model:
- Corpus: Layer 2 only —
wissensbasis/dokumente/*.md, 601 entries, frontmatter is the single source of truth;kb.jsonis its generated, validated projection.
Binding grounding constraints
These are the product's core promise — never weaken them:
- Answers only from the retrieved Layer-2 context. No training knowledge, no web search, no tools, no browsing hooks. The pipeline has no outbound path besides Ollama — keep it that way.
- Citation duty: every factual statement carries its KB ID
(e.g.
[lb-atz-07]); every value carries its Stand ((Stand YYYY-MM)), mirroring the Wissensbasis curation convention. - Post-validation: every ID cited in an answer must be in the retrieved set. On violation: one regeneration with a stricter instruction, then refuse or mark the answer as uncertain. Never ship an answer that fails this check.
- Refusal duty: if retrieval is empty or weak, say so ("Dazu enthält die Wissensbasis keine Aussage") and optionally name related clusters. Never fill gaps from prior knowledge.
- Corpus conflicts: present both values with ⚠ and IDs (e.g. ATZ replacement quota 28,5 % vs 27,5 %, lb-atz-07 vs lb-atz-09/12); never resolve silently — same rule as curation convention 3.
- § discipline: cite norms only as the source names them
(
legal_bases); no § completion from training knowledge. - Layer 1 stays out of prompts (
.lexis360/,.wiku/are licensed). Layer-2 text is curated own-words content and safe. Layer-1 provisioning for deeper quotes is an open point (seewissensbasis/README.md) — do not decide it ad hoc. - Privacy: the agent is a knowledge assistant. No employee or payroll data flows into prompts — only the question and Layer-2 text.
Architecture decisions (do not redesign without user approval)
- Lean custom pipeline, no LangChain/LlamaIndex (601 docs, full control over grounding beats framework convenience).
- One SQLite file
data/index.db(gitignored): FTS5 (BM25) + dense vectors + metadata columns. No external vector DB. - Chunking: H2 sections per entry;
## Kernwerte & Fristentables become their own chunks (numeric questions); parent-child — retrieve on section, provide section + metadata header as context. - Hybrid retrieval: BM25 + dense (RRF fusion), optional reranker,
metadata filters (
topic,standrecency),cross_refsexpansion of top hits; 8–12 context blocks, each with a metadata header (ID · Titel · Stand · topic · Werk). - FastAPI surface:
POST /ask,GET /health,POST /reindex;agent/cli.pyfor the dev loop; minimal static web UI for demos. - German normalization for FTS5: umlaut folding at ingest time (ä→ae or ä→a — pick once, stay consistent; ASCII slugs follow the Wissensbasis convention: umlauts dropped, ß→ss).
Ingestion rules
- Parse Layer-2 frontmatter directly from the
.mdfiles; treatkb.jsonas a consistency gate (entry counts and ID sets must match — mismatch aborts the ingest with a clear error). - Incremental embeddings: cache vectors keyed by content hash; a reindex only embeds new/changed chunks.
- After each new Wissensbasis batch (workflow in
.agents/wissensbasis/SKILL.md): runPOST /reindex, then run the eval suite.
Validation gates
- Goldset
agent/eval/goldset.yaml: 30–50 questions with expected IDs, including conflict cases (ATZ quotas) and 3–5 out-of-KB questions that must be refused. - Metrics (run before merging any retrieval/prompt/model change): retrieval recall@8 (target > 0.9), citation precision (target 100 %), refusal correctness, end-to-end latency.
- Unit tests (
tests/): ingest schema validation, normalization, post-validation behaviour (hallucinated ID → regeneration → refuse), conflict rendering. - Never validate with values from training knowledge — use the Wissensbasis and Layer-1 spot checks instead.
Model change protocol (bake-off, M3)
The answer model is only changed via a documented bake-off on the
goldset: qwen3.8:27b vs. qwen3:32b vs. gemma3:27b vs.
mistral-small3.2:24b (plus qwen3:14b as latency floor; temperature
~0.1, thinking off where the model has a thinking mode). Decision criteria: citation precision first, then refusal
correctness, then latency. Record the outcome like other project
decisions (D1/D2 style) in planung.md and .agents/MEMORY.md
(workflow: .agents/SKILL.md — agent-memory). A faster model may only
win if citation precision is equal.
Odoo Enterprise integration (Phase B)
- Option A (planned default): thin custom module with an OWL chat
panel; service URL via
ir.config_parameter; role-based access. The RAG service remains the single source of truth for grounding and citations. No retrieval/grounding logic in Odoo. - Option B (to verify first): Odoo 19's native LLM modules with
Ollama as an OpenAI-compatible provider. Never assume module
names, models, fields or endpoints — verify against the actual
Odoo 19 source before planning Option B in detail
(
.agents/odoo19-development/SKILL.md). - Phase A runs independently of this decision; do not couple the service API to Odoo specifics.
Hygiene
data/index.db,data/, logs and caches: gitignored..lexis360/,.wiku/,.firecrawl/,.ris/stay unversioned (licensed / local). Never commit them.- Configuration via environment variables (
agent/config.py): Ollama URL, model names, port — no hardcoded hosts in business code.