客服 Agent:知识检索、会话记忆、图投影与适当性裁决 #3
@@ -68,7 +68,8 @@ FALLBACK_TEMPLATE = (
|
||||
"抱歉,这个问题我暂时无法给出准确答复。为避免给您错误信息,"
|
||||
f"建议您拨打客服热线 {HOTLINE}({SERVICE_HOURS})转人工客服咨询。"
|
||||
)
|
||||
INCOMPLETE_NOTICE = "(以上信息可能不完整,具体以产品说明书与公司制度为准)"
|
||||
# 客户侧只展示这一句固定话术(业务方确定)。原中置信的"信息可能不完整"提示已按此移除,
|
||||
# 即中置信回答不再对客户标注不确定性——这是调整时知情的取舍,不是遗漏。
|
||||
DISCLAIMER = "(以上内容由智能客服依据公司公开资料整理,不构成投资建议)"
|
||||
|
||||
CHITCHAT_PROMPT_CODE = "customer_service_chitchat"
|
||||
@@ -149,20 +150,17 @@ class CustomerServiceAgent(BaseAgent):
|
||||
if not content:
|
||||
return self._guide_to_human("命中内容为空")
|
||||
|
||||
answer = content[:MAX_ANSWER_CHARS]
|
||||
if not confident:
|
||||
answer = f"{answer}\n{INCOMPLETE_NOTICE}"
|
||||
# 知识出处写进正文,而不是塞进 source_references:
|
||||
# `governance.review_output` 只接受「本次召回的记忆」与「本次成功调用的工具」两类引用
|
||||
# (用于防止 Agent 伪造来源),知识块的 doc_id 不属于这两类,会被判为非法引用。
|
||||
# 把文件标题与内部文件编号写进正文,客户与人工同样能核对,且不必放开那道校验。
|
||||
source_note = self._source_note(best)
|
||||
text = (
|
||||
f"{answer}\n{source_note}\n{DISCLAIMER}"
|
||||
if source_note
|
||||
else f"{answer}\n{DISCLAIMER}"
|
||||
# 正文只保留「答案 + 固定免责声明」:业务方要求客户侧只看到这一句固定话术,
|
||||
# 因此不确定性提示与出处行都不再出现在正文里。
|
||||
#
|
||||
# 可追溯性不受影响:本次命中哪个知识块仍由审计(agent.tool_executed 的工具调用记录)
|
||||
# 与消息表留痕,只是不面向客户展示。若将来要把出处给客户看,应当走
|
||||
# source_references 的 knowledge 类型(需先让 ToolExecutor 登记本次可引用的 doc_id),
|
||||
# 而不是继续往正文里拼字符串。
|
||||
return CoreResult(
|
||||
text=f"{content[:MAX_ANSWER_CHARS]}\n{DISCLAIMER}",
|
||||
intent=self._classified_intent,
|
||||
)
|
||||
return CoreResult(text=text, intent=self._classified_intent)
|
||||
|
||||
# ---- 出口二:闲聊(提示词走发布配置) ----
|
||||
|
||||
@@ -242,15 +240,6 @@ class CustomerServiceAgent(BaseAgent):
|
||||
return 0.0
|
||||
return self._score(hits[1].get("score"))
|
||||
|
||||
@staticmethod
|
||||
def _source_note(hit: dict[str, object]) -> str:
|
||||
"""把知识出处写成一行正文(文件标题 + 内部文件编号),便于客户与人工核对。"""
|
||||
title = str(hit.get("title") or "").strip()
|
||||
doc_no = str(hit.get("doc_no") or "").strip()
|
||||
if not title:
|
||||
return ""
|
||||
return f"(依据:{title}{',' + doc_no if doc_no else ''})"
|
||||
|
||||
def _references(self, hits: list[object]) -> tuple[SourceReference, ...]:
|
||||
"""保留待用:等基座支持 knowledge 类型引用后再启用。
|
||||
|
||||
|
||||
@@ -96,8 +96,6 @@ async def ask(
|
||||
references = result.get("source_references") or []
|
||||
for reference in references:
|
||||
print(f"来源引用:{reference.get('source_type')} / {reference.get('source_id')}")
|
||||
if not guided and "依据:" not in text:
|
||||
print("提示:这条回答正文里没有「依据:…」,说明知识命中的是通用来源,请人工核对。")
|
||||
print()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user