fix(faktencheck): Zahl der Faktenaussagen richtet sich nach dem Material
In allen Auftraegen stand fest "5-10 wichtigste Faktenaussagen", bei der Aktualisierung "3-5 neue". Die Zahl hatte damit nichts mit der Menge des Materials zu tun. Aus 16 Meldungen wurden genauso viele Fakten wie aus 91. Beide Wege lasen dieselbe Vorgabe verschieden. Der Weg ueber die Anthropic-CLI behandelte sie als Richtwert und lag zwischen 9 und 21 Fakten, ueberschritt die Zehn also regelmaessig. Das Modell auf dem EU-Weg las sie als Zielvorgabe und traf sie in neun von siebzehn Laeufen exakt. Daher wirkten die EU-Berichte so gleichfoermig, nicht die Lage bestimmte den Umfang, sondern die Zahl im Text. Bei der Ceuta-Lage bedeutete das, dass zehn Punkte eine europaweite Krise abbilden mussten, in der Opferzahlen, die schwimmende Barriere, das Sondertreffen der Innenminister, Italiens Schengen-Aussetzung, der offene Brief von 22 Staaten, die Rueckfuehrungen und mehrere Regierungsaeusserungen vorkamen. faktenspanne() berechnet den Richtwert jetzt aus der Zahl der Meldungen, grob eine Aussage je fuenf Meldungen, begrenzt auf 5 bis 20 bei der Erstpruefung und 3 bis 10 bei der Aktualisierung. 16 Meldungen ergeben weiterhin 5 bis 10, 88 Meldungen ergeben 9 bis 18. Alle Werte sind ueber Umgebungsvariablen einstellbar. Dazu die Formulierung. Die Spanne ist jetzt ausdruecklich als Richtwert und nicht als Zielvorgabe bezeichnet, mit der Erlaubnis, weniger zu nennen wenn das Material nicht mehr hergibt, und mehr wenn sonst wichtige Punkte fehlen wuerden. Betroffen sind die vier Faktencheck-Vorlagen und die Triage. Neu sind 25 Pruefungen, insgesamt laufen 279 ohne Netzzugriff und ohne Kosten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -162,6 +162,7 @@ tests/:
|
|||||||
hinweis: "Laufen ohne Netzzugriff und ohne Kosten, Modell, Suche und Datenbank sind durch Testdoubles ersetzt. Aufruf aus dem Projektstamm, zum Beispiel venv/bin/python tests/test_eu_factcheck.py"
|
hinweis: "Laufen ohne Netzzugriff und ohne Kosten, Modell, Suche und Datenbank sind durch Testdoubles ersetzt. Aufruf aus dem Projektstamm, zum Beispiel venv/bin/python tests/test_eu_factcheck.py"
|
||||||
test_eu_factcheck.py: "EU-Faktencheck, Nachhak-Runde, Quellenzuordnung, plus Regressionsschutz fuer den Anthropic-Weg"
|
test_eu_factcheck.py: "EU-Faktencheck, Nachhak-Runde, Quellenzuordnung, plus Regressionsschutz fuer den Anthropic-Weg"
|
||||||
test_eu_belegsuche.py: "Gezielte Belegsuche ueber staan, Planung, Grenzen, Entdopplung, Ausfallverhalten"
|
test_eu_belegsuche.py: "Gezielte Belegsuche ueber staan, Planung, Grenzen, Entdopplung, Ausfallverhalten"
|
||||||
|
test_faktenspanne.py: "Richtwert fuer die Zahl der Faktenaussagen, waechst mit der Menge der Meldungen"
|
||||||
test_qc_und_runden.py: "Absicherung der Duplikatpruefung und Abbruch der Suchrunden bei erreichter Treffergrenze"
|
test_qc_und_runden.py: "Absicherung der Duplikatpruefung und Abbruch der Suchrunden bei erreichter Treffergrenze"
|
||||||
test_mehrfachantwort.py: "Antworten, in denen sich das Modell selbst korrigiert und mehrere Fassungen liefert, die ausfuehrlichste muss gewinnen"
|
test_mehrfachantwort.py: "Antworten, in denen sich das Modell selbst korrigiert und mehrere Fassungen liefert, die ausfuehrlichste muss gewinnen"
|
||||||
test_faktencheck_belegtiefe.py: "Belegzaehlung nach Medienhaus, Nachbedingung fuer bestaetigte Fakten, Sperre gegen das Hochstufen von developing, getrennte Bezeichnungen fuer Widerspruch und Widerlegung"
|
test_faktencheck_belegtiefe.py: "Belegzaehlung nach Medienhaus, Nachbedingung fuer bestaetigte Fakten, Sperre gegen das Hochstufen von developing, getrennte Bezeichnungen fuer Widerspruch und Widerlegung"
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ STRENGE REGELN - KEINE HALLUZINATIONEN:
|
|||||||
- Lieber "unconfirmed" als falsch bestätigt
|
- Lieber "unconfirmed" als falsch bestätigt
|
||||||
|
|
||||||
AUFTRAG:
|
AUFTRAG:
|
||||||
1. Identifiziere die 5-10 wichtigsten Faktenaussagen aus den Meldungen
|
1. Identifiziere die wichtigsten Faktenaussagen aus den Meldungen. Als Richtwert
|
||||||
|
sind das etwa {fakten_min} bis {fakten_max} Aussagen. Das ist ein Richtwert und keine
|
||||||
|
Zielvorgabe. Nenne weniger, wenn das Material nicht mehr hergibt, und mehr, wenn
|
||||||
|
sonst wichtige Punkte der Lage fehlen wuerden.
|
||||||
2. Prüfe jeden Claim aktiv per WebSearch gegen mindestens eine weitere unabhängige Quelle
|
2. Prüfe jeden Claim aktiv per WebSearch gegen mindestens eine weitere unabhängige Quelle
|
||||||
3. Kategorisiere jede Aussage:
|
3. Kategorisiere jede Aussage:
|
||||||
- "confirmed": Mindestens 2 unabhängige Medienhäuser mit überprüfbarer URL bestätigen die Aussage
|
- "confirmed": Mindestens 2 unabhängige Medienhäuser mit überprüfbarer URL bestätigen die Aussage
|
||||||
@@ -71,7 +74,10 @@ STRENGE REGELN - KEINE HALLUZINATIONEN:
|
|||||||
AUFTRAG:
|
AUFTRAG:
|
||||||
Fokus: "Was sind die gesicherten Fakten zu diesem Thema?"
|
Fokus: "Was sind die gesicherten Fakten zu diesem Thema?"
|
||||||
|
|
||||||
1. Identifiziere die 5-10 wichtigsten Faktenaussagen aus den Quellen
|
1. Identifiziere die wichtigsten Faktenaussagen aus den Quellen. Als Richtwert
|
||||||
|
sind das etwa {fakten_min} bis {fakten_max} Aussagen. Das ist ein Richtwert und keine
|
||||||
|
Zielvorgabe. Nenne weniger, wenn das Material nicht mehr hergibt, und mehr, wenn
|
||||||
|
sonst wichtige Punkte der Lage fehlen wuerden.
|
||||||
2. Prüfe jeden Claim aktiv per WebSearch gegen weitere unabhängige Quellen
|
2. Prüfe jeden Claim aktiv per WebSearch gegen weitere unabhängige Quellen
|
||||||
3. Kategorisiere jede Aussage:
|
3. Kategorisiere jede Aussage:
|
||||||
- "established": Breit dokumentierter Fakt, 3+ unabhängige Medienhäuser mit URL
|
- "established": Breit dokumentierter Fakt, 3+ unabhängige Medienhäuser mit URL
|
||||||
@@ -115,7 +121,8 @@ STRENGE REGELN - KEINE HALLUZINATIONEN:
|
|||||||
AUFTRAG:
|
AUFTRAG:
|
||||||
1. Prüfe ob die neuen Meldungen bereits geprüfte Fakten BESTÄTIGEN, WIDERLEGEN oder ERGÄNZEN
|
1. Prüfe ob die neuen Meldungen bereits geprüfte Fakten BESTÄTIGEN, WIDERLEGEN oder ERGÄNZEN
|
||||||
2. Aktualisiere den Status bestehender Fakten wenn nötig (z.B. "unconfirmed" → "confirmed")
|
2. Aktualisiere den Status bestehender Fakten wenn nötig (z.B. "unconfirmed" → "confirmed")
|
||||||
3. Identifiziere 3-5 NEUE Faktenaussagen aus den neuen Meldungen
|
3. Identifiziere NEUE Faktenaussagen aus den neuen Meldungen, als Richtwert etwa
|
||||||
|
{fakten_min} bis {fakten_max}. Auch das ist ein Richtwert, keine Zielvorgabe.
|
||||||
4. Prüfe neue Claims per WebSearch gegen unabhängige Quellen
|
4. Prüfe neue Claims per WebSearch gegen unabhängige Quellen
|
||||||
5. Markiere wichtige Statusänderungen und neue Entwicklungen mit is_notification: true
|
5. Markiere wichtige Statusänderungen und neue Entwicklungen mit is_notification: true
|
||||||
|
|
||||||
@@ -159,7 +166,8 @@ STRENGE REGELN - KEINE HALLUZINATIONEN:
|
|||||||
AUFTRAG:
|
AUFTRAG:
|
||||||
1. Prüfe ob die neuen Quellen bereits geprüfte Fakten bestätigen, widerlegen oder ergänzen
|
1. Prüfe ob die neuen Quellen bereits geprüfte Fakten bestätigen, widerlegen oder ergänzen
|
||||||
2. Aktualisiere den Status bestehender Fakten wenn nötig
|
2. Aktualisiere den Status bestehender Fakten wenn nötig
|
||||||
3. Identifiziere 3-5 NEUE Faktenaussagen aus den neuen Quellen
|
3. Identifiziere NEUE Faktenaussagen aus den neuen Quellen, als Richtwert etwa
|
||||||
|
{fakten_min} bis {fakten_max}. Auch das ist ein Richtwert, keine Zielvorgabe.
|
||||||
4. Prüfe neue Claims per WebSearch
|
4. Prüfe neue Claims per WebSearch
|
||||||
|
|
||||||
Status-Kategorien:
|
Status-Kategorien:
|
||||||
@@ -198,7 +206,8 @@ Analysiere die neuen Artikel und identifiziere:
|
|||||||
betroffen sein? (neue Bestätigung, Widerlegung, neue Evidenz, Status-Update nötig)
|
betroffen sein? (neue Bestätigung, Widerlegung, neue Evidenz, Status-Update nötig)
|
||||||
|
|
||||||
2. NEUE FAKTENAUSSAGEN: Welche neuen prüfbaren Faktenaussagen enthalten die Artikel,
|
2. NEUE FAKTENAUSSAGEN: Welche neuen prüfbaren Faktenaussagen enthalten die Artikel,
|
||||||
die noch nicht in den bestehenden Fakten erfasst sind? (3-5 neue Claims)
|
die noch nicht in den bestehenden Fakten erfasst sind? Als Richtwert etwa
|
||||||
|
{fakten_min} bis {fakten_max} neue Claims, je nachdem was die Artikel hergeben.
|
||||||
|
|
||||||
3. GRUPPIERUNG: Gruppiere verwandte Fakten thematisch für die parallele Batch-Verarbeitung.
|
3. GRUPPIERUNG: Gruppiere verwandte Fakten thematisch für die parallele Batch-Verarbeitung.
|
||||||
Verwandte Fakten MÜSSEN in derselben Gruppe sein. Max {max_per_group} Fakten pro Gruppe.
|
Verwandte Fakten MÜSSEN in derselben Gruppe sein. Max {max_per_group} Fakten pro Gruppe.
|
||||||
@@ -398,6 +407,34 @@ BEWERTUNGSREGELN (verbindlich, sie gehen allen Angaben oben vor):
|
|||||||
keine Pflicht zur Erfindung."""
|
keine Pflicht zur Erfindung."""
|
||||||
|
|
||||||
|
|
||||||
|
def faktenspanne(anzahl_meldungen: int, neu: bool = False) -> tuple[int, int]:
|
||||||
|
"""Richtwert fuer die Zahl der Faktenaussagen, gemessen am Material.
|
||||||
|
|
||||||
|
Frueher stand in allen Auftraegen fest "5-10 wichtigste Faktenaussagen".
|
||||||
|
Das fuehrte dazu, dass aus 16 Meldungen genauso viele Fakten wurden wie aus
|
||||||
|
91, obwohl die groessere Lage sichtbar mehr pruefbare Punkte hergab. Das
|
||||||
|
Modell auf dem EU-Weg traf die Zehn in neun von siebzehn Laeufen exakt, es
|
||||||
|
las die Spanne als Zielvorgabe. Der Weg ueber die Anthropic-CLI behandelte
|
||||||
|
sie als Richtwert und lag zwischen neun und einundzwanzig.
|
||||||
|
|
||||||
|
neu=True gilt fuer die Aktualisierung, dort zaehlen nur die neu
|
||||||
|
hinzugekommenen Meldungen und der Korridor ist enger.
|
||||||
|
"""
|
||||||
|
from config import (
|
||||||
|
FAKTEN_JE_ARTIKEL, FAKTEN_MAX, FAKTEN_MIN,
|
||||||
|
FAKTEN_NEU_JE_ARTIKEL, FAKTEN_NEU_MAX, FAKTEN_NEU_MIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
je_artikel = FAKTEN_NEU_JE_ARTIKEL if neu else FAKTEN_JE_ARTIKEL
|
||||||
|
kleinstwert = FAKTEN_NEU_MIN if neu else FAKTEN_MIN
|
||||||
|
groesstwert = FAKTEN_NEU_MAX if neu else FAKTEN_MAX
|
||||||
|
|
||||||
|
aus_material = round(max(0, anzahl_meldungen) / max(1, je_artikel))
|
||||||
|
obergrenze = max(kleinstwert * 2, min(groesstwert, aus_material))
|
||||||
|
untergrenze = max(kleinstwert, obergrenze // 2)
|
||||||
|
return untergrenze, obergrenze
|
||||||
|
|
||||||
|
|
||||||
def bewertungsregeln() -> str:
|
def bewertungsregeln() -> str:
|
||||||
"""Verbindlicher Regelblock, wird an jeden Faktencheck-Auftrag angehaengt.
|
"""Verbindlicher Regelblock, wird an jeden Faktencheck-Auftrag angehaengt.
|
||||||
|
|
||||||
@@ -1055,10 +1092,16 @@ class FactCheckerAgent:
|
|||||||
articles_text = self._format_articles_text(articles)
|
articles_text = self._format_articles_text(articles)
|
||||||
|
|
||||||
template = RESEARCH_FACTCHECK_PROMPT_TEMPLATE if incident_type == "research" else FACTCHECK_PROMPT_TEMPLATE
|
template = RESEARCH_FACTCHECK_PROMPT_TEMPLATE if incident_type == "research" else FACTCHECK_PROMPT_TEMPLATE
|
||||||
|
fakten_min, fakten_max = faktenspanne(len(articles))
|
||||||
|
logger.info(
|
||||||
|
"Faktencheck: %d Meldungen, Richtwert %d bis %d Faktenaussagen",
|
||||||
|
len(articles), fakten_min, fakten_max)
|
||||||
prompt = template.format(
|
prompt = template.format(
|
||||||
title=title,
|
title=title,
|
||||||
articles_text=articles_text,
|
articles_text=articles_text,
|
||||||
output_language=output_language,
|
output_language=output_language,
|
||||||
|
fakten_min=fakten_min,
|
||||||
|
fakten_max=fakten_max,
|
||||||
) + bewertungsregeln()
|
) + bewertungsregeln()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -1105,11 +1148,17 @@ class FactCheckerAgent:
|
|||||||
else:
|
else:
|
||||||
template = INCREMENTAL_FACTCHECK_PROMPT_TEMPLATE
|
template = INCREMENTAL_FACTCHECK_PROMPT_TEMPLATE
|
||||||
|
|
||||||
|
fakten_min, fakten_max = faktenspanne(len(new_articles), neu=True)
|
||||||
|
logger.info(
|
||||||
|
"Inkrementeller Faktencheck: %d neue Meldungen, Richtwert %d bis %d neue Aussagen",
|
||||||
|
len(new_articles), fakten_min, fakten_max)
|
||||||
prompt = template.format(
|
prompt = template.format(
|
||||||
title=title,
|
title=title,
|
||||||
articles_text=articles_text,
|
articles_text=articles_text,
|
||||||
existing_facts_text=existing_facts_text,
|
existing_facts_text=existing_facts_text,
|
||||||
output_language=output_language,
|
output_language=output_language,
|
||||||
|
fakten_min=fakten_min,
|
||||||
|
fakten_max=fakten_max,
|
||||||
) + bewertungsregeln()
|
) + bewertungsregeln()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -1164,6 +1213,7 @@ class FactCheckerAgent:
|
|||||||
articles_text = self._format_articles_text(new_articles, max_articles=15)
|
articles_text = self._format_articles_text(new_articles, max_articles=15)
|
||||||
|
|
||||||
from config import CLAUDE_MODEL_FAST
|
from config import CLAUDE_MODEL_FAST
|
||||||
|
triage_min, triage_max = faktenspanne(len(new_articles), neu=True)
|
||||||
triage_prompt = TRIAGE_PROMPT_TEMPLATE.format(
|
triage_prompt = TRIAGE_PROMPT_TEMPLATE.format(
|
||||||
output_language=output_language,
|
output_language=output_language,
|
||||||
fact_count=len(existing_facts),
|
fact_count=len(existing_facts),
|
||||||
@@ -1171,6 +1221,8 @@ class FactCheckerAgent:
|
|||||||
article_count=len(new_articles),
|
article_count=len(new_articles),
|
||||||
articles_text=articles_text,
|
articles_text=articles_text,
|
||||||
max_per_group=MAX_FACTS_PER_VERIFY_GROUP,
|
max_per_group=MAX_FACTS_PER_VERIFY_GROUP,
|
||||||
|
fakten_min=triage_min,
|
||||||
|
fakten_max=triage_max,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -140,6 +140,19 @@ EU_VERIFY_COUNTER_SHARE = float(os.environ.get("EU_VERIFY_COUNTER_SHARE", "0.3")
|
|||||||
EU_VERIFY_FULLTEXT_QUERIES = int(os.environ.get("EU_VERIFY_FULLTEXT_QUERIES", "3"))
|
EU_VERIFY_FULLTEXT_QUERIES = int(os.environ.get("EU_VERIFY_FULLTEXT_QUERIES", "3"))
|
||||||
EU_VERIFY_FULLTEXT_CHARS = int(os.environ.get("EU_VERIFY_FULLTEXT_CHARS", "1800"))
|
EU_VERIFY_FULLTEXT_CHARS = int(os.environ.get("EU_VERIFY_FULLTEXT_CHARS", "1800"))
|
||||||
|
|
||||||
|
# Wie viele Faktenaussagen ein Faktencheck aufstellen soll. Der Richtwert waechst
|
||||||
|
# mit der Menge des Materials. Eine feste Obergrenze von zehn fuehrte dazu, dass
|
||||||
|
# aus 16 Meldungen genauso viele Fakten wurden wie aus 91, obwohl die Lage im
|
||||||
|
# zweiten Fall deutlich mehr pruefbare Punkte hergibt.
|
||||||
|
FAKTEN_JE_ARTIKEL = int(os.environ.get("FAKTEN_JE_ARTIKEL", "5"))
|
||||||
|
FAKTEN_MIN = int(os.environ.get("FAKTEN_MIN", "5"))
|
||||||
|
FAKTEN_MAX = int(os.environ.get("FAKTEN_MAX", "20"))
|
||||||
|
# Dasselbe fuer die Aktualisierung, dort zaehlen nur die neu hinzugekommenen
|
||||||
|
# Meldungen.
|
||||||
|
FAKTEN_NEU_JE_ARTIKEL = int(os.environ.get("FAKTEN_NEU_JE_ARTIKEL", "5"))
|
||||||
|
FAKTEN_NEU_MIN = int(os.environ.get("FAKTEN_NEU_MIN", "3"))
|
||||||
|
FAKTEN_NEU_MAX = int(os.environ.get("FAKTEN_NEU_MAX", "10"))
|
||||||
|
|
||||||
# --- Verbrauchssaetze (Credits je Aktion) -------------------------------------
|
# --- Verbrauchssaetze (Credits je Aktion) -------------------------------------
|
||||||
# Beschlossen 2026-07-23, der Verbrauchsrechner im Verwaltungsportal nutzt
|
# Beschlossen 2026-07-23, der Verbrauchsrechner im Verwaltungsportal nutzt
|
||||||
# dieselben Werte: Live-Lauf 45, Recherche je Durchlauf 40 (das Anlegen faehrt
|
# dieselben Werte: Live-Lauf 45, Recherche je Durchlauf 40 (das Anlegen faehrt
|
||||||
|
|||||||
125
tests/test_faktenspanne.py
Normale Datei
125
tests/test_faktenspanne.py
Normale Datei
@@ -0,0 +1,125 @@
|
|||||||
|
"""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)
|
||||||
In neuem Issue referenzieren
Einen Benutzer sperren