AI助手模块工作流程技术总结

AI 助手模块工作流程技术文档

一、系统架构总览

复制代码
┌──────────────────────────────────────────────────────────┐
│                    前端 (Vue 3)                          │
│   index.vue --- ai.js (API 客户端 + SSE 流式接收)          │
└────────────────────────┬─────────────────────────────────┘
                         │ HTTP / SSE
                         ▼
┌──────────────────────────────────────────────────────────┐
│              API 层 (FastAPI)                            │
│   ai_controller.py --- 路由分发 + 意图识别 + 模式编排      │
│   IntentRouter --- 关键词 + RAG 混合意图识别               │
└────────────────────────┬─────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────┐
│                    服务层                                │
│  ┌──────────────┐ ┌──────────────┐ ┌───────────────┐    │
│  │  ai_service  │ │rag_service   │ │education_tools│    │
│  │  (LLM通信)   │ │(RAG检索)     │ │ (8个教育工具) │    │
│  └──────┬───────┘ └──────┬───────┘ └───────────────┘    │
│  ┌──────┴───────┐ ┌──────┴───────┐ ┌───────────────┐    │
│  │chat_history  │ │memory_store  │ │permission_    │    │
│  │_service      │ │_service      │ │text2sql       │    │
│  │ (会话管理)   │ │ (用户记忆)   │ │ (SQL安全)     │    │
│  └──────────────┘ └──────────────┘ └───────────────┘    │
└────────────────────────┬─────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────┐
│     数据层                                              │
│  ┌──────────────┐ ┌──────────────┐ ┌───────────────┐    │
│  │   MySQL      │ │   Milvus     │ │  BM25 Model   │    │
│  │  (会话/消息) │ │  (向量库)    │ │ (稀疏索引)    │    │
│  └──────────────┘ └──────┬───────┘ └───────────────┘    │
│  ┌──────────────┐ ┌──────┴───────┐                       │
│  │ qa_pairs.json│ │ 四大名著.txt │  (原始语料)            │
│  └──────────────┘ └──────────────┘                       │
└──────────────────────────────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────┐
│               AI 大模型 (阿里云 Qwen 系列)                │
│   qwen-max / qwen-plus --- 对话、意图识别、Text2SQL        │
│   text-embedding-v4 --- 文本向量化 (1024维)               │
└──────────────────────────────────────────────────────────┘

二、离线数据处理流水线(知识库构建)

2.1 整体流程

复制代码
《三国演义》.txt (原始文本)
        │
        ▼
  [txt_parser.py]
  parse_txt_file()   --- 读取 TXT 文件(自动检测编码 utf-8/gbk)
  clean_text()       --- 清除 HTML 标签,统一格式
  extract_chapters() --- 按 "第X回" 正则拆分章节
        │
        ▼
  章节列表 [{index, title, content}, ...]  (120章, 约60万字)
        │
        ├──────────────────┬──────────────────┐
        ▼                  ▼                  ▼
  [text_splitter]   [generate_qa_pairs]  [BM25Encoder]
  文本分块            AI生成问答对          训练词频模型
        │                  │                  │
        ▼                  ▼                  ▼
  chunks (~2500块)   qa_pairs.json       bm25_model.json
  每块500字重叠50字   (~600条)            稀疏向量权重
        │                  │
        └────────┬─────────┘
                 ▼
        [vdb_init.py / import_qa_to_milvus.py]
        将数据导入 Milvus 向量库
                 │
                 ▼
        ┌────────────────────────────────────────────────────┐
        │                 Milvus 向量库 (8个集合)            │
        │                                                    │
        │  sgyy_chunks     (1768行)  │ sgyy_qa_pairs (1744行)│
        │  hlm_chunks      (5050行)  │ hlm_qa_pairs  (3008行)│
        │  xyj_chunks      (1928行)  │ xyj_qa_pairs  (1514行)│
        │  shuihu_chunks   (2305行)  │ shuihu_qa_pairs(1723行)│
        └────────────────────────────────────────────────────┘

2.2 各技术切片详解

2.2.1 文档解析 --- txt_parser.py
函数 职责 技术细节
parse_txt_file() 读取 TXT 文件 自动尝试 utf-8/gbk/gb2312/utf-16 编码
clean_text() 清洗文本 正则替换 HTML 标签为换行,压缩多余空行,去除中文间空格
extract_chapters() 按章节拆分 正则 ^(第[一二三四五六七八九十百零\d]+回\s*.+?)$ 匹配章节标题,返回 {index, title, content} 列表
2.2.2 文本分块 --- text_splitter.py
组件 技术 细节
主方案 LangChain RecursiveCharacterTextSplitter 分隔符优先级:\n\n\n。」!」?」 ""
备选方案 _simple_split() 无 LangChain 时按句子边界分块,保留重叠
参数 chunk_size=500 每块约 500 字
参数 chunk_overlap=50 重叠 50 字,保证上下文连贯
元数据 metadata 每块携带 chapter(章节名)、chapter_index(序号)、chunk_index(块索引)、char_count(字数)
2.2.3 问答对生成 --- generate_qa_pairs.py
步骤 说明
模型 阿里云 Qwen 系列 (qwen3.6-plus / qwen-max)
输入 每章原文前 2000 字
输出 每个章节 5 个问答对
Prompt 要求从人物、事件、原因、结果多角度出题,输出严格 JSON 格式
后处理 清理 Qwen 的 <think> 思考标签,清理 markdown 代码块标记
限流 每 5 章暂停 3 秒,避免 API 限流
累计 120 章 × 5 ≈ 600 条问答对
2.2.4 BM25 稀疏向量 --- bm25_encoder.py
组件 说明
分词 优先 jieba 分词,备选单字符切分
停用词 过滤中英文标点、空白符
训练 fit(documents) --- 遍历所有文档统计词频和文档频率
词汇表 按词频降序分配 token_id
IDF 公式 log((N - df + 0.5) / (df + 0.5) + 1)
BM25 评分 tf_norm = (tf * (k1+1)) / (tf + k1*(1-b + b*doc_len/avg_doc_len)),参数 k1=1.5, b=0.75
查询编码 encode_query() --- 使用 IDF × TF 权重
空向量保护 添加占位符 {0: 0.001} 避免 Milvus 报错
2.2.5 稠密向量 --- Embedding API
参数
API 阿里云 DashScope https://dashscope.aliyuncs.com/compatible-mode/v1
模型 text-embedding-v4 (环境变量 EMBEDDING_MODEL)
维度 1024 维 (环境变量 EMBEDDING_DIMENSIONS)
SDK openai 库兼容模式调用
批量限制 每批最多 10 条,get_embeddings_batch() 自动分批
2.2.6 Milvus 向量库 --- vdb_init.py

8 个集合命名规则

小说 ID 章节切片集合 问答对集合 标签
sgyy sgyy_chunks sgyy_qa_pairs 三国演义
hlm hlm_chunks hlm_qa_pairs 红楼梦
xyj xyj_chunks xyj_qa_pairs 西游记
shz shuihu_chunks shuihu_qa_pairs 水浒传

sgyy_chunks 集合 Schema

字段名 类型 说明
chunk_id INT64 (主键, 自增) 切片 ID
text VARCHAR(2000) 切片文本内容
chapter VARCHAR(100) 所属章节名称
chapter_index INT32 章节序号
char_count INT32 切片字数
dense_vector FLOAT_VECTOR(1024) 稠密向量
sparse_vector SPARSE_FLOAT_VECTOR BM25 稀疏向量

sgyy_qa_pairs 集合 Schema

字段名 类型 说明
qa_id INT64 (主键, 自增) 问答对 ID
question VARCHAR(500) 问题
answer VARCHAR(2000) 答案
reasoning VARCHAR(2000) 推理过程
chapter VARCHAR(100) 所属章节
scene VARCHAR(200) 场景描述
dense_vector FLOAT_VECTOR(1024) 问题的稠密向量
sparse_vector SPARSE_FLOAT_VECTOR 问题的 BM25 稀疏向量

索引配置

