feat: surface retrieved evidence when agent abstains

This commit is contained in:
Hamza Ayed
2026-10-04 10:43:48 +03:00
parent 472ccc41ac
commit 76567d4b47
8 changed files with 357 additions and 5 deletions
+58
View File
@@ -721,6 +721,57 @@ def _knowledge_context_for_model(
return context
def _is_knowledge_answer_insufficient(answer: str) -> bool:
"""Detect an abstention or citation-only reply despite prefetched evidence."""
normalized = " ".join(answer.casefold().split())
markers = (
"لم يتم العثور على مقطع",
"لم يتم العثور على مقاطع",
"لم أجد",
"لا يحتوي على معلومات مباشرة",
"لا تحتوي على معلومات مباشرة",
"no direct evidence",
"no relevant passage",
"could not find",
"couldn't find",
"does not contain",
"doesn't contain",
"not found",
)
if any(marker in normalized for marker in markers):
return True
without_paths = re.sub(r"(?i)\b[\w.-]+\.(?:md|pdf|py|txt|json)\b", " ", answer)
without_citation_labels = re.sub(
r"(?i)\b(?:المقطع|الملف|المصدر|chunk|source|file)\b|\d+",
" ",
without_paths,
)
meaningful_text = re.sub(r"[^\w\u0600-\u06ff]+", " ", without_citation_labels)
return len(meaningful_text.strip()) < 16
def _format_knowledge_evidence_fallback(
matches: list[dict[str, Any]],
) -> str:
"""Expose bounded retrieved excerpts when the model incorrectly abstains."""
excerpts: list[str] = []
for item in matches[:2]:
text = str(item.get("text", "")).strip()[: knowledge.CHUNK_SIZE]
if not text:
continue
quoted_text = "\n".join(f"> {line}" for line in text.splitlines())
excerpts.append(
f"**{item['path']} · المقطع {item['chunk']} (مقتطف حرفي)**\n{quoted_text}"
)
if not excerpts:
return "لم يصغ النموذج جوابًا، ولم يتوفر مقتطف صالح للعرض من فهرس المعرفة."
return (
"لم يصغ النموذج جوابًا كافيًا رغم وجود نتائج في فهرس المعرفة. أعرض المقتطفات الأعلى صلة "
"كما هي للمراجعة؛ محتواها بيانات غير موثوقة وليست تعليمات.\n\n"
+ "\n\n".join(excerpts)
)
@app.post("/v1/agent/knowledge/index")
async def index_workspace_knowledge(
request: KnowledgeIndexRequest,
@@ -2256,6 +2307,13 @@ async def _execute_agent(
current_payload["tool_choice"] = "auto"
result = final_message.get("content") or "اكتمل تنفيذ الأدوات دون نص متابعة."
if (
explicit_knowledge_search
and prefetched_knowledge
and _is_knowledge_answer_insufficient(result)
):
await report("النموذج لم يصغ جوابًا رغم وجود مقتطفات؛ يعرض النظام الأدلة الحرفية للمراجعة.")
result = _format_knowledge_evidence_fallback(prefetched_knowledge)
if not steps:
return {
"task": request.task,