feat: surface retrieved evidence when agent abstains
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user