fix(eu): Belastungsprobe folgt auch auf eine erfolgreiche Nachbelegung
Der erste Lauf mit den Gegenproben (Lage 64) zeigte, dass der Faktencheck selbst jetzt ehrlich arbeitet. Der erste Durchgang liess 3 von 10 Behauptungen offen, also 30 Prozent und damit genau das Niveau des Anthropic-Wegs. Vorher waren es acht Laeufe hintereinander null. Danach hob die Nachhak-Runde alle drei wieder auf bestaetigt, und der Lauf endete erneut ohne eine einzige Unsicherheit. Ursache war ein Denkfehler im Aufbau. Die zweite Runde war ein Entweder-oder. Entweder wurde nachbelegt oder es lief die Belastungsprobe. Sobald nachbelegt wurde, stand am Ende wieder alles auf bestaetigt und niemand prueft das nach. Jetzt laufen beide Schritte nacheinander. Erst wird nachbelegt, danach greift die Belastungsprobe, wenn kaum noch etwas offen ist. Sie prueft damit genau die frisch vergebenen Bestaetigungen. Damit sie wirklich neu sucht, meldet die Nachhak-Runde ihre Anfragen zurueck und die Belastungsprobe meidet auch diese. Der Weg ueber die Anthropic-CLI bleibt unveraendert. 254 Pruefungen laufen ohne Netzzugriff und ohne Kosten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -769,30 +769,38 @@ class FactCheckerAgent:
|
||||
# Die zweite Runde ist eine Verbesserung, keine Voraussetzung. Faellt sie
|
||||
# aus, bleibt das Ergebnis des ersten Durchgangs erhalten, statt dass der
|
||||
# ganze Faktencheck verloren geht.
|
||||
gestellte_anfragen = list(suche.queries)
|
||||
try:
|
||||
# Erster Schritt: offene Punkte nachbelegen, sofern welche da sind.
|
||||
offene = [f for f in facts if f.get("status") in OFFENE_STATUS]
|
||||
if len(offene) >= EU_VERIFY_FOLLOWUP_MIN_OPEN:
|
||||
logger.info(
|
||||
"EU-Faktencheck: %d von %d Behauptungen offen, starte Nachhak-Runde",
|
||||
len(offene), len(facts))
|
||||
facts, zweite_usage = await self._eu_nachhaken(
|
||||
facts, nachhak_usage, nachhak_anfragen = await self._eu_nachhaken(
|
||||
facts=facts, offene=offene, title=title,
|
||||
output_language=output_language, incident_type=incident_type,
|
||||
avoid_queries=suche.queries, followup_queries=anzahl_nachhak,
|
||||
avoid_queries=gestellte_anfragen, followup_queries=anzahl_nachhak,
|
||||
)
|
||||
else:
|
||||
bestaetigt = [f for f in facts if f.get("status") in BESTAETIGTE_STATUS]
|
||||
if not bestaetigt:
|
||||
return facts, gesamt
|
||||
_add_usage(gesamt, nachhak_usage)
|
||||
gestellte_anfragen += nachhak_anfragen
|
||||
|
||||
# Zweiter Schritt: bleibt danach kaum etwas offen, wird das
|
||||
# geprueft. Ohne diesen Schritt hob die Nachhak-Runde am 02.08.2026
|
||||
# alle drei offenen Punkte wieder hoch und der Lauf endete erneut
|
||||
# ohne eine einzige Unsicherheit.
|
||||
offene = [f for f in facts if f.get("status") in OFFENE_STATUS]
|
||||
bestaetigt = [f for f in facts if f.get("status") in BESTAETIGTE_STATUS]
|
||||
if bestaetigt and len(offene) < EU_VERIFY_FOLLOWUP_MIN_OPEN:
|
||||
logger.info(
|
||||
"EU-Faktencheck: %d von %d Behauptungen bestaetigt, starte Belastungsprobe",
|
||||
len(bestaetigt), len(facts))
|
||||
facts, zweite_usage = await self._eu_belastungsprobe(
|
||||
"EU-Faktencheck: nur %d von %d Behauptungen offen, starte Belastungsprobe",
|
||||
len(offene), len(facts))
|
||||
facts, probe_usage = await self._eu_belastungsprobe(
|
||||
facts=facts, bestaetigt=bestaetigt, title=title,
|
||||
output_language=output_language, incident_type=incident_type,
|
||||
avoid_queries=suche.queries, queries=anzahl_nachhak,
|
||||
avoid_queries=gestellte_anfragen, queries=anzahl_nachhak,
|
||||
)
|
||||
_add_usage(gesamt, zweite_usage)
|
||||
_add_usage(gesamt, probe_usage)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception as e:
|
||||
@@ -912,9 +920,14 @@ class FactCheckerAgent:
|
||||
incident_type: str,
|
||||
avoid_queries: list[str],
|
||||
followup_queries: int | None = None,
|
||||
) -> tuple[list[dict], ClaudeUsage]:
|
||||
) -> tuple[list[dict], ClaudeUsage, list[str]]:
|
||||
"""Sucht gezielt Belege fuer die offenen Behauptungen und bewertet nur
|
||||
diese erneut. Gibt die zusammengefuehrte Faktenliste zurueck."""
|
||||
diese erneut.
|
||||
|
||||
Gibt die zusammengefuehrte Faktenliste, den Verbrauch und die gestellten
|
||||
Anfragen zurueck. Letztere braucht die Belastungsprobe, damit sie nicht
|
||||
dieselben Anfragen noch einmal stellt.
|
||||
"""
|
||||
from agents.claude_client import call_claude
|
||||
from agents.eu_researcher import (
|
||||
plan_verification_searches, build_eu_prompt, _add_usage,
|
||||
@@ -926,7 +939,7 @@ class FactCheckerAgent:
|
||||
kandidaten = offene[:MAX_FACTS_PER_VERIFY_GROUP]
|
||||
claims = [f.get("claim", "") for f in kandidaten if f.get("claim")]
|
||||
if not claims:
|
||||
return facts, gesamt
|
||||
return facts, gesamt, []
|
||||
|
||||
suche = await plan_verification_searches(
|
||||
title=title, search_items=claims, output_language=output_language,
|
||||
@@ -937,7 +950,7 @@ class FactCheckerAgent:
|
||||
_add_usage(gesamt, suche.usage)
|
||||
if not block:
|
||||
logger.info("EU-Nachhak-Runde: keine zusaetzlichen Belege gefunden, Fakten bleiben unveraendert")
|
||||
return facts, gesamt
|
||||
return facts, gesamt, suche.queries
|
||||
|
||||
status_werte = ("established|unverified|disputed|false|developing"
|
||||
if incident_type == "research"
|
||||
@@ -954,17 +967,17 @@ class FactCheckerAgent:
|
||||
_add_usage(gesamt, usage)
|
||||
except TimeoutError:
|
||||
logger.warning("EU-Nachhak-Runde: Timeout, Fakten bleiben unveraendert")
|
||||
return facts, gesamt
|
||||
return facts, gesamt, suche.queries
|
||||
except Exception as e:
|
||||
logger.warning("EU-Nachhak-Runde fehlgeschlagen (%s), Fakten bleiben unveraendert", e)
|
||||
return facts, gesamt
|
||||
return facts, gesamt, suche.queries
|
||||
|
||||
# Korrigiert sich das Modell selbst und haengt eine zweite Fassung an,
|
||||
# zaehlt die inhaltsreichste, nicht die erste.
|
||||
fassungen = extract_json_arrays(result or "")
|
||||
if not fassungen:
|
||||
logger.warning("EU-Nachhak-Runde: Antwort nicht auswertbar, Fakten bleiben unveraendert")
|
||||
return facts, gesamt
|
||||
return facts, gesamt, suche.queries
|
||||
aktualisierungen = max(fassungen, key=len)
|
||||
|
||||
hochgestuft = 0
|
||||
@@ -1032,7 +1045,7 @@ class FactCheckerAgent:
|
||||
"EU-Nachhak-Runde abgeschlossen: %d von %d offenen Behauptungen belegt",
|
||||
hochgestuft, len(kandidaten),
|
||||
)
|
||||
return facts, gesamt
|
||||
return facts, gesamt, suche.queries
|
||||
|
||||
async def check(self, title: str, articles: list[dict], incident_type: str = "adhoc", output_language: str = "Deutsch") -> tuple[list[dict], ClaudeUsage | None]:
|
||||
"""Führt vollständigen Faktencheck durch (erster Refresh)."""
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren