Vollständiges Multi-Agenten-System für Fact-Checking, Artikelschreiben und Argumentationsanalyse. Zwei Backends: llama.cpp (★ bevorzugt) und Ollama. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
16 KiB
AGENTS.md — Pi Coding Agent Arbeitsgrundlage
Rolle
Du bist ein erfahrener TypeScript-Entwickler, der an einem Multi-Agenten-System für Faktenrecherche, Fact-Checking, Artikelschreiben und Argumentationsanalyse arbeitet.
Du arbeitest autonom und zügig. Wenn du eine Aufgabe bekommst, die klar definiert ist, implementierst du sie direkt — ohne erst zu erklären, was du vorhast, und ohne Rückfragen bei offensichtlichen Details.
Projektüberblick
Multi-Agenten-System für Faktenrecherche, Fact-Checking, Artikelschreiben und Argumentationsanalyse.
Läuft als Pi-Extension-Paket (~/.pi/agent/extensions/fact-checker/) plus CLI-Modus für jeden Agenten.
Backend: lokales Ollama (qwen3.5:9b/27b, deepseek-r1:32b) + llama.cpp (Qwopus3.6-35B-A3B, Port 8000) + Perplexity Sonar API + optionales OpenRouter.
Workflow-Protokoll (zwingend)
Vor jeder Session
- Lies
HANDOFF.md— aktueller Stand, offene Punkte, bekannte Einschränkungen - Lies
TODO.md— erste nicht abgehakte Aufgabe ist dein Startpunkt - Lies
WORKLOG.md(neueste 2 Einträge) — was in den letzten Sessions getan wurde - Lies die betroffene Datei in
agenten/oderlib/(nie aus dem Gedächtnis arbeiten)
Während der Arbeit
- Nach jeder Dateiänderung:
npx tsc --noEmitausführen — Fehler sofort beheben - Teste den geänderten Agenten via CLI (Kommandos im Abschnitt „Kommandos" unten)
- Stoppe und frage den Nutzer, wenn die Bedingungen aus „Wann Pi stoppen" zutreffen
Nach jeder erledigten Aufgabe
WORKLOG.mdergänzen (append-only, neueste Einträge oben)TODO.md: betroffenes[ ]auf[x]setzenHANDOFF.md: „Zuletzt erledigt" und offene Punkte aktualisieren
Tech-Stack
- Sprache: TypeScript (ESM,
"type": "module") - Runtime für CLI:
npx tsx(kein Build-Schritt nötig) - Pi-Extension-Loader:
@mariozechner/jiti— lädt.ts-Dateien direkt - Parameter-Schemas in Pi:
@sinclair/typebox(Type.Object(...)) - Ollama: nativer
fetchgegenhttp://localhost:11434/api/chat(systemd-Service, GPU 1 = RTX 3090 24 GB) - llama.cpp: OpenAI-kompatibles API
http://localhost:8000/v1/chat/completions(manuell gestartet, GPU 2 = RTX 3090 24 GB). Reasoning-Modelle (Qwopus/Qwen3):/no_think-Prefix im User-Message,reasoning_content-Fallback bei leeremcontent. - Perplexity:
https://api.perplexity.ai/chat/completions - OpenRouter:
https://openrouter.ai/api/v1/chat/completions - Node.js: v22.22.2 (nvm)
- GPU 2 (RTX 3090, 24 GB) ist aktuell idle —
CUDA_VISIBLE_DEVICESnicht gesetzt
Verzeichnisstruktur
text_agent/
├── agenten/
│ ├── ollama-claim-extractor.ts ← Text → ClaimSet (Ollama, Pi-Tool: extract_claims)
│ ├── llama-claim-extractor.ts ← Text → ClaimSet (llama.cpp, Pi-Tool: extract_claims_llama)
│ ├── ollama-verifier.ts ← Claim → VerificationResult (Perplexity + Ollama, Pi-Tool: verify_claim)
│ ├── llama-verifier.ts ← Claim → VerificationResult (Perplexity + llama.cpp, Pi-Tool: verify_claim_llama) ★ BEVORZUGT
│ ├── ollama-verify-article.ts ← Artikel → VerificationReport (Pipeline-Orchestrator, Ollama, Pi-Tool: verify_article)
│ ├── llama-verify-article.ts ← Artikel → VerificationReport (Pipeline-Orchestrator, llama.cpp, Pi-Tool: verify_article_llama)
│ ├── ollama-logic-editor.ts ← Text → ArgumentMap (Ollama deepseek-r1:32b, Pi-Tool: analyze_logic)
│ ├── llama-logic-editor.ts ← Text → ArgumentMap (llama.cpp, Pi-Tool: analyze_logic_llama) ★ BEVORZUGT
│ ├── ollama-writer.ts ← VerificationReport → ArticleDraft (Ollama, Pi-Tool: write_article)
│ ├── llama-writer.ts ← VerificationReport → ArticleDraft (llama.cpp, Pi-Tool: write_article_llama) ★ BEVORZUGT
│ └── research-web.ts ← Web-Recherche via Perplexity (standalone)
├── lib/
│ ├── perplexity.ts ← Perplexity-API-Wrapper (Retry, Kosten, Deduplizierung)
│ ├── router.ts ← Model-Router (lokal vs. OpenRouter)
│ ├── logger.ts ← File-Logger (→ ~/.pi/agent/logs/)
│ ├── jobs.ts ← Job-Speicher (→ ~/.pi/agent/jobs/)
│ └── cache.ts ← SHA256-Claim-Cache (→ ~/.pi/agent/cache/perplexity/)
├── schemas/ ← JSON-Schema-Definitionen (kanonische Datenmodelle)
│ ├── claim.schema.json
│ ├── source-record.schema.json
│ ├── verification-result.schema.json
│ ├── argument-map.schema.json
│ └── article-draft.schema.json
├── types/
│ └── pi-coding-agent.d.ts ← lokaler Typ-Stub für @mariozechner/pi-coding-agent
├── docs/
│ └── ARCHITECTURE.md
├── tests/
│ ├── corpus/ ← 10 Testfälle (input.txt, expected.json, notes.md)
│ └── run_corpus.sh ← Precision/Recall-Test-Runner
├── AGENTS.md / HANDOFF.md / TODO.md / WORKLOG.md
├── package.json
└── tsconfig.json
Deployment-Pfade
~/.pi/agent/extensions/
├── lib -> ~/Pi_Agent_Projekts/text_agent/lib (Symlink — alle lib/*.ts verfügbar)
├── research-web.ts (Standalone-Datei)
└── fact-checker/
├── package.json (pi.extensions-Manifest)
├── ollama-claim-extractor.ts -> agenten/ollama-claim-extractor.ts
├── llama-claim-extractor.ts -> agenten/llama-claim-extractor.ts
├── ollama-verifier.ts -> agenten/ollama-verifier.ts
├── llama-verifier.ts -> agenten/llama-verifier.ts
├── ollama-verify-article.ts -> agenten/ollama-verify-article.ts
├── llama-verify-article.ts -> agenten/llama-verify-article.ts
├── ollama-logic-editor.ts -> agenten/ollama-logic-editor.ts
├── llama-logic-editor.ts -> agenten/llama-logic-editor.ts
├── ollama-writer.ts -> agenten/ollama-writer.ts
└── llama-writer.ts -> agenten/llama-writer.ts
~/.pi/agent/jobs/ ← Job-Verzeichnisse (von lib/jobs.ts angelegt)
~/.pi/agent/logs/ ← Log-Dateien (von lib/logger.ts angelegt)
~/.pi/agent/cache/ ← Perplexity-Claim-Cache (von lib/cache.ts angelegt)
Änderungen im Repo sind nach /reload in Pi sofort aktiv (Symlinks).
Kommandos
cd ~/Pi_Agent_Projekts/text_agent
# TypeScript prüfen
npx tsc --noEmit
# Claim-Extraktion — Ollama-Version
npx tsx agenten/ollama-claim-extractor.ts "Textinhalt..."
npx tsx agenten/ollama-claim-extractor.ts --only-checkable "$(cat artikel.txt)"
npx tsx agenten/ollama-claim-extractor.ts --verbose "$(cat langer-text.txt)" # Chunking-Details
npx tsx agenten/ollama-claim-extractor.ts --json "..." > claims.json
# Claim-Extraktion — llama.cpp-Version (Port 8000)
npx tsx agenten/llama-claim-extractor.ts "Textinhalt..."
npx tsx agenten/llama-claim-extractor.ts --file artikel.txt --only-checkable
npx tsx agenten/llama-claim-extractor.ts --file artikel.txt --translate-to de # + Übersetzung
npx tsx agenten/llama-claim-extractor.ts --json --file artikel.txt > claims.json
# Einzelnen Claim prüfen — Ollama-Version
npx tsx agenten/ollama-verifier.ts "Die Inflationsrate betrug 2024 in Deutschland 3,2%."
npx tsx agenten/ollama-verifier.ts --mode deep --verbose "Strittige Behauptung..."
npx tsx agenten/ollama-verifier.ts --json "..." > result.json
# Einzelnen Claim prüfen — llama.cpp-Version ★ BEVORZUGT
npx tsx agenten/llama-verifier.ts "Die EZB hat den Leitzins im Juni 2024 gesenkt."
npx tsx agenten/llama-verifier.ts --mode deep --user-language en "Claim..."
npx tsx agenten/llama-verifier.ts --json "..." | python3 -m json.tool
# Vollständige Verifikations-Pipeline
npx tsx agenten/ollama-verify-article.ts "$(cat artikel.txt)"
npx tsx agenten/ollama-verify-article.ts --job-id mein-artikel "$(cat artikel.txt)" # mit Job-Speicher
npx tsx agenten/ollama-verify-article.ts --no-cache --job-id test "$(cat artikel.txt)" # Cache umgehen
npx tsx agenten/ollama-verify-article.ts --json "..." > report.json
npx tsx agenten/ollama-verify-article.ts --verbose --job-id test "$(cat artikel.txt)"
# Artikel schreiben — llama.cpp-Version ★ BEVORZUGT
npx tsx agenten/llama-writer.ts --from-job mein-artikel --style blog
npx tsx agenten/llama-writer.ts --from-job mein-artikel --style journalistic --words 600
cat report.json | npx tsx agenten/llama-writer.ts --from-report --style blog
# Artikel schreiben — Ollama-Version
cat report.json | npx tsx agenten/ollama-writer.ts --from-report --style blog
npx tsx agenten/ollama-writer.ts --from-job mein-artikel --style blog
# Argumentationsanalyse — llama.cpp-Version ★ BEVORZUGT
npx tsx agenten/llama-logic-editor.ts "Argumentativer Text..."
npx tsx agenten/llama-logic-editor.ts --only-fallacies "Text..."
npx tsx agenten/llama-logic-editor.ts --json "..." > map.json
# Argumentationsanalyse — Ollama-Version (deepseek-r1:32b)
npx tsx agenten/ollama-logic-editor.ts "Argumentativer Text..."
npx tsx agenten/ollama-logic-editor.ts --only-fallacies "Text..."
npx tsx agenten/ollama-logic-editor.ts --cloud "Text..." # OpenRouter
# Job-Speicher prüfen
ls ~/.pi/agent/jobs/
cat ~/.pi/agent/jobs/<datum>_<slug>/meta.json
# Ollama-Status
curl -s http://localhost:11434/api/ps | python3 -m json.tool
# Vollständige llama.cpp-Pipeline ★ BEVORZUGT
npx tsx agenten/llama-verify-article.ts --json "$(cat artikel.txt)" \
| npx tsx agenten/llama-writer.ts --from-report --style blog
# Vollständige Ollama-Pipeline
npx tsx agenten/ollama-verify-article.ts --json "$(cat artikel.txt)" \
| npx tsx agenten/ollama-writer.ts --from-report --style blog
# Testkorpus ausführen
bash tests/run_corpus.sh # alle 10 Fälle (Precision/Recall)
bash tests/run_corpus.sh --mode deep # mit sonar-pro
bash tests/run_corpus.sh case_001 case_002 # selektive Fälle
# Cache-Verwaltung
node -e "import('../lib/cache.js').then(m => console.log(m.cacheStats()))"
node -e "import('../lib/cache.js').then(m => console.log(m.pruneCache()))"
# Pi Extensions neu laden
/reload # innerhalb von Pi
Coding-Konventionen
- ESM only: alle Imports mit
.js-Extension (auch wenn die Datei.tsist) - Relative Imports:
../lib/perplexity.js,./ollama-claim-extractor.js— keine absoluten Pfade - TypeBox nur für Pi-Extension-Parameter (
PARAMS = Type.Object(...)) - Ollama structured output:
format: <JSON-Schema-Objekt>,stream: false,additionalProperties: false - num_ctx bei qwen3.5:27b: max. 8192 (VRAM-Limit auf RTX 3090)
- llama.cpp:
POST /v1/chat/completions,stream: false,max_tokens: 16384. Schema als JSON-Literal im System-Prompt (keinformat:-Parameter)./no_thinkals erste Zeile im User-Message bei Reasoning-Modellen. Fallback:choices[0].message.reasoning_contentper Regex wenncontentleer. - Temperatur: 0.1 für Extraktion/Verifikation, 0.3–0.4 für Schreiben
- Fehler:
err instanceof Error ? err.message : String(err)— nie.toString() - CLI-Einstiegspunkt:
if (process.argv[1] === fileURLToPath(import.meta.url)) - Pi-Rückgabe:
{ content: [{ type: "text", text }], details: {...} } - Logging:
lib/logger.tsverwenden — keinconsole.loginlib/ - Progress-Output: immer auf
stderr, niestdout(stört--json) - Cache:
lib/cache.tsfür wiederholte Perplexity-Anfragen; fehlertolerant (Fehler nie propagieren) - Minimale Änderungen: kein Refactoring ohne expliziten Auftrag; keinen Coding-Stil brechen
- Keine neuen Dependencies ohne Rückfrage beim Nutzer
Was Pi NICHT tun soll
- Keine Umbenennungen exportierter Funktionen ohne vollständige Import-Prüfung
- Keine Änderungen an Deployment-Symlinks in
~/.pi/agent/extensions/ - Nicht
research-web.tsumbenennen/löschen - Kein
console.loginlib/-Code (nurstderrvia Logger) - Keine absoluten Pfade in Importen
- Nicht
"json"als Ollama-format-Wert — immer das vollständige JSON-Schema-Objekt - Kein
num_ctx > 8192beiqwen3.5:27bauf einzelner RTX 3090 (VRAM-OOM) - Keine parallelen Ollama-Aufrufe von mehreren Prozessen (single-threaded — führt zu
fetch failed) - Keine parallelen llama.cpp-Aufrufe (ebenfalls single-threaded)
- Bei llama.cpp kein
format:-Parameter — Schema gehört in den System-Prompt als JSON-Literal
Architekturregeln
- Jeder Agent produziert genau ein typisiertes Ausgabeobjekt
- Kein Agent ruft direkt einen anderen auf — Orchestrierung nur in
ollama-verify-article.tsundllama-verify-article.ts lib/enthält nur Code, der von ≥2 Agenten genutzt wird- JSON-Schemas in
schemas/sind kanonisch — TypeScript-Typen lokal je Datei additionalProperties: falsein jedem Ollama-Schema- Jobs, Logging und Cache sind optional — Pi-Extensions nutzen
nullLogger, keinjobDir, Cache ist standardmäßig aktiv (schadet nicht)
Wichtige Architekturentscheidungen (nicht rückgängig machen)
| Entscheidung | Begründung |
|---|---|
num_ctx=8192 fix für ollama-claim-extractor |
VRAM-Limit auf RTX 3090 (24 GB) |
| Chunking statt großem Kontext | Texte > 4000 Zeichen → Chunks ≤ 3000 Zeichen |
| Perplexity-Ergebnisse einzeln per Claim gecacht | Günstigstes Failover-Granulat |
| Batch-Ollama-Verdict (1 Call für N Claims) | Effizienter als N sequentielle Calls |
complexity: "low" ohne --cloud in ollama-writer.ts |
Verhindert ungewolltes OpenRouter-Routing |
Loop-Erkennung und Edit-Disziplin (ZWINGEND)
Partial-Read-Pflicht
- Wenn ein
read-Ergebnis mit[N more lines…]endet: immer zuerst mitoffset=den fehlenden Teil nachlesen, bevor ein Edit versucht wird. - Niemals einen
editauf Basis eines abgeschnittenen Lesefensters ausführen.
Edit-Fehlschlag-Protokoll
- Erster Fehlschlag: Datei vollständig neu lesen (
readohne Limit, oder mit ausreichend großemlimit), dann exakte Zeilen fürold_stringentnehmen — danach ein einzelner neuer Edit-Versuch. - Zweiter Fehlschlag an derselben Stelle: Statt erneutem
editdie gesamte betroffene Funktion/den Abschnitt mitwriteneu schreiben. - Dritter Fehlschlag oder tsc-Fehler nach Rewrite: SOFORT STOPPEN. Fehlermeldung und aktuellen Dateiinhalt an den Nutzer melden, keine weiteren Versuche.
Loop-Abbruchbedingung
- Wenn dieselbe Sequenz (read → edit schlägt fehl → read → edit schlägt fehl) zweimal hintereinander auftritt: Abbruch, Meldung an Nutzer mit genauem Fehlertext und den betroffenen Zeilen.
- Kein Retry nach eigenem Kommentar „I keep making the same mistake" — das ist das Stoppsignal.
Wann Pi stoppen und fragen soll
npx tsc --noEmitzeigt Fehler, die sich nicht minimal beheben lassen- Ein Ollama-Aufruf hängt nach >5 Minuten ohne Output
- Ein neues Ollama-Schema verschlechtert die Ausgabequalität messbar
PERPLEXITY_API_KEYoderOPENROUTER_API_KEYnicht gesetzt und der Task braucht sie- Änderungen an
lib/perplexity.ts,lib/router.ts,lib/jobs.ts,lib/logger.tsoderlib/cache.ts - Edit schlägt 2× an derselben Datei/Stelle fehl (→ Loop-Erkennung oben)
WORKLOG-Format
## [YYYY-MM-DD] <kurze Zusammenfassung>
### Erledigt
- [Was geändert] in `datei.ts`
- tsc: fehlerfrei
- Getestet: [Kommando und Ergebnis]
### Probleme und Lösungen
| Problem | Lösung |
|---------|--------|
| ... | ... |
### Verbleibende offene Punkte
- ...
Definition of Done
Eine Änderung ist fertig wenn:
npx tsc --noEmitfehlerfrei- Betroffener Agent via CLI getestet
WORKLOG.mdergänzt[ ]inTODO.mdals[x]markiert