fix(knowledge): 检索服务适配现库集合 schema、发布对齐的工具白名单、免责声明只由治理层注入

合并暴露的三个真机问题(单测全绿但线上必挂):

1. 检索服务字段名与现库集合不符 -> 静默零召回
   架构师那套按 load_knowledge_milvus.py 的 schema 读 doc_id/content/chapter/section/
   visibility,而现库三集合的真实字段是 knowledge_id/title/snippet/tags/version/intent。
   Milvus 对不存在的字段直接报错 -> 三集合全失败 -> degraded -> 客服一律转人工。
   改法:只改读取侧,用 _FIELD_ALIASES 映射;KnowledgeHit 对外形状不变(下游与测试不动)。
   代价已注明:没有 visibility 字段 -> 检索层内部资料硬隔离失效(现库 356 行均为对外知识)。

2. 发布白名单与代码上限不匹配 -> AGENT_PERMISSION_DENIED
   active 版本白名单是 query_knowledge,而合并后代码上限是 search_knowledge/check_suitability/
   query_customer_profile -> 交集为空 -> 所有知识问题 failed。
   改法:publish_customer_service_config.py 补 PROFILE_TOOL 进 faq 白名单,并让同 key 的
   继承项被本次定义覆盖(旧值原样继承会被子集校验 422 拒掉整次发布)。已激活版本 216。

3. 免责声明重复出现
   Agent 自己拼一句 + 治理层追加权威话术 -> 客户看到两条。改为只由治理层注入
   (话术属发布配置,改文案不该改代码)。风控等内部 Agent 不注入(结构化输出不被污染)。

测试:934 passed / 1 failed(test_fund_readonly_contract 既有空集缺陷,与本线无关)
真机:知识问答两问 succeeded 且只带一条声明;画像问答 succeeded;知识库三端点全绿
This commit is contained in:
qyqy
2026-09-11 15:27:16 +08:00
parent 57c4add7d8
commit 395bad25b7
5 changed files with 142 additions and 71 deletions
@@ -159,9 +159,16 @@ FALLBACK_TEMPLATE = (
"抱歉,这个问题我暂时无法给出准确答复。为避免给您错误信息,"
f"建议您拨打客服热线 {HOTLINE}({SERVICE_HOURS})转人工客服咨询。"
)
# 客户侧只展示这一句固定话术(业务方确定)。原中置信的"信息可能不完整"提示已按此移除,
# 即中置信回答不再对客户标注不确定性——这是调整时知情的取舍,不是遗漏。
DISCLAIMER = "(以上内容由智能客服依据公司公开资料整理,不构成投资建议)"
# 免责声明**只由治理层注入**(`PlatformGovernance.review` → `review_output`,话术取自
# `agent_reply_template` 的 `TPL_DISCLAIMER`,取不到时退回 `FALLBACK_DISCLAIMER`)。
#
# 这里曾自行拼一句 `DISCLAIMER`,合并后与治理层的话术**同时出现**,客户会看到两条
# 意思重复的声明的(实测复现)。更重要的是分工问题:话术是合规文案,属于**发布配置**,
# 改文案不该改代码;Agent 自己拼等于把可配置的合规文案硬编码进业务逻辑,
# 而且治理层无法判断"业务是不是已经加过了"(它只认自己追加过的那个形状)。
# 因此本文件不再定义、也不再引用任何免责声明常量。
# 客服热线:正式号码确定后改这里(或改为读配置项,避免改代码)
CHITCHAT_PROMPT_CODE = "customer_service_chitchat"
CHITCHAT_TASK_TYPE = "chat"
@@ -291,15 +298,15 @@ class CustomerServiceAgent(BaseAgent):
if not content:
return self._guide_to_human("命中内容为空")
# 正文只保留「答案 + 固定免责声明」:业务方要求客户侧只看到这一句固定话术,
# 因此不确定性提示与出处行都不再出现在正文里。
# 正文只保留答案本身:固定免责声明由**治理层**统一追加(见文件头 `DISCLAIMER` 说明),
# 业务代码不再拼字符串——否则会出现两条重复声明,且合规文案变成不可配置的硬编码。
#
# 可追溯性不受影响:本次命中哪个知识块仍由审计(agent.tool_executed 的工具调用记录)
# 与消息表留痕,只是不面向客户展示。若将来要把出处给客户看,应当走
# source_references 的 knowledge 类型(需先让 ToolExecutor 登记本次可引用的 doc_id),
# 而不是继续往正文里拼字符串。
return CoreResult(
text=f"{content[:MAX_ANSWER_CHARS]}\n{DISCLAIMER}",
text=content[:MAX_ANSWER_CHARS],
intent=self._classified_intent,
)
@@ -383,7 +390,7 @@ class CustomerServiceAgent(BaseAgent):
f"风险测评结果为准,不以本次自述为准。\n{text}"
)
return CoreResult(
text=f"{text}\n{DISCLAIMER}",
text=text,
intent=self._classified_intent,
)
@@ -505,7 +512,7 @@ class CustomerServiceAgent(BaseAgent):
if not text:
return self._guide_to_human("模型返回为空")
return CoreResult(
text=f"{text[:MAX_ANSWER_CHARS]}\n{DISCLAIMER}",
text=text[:MAX_ANSWER_CHARS],
intent=self._classified_intent,
)