refactor: 客服回答正文只保留固定免责声明
业务方要求客户侧只看到一句固定话术(不构成投资建议),因此从回答正文移除: 1. 中置信的「(以上信息可能不完整,具体以产品说明书与公司制度为准)」提示; 2. 「(依据:…)」出处行——原先它显示的是知识块标题,FAQ 的标题就是问题本身, 展示为「(依据:公司什么时候成立的?)」并没有可读价值。 可追溯性不受影响:本次命中哪个知识块仍由审计(agent.tool_executed 的工具调用记录) 与消息表留痕,source_references(tool 类型)也照常返回,只是不再面向客户展示。 取舍已在代码注释中标明:中置信回答此后不再向客户标注不确定性。 若将来要把出处展示给客户,应当走 source_references 的 knowledge 类型 (前提是让 ToolExecutor 把工具返回的 doc_id 登记为本次可引用来源), 而不是继续往正文里拼字符串。 同时移除因此不再使用的 INCOMPLETE_NOTICE 常量、_source_note 方法, 以及提问工具里那句"正文没有依据行"的提示。 验证:ruff 通过、mypy 107 文件无错;customer_service_check 9/9 通过; ask_customer_service 实测回答正文为「答案 + 免责声明」两行。
This commit is contained in:
@@ -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