索引 字段 类型 参数
稠密索引 dense_vector IVF_FLAT metric_type=COSINE, nlist=128
稀疏索引 sparse_vector SPARSE_INVERTED_INDEX metric_type=IP

数据导入insert_chunks_data()insert_qa_pairs_data() 每 100 条一批插入。


三、在线推理工作流

3.1 完整用户请求处理流程

复制代码
用户输入: "曹操在官渡之战用了什么计策?"
        │
        ▼
┌─── STEP 1: API 入口 ───────────────────────────────────┐
│  POST /api/ai/chat       → ai_chat()       (非流式)    │
│  POST /api/ai/chat/stream → ai_chat_stream() (流式)    │
│                                                        │
│  ├─ 参数提取: user_message, mode, session_id            │
│  ├─ RBAC 鉴权: 需 AI_CHAT 权限 (admin/teacher)         │
│  └─ 自动创建会话: 若 session_id 为 None                  │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── STEP 2: 记忆加载 ───────────────────────────────────┐
│  memory_store_service.build_memory_prompt(user_id)      │
│                                                        │
│  ├─ 从 UserPreference 表加载 4 个命名空间:              │
│  │   preferences---对话风格偏好                            │
│  │   profile---兴趣话题                                    │
│  │   interests---用户画像信息                               │
│  │   facts---提取的事实信息                                 │
│  ├─ 构建记忆提示词, 例如:                                │
│  │   "【用户长期记忆】                                   │
│  │   用户偏好的对话风格:喜欢风趣幽默的回答               │
│  │   用户感兴趣的话题:编程、文学、历史                   │
│  │   用户画像:25岁男程序员                              │
│  │   关于用户:用户名叫张三,喜欢读红楼梦"               │
│  └─ 超时兜底: 5秒超时返回空字符串                        │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── STEP 3: 意图识别 ───────────────────────────────────┐
│  IntentRouter.recognize_async(user_message)              │
│  (若 mode 已指定则跳过, 直接路由)                       │
│                                                        │
│  匹配顺序 (优先级降序):                                  │
│  1. CRITICAL_KEYWORDS               → "critical"        │
│     自杀/自残/不想活/活不下去了...                       │
│  2. rag_service.detect_novel()      → "knowledge"       │
│     四大名著关键词匹配                                    │
│  3. IMAGE_KEYWORDS                  → "image"           │
│     画/图片/生成图/作图/画画...                          │
│  4. TOOL_KEYWORDS                   → "tools"           │
│     评语/违纪/校规/面试/分班...                          │
│  5. QUERY_KEYWORDS                  → "text2sql"        │
│     查询/统计/排名/成绩单/就业率...                      │
│  6. LIN_DAIYU_KEYWORDS             → "lin_daiyu"        │
│     颦儿/诗词/黛玉...(强制林黛玉模式)                    │
│  7. (无匹配)                        → "general"         │
│     默认模式                                            │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── STEP 4: 模式分发 ───────────────────────────────────┐
│  根据 intent 分发到 6 个处理函数                          │
│                                                        │
│  critical  ──→ _handle_critical()   (危机干预)           │
│  knowledge ──→ _handle_knowledge_mode() (名著的RAG)     │
│  image     ──→ _handle_image_mode()  (文生图)           │
│  text2sql  ──→ _handle_text2sql_mode() (SQL查询)        │
│  tools     ──→ _handle_tools_mode()   (教育工具)        │
│  lin_daiyu/                                              │
│  general   ──→ _handle_chat_mode()    (林黛玉对话)       │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── STEP 5: 消息持久化 ──────────────────────────────────┐
│  _save_chat_messages()                                  │
│                                                        │
│  ├─ chat_history_service.save_messages()                │
│  │    → 写入 ChatMessage 表 + 更新 ChatSession 统计     │
│  ├─ chat_history_service.trigger_summary_if_needed()    │
│  │   → 消息数 ≥ 20 时自动生成会话摘要, 写入              │
│  │     SessionSummary 表                                │
│  └─ memory_store_service.extract_facts_from_messages()  │
│     → AI 从对话中提取用户事实, 存入                       │
│       UserPreference 表 (facts 命名空间)                 │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── STEP 6: 响应返回 ───────────────────────────────────┐
│  非流式: BaseResponse.success(data=AIChatResponse)      │
│  流式:   StreamingResponse (SSE 格式)                   │
│  格式:   {"code":200, "data":{"reply":"...",            │
│           "msg_type":"knowledge", "suggestions":[...]}} │
└─────────────────────────────────────────────────────────┘

