"""Testet, dass die Zahl der Faktenaussagen mit dem Material waechst. Laeuft ohne Netzzugriff und ohne Kosten, der Modellaufruf ist ersetzt. Aufruf aus dem Projektstamm: venv/bin/python tests/test_faktenspanne.py """ import asyncio import os import sys sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "src")) import agents.factchecker as fcmod # noqa: E402 import agents.claude_client as cc # noqa: E402 from agents.factchecker import ( # noqa: E402 FactCheckerAgent, faktenspanne, FACTCHECK_PROMPT_TEMPLATE, RESEARCH_FACTCHECK_PROMPT_TEMPLATE, INCREMENTAL_FACTCHECK_PROMPT_TEMPLATE, INCREMENTAL_RESEARCH_FACTCHECK_PROMPT_TEMPLATE, TRIAGE_PROMPT_TEMPLATE, ) from agents.claude_client import _ai_backend_var, ClaudeUsage # noqa: E402 from config import FAKTEN_MAX, FAKTEN_MIN, FAKTEN_NEU_MAX, FAKTEN_NEU_MIN # noqa: E402 ok = 0 fail = 0 def pruefe(name, bedingung, extra=""): global ok, fail if bedingung: ok += 1 print(" OK " + name) else: fail += 1 print(" FEHL " + name + " " + str(extra)) print("\nA) Die Spanne waechst mit der Zahl der Meldungen") klein = faktenspanne(16) mittel = faktenspanne(53) gross = faktenspanne(88) sehr_gross = faktenspanne(300) pruefe("A1 wenige Meldungen ergeben die alte Spanne", klein == (5, 10), klein) pruefe("A2 mehr Meldungen ergeben mehr Fakten", gross[1] > klein[1], (klein, gross)) pruefe("A3 die Reihenfolge stimmt", klein[1] <= mittel[1] <= gross[1] <= sehr_gross[1], (klein, mittel, gross, sehr_gross)) pruefe("A4 Obergrenze wird eingehalten", sehr_gross[1] == FAKTEN_MAX, sehr_gross) pruefe("A5 Untergrenze wird eingehalten", faktenspanne(0)[0] == FAKTEN_MIN, faktenspanne(0)) pruefe("A6 Untergrenze liegt nie ueber der Obergrenze", all(faktenspanne(n)[0] <= faktenspanne(n)[1] for n in range(0, 400, 7))) pruefe("A7 negative Eingabe bricht nicht", faktenspanne(-5) == (5, 10), faktenspanne(-5)) print("\nB) Fuer die Aktualisierung gilt ein engerer Korridor") neu_klein = faktenspanne(8, neu=True) neu_gross = faktenspanne(200, neu=True) pruefe("B1 wenige neue Meldungen ergeben die alte Spanne", neu_klein == (FAKTEN_NEU_MIN, FAKTEN_NEU_MIN * 2), neu_klein) pruefe("B2 Obergrenze der Aktualisierung greift", neu_gross[1] == FAKTEN_NEU_MAX, neu_gross) pruefe("B3 Aktualisierung bleibt unter der Erstpruefung", faktenspanne(200, neu=True)[1] < faktenspanne(200)[1]) print("\nC) Die Auftraege enthalten Platzhalter statt fester Zahlen") for name, vorlage in ( ("Erstpruefung adhoc", FACTCHECK_PROMPT_TEMPLATE), ("Erstpruefung Recherche", RESEARCH_FACTCHECK_PROMPT_TEMPLATE), ("Aktualisierung adhoc", INCREMENTAL_FACTCHECK_PROMPT_TEMPLATE), ("Aktualisierung Recherche", INCREMENTAL_RESEARCH_FACTCHECK_PROMPT_TEMPLATE), ("Triage", TRIAGE_PROMPT_TEMPLATE)): pruefe(f"C {name} nutzt den Richtwert", "{fakten_min}" in vorlage and "{fakten_max}" in vorlage) pruefe(f"C {name} ohne feste Vorgabe", "5-10" not in vorlage and "3-5 " not in vorlage and "(3-5" not in vorlage) pruefe("C Richtwert ist ausdruecklich keine Zielvorgabe", "Richtwert und keine" in FACTCHECK_PROMPT_TEMPLATE and "Zielvorgabe" in FACTCHECK_PROMPT_TEMPLATE) pruefe("C Abweichen nach oben und unten ist erlaubt", "weniger" in FACTCHECK_PROMPT_TEMPLATE and "mehr" in FACTCHECK_PROMPT_TEMPLATE) print("\nD) Der berechnete Wert landet im Auftrag") letzter = {"prompt": ""} async def fake_call_claude(prompt, tools="WebSearch,WebFetch", model=None, raw_text=False, timeout=None): letzter["prompt"] = prompt return "[]", ClaudeUsage(input_tokens=10, output_tokens=5, cost_usd=0.01) fcmod.call_claude = fake_call_claude cc.call_claude = fake_call_claude _ai_backend_var.set("cli") fc = FactCheckerAgent() def meldungen(n): return [{"headline": f"Meldung {i}", "source": "tagesschau", "source_url": f"https://tagesschau.de/{i}", "content_original": "t"} for i in range(n)] asyncio.run(fc.check("Lage", meldungen(16), "adhoc", "Deutsch")) u, o = faktenspanne(16) pruefe("D1 kleine Lage traegt ihren Richtwert", f"etwa {u} bis {o} Aussagen" in letzter["prompt"], [z for z in letzter["prompt"].splitlines() if "Richtwert" in z][:1]) asyncio.run(fc.check("Lage", meldungen(88), "adhoc", "Deutsch")) u2, o2 = faktenspanne(88) pruefe("D2 grosse Lage traegt einen groesseren Richtwert", f"etwa {u2} bis {o2} Aussagen" in letzter["prompt"] and o2 > o, [z for z in letzter["prompt"].splitlines() if "Richtwert" in z][:1]) asyncio.run(fc.check_incremental( "Lage", meldungen(30), [{"claim": "Ein bestehender Punkt", "status": "confirmed", "evidence": "e"}], "adhoc", "Deutsch")) u3, o3 = faktenspanne(30, neu=True) pruefe("D3 Aktualisierung nutzt den engeren Korridor", f"etwa\n {u3} bis {o3}" in letzter["prompt"] or f"{u3} bis {o3}" in letzter["prompt"], [z for z in letzter["prompt"].splitlines() if "Richtwert" in z][:1]) print("\nErgebnis: " + str(ok) + " bestanden, " + str(fail) + " fehlgeschlagen") sys.exit(1 if fail else 0)