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 == 0 且 message_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
相关推荐
GISMagic2 小时前
AI 时代的软件工程与架构能力提升路线
人工智能·架构·软件工程
中伟视界2 小时前
化工检修作业新规明日施行,边缘AI如何守好现场?
人工智能
OpenCSG2 小时前
OpenCSG Agentic-27B 正式开源:27B Dense 模型,Agent 执行能力实现全面跃升
人工智能·开源·opencsg
Elastic 中国社区官方博客2 小时前
使用 Lucene 搜索你的 Bean —— Elasticsearch
大数据·开发语言·人工智能·elasticsearch·搜索引擎·全文检索·lucene
敲代码的小霖2 小时前
NovaNova Studio开源免费漫剧短剧生成平台
ai·开源软件·视频生成·图片生成·ai短剧·无线画布
雪兽软件2 小时前
AI爆改学术研究?
人工智能·学术研究
合调于形2 小时前
Rengong zhzzneng 《人工智能》词条汉语拼音字母标调拼写实测案例
人工智能·自然语言处理·人机交互·语音识别·学习方法
cg50172 小时前
大模型 SFT(监督微调)该怎么做?(实践版)
人工智能·深度学习·机器学习
Qt云程序员2 小时前
选型参考:光刃RPA 与常见 RPA / 自动化方案的对比
人工智能·自动化·rpa
neocheng_5222 小时前
品牌、内容和效果营销,受AI影响为什么完全不同?
人工智能