3.2 知识库检索流程(5阶段RAG管道)

复制代码
用户: "曹操在官渡之战用了什么计策?"
        │
        ▼
  detect_novel(question)
        │
        ├─ 关键词匹配: 曹操、官渡之战 → 匹配 "sgyy"
        │
        ▼
  retrieve_novel_context(question, novel_id="sgyy")
        │
        ▼
┌─── 阶段1: 查询预处理 ──────────────────────────────────┐
│  query_clean()   --- 去特殊符号,过滤 <3字短查询           │
│  query_rewrite_llm() --- 口语化→检索式(当前为空实现)      │
│  query_expand()  --- 同义词扩展(曹操→曹孟德/曹阿瞒等)    │
│  输入: "曹操在官渡之战用了什么计策"                      │
│  输出: "曹操在官渡之战用了什么计策 曹孟德 曹阿瞒 曹公"   │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── 阶段2: 多路召回 (hybrid_search) ─────────────────────┐
│                                                          │
│  诊断: 检查集合存在性 + get_collection_stats().row_count │
│  ├─ 集合不存在 → 返回空 (明确日志告警)                    │
│  ├─ 行数为 0   → 返回空 (明确日志告警)                    │
│  └─ 有数据     → 继续检索                                 │
│                                                          │
│  ┌─ 稠密向量: _get_embedding() → DashScope text-embedding│
│  │  -v4 → 1024维                                         │
│  └─ 稀疏向量: _get_sparse_vector() → BM25 jieba 分词     │
│                                                          │
│  并行执行 (ThreadPoolExecutor + 各自 try/except):        │
│                                                          │
│  2a. search_chunks() --- 原文切片 (output_fields: text,    │
│      chapter, chapter_index, char_count)                  │
│      ┌─ AnnSearchRequest(稠密, COSINE, nprobe=10)        │
│      └─ AnnSearchRequest(稀疏, IP)                       │
│      → RRFRanker(k=100) 融合 → top_k=8                  │
│                                                          │
│  2b. search_qa_pairs() --- 问答对 (output_fields: question,│
│      answer, reasoning, chapter, scene)                   │
│      ┌─ AnnSearchRequest(稠密, COSINE, nprobe=10)        │
│      └─ AnnSearchRequest(稀疏, IP)                       │
│      → RRFRanker(k=100) 融合 → top_k=5                  │
│                                                          │
│  超时保护: RAG_TIMEOUT_SEC = 15s                          │
│  RRF阈值过滤: RRF_MIN_SCORE = 0.001 (RRF为排名倒数值)    │
│                                                          │
│  召回qa=5, chunks=8, 耗时~4s                             │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── 阶段3: 融合去重 (fusion_dedup) ───────────────────────┐
│  chunks 来源 + QA pairs 来源 → 统一列表                   │
│  去重: 按 text/question 前80字做 hash                     │
│  压缩: 最多保留 15 条                                     │
│  输出: qa=5, chunks=8 → 融合后=13                        │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── 阶段4: Rerank 重排精筛 ──────────────────────────────┐
│                                                          │
│  模型: BAAI/bge-reranker-v2-m3 (本地缓存, 2.27GB)        │
│  加载: HuggingFace Transformers, local_files_only=True   │
│  降级: 模型加载失败 → 关键词过滤 (_rerank_fallback)       │
│                                                          │
│  推理方式: 同步推理 + 事后超时检查                         │
│  超时保护: 推理耗时 > 8s → 降级为关键词过滤               │
│  首次优化: 模型刚加载(已耗5s) → 跳过推理, 直接关键词过滤  │
│                                                          │
│  BGE 推理:                                               │
│  ├─ 输入: (query, candidate) 13对                        │
│  ├─ Tokenizer: max_length=512                            │
│  ├─ 模型: CrossEncoder → logits                          │
│  ├─ 归一化: torch.sigmoid(logits) → [0,1] 得分           │
│  └─ 过滤: threshold ≥ 0.30 → Top5                       │
│                                                          │
│  保底: 如果Rerank过滤所有候选, 保留融合阶段最高分1条      │
│                                                          │
│  输出: qa=2, chunks=1 (命中) 或 qa=1, chunks=1 (保底)   │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─── 阶段5: 上下文构建与输出 ─────────────────────────────┐
│                                                          │
│  direct模式 (QA对得分 ≥ 0.35):                           │
│  ├─ direct_answer = QA对答案 + 推理 + 相关问题           │
│  ├─ trim_context(direct_answer, MAX_CONTEXT_CHARS=2500)  │
│  └─ 进入LLM林黛玉润色 (不走原始流式)                      │
│                                                          │
│  augment模式 (QA对得分 < 0.35):                          │
│  ├─ context = 【相关问答】 + 【原文片段】拼接              │
│  ├─ trim_context(context, MAX_CONTEXT_CHARS=2500)        │
│  └─ 注入 system_prompt 作为参考资料                       │
│                                                          │
│  未命中 (None):                                          │
│  └─ LLM提示: "颦儿在知识库中未查到相关内容,以下凭记忆回答"│
│     + "💡 此回答来自AI自身知识,非知识库检索结果"          │
│                                                          │
│  流式端点额外输出 SSE 事件:                                │
│  data: {"type":"references", "data":{"qa_pairs":[...],   │
│         "chunks":[...]}}  (在[DONE]之前)                 │
└─────────────────────────────────────────────────────────┘

