Files
wiki/银行业Agent建设方案/报告/banking-intent-recognition.html
zdh c677393d08
Deploy Wiki to Production / deploy (push) Has been cancelled
feat: 入库 17 个新报告页
- 银行业Agent建设方案/报告/ 4 篇:建设方案 · 智能中台 · 意图识别 · 合规风险
- 研发型企业AI转型方案/报告/ 9 篇:角色矩阵(交互版) · 培训1-6课 · 角色矩阵 · 实操培训 · 培训路线图
- AI Agent 驾驭工程/报告/ 1 篇:Harness Engineering 全面解析
- 简历AI技术讲解.html + .md
- Dify部署分析报告.html
2026-06-20 22:38:20 +08:00

849 lines
50 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>银行智能中台 — 意图识别与工具检索方案</title>
<style>
:root {
--color-primary: #0078D4;
--color-primary-hover: #1E8CD8;
--color-primary-active: #005A9E;
--color-primary-bg: #E8F3FB;
--color-success: #107C10;
--color-success-bg: #E7F2E7;
--color-success-border: #9FC89F;
--color-warning: #FF8C00;
--color-warning-bg: #FFF4E5;
--color-warning-border: #FFC97F;
--color-error: #FF4D4F;
--color-error-bg: #FFF0F0;
--color-error-border: #FFB7B8;
--bg: #F5F5F5;
--bg-container: #FFFFFF;
--bg-elevated: #FAFAFA;
--border: #D9D9D9;
--border-light: #F0F0F0;
--text-primary: #141414;
--text-secondary: #595959;
--text-tertiary: #767676;
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 8px;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.03), 0 1px 6px -1px rgba(0,0,0,0.02);
--shadow-md: 0 2px 4px rgba(0,0,0,0.04), 0 4px 12px -2px rgba(0,0,0,0.04);
--shadow-lg: 0 4px 8px rgba(0,0,0,0.06), 0 8px 24px -4px rgba(0,0,0,0.08);
--sidebar-w: 280px;
--header-h: 64px;
--fluent-font-family-text: 'Segoe UI Variable Text', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
--fluent-font-family-mono: 'Cascadia Code', 'Fira Code', 'SF Mono', 'Consolas', monospace;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: var(--fluent-font-family-text);
background: var(--bg); color: var(--text-primary);
line-height: 1.57; font-size: 14px;
}
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); }
/* ===== HEADER ===== */
.header {
position: fixed; top: 0; left: 0; right: 0; height: var(--header-h);
background: rgba(255,255,255,0.88); backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border-light);
display: flex; align-items: center; padding: 0 2rem; z-index: 100;
}
.header h1 {
font-size: 18px; font-weight: 700;
background: linear-gradient(135deg, var(--color-primary), #1E8CD8);
-webkit-background-clip: text; background-clip: text;
-webkit-text-fill-color: transparent; color: transparent;
}
.header .back-link {
margin-right: 16px; font-size: 13px; color: var(--color-primary);
text-decoration: none; flex-shrink: 0;
}
.header .back-link:hover { text-decoration: underline; }
.header .version {
margin-left: auto; font-size: 12px; color: var(--text-tertiary);
font-family: var(--fluent-font-family-mono);
}
/* ===== SIDEBAR ===== */
.sidebar {
position: fixed; top: var(--header-h); left: 0; bottom: 0;
width: var(--sidebar-w); background: var(--bg-container);
border-right: 1px solid var(--border); overflow-y: auto;
padding: 1.25rem 0; z-index: 90;
}
.sidebar .toc-label {
font-size: 12px; text-transform: uppercase; letter-spacing: 0.1em;
color: var(--text-tertiary); padding: 0 1.25rem; margin-bottom: 0.75rem;
}
.sidebar nav ol { list-style: none; padding: 0; counter-reset: toc; }
.sidebar nav li { counter-increment: toc; padding: 0; }
.sidebar nav a {
display: block; padding: 0.45rem 1.25rem; color: var(--text-secondary);
text-decoration: none; font-size: 13px; line-height: 1.4;
border-left: 2px solid transparent; transition: all 0.15s;
}
.sidebar nav a::before {
content: counter(toc) ". "; color: var(--color-primary);
font-weight: 600; font-size: 12px; margin-right: 0.4rem;
}
.sidebar nav a:hover { color: var(--color-primary); background: var(--color-primary-bg); }
.sidebar nav a.active { color: var(--color-primary); border-left-color: var(--color-primary); background: var(--color-primary-bg); font-weight: 600; }
.hamburger-btn {
display: none; position: fixed; top: 12px; right: 16px; z-index: 200;
background: var(--bg-container); border: 1px solid var(--border);
border-radius: var(--radius-md); width: 40px; height: 40px;
font-size: 20px; cursor: pointer; align-items: center; justify-content: center;
}
/* ===== MAIN ===== */
.main {
margin-left: var(--sidebar-w); margin-top: var(--header-h);
padding: 32px 40px 64px; min-height: calc(100vh - var(--header-h));
max-width: 1200px;
}
/* ===== SECTIONS ===== */
section {
margin: 48px 0; scroll-margin-top: calc(var(--header-h) + 1rem);
}
section h2 { font-size: 22px; line-height: 30px; padding-bottom: 8px; border-bottom: 1px solid var(--border); margin-bottom: 20px; color: var(--color-primary); }
h3 { font-size: 18px; line-height: 26px; margin: 24px 0 12px; color: #0078D4; }
h4 { font-size: 15px; line-height: 22px; margin: 16px 0 8px; color: var(--color-success); }
/* ===== PARAGRAPH ===== */
p { color: var(--text-secondary); font-size: 14px; margin: 10px 0; text-align: justify; }
p strong { color: var(--text-primary); }
/* ===== CODE ===== */
code {
font-family: var(--fluent-font-family-mono);
font-size: 13px; background: var(--bg-elevated);
padding: 2px 6px; border-radius: var(--radius-sm);
border: 1px solid var(--border-light); color: #D4380D;
}
pre {
background: #1E1E1E; color: #D4D4D4; border-radius: var(--radius-md);
padding: 16px 20px; overflow-x: auto; margin: 16px 0;
font-family: var(--fluent-font-family-mono); font-size: 13px;
line-height: 1.6; tab-size: 4;
}
pre code { background: none; border: none; padding: 0; color: inherit; font-size: inherit; }
pre.ascii-diagram {
background: var(--bg-elevated); color: var(--text-secondary);
border: 1px solid var(--border); font-family: var(--fluent-font-family-mono);
font-size: 12px; line-height: 1.35; padding: 16px 20px; white-space: pre;
}
/* ===== TABLES ===== */
.table-wrap { overflow-x: auto; margin: 20px 0; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { padding: 10px 14px; border: 1px solid var(--border); text-align: left; vertical-align: top; }
th { background: var(--bg-elevated); font-weight: 700; color: var(--text-primary); white-space: nowrap; }
td { background: var(--bg-container); color: var(--text-secondary); }
tbody tr:hover td { background: var(--color-primary-bg); }
/* ===== LISTS ===== */
ul, ol { margin: 8px 0 8px 20px; }
li { margin: 6px 0; color: var(--text-secondary); font-size: 14px; }
li strong { color: var(--text-primary); }
/* ===== INFO BOXES ===== */
.box {
border-radius: var(--radius-md); padding: 20px 24px; margin: 18px 0;
}
.box h4 { margin: 0 0 8px; font-size: 14px; font-weight: 700; }
.box p { font-size: 14px; margin: 4px 0; text-indent: 0; }
.box-info { background: var(--color-primary-bg); border: 1px solid #91CAFF; }
.box-info h4 { color: var(--color-primary); }
.box-good { background: var(--color-success-bg); border: 1px solid var(--color-success-border); }
.box-good h4 { color: var(--color-success); }
.box-warn { background: var(--color-warning-bg); border: 1px solid var(--color-warning-border); }
.box-warn h4 { color: var(--color-warning); }
/* ===== BLOCKQUOTE ===== */
blockquote {
margin: 16px 0; padding: 16px 22px; background: var(--bg-elevated);
border-left: 3px solid var(--color-primary);
border-radius: 0 var(--radius-sm) var(--radius-sm) 0; color: var(--text-secondary);
}
blockquote p { text-indent: 0; }
hr { border: none; border-top: 1px solid var(--border-light); margin: 32px 0; }
.footer {
text-align: center; padding: 28px 0; color: var(--text-tertiary);
font-size: 13px; border-top: 1px solid var(--border-light); margin-top: 40px;
}
/* ===== KPI BAR ===== */
.kpi-bar {
display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 32px;
}
.kpi {
flex: 1; min-width: 130px; background: var(--bg-container);
border: 1px solid var(--border-light); border-radius: var(--radius-md);
padding: 16px 14px; text-align: center; box-shadow: var(--shadow-sm);
}
.kpi .num { font-size: 22px; font-weight: 800; color: var(--color-primary); line-height: 1.2; }
.kpi .label { font-size: 11px; color: var(--text-tertiary); margin-top: 4px; }
/* ===== FIGURE ===== */
.figure-block {
margin: 24px 0; padding: 20px 24px; background: var(--bg-container);
border: 1px solid var(--border); border-radius: var(--radius-md);
}
.figure-block .fig-title {
font-size: 13px; font-weight: 700; color: var(--text-primary); margin-bottom: 12px;
}
@media (max-width: 768px) {
.sidebar { display: none; }
.sidebar.open {
display: block; position: fixed; top: var(--header-h); left: 0; bottom: 0;
width: 280px; z-index: 150; box-shadow: var(--shadow-lg);
}
.hamburger-btn { display: flex; }
.main { margin-left: 0; padding: 20px 16px 40px; }
table { font-size: 12px; }
th, td { padding: 6px 8px; }
section { margin: 28px 0; }
section h2 { font-size: 18px; }
.kpi-bar { gap: 8px; }
.kpi { min-width: 90px; padding: 10px 8px; }
.kpi .num { font-size: 18px; }
}
</style>
</head>
<body>
<header class="header">
<a href="../../index.html" class="back-link">← 返回知识库</a>
<h1>意图识别与工具检索方案</h1>
<span class="version">银行智能中台子方案 · 2026-06</span>
</header>
<button class="hamburger-btn" onclick="document.getElementById('sidebar').classList.toggle('open')"></button>
<aside class="sidebar" id="sidebar">
<div class="toc-label">方案目录</div>
<nav><ol>
<li><a href="#问题定义">问题定义</a></li>
<li><a href="#整体架构意图识别在银行智能中台的位置">整体架构:意图识别在银行智能中台的位置</a></li>
<li><a href="#工具描述增强llm离线语义增强">工具描述增强:LLM离线语义增强</a></li>
<li><a href="#l1-意图提取">L1:意图提取</a></li>
<li><a href="#l1-混合检索dense--sparse--rrf">L1:混合检索(Dense + Sparse → RRF</a></li>
<li><a href="#l2-精排cross-encoder-rerank">L2:精排(Cross-encoder Rerank</a></li>
<li><a href="#l3-l5-多层兜底与持续优化">L3-L5:多层兜底与持续优化</a></li>
<li><a href="#场景走查意图识别实战">场景走查:意图识别实战</a></li>
<li><a href="#准确率指标与验证方式">准确率指标与验证方式</a></li>
<li><a href="#风险与缓解">风险与缓解</a></li>
</ol></nav>
</aside>
<main class="main" onclick="document.getElementById('sidebar').classList.remove('open')">
<div class="kpi-bar">
<div class="kpi"><div class="num">30<span style="font-size:11px;font-weight:400"> 万+</span></div><div class="label">待检索工具总量</div></div>
<div class="kpi"><div class="num">99<span style="font-size:11px;font-weight:400">%+</span></div><div class="label">L0预过滤削减率</div></div>
<div class="kpi"><div class="num">&lt;80<span style="font-size:11px;font-weight:400">ms</span></div><div class="label">混合检索延迟</div></div>
<div class="kpi"><div class="num">&gt;97<span style="font-size:11px;font-weight:400">%</span></div><div class="label">Top-15命中率目标</div></div>
<div class="kpi"><div class="num">6<span style="font-size:11px;font-weight:400"></span></div><div class="label">准确性保障层级</div></div>
</div>
<!-- ===== 1. 问题定义 ===== -->
<section><h2 id="问题定义">问题定义</h2>
<h3>规模量化</h3>
<p>银行存量服务 <strong>30 万个</strong>,每个工具平均约 300 tokens,全量描述 <strong>9000 万 tokens</strong>。而 LLM 上下文窗口 64K,实际可用空间约 40K tokens,单次可装载工具 ≤ <strong>130 个</strong>——仅占全部工具的 <strong>0.04%</strong></p>
<div class="figure-block">
<div class="fig-title">问题本质</div>
<pre class="ascii-diagram">用户自然语言问法
│ "查一下张三的征信" / "我能贷多少钱" / "这笔转账合规吗"
┌─────────────────────────────────────────────┐
│ 意图识别系统 │
│ │
│ 输入: 自然语言 + 用户三维上下文 │
│ 输出: 最匹配的 ≤15 个工具定义 │
│ │
│ 约束: 30万候选池 → 40K token预算 │
│ 延迟要求: 端到端 &lt; 300ms │
│ 准确率: Top-15 命中率 &gt; 97% │
│ 确定性: 安全相关过滤必须 100% 可靠 │
└─────────────────────────────────────────────┘</pre>
</div>
<h3>银行场景的特殊难度</h3>
<div class="table-wrap"><table>
<tr><th>难点</th><th>通用NLU</th><th>银行意图识别</th></tr>
<tr><td><strong>工具数量</strong></td><td>数十~数百个 API</td><td>30 万个服务,且持续增长</td></tr>
<tr><td><strong>领域术语</strong></td><td>通用词汇</td><td>"征信""授信""保函""贴现""头寸"等金融专有名词,且行内大量缩写</td></tr>
<tr><td><strong>问法多样性</strong></td><td>有限的同义表达</td><td>同一意图可能有 50+ 种自然问法:"查额度""能贷多少""我的信用贷款上限是多少""给我看看可用贷款"</td></tr>
<tr><td><strong>安全约束</strong></td><td>通常无</td><td>某些"漏"和"错"不可接受——对公客户经理绝不能看到对私储蓄工具;未签约产品的 API 不可见</td></tr>
<tr><td><strong>多意图混合</strong></td><td>较少</td><td>高频:"帮我查这个客户的征信,再评估一下他的还款能力"(征信查询+风险评估,2个工具)</td></tr>
</table></div>
</section>
<hr>
<!-- ===== 2. 整体架构 ===== -->
<section><h2 id="整体架构意图识别在银行智能中台的位置">整体架构:意图识别在银行智能中台的位置</h2>
<p>意图识别不是孤立模块,而是嵌入银行智能中台的<strong>工具检索漏斗</strong>中。整体链路如下:</p>
<pre class="ascii-diagram">用户消息 (自然语言)
│ "查张三的征信"
┌──────────────────────────────────────────────────────────────────┐
│ Gateway Layer: 三维鉴权网关 │
│ 渠道验签 → 用户身份解析 → 数据范围确定 → 构建 SecurityContext │
└──────────────────────────┬───────────────────────────────────────┘
│ SecurityContext {userType, channelId, dataScope, tenantId, ...}
┌──────────────────────────────────────────────────────────────────┐
│ L0: 确定性预过滤 (Deterministic Pre-filter) ★ 非意图识别 │
│ 规则引擎 × BitMap AND → 30万 → 500~3000 候选 │
│ 安全属性,100% 确定性,不依赖语义 │
└──────────────────────────┬───────────────────────────────────────┘
│ ~2000 候选工具
┌──────────────────────────────────────────────────────────────────┐
│ L1: 意图提取 + 混合检索 ★ 意图识别核心 │
│ │
│ ┌─────────────────────┐ ┌──────────────────────────────┐ │
│ │ 意图提取 (NLU) │ │ 混合检索 (Hybrid Retrieval) │ │
│ │ │ │ │ │
│ │ 自然语言 → 结构化意图 │ │ Dense (向量语义) │ │
│ │ {intent, domain, │ │ + Sparse (BM25关键词) │ │
│ │ entities, params} │ │ → RRF 倒数秩融合 │ │
│ │ │ │ → Top-100 │ │
│ │ LLM few-shot / │ │ │ │
│ │ 微调小模型 │ │ 延迟: &lt; 80ms │ │
│ └─────────────────────┘ └──────────────────────────────┘ │
└──────────────────────────┬───────────────────────────────────────┘
│ Top-100 候选工具
┌──────────────────────────────────────────────────────────────────┐
│ L2: 精排 (Cross-encoder Rerank) │
│ Cross-encoder 模型 → 100 候选重排序 → Top-15 │
│ 注入 Agent 当前对话上下文 → 延迟: &lt; 150ms │
└──────────────────────────┬───────────────────────────────────────┘
│ Top-15 工具定义 (约 4500 tokens)
┌──────────────────────────────────────────────────────────────────┐
│ Agent Orchestration Layer │
│ LLM 接收 {用户消息 + Top-15 工具定义 + System Prompt} │
│ → 选择最合适的工具 → 生成调用参数 → 执行 │
└──────────────────────────────────────────────────────────────────┘</pre>
<div class="box box-info"><h4>设计原则</h4><p><strong>确定性优先于概率性</strong>:L0 用规则做硬过滤(安全底线),L1/L2 用语义做软匹配(效果上限)。<br>
<strong>漏斗逐级收敛</strong>30万 → 2000 → 100 → 15,每级延迟可控,总体 < 300ms<br>
<strong>意图提取与检索解耦</strong>:意图提取产出结构化意图对象,检索模块消费该对象,两者可独立迭代。</p></div>
</section>
<hr>
<!-- ===== 3. 工具描述增强 ===== -->
<section><h2 id="工具描述增强llm离线语义增强">工具描述增强:LLM离线语义增强</h2>
<p>意图识别的前提是<strong>工具有好的语义描述</strong>。30万存量服务的原始 API 文档通常只有技术参数,缺乏业务语义。本方案在工具入库前进行离线 LLM 增强。</p>
<h3>增强前后对比</h3>
<div class="table-wrap"><table>
<tr><th>字段</th><th>原始(来自 OpenAPI</th><th>增强后(LLM 离线生成)</th></tr>
<tr><td><strong>name</strong></td><td><code>cbs_query_credit_report</code></td><td><code>cbs_query_credit_report</code>(保留原名)</td></tr>
<tr><td><strong>description</strong></td><td>"查询信用报告"</td><td>"查询个人或企业的信用报告,返回征信评分、贷款记录、逾期记录、担保记录等。适用于客户经理贷前审查、风控审批等场景。"</td></tr>
<tr><td><strong>target_audience</strong></td><td>—(无)</td><td>["客户经理", "风控审批员"]</td></tr>
<tr><td><strong>common_questions</strong></td><td>—(无)</td><td>["查张三的征信", "这个客户的信用怎么样", "看看他的征信评分", "有没有逾期记录"]</td></tr>
<tr><td><strong>caveats</strong></td><td>—(无)</td><td>"征信查询为敏感操作,需客户授权。仅返回持卡人授权范围内的数据。"</td></tr>
<tr><td><strong>tags</strong></td><td>—(无)</td><td>["征信", "信贷", "风控", "贷前审查"]</td></tr>
</table></div>
<h3>增强管道</h3>
<pre class="ascii-diagram">原始 API 元数据 (OpenAPI / gRPC Proto / API Gateway)
┌─────────────────────────────────────────────┐
│ Step 1: 元数据标准化 │
│ 统一为内部 ToolDefinition schema │
│ 提取: name, path, method, params, response │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ Step 2: LLM 批量增强 (qwen-turbo 离线) │
│ │
│ Prompt 模板: │
│ "你是一个银行系统专家。以下是API的技术定义: │
│ [原始元数据] │
│ 请补充: │
│ 1. 用3-5句话描述这个API的业务用途 │
│ 2. 列出可能使用此API的角色/客群 │
│ 3. 生成5-10条用户可能的自然语言问法 │
│ 4. 标注注意事项和风险提示 │
│ 5. 打上3-8个业务标签" │
│ │
│ 批次: 100条/批,qwen-turbo,离线异步 │
│ 成本: ~0.3元/千条 │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ Step 3: 向量化 + 入库 │
│ description → text-embedding-v3 → pgvector │
│ common_questions → 扩展为虚拟文档 → 索引 │
│ tags → Elasticsearch 倒排索引 │
└─────────────────────────────────────────────┘</pre>
<div class="box box-good"><h4>为什么是离线增强而非在线</h4><p>在线增强(每次请求时让 LLM 理解工具)会产生 2-5s 额外延迟且不可缓存。离线增强将 LLM 的语义理解能力<strong>提前注入索引</strong>,检索时直接匹配向量,延迟 < 80ms增强后语义检索命中率提升 30%+</p></div>
</section>
<hr>
<!-- ===== 4. L1 意图提取 ===== -->
<section><h2 id="l1-意图提取">L1:意图提取</h2>
<p>将用户的自然语言问法转化为<strong>结构化意图对象</strong>,作为后续混合检索的查询依据。</p>
<h3>意图 Schema</h3>
<pre class="ascii-diagram">// Intent 结构化输出
{
"intent": "征信查询", // 主意图分类
"domain": "credit", // 业务域
"sub_domain": "credit_report", // 子域
"entities": [ // 实体抽取
{ "type": "PERSON_NAME", "value": "张三" },
{ "type": "ID_TYPE", "value": "身份证" }
],
"intent_type": "QUERY", // QUERY | ACTION | ANALYSIS | APPROVAL
"confidence": 0.94, // 置信度
"multi_intent": false, // 是否多意图
"suggested_tool_categories": [ // 建议的工具类别(用于检索加权)
"征信查询", "客户信息", "风控评估"
]
}</pre>
<h3>实现方案选型</h3>
<div class="table-wrap"><table>
<tr><th>方案</th><th>延迟</th><th>准确率</th><th>成本</th><th>适用阶段</th></tr>
<tr><td><strong>Few-shot LLM(千问/DeepSeek</strong></td><td>200-500ms</td><td>~92%</td><td></td><td>Phase 1 快速启动,Prompt 迭代灵活</td></tr>
<tr><td><strong>微调小模型(Qwen2.5-7B 微调)</strong></td><td>30-80ms</td><td>~95%</td><td>一次投入</td><td>Phase 3+ 生产化,延迟和准确率最优</td></tr>
<tr><td><strong>规则 + 关键词(无 LLM</strong></td><td>&lt; 5ms</td><td>~70%</td><td>极低</td><td>兜底方案,简单高频问法</td></tr>
</table></div>
<h3>意图分类体系(银行业务域)</h3>
<div class="table-wrap"><table>
<tr><th>一级域</th><th>二级意图</th><th>典型问法示例</th><th>涉及工具数(约)</th></tr>
<tr><td><strong>credit(信贷)</strong></td><td>征信查询 / 额度查询 / 贷款申请 / 还款记录 / 利率查询</td><td>"查张三征信""我能贷多少""申请经营贷"</td><td>~8000</td></tr>
<tr><td><strong>risk(风控)</strong></td><td>风险评估 / 反欺诈 / 关联交易 / 黑名单校验</td><td>"评估这个客户风险等级""查关联方"</td><td>~5000</td></tr>
<tr><td><strong>customer(客户)</strong></td><td>客户信息 / 账户查询 / 交易流水 / 资产概览</td><td>"张三的基本信息""最近三个月的流水"</td><td>~12000</td></tr>
<tr><td><strong>product(产品)</strong></td><td>产品查询 / 利率对比 / 签约状态 / 持有产品</td><td>"这款理财收益多少""有哪些贷款产品"</td><td>~6000</td></tr>
<tr><td><strong>compliance(合规)</strong></td><td>反洗钱 / 大额可疑 / 监管报送 / 合规检查</td><td>"这笔转账是否触发反洗钱规则"</td><td>~3000</td></tr>
<tr><td><strong>operation(运营)</strong></td><td>柜面操作 / 账户管理 / 参数维护 / 日终处理</td><td>"开立对公账户流程""修改客户手机号"</td><td>~5000</td></tr>
<tr><td><strong>report(报表)</strong></td><td>经营报表 / 监管报表 / 绩效考核 / 数据统计</td><td>"本月信贷投放情况""生成季度报表"</td><td>~4000</td></tr>
</table></div>
<h3>多意图处理</h3>
<p>当用户一次性提出复合需求时,意图提取模块识别并拆解为多个子意图:</p>
<pre class="ascii-diagram">输入: "帮我查这个客户的征信,再评估一下他的还款能力"
意图提取:
┌─────────────────────────────────────────────┐
│ 主意图判定: multi_intent = true │
│ │
│ 子意图 1: │
│ intent: "征信查询" │
│ domain: "credit" │
│ entities: [{type: PERSON, value: "这个客户"}]│
│ │
│ 子意图 2: │
│ intent: "还款能力评估" │
│ domain: "risk" │
│ entities: [{type: PERSON, value: "这个客户"}]│
│ │
│ 执行顺序: 串行(子意图2依赖子意图1的结果) │
└─────────────────────────────────────────────┘</pre>
</section>
<hr>
<!-- ===== 5. L1 混合检索 ===== -->
<section><h2 id="l1-混合检索dense--sparse--rrf">L1:混合检索(Dense + Sparse → RRF</h2>
<p>单一检索方式在银行场景存在明显短板,本方案采用<strong>混合检索 + 倒数秩融合(RRF</strong> 策略。</p>
<h3>为什么需要混合</h3>
<div class="table-wrap"><table>
<tr><th>检索方式</th><th>原理</th><th>优势</th><th>劣势</th><th>银行场景典型失败 case</th></tr>
<tr><td><strong>Dense(向量语义)</strong></td><td>text-embedding-v3 → pgvector HNSW</td><td>理解同义改写和模糊表达</td><td>对专有缩写和精确 ID 匹配差</td><td>"调CBS查张三征信"——embedding 无法理解 CBS 是核心系统标识</td></tr>
<tr><td><strong>SparseBM25 关键词)</strong></td><td>Elasticsearch BM25 倒排索引</td><td>精确字段匹配、缩写、ID</td><td>无法理解同义表达和上下文</td><td>"看看他能借多少"——没有"贷款"关键词,BM25 可能漏掉</td></tr>
</table></div>
<h3>检索流程</h3>
<pre class="ascii-diagram">意图对象 + 原始用户消息 + 增强后的常见问法
├──────────────────┬──────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ 向量检索 │ │ BM25 关键词 │ │ Tag 精准匹配 │
│ (Dense) │ │ (Sparse) │ │ (Filter) │
│ │ │ │ │ │
│ pgvector │ │ ES BM25 │ │ ES term │
│ HNSW │ │ 在 L0 过滤后 │ │ 标签过滤 │
│ cosine │ │ 的候选池内 │ │ │
│ │ │ │ │ │
│ Top-200 │ │ Top-200 │ │ 全部命中标签 │
└────┬──────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└─────────────────┴──────────────────┘
┌─────────────────────────────────────────────────┐
│ RRF (Reciprocal Rank Fusion) 倒数秩融合 │
│ │
│ score(doc) = Σ 1/(k + rank_i(doc)) │
│ i∈{dense, sparse, tag} │
│ │
│ k=60 (标准平滑参数) │
│ 如果一个工具在三种检索中分别排第3、第8、未出现: │
│ score = 1/(60+3) + 1/(60+8) + 0 = 0.031 │
│ │
│ → 融合排序 → Top-100 │
└─────────────────────────────────────────────────┘</pre>
<h3>向量化策略</h3>
<div class="table-wrap"><table>
<tr><th>索引内容</th><th>向量模型</th><th>维度</th><th>说明</th></tr>
<tr><td><strong>增强后的 description</strong></td><td>text-embedding-v3</td><td>1024</td><td>主向量,承载核心业务语义</td></tr>
<tr><td><strong>common_questions 扩展</strong></td><td>text-embedding-v3</td><td>1024</td><td>每条常见问法作为独立虚拟文档,桥接自然语言与工具定义</td></tr>
<tr><td><strong>意图标签组合</strong></td><td>text-embedding-v3</td><td>256</td><td>"{domain}_{intent}" 组合编码,加速意图路由</td></tr>
</table></div>
<div class="box box-info"><h4>common_questions 虚拟文档扩展</h4><p>这是提升检索命中率的关键技巧。一个工具的 5-10 条常见问法各自作为独立向量文档入库,<code>parent_id</code> 指向原始工具。检索时匹配到任意一条问法都能召回该工具。这实质上是将"用户会怎么问"的信息提前编码进索引。</p></div>
</section>
<hr>
<!-- ===== 6. L2 精排 ===== -->
<section><h2 id="l2-精排cross-encoder-rerank">L2:精排(Cross-encoder Rerank</h2>
<p>L1 混合检索产出 Top-100,但排序精度有天花板——双塔模型在 0.01s 内判断 100 个候选的语义相关性,和花 0.15s 精细比较 100 对(用户问法, 工具描述)的语义匹配度,后者准确得多。</p>
<h3>Bi-encoder vs Cross-encoder</h3>
<div class="table-wrap"><table>
<tr><th>特性</th><th>Bi-encoderL1 Dense</th><th>Cross-encoderL2 精排)</th></tr>
<tr><td><strong>原理</strong></td><td>用户查询和工具描述分别编码为向量,计算余弦相似度</td><td>用户查询和工具描述拼接后一起输入 Transformer,输出相关性分数</td></tr>
<tr><td><strong>交互方式</strong></td><td>浅层交互(仅余弦相似度)</td><td>深层交互(Attention 跨查询-文档)</td></tr>
<tr><td><strong>速度</strong></td><td>快(向量已预计算,仅做内积)</td><td>慢(每对都需过一次完整前向传播)</td></tr>
<tr><td><strong>准确率</strong></td><td>中高</td><td>高(显著优于 Bi-encoder</td></tr>
<tr><td><strong>使用方式</strong></td><td>在海量候选池中快速召回</td><td>在少量候选(≤200)中精细排序</td></tr>
</table></div>
<h3>精排流程</h3>
<pre class="ascii-diagram">L1 产出 Top-100 工具
┌─────────────────────────────────────────────┐
│ 构建 Cross-encoder 输入对 (100 对) │
│ │
│ Pair i: │
│ Query: "查张三的征信" │
│ Doc: "[工具名] cbs_query_credit_report │
│ [描述] 查询个人或企业的信用报告... │
│ [常见问法] 查征信/信用评估/... │
│ [标签] 征信, 信贷, 风控" │
│ │
│ → 100 对并行推理 │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ Cross-encoder 模型 (BGE-Reranker-v2-m3) │
│ 对每对输出 relevance_score ∈ [0, 1] │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ Agent 上下文注入 │
│ │
│ ● 对话历史中已确认的实体加权 │
│ "之前提到客户是张三" → 含"张三"的工具加权 │
│ ● 当前任务类型偏好 │
│ 查询类 > 写操作类(安全偏好) │
│ ● 用户角色偏好 │
│ 客户经理常用工具加权 │
└──────────────────┬──────────────────────────┘
Top-15 工具定义
(~4500 tokens)
注入 Agent LLM 上下文</pre>
<h3>模型选型</h3>
<div class="table-wrap"><table>
<tr><th>模型</th><th>速度(100对)</th><th>NDCG@10</th><th>部署方式</th></tr>
<tr><td><strong>BGE-Reranker-v2-m3</strong></td><td>~120ms</td><td></td><td>本地 GPU (T4/L20)</td></tr>
<tr><td><strong>Cohere Rerank API</strong></td><td>~200ms (网络)</td><td></td><td>SaaS API(银行内网不可用)</td></tr>
<tr><td><strong>BGE-Reranker-v2-minicpm</strong></td><td>~60ms</td><td>中高</td><td>本地 CPU 可运行</td></tr>
</table></div>
<div class="box box-warn"><h4>银行内网约束</h4><p>银行生产环境无法访问外网 API,Reranker 必须本地部署。推荐 BGE-Reranker-v2-m3 部署在推理 GPU 节点,单卡可支撑 200+ QPS。</p></div>
</section>
<hr>
<!-- ===== 7. L3-L5 ===== -->
<section><h2 id="l3-l5-多层兜底与持续优化">L3-L5:多层兜底与持续优化</h2>
<h3>L3Agent 自行验证</h3>
<p>即使前两层给出了 Top-15 工具,LLM 也可能判断检索结果不匹配用户意图。此时 Agent 可主动调用 <code>search_tools()</code> 进行二次检索(调整查询词、放宽过滤条件)。</p>
<div class="figure-block">
<div class="fig-title">Agent 自验证逻辑(System Prompt 内置)</div>
<pre class="ascii-diagram">给定 {用户消息} 和 {Top-15 工具列表}
1. 逐一评估每个工具与用户意图的匹配度
2. 如果至少有一个工具匹配度 ≥ 0.8 → 选择最匹配的执行
3. 如果所有工具匹配度 < 0.5 调用 search_tools(rewrite_query)
- 改写策略: 扩展缩写补充同义词拆分多意图
4. 如果改写后仍无匹配 告知用户"未找到对应服务请提供更多信息"
目标: 首次无结果率 < 3%</pre>
</div>
<h3>L4:用户/租户个性化加权</h3>
<p>不同角色、不同租户的工具使用频率差异巨大。个性化加权让高频工具自动排前:</p>
<ul>
<li><strong>个人级别</strong>:当前用户最近30天高频调用的工具加权 1.5×</li>
<li><strong>角色级别</strong>:同角色(如"客户经理")群体的高频工具加权 1.3×</li>
<li><strong>租户级别</strong>:当前租户(如"北京分行")的高频工具加权 1.2×</li>
<li><strong>协同过滤</strong>:相似用户群体使用但当前用户未用过的工具轻度加权(发现新工具)</li>
</ul>
<p>权重在 RRF 融合后的分数上叠加,不参与 RRF 计算本身,确保不会因为个性化而掩盖语义相关性。</p>
<h3>L5:人工反馈闭环</h3>
<pre class="ascii-diagram">Agent 执行工具调用
Web Dashboard 展示 "工具调用卡片"
│ 显示: 调用了哪个工具、参数、结果摘要
├─ 用户点击 [✓ 工具正确] → 正反馈 → 该(query, tool)对进入正样本池
└─ 用户点击 [✗ 工具选错了] → 负反馈
┌─────────────────────────────────────────┐
│ 负反馈处理: │
│ 1. 弹出 "正确的工具应该是?" 搜索框 │
│ 2. 用户选择正确工具 │
│ 3. (query, wrong_tool) → 负样本 │
│ (query, correct_tool) → 正样本 │
│ 4. 回流到 Reranker 微调数据集 │
│ 5. 每月增量微调 Cross-encoder │
└─────────────────────────────────────────┘</pre>
</section>
<hr>
<!-- ===== 8. 场景走查 ===== -->
<section><h2 id="场景走查意图识别实战">场景走查:意图识别实战</h2>
<h3>场景 1:客户经理查客户征信(B2E</h3>
<pre class="ascii-diagram">┌─ 原始输入 ─────────────────────────────────────────────┐
│ 用户消息: "查张三的征信" │
│ 渠道: 信贷系统 (Channel=credit-system) │
│ 用户: EMPLOYEE | 客户经理 | 北京分行 | BRANCH │
└────────────────────────────────────────────────────────┘
L0 预过滤:
规则1: credit-system → 信贷/风控/查询类接口
规则2: EMPLOYEE → 内部员工工具集
规则3: 客户经理+对公 → 对公信贷类 + 通用查询
规则6: BRANCH → 本支行客户数据
→ 30万 → ~1200 候选
L1 意图提取:
输入: "查张三的征信"
输出: {
intent: "征信查询",
domain: "credit",
entities: [{type: PERSON_NAME, value: "张三"}],
intent_type: "QUERY",
confidence: 0.96
}
L1 混合检索 (在 1200 候选内):
Dense: 向量相似度 Top-200
Sparse: BM25 "征信"+"张三" Top-200
RRF 融合 → Top-100
延迟: 72ms
L2 精排:
Cross-encoder: 100 对 → 排序 → Top-15
上下文注入: 当前对话是新会话,无历史加权
延迟: 118ms
Agent 上下文 (注入 LLM):
System: "你是银行客户经理助手..."
Tools: Top-15 定义 (含 cbs_query_credit_report 排第1)
User: "查张三的征信"
Agent 输出:
→ 选择 cbs_query_credit_report(idNumber="...")
→ PermissionMiddleware ✓
→ 返回: "张三征信评分720分,共有3笔贷款记录..."</pre>
<h3>场景 2C端客户模糊问法(B2C</h3>
<pre class="ascii-diagram">┌─ 原始输入 ─────────────────────────────────────────────┐
│ 用户消息: "我能贷多少钱" │
│ 渠道: 手机银行 (Channel=mobile-bank) │
│ 用户: RETAIL_CUSTOMER | CUST-88231 | SELF │
└────────────────────────────────────────────────────────┘
L0 预过滤:
规则1: mobile-bank → 仅限电子渠道开放接口
规则2: RETAIL_CUSTOMER → 仅限C端客户工具
规则6: SELF → 仅限本人数据
→ 30万 → ~300 候选
L1 意图提取:
输入: "我能贷多少钱" (无"贷款"关键词!)
输出: {
intent: "贷款额度查询",
domain: "retail_loan",
entities: [{type: SELF_REFERENCE, value: "我"}],
intent_type: "QUERY",
confidence: 0.91
}
注: LLM 意图提取识别出"能贷多少" = "贷款额度查询"
即使没有"贷款"二字
L1 混合检索 (在 300 候选内):
Dense: "我能贷多少钱" 与工具描述的语义匹配
→ "retail_query_loan_limit" 的 common_questions 包含
"我能贷多少钱"/"可用额度是多少"/"贷款上限查询"
→ 余弦相似度 0.94,排第 1
Sparse: "贷" 匹配到"贷款"、"额度"
RRF 融合 → Top-50
延迟: 58ms
L2 精排:
Cross-encoder 确认 retail_query_loan_limit 排第 1
→ Top-10 → 注入 Agent
Agent 输出:
→ retail_query_loan_limit(customerId="CUST-88231")
→ "您目前的可用额度为30万元,其中信用贷20万、抵押贷10万..."
┌────────────────────────────────────────────────────────┐
│ ★ 关键: Dense 检索命中了 common_questions 虚拟文档。 │
│ 如果仅用 BM25"能贷多少" 没有"贷款"关键词可能漏排。 │
│ 如果仅用 Dense,可能召回"理财产品收益"等语义相近但 │
│ 实际无关的工具。混合检索 + 精排保证了鲁棒性。 │
└────────────────────────────────────────────────────────┘</pre>
<h3>场景 3:精确缩写查询(B2E</h3>
<pre class="ascii-diagram">用户: "调CBS查一下这个企业的ECIF信息"
├─ CBS = 核心银行系统 (Core Banking System)
├─ ECIF = 企业客户信息文件 (Enterprise Customer Information File)
└─ 这是银行内部的高度专业化缩写
L1 意图提取:
intent: "企业客户信息查询"
domain: "customer"
entities: [
{type: SYSTEM, value: "CBS"},
{type: CUSTOMER_TYPE, value: "企业"},
{type: DATA_TYPE, value: "ECIF"}
]
混合检索:
Dense: "ECIF" 的 embedding 可能与工具描述中的"企业客户信息文件"
有语义距离(缩写向量 vs 全称向量)
Sparse: BM25 精确命中 tool tags 中的 "ECIF"、"CBS"
→ 互补!Sparse 救了 Dense 的缩写盲区
→ RRF 融合后,目标工具排 Top-3
结论: 混合检索在银行缩写密集场景下不可或缺。</pre>
</section>
<hr>
<!-- ===== 9. 验证方式 ===== -->
<section><h2 id="准确率指标与验证方式">准确率指标与验证方式</h2>
<h3>核心指标</h3>
<div class="table-wrap"><table>
<tr><th>指标</th><th>目标值</th><th>测量方式</th></tr>
<tr><td><strong>Top-15 命中率</strong></td><td>&gt; 97%</td><td>人工标注 1000 条银行真实问法,检查正确答案是否在 Top-15 内</td></tr>
<tr><td><strong>Top-1 命中率</strong></td><td>&gt; 80%</td><td>相同标注集,检查第一位是否即正确答案</td></tr>
<tr><td><strong>首次无结果率</strong></td><td>&lt; 3%</td><td>统计生产环境中 Agent 触发 search_tools() 重试的比例</td></tr>
<tr><td><strong>MRR (Mean Reciprocal Rank)</strong></td><td>&gt; 0.85</td><td>标注集上正确答案排名的倒数的平均值</td></tr>
<tr><td><strong>端到端检索延迟 P99</strong></td><td>&lt; 300ms</td><td>Prometheus + Grafana 监控 L0+L1+L2 全链路延迟</td></tr>
</table></div>
<h3>验证方式</h3>
<ol>
<li><strong>离线标注集评估</strong>:构建 1000 条银行典型问法 + 正确答案标注,每次检索模型迭代时跑评估</li>
<li><strong>A/B 对比</strong>:工具描述增强前后检索命中率对比(预期提升 30%+);混合检索 vs 纯 Dense vs 纯 Sparse 对比</li>
<li><strong>生产监控</strong>:统计 L3 Agent 二次检索触发率(首次无结果率);统计 L5 人工"工具选错了"按钮点击率趋势</li>
<li><strong>抽样验证</strong>:每日随机抽取 100 次真实调用,人工检查工具选择是否正确</li>
<li><strong>压力测试</strong>:1000 并发检索请求,P99 延迟 < 300ms错误率 < 0.1%</li>
</ol>
</section>
<hr>
<!-- ===== 10. 风险 ===== -->
<section><h2 id="风险与缓解">风险与缓解</h2>
<div class="table-wrap"><table>
<tr><th>风险</th><th>概率</th><th>影响</th><th>缓解措施</th></tr>
<tr><td><strong>Router Agent 意图识别不准</strong></td><td></td><td></td><td>Phase 2 投入人工标注 1000+ 银行问法;微调替代 Few-shot;规则兜底保证高频 20 种意图 100% 准确</td></tr>
<tr><td><strong>工具描述增强质量差</strong></td><td></td><td></td><td>Prompt 迭代 + 人工抽检增强结果;核心系统工具人工审核描述;低质量描述标记"待完善"降低检索权重</td></tr>
<tr><td><strong>OpenAPI 覆盖率不足导致向量质量差</strong></td><td></td><td></td><td>三级降级(Swagger→gRPC→基础元数据);优先保障核心系统(前 20%)工具描述质量</td></tr>
<tr><td><strong>Dense 检索在缩写密集场景失效</strong></td><td></td><td></td><td>混合检索中 Sparse/BM25 互补;构建行内缩写词典索引增强</td></tr>
<tr><td><strong>Reranker 模型内网部署困难</strong></td><td></td><td></td><td>BGE-Reranker-v2-minicpm 可在 CPU 运行,作为 GPU 不可用时的降级方案</td></tr>
<tr><td><strong>C端问法多样性超出训练分布</strong></td><td></td><td></td><td>持续收集 C 端真实问法日志 → 每月扩充 common_questions;个性化加权提升高频用户命中率</td></tr>
</table></div>
<div class="footer">
<p>银行智能中台子方案 · 意图识别与工具检索 · 2026-06</p>
<p style="margin-top:4px;">基于 <a href="./agentscope-java-openclaw-banking-midplatform.html" style="color:var(--color-primary);">银行智能中台架构方案 v2.0</a> 提炼</p>
</div>
</main>
<script>
(function() {
var sidebarLinks = document.querySelectorAll('.sidebar nav a');
var sections = [];
sidebarLinks.forEach(function(a) {
var target = document.querySelector(a.getAttribute('href'));
if (target) sections.push({link: a, target: target});
});
function onScroll() {
var scrollPos = window.scrollY + 100, current = null;
sections.forEach(function(s) { if (s.target.offsetTop <= scrollPos) current = s; });
sidebarLinks.forEach(function(a) { a.classList.remove('active'); });
if (current) current.link.classList.add('active');
}
window.addEventListener('scroll', onScroll);
onScroll();
})();
</script>
</body>
</html>