Files
pv-agent/.agents/skills/pv-rag-agent/SKILL.md
T
fegger 0281d8fa24 Bake-off M3: qwen3.8 vs qwen3.6 gemessen; Topologie korrigiert (Remote-GPU-Maschine)
Zwischenstand Bake-off (Antwortmodus, 35 Goldset-Fragen):
qwen3.8:27b 100% Zitier-Praezision / 94,3% Verweigerung korrekt / 32s;
qwen3.6:27B 94,3% / 85,7% / 43s (10 Regenerierungen) - klar schwächer.

Topologie korrigiert: 100.103.83.12:11435 ist die Remote-GPU-Maschine
(Tailscale, R9700), NICHT dieselbe wie die Dev-Maschine (deren localhost:
11434 ist ein eigener, fast leerer Ollama; URL-Nicht-auf-11434-Korrigieren
in Skill/README/Config präzisiert). bge-m3 auf der GPU-Maschine gepullt.

gemma4:26b-Lauf brach ab: auf der GPU-Maschine sterben seit dem Crash
alle llama-server-Loads (API 500 'exit status 1'), auch bge-m3. Neustart
dort noetig: sudo systemctl restart ollama. Danach mistral-small3.1:24b
und gemma4:12B ausstehen.
2026-09-14 22:42:54 +02:00

178 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: pv-rag-agent
description: |
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.
disable-model-invocation: 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
M1M4, 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` — a **remote GPU
machine** in the Tailscale network (development environment, Radeon
AI Pro R9700) holding the model zoo: qwen3.8:27b, bge-m3, bake-off
candidates. Do **not** "correct" the URL to localhost or port 11434 —
a local Ollama on the dev machine's 11434 is a different, near-empty
instance. Verify with `curl http://100.103.83.12:11435/api/tags`.
Shell access for restarts/logs exists only on that machine.
- **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 plus
`reasoning_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-m3` via `/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).
- **Corpus:** Layer 2 only — `wissensbasis/dokumente/*.md`, 601 entries,
frontmatter is the single source of truth; `kb.json` is its generated,
validated projection.
## Binding grounding constraints
These are the product's core promise — never weaken them:
1. **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.
2. **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.
3. **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.
4. **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.
5. **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.
6. **§ discipline:** cite norms only as the source names them
(`legal_bases`); no § completion from training knowledge.
7. **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 (see
`wissensbasis/README.md`) — do not decide it ad hoc.
8. **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 & Fristen` tables
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`, `stand` recency), `cross_refs` expansion
of top hits; 812 context blocks, each with a metadata header
(ID · Titel · Stand · topic · Werk).
- FastAPI surface: `POST /ask`, `GET /health`, `POST /reindex`;
`agent/cli.py` for 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 `.md` files; treat
`kb.json` as 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`): run `POST /reindex`, then run the
eval suite.
## Validation gates
- **Goldset** `agent/eval/goldset.yaml`: 3050 questions with expected
IDs, including conflict cases (ATZ quotas) and 35 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.