3.3 流式推理流程

复制代码
用户请求流式对话 (POST /api/ai/chat/stream)
        │
        ▼
  记忆加载 (同非流式)
        │
        ▼
  四大名著知识库检测 (detect_novel)
        │
        ├── 命中名著 → retrieve_novel_context (5阶段管道, 超时30s)
        │      │
        │      ├── direct模式 → 注入system prompt, 走LLM林黛玉润色
        │      ├── augment模式 → 注入上下文到system prompt
        │      └── 未命中 → 提示"未查到相关内容,以下凭记忆回答"
        │
        ├── 敏感问题检测
        │    └── 调用 _handle_critical() 获得完整回复后分片输出
        │
        ├── Text2SQL 检测
        │    └── 成功时分段流式输出: 文本 → SQL 代码 → 结果表格
        │
        └── 通用流式
             └── 构建 system prompt (含记忆+风格+RAG上下文)
                  → ai_service.chat_stream()
                  → SSE 逐 chunk 返回

  流式额外输出 (在 [DONE] 之前):
  └── data: {"type":"references", "data":{"qa_pairs":[...], "chunks":[...]}}

3.4 Text2SQL 处理流程

复制代码
用户: "查一下计算机一班有多少学生"
        │
        ▼
  _try_text2sql(question, db, user_id, current_user)
        │
        ▼
