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:
@@ -34,10 +34,15 @@ ADMIN = "9003"
|
||||
AGENT_TYPE = "customer_service"
|
||||
TOOL_NAME = "search_knowledge"
|
||||
SUITABILITY_TOOL = "check_suitability"
|
||||
# 画像只读工具:客服的"出口零"(本人风险等级/投资偏好/测评是否过期)走它取权威字段。
|
||||
# 那个出口复用的是 `faq` 意图 key(见 `customer_service.PROFILE_WHITELIST_INTENT`),
|
||||
# 所以**必须**把它加进 `faq` 的白名单里;漏了的表现是"问画像一律转人工",
|
||||
# 而画像出口本身是对的——这是纯配置缺口(实测复现过)。
|
||||
PROFILE_TOOL = "query_customer_profile"
|
||||
# 只有会调用工具的意图才需要白名单;chitchat(模型生成)与 transfer_human(引导人工)
|
||||
# 都不查知识库。给它们配空白名单反而会掩盖"配置漏配",因此不发布这两条。
|
||||
INTENT_TOOLS: dict[str, tuple[str, ...]] = {
|
||||
"faq": (TOOL_NAME,),
|
||||
"faq": (TOOL_NAME, PROFILE_TOOL),
|
||||
"product_inquiry": (TOOL_NAME,),
|
||||
"policy_explain": (TOOL_NAME,),
|
||||
# 适当性裁决要两步:先从知识库拿到产品的风险等级,再由底座按档案里的客户等级裁决
|
||||
@@ -208,9 +213,25 @@ async def main() -> int:
|
||||
for intent, tools in INTENT_TOOLS.items()
|
||||
]
|
||||
inherited_keys = {(str(i["namespace"]), str(i["item_key"])) for i in inherited}
|
||||
# **同 key 的继承项必须被本次新定义覆盖**,不能原样搬过去。
|
||||
# 血泪教训(实测):上一版发布的是 `faq = ["query_knowledge", ...]`,而那个工具
|
||||
# 已随"客服检索改为 search_knowledge"从代码上限移除;原样继承会让 admin 服务的
|
||||
# 子集校验(白名单 ⊆ 代码限定的 allowed_tools)直接 422 拒绝整次发布,
|
||||
# 报错是"配置超出 Agent 工具上限",看不出是继承造成的。
|
||||
inherited_only = [
|
||||
item for item in inherited
|
||||
if (str(item["namespace"]), str(item["item_key"])) not in {
|
||||
("agent_tools", f"{AGENT_TYPE}:{intent}") for intent in INTENT_TOOLS
|
||||
}
|
||||
]
|
||||
dropped = [item for item in inherited if item not in inherited_only]
|
||||
for item in dropped:
|
||||
print(f" [覆盖] {item['namespace']}/{item['item_key']} 将由本次定义替换"
|
||||
f"(原值 {item['value_json']})")
|
||||
pending = [
|
||||
item for item in new_items
|
||||
if (str(item["namespace"]), str(item["item_key"])) not in inherited_keys
|
||||
if (str(item["namespace"]), str(item["item_key"])) not in
|
||||
{(str(i["namespace"]), str(i["item_key"])) for i in inherited_only}
|
||||
]
|
||||
if not pending:
|
||||
print("客服白名单已存在于当前生效版本,无需发布")
|
||||
@@ -228,9 +249,9 @@ async def main() -> int:
|
||||
print(f"\n发布版本 id={release_id}")
|
||||
|
||||
base = f"/api/v1/admin/config-releases/{release_id}/platform-config-items"
|
||||
for item in [*inherited, *pending]:
|
||||
for item in [*inherited_only, *pending]:
|
||||
response = await post(client, base, auth=auth, payload=item)
|
||||
mark = "继承" if item in inherited else "新增"
|
||||
mark = "继承" if item in inherited_only else "新增"
|
||||
print(f" [{mark}] {item['namespace']}/{item['item_key']} → {response.status_code}")
|
||||
if response.status_code != 201:
|
||||
print(f" 失败:{response.text[:200]}")
|
||||
|
||||
Reference in New Issue
Block a user