Files
group_fqcd_jr/客服agent/D2.2-客服Agent需求文档.html
T
张胜宇 bc61d5c579 docs: 入库权威文档目录(客服agent/ 24 份 + 开发文档/ 50 份,替换旧命名的过期副本)
## 为什么做这一步

权威文档 74 份此前**只在本机**,评审者 clone 分支后看不到任何设计文档;而仓库里那两份同名目录
是 **2026-09-16 之前的过期副本,连文件名都是旧的**(无体系编号)。本次按「**权威覆盖过期**」入库。

## 入库内容

| 目录 | 文件数 | 体积 | 说明 |
|---|---|---|---|
| `客服agent/` | 24 | 0.77 MB | `D2.1`~`D2.6` 对外交付四件套 + 演示脚本/答辩报告 + `_build` 构建工具 |
| `开发文档/` | 50 | 2.16 MB | `D1.x` 索引与决策、`D3.x` 方案、`D4.x` 清除与重构留痕、`D5.x` 业务流程、`D6.x` 业务事实基座、`D7.x` 交付物、`D8.x` 规范 |

**旧的过期副本整体移除**(`客服Agent执行Todolist.md` → `D2.1-客服Agent执行Todolist.md` 之类
的改名 + 新增 `D2.5`/`D2.6`),入库后目录内容与权威副本**逐文件一致(零差异,已复核)**。

## 入库前的安全扫描(必须留痕)

- 扫描规则:`sk-` 类密钥 / `Bearer` 长串 / `password=`、`api_key=` 赋值 / 会话中出现过的两把明文 key 片段。
- 结论:**真实密钥只出现在 `.env`**(已被 `.gitignore` 命中,未入库);`.env.example` 与
  `config/risk.env.example` 只有**空占位**。
- 文档内唯一命中是 `D3.1` 里一处**截断的示例 JWT**(`Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`),
  末尾带省略号,是接口文档的示意值,**不是可用凭据**。
2026-09-20 15:03:15 +08:00

1086 lines
107 KiB
HTML
Raw 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>南方基金·智能服务系统 — 智能客服 Agent 需求文档</title>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Serif+SC:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
:root {
--navy-900: #0a1628;
--navy-800: #121e33;
--navy-700: #1a2a44;
--navy-600: #243552;
--navy-500: #2d4160;
--gold-500: #c9a84c;
--gold-400: #d4b966;
--gold-300: #e0cc85;
--gold-600: #a8873a;
--bg: #f4f1eb;
--bg-white: #ffffff;
--text: #1e293b;
--text-muted: #64748b;
--border: #e2ddd5;
--code-bg: #0d1117;
--sidebar-w: 288px;
--topbar-h: 56px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: 'Inter', -apple-system, sans-serif;
color: var(--text);
background: var(--bg);
line-height: 1.75;
font-size: 15px;
}
#progress-bar {
position: fixed; top: 0; left: 0; height: 3px; z-index: 9999;
background: linear-gradient(90deg, var(--gold-600), var(--gold-400), var(--gold-500));
width: 0%; transition: width 0.15s ease-out;
}
#sidebar {
position: fixed; top: 0; left: 0; width: var(--sidebar-w); height: 100vh;
background: linear-gradient(180deg, var(--navy-900), var(--navy-800));
z-index: 1000; display: flex; flex-direction: column;
border-right: 1px solid rgba(201,168,76,0.15);
}
.sidebar-header { padding: 22px 20px 14px; border-bottom: 1px solid rgba(201,168,76,0.12); }
.sidebar-brand {
display: flex; align-items: center; gap: 10px;
font-family: 'Noto Serif SC', serif; font-weight: 700;
font-size: 16px; color: var(--gold-400); letter-spacing: 0.5px;
}
.sidebar-brand .brand-icon {
width: 32px; height: 32px; border-radius: 8px;
background: linear-gradient(135deg, var(--gold-500), var(--gold-600));
display: flex; align-items: center; justify-content: center;
font-size: 16px; color: var(--navy-900); flex-shrink: 0;
}
.sidebar-subtitle {
font-size: 11px; color: rgba(255,255,255,0.4);
margin-top: 6px; letter-spacing: 1px;
}
#toc-search {
margin: 12px 16px; padding: 8px 12px;
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 6px; color: #fff;
font-size: 13px; font-family: 'Inter', sans-serif;
outline: none; transition: border-color 0.2s;
}
#toc-search::placeholder { color: rgba(255,255,255,0.3); }
#toc-search:focus { border-color: var(--gold-500); }
#toc-container {
flex: 1; overflow-y: auto; padding: 8px 0 32px;
scrollbar-width: thin; scrollbar-color: rgba(201,168,76,0.3) transparent;
}
#toc-container::-webkit-scrollbar { width: 4px; }
#toc-container::-webkit-scrollbar-thumb { background: rgba(201,168,76,0.3); border-radius: 2px; }
.toc-item {
display: block; padding: 5px 20px;
color: rgba(255,255,255,0.6); font-size: 12.5px;
text-decoration: none; border-left: 3px solid transparent;
transition: all 0.15s; line-height: 1.5;
}
.toc-item:hover { color: var(--gold-400); background: rgba(201,168,76,0.06); }
.toc-item.active { color: var(--gold-400); border-left-color: var(--gold-500); background: rgba(201,168,76,0.08); font-weight: 500; }
.toc-group { margin-bottom: 2px; }
.toc-toggle {
display: flex; align-items: flex-start; gap: 6px;
width: 100%; padding: 6px 16px;
color: rgba(255,255,255,0.85);
font-weight: 600; font-size: 13px;
font-family: inherit; background: none; border: none;
cursor: pointer; text-align: left; line-height: 1.45;
border-left: 3px solid transparent; transition: all 0.15s ease;
}
.toc-toggle:hover { color: var(--gold-400); background: rgba(201,168,76,0.06); }
.toc-toggle.active { color: var(--gold-400); border-left-color: var(--gold-500); background: rgba(201,168,76,0.1); }
.toc-toggle .arr { display: inline-block; width: 12px; flex-shrink: 0; font-size: 9px; color: rgba(255,255,255,0.25); transition: transform 0.2s ease; padding-top: 4px; }
.toc-toggle .arr.open { transform: rotate(90deg); }
.toc-kids { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }
.toc-kids.open { max-height: 2400px; }
.toc-kids .toc-item { padding-left: 34px; }
#topbar {
position: fixed; top: 0; left: var(--sidebar-w); right: 0;
height: var(--topbar-h); z-index: 999;
background: rgba(244,241,235,0.88); backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
padding: 0 32px;
}
#topbar-title { font-family: 'Noto Serif SC', serif; font-size: 14px; font-weight: 600; color: var(--navy-800); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#topbar-badge {
font-size: 11px; padding: 3px 10px;
background: linear-gradient(135deg, var(--gold-500), var(--gold-600));
color: var(--navy-900); border-radius: 12px; font-weight: 600;
letter-spacing: 0.5px; white-space: nowrap;
}
#main { margin-left: var(--sidebar-w); margin-top: var(--topbar-h); min-height: calc(100vh - var(--topbar-h)); }
.doc-container { max-width: 900px; margin: 0 auto; padding: 40px 40px 90px; }
.doc-header { margin-bottom: 44px; padding-bottom: 30px; border-bottom: 2px solid var(--gold-500); }
.doc-eyebrow { font-size: 12px; text-transform: uppercase; letter-spacing: 2px; color: var(--gold-600); font-weight: 600; margin-bottom: 12px; }
.doc-title { font-family: 'Noto Serif SC', serif; font-size: 31px; font-weight: 700; color: var(--navy-900); line-height: 1.35; margin-bottom: 20px; }
.doc-meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; }
.doc-meta-item { display: flex; flex-direction: column; padding: 12px 16px; background: var(--bg-white); border-radius: 8px; border: 1px solid var(--border); }
.doc-meta-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--text-muted); font-weight: 500; }
.doc-meta-value { font-size: 14px; font-weight: 500; color: var(--navy-800); margin-top: 2px; }
.doc-container h1 {
font-family: 'Noto Serif SC', serif; font-size: 25px; font-weight: 700;
color: var(--navy-900); margin: 50px 0 16px; padding-top: 18px;
border-top: 1px solid var(--border);
}
.doc-container h1:first-of-type { border-top: none; margin-top: 0; padding-top: 0; }
.doc-container h2 { font-family: 'Noto Serif SC', serif; font-size: 20px; font-weight: 600; color: var(--navy-800); margin: 38px 0 12px; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.doc-container h3 { font-family: 'Noto Serif SC', serif; font-size: 16.5px; font-weight: 600; color: var(--navy-700); margin: 26px 0 10px; }
.doc-container h4 { font-family: 'Noto Serif SC', serif; font-size: 15px; font-weight: 600; color: var(--navy-600); margin: 20px 0 8px; }
.mermaid { background: var(--bg-white); border: 1px solid var(--border); border-radius: 8px; padding: 20px; margin: 20px 0 26px; text-align: center; overflow-x: auto; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
table { width: 100%; border-collapse: collapse; margin: 16px 0 24px; font-size: 13.5px; background: var(--bg-white); border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.04); border: 1px solid var(--border); }
thead th { background: var(--navy-800); color: var(--gold-400); font-weight: 600; font-size: 12.5px; padding: 11px 14px; text-align: left; letter-spacing: 0.3px; }
tbody td { padding: 9px 14px; border-top: 1px solid var(--border); vertical-align: top; }
tbody tr:hover { background: rgba(201,168,76,0.045); }
pre { background: var(--code-bg); color: #e6edf3; padding: 18px; border-radius: 8px; overflow-x: auto; margin: 16px 0 24px; font-family: 'JetBrains Mono', monospace; font-size: 12.5px; line-height: 1.62; }
.code-block { margin: 16px 0 24px; border-radius: 8px; overflow: hidden; border: 1px solid rgba(201,168,76,0.12); background: var(--code-bg); }
.code-header { padding: 6px 14px; background: rgba(201,168,76,0.06); border-bottom: 1px solid rgba(201,168,76,0.1); }
.code-lang { font-size: 11px; font-weight: 600; color: var(--gold-400); font-family: 'JetBrains Mono', monospace; text-transform: uppercase; letter-spacing: 1px; }
.code-block pre { margin: 0; border-radius: 0; border: none; padding: 16px 18px; }
:not(pre) > code { font-family: 'JetBrains Mono', monospace; background: rgba(26,42,68,0.08); color: var(--navy-700); padding: 2px 6px; border-radius: 4px; font-size: 0.87em; }
blockquote {
background: linear-gradient(135deg, rgba(201,168,76,0.12), rgba(36,53,82,0.06));
border-left: 4px solid var(--gold-500);
color: var(--navy-800);
padding: 14px 20px; border-radius: 0 8px 8px 0; margin: 16px 0 24px; font-size: 14px;
}
blockquote.callout-warn { border-left-color: #c62828; background: linear-gradient(135deg, rgba(198,40,40,0.08), rgba(198,40,40,0.02)); }
blockquote.callout-info { border-left-color: #0288d1; background: linear-gradient(135deg, rgba(2,136,209,0.08), rgba(2,136,209,0.02)); }
blockquote.callout-design { border-left-color: #6a1b9a; background: linear-gradient(135deg, rgba(106,27,154,0.08), rgba(106,27,154,0.02)); }
blockquote p { margin: 0; }
blockquote p + p { margin-top: 8px; }
.doc-container ul, .doc-container ol { padding-left: 24px; margin: 12px 0; }
.doc-container li { margin: 6px 0; line-height: 1.7; }
.doc-container ul { list-style: none; padding-left: 0; }
.doc-container ul li { padding-left: 20px; position: relative; }
.doc-container ul li::before { content: ''; position: absolute; left: 0; top: 10px; width: 6px; height: 6px; border-radius: 50%; background: var(--gold-500); }
.doc-container ol li::marker { color: var(--gold-600); font-weight: 600; }
.intent-tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-family: 'JetBrains Mono', monospace; font-weight: 500; }
.intent-tag.high { background: #ffebee; color: #c62828; }
.intent-tag.mid { background: #fff3e0; color: #e65100; }
.intent-tag.low { background: #e8f5e9; color: #2e7d32; }
.pill { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: 11px; font-weight: 600; letter-spacing: .3px; }
.pill.p0 { background: #ffebee; color: #c62828; }
.pill.p1 { background: #fff3e0; color: #e65100; }
.pill.p2 { background: #e8f5e9; color: #2e7d32; }
hr { border: none; height: 1px; background: linear-gradient(90deg, transparent, var(--gold-500), transparent); margin: 34px 0; }
.doc-container p { margin: 10px 0; line-height: 1.82; color: #1f2937; }
.doc-container strong { font-weight: 600; color: var(--navy-900); }
.doc-container a { color: var(--gold-600); text-decoration: none; border-bottom: 1px solid var(--gold-300); }
.req-card { background: var(--bg-white); border-radius: 12px; border: 1px solid var(--border); padding: 22px 26px; margin: 18px 0 24px; position: relative; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
.req-card::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; border-radius: 12px 0 0 12px; background: linear-gradient(180deg, #4fc3f7, #0288d1); }
.tag-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
@media print {
#sidebar, #topbar, #progress-bar { display: none !important; }
#main { margin-left: 0; margin-top: 0; }
.doc-container { padding: 20px; max-width: 100%; }
.req-card { break-inside: avoid; box-shadow: none; }
table { break-inside: avoid; }
}
@media (max-width: 1024px) {
#sidebar { display: none; }
#topbar { left: 0; }
#main { margin-left: 0; }
.doc-container { padding: 24px 20px 60px; }
.doc-title { font-size: 23px; }
}
.doc-container h1[id], .doc-container h2[id], .doc-container h3[id], .doc-container h4[id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
</style>
</head>
<body>
<div id="progress-bar"></div>
<nav id="sidebar">
<div class="sidebar-header">
<div class="sidebar-brand">
<div class="brand-icon">🎧</div>
<span>南方基金</span>
</div>
<div class="sidebar-subtitle">客服 Agent 需求文档 v2.4 · 双主体</div>
</div>
<input type="text" id="toc-search" placeholder="搜索目录...">
<div id="toc-container">
<div class="toc-group">
<button class="toc-toggle active" data-group="1"><span class="arr open">▶</span><span>0. 文档定位与阅读指引</span></button>
<div class="toc-kids open">
<a class="toc-item" href="#0.1-文档目的与范围">0.1 文档目的与范围</a>
<a class="toc-item" href="#0.2-上游依据与冲突裁决">0.2 上游依据与冲突裁决</a>
<a class="toc-item" href="#0.3-术语与用词对照">0.3 术语与用词对照</a>
<a class="toc-item" href="#0.4-文档修订记录">0.4 文档修订记录</a>
</div></div>
<div class="toc-group">
<button class="toc-toggle" data-group="2"><span class="arr">▶</span><span>1. 需求分析</span></button>
<div class="toc-kids">
<a class="toc-item" href="#1.1-业务背景与痛点">1.1 业务背景与痛点</a>
<a class="toc-item" href="#1.2-服务对象与主体模型">1.2 服务对象与主体模型</a>
<a class="toc-item" href="#1.3-典型场景与用户故事">1.3 典型场景与用户故事</a>
<a class="toc-item" href="#1.4-功能需求清单">1.4 功能需求清单(48 条)</a>
<a class="toc-item" href="#1.5-非功能需求">1.5 非功能需求(21 条)</a>
<a class="toc-item" href="#1.6-合规约束专章">1.6 合规约束专章</a>
<a class="toc-item" href="#1.7-范围边界">1.7 范围边界</a>
<a class="toc-item" href="#1.8-身份与鉴权模型">1.8 身份与鉴权模型</a>
<a class="toc-item" href="#1.9-业务基线对齐">1.9 业务基线对齐(两条线)</a>
<a class="toc-item" href="#1.10-业务红线与-MVP-必守项">1.10 业务红线与 MVP 必守项</a>
</div></div>
<div class="toc-group">
<button class="toc-toggle" data-group="3"><span class="arr">▶</span><span>2. 验收与测试</span></button>
<div class="toc-kids">
<a class="toc-item" href="#2.1-测试策略与矩阵">2.1 测试策略与矩阵</a>
<a class="toc-item" href="#2.2-验收标准">2.2 验收标准</a>
<a class="toc-item" href="#2.3-访客与身份专项用例">2.3 访客与身份专项用例</a>
<a class="toc-item" href="#2.4-端到端演示脚本">2.4 端到端演示脚本</a>
</div></div>
<div class="toc-group">
<button class="toc-toggle" data-group="4"><span class="arr">▶</span><span>3. 风险与对策</span></button>
<div class="toc-kids">
<a class="toc-item" href="#3.1-风险登记表">3.1 风险登记表</a>
<a class="toc-item" href="#3.2-评分口径对齐">3.2 评分口径对齐</a>
</div></div>
<div class="toc-group">
<button class="toc-toggle" data-group="5"><span class="arr">▶</span><span>4. 待确认与改进</span></button>
<div class="toc-kids">
<a class="toc-item" href="#4.1-待确认事项清单">4.1 待确认事项清单</a>
<a class="toc-item" href="#4.2-已识别的问题及处理状态">4.2 已识别的问题及处理状态</a>
<a class="toc-item" href="#4.3-改进建议">4.3 改进建议</a>
</div></div>
<div class="toc-group">
<button class="toc-toggle" data-group="6"><span class="arr">▶</span><span>附录</span></button>
<div class="toc-kids">
<a class="toc-item" href="#附录-双主体差异对照表">附录 双主体差异对照表</a>
</div></div>
</div>
</nav>
<header id="topbar">
<div id="topbar-title">智能服务系统 — 智能客服 Agent 需求文档</div>
<span id="topbar-badge">v2.4 · 双主体 · 投顾已清除</span>
</header>
<main id="main">
<div class="doc-container">
<div class="doc-header">
<div class="doc-eyebrow">专项需求文档 · 四份交付文档之一</div>
<h1 class="doc-title">南方基金·智能服务系统<br>智能客服 Agent 需求文档</h1>
<div class="doc-meta">
<div class="doc-meta-item">
<span class="doc-meta-label">体系编号</span>
<span class="doc-meta-value">D2.2 · 域:二、对外交付 · 编号体系见 开发文档/D1.1-文档索引与权威声明.md §4.0</span>
</div>
<div class="doc-meta-item">
<span class="doc-meta-label">文档版本</span>
<span class="doc-meta-value">v2.5(双主体 · 身份与角色分离 · 投顾已清除 · 五出口智能增强对接)</span>
</div>
<div class="doc-meta-item">
<span class="doc-meta-label">文档定位</span>
<span class="doc-meta-value">四份交付文档之一 · 需求分册</span>
</div>
<div class="doc-meta-item">
<span class="doc-meta-label">服务对象</span>
<span class="doc-meta-value">访客(未登录)+ 已登录客户</span>
</div>
<div class="doc-meta-item">
<span class="doc-meta-label">需求规模</span>
<span class="doc-meta-value">功能需求 <strong>52 条</strong> / 非功能需求 21 条</span>
</div>
<div class="doc-meta-item">
<span class="doc-meta-label">上游依据</span>
<span class="doc-meta-value">需求文档 v4.53 / 功能设计 v1.5 / MVP 定稿 / 访客鉴权方案 CS-AUTH-2026-011</span>
</div>
<div class="doc-meta-item">
<span class="doc-meta-label">文档密级</span>
<span class="doc-meta-value">内部公开</span>
</div>
</div>
</div>
<!-- ==================== 0 ==================== -->
<h1 id="0.-文档定位与阅读指引">0. 文档定位与阅读指引</h1>
<h2 id="0.1-文档目的与范围">0.1 文档目的与范围</h2>
<p>本文档是《南方基金·智能服务系统》<strong>智能客服 Agent</strong> 的<strong>需求文档</strong>,回答「<strong>要做什么、为谁做、边界在哪、做到什么程度算通过</strong>」。<strong>不含</strong>实施排期(见《客服 Agent 开发计划》)、逐项任务清单(见《客服 Agent 执行 Todolist》)与知识库专项设计(见《客服 Agent 知识库设计方案》)。</p>
<table>
<thead><tr><th>覆盖</th><th>不覆盖(归属)</th></tr></thead>
<tbody>
<tr><td>业务背景、服务对象与主体模型、典型场景</td><td>实施排期、里程碑、批次划分 → 《开发计划》</td></tr>
<tr><td>功能需求 48 条(FR-CS-001~048)、非功能需求 21 条(NFR-CS-001~021)</td><td>逐项任务与验收动作 → 《执行 Todolist》</td></tr>
<tr><td>合规约束与三条红线、范围边界</td><td>集合划分、分块、检索参数、档位标注规则 → 《知识库设计方案》</td></tr>
<tr><td>身份与鉴权模型(三条不变量)、验收标准、风险、待确认事项</td><td>接口字段级契约 → 《底座接口文档》(<code>docs/05</code>)</td></tr>
</tbody>
</table>
<blockquote class="callout-info"><p><strong>📌 四份交付文档的配套关系</strong><br>① <strong><code>D2.2-客服Agent需求文档.html</code></strong>(本文档)——「要做什么 / 边界在哪 / 验收标准」;<br>② <strong><code>D2.3-客服Agent开发计划.html</code></strong>——「分几步 / 什么顺序 / 谁做 / 何时算完」;<br>③ <strong><code>D2.1-客服Agent执行Todolist.md</code></strong>——逐项任务与验收动作(<strong>开工只看那一份</strong>);<br>④ <strong><code>D2.4-客服Agent知识库设计方案.html</code></strong>——知识库专项设计。<br>需求规模:<strong>功能需求 48 条(FR-CS-001~048)+ 非功能需求 21 条(NFR-CS-001~021)</strong>;执行侧落到 <strong>51 项 / 7 个批次 / 12 步关键路径</strong>;交付必须可举证 <strong>三条业务红线</strong>(风险等级唯一来源 / 先揭示后确认 / 不生成交易指令)。</p></blockquote>
<h2 id="0.2-上游依据与冲突裁决">0.2 上游依据与冲突裁决</h2>
<table>
<thead><tr><th>上游文档</th><th>本文档承接</th></tr></thead>
<tbody>
<tr><td><code>D7.1-需求文档.html</code> v4.53</td><td>§4 Phase 1 的 F1.1 目录规范 / <strong>F1.2 RAG 知识库</strong> / <strong>F1.3 客服 Agent</strong>;§7.3 标准组件清单</td></tr>
<tr><td><code>D7.2-功能设计文档.html</code> v1.5</td><td>§2.2 意图分类、§2.3 生成约束、§8.1 <code>rag_search</code> 工具契约、§8.2 工具调用协议</td></tr>
<tr><td><code>D7.3-记忆架构设计.html</code> v2.3</td><td>§6.2 记忆单元与身份标识(<code>customer_id</code> 为必填 → <strong>据此排除「虚拟访客账号」方案</strong>)</td></tr>
<tr><td><strong><code>D5.1-业务流程-MVP版-最终交付-2026-09-15.md</code></strong></td><td>业务范围(两条业务线)、三条红线、「演示跑通」为唯一验收方式</td></tr>
<tr><td><strong><code>客服与投顾模块重构前代码清理建议-2026-09-15.md</code></strong></td><td>既有实现真实结构与死代码清单;<strong>投顾与客服零耦合</strong>这一事实</td></tr>
<tr><td><strong><code>D3.3-访客与角色分离的鉴权方案建议-2026-09-16.md</code></strong>(CS-AUTH-2026-011)</td><td>§1.8 身份与鉴权模型的四条方案与推荐时序</td></tr>
<tr><td><code>docs/33</code> / <code>docs/34</code>(架构师对访客扩展的正式答复)</td><td>§1.8.1 三条不变量(单点鉴权 / 兜底位置 / 最小权限与档位标注)</td></tr>
<tr><td><code>docs/14</code> 统一接入说明书、<code>AGENTS.md</code> 项目级约束</td><td>§1.8.4 底座接触面纪律;分层判据</td></tr>
</tbody>
</table>
<blockquote class="callout-info"><p><strong>📌 冲突裁决优先级</strong>:与《业务流程 MVP 定稿》冲突 → <strong>以 MVP 定稿为准</strong>;与监管文件冲突 → <strong>以监管文件为准</strong>;与本项目 <code>docs/**</code> 底座规范冲突 → <strong>以底座规范为准</strong>;其余冲突 → 以本文档为准。</p></blockquote>
<h2 id="0.3-术语与用词对照">0.3 术语与用词对照</h2>
<table>
<thead><tr><th>术语</th><th>含义</th></tr></thead>
<tbody>
<tr><td><strong>访客</strong>(= 游客)</td><td><strong>同一角色的两种叫法</strong>:业务口径称「游客」,技术口径称「访客」。目标模型下对应 <code>subject_type = guest</code>。<strong>本文档统一用「访客」</strong></td></tr>
<tr><td><code>subject_type</code></td><td>会话<strong>主体类型</strong>,由服务端从凭证推导,客户端不可声明。取值 <code>guest</code> / <code>customer</code>(目标模型另含 <code>staff</code>)。<strong>权限与可见性判定的唯一依据</strong></td></tr>
<tr><td><code>visibility</code> / <strong>档位</strong></td><td>知识条目的可见档位:<code>public</code>(访客 + 客户)/ <code>registered</code>(仅客户)/ <code>internal</code>(<strong>不入库</strong>)</td></tr>
<tr><td><code>roles</code></td><td>RBAC <strong>角色</strong>轴,取值来自 <code>sys_role</code>(<code>customer</code> / <code>risk_operator</code> / <code>admin</code> / <code>advisor</code> 等)。<strong>目标模型下不含 <code>visitor</code></strong></td></tr>
<tr><td><code>data_scope</code></td><td>数据范围,RBAC 词表为 <code>{self, own_customers, all}</code>;访客取 <code>"public"</code> 属<strong>语义标注</strong>(已获架构师追认)</td></tr>
<tr><td>fail-closed</td><td>默认拒绝 / 最小权限:参数缺失或取值非法时收敛到最小权限,而非放行</td></tr>
<tr><td>over-fetch</td><td>先取 <code>top_k × N</code> 条候选、过滤后再截断为 <code>top_k</code>——避免过滤后 TopK 不足被误判为「知识库无答案」。<strong>🔴 v2.5 已取消</strong>——改由集合内分区裁剪结构性保证(见 <code>FR-CS-033</code>)</td></tr>
<tr><td>三条红线</td><td>① C1—C5 风险等级唯一来源=问卷测评;② 先风险揭示、后客户确认;③ 不生成交易指令、交易跳转</td></tr>
<tr><td>演示跑通</td><td>MVP 的<strong>唯一验收方式</strong>——能演出来即通过,不依赖自动化门禁</td></tr>
</tbody>
</table>
<h2 id="0.4-文档修订记录">0.4 文档修订记录</h2>
<table>
<thead><tr><th>版本</th><th>日期</th><th>变更摘要</th></tr></thead>
<tbody>
<tr><td>v1.0</td><td>2026-09-16</td><td>首次发布:需求清单、架构、详细设计、接口、数据、测试、计划、风险</td></tr>
<tr><td>v2.0</td><td>2026-09-16</td><td>新增「访客(未登录)」主体,形成双主体设计(FR-CS-029~042;§1.8 角色与主体模型)</td></tr>
<tr><td>v2.1</td><td>2026-09-16</td><td>决策落文:两段式回滚 + 72 小时稳定窗口;品牌配置化;投诉时限分层披露</td></tr>
<tr><td>v2.2</td><td>2026-09-16</td><td>基线对齐:新增 §1.9 业务基线、§1.10 红线与 MVP 必守项、§1.11 重构基线;修正 §8.1 目录落位</td></tr>
<tr><td>v2.3</td><td>2026-09-17</td><td>身份与鉴权分离:新增 §1.12 + FR-CS-043~048 + NFR-CS-019~021</td></tr>
<tr><td><strong>v2.4</strong></td><td><strong>2026-09-17</strong></td><td><strong>本文档为四份交付文档的「需求」分册,做过一次全局收敛</strong>:① <strong>投顾模块已整体清除</strong>(后端 21 文件 / 前端 <code>employee-advisor/</code> / <code>/api/v1/advisor</code> 全部端点 / 相关权限码),据此把业务基线由三条线收窄为<strong>两条线</strong>,并清理 T-12 / T-13 / T-15、I-02 / I-03 / I-07、RK-10 等投顾相关条目;② 把身份与鉴权模型由原 §1.12 提升为 <strong>§1.8</strong>(与主体模型合并);③ <strong>FR-CS-041 修正</strong>——原前提表 <code>conversation_archive</code> 经核实<strong>在库中不存在</strong>,原 §5.5.2 / §5.5.3 的整套容器变更流程<strong>作废</strong>;④ FR / NFR 按编号升序重排(原插入顺序)</td></tr>
<tr><td><strong>v2.4.1</strong></td><td><strong>2026-09-17</strong></td><td><strong>品牌全量口径统一</strong>:主体由包装占位(<code>XX科技</code> / <code>400-XXX-XXXX</code>)与旧名(<code>南方财富</code> / <code>nanfangwm.com</code>)统一为<strong>南方基金</strong>(南方基金管理股份有限公司 · 热线 <code>400-889-8899</code> · 官网 <code>nffund.com</code>);系统名由「智能财富管家系统」改为「<strong>智能服务系统</strong>」。</td></tr>
<tr><td><strong>v2.5</strong></td><td><strong>2026-09-17</strong></td><td><strong>对接「五出口」智能增强架构</strong>(依据 <code>D3.6</code>,其 §9 八项决策已裁定):① <strong><code>FR-CS-003</code> 重写</strong>——澄清由「置信度 &lt; 0.6 短路」扩为<strong>出口 <code>E1</code></strong>(四类触发条件、一次只问一个问题、同话题上限 2 轮、候选限当前档位可见);② <strong><code>FR-CS-008</code> 重写</strong>——改为<strong>分级回退 <code>E5</code></strong>(跨集合回退 → <strong>部分作答 + 引导</strong> → 转人工),并补硬约束<strong>回退不得跨档位</strong>;③ <strong><code>FR-CS-023</code> 重写</strong>——转人工收敛为<strong>触发白名单 4 类</strong>,<strong>删除「连续 2 轮兜底」</strong>(兜底是能力不足的表征,不是风险);④ <strong>新增 §1.4.8 域 H</strong>(<code>FR-CS-049</code>—<code>052</code>:证据约束生成 / 计算型回答 / 输出数字一致性校验 / 评测门禁),功能需求 <strong>48 → 52 条</strong>、功能域 <strong>7 → 8</strong>;⑤ <strong>§1.6.3 修正</strong>——<code>public</code> 档<strong>删除「产品参数与费率」</strong>(与 <code>D6.1.2</code> §四 判据、T-07 定案及《知识库设计方案》v1.3 §4.2 对齐);⑥ 新增验收项 <strong><code>AC-13</code></strong>(金标集门禁);⑦ <strong>档位隔离口径改为集合内分区裁剪</strong>——<code>FR-CS-032</code> / <code>FR-CS-033</code> 重写,取消 <code>over-fetch ×3</code>(与《知识库设计方案》v1.3 §7.2.1 对齐)。</td></tr>
</tbody>
</table>
<hr>
<!-- ==================== 1 ==================== -->
<h1 id="1.-需求分析">1. 需求分析</h1>
<h2 id="1.1-业务背景与痛点">1.1 业务背景与痛点</h2>
<p>客服 Agent 直接对应《需求文档》§1.1 五大痛点中的<strong>第一条「客户服务」</strong>:当前零售与高净值客户的咨询依赖人工逐一解答,等待时间长、服务标准不统一;目标是「AI 7×24 小时响应,话术统一」。</p>
<table>
<thead><tr><th>现状指标</th><th>公司既有口径</th><th>客服 Agent 的改善目标</th></tr></thead>
<tbody>
<tr><td>客服工时</td><td>人工 7:00—22:00(7×12),热线 <code>400-889-8899</code></td><td>升级为 7×24 在线应答,人工只承接复杂/高价值会话</td></tr>
<tr><td>常见咨询覆盖率</td><td>战略目标「智能客服可处理 <strong>85%</strong> 以上常见咨询」</td><td>FAQ 与产品咨询类命中率 + 一次解决率 <strong>≥ 85%</strong></td></tr>
<tr><td>VIP 响应时效</td><td>钻石/私行客户 15 分钟内响应、投诉 4 小时内响应</td><td>Agent 秒级响应;复杂事项按客群分层路由到对应服务等级</td></tr>
</tbody>
</table>
<h2 id="1.2-服务对象与主体模型">1.2 服务对象与主体模型</h2>
<h3>1.2.1 三类主体</h3>
<table>
<thead><tr><th>主体</th><th>是否登录</th><th>能看什么</th><th>不能做什么</th></tr></thead>
<tbody>
<tr><td><strong>访客</strong>(<code>guest</code>)</td><td>否(持有 15 分钟匿名令牌)</td><td>公司公开信息、金融行业基础信息、监管政策原文、<strong>公开</strong>匹配规则(C1—C5 / R1—R5)、产品与业务的概念解释与交易时限规则。<strong>产品参数类内容(费率 / 起投金额 / 收益率区间 / 产品规模 / 门槛金额 / 合作家数)不可见</strong>——2026-09-17 定案,该类条目档位为 <code>registered</code></td><td>❌ 查持仓/交易/账户/工单进度 ❌ 给投资建议 ❌ 给个性化适当性结论</td></tr>
<tr><td><strong>客户</strong>(<code>customer</code>)</td><td>是</td><td>访客全部 + 本人持仓/交易/账户/自己的画像与风评 + 分层权益类内容</td><td>❌ 查他人数据 ❌ 代客交易 ❌ 修改资料/销户</td></tr>
<tr><td><strong>员工</strong>(<code>staff</code>,<span class="pill p2">二期</span>)</td><td>是</td><td>工单队列、画像治理、知识库管理面</td><td>❌ 越过 RBAC 权限码</td></tr>
</tbody>
</table>
<h3>1.2.2 客群分层(仅用于话术与转人工优先级)</h3>
<table>
<thead><tr><th>层级</th><th>口径</th><th>本 Agent 的处理</th></tr></thead>
<tbody>
<tr><td>普通客户 / 零售</td><td>默认</td><td>标准话术;工单 priority 普通</td></tr>
<tr><td>高净值(钻石 / 私行)</td><td><code>sys_user.customer_level</code></td><td>话术更克制;<strong>工单 priority 升级为紧急</strong>;投诉类一律紧急</td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ 分层不等于卡级体系</strong>:MVP 明确「卡级体系不在范围」。<strong>分层只影响话术与转人工优先级,不得实现分层分派、升降级或权益自动判定。</strong></p></blockquote>
<h2 id="1.3-典型场景与用户故事">1.3 典型场景与用户故事</h2>
<table>
<thead><tr><th>编号</th><th>场景</th><th>主体</th><th>关键要求</th></tr></thead>
<tbody>
<tr><td>US-CS-01</td><td>问「XX 稳健增利债券 A 的起投金额是多少」</td><td>客户</td><td>命中产品集合,不编造<strong>(⏸ 本期不展示来源引用:<code>C-10</code> 乙)</strong></td></tr>
<tr><td>US-CS-02</td><td>问「理财产品销售管理办法对承诺收益怎么规定」</td><td>客户</td><td>命中政策集合,引用条款号</td></tr>
<tr><td>US-CS-03</td><td>连续多轮:「XX 基金风险高吗」→「它费率多少」(<strong>指代</strong>)</td><td>客户</td><td>指代消解后检索;上下文 ≥ 3 轮不丢</td></tr>
<tr><td>US-CS-04</td><td>问「我买的基金为什么跌了」</td><td>访客</td><td><code>auth_required</code> → 登录引导,<strong>不落兜底话术</strong></td></tr>
<tr><td>US-CS-05</td><td>问「钻石客户有哪些专属权益」</td><td>访客</td><td><strong>返回空 + 兜底</strong>,不暴露 <code>registered</code> 内容</td></tr>
<tr><td>US-CS-06</td><td>问「我该买哪个产品」</td><td>访客</td><td>拒绝推介;可讲公开匹配规则;引导开户</td></tr>
<tr><td>US-CS-07</td><td>说「转人工,我要投诉」</td><td>两者</td><td>返回转接话术 + 建工单;访客走「售前咨询」通道</td></tr>
<tr><td>US-CS-08</td><td>连续 2 轮答不上来</td><td>两者</td><td><strong>不转人工</strong>(<code>v2.5</code> 已删除 <code>low_score_repeat</code> 触发):同一话题第 2 轮起改走 <code>E5b</code> 部分答 + 引导;转人工仅限 <code>FR-CS-023</code> 白名单 4 类,<strong>白名单外转人工判验收不合格</strong></td></tr>
</tbody>
</table>
<h2 id="1.4-功能需求清单">1.4 功能需求清单(<strong>52 条</strong> · <strong>8</strong> 个功能域)</h2>
<p>优先级:<span class="pill p0">P0</span> 必须实现否则不通过验收;<span class="pill p1">P1</span> 应实现;<span class="pill p2">P2</span> 可选加分。<strong>全部条目按编号升序排列。</strong></p>
<h3>1.4.1 域 A · 对话接入与意图识别</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-001</code></td><td>客服对话接口:<code>POST /api/v1/agent-runs</code>(<code>agent_type=customer_service</code>)或 <code>/api/chat/customer</code>(以底座实际路由为准);后端须以鉴权上下文中的 <code>user_id</code> 为准,<strong>与请求体比对,防越权</strong>。</td><td><span class="pill p0">P0</span></td><td>需求文档 F1.3</td></tr>
<tr><td><code>FR-CS-002</code></td><td>5 类业务意图分类:<code>product_inquiry</code> / <code>policy_explain</code> / <code>faq</code> / <code>chitchat</code> / <code>transfer_human</code>,输出结构化 <code>{intent, confidence, reason}</code>。</td><td><span class="pill p0">P0</span></td><td>功能设计 §2.2</td></tr>
<tr><td><code>FR-CS-003</code></td><td><strong>澄清(出口 <code>E1</code>,v2.5 重写)</strong>:满足任一条件即触发澄清——① 意图置信度低于 <strong>0.6</strong>;② 检索结果<strong>跨族并列</strong>(<strong>同族并列不澄清</strong>,走 <code>FR-CS-049</code> 合并作答);③ 分数不足且候选落在<strong>多个不同族</strong>;④ 查询<strong>缺主语</strong>(指代未消解)。<strong>一次只问一个问题</strong>,给出 <strong>2—3 个候选</strong>供选择;<strong>同一话题澄清上限 2 轮</strong>,超限降级到 <code>FR-CS-008</code> 的分级回退。<strong>候选必须来自当前主体可见档位</strong>,不得以任何方式暗示不可见条目的存在性。</td><td><span class="pill p0">P0</span></td><td>功能设计 §2.2 / <code>D3.6</code> §3.1</td></tr>
<tr><td><code>FR-CS-004</code></td><td>规则前置:命中明确关键词(「转人工」「找客服」「投诉」「验证码」等)时<strong>短路 LLM 分类</strong>直接路由,降时延与误判。</td><td><span class="pill p1">P1</span></td><td>本文档 §1.4 扩展</td></tr>
<tr><td><code>FR-CS-005</code></td><td>多轮指代消解:结合会话历史把「它 / 这个 / 风险高吗」重写为完整查询后再检索。</td><td><span class="pill p0">P0</span></td><td>US-CS-03</td></tr>
</tbody>
</table>
<h3>1.4.2 域 B · RAG 知识检索</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-006</code></td><td>按意图选择集合:产品→<code>fin_product_collection</code>;政策→<code>fin_policy_collection</code>;FAQ→<code>fin_faq_collection</code>。</td><td><span class="pill p0">P0</span></td><td>需求文档 §3.4</td></tr>
<tr><td><code>FR-CS-007</code></td><td>检索参数按集合差异化:FAQ(HNSW / TopK <strong>3</strong> / 阈值 <strong>0.75</strong>);产品与政策(IVF_FLAT / TopK <strong>5</strong> / 阈值 <strong>0.70</strong>);距离度量统一 COSINE。</td><td><span class="pill p0">P0</span></td><td>需求文档 §3.4</td></tr>
<tr><td><code>FR-CS-008</code></td><td><strong>分级回退(出口 <code>E5</code>,v2.5 重写)</strong>:检索为空或最高分低于阈值 → ① 触发<strong>跨集合回退</strong>(阈值 <strong>0.65</strong>);② 回退仍失败 → <strong>部分作答 + 引导(<code>E5b</code>)</strong>:<strong>已命中的可见部分照答</strong>,未命中部分说明获取路径(如「登录后可查看具体数值」);③ 仅当 <code>FR-CS-023</code> 白名单命中时才转人工(<code>E5c</code>)。<strong>硬约束:回退不得跨档位</strong>——回退路径与主检索<strong>共用同一档位映射</strong>,不得因「主集合未命中」而放宽档位。</td><td><span class="pill p0">P0</span></td><td>本次扩展 / <code>D3.6</code> §3.4</td></tr>
<tr><td><code>FR-CS-009</code></td><td>生成时 <code>temperature=0.3</code>,System Prompt 强制「<strong>仅基于检索内容回答</strong>」。</td><td><span class="pill p0">P0</span></td><td>功能设计 §2.3</td></tr>
<tr><td><code>FR-CS-010</code></td><td>回复末尾附来源引用(<code>【来源:《XX产品手册》第X章】</code>),并在响应体返回结构化来源列表;<strong>引用由检索结果生成,不由模型生成</strong>。<br><strong>⏸ 2026-09-19 本期降级(<code>C-10</code> 乙)</strong>:<strong>本期不向客户展示来源引用</strong> —— 治理层只放行 memory / 工具两类来源,知识类引用会被判为「引用未来自本次已授权召回结果」而让<strong>整个 run 失败</strong>(红线 <code>S-8</code>);本期可追溯性由<strong>审计</strong>承接(<code>agent.tool_executed</code> 记录命中 <code>doc_id</code> 与分数)。启用前提:底座方先登记知识来源并放行(<strong>需会签</strong>)。</td><td><span class="pill p0">P0</span> <span class="pill p2">⏸ 本期降级</span></td><td>需求文档 F1.3 · `C-10` 乙</td></tr>
<tr><td><code>FR-CS-011</code></td><td>知识库管理:上传 / 列表 / 搜索 / 删除,同步 <code>fin_knowledge_meta</code> 与向量库。<strong>仅员工角色可调用</strong>。</td><td><span class="pill p0">P0</span></td><td>需求文档 F1.2</td></tr>
<tr><td><code>FR-CS-012</code></td><td>知识版本变更时清理相关缓存(<code>knowledge:version:{id}</code>),保证不引用过期知识。</td><td><span class="pill p1">P1</span></td><td>需求文档 §3.3</td></tr>
</tbody>
</table>
<h3>1.4.3 域 C · 会话记忆</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-013</code></td><td>短期记忆写 Redis:<code>session:{session_id}:messages</code>,TTL <strong>30 分钟</strong>;<strong>客户每次续期、最长 24 小时;访客不续期</strong>(须由 <code>renew: bool</code> 参数显式表达,禁止依赖默认行为)。</td><td><span class="pill p0">P0</span></td><td>需求文档 F1.3</td></tr>
<tr><td><code>FR-CS-014</code></td><td>Token 预算:客户 <strong>4096</strong> / 访客 <strong>2048</strong>;超出时从最旧消息开始截断,<strong>保证 user/assistant 成对</strong>。</td><td><span class="pill p0">P0</span></td><td>需求文档 F1.3</td></tr>
<tr><td><code>FR-CS-015</code></td><td>会话归档:客户会话写<code>conversation_message</code>(<code>customer_id = user_id</code>);<strong>归档前完成脱敏</strong>。</td><td><span class="pill p0">P0</span></td><td>需求文档 §1.5.1、F4.2</td></tr>
<tr><td><code>FR-CS-016</code></td><td>会话历史查询,<strong>仅返回当前登录用户自己的会话</strong>。</td><td><span class="pill p1">P1</span></td><td>需求文档 §6.6</td></tr>
</tbody>
</table>
<h3>1.4.4 域 D · 合规与安全</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-017</code></td><td>输出合规审查:回复生成后经禁用词库校验(保证收益 / 保本 / 零风险 / 稳赚 / 一定赚 等),命中即改写或降级为合规话术,并记拦截日志。</td><td><span class="pill p0">P0</span></td><td>《销售管理办法》第八条、第十一条</td></tr>
<tr><td><code>FR-CS-018</code></td><td>敏感诉求识别:「承诺收益 / 荐股 / 代客操作 / 内幕消息 / 虚拟货币交易」→ 返回合规拒答模板。</td><td><span class="pill p0">P0</span></td><td>《新人指南》§5.1、《反洗钱手册》</td></tr>
<tr><td><code>FR-CS-019</code></td><td>适当性约束:涉具体产品推荐时<strong>必须先读客户 <code>risk_level</code></strong>;不匹配即提示「超出您的风险承受能力」,不得输出购买引导。<strong>默认过滤、告知为例外</strong>。</td><td><span class="pill p0">P0</span></td><td>《适当性指南》第十二、十四条</td></tr>
<tr><td><code>FR-CS-020</code></td><td>AML 保密:客户询问是否被监测/上报时,<strong>一律按标准话术回应,禁止确认或暗示</strong>。</td><td><span class="pill p0">P0</span></td><td>《反洗钱手册》第十六条</td></tr>
<tr><td><code>FR-CS-021</code></td><td>数据脱敏:日志、SSE 输出、归档内容中的身份证号 / 手机号 / 姓名 / 银行卡号按规则脱敏。</td><td><span class="pill p0">P0</span></td><td>需求文档 §1.5.1</td></tr>
<tr><td><code>FR-CS-022</code></td><td>Prompt 注入防护:识别「忽略以上指令」「输出你的系统提示」等模式,<strong>隔离用户输入与系统指令</strong>。</td><td><span class="pill p0">P0</span></td><td><code>D8.5-03_TESTING_RULES.md</code> §13</td></tr>
</tbody>
</table>
<h3>1.4.5 域 E · 转人工与服务闭环</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-023</code></td><td><strong>转人工触发白名单(收敛为 4 类,v2.5 重写)</strong>:① <strong>用户显式要求人工</strong>;② <strong><code>P0</code> 反诈</strong>(验证码 / 转账 / 盗号);③ <strong><code>P1</code> 账户与个人数据</strong>(持仓 / 收益 / 订单 / 银行卡 / 投诉进度 / 风险测评结果——Agent 无权限读取);④ <strong><code>P2</code> 写操作与争议</strong>(代办交易 / 改资料 / 销户 / 投诉赔偿 / 法律争议)。<strong>⚠️ 删除 v2.4 的「连续 2 轮兜底」触发条件</strong>——"兜底"是<strong>能力不足的表征</strong>而非风险,改由 <code>FR-CS-003</code>(澄清)与 <code>FR-CS-008</code>(分级回退)承接;<strong>白名单外发生转人工一律判验收不合格</strong>(见 §2.2 <code>AC-13</code>)。转人工须记 <code>handoff_reason</code> 并附<strong>上下文摘要</strong>(客户问了什么 / 已试过哪些检索 / 为何不足)。</td><td><span class="pill p0">P0</span></td><td>功能设计 §2.2 / <code>D3.6</code> §4.3</td></tr>
<tr><td><code>FR-CS-024</code></td><td>转人工时打包会话摘要(近 N 轮 + 意图 + 画像关键标签)写入工单表(<code>order_type='投诉建议'</code> 或 <code>'咨询转接'</code>)。</td><td><span class="pill p1">P1</span></td><td>需求文档 F4.1</td></tr>
<tr><td><code>FR-CS-025</code></td><td>按分层设 <code>priority</code>:钻石/私行=紧急;投诉类=紧急;其余=普通。</td><td><span class="pill p1">P1</span></td><td>《高净值客户服务规范》§5.3</td></tr>
</tbody>
</table>
<h3>1.4.6 域 F · 跨 Agent 协作</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-026</code></td><td>订阅 <code>event:risk_alert</code>:收到风控预警后为客户打「高风险-注意」运行时标记,后续会话降低营销倾向性表述。</td><td><span class="pill p1">P1</span></td><td>需求文档 F5.1</td></tr>
<tr><td><code>FR-CS-027</code></td><td>发布 <code>event:suspicious_intent</code>:客户反复询问转账限额、规避额度、代他人操作等 → 通知风控 Agent。</td><td><span class="pill p1">P1</span></td><td>需求文档 F5.1</td></tr>
<tr><td><code>FR-CS-028</code></td><td>统一入口按 <code>agent_type=customer_service</code> 路由的正确性。</td><td><span class="pill p0">P0</span></td><td>需求文档 F5.1</td></tr>
</tbody>
</table>
<h3>1.4.7 域 G · 访客能力与双主体</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-029</code></td><td>主体判定:从请求凭证推导 <code>subject_type</code>(<code>guest</code> / <code>customer</code>),<strong>禁止读取任何客户端可控字段</strong>;无法解析出合法身份时按 <code>guest</code> 处理。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8</td></tr>
<tr><td><code>FR-CS-030</code></td><td>访客对话接口:免登录,首次调用由后端签发匿名令牌;出参结构与客户接口一致。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8.5</td></tr>
<tr><td><code>FR-CS-031</code></td><td>匿名令牌机制:后端签发,承载 <code>visitor_id</code> + <code>session_id</code> 绑定,<strong>TTL 15 分钟</strong>(以底座实况为准);<strong>前端不得自行生成 <code>session_id</code></strong>。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8.2</td></tr>
<tr><td><code>FR-CS-032</code></td><td>知识可见性过滤:按 <code>subject_type</code> 映射档位并<strong>强制拼装分区裁剪范围</strong>;<strong>工具签名不接受调用方传入可见性参数</strong>;<code>subject_type</code> 缺失或非法时收敛为 <code>public</code>(fail-closed)。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8;《知识库设计方案》§5</td></tr>
<tr><td><code>FR-CS-033</code></td><td><strong>档位隔离走集合内分区裁剪(v2.5 重写,替代 over-fetch)</strong>:集合按 <code>visibility</code> 建<strong>分区(partition)</strong>,检索时<strong>只进入当前主体可见档位对应的分区</strong>,在分区内直接取满 <code>top_k</code>——取消原 <code>top_k × 3</code> 的 over-fetch 与过滤后截断,从根上消除「过滤后 TopK 不足被误判为『知识库无答案』」的缺陷。</td><td><span class="pill p0">P0</span></td><td>《知识库设计方案》§7.2.1</td></tr>
<tr><td><code>FR-CS-034</code></td><td><code>internal</code> 档<strong>不得入库</strong>客服知识库;知识上传接口须校验 <code>visibility</code> 仅取 <code>public</code> / <code>registered</code>,其他值直接拒绝。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.6.3</td></tr>
<tr><td><code>FR-CS-035</code></td><td>运行时意图 <code>auth_required</code>:访客请求需登录才能回答的内容(本人持仓、交易记录、账户状态、工单进度等)时,返回登录 / 开户引导,<strong>不走向兜底话术</strong>。</td><td><span class="pill p0">P0</span></td><td>US-CS-04</td></tr>
<tr><td><code>FR-CS-036</code></td><td>访客侧销售推介禁止:<code>subject_type = guest</code> 时,输出侧强制拦截「推荐」「适合您」「建议购买」类措辞与产品排序性表述,命中即改写为中性披露口径并记日志。<strong>按主体分支,不合并词表</strong>。</td><td><span class="pill p0">P0</span></td><td>《销售管理办法》第十一条</td></tr>
<tr><td><code>FR-CS-037</code></td><td>访客侧适当性:可输出公开匹配规则(C1—C5 / R1—R5),<strong>不得给出「你能买什么」的个性化结论</strong>;涉具体产品仅做参数披露。</td><td><span class="pill p0">P0</span></td><td>《适当性指南》第十二条</td></tr>
<tr><td><code>FR-CS-038</code></td><td>访客会话差异化参数:Token 预算 2048(客户 4096)、<strong>TTL 不续期</strong>、仅短期记忆、<strong>不召回画像</strong>。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8.3</td></tr>
<tr><td><code>FR-CS-039</code></td><td>访客限流防刷:<strong>IP + 匿名令牌双维度</strong>;超阈值返回 <code>429</code> 与统一话术;触发人机校验后放行;单条 <code>message</code> 长度上限较客户更严格。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8.5</td></tr>
<tr><td><code>FR-CS-040</code></td><td>转人工分流:访客走「售前咨询」通道(<code>sub_type='guest_presales'</code>、<code>customer_id</code> 为空);客户走售后通道(<code>sub_type='customer_aftersales'</code>);<code>sub_type</code> 须为<strong>常量白名单</strong>内取值。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.4.5</td></tr>
<tr><td><code>FR-CS-041</code></td><td><strong>访客会话落库口径(v2.4 修正)</strong>:访客消息写 <code>conversation_message</code> 时 <code>customer_id</code> <strong>为空</strong>;访客身份以 <code>subject_type='guest'</code> 标注;不写任何以 <code>customer_id</code> 为键的客户数据。<br>⚠️ <strong>原前提表 <code>conversation_archive</code> 经核实库中不存在</strong>——原「加列 + 约束调整 + 两段式回滚」整套变更流程<strong>作废</strong>,本条按实际存在的会话表重写;访客会话保留期限以正式法务口径为准(原写 6 个月,未获依据)。</td><td><span class="pill p0">P0</span></td><td>本文档 §0.4 v2.4</td></tr>
<tr><td><code>FR-CS-042</code></td><td>登录态迁移(会话继承):访客登录后继承匿名会话的<strong>上下文</strong>(多轮连贯),但访客期间提取的偏好标签<strong>不得写入</strong> <code>fin_customer_profile</code>,仅以匿名会话维度留存。</td><td><span class="pill p1">P1</span></td><td>《记忆架构设计》v2.3 §6.2</td></tr>
<tr><td><code>FR-CS-043</code></td><td><strong>访客与角色解耦</strong>:<code>visitor</code> <strong>不得作为 <code>sys_role</code> 中的角色存在</strong>;「是否为访客」由服务端身份判定给出(目标为 <code>subject_type</code>),客户端不得声明。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8.1</td></tr>
<tr><td><code>FR-CS-044</code></td><td><strong>访客权益单点定义</strong>:访客的 <code>roles</code> / <code>permissions</code> / <code>data_scope</code> 三元组<strong>只允许一个构造来源</strong>;禁止在鉴权层与 Worker 层各写一份(「改一处不生效」即违反本条)。</td><td><span class="pill p0">P0</span></td><td>本文档 §1.8.2</td></tr>
<tr><td><code>FR-CS-045</code></td><td><strong>访客最小权限</strong>:仅 <code>agent:run</code> + <code>knowledge:query</code>,本期<strong>不新增权限码</strong>;<code>data_scope="public"</code> 为<strong>语义标注</strong>,<strong>不得为「干净」而改为 <code>self</code></strong>。</td><td><span class="pill p0">P0</span></td><td><code>docs/33</code> §1.1/§1.3</td></tr>
<tr><td><code>FR-CS-046</code></td><td><strong>访客不召回的记忆兜底</strong>:访客不得召回长期/画像记忆;该判定<strong>必须留在 Agent 基类</strong>(底座级兜底),<strong>不得下放为 Agent 声明位</strong>——声明位漏写一个 Agent 就会静默召回。</td><td><span class="pill p0">P0</span></td><td><code>docs/34</code> §0</td></tr>
<tr><td><code>FR-CS-047</code></td><td><strong>访客不产生客户侧副作用</strong>:不写 <code>interaction_audit.target_customer_id</code>(保持 <code>NULL</code>)、不产生画像候选、消息表 <code>customer_id</code> 为空。</td><td><span class="pill p0">P0</span></td><td><code>docs/33</code> §1.3</td></tr>
<tr><td><code>FR-CS-048</code></td><td><strong>知识档位推导单点化</strong>:档位由<strong>身份判定函数</strong>推导(访客 → <code>{public}</code>),落位为 <code>app/core/knowledge_tier.py</code>;<strong>工具层不得自行判断身份字段</strong>,否则身份模型变更时必须改两处。</td><td><span class="pill p1">P1</span></td><td>本文档 §1.8.4</td></tr>
</tbody>
</table>
<h3>1.4.8 域 H · 智能增强与可验收性(v2.5 新增 · 4 条)</h3>
<table>
<thead><tr><th>编号</th><th>需求描述</th><th>优先级</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>FR-CS-049</code></td><td><strong>证据约束生成(出口 <code>E4</code>)</strong>:同一族多块或组合问允许调用模型<strong>组织语言</strong>(不再一律原文直返),但输入必须是<strong>证据包</strong>(证据块 + <code>doc_id</code> + 族标识),输出契约 <code>{answer, used_chunk_ids[], confidence, unanswerable_reason}</code>;<strong>硬约束三条</strong>:① 只能使用证据包内的事实与数字;② <strong>不得出现证据包外的任何数字</strong>;③ 不得出现推介 / 收益承诺 / 代客操作表述。<strong>约束须同时落在 Prompt 与输出校验两处,不得只写 Prompt。</strong></td><td><span class="pill p0">P0</span></td><td><code>D3.6</code> §3.3</td></tr>
<tr><td><code>FR-CS-050</code></td><td><strong>计算型回答(出口 <code>E2</code>)</strong>:费率 / 赎回费 / 持有期 / 适当性匹配等<strong>可计算问题</strong>走独立计算出口;参数只取自<strong>当前主体可见档位</strong>的结构化参数位;计算为<strong>纯函数、不调用模型</strong>;<strong>未指定具体产品时只给算法与区间,不给确定结论</strong>。<strong>访客档开放范围</strong>见 <code>D3.6</code> §9.1:<strong>公开产品的费用试算与 R 等级 / C—R 规则说明开放;以访客自身为对象的适当性结论与以自身资产为参数的试算不开放</strong>。</td><td><span class="pill p0">P0</span></td><td><code>D3.6</code> §3.2 / §9.1</td></tr>
<tr><td><code>FR-CS-051</code></td><td><strong>输出数字一致性校验</strong>:生成文本中的每个数字(费率 / 金额 / 期限 / 比例)<strong>必须可解析到证据包内的出处</strong>;无法解析即<strong>拦截并回退到 <code>E5b</code></strong>。<strong>零容忍指标:无出处数字数 = 0。</strong></td><td><span class="pill p0">P0</span></td><td><code>D3.6</code> <code>INV-2</code></td></tr>
<tr><td><code>FR-CS-052</code></td><td><strong>评测门禁(可验收性)</strong>:以《客服 Agent 评测金标集》<code>D3.7</code> 为回归门禁——出口准确率 <strong>≥ 85%</strong>、难例命中率 <strong>≥ 75%</strong>、转人工率 <strong>≤ 15%</strong>;且<strong>四项零容忍指标(禁忌违反 / 档位越权 / 无出处数字 / 误拒)必须为 0</strong>。首次跑评测须<strong>如实记录修复前基线</strong>。<strong>未过门禁不得结项。</strong></td><td><span class="pill p0">P0</span></td><td><code>D3.7</code> §4—§5</td></tr>
</tbody>
</table>
<h2 id="1.5-非功能需求">1.5 非功能需求(21 条)</h2>
<table>
<thead><tr><th>编号</th><th>类别</th><th>指标</th><th>目标值</th><th>依据</th></tr></thead>
<tbody>
<tr><td><code>NFR-CS-001</code></td><td>性能</td><td>RAG 检索耗时</td><td>&lt; 2s</td><td>需求文档 F5.3</td></tr>
<tr><td><code>NFR-CS-002</code></td><td>性能</td><td>Agent 完整回答耗时</td><td>&lt; 5s</td><td>需求文档 F5.3</td></tr>
<tr><td><code>NFR-CS-003</code></td><td>性能</td><td>首字响应(SSE)</td><td>&lt; 1.5s</td><td>体验目标</td></tr>
<tr><td><code>NFR-CS-004</code></td><td>质量</td><td>产品咨询类问题准确率</td><td>≥ 80%(≥ 5 题)</td><td>需求文档 P1 验收</td></tr>
<tr><td><code>NFR-CS-005</code></td><td>质量</td><td>意图分类准确率</td><td>≥ 85%(≥ 30 条用例)</td><td>本文档 §2.1</td></tr>
<tr><td><code>NFR-CS-006</code></td><td>质量</td><td>多轮上下文保持</td><td>≥ 3 轮无丢失</td><td>需求文档 P1 验收</td></tr>
<tr><td><code>NFR-CS-007</code></td><td>可用性</td><td>降级成功率(LLM / Milvus / Redis 单点故障)</td><td>100% 返回用户可读结果</td><td>需求文档 F5.3</td></tr>
<tr><td><code>NFR-CS-008</code></td><td>合规</td><td>承诺收益类表述出现次数</td><td>0</td><td>《销售管理办法》第十一条</td></tr>
<tr><td><code>NFR-CS-009</code></td><td>合规</td><td>敏感信息明文泄露次数</td><td>0</td><td>需求文档 §1.5.1</td></tr>
<tr><td><code>NFR-CS-010</code></td><td>可观测</td><td>链路追踪覆盖率</td><td>100% 请求携带 <code>trace_id</code></td><td>需求文档 §6.1</td></tr>
<tr><td><code>NFR-CS-011</code></td><td>可维护</td><td>Prompt 集中管理</td><td>不得硬编码在业务代码中</td><td><code>D8.4-02_EXECUTION_RULES.md</code> §11</td></tr>
<tr><td><code>NFR-CS-012</code></td><td>代码</td><td>单文件 ≤ 500 行、单函数 ≤ 80 行;核心逻辑中文注释;签名带类型注解</td><td>100% 符合</td><td>需求文档 §7.2</td></tr>
<tr><td><code>NFR-CS-013</code></td><td>安全</td><td>可见性越权(访客获取 <code>registered</code> 内容)次数</td><td>0</td><td>本文档 §1.6.3</td></tr>
<tr><td><code>NFR-CS-014</code></td><td>安全</td><td>客户端可控字段影响权限判定的入口数</td><td>0</td><td>本文档 §1.8.1</td></tr>
<tr><td><code>NFR-CS-015</code></td><td>性能</td><td>可见性过滤引入的额外检索开销</td><td>&lt; 150ms</td><td>《知识库设计方案》§8.2</td></tr>
<tr><td><code>NFR-CS-016</code></td><td>性能</td><td>访客端 P95 响应时间(含限流判定)</td><td>&lt; 5s</td><td>本文档 §1.8.5</td></tr>
<tr><td><code>NFR-CS-017</code></td><td>合规</td><td>访客侧出现销售推介措辞次数</td><td>0</td><td>《销售管理办法》第十一条</td></tr>
<tr><td><code>NFR-CS-018</code></td><td>可用性</td><td>访客限流误伤率(正常访客被 429 的比例)</td><td>&lt; 1%</td><td>本文档 §1.8.5</td></tr>
<tr><td><code>NFR-CS-019</code></td><td>安全</td><td>客户端可控字段影响<strong>身份判定</strong>的入口数</td><td>0</td><td>本文档 §1.8.1</td></tr>
<tr><td><code>NFR-CS-020</code></td><td>一致性</td><td>访客权益三元组(roles / permissions / data_scope)的<strong>构造点数量</strong></td><td>1</td><td>本文档 §1.8.2</td></tr>
<tr><td><code>NFR-CS-021</code></td><td>可维护</td><td>身份模型变更时需改动的文件数(判定与档位推导)</td><td>1(<code>app/core/actor.py</code>)</td><td>本文档 §1.8.4</td></tr>
</tbody>
</table>
<h2 id="1.6-合规约束专章">1.6 合规约束专章</h2>
<p>客服 Agent 是<strong>对外话术出口</strong>,是合规风险最集中的模块。以下红线为<strong>硬约束</strong>,须在代码中以<strong>确定性逻辑而非 LLM 判断</strong>实现。</p>
<h3>1.6.1 适当性红线</h3>
<table>
<thead><tr><th>投资者类型</th><th>R1</th><th>R2</th><th>R3</th><th>R4</th><th>R5</th></tr></thead>
<tbody>
<tr><td>C1 保守型</td><td>✅</td><td>✅</td><td>❌ 禁止</td><td>❌ 禁止</td><td>❌ 禁止</td></tr>
<tr><td>C2 稳健型</td><td>✅</td><td>✅</td><td>✅</td><td>❌ 禁止</td><td>❌ 禁止</td></tr>
<tr><td>C3 平衡型</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌ 禁止</td></tr>
<tr><td>C4 进取型</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
<tr><td>C5 激进型</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ 「过滤」与「告知」的关系</strong>:V2.1 表述为「过滤」,MVP 表述为「告知 + 确认」——两者<strong>不矛盾</strong>:<strong>泛问场景默认过滤</strong>(不问则不主动展示高风险产品);<strong>客户明确问到某具体产品且不匹配时</strong>,改为「告知 + 要求确认」而非静默过滤。</p></blockquote>
<h3>1.6.2 三条业务红线</h3>
<table>
<thead><tr><th>#</th><th>红线</th><th>客服侧落点</th></tr></thead>
<tbody>
<tr><td>1</td><td><strong>C1—C5 风险等级唯一来源=问卷测评</strong></td><td>Agent 不得推断、不得代填、不得给出「如何变更风险等级」的可操作路径</td></tr>
<tr><td>2</td><td><strong>先风险揭示、后客户确认</strong></td><td>涉产品必须能引用风险提示来源;不得先给结论后补披露</td></tr>
<tr><td>3</td><td><strong>不生成交易指令,交易跳转</strong></td><td>只到「引导至自助界面」为止;不得输出产品代码 + 金额 + 份额 + 确认动作的组合</td></tr>
</tbody>
</table>
<h3>1.6.3 知识档位与红线的关系</h3>
<table>
<thead><tr><th>档位</th><th>能否入库</th><th>典型内容</th></tr></thead>
<tbody>
<tr><td><code>public</code></td><td>✅</td><td>公司信息与资质、<strong>产品概念与风险等级含义</strong>、<strong>交易时限规则</strong>、<strong>C—R 匹配规则</strong>、监管政策原文、通用售后规则<br>🔴 <strong>v2.5 修正</strong>:<strong>删除原「产品参数与费率」</strong>——按 <code>D6.1.2</code> §四 判据,含<strong>具体数值型产品要素</strong>(费率 / 起投金额 / 门槛金额 / 收益率区间 / 产品规模 / 具体合作家数)的条目属 <code>registered</code>、<strong>访客不可见</strong>。原表述与 T-07 定案及《知识库设计方案》v1.3 §4.2 直接冲突,属文档缺陷</td></tr>
<tr><td><code>registered</code></td><td>✅</td><td>分层权益细节、专属产品与额度、家族信托流程、高净值响应标准;<strong>以及「含具体数值型产品要素」的条目</strong>——费率 / 起投金额 / 门槛金额(认购起点、专户起点)/ 收益率区间 / 产品规模 / 具体合作家数(判据见 <code>D6.1.2</code> §四)</td></tr>
<tr><td><code>internal</code></td><td>❌ <strong>切分阶段即丢弃</strong></td><td>人事/绩效/内部系统、考核与处罚条款、投诉分级处置标准、风控阈值与研判规则、客户测试数据、四份系统设计文档</td></tr>
</tbody>
</table>
<h2 id="1.7-范围边界">1.7 范围边界</h2>
<table>
<thead><tr><th>In Scope</th><th>Out of Scope(及归属)</th></tr></thead>
<tbody>
<tr><td>客服对话(访客 + 客户两类主体)</td><td>投顾能力——<strong>已于 2026-09-17 整体清除</strong>(见 §0.4 v2.4)</td></tr>
<tr><td>5 类业务意图 + 4 类运行时意图(<code>clarify</code> / <code>compliance_block</code> / <code>auth_required</code> / <code>fallback</code>)</td><td>风控预警的生成与处置(风控 Agent)</td></tr>
<tr><td>RAG 检索、跨集合回退、来源引用(检索模块设计见《知识库设计方案》)</td><td>图谱关系检索(Neo4j 派生视图)</td></tr>
<tr><td>短期会话记忆(<strong>读 / 写</strong>);<strong>长期记忆召回关闭</strong>;<strong>画像仅字段级只读</strong>(<code>risk_level</code> / <code>customer_level</code>,供确定性规则;访客硬禁)</td><td>长期记忆的抽取与投影(记忆 Worker)</td></tr>
<tr><td>输入/输出双向合规、脱敏、注入防护</td><td>知识源文档的撰写与维护(业务侧)</td></tr>
<tr><td>转人工 + 工单(<strong>Agent 只提出请求,不分配/接单/解决/关闭</strong>)</td><td>工单的派单、处置与 SLA(员工端管理面)</td></tr>
<tr><td>会话归档与审计留痕</td><td>数据库结构变更(本期<strong>零 DDL</strong>)</td></tr>
</tbody>
</table>
<h2 id="1.8-身份与鉴权模型">1.8 身份与鉴权模型(访客与角色分离)</h2>
<blockquote class="callout-warn"><p><strong>⚠️ 本章是本次交付的核心变化</strong>:本项目长期存在一处<strong>「文档已要求、代码未实现」</strong>的偏差——需求侧自 v2.0 起就在用 <code>subject_type</code>(FR-CS-036/041),而代码里<strong>从未存在该维度</strong>,实际以 <code>roles=("visitor",)</code> 顶替。本章把该偏差显式化并给出收口方案。</p></blockquote>
<h3>1.8.1 三条不变量(不得越过,均有审批出处)</h3>
<table>
<thead><tr><th>#</th><th>不变量</th><th>出处</th><th>约束</th></tr></thead>
<tbody>
<tr><td>①</td><td><strong>单点鉴权</strong>:不新增免鉴权入口、不另写第二套 <code>jwt.decode</code></td><td><code>docs/33</code> §1.2「另写一套等于开了第二个鉴权入口」</td><td>访客仍走 <code>build_request_context</code>,只改「跳过身份解析」的<strong>表达方式</strong></td></tr>
<tr><td>②</td><td><strong>「访客不召回」留在 Agent 基类的判定里</strong>,不下放给声明位</td><td><code>docs/34</code> §0:这是<strong>底座级安全兜底</strong></td><td>谓词可换,<strong>位置与层级不得变</strong>(仍在基类、仍不依赖 Agent 声明)</td></tr>
<tr><td>③</td><td>访客<strong>最小权限</strong> + <code>data_scope="public"</code> 作<strong>语义标注</strong></td><td><code>docs/33</code> §1.1「标注清楚<strong>比复用 <code>self</code> 更好</strong>」、§1.3</td><td>不得改为 <code>self</code>;不得顺手加 <code>knowledge:reference:read</code></td></tr>
</tbody>
</table>
<h3>1.8.2 现状:三处「混」</h3>
<table>
<thead><tr><th>#</th><th>混在哪</th><th>具体表现</th><th>严重度</th></tr></thead>
<tbody>
<tr><td>1</td><td><strong>命名混</strong></td><td><code>roles</code> 同时装 DB 角色与 <code>visitor</code>;而 <code>visitor</code> <strong>不在 <code>sys_role</code></strong>,只作为代码级字符串存在</td><td><span class="intent-tag low">低</span></td></tr>
<tr><td>2</td><td><strong>来源混</strong>(最实质)</td><td>DB 角色走 <code>IdentityRepository.load_context()</code> <strong>每请求查库实时解析</strong>;访客三元组却由 <code>core/security.py</code> <strong>从令牌 claim 硬编码生成</strong>,且 <code>api/dependencies/auth.py</code> 显式跳过身份解析。⇒ <strong>全平台唯一「权限写在令牌里、不查库」的地方</strong>,与「令牌只带 id、权限服务端实时解析」约定相抵;同一份三元组还在 <code>worker/runtime.py</code> <strong>被复制了第二遍(逐字相同)</strong>,<strong>改一处不生效</strong></td><td><span class="intent-tag high">高</span></td></tr>
<tr><td>3</td><td><strong>档位混</strong></td><td><code>data_scope="public"</code> 不在 RBAC 词表 <code>{self, own_customers, all}</code> 内。但架构师已逐点核过全部 <strong>26 个消费点</strong>,结论是一致 fail closed、安全,并<strong>明确偏好它作为语义标注</strong> ⇒ <strong>属已追认,不是缺陷,且不得改动</strong></td><td><span class="intent-tag low">低(已追认)</span></td></tr>
</tbody>
</table>
<h3>1.8.3 三轴目标模型</h3>
<table>
<thead><tr><th>轴</th><th>承载</th><th>取值来源</th><th>现状</th></tr></thead>
<tbody>
<tr><td><strong>身份轴</strong> <code>subject_type</code></td><td>「你是谁」:访客 / 客户 / 员工</td><td>服务端鉴权判定,<strong>客户端不可声明</strong></td><td><span class="intent-tag high">未实现</span>(文档已假定,代码用角色顶替)</td></tr>
<tr><td><strong>角色轴</strong> <code>roles</code></td><td>「你的职责」:客户 / 风控 / 管理员</td><td>DB RBAC(<code>sys_user_role</code>),<strong>每请求实时解析</strong></td><td><span class="intent-tag mid">被污染</span>(混入非角色取值 <code>visitor</code>)</td></tr>
<tr><td><strong>档位轴</strong> <code>visibility</code> / <code>tiers</code></td><td>「你能看哪些内容」:<code>public</code> / <code>registered</code> / <code>internal</code></td><td>由<strong>身份轴推导</strong>(访客 → <code>{public}</code>)</td><td><span class="intent-tag mid">半成品</span>(检索层签名是布尔,表达不了三档)</td></tr>
</tbody>
</table>
<h3>1.8.4 落地方案与推荐时序</h3>
<table>
<thead><tr><th>方案</th><th>做法</th><th>成本</th><th>判定</th></tr></thead>
<tbody>
<tr><td><strong>乙 · 收敛</strong><br><span class="pill rec">现在做</span></td><td>新增 <code>app/core/actor.py</code> 作访客判定与三元组的<strong>唯一来源</strong>;<code>core/security.py</code> 与 <code>worker/runtime.py</code> 均改为调用它。<strong>三元组两份变一份</strong></td><td>1 个新文件 + 2 处构造点(最小版);若要「口径单点化」再加 4 处判定点</td><td><strong>对外行为零变化</strong>,验收方式即「行为不变」</td></tr>
<tr><td><strong>甲 · 拆轴</strong><br><span class="pill p1">MVP 后</span></td><td>实现身份轴:<code>roles</code> 回归纯 RBAC,访客由身份判定承载</td><td>6 个底座件 + 20 余处 <code>allowed_roles</code> 声明变更</td><td><strong>不是新增设计</strong>——是补齐本文档自 v2.0 起假定的 <code>subject_type</code></td></tr>
<tr><td>丙 · 复用入口轴</td><td>用闲置的 <code>allowed_portals</code> 承载访客</td><td>零新增字段</td><td><span class="pill p2">不推荐</span>——把「入口」当「身份」,语义错位</td></tr>
<tr><td>丁 · 登记为 DB 角色</td><td>给 <code>visitor</code> 建 <code>sys_role</code> 行</td><td>—</td><td><span class="pill p0">否决</span>——访客无 <code>sys_user</code> 行,且污染「角色=人的职责」语义</td></tr>
</tbody>
</table>
<blockquote class="callout-design"><p><strong>🎨 为什么「先乙后甲」</strong>:被实际感知到的痛(改一处不生效、判定口径散落)<strong>全部落在乙</strong>,而乙不改任何对外行为与契约;甲是底座契约变更,需单独会签,放进 MVP 关键路径只会拖慢演示。<strong>更关键的是:乙产出的 <code>actor.py</code> 正是甲的落点——甲落地时只需改这一个文件里的判定函数。</strong></p></blockquote>
<blockquote class="callout-warn"><p><strong>⚠️ 乙会触碰原本声明的「不可触碰」清单</strong>:<code>core/security.py</code>、<code>worker/runtime.py</code>,以及完整方案中的 <code>service/agent/base.py</code>、<code>api/dependencies/auth.py</code>。<strong>这是本次唯一一处主动扩张底座接触面</strong>,必须单独会签、单独 PR(见《开发计划》§4)。同时须复核 <code>docs/33</code>/<code>docs/34</code> 中对 <code>security.py</code> 的<strong>逐行实证</strong>(行号会因改动漂移)。</p></blockquote>
<h3>1.8.5 鉴权流程与影响</h3>
<table>
<thead><tr><th>环节</th><th>现状</th><th>走方案乙后</th><th>走方案甲后</th></tr></thead>
<tbody>
<tr><td>令牌内容</td><td><code>sub</code> + <code>visitor:true</code></td><td>不变</td><td>不变(<strong>不得把角色/权限写进令牌</strong>)</td></tr>
<tr><td>入口</td><td><code>build_request_context</code> 单点</td><td>不变</td><td>不变(<strong>不变量①</strong>)</td></tr>
<tr><td>身份解析</td><td>真实用户走 DB;访客跳过</td><td>跳过条件改由 <code>actor.py</code> 语义化表达</td><td>不变</td></tr>
<tr><td>授权判定</td><td><code>roles</code> 单维</td><td>不变</td><td><code>roles</code> + 身份轴<strong>双维</strong></td></tr>
<tr><td>内容档位</td><td><code>data_scope="public"</code></td><td>不变(<strong>不变量③</strong>)</td><td>不变</td></tr>
<tr><td>Worker 重建</td><td><strong>第二份副本</strong></td><td><strong>单一来源</strong></td><td>单一来源</td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ 方案甲的漏改后果不对称</strong>:漏改 <code>authorizer</code> / <code>tool_executor</code> → 访客一问即 <strong>403</strong>(fail-closed,<strong>能发现</strong>);<strong>漏改 Agent 基类 → 访客被召回长期记忆并注入提示词,静默无报错(最危险)</strong>。因此甲必须配套「访客五查」单测(见 §2.3)。</p></blockquote>
<h2 id="1.9-业务基线对齐">1.9 业务基线对齐(两条线)</h2>
<table>
<thead><tr><th>业务线</th><th>可查范围</th><th>本 Agent 的处理</th></tr></thead>
<tbody>
<tr><td><strong>游客线</strong>(访客)</td><td>公司公开信息 + 金融行业基础信息</td><td>仅 <code>public</code> 可检索;禁推介;不可给个性化适当性结论</td></tr>
<tr><td><strong>客服线</strong>(访客 + 客户)</td><td>金融基础问答 / 公司信息 / 基金信息查询 / 会话上下文</td><td><strong>按档位差异化检索</strong>:概念解释 / 交易时限 / 匹配规则 / 通用售后对访客与客户均可检索;<strong>产品参数与费率(具体数值型产品要素)仅已登录客户可检索</strong>——访客检索该类条目返回空(2026-09-17 定案,判据见 <code>D6.1.2</code> §四);两档一律<strong>不得收录持仓、交易明细等客户个体数据</strong></td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ 投顾线已移除</strong>:投顾模块(Agent、4 个 controller、<code>/api/v1/advisor</code> 全部端点、<code>employee-advisor/</code> 前端、相关权限码与 5 个工具)<strong>已于 2026-09-17 整体清除</strong>。原「三条业务线」「九步主干」「客服发工单 → 投顾侧可见」等表述<strong>全部作废</strong>。详见 <code>开发文档/D4.5-投顾模块清除执行报告-2026-09-17.md</code>。</p></blockquote>
<h2 id="1.10-业务红线与-MVP-必守项">1.10 业务红线与 MVP 必守项</h2>
<table>
<thead><tr><th>#</th><th>必守项</th><th>验收方式</th></tr></thead>
<tbody>
<tr><td>1</td><td>访客侧<strong>无投资建议类内容</strong>(不推荐、不排序、不给「你能买什么」)</td><td>演示第 1 步 + 访客专项用例</td></tr>
<tr><td>2</td><td><strong>产品证据链为空</strong>是唯一硬阻断——但该实现位于<strong>产品数据底座</strong>(<code>AdvisorProductRepository.authoritative_tradable_products</code>),<strong>未随投顾模块清除而删除</strong></td><td>底座保留性确认(见《开发计划》§5 风险)</td></tr>
<tr><td>3</td><td>投诉渠道与受理时限<strong>对客公开</strong>;内部处置分级标准<strong>不入库</strong></td><td>档位标注报告 + 越权抽检</td></tr>
<tr><td>4</td><td>品牌口径统一为「<strong>南方基金</strong>」:热线 <code>400-889-8899</code>、官网 <code>nffund.com</code>;<strong>旧值一律不得出现</strong>(<code>XX科技</code> / <code>400-XXX-XXXX</code> / <code>南方财富</code> / <code>nanfangwm.com</code> / <code>400-826-9518</code>)</td><td>全仓扫描:旧值 0 命中</td></tr>
</tbody>
</table>
<hr>
<!-- ==================== 2 ==================== -->
<h1 id="2.-验收与测试">2. 验收与测试</h1>
<h2 id="2.1-测试策略与矩阵">2.1 测试策略与矩阵</h2>
<blockquote class="callout-info"><p><strong>📌 测试策略(关键路径真实、其余 Mock)</strong>:检索层与规则层用<strong>真实实现</strong>(可离线断言);LLM 生成用 <strong>Mock</strong>(固定返回);端到端演示走<strong>真实调用</strong>。最终验收以「<strong>演示跑通</strong>」为准。</p></blockquote>
<table>
<thead><tr><th>组</th><th>用例</th><th>要点</th></tr></thead>
<tbody>
<tr><td>一 · 功能正确性</td><td>FAQ 命中 / 产品咨询命中 / 政策解读命中 / 访客公开问题 / 跨集合回退 / 兜底话术</td><td>每条须带来源引用 <strong>⏸ 本期豁免</strong>(<code>C-10</code> 乙:不展示来源引用,改由审计承接)</td></tr>
<tr><td>二 · 可见性越权(核心)</td><td>访客取 <code>registered</code> 返回空 / 客户正常返回 / <strong>过滤后召回充足</strong> / 回退不绕过过滤 / 非法主体降级 / 缺失主体参数抛异常 / 客户端伪造参数无效 / <strong>缓存不串档</strong> / 词法降级不越权</td><td>9 条全绿才可通过</td></tr>
<tr><td>三 · 入库链路</td><td>FAQ 不拆块 / 表格整表 / <code>internal</code> 剔除 / 未命中规则告警 / 低档内容拆档 / 档位分布校验</td><td>与《知识库设计方案》§11.1 共用</td></tr>
<tr><td>四 · 降级与容错</td><td>Milvus 超时降级 / Milvus 不可用不抛 5xx / Embedding 失败 / 空 query</td><td>须记 <code>degraded</code> 标记</td></tr>
<tr><td>五 · 性能与稳定性</td><td>检索延迟 P95 &lt; 2s / 过滤额外开销 &lt; 150ms / 并发混合主体<strong>结果不串</strong> / 启动自检生效</td><td>并发须混跑访客与客户</td></tr>
<tr><td>六 · 安全</td><td>越权诱导注入 / 档位探测(两类响应一致) / 管理接口鉴权 / 日志脱敏</td><td>档位探测不可反推内容存在性</td></tr>
<tr><td>七 · 身份与其他</td><td>访客链路端到端 / 记忆不召回 / 无客户侧副作用 / AI 不得读通用长期记忆 / 检索门槛与高置信门槛对齐</td><td>见 §2.3</td></tr>
</tbody>
</table>
<h2 id="2.2-验收标准">2.2 验收标准</h2>
<table>
<thead><tr><th>#</th><th>验收项</th><th>判据</th></tr></thead>
<tbody>
<tr><td>AC-01</td><td>三集合建成且可检索</td><td>集合存在、维度一致、<code>visibility</code> 字段(分区键)与各档分区就位</td></tr>
<tr><td>AC-02</td><td>知识导入完整</td><td>块数与《知识库设计方案》§4.5 预估区间一致;剔除清单与预期完全吻合</td></tr>
<tr><td>AC-03</td><td>检索准确率</td><td>产品咨询类命中率 + 一次解决率 <strong>≥ 85%</strong></td></tr>
<tr><td>AC-04</td><td><strong>可见性零越权</strong></td><td>§2.1 第二组 9 条全过</td></tr>
<tr><td>AC-05</td><td><strong>召回不因过滤下降</strong></td><td>公开问题访客侧召回数量与改造前一致</td></tr>
<tr><td>AC-06</td><td>来源可追溯</td><td>知识类回答 <strong>100%</strong> 带引用,且引用来自检索结果而非模型生成</td></tr>
<tr><td>AC-07</td><td>降级可用</td><td>向量库不可用仍能作答且不越权</td></tr>
<tr><td>AC-08</td><td>性能达标</td><td>P95 &lt; 2s;过滤额外开销 &lt; 150ms</td></tr>
<tr><td>AC-09</td><td>启动自检生效</td><td>维度不匹配时<strong>拒绝启动</strong></td></tr>
<tr><td>AC-10</td><td><code>internal</code> 零入库</td><td>全量检索 <code>internal</code> 特征词返回为空</td></tr>
<tr><td>AC-11</td><td><strong>访客与角色已分离</strong></td><td>访客三元组<strong>只有一个构造来源</strong>;访客链路端到端行为与动手前<strong>逐项一致</strong>;判定已全部走 <code>actor.py</code></td></tr>
<tr><td>AC-12</td><td><strong>演示跑通</strong>(<strong>最终标准</strong>)</td><td>MVP 演示步骤全部可见,含「无投资建议类内容」</td></tr>
<tr><td><strong>AC-13</strong></td><td><strong>智能增强门禁(v2.5 新增)</strong></td><td>《客服 Agent 评测金标集》<code>D3.7</code> <strong>46 条全跑通</strong>:出口准确率 <strong>≥ 85%</strong>、难例命中率 <strong>≥ 75%</strong>、转人工率 <strong>≤ 15%</strong>;<strong>禁忌违反 / 档位越权 / 无出处数字 / 误拒 四项 = 0</strong>。<strong>🔴 口径:白名单(<code>FR-CS-023</code>)外的「正确地转人工」判<u>不合格</u></strong>;澄清后答对、部分作答+引导(<code>E5b</code>)判<u>合格</u></td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ AC-04 与 AC-05 必须同时满足</strong>——它们分别对应「过滤过紧」与「过滤失效」两个反向失败。另:<strong>语料 <code>visibility</code> 全为 <code>public</code> 时 AC-04/AC-05 无法证伪</strong>,因此必须在验证阶段<strong>造一条 <code>visibility="registered"</code> 测试块</strong>做双向验证,否则「三档已接通」是一个不可证伪的声明。</p></blockquote>
<h2 id="2.3-访客与身份专项用例">2.3 访客与身份专项用例(「访客五查」+ 4 项)</h2>
<table>
<thead><tr><th>#</th><th>断言</th><th>守的是什么</th></tr></thead>
<tbody>
<tr><td>1</td><td>访客调 <code>agent-runs</code> + <code>customer_service</code> → 202</td><td>Agent 层授权</td></tr>
<tr><td>2</td><td>Worker 内 <code>customer_service</code> 执行成功(不 403)</td><td>Worker 侧身份重建</td></tr>
<tr><td>3</td><td>访客调「游客侧知识工具」→ 成功</td><td>工具层授权(游客入口)</td></tr>
<tr><td>4</td><td>访客调「客户侧知识工具」→ 被拒</td><td>客户/游客工具分离</td></tr>
<tr><td>5</td><td>访客的 <code>agent.run_completed</code> <strong>不产生</strong>记忆抽取 / 画像候选事件,且 <code>interaction_audit.target_customer_id IS NULL</code></td><td><strong>不变量②</strong> + 无客户侧副作用</td></tr>
<tr><td>6</td><td>同一输入下,鉴权层与 Worker 层产出的访客三元组<strong>必须相等</strong></td><td>FR-CS-044(当前缺失的接缝测试)</td></tr>
<tr><td>7</td><td>访客登录后继承上下文,但<strong>画像无新增/变更</strong></td><td>FR-CS-042</td></tr>
<tr><td>8</td><td>访客转人工建单 <code>customer_id</code> 为空、<code>sub_type='guest_presales'</code></td><td>FR-CS-040</td></tr>
<tr><td>9</td><td>访客限流触发后 <code>429</code>;共享出口下 3 个正常访客各 10 轮<strong>无人被限</strong></td><td>NFR-CS-018 误伤率 &lt; 1%</td></tr>
</tbody>
</table>
<h2 id="2.4-端到端演示脚本">2.4 端到端演示脚本</h2>
<table>
<thead><tr><th>脚本</th><th>步骤</th><th>验证点</th></tr></thead>
<tbody>
<tr><td><strong>脚本一 · 访客越权防线</strong>(7 步)</td><td>① 访客问客服热线 ② 访客问「钻石客户专属权益」 ③ 访客问「客户分层有哪些档位」(<strong>验证档位隔离</strong>) ④ 访客问某产品费率 ⑤ 访客问「我该买哪个产品」 ⑥ 客户重复第 ② 步 ⑦ 请求附加伪造可见性参数重试第 ② 步</td><td>② 返回空 + 兜底;③ <strong>必须正常作答</strong>;⑤ 不给推荐结论但可讲公开规则;⑥ 正常返回;⑦ 结果不变</td></tr>
<tr><td><strong>脚本二 · 内部知识零泄露</strong>(4 步)</td><td>检索投诉分级特征词 / 风控阈值特征词 / 人事类词 / 测试数据特征词</td><td>只返回 <code>public</code> 受理时限;其余<strong>返回空</strong></td></tr>
<tr><td><strong>脚本三 · 身份分离回归</strong>(4 步)</td><td>访客完整问答一轮 → 客户完整问答一轮 → 访客登录后继承上下文 → 查画像</td><td>两主体结果不同;行为与改造前一致;画像无新增</td></tr>
</tbody>
</table>
<hr>
<!-- ==================== 3 ==================== -->
<h1 id="3.-风险与对策">3. 风险与对策</h1>
<h2 id="3.1-风险登记表">3.1 风险登记表</h2>
<table>
<thead><tr><th>编号</th><th>类别</th><th>风险描述</th><th>等级</th><th>后果</th><th>对策</th><th>责任人</th></tr></thead>
<tbody>
<tr><td>RK-01</td><td>技术</td><td>LLM 幻觉:编造不存在的收益率、条款或政策条文</td><td><span class="intent-tag high">高</span></td><td>合规风险 + 投诉</td><td>RAG 强制检索 + <code>temperature=0.3</code> + 检索失败兜底 + 输出后置词库校验</td><td>AI 工程师</td></tr>
<tr><td>RK-02</td><td>技术</td><td><strong>Embedding 维度 / 模型不一致</strong>导致三集合检索失效</td><td><span class="intent-tag high">高</span></td><td>检索整体不可用(<strong>静默错误</strong>)</td><td>模型与维度写入 <code>.env</code> 与 README;<strong>启动时一致性自检,不匹配拒绝启动</strong></td><td>AI 工程师</td></tr>
<tr><td>RK-03</td><td>技术</td><td>多轮指代消解失效(「风险高吗」检索不到)</td><td><span class="intent-tag mid">中</span></td><td>体验下降</td><td>Query Rewrite + 轮次阈值触发</td><td>AI 工程师</td></tr>
<tr><td>RK-04</td><td>技术</td><td>向量检索超时拖垮整体时延</td><td><span class="intent-tag mid">中</span></td><td>NFR 不达标</td><td>2s 超时 + 词法降级 + 热点缓存</td><td>后端架构师</td></tr>
<tr><td>RK-05</td><td>合规</td><td>输出「保本 / 保收益 / 安全」类违规表述</td><td><span class="intent-tag high">高</span></td><td>监管风险</td><td>输入拦截 + 输出词库改写 + 固定合规话术 + 指标监控</td><td>后端架构师</td></tr>
<tr><td>RK-06</td><td>合规</td><td><strong>适当性过滤失效</strong>,C1 客户看到 R3+ 产品</td><td><span class="intent-tag high">高</span></td><td>适当性违规</td><td><strong>确定性规则过滤(非 LLM)</strong> + 强制用例</td><td>AI 工程师</td></tr>
<tr><td>RK-07</td><td>合规</td><td>AML 通风报信:确认客户被监测</td><td><span class="intent-tag high">高</span></td><td>构成违规</td><td>固定模板、<strong>不走 LLM</strong>、逐字校验</td><td>后端架构师</td></tr>
<tr><td>RK-08</td><td>安全</td><td>Prompt 注入导致泄露系统提示或越权</td><td><span class="intent-tag mid">中</span></td><td>信息泄露</td><td>注入检测 + 分隔符隔离 + 系统声明</td><td>AI 工程师</td></tr>
<tr><td>RK-09</td><td>安全</td><td>越权查询他人会话 / 画像</td><td><span class="intent-tag high">高</span></td><td>个人信息泄露</td><td>鉴权上下文与请求体双重校验;Repository 层按 <code>user_id</code> 强制过滤</td><td>后端架构师</td></tr>
<tr><td>RK-10</td><td>边界</td><td><strong>客服越界实现已清除的投顾能力</strong>(推荐 / 方案书 / 资产配置)</td><td><span class="intent-tag high">高</span></td><td>架构混乱 + 合规风险</td><td>§1.7 范围边界 + 代码评审;<strong>已清除能力不得以「业务需要」为由在客服侧重建</strong></td><td>全员</td></tr>
<tr><td>RK-11</td><td>知识</td><td>知识库覆盖不足导致兜底率过高(&gt; 20%)</td><td><span class="intent-tag mid">中</span></td><td>体验与成本上升</td><td>监控兜底率;按回退日志补语料</td><td>AI 工程师</td></tr>
<tr><td>RK-12</td><td>知识</td><td>风控规则类文件误入库 → 风控参数泄露</td><td><span class="intent-tag high">高</span></td><td>合规风险</td><td>§1.6.3 明确不入库;<code>internal</code> 在切分阶段丢弃</td><td>AI 工程师</td></tr>
<tr><td>RK-13</td><td>进度</td><td>工期紧,测试时间被压缩</td><td><span class="intent-tag mid">中</span></td><td>交付质量下降</td><td>优先级裁剪从「跨 Agent 事件」与「SSE」开始降级</td><td>后端架构师</td></tr>
<tr><td>RK-14</td><td>进度</td><td><strong>项目无法启动</strong>(环境问题)</td><td><span class="intent-tag high">高</span></td><td>直接判负</td><td>环境自检脚本 + 提交前冷启动验证</td><td>后端架构师</td></tr>
<tr><td>RK-15</td><td>安全</td><td>可见性过滤被绕过(访客获取 <code>registered</code>)</td><td><span class="intent-tag high">高</span></td><td>内部信息泄露</td><td>fail-closed 签名 + 目录级单测 + §2.4 脚本一</td><td>AI 工程师</td></tr>
<tr><td>RK-16</td><td>体验</td><td>过滤导致召回不足,公开问题被误判「无答案」</td><td><span class="intent-tag mid">中</span></td><td>兜底率上升</td><td><strong>集合内分区裁剪</strong>(v2.5,取代 <code>top_k × 3</code> over-fetch)+ 监控过滤后为空的独立指标</td><td>AI 工程师</td></tr>
<tr><td>RK-17</td><td>合规</td><td>访客侧出现销售推介 / 无依据适当性结论</td><td><span class="intent-tag high">高</span></td><td>《销售管理办法》第十一条违规</td><td><strong>按主体分支</strong>的输出拦截 + 监控拦截次数</td><td>后端架构师</td></tr>
<tr><td>RK-18</td><td>体验/成本</td><td>访客限流阈值不当:过严误伤共享出口、过松失去防刷</td><td><span class="intent-tag mid">中</span></td><td>正常用户被 429 / 被刷量拖垮</td><td>IP 从严 + 令牌从宽 + 人机校验夹层;监控误伤率 &lt; 1%</td><td>后端架构师</td></tr>
<tr><td>RK-19</td><td>数据</td><td>访客身份被误当客户处理,污染客户指标或画像</td><td><span class="intent-tag high">高</span></td><td>披露口径失真 + 画像体系被绕过</td><td>不写 <code>sys_user</code>、不生成 <code>customer_id</code>;<strong>仓库层类型隔离</strong></td><td>AI 工程师</td></tr>
<tr><td>RK-20</td><td>一致性</td><td><strong>访客三元组两处定义不一致</strong>,改一处不生效</td><td><span class="intent-tag high">高</span></td><td>受理放行但执行失败(run 卡 <code>queued</code> 且无报错)</td><td>方案乙单点化(§1.8.4)+ 接缝单测</td><td>后端架构师</td></tr>
<tr><td>RK-21</td><td>范围</td><td><strong>投顾清除后失去第二条回归业务线</strong></td><td><span class="intent-tag mid">中</span></td><td>底座改动的回归验证只剩客服一条线</td><td>上调「测试环境就位」优先级;<strong>底座两组改动必须全量跑门禁</strong></td><td>全员</td></tr>
</tbody>
</table>
<h2 id="3.2-评分口径对齐">3.2 评分口径对齐</h2>
<table>
<thead><tr><th>评分项</th><th>权重 / 分值</th><th>本方案的对应动作</th></tr></thead>
<tbody>
<tr><td>基础设施与客服 Agent(P1)</td><td>15%</td><td>《执行 Todolist》全部批次;§2.2 十二项验收</td></tr>
<tr><td>功能完整性(占该 Phase 60%)</td><td>—</td><td><strong>§1.4 共 48 条功能需求</strong>逐条落地</td></tr>
<tr><td>代码质量(20%)</td><td>—</td><td>NFR-CS-012;Prompt 集中管理;类型注解与中文注释</td></tr>
<tr><td>文档规范(20%)</td><td>—</td><td>四份文档 + API 文档 + 入库清单 + 测试报告 + 会议纪要</td></tr>
<tr><td>加分:架构设计优秀</td><td>+5</td><td>意图分级流水线、合规双向钩子、跨集合回退、降级矩阵、<strong>身份/角色/档位三轴分离</strong></td></tr>
<tr><td>加分:RAG 效果优秀</td><td>+3</td><td>多轮指代消解、来源可溯源、阈值差异化</td></tr>
<tr><td>扣分:适当性违规</td><td>-10</td><td><strong>RK-06</strong> 对策:确定性过滤 + 强制用例</td></tr>
<tr><td>扣分:安全事故</td><td>-10</td><td>RK-08 / RK-09 / RK-15 对策 + 安全用例</td></tr>
<tr><td>扣分:项目无法启动</td><td>-20</td><td>RK-14 对策:冷启动自检</td></tr>
</tbody>
</table>
<hr>
<!-- ==================== 4 ==================== -->
<h1 id="4.-待确认事项与改进建议">4. 待确认事项、问题与改进建议</h1>
<h2 id="4.1-待确认事项清单">4.1 待确认事项清单</h2>
<table>
<thead><tr><th>#</th><th>事项</th><th>为何不能定论</th><th>影响</th><th>谁确认</th></tr></thead>
<tbody>
<tr><td colspan="5" style="background:rgba(198,40,40,0.06);font-weight:600;">一、阻塞类(不确认则不应动对应代码)</td></tr>
<tr><td><strong>T-01</strong></td><td><strong>Embedding 模型与向量维度(底座实况)</strong></td><td>底座实际配置未核对;示例值为 1024 维但<strong>不得假定</strong></td><td><strong>维度不一致导致检索结果无意义(静默错误)</strong></td><td>后端架构师</td></tr>
<tr><td><strong>T-02</strong></td><td><strong>三集合是否已存在及其 Schema</strong></td><td>决定「首次建集合」还是「改造既有」</td><td>决定是否需 <code>visibility</code> 回填与变更脚本</td><td>后端架构师</td></tr>
<tr><td><strong>T-03</strong></td><td><strong>RAG 基础设施的落位与签名</strong></td><td>《代码清理建议》未覆盖 RAG 基础设施</td><td><strong>影响面最大</strong>:决定检索是「改造既有签名」还是「新建入口」</td><td>后端架构师</td></tr>
<tr><td><strong>T-04</strong></td><td><strong>一期安全路由是否被二期完整覆盖(含关键词 diff)</strong></td><td>一期承载提示词注入与凭据泄露拦截,二期<strong>未逐条比对</strong></td><td><strong>若覆盖不全,删除一期路由将造成安全回归</strong>——这是全部动作中唯一带安全性的删除</td><td>安全/合规负责人</td></tr>
<tr><td><strong>T-05</strong></td><td><strong>访客三元组去重的授权</strong>(方案乙要改 4 个底座文件)</td><td>其中 3 个原在「零改动清单」内</td><td>不做则<strong>访客权限无法实时收紧</strong>、受理与执行身份可能不一致</td><td>项目负责人 + 底座 owner</td></tr>
<tr><td colspan="5" style="background:rgba(230,81,0,0.05);font-weight:600;">二、范围与内容类</td></tr>
<tr><td><strong>T-06</strong></td><td><strong>「金融行业基础信息」的知识源与归属集合</strong></td><td>MVP 游客线明确要求,但三集合不含且<strong>无源文件</strong></td><td><strong>游客线唯一内容缺口</strong></td><td>业务侧</td></tr>
<tr><td><strong>T-07</strong></td><td>访客是否可见产品参数</td><td>✅ <strong>2026-09-17 已定案:不可见</strong>。业务明确要求「访客智能询问公开的信息,<strong>不能询问产品参数</strong>」,本文档原「推断可见」的判定作废</td><td>已落地三处:① <code>D6.1.2-南方基金-高频问答对.md</code> §四 档位重划(<code>public</code> 54 条 / <code>registered</code> 10 条);② 《知识库设计方案》§4.2 档位定义表与决策项 4 同步修订;③ 访客令牌 <code>data_scope="public"</code> 在检索层拦截 <code>registered</code> 条目。判据 = 答案是否含「具体数值型产品要素」(费率 / 起投金额 / 收益率区间 / 规模 / 门槛金额 / 合作家数)</td><td>业务侧(已确认)</td></tr>
<tr><td><strong>T-08</strong></td><td>检索参数(三档阈值、<strong>档位边界</strong>)是否需按真实语料校准</td><td>阈值为形态推断值,未在真实语料验证;<strong>v2.5:over-fetch 因子已取消</strong></td><td>影响召回与兜底率</td><td>技术执行</td></tr>
<tr><td><strong>T-09</strong></td><td>演示用测试账号与数据</td><td>需可登录账号与配套数据</td><td>决定演示准备工作量</td><td>业务侧 + 技术</td></tr>
<tr><td><strong>T-10</strong></td><td>数据库表结构现状(<code>fin_knowledge_meta</code> 等是否已建)</td><td>决定入库第 7 步是新建还是复用</td><td>影响入库链路</td><td>后端架构师</td></tr>
<tr><td><strong>T-11</strong></td><td><code>config_release</code> 白名单是否仍列出<strong>已随投顾清除的工具名</strong></td><td>本机 active 配置未实测</td><td>若仍列出,调用会以「工具未注册」失败(fail-closed,不静默)</td><td>后端架构师</td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ 开工前必须闭环的四项</strong>:<strong>T-01 / T-02 / T-03</strong>(决定建集合与检索改造的形态,影响面最大)、<strong>T-04</strong>(唯一带安全性的删除动作)、<strong>T-05</strong>(底座接触面授权的纪律前置)。其余可并行确认,不阻塞开工。</p></blockquote>
<h2 id="4.2-已识别的问题及处理状态">4.2 已识别的问题及处理状态</h2>
<table>
<thead><tr><th>#</th><th>问题</th><th>影响</th><th>状态</th></tr></thead>
<tbody>
<tr><td>P-01</td><td>目录落位曾与底座不符(v2.1 按「新建模块」假定路径)</td><td>会新建并行目录,违反「不新增架构层」</td><td>✅ v2.2 已修正</td></tr>
<tr><td>P-02</td><td>文档定位曾偏差(按「新建模块」而非「重构既有实现」)</td><td>漏掉「复用既有能力」,导致重复实现</td><td>✅ v2.2 已修正</td></tr>
<tr><td>P-03</td><td>「查持仓」表述看似矛盾</td><td>可能误开持仓查询能力</td><td>✅ v2.2 已辨明(自助界面为唯一入口)</td></tr>
<tr><td>P-04</td><td>适当性「过滤」与「告知」看似冲突</td><td>可能误删过滤逻辑</td><td>✅ v2.2 已辨明(§1.6.1)</td></tr>
<tr><td>P-05</td><td>术语不统一(「访客」vs「游客」)</td><td>误认为两个角色</td><td>✅ 已加术语对照(§0.3)</td></tr>
<tr><td>P-06</td><td>客群分层 vs「不做卡级体系」的张力</td><td>误实现分层分派与升降级</td><td>✅ 已说明(§1.2.2)</td></tr>
<tr><td><strong>P-07</strong></td><td><strong>FR-CS-041 的前提表 <code>conversation_archive</code> 在库中不存在</strong>,但正文仍按其设计变更流程</td><td>照此实施会走向一套无对象的数据库变更</td><td>✅ <strong>v2.4 已修正</strong>(FR-CS-041 重写;原容器变更流程作废)</td></tr>
<tr><td><strong>P-08</strong></td><td><strong>§8.2 任务表用的仍是被 §8.1 判定为错误的路径</strong>(<code>app/api/chat.py</code>、<code>customer_agent.py</code>、<code>intent_router.py</code> 等)</td><td>照此施工会建出一套并行结构</td><td>✅ <strong>v2.4 已修正</strong>——任务与排期<strong>整体移交《开发计划》与《执行 Todolist》</strong>,按真实落位重写</td></tr>
<tr><td><strong>P-09</strong></td><td><strong>§8.1.1「不触碰 <code>base.py</code>」与 §1.8 要改 <code>base.py</code> 互斥</strong></td><td>实施时口径不明</td><td>✅ <strong>v2.4 已裁定</strong>:<code>base.py</code> <strong>允许触碰,但仅限谓词替换</strong>(位置与层级不变,见不变量②);其余部分仍不触碰</td></tr>
<tr><td>P-10</td><td>品牌占位(<strong>原</strong> <code>XX科技</code> / <code>400-XXX-XXXX</code>)与实际素材并存</td><td>品牌混用</td><td>✅ 已处置:品牌配置化 + 硬编码扫描;<strong>2026-09-17 全量口径统一为「南方基金」</strong></td></tr>
<tr><td>P-11</td><td>数据条数口径不一致(文中「10 张表」vs §5.1 实际 8 张)</td><td>误导实施范围</td><td>✅ v2.4 已按 8 张修正</td></tr>
<tr><td><strong>P-12</strong></td><td><strong>投顾相关内容残留</strong>(业务基线三线、九步主干、工单投顾可见、产品证据链归属、灰度闸门)</td><td>指向已删除的模块</td><td>✅ <strong>v2.4 已清理</strong>(§1.9 / T-12 / T-13 / T-15 / I-02 / I-03 / I-07 / RK-10)</td></tr>
</tbody>
</table>
<h2 id="4.3-改进建议">4.3 改进建议</h2>
<table>
<thead><tr><th>#</th><th>建议</th><th>理由</th><th>优先级</th></tr></thead>
<tbody>
<tr><td>J-01</td><td><strong>先做关键词安全 diff,再动任何路由代码</strong></td><td>唯一可能造成安全回归的删除(T-04)</td><td><span class="pill p0">P0</span></td></tr>
<tr><td>J-02</td><td><strong>先核对 RAG 基础设施签名,再动检索相关代码</strong></td><td>检索入口只能有一个(T-03)</td><td><span class="pill p0">P0</span></td></tr>
<tr><td>J-03</td><td>把「不生成交易指令」落为<strong>入库审查规则</strong></td><td>红线 3 只在生成侧拦截不够,须在入库 SOP 增「可执行要素检查」</td><td><span class="pill p0">P0</span></td></tr>
<tr><td>J-04</td><td>补「金融行业基础信息」知识源并明确归属集合</td><td>补游客线唯一内容缺口(T-06)</td><td><span class="pill p1">P1</span></td></tr>
<tr><td>J-05</td><td>在真实语料上校准三档阈值<strong>与档位划分</strong></td><td>阈值为推断值(T-08);v2.5 起校准对象为阈值 + 档位边界</td><td><span class="pill p1">P1</span></td></tr>
<tr><td>J-06</td><td>把档位规则表纳入版本控制</td><td>规则表是「重建知识库能力」的关键资产</td><td><span class="pill p1">P1</span></td></tr>
<tr><td>J-07</td><td>保留既有实现的注释</td><td>这些注释质量高、含大量「为什么这么写」的决策记录,是重要设计依据</td><td><span class="pill p1">P1</span></td></tr>
<tr><td>J-08</td><td><strong>造一条 <code>registered</code> 测试块</strong></td><td>否则「三档已接通」不可证伪(§2.2)</td><td><span class="pill p1">P1</span></td></tr>
<tr><td>J-09</td><td>修复上游 <code>D7.1-需求文档.html</code> 的失效目录锚点</td><td>目录是主要导航方式</td><td><span class="pill p2">P2</span></td></tr>
</tbody>
</table>
<hr>
<!-- ==================== 附录 ==================== -->
<h1 id="附录-双主体差异对照表">附录 双主体(访客 / 客户)差异对照表</h1>
<table>
<thead><tr><th>#</th><th>维度</th><th>访客</th><th>客户</th></tr></thead>
<tbody>
<tr><td>1</td><td>鉴权</td><td>匿名令牌(15 分钟)</td><td>登录 JWT</td></tr>
<tr><td>2</td><td><code>subject_type</code>(目标)</td><td><code>guest</code></td><td><code>customer</code></td></tr>
<tr><td>3</td><td>令牌是否带权限</td><td>否(目标模型;现状由 claim 生成,属待消除的例外)</td><td>否(令牌只带 id)</td></tr>
<tr><td>4</td><td><code>roles</code>(现状)</td><td><code>("visitor",)</code></td><td><code>("customer",)</code></td></tr>
<tr><td>5</td><td><code>roles</code>(目标)</td><td><strong>空</strong>(不进入角色体系)</td><td><code>("customer",)</code></td></tr>
<tr><td>6</td><td>权限</td><td><code>agent:run</code> + <code>knowledge:query</code></td><td>按 RBAC</td></tr>
<tr><td>7</td><td><code>data_scope</code></td><td><code>"public"</code>(<strong>语义标注,勿改</strong>)</td><td><code>self</code>(按权限可升)</td></tr>
<tr><td>8</td><td>知识档位</td><td><code>{public}</code></td><td><code>{public, registered}</code></td></tr>
<tr><td>9</td><td><code>conversation_message.customer_id</code></td><td><strong>空</strong></td><td><code>= user_id</code></td></tr>
<tr><td>10</td><td>会话 TTL</td><td>30 分钟,<strong>不续期</strong></td><td>30 分钟,续期至最长 24 小时</td></tr>
<tr><td>11</td><td>Token 预算</td><td><strong>2048</strong></td><td><strong>4096</strong></td></tr>
<tr><td>12</td><td><strong>长期记忆召回</strong>(<code>memory_unit</code> / <code>user_facts</code>)</td><td><strong>关闭</strong>(访客无 <code>customer_id</code> 可召回,基类兜底)</td><td><strong>关闭召回</strong>——收益方(投顾)已整体清除;注入生成上下文与证据约束生成直接冲突</td></tr>
<tr><td>13</td><td>销售推介</td><td><strong>强制禁止</strong>(改写为中性披露)</td><td>允许信息披露,禁止承诺</td></tr>
<tr><td>14</td><td>适当性输出</td><td>仅公开规则,<strong>无个性化结论</strong></td><td>可给本人匹配结论 + 不匹配提示</td></tr>
<tr><td>15</td><td>账户类提问</td><td><code>auth_required</code> → 登录/开户引导</td><td>正常受理(经自助界面)</td></tr>
<tr><td>16</td><td>转人工通道</td><td><code>sub_type='guest_presales'</code></td><td><code>sub_type='customer_aftersales'</code></td></tr>
<tr><td>17</td><td>限流</td><td>IP + 令牌双维度</td><td>按用户维度</td></tr>
<tr><td>18</td><td>画像候选</td><td><strong>不产生</strong></td><td><strong>关闭</strong>——不得绕过 <code>evidence ≥ 2</code> / <code>confidence ≥ 0.90</code> 与 <code>FM-01</code>~<code>FM-05</code> 熔断</td></tr>
<tr><td>19</td><td>审计副作用</td><td><code>target_customer_id</code> 保持 <code>NULL</code></td><td>正常写</td></tr>
<tr><td>20</td><td>前端入口</td><td>公开首页 / 产品页浮窗</td><td>客户工作台浮窗</td></tr>
<tr><td>21</td><td><strong>画像字段级读取</strong>(<code>risk_level</code> / <code>customer_level</code>)</td><td><strong>不适用</strong>(访客无画像)</td><td><strong>只读,且仅用于确定性规则</strong>(适当性过滤 / 转人工优先级 / 画像问答字段直返);<strong>禁止把画像原文注入生成上下文</strong></td></tr>
</tbody>
</table>
<blockquote class="callout-warn"><p><strong>⚠️ 「记忆关闭」的准确含义(本轮澄清)</strong>:本表第 12 项易被读成「客户侧画像完全不可读」,与本文档主体模型(客户可查<strong>自己的画像与风评</strong>)及 <code>FR-CS-024</code>(转人工摘要含<strong>画像关键标签</strong>)冲突。准确口径是<strong>三件独立的事</strong>:① <strong>短期会话记忆=开(读 / 写)</strong>——多轮连贯与指代消解的前提;② <strong>长期记忆召回(<code>memory_unit</code> / <code>user_facts</code>)=关</strong>——收益方投顾已清除,且注入生成上下文会引入检索证据之外的内容;③ <strong>画像=客户侧字段级只读</strong>(仅 <code>risk_level</code> / <code>customer_level</code> 两个字段,供确定性规则),<strong>不进生成上下文</strong>。完整版 <code>D3.1</code> §3.5 已同步该口径。</p></blockquote>
<blockquote class="callout-info"><p><strong>📌 使用说明</strong>:本表可直接作为联调核对清单——每实现一个维度,对照两列分别验证一次。<strong>第 3、5、8、9、12、17 项是最容易实现错的六项</strong>,建议优先复核。</p></blockquote>
<hr>
<blockquote class="callout-info"><p><strong>文档结束</strong> —— 本文档为《南方基金·智能服务系统》智能客服 Agent 的<strong>需求文档 v2.5</strong>,是四份交付文档的「需求」分册。配套:《客服 Agent 开发计划》《客服 Agent 执行 Todolist》《客服 Agent 知识库设计方案》。上游依据见 §0.2;冲突裁决优先级见 §0.2 callout;如后续需求变更,须同步修订本文档并记录版本(见 §0.4)。</p></blockquote>
</div><!-- end doc-container -->
</main>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'base',
themeVariables: {
primaryColor: '#e3f2fd',
primaryTextColor: '#1e293b',
primaryBorderColor: '#1976d2',
lineColor: '#64748b',
secondaryColor: '#fff3e0',
tertiaryColor: '#f4f1eb',
fontFamily: 'Inter, sans-serif',
fontSize: '14px',
},
flowchart: { curve: 'basis', padding: 15 },
securityLevel: 'loose',
});
// ── Progress bar ──
const bar = document.getElementById('progress-bar');
function updateProgress() {
const h = document.documentElement;
const pct = ((h.scrollTop) / (h.scrollHeight - h.clientHeight)) * 100;
bar.style.width = Math.min(100, pct) + '%';
}
window.addEventListener('scroll', updateProgress);
// ── Topbar title ──
const topbarTitle = document.getElementById('topbar-title');
const headings = document.querySelectorAll('.doc-container h1[id], .doc-container h2[id], .doc-container h3[id], .doc-container h4[id]');
function updateTopbar() {
let current = '';
headings.forEach(h => {
if (h.getBoundingClientRect().top <= 120) current = h.textContent;
});
if (current) topbarTitle.textContent = current;
}
window.addEventListener('scroll', updateTopbar);
// ── TOC active state ──
const tocLinks = document.querySelectorAll('.toc-item');
function updateToc() {
let activeId = '';
headings.forEach(h => {
if (h.getBoundingClientRect().top <= 120) activeId = h.id;
});
tocLinks.forEach(link => {
link.classList.toggle('active', link.getAttribute('href') === '#' + activeId);
});
}
window.addEventListener('scroll', updateToc);
// ── Collapsible TOC groups ──
document.querySelectorAll('.toc-toggle').forEach(btn => {
btn.addEventListener('click', () => {
const kids = btn.nextElementSibling;
const arr = btn.querySelector('.arr');
btn.classList.toggle('active');
kids.classList.toggle('open');
arr.classList.toggle('open');
});
});
// ── TOC search ──
const tocSearch = document.getElementById('toc-search');
tocSearch.addEventListener('input', () => {
const q = tocSearch.value.toLowerCase();
document.querySelectorAll('.toc-item, .toc-toggle').forEach(item => {
item.style.display = (!q || item.textContent.toLowerCase().includes(q)) ? '' : 'none';
});
});
// ── Initial ──
updateProgress();
updateTopbar();
updateToc();
</script>
</body>
</html>