┌─── Text2SQL 执行链 ──────────────────────────────────┐
│ 1. 构建 System Prompt                                  │
│    ├─ 数据库表结构 (show create table)                  │
│    ├─ 外键关系描述                                      │
│    └─ 权限上下文 (用户角色、可见范围)                    │
│                                                        │
│ 2. ai_service.chat() → LLM 生成 SQL                    │
│    ├─ prompt 要求: 只输出 SQL, 不要注释                 │
│    ├─ 仅允许 SELECT, 禁止 INSERT/UPDATE/DELETE         │
│    └─ SQL 提取: 从 ''```sql...'''' 块中提取              │
│                                                        │
│ 3. validate_and_sanitize_sql() --- 安全校验               │
│    ├─ 检测写操作关键字                                  │
│    ├─ 移除注释和分号                                    │
│    └─ 验证为纯 SELECT                                   │
│                                                        │
│ 4. PermissionText2SQL.apply_row_level_security()       │
│    ├─ 教师: WHERE class_id IN (所带班级)               │
│    ├─ 学生: WHERE student_id = 自己                    │
│    └─ 管理员: 无过滤                                   │
│                                                        │
│ 5. execute_sql() --- 执行 SQL                            │
│    ├─ SET TRANSACTION READ ONLY (保证只读)              │
│    └─ 超时: 10 秒                                      │
│                                                        │
│ 6. clean_results() --- 清理结果                           │
│    ├─ 移除自增 id 字段                                  │
│    ├─ Decimal → float (JSON 序列化)                     │
│    └─ 字段按优先级排序                                  │
│                                                        │
│ 7. ai_service.chat() → AI 润色为自然语言               │
│    └─ 返回 {reply, sql, results, suggestions}          │
└─────────────────────────────────────────────────────────┘

3.5 教育工具处理流程

复制代码
用户点击 "📝 期末评语" 或输入 "生成期末评语:张三"
        │
        ▼
  IntentRouter.detect_tool(user_message)
        │
        ├── 未检测到工具名
        │    └── 展示工具列表让用户选择 (AI生成)
        │
        └── 检测到工具名
             │
             ├── 权限检查: teacher 工具需 role=teacher
             │
             ├── 纯触发检测 (is_pure_trigger)
             │    ├── 条件: 无前缀剥离 + 去掉关键词后剩余<3字
             │    └── 返回 TOOL_ENTRY_MESSAGES 静态话术 (零AI调用)
             │         例: "(铺开宣纸,执笔蘸墨)公子要写期末评语?..."
             │
             └── 有实质内容
                  └── 调用 TOOL_MAP[tool_name]["fn"](content)
                       │
                       ├── generate_comment()     (期末评语)
                       ├── generate_discipline_talk() (违纪话术)
                       ├── polish_notice()        (通知润色)
                       ├── query_school_rules()   (校规问答)
                       ├── diagnose_scores()      (成绩诊断)
                       ├── generate_activity()    (班会策划)
                       ├── generate_interview()   (模拟面试)
                       └── smart_grouping()       (智能分班)
                       │
                       └── 所有工具通过 _call_ai() 调用 AI 服务
                            └── ai_service.chat([system, user])
                            │
                            ▼
                      结果以林黛玉引语包装后返回

3.6 会话管理与长对话策略

复制代码
load_history(session_id) --- 三级加载策略
        │
        ├── 消息数 ≤ 20 (BUFFER_THRESHOLD)
        │    └── 全量加载所有消息
        │
        ├── 20 < 消息数 ≤ 50 (WINDOW_THRESHOLD)
        │    ├── 注入最新的 SessionSummary 作为上下文
        │    └── + 最近 20 轮 (WINDOW_KEEP) 消息
        │
        └── 消息数 > 50
             ├── 注入最近 N 层摘要(多层摘要压缩)
             └── + 最近 10 轮 (SUMMARY_KEEP) 消息

自动摘要触发

  • trigger_summary_if_needed() --- 每次保存消息时检测
  • 条件:message_count % 10 == 0message_count >= 20
  • 调用 ai_service.chat() 用 AI 生成摘要
  • 摘要写入 SessionSummary

四、关键技术切片说明

4.1 林黛玉角色提示词分层策略

层次 内容 用途
PERSONA_BASE 角色基础设定:林黛玉身份、语言风格、行为约束 所有模式的基础人设
STYLE_FULL_DAIYU 全程林黛玉风格:动作描写+半文半白 chat/image 模式全程保持
STYLE_OPENING_DAIYU 首段林黛玉引语 + 后续标准白话 knowledge/text2sql/tools 模式用于开场白
INTENT_OPENINGS 各模式的固定开场白模板 注入到 system prompt 指引回答格式
CRITICAL_RESPONSE_TEMPLATE 危机干预预设话术 + 心理热线 检测到敏感词时直接使用

4.2 混合检索(Hybrid Search)技术

技术 检索方式 距离度量 参数 用途
稠密检索 (Dense) Embedding + IVF_FLAT COSINE nprobe=10 语义相似度匹配
稀疏检索 (Sparse) BM25 + SPARSE_INVERTED_INDEX IP (内积) --- 关键词精确匹配
融合排序 (Fusion) RRF (Reciprocal Rank Fusion) k=100 --- 合并两种检索结果
RRF 滤除 RRF_MIN_SCORE = 0.001 --- score < 0.001 丢弃 过滤完全无关结果

RRF 分数说明:RRF 分数 = 1 / (k + rank),k=100 时 top1 ≈ 0.0099,远小于余弦相似度。因此 RRF 滤除阈值必须极低(0.001),不可用类似余弦相似度 0.3 这类阈值。

4.3 BGE Reranker 重排策略

配置项 说明
模型 BAAI/bge-reranker-v2-m3 中文最优CrossEncoder,2.27GB
加载方式 local_files_only=True 仅读取本地缓存,不触发联网下载
降级策略 加载失败 → _rerank_fallback 关键词重叠度计算(无需模型)
得分归一化 torch.sigmoid(logits) 将任意范围 logits 映射到 [0, 1]
过滤阈值 ≥ 0.30 低于此值的候选片段淘汰
Top-K 保留 5 Rerank 后最多保留 5 条
超时保护 推理 > 8s → 降级关键词过滤 防止 Reranker 拖垮整个管道
首次优化 模型刚加载 → 跳过首次推理 模型加载已耗 5s,跳过推理直接降级
保底机制 Rerank 全过滤 → 保留融合最高分 1 条 确保知识库至少有条目可用

4.4 多层 Prompt 注入机制

复制代码
最终 system prompt 的构建顺序(以 knowledge + augment 模式为例):

┌─ 1. PERSONA_BASE        "你是林黛玉,金陵十二钗之首..."
├─ 2. memory_prompt       "【用户长期记忆】..."
├─ 3. STYLE_OPENING_DAIYU  "第一段:以1-2句林黛玉引语开头..."
├─ 4. 模式引导            "你是{sgyy}的知识专家,请引用原文回答..."
│     或 direct模式:     "以下是知识库答案,请用林黛玉口吻重新组织..."
│     或 未命中:         "未查到相关内容,以下凭记忆回答..."
├─ 5. RAG上下文           "【参考资料】\n{context}\n..."
│     或 direct答案:      "【知识库答案】\n{direct_answer}\n..."
├─ 6. INTENT_OPENING      "请以以下引语开头回复:..."
└─ 7. (用户实际消息)       "曹操在官渡之战用了什么计策?"

4.6 数据库表结构汇总

表名 引擎 主键 关键索引 Milvus 数据量 用途
chat_sessions InnoDB id (INT) user_id, update_time --- 会话元数据
chat_messages InnoDB id (BIGINT) session_id, (session_id, create_time) --- 消息内容
session_summaries InnoDB id (INT) session_id --- 会话摘要
user_preferences InnoDB id (INT) user_id --- 用户偏好/记忆
sgyy_chunks Milvus chunk_id IVF_FLAT + SPARSE_INVERTED 1768行 三国演义原文切片
sgyy_qa_pairs Milvus qa_id IVF_FLAT + SPARSE_INVERTED 1744行 三国演义问答对
hlm_chunks Milvus chunk_id IVF_FLAT + SPARSE_INVERTED 5050行 红楼梦原文切片
hlm_qa_pairs Milvus qa_id IVF_FLAT + SPARSE_INVERTED 3008行 红楼梦问答对
xyj_chunks Milvus chunk_id IVF_FLAT + SPARSE_INVERTED 1928行 西游记原文切片
xyj_qa_pairs Milvus qa_id IVF_FLAT + SPARSE_INVERTED 1514行 西游记问答对
shuihu_chunks Milvus chunk_id IVF_FLAT + SPARSE_INVERTED 2305行 水浒传原文切片
shuihu_qa_pairs Milvus qa_id IVF_FLAT + SPARSE_INVERTED 1723行 水浒传问答对

4.7 外部服务依赖

服务 用途 连接方式 配置项
阿里云 DashScope LLM 对话、文生图、Embedding OpenAI 兼容 SDK AI_API_KEY, AI_BASE_URL, AI_MODEL
Milvus 向量数据库 pymilvus MilvusClient MILVUS_HOST:PORT, MILVUS_DB_NAME
MySQL 业务数据存储 SQLAlchemy 标准数据库连接串

五、部署与初始化

5.1 知识库初始化命令

bash 复制代码
# 1. 解析文档 + 创建 Milvus 表 + 切片 + 插入数据
python rag_demo/vdb_init.py init_all

# 或分步执行:
python rag_demo/vdb_init.py create_tables    # 创建 Milvus 集合和索引
python rag_demo/vdb_init.py insert_chunks     # 插入切片数据
python rag_demo/import_qa_to_milvus.py        # 插入问答对数据

5.2 问答对生成

bash 复制代码
# 为所有 120 章生成问答对 (需先有《三国演义》.txt 文件)
python rag_demo/generate_qa_pairs.py

# 仅处理前 10 章 (测试用)
python rag_demo/generate_qa_pairs.py 10

5.3 环境变量配置

复制代码
# .env 文件核心配置
AI_API_KEY=sk-xxxxx                          # DashScope API Key
AI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
AI_MODEL=qwen-max

MILVUS_HOST=127.0.0.1
MILVUS_PORT=19530
MILVUS_DB_NAME=ai80

EMBEDDING_MODEL=text-embedding-v4
EMBEDDING_DIMENSIONS=1024

5.4 检索超时配置

配置项 旧值 新值 说明
检索整体超时 15s 30s 覆盖 Embedding API + BM25 + Milvus + Reranker 全链路
名著检测超时 5s 5s 纯关键词匹配,毫秒级,无需更改
Rerank 推理超时 8s BGE 模型 CPU 推理 13 对候选可能超时,超时后降级关键词过滤

5.5 RAG 管道常见故障排查指南

现象 日志关键词 可能原因 解决方案
无召回结果 阶段2: 无召回结果 RRF_MIN_SCORE 过滤了所有结果 检查 RRF_MIN_SCORE 是否过高(应 ≤ 0.001)
无召回结果 集合存在但为空 Milvus 集合有结构无数据 运行 vdb_init.py insert_{chunks,qa} 导入数据
检索超时 流式名著知识库检索 超时 Reranker 推理过慢阻塞管道 检查 Rerank 超时保护是否正常工作(≤ 8s 降级)
没有命中但 LLM 回答正确 无引用标识 结果被 Rerank 过滤 + 无保底 检查 rerank() 中的保底逻辑是否生效
所有小说返回"未命中" Milvus集合状态 无输出 Milvus 连接失败 检查 MILVUS_HOST:PORT 是否可达
流式有回答但无引用数据 mode=chat 外层 timeout 超时后返回 None 延长检索超时或加速 Reranker
相关推荐
eastyuxiao1 小时前
主流物联网协议 超详细讲解
大数据·人工智能·物联网·智慧城市·能源·数字孪生
令狐少侠20111 小时前
workbuddy、openclaw能控制浏览器
windows·ai
清风lsq1 小时前
大模型-vllm 实现lora解析
人工智能·vllm·大模型推理
weixin_373470691 小时前
coze实战:用工作流搭建美食地图
ai·aigc·ai编程·美食
心疼你的一切1 小时前
从零到一:鸿蒙健康监测应用的全流程开发实录
人工智能·华为·harmonyos·鸿蒙·鸿蒙系统
何忆清风1 小时前
Easy Agent Pilot - Rust实现的开源桌面Agent软件
ai·rust·vue·agent·tauri·开发工具
青岛前景互联信息技术有限公司1 小时前
大典型案例,详细阐述分级预警与应急联动机制的构建逻辑
人工智能·物联网
Lyon198505281 小时前
注解:汉字逻辑 与 字母逻辑——DeepSeek体验《文字定律》
人工智能·ai·ai写作·deepseek
蜘蛛小助理1 小时前
从一张表到一套系统:AI自动生成跨表关联与自动化工作流
人工智能·ai·多维表·多维表格·蜘蛛表格