497 lines
19 KiB
Markdown
497 lines
19 KiB
Markdown
# 语音通话模块重构方案 — KB直出 + 重排 + Redis上下文
|
||
|
||
> 版本:1.0 | 日期:2026-03-24
|
||
|
||
---
|
||
|
||
## 1. 现状分析
|
||
|
||
### 1.1 当前 KB 查询链路
|
||
|
||
```
|
||
ASR final
|
||
→ realtimeDialogRouting.resolveReply()
|
||
→ ToolExecutor.searchKnowledge()
|
||
→ rewriteKnowledgeQuery() // query改写
|
||
→ searchArkKnowledge() // ★ 核心瓶颈
|
||
┌──────────────────────────────────────────────┐
|
||
│ POST ark.cn-beijing.volces.com │
|
||
│ /api/v3/chat/completions │
|
||
│ │
|
||
│ model: Seed-2.0-lite (ep-xxx) │
|
||
│ metadata.knowledge_base: { dataset_ids, ... }│
|
||
│ max_tokens: 80 │
|
||
│ thinking: disabled │
|
||
│ │
|
||
│ → 1. 向量检索 top_k=3 chunks │
|
||
│ → 2. LLM 基于 chunks 生成回答文本(80 tokens)│ ← 要去掉
|
||
└──────────────────────────────────────────────┘
|
||
→ classifyKnowledgeAnswer() // 判断 hit/no-hit
|
||
→ external_rag (event 502) // 注入 S2S
|
||
→ S2S 基于 RAG 内容合成语音
|
||
```
|
||
|
||
### 1.2 痛点
|
||
|
||
| 痛点 | 说明 |
|
||
|------|------|
|
||
| **LLM 加工多余** | KB 检索后还经过 Seed-2.0-lite 生成 80 tokens 回答,增加 ~1-2s 延迟,且回答被模型"改写",不够原汁原味 |
|
||
| **无重排** | 向量检索 top_k=3 直接使用,靠 threshold=0.3 卡阈值,相关性排序不够精准 |
|
||
| **上下文断裂** | S2S 仅接收单次 RAG 内容,不知道前几轮聊了什么,多轮追问体验差 |
|
||
| **context 来源慢** | 上下文从 MySQL `getRecentMessages()` 获取,单次 50-200ms |
|
||
| **内存缓存不可靠** | KB 缓存用 Node.js `Map`,进程重启即丢失,PM2 多实例不共享 |
|
||
|
||
---
|
||
|
||
## 2. 重构目标
|
||
|
||
```
|
||
ASR final
|
||
→ resolveReply()
|
||
→ rewriteKnowledgeQuery()
|
||
→ ★ 方舟 KB 纯检索(返回原始 chunks,不经 LLM 加工)
|
||
→ ★ 重排模型(reranker)对 chunks 按相关性排序
|
||
→ 取 top 3 reranked chunks
|
||
→ ★ 从 Redis 读取最近 5 轮对话
|
||
→ 构建 external_rag payload:{ chunks + conversation_context }
|
||
→ event 502 注入 S2S
|
||
→ S2S 结合上下文 + KB 原始片段,自主生成回答并合成语音
|
||
```
|
||
|
||
### 核心改变
|
||
|
||
| 项目 | 现状 | 目标 |
|
||
|------|------|------|
|
||
| KB 检索 | chat/completions + knowledge_base metadata(检索+生成一体) | 纯检索 API,只返回原始 chunks |
|
||
| 回答生成 | Seed-2.0-lite 生成 80 tokens | 去掉,由 S2S 直接基于 RAG 内容生成 |
|
||
| 重排 | 无 | 方舟重排模型,对检索结果排序 |
|
||
| 上下文存储 | MySQL + Node.js 内存 Map | Redis(最近 5 轮 = 10 条消息) |
|
||
| S2S 输入 | 单条 RAG 回答文本 | 3 条原始 KB 片段 + 5 轮对话上下文 |
|
||
|
||
---
|
||
|
||
## 3. 改动全景图
|
||
|
||
```
|
||
涉及文件 改动类型 改动量级 说明
|
||
─────────────────────────────────────────────────────────
|
||
新增文件
|
||
services/redisClient.js 新增 ~120行 Redis 连接管理 + 对话读写
|
||
services/kbRetriever.js 新增 ~200行 KB 纯检索 + 重排 + 结果组装
|
||
|
||
修改文件
|
||
toolExecutor.js 重构 大 searchArkKnowledge → 调用 kbRetriever
|
||
nativeVoiceGateway.js 修改 中 persist* 同步写 Redis;sendExternalRag 注入上下文
|
||
realtimeDialogRouting.js 修改 小 resolveReply 适配新返回格式
|
||
package.json 修改 小 添加 ioredis 依赖
|
||
.env / .env.example 修改 小 新增 Redis + 重排模型配置
|
||
|
||
不动的文件
|
||
realtimeDialogProtocol.js 不动 event 502 协议格式不变
|
||
knowledgeKeywords.js 不动 关键词路由不变
|
||
contextKeywordTracker.js 不动 关键词追踪不变
|
||
contentSafeGuard.js 不动 内容安全不变
|
||
fastAsrCorrector.js 不动 ASR纠错不变
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 详细设计
|
||
|
||
### Phase 1:Redis 基础设施
|
||
|
||
#### 4.1 新增 `services/redisClient.js`
|
||
|
||
**职责**:Redis 连接管理 + 对话历史读写
|
||
|
||
```
|
||
功能清单:
|
||
├── createRedisClient() // 连接管理,断线重连,错误日志
|
||
├── pushMessage(sessionId, msg) // LPUSH + LTRIM 保留最近 10 条
|
||
├── getRecentHistory(sessionId) // LRANGE 获取最近 5 轮(10 条)
|
||
├── clearSession(sessionId) // DEL 清理
|
||
└── setKbCache / getKbCache // KB 结果缓存(替代内存 Map)
|
||
```
|
||
|
||
**数据结构设计**:
|
||
|
||
```
|
||
Key: voice:history:{sessionId}
|
||
Type: List
|
||
Items: JSON string → { role, content, source, timestamp }
|
||
MaxLen: 10 (5轮 × 2条/轮)
|
||
TTL: 1800s (30分钟)
|
||
|
||
Key: voice:kb_cache:{cacheKey}
|
||
Type: String (JSON)
|
||
TTL: 300s (hit) / 120s (no-hit)
|
||
```
|
||
|
||
**降级策略**:Redis 不可用时,自动降级到当前的内存 Map + MySQL 方案,不阻塞主链路。
|
||
|
||
#### 4.2 环境变量
|
||
|
||
```env
|
||
# Redis
|
||
REDIS_URL=redis://127.0.0.1:6379
|
||
REDIS_PASSWORD=
|
||
REDIS_DB=0
|
||
REDIS_KEY_PREFIX=bigwo:
|
||
|
||
# 重排模型
|
||
VOLC_ARK_RERANKER_ENDPOINT_ID=ep-xxxxxxxx
|
||
VOLC_ARK_RERANKER_TOP_N=3
|
||
|
||
# KB 纯检索(替代 chat/completions)
|
||
VOLC_ARK_KB_RETRIEVAL_MODE=raw
|
||
# 可选值: raw(纯检索,本次启用)| answer(当前模式,保留降级用)
|
||
```
|
||
|
||
#### 4.3 依赖
|
||
|
||
```json
|
||
{
|
||
"ioredis": "^5.4.0"
|
||
}
|
||
```
|
||
|
||
选 `ioredis` 而非 `redis`:自动重连、Sentinel/Cluster 原生支持、性能更好。
|
||
|
||
---
|
||
|
||
### Phase 2:KB 检索改造
|
||
|
||
#### 4.4 新增 `services/kbRetriever.js`
|
||
|
||
**职责**:KB 纯检索 + 重排 + 结果组装(替代 `searchArkKnowledge` 中的检索+生成一体逻辑)
|
||
|
||
```
|
||
功能清单:
|
||
├── retrieveChunks(query, datasetIds, topK) // 纯向量检索,返回原始 chunks
|
||
├── rerankChunks(query, chunks, topN) // 重排模型调用
|
||
├── buildRagPayload(chunks, history) // 组装 external_rag 载荷
|
||
└── searchAndRerank(query, opts) // 主入口:检索 → 重排 → 组装
|
||
```
|
||
|
||
**核心流程**:
|
||
|
||
```
|
||
searchAndRerank(query, { datasetIds, sessionId, session })
|
||
│
|
||
├─ 1. retrieveChunks(query, datasetIds, topK=10)
|
||
│ POST /api/v3/chat/completions
|
||
│ model: 最轻量模型
|
||
│ metadata.knowledge_base: { dataset_ids, top_k: 10, threshold: 0.1 }
|
||
│ max_tokens: 1 ← 关键:只要1个token,目的是触发检索
|
||
│ stream: false
|
||
│ ※ 从 response 中提取 references/chunks 字段
|
||
│ ※ 如果方舟API不在response中返回原始chunks:
|
||
│ → 降级方案:用 snippet 模式 prompt 让模型返回原文
|
||
│ → 或调用方舟知识库独立检索API(如有)
|
||
│
|
||
├─ 2. rerankChunks(query, chunks, topN=3)
|
||
│ POST /api/v3/chat/completions(或 /api/v3/rerank)
|
||
│ model: reranker-endpoint-id
|
||
│ 输入:query + documents[]
|
||
│ 输出:按相关性排序的 chunks + scores
|
||
│ 超时:3s
|
||
│ 降级:重排失败时直接使用原始检索排序
|
||
│
|
||
├─ 3. getRecentHistory(sessionId) ← 从 Redis
|
||
│ 返回最近 5 轮对话
|
||
│
|
||
└─ 4. buildRagPayload(top3Chunks, history)
|
||
组装 ragItems[]:
|
||
[
|
||
{ title: "对话上下文", content: "用户: xxx\n助手: xxx\n..." },
|
||
{ title: "知识库片段1", content: chunk1.content },
|
||
{ title: "知识库片段2", content: chunk2.content },
|
||
{ title: "知识库片段3", content: chunk3.content },
|
||
]
|
||
```
|
||
|
||
#### 4.5 关于方舟 KB 纯检索的技术方案
|
||
|
||
方舟 `chat/completions` + `knowledge_base` 的 response 结构中,`choices[0].message` 包含 LLM 生成的回答,但**原始检索 chunks 可能在 `references` 字段中返回**(取决于方舟版本)。
|
||
|
||
需要验证的关键点:
|
||
|
||
```
|
||
方案 A(优先):方舟 response 中有 references 字段
|
||
→ response.data.references = [{ content, score, doc_name, ... }, ...]
|
||
→ 直接提取,不用 choices[0].message.content
|
||
|
||
方案 B(备选):方舟有独立的知识库检索 API
|
||
→ POST /api/v3/knowledge-base/retrieve 或类似端点
|
||
→ 纯向量检索 + BM25,不经 LLM
|
||
|
||
方案 C(保底):利用 snippet 模式 prompt 提取原文
|
||
→ system prompt = "原样输出检索到的所有文档片段,不改写不总结"
|
||
→ max_tokens = 500
|
||
→ 解析输出为独立 chunks
|
||
```
|
||
|
||
**建议**:先用方案 A 验证 `references` 字段是否存在;若不存在,采用方案 B 或 C。
|
||
|
||
#### 4.6 重排模型选型
|
||
|
||
| 模型 | 延迟(估) | 精度 | 建议 |
|
||
|------|----------|------|------|
|
||
| bge-reranker-v2-m3 | ~200ms | 高 | 首选,多语言支持好 |
|
||
| bge-reranker-large | ~150ms | 较高 | 备选 |
|
||
| cohere-rerank-v3 | ~300ms | 最高 | 如果方舟支持 |
|
||
|
||
需要在方舟平台创建重排模型的推理接入点。
|
||
|
||
---
|
||
|
||
### Phase 3:S2S 上下文注入
|
||
|
||
#### 4.7 修改 `nativeVoiceGateway.js`
|
||
|
||
**改动 1:`persistUserSpeech` / `persistAssistantSpeech` 同步写 Redis**
|
||
|
||
```
|
||
persistUserSpeech(session, text)
|
||
├─ 原有逻辑不变(MySQL + 字幕推送)
|
||
└─ 新增:redisClient.pushMessage(sessionId, { role: 'user', content: text })
|
||
|
||
persistAssistantSpeech(session, text, opts)
|
||
├─ 原有逻辑不变
|
||
└─ 新增:redisClient.pushMessage(sessionId, { role: 'assistant', content: text })
|
||
```
|
||
|
||
**改动 2:`sendExternalRag` 接受新格式**
|
||
|
||
```
|
||
现状:sendExternalRag(session, [{ title, content }])
|
||
→ 直接发 event 502
|
||
|
||
新增:注入上下文到 ragItems
|
||
→ ragItems 前置一条 { title: "对话上下文", content: "最近5轮..." }
|
||
→ 再跟 3 条 KB 片段
|
||
→ 发 event 502
|
||
```
|
||
|
||
#### 4.8 修改 `realtimeDialogRouting.js` — `resolveReply`
|
||
|
||
```
|
||
现状 resolveReply:
|
||
→ ToolExecutor.execute('search_knowledge', { response_mode: 'answer', ... })
|
||
→ extractToolResultText → 得到 LLM 生成的回答文本
|
||
→ delivery: 'external_rag', ragItems: [{ content: LLM回答 }]
|
||
|
||
改为:
|
||
→ kbRetriever.searchAndRerank(query, { sessionId, session, datasetIds })
|
||
→ 返回 { chunks: [...], rerankedChunks: [...], history: [...], ragPayload: [...] }
|
||
→ delivery: 'external_rag', ragItems: ragPayload(已包含上下文 + 3个原始片段)
|
||
```
|
||
|
||
#### 4.9 修改 `toolExecutor.js`
|
||
|
||
```
|
||
现状 searchKnowledge:
|
||
→ searchArkKnowledge() → LLM 加工 → classifyKnowledgeAnswer()
|
||
|
||
改为:
|
||
→ kbRetriever.searchAndRerank() → 纯检索 + 重排
|
||
→ 判断 hit/no-hit 改为基于 reranker score 阈值
|
||
→ 不再调用 classifyKnowledgeAnswer()(因为没有 LLM 生成的回答文本了)
|
||
```
|
||
|
||
---
|
||
|
||
### Phase 4:清理与适配
|
||
|
||
#### 4.10 可移除/简化的代码
|
||
|
||
| 位置 | 内容 | 原因 |
|
||
|------|------|------|
|
||
| `toolExecutor.js` L925-946 | system prompt 构建(baseAnswerPrompt, buildQuestionSlotInstruction等) | 不再需要 LLM 生成回答 |
|
||
| `toolExecutor.js` L953-966 | chat/completions body 构建(max_tokens:80, thinking:disabled) | 改为纯检索调用 |
|
||
| `toolExecutor.js` L981-996 | classifyKnowledgeAnswer() 调用 | 改为 reranker score 判断 |
|
||
| `toolExecutor.js` L47-74 | 内存 kbQueryCache Map | 迁移到 Redis |
|
||
| `realtimeDialogRouting.js` L275 | `normalizeTextForSpeech(replyText).replace(...)` 去除"根据知识库" | 不再有 LLM 加工文本 |
|
||
|
||
#### 4.11 保留不动的模块
|
||
|
||
| 模块 | 原因 |
|
||
|------|------|
|
||
| KB 保护窗口(60s) | 多轮追问保护仍有价值 |
|
||
| shouldForceKnowledgeRoute | 路由判断逻辑不受影响 |
|
||
| prequery 预查询 | 仍然有效,改为调用 kbRetriever |
|
||
| ASR 纠错 + 词表 | 与 KB 检索解耦 |
|
||
| HOT_ANSWERS | 保留作为 0ms 极速响应,但需标记来源 |
|
||
| 品牌保护兜底(传销问题) | 安全需求,保留 |
|
||
| 助手资料系统 | 与 KB 检索解耦 |
|
||
|
||
---
|
||
|
||
## 5. 数据流对比
|
||
|
||
### 5.1 现状(LLM 加工模式)
|
||
|
||
```
|
||
用户: "小红产品怎么吃?"
|
||
↓
|
||
searchArkKnowledge()
|
||
→ Ark API: model=Seed-2.0-lite, max_tokens=80
|
||
→ KB 检索到 3 chunks + LLM 生成回答:
|
||
"小红Activize的服用方法是兑100-150ml温水,小口慢饮,建议在大白之后15-30分钟。"
|
||
↓
|
||
event 502: [{ title: "知识库结果", content: "小红Activize的服用方法..." }]
|
||
↓
|
||
S2S 合成语音播报(S2S 不知道前几轮聊了什么)
|
||
```
|
||
|
||
### 5.2 重构后(直出 + 重排 + 上下文模式)
|
||
|
||
```
|
||
用户: "小红产品怎么吃?"
|
||
↓
|
||
kbRetriever.searchAndRerank()
|
||
→ 纯检索: top_k=10, threshold=0.1 → 得到 10 个原始 chunks
|
||
→ 重排: reranker 对 10 chunks 排序 → 取 top 3
|
||
→ Redis: 取最近 5 轮对话
|
||
↓
|
||
event 502: [
|
||
{ title: "对话上下文",
|
||
content: "用户: 你们有什么产品?\n助手: 我们有基础三合一...\n用户: 小红是什么?\n助手: 小红是Activize Oxyplus..." },
|
||
{ title: "知识库片段1",
|
||
content: "Activize Oxyplus(小红):水溶性CoQ10+维生素B族+瓜拉那提取物..." },
|
||
{ title: "知识库片段2",
|
||
content: "基础三合一服用方法:大白空腹→小红15-30分钟后→小白睡前..." },
|
||
{ title: "知识库片段3",
|
||
content: "小红用法:兑100-150ml温水,小口慢饮。水温不超过40度..." },
|
||
]
|
||
↓
|
||
S2S 基于上下文 + 3个原始片段自主生成自然口语回答,合成语音
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 延迟预估
|
||
|
||
| 环节 | 现状 | 重构后 | 变化 |
|
||
|------|------|--------|------|
|
||
| query 改写 | ~5ms | ~5ms | 不变 |
|
||
| KB 检索 | ~2000ms(检索+LLM生成) | ~800ms(纯检索) | ↓60% |
|
||
| 重排 | 无 | ~200ms | 新增 |
|
||
| Redis 读上下文 | 无(MySQL ~100ms) | ~5ms | ↓95% |
|
||
| 组装 payload | ~1ms | ~2ms | 不变 |
|
||
| **总计** | **~2300ms** | **~1000ms** | **↓56%** |
|
||
|
||
> 注意:S2S 接收到更丰富的 RAG 内容后,语音合成可能略增,但整体用户体验(首字节到达时间)应显著改善。
|
||
|
||
---
|
||
|
||
## 7. 风险与降级
|
||
|
||
| 风险 | 概率 | 影响 | 降级方案 |
|
||
|------|------|------|----------|
|
||
| 方舟 API 不返回原始 chunks(无 references 字段) | 中 | 高 | 用 snippet prompt + max_tokens=500 提取原文 |
|
||
| 重排模型部署/调用失败 | 低 | 中 | 跳过重排,直接使用检索排序 |
|
||
| Redis 连接失败 | 低 | 中 | 降级到内存 Map + MySQL |
|
||
| S2S 处理多条 RAG 片段质量下降 | 中 | 高 | A/B 测试对比,保留旧模式开关 |
|
||
| Redis 内存溢出 | 低 | 低 | TTL=30min + maxmemory-policy=allkeys-lru |
|
||
|
||
### 关键降级开关
|
||
|
||
```env
|
||
# .env 中控制
|
||
VOLC_ARK_KB_RETRIEVAL_MODE=raw # raw | answer(旧模式)
|
||
ENABLE_RERANKER=true # true | false
|
||
ENABLE_REDIS_CONTEXT=true # true | false
|
||
```
|
||
|
||
每个新能力可独立关闭,回退到当前行为。
|
||
|
||
---
|
||
|
||
## 8. 实施计划
|
||
|
||
### 阶段一:基础设施(1天)
|
||
|
||
| # | 任务 | 文件 | 预估 |
|
||
|---|------|------|------|
|
||
| 1.1 | 安装 ioredis 依赖 | package.json | 5min |
|
||
| 1.2 | 新建 redisClient.js,实现连接管理 + pushMessage + getRecentHistory | services/redisClient.js | 2h |
|
||
| 1.3 | .env 增加 Redis 配置 | .env, .env.example | 10min |
|
||
| 1.4 | 服务器安装 Redis(宝塔一键装) | 运维 | 30min |
|
||
| 1.5 | 验证 Redis 连接 + 读写 | 手动测试 | 30min |
|
||
|
||
### 阶段二:Redis 对话存储接入(0.5天)
|
||
|
||
| # | 任务 | 文件 | 预估 |
|
||
|---|------|------|------|
|
||
| 2.1 | persistUserSpeech 增加 Redis 写入 | nativeVoiceGateway.js | 30min |
|
||
| 2.2 | persistAssistantSpeech 增加 Redis 写入 | nativeVoiceGateway.js | 30min |
|
||
| 2.3 | resolveReply 中的 getRecentMessages 改为优先读 Redis | realtimeDialogRouting.js | 1h |
|
||
| 2.4 | KB 缓存迁移到 Redis(替代内存 Map) | toolExecutor.js, redisClient.js | 1h |
|
||
|
||
### 阶段三:KB 纯检索 + 重排(1.5天)
|
||
|
||
| # | 任务 | 文件 | 预估 |
|
||
|---|------|------|------|
|
||
| 3.1 | 方舟 API 验证:确认 references 字段是否可用 | 手动测试 | 2h |
|
||
| 3.2 | 新建 kbRetriever.js:retrieveChunks 实现 | services/kbRetriever.js | 3h |
|
||
| 3.3 | 方舟部署重排模型,获取 endpoint_id | 方舟控制台 | 1h |
|
||
| 3.4 | kbRetriever.js:rerankChunks 实现 | services/kbRetriever.js | 2h |
|
||
| 3.5 | kbRetriever.js:buildRagPayload + searchAndRerank 主流程 | services/kbRetriever.js | 2h |
|
||
| 3.6 | toolExecutor.js 改造:searchKnowledge 调用 kbRetriever | toolExecutor.js | 2h |
|
||
|
||
### 阶段四:S2S 注入适配(0.5天)
|
||
|
||
| # | 任务 | 文件 | 预估 |
|
||
|---|------|------|------|
|
||
| 4.1 | resolveReply 适配新的 ragItems 格式(多片段 + 上下文) | realtimeDialogRouting.js | 1h |
|
||
| 4.2 | sendExternalRag 验证多 items 发送 | nativeVoiceGateway.js | 1h |
|
||
| 4.3 | hit/no-hit 判断改为 reranker score 阈值 | kbRetriever.js | 1h |
|
||
|
||
### 阶段五:测试 + 部署(1天)
|
||
|
||
| # | 任务 | 说明 | 预估 |
|
||
|---|------|------|------|
|
||
| 5.1 | 单元测试:kbRetriever、redisClient | tests/ | 2h |
|
||
| 5.2 | 集成测试:端到端语音对话验证 | 真机测试 | 2h |
|
||
| 5.3 | A/B 对比:旧模式 vs 新模式(延迟、回答质量) | 测试脚本 | 2h |
|
||
| 5.4 | 部署到生产 | deploy 脚本 | 1h |
|
||
|
||
**总工期预估:4-5 天**
|
||
|
||
---
|
||
|
||
## 9. 验证标准
|
||
|
||
### 功能验证(必须全部通过)
|
||
|
||
| # | 场景 | 期望结果 |
|
||
|---|------|----------|
|
||
| V1 | 问"小红怎么吃" | S2S 基于 KB 原始片段回答,包含正确服用方法 |
|
||
| V2 | 连续追问"那大白呢""小白呢" | S2S 结合上下文理解"那"指的是什么,正确回答 |
|
||
| V3 | 问"你们公司正规吗" | 品牌保护兜底正常触发 |
|
||
| V4 | Redis 断开时问产品问题 | 自动降级到 MySQL,不报错 |
|
||
| V5 | 重排模型超时 | 跳过重排,使用原始检索结果 |
|
||
| V6 | KB 检索无结果 | 走 honest_fallback 或 upstream_chat |
|
||
|
||
### 性能验证
|
||
|
||
| 指标 | 当前基线 | 目标 |
|
||
|------|----------|------|
|
||
| KB 查询延迟(P50) | ~2300ms | <1200ms |
|
||
| KB 查询延迟(P95) | ~4500ms | <2000ms |
|
||
| 上下文读取延迟 | ~100ms (MySQL) | <10ms (Redis) |
|
||
| 多轮追问准确率 | ~40%(无上下文) | >80%(5轮上下文) |
|
||
|
||
---
|
||
|
||
## 10. 后续迭代方向
|
||
|
||
| 方向 | 说明 | 优先级 |
|
||
|------|------|--------|
|
||
| **语义缓存** | 用 embedding 相似度判断是否命中缓存,而非精确 query 匹配 | P1 |
|
||
| **Redis Streams** | 对话历史用 Streams 代替 List,支持消费者组、重放 | P2 |
|
||
| **Hybrid Search** | 向量检索 + BM25 关键词检索融合,提升召回率 | P1 |
|
||
| **动态 top_k** | 根据 query 复杂度自动调整检索数量 | P3 |
|
||
| **多轮 query 改写** | 基于 Redis 上下文做指代消解("那个"→"小红") | P1 |
|