fix(eu): drei Fehler beheben, die den Ertrag des Faktenchecks aufzehrten
Der Vergleichslauf zur Innenministerkonferenz (Lage 49) zeigte, dass der verbesserte Faktencheck zwar zehn Fakten lieferte, davon aber nur drei uebrig blieben. Die Ursachen lagen in drei nachgelagerten Stellen. 1. Quellenzuordnung stufte alle zehn Fakten herab. Durch den groesseren Belegblock stuetzt das Modell seine Fakten jetzt staerker auf die europaeische Suche als auf die gespeicherten Meldungen. Es zitiert dabei die Belegnummern statt vollstaendiger Adressen. Die Quellenzuordnung suchte daraufhin vergeblich nach passenden Meldungen und stufte jeden Fakt herab. Im Vergleich: Lauf 45 hatte null Herabstufungen, Lauf 44 eine, Lauf 49 zehn von zehn. Behoben an zwei Stellen. Die Belegsuche gibt die gefundenen Quellen jetzt einzeln zurueck, der Faktencheck reicht sie an die Zuordnung durch, und der Auftrag verlangt ausdruecklich die vollstaendige Adresse je Beleg. 2. Duplikatpruefung loeschte sieben von zehn Fakten. Das Clustering warf inhaltlich verschiedene Beschluesse in eine Gruppe, weil viele Behauptungen gleich beginnen. Es gab keinerlei Absicherung, bei kleinen Faktenmengen entschied das Modell sogar voellig allein. Zwei Sicherungen greifen jetzt. Eine Gruppe, die mehr als 40 Prozent aller Fakten umfasst, wird verworfen. Und jeder Loeschkandidat muss dem behaltenen Fakt auch rechnerisch aehnlich sein, Grenze 0,55 im selben Mass wie im Vorfilter. Beide Werte sind ueber Umgebungsvariablen einstellbar. 3. Leerrunden in der Recherche. War die Treffer-Obergrenze erreicht, brach nur die innere Schleife ab. Die Rundenschleife lief bis zum Ende weiter und befragte jedes Mal das teuerste Modell, ohne noch eine einzige Suche auszufuehren. Das kostete rund 0,17 USD je Durchgang, bei drei Durchgaengen etwa 0,50 USD pro Aktualisierung. Der Weg ueber die Anthropic-CLI bleibt unveraendert. Neu sind 16 Pruefungen, darunter der nachgebildete Fall aus Lage 49, insgesamt laufen jetzt 80 Pruefungen ohne Netzzugriff und ohne Kosten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -80,10 +80,11 @@ plan_antwort["queries"] = [
|
||||
treffer_je_anfrage["Ceuta Opferzahl offiziell"] = treffer(2, "a")
|
||||
treffer_je_anfrage["Ceuta border deaths toll"] = treffer(2, "b")
|
||||
treffer_je_anfrage["Sanchez Ceuta declaracion"] = treffer(2, "c")
|
||||
block, usage, ausgefuehrt = asyncio.run(eur.plan_verification_searches(
|
||||
_r = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["57 Tote gemeldet", "Sanchez sprach von Angriff"],
|
||||
output_language="Deutsch", max_queries=7,
|
||||
))
|
||||
block, usage, ausgefuehrt = _r.block, _r.usage, _r.queries
|
||||
pruefe("A1 alle geplanten Anfragen ausgefuehrt", len(zustand["suchen"]) == 3, zustand["suchen"])
|
||||
pruefe("A2 ausgefuehrte Anfragen zurueckgemeldet", len(ausgefuehrt) == 3, ausgefuehrt)
|
||||
pruefe("A3 jeder Punkt steht im Planungsauftrag",
|
||||
@@ -106,9 +107,10 @@ plan_antwort["queries"] = [
|
||||
]
|
||||
treffer_je_anfrage["anfrage eins"] = treffer(3, "x")
|
||||
treffer_je_anfrage["anfrage zwei"] = treffer(3, "x") # identische URLs
|
||||
block_b, _, _ = asyncio.run(eur.plan_verification_searches(
|
||||
_rb = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=7,
|
||||
))
|
||||
block_b = _rb.block
|
||||
pruefe("B1 Dubletten entfernt", block_b.count("[S") == 3, block_b.count("[S"))
|
||||
pruefe("B2 Nummerierung bleibt luecklos",
|
||||
all(("[S" + str(i) + "]") in block_b for i in (1, 2, 3)))
|
||||
@@ -120,10 +122,11 @@ plan_antwort["queries"] = [
|
||||
{"q": "neue anfrage", "market": "de-de"},
|
||||
]
|
||||
treffer_je_anfrage["neue anfrage"] = treffer(2, "n")
|
||||
block_c, _, ausgefuehrt_c = asyncio.run(eur.plan_verification_searches(
|
||||
_rc = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=5,
|
||||
avoid_queries=["alte anfrage"], label="Nachhak-Suche",
|
||||
))
|
||||
block_c, ausgefuehrt_c = _rc.block, _rc.queries
|
||||
pruefe("C1 bereits gestellte Anfrage wird verworfen",
|
||||
[s["q"] for s in zustand["suchen"]] == ["neue anfrage"], zustand["suchen"])
|
||||
pruefe("C2 Sperrliste steht im Planungsauftrag", "alte anfrage" in zustand["plan_prompt"])
|
||||
@@ -134,9 +137,10 @@ neu()
|
||||
plan_antwort["queries"] = [{"q": "q" + str(i), "market": "de-de"} for i in range(1, 11)]
|
||||
for i in range(1, 11):
|
||||
treffer_je_anfrage["q" + str(i)] = treffer(20, "y" + str(i))
|
||||
block_d, _, ausgefuehrt_d = asyncio.run(eur.plan_verification_searches(
|
||||
_rd = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=4,
|
||||
))
|
||||
block_d, ausgefuehrt_d = _rd.block, _rd.queries
|
||||
pruefe("D1 hoechstens max_queries Anfragen", len(ausgefuehrt_d) == 4, ausgefuehrt_d)
|
||||
pruefe("D2 Treffer je Anfrage begrenzt",
|
||||
block_d.count("[S") == 4 * EU_VERIFY_HITS_PER_QUERY, block_d.count("[S"))
|
||||
@@ -163,10 +167,11 @@ async def staan_mit_fehler(q, **kw):
|
||||
|
||||
|
||||
eur.staan_search = staan_mit_fehler
|
||||
block_e, usage_e, ausgefuehrt_e = asyncio.run(eur.plan_verification_searches(
|
||||
_re = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=5,
|
||||
))
|
||||
eur.staan_search = fake_staan
|
||||
block_e, usage_e, ausgefuehrt_e = _re.block, _re.usage, _re.queries
|
||||
pruefe("E1 gescheiterte Suche uebersprungen", ausgefuehrt_e == ["heil"], ausgefuehrt_e)
|
||||
pruefe("E2 gefundene Belege bleiben erhalten", block_e.count("[S") == 2, block_e.count("[S"))
|
||||
pruefe("E3 nur bezahlte Suchen berechnet",
|
||||
@@ -174,15 +179,48 @@ pruefe("E3 nur bezahlte Suchen berechnet",
|
||||
|
||||
neu()
|
||||
plan_antwort["queries"] = []
|
||||
block_f, _, ausgefuehrt_f = asyncio.run(eur.plan_verification_searches(
|
||||
_rf = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=5,
|
||||
))
|
||||
block_f, ausgefuehrt_f = _rf.block, _rf.queries
|
||||
pruefe("E4 leere Planung liefert leeren Block", block_f == "" and ausgefuehrt_f == [])
|
||||
|
||||
block_g, _, _ = asyncio.run(eur.plan_verification_searches(
|
||||
_rg = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=[], max_queries=5,
|
||||
))
|
||||
block_g = _rg.block
|
||||
pruefe("E5 ohne Pruefpunkte keine Suche", block_g == "")
|
||||
|
||||
print("\nF) Gefundene Quellen werden einzeln zurueckgegeben")
|
||||
neu()
|
||||
plan_antwort["queries"] = [{"q": "eine anfrage", "market": "de-de"}]
|
||||
treffer_je_anfrage["eine anfrage"] = treffer(3, "q", host="tagesschau.de")
|
||||
_rh = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=5,
|
||||
))
|
||||
pruefe("F1 jede Quelle einzeln gemeldet", len(_rh.quellen) == 3, len(_rh.quellen))
|
||||
pruefe("F2 Quelle traegt Titel, Herkunft und Adresse",
|
||||
all(q.get("headline") and q.get("source") and q.get("source_url") for q in _rh.quellen),
|
||||
_rh.quellen[:1])
|
||||
pruefe("F3 Adressen stimmen mit dem Block ueberein",
|
||||
all(q["source_url"] in _rh.block for q in _rh.quellen))
|
||||
neu()
|
||||
plan_antwort["queries"] = [{"q": "a", "market": "de-de"}, {"q": "b", "market": "de-de"}]
|
||||
treffer_je_anfrage["a"] = treffer(2, "dup")
|
||||
treffer_je_anfrage["b"] = treffer(2, "dup")
|
||||
_ri = asyncio.run(eur.plan_verification_searches(
|
||||
title="Ceuta", search_items=["Punkt"], max_queries=5,
|
||||
))
|
||||
pruefe("F4 doppelte Quellen nur einmal gemeldet", len(_ri.quellen) == 2, len(_ri.quellen))
|
||||
|
||||
print("\nG) Der Auftrag verlangt vollstaendige Quellenadressen")
|
||||
from agents.eu_researcher import build_eu_prompt # noqa: E402
|
||||
|
||||
mit = build_eu_prompt("Auftrag", "\n\nBELEGE\n[S1] Titel | host | https://x.y/z")
|
||||
ohne = build_eu_prompt("Auftrag", "")
|
||||
pruefe("G1 Hinweis auf die Adresspflicht vorhanden",
|
||||
"vollständige" in mit and "URL" in mit)
|
||||
pruefe("G2 ohne Belege kein Adresshinweis", "Adresse (die URL" not in ohne)
|
||||
|
||||
print("\nErgebnis: " + str(ok) + " bestanden, " + str(fail) + " fehlgeschlagen")
|
||||
sys.exit(1 if fail else 0)
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren