Files
group_xinghuo_jinrong/app/tool/kb_tools.py
T

72 lines
2.7 KiB
Python
Raw Normal View History

"""知识库对话 Tool(T21-5 · FLOW §2「milvus_tool:产品规则 RAG + source_refs」)。
与 core_tools / risk.chat_tools 同构的 Tool 定义层:由 tool_service.run_tool
经统一注册表分发。search_knowledge 是公开知识检索(产品手册/交易规则)——
**不做客户归属校验**(ToolSpec.skip_access_check=True):
- 知识内容为公开产品信息,无客户数据,归属校验无对象;
- 开放范围(customer + advisor,用户拍板 2026-09-07)由意图层控制:
_INTENT_KEYWORDS 仅 customer/advisor 组配置 kb 关键词,risk/analyst
不命中 → Tool 不会被触发;即使被直接调用,返回的也只是公开知识。
func 签名对齐 runner 约定 ``func(customer_id, core_ro, risk_repo, **params)``;
query 为唯一业务参数(tool_node 从 user_message 构造 tool_input 注入,
一期不来自 LLM 输出)。RAG 异常(EmbeddingError 等)原样上抛 → run_tool
统一转 TOOL_ERROR 留痕,不静默降级空结果(防 LLM 编造回答)。
"""
from __future__ import annotations
from typing import Any, Callable
from app.service import rag_service
# 对话 Tool 检索条数(与 rag_service.DEFAULT_TOP_K 一致;独立常量便于对话口径单独调整)
KB_TOP_K = 3
def search_knowledge(
query: str = "",
customer_id: str = "",
core_ro=None,
risk_repo=None,
) -> dict[str, Any]:
"""产品知识检索(TopK chunks + 溯源清单)。
customer_id/core_ro/risk_repo 为 runner 恒传参数,本 Tool 不使用
(公开知识,无归属语义);保留形参以满足统一签名。
"""
out = rag_service.search_knowledge(query, top_k=KB_TOP_K)
return {
"hit_count": len(out["results"]),
"results": out["results"],
"source_refs": out["source_refs"],
}
class KBToolSpec(dict):
"""知识库 Tool 注册表条目(与 core_tools.ToolSpec / RiskToolSpec 同构;
新增 skip_access_check:True → run_tool 跳过客户归属校验)。"""
KB_TOOL_REGISTRY: dict[str, KBToolSpec] = {
"search_knowledge": KBToolSpec(
func=search_knowledge,
description="检索产品知识库(基金产品手册、费率、申赎规则、风险说明;返回结果附溯源)",
requires_customer=False,
param_whitelist=("query",),
int_bounds={},
skip_access_check=True,
),
}
def get_kb_tool(name: str) -> KBToolSpec | None:
"""白名单查找(未知 Tool 返回 None)。"""
return KB_TOOL_REGISTRY.get(name)
def kb_tool_func(name: str) -> Callable[..., dict[str, Any]] | None:
spec = KB_TOOL_REGISTRY.get(name)
return spec["func"] if spec else None