Submit the formed RAG documentation set produced across Sprint-1/2/3 (WS-12 through WS-26) under docs/rag/. Includes: - README.md / INDEX.md: landing + total index (responsibility matrix, review verdicts, dual-link to source issues) - overview/: full-pipeline architecture (4 .mmd diagrams), 11-stage boundary contracts, doc map, source-code inventory - pipeline/: 5 deep-dives (Loader/Parser/Chunking, Embedding, VDB & retrieval, GraphRAG, Rerank/Prompt/LLM) - graphrag/, end-to-end/: v1.0 formal versions with full source retained as reference - evolution/: 11 architecture-refactor proposals, 6-direction roadmap, capability map - review/: S3-T1 / S3-T2 final reviews, S2-T7 final summary - _indexes/: glossary (81 terms), source->doc reverse index, chart index - _release/: v1.0-RC1 release manifest, versioning convention, ops & freshness plan - _meta/README.md: placeholder noting WS-12 governance assets gap Aggregate review score 92.6/100 (8/8 PASS, 31/31 source-code spot checks hit). The legacy docs/ ignore in .gitignore is narrowed to docs/* with an explicit allowlist for docs/rag/. Refs: WS-26 Co-authored-by: multica-agent <github@multica.ai>
17 KiB
source-commit:
feae2f2e (Merge PR #1033 release/v0.3.2)reviewer: 待 [S2-T7] 评审
last-reviewed-at: 2026-05-08
一句话定位
本文档覆盖 MemoryBear RAG 链路的后半段:从检索结果进入系统,到最终 LLM 生成答案并输出给用户的全过程,包括重排序、Prompt 组装、多模型 LLM 调用、流式输出、工具调用及生成后处理。
设计目标与适用场景
- 设计目标:在多知识库、多检索策略(关键词 / 向量 / 混合 / GraphRAG)返回的原始结果上,通过重排序提升相关性,通过 Prompt 工程高效利用上下文,通过多提供商 LLM 封装实现高可用调用,最终输出带引用溯源、支持流式/非流式的答案。
- 适用场景:
- Agent 聊天(
app_chat_service.py/draft_run_service.py) - Workflow 知识检索节点(
workflow/nodes/knowledge/node.py) - 独立 chunk 检索 API(
chunk_controller.py)
- Agent 聊天(
关键概念与术语表
| 术语 | 含义 |
|---|---|
| Rerank | 在初步召回后对 chunk 进行精细重排序 |
| RedBearRerank | 基于 LangChain BaseDocumentCompressor 的 rerank 封装 |
| Dealer | 底层检索调度器,负责混合搜索、内置 rerank、引用插入 |
| KnowledgeRetrievalNode | Workflow 引擎中的知识检索节点 |
| LangChainAgent | 基于 create_agent 的 ReAct Agent,负责工具调用循环 |
| citation | 生成后处理阶段向答案文本中插入 [ID:N] 引用标记 |
| rank_feature | 基于 tag 特征和 PageRank 的辅助排序分 |
实现概览(Mermaid 流程图)
检索结果输入
│
▼
┌─────────────────┐
│ Rerank 层 │
│ A:内置混合 │
│ B:外部模型 │
│ C:RedBearRerank │
│ D:ES层封装 │
└────────┬────────┘
│
▼
┌─────────────────────────┐
│ Prompt 工程与上下文组装 │
│ 系统 Prompt + 技能 Prompt │
│ 知识上下文拼接 │
│ Token 预算管理 │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ LLM 调用层 (LangChainAgent)│
│ ReAct 工具调用循环 │
│ 流式/非流式 │
│ 多模态 + 深度思考 │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 生成后处理 │
│ 引用过滤 + 下载链接 │
│ 引用插入 (embedding 匹配) │
│ JSON 结构化校验 │
└─────────────────────────┘
1. Reranking 章节
1.1 是否使用显式 Rerank
是。MemoryBear 在多处实现了 rerank,采用"多方案并存、按场景选择"策略。
1.2 Rerank 方案全景
方案 A:内置混合 Rerank(Dealer.rerank)
源码:api/app/core/rag/nlp/search.py:606-643
核心融合公式:
score = tkweight * token_similarity + vtweight * vector_similarity + rank_feature
tkweight默认 0.3,vtweight默认 0.7token_similarity:基于 rag_tokenizer 分词后的 Jaccard 风格相似度vector_similarity:query_vector 与 chunk 向量的余弦相似度rank_feature:tag 特征 TF-IDF 余弦 + PageRank,缩放 10 倍(search.py:579-604)- token 权重分配:
content_ltks + title_tks*2 + important_kwd*5 + question_tks*6
方案 B:外部 Rerank 模型(Dealer.rerank_by_model)
源码:api/app/core/rag/nlp/search.py:645-666
将向量相似度替换为外部 rerank 模型的 similarity() 输出,保留 token 相似度和 rank_feature。
方案 C:RedBearRerank(LCEL 兼容封装)
源码:api/app/core/models/rerank.py:11-84
- 继承
langchain_core.documents.BaseDocumentCompressor - 支持
XINFERENCE/GPUSTACK→JinaRerank - 支持
DASHSCOPE→DashScopeRerank - 端点自动规范化:补齐
/v1/rerank
使用场景:
- Workflow
KnowledgeRetrievalNode.rerank()(node.py:108-155) ElasticSearchVector.rerank()(elasticsearch_vector.py:560-607)nlp/search.py:rerank()(search.py:284-343)
方案 D:ElasticSearchVector 层 Rerank
ES Vector 初始化时注入 reranker_config,rerank() 中调用 self.reranker.compress_documents()。
1.3 阈值与延迟
- 内置 rerank:本地 numpy 计算,毫秒级延迟
- 外部 rerank:网络调用,本地 Xinference <10ms,远程 DashScope 100-500ms
- 相似度阈值:
similarity_threshold默认 0.2,低于此值的 chunk 被过滤(search.py:674-768)
1.4 为什么没有统一使用 Cross-Encoder
- Cross-Encoder 需额外部署,对小型部署不友好
- 内置
Dealer.rerank在多数场景已足够 - RedBearRerank 作为可选增强,仅在显式配置
reranker_id时启用
2. Prompt 工程与上下文组装
2.1 Prompt 模板组织
目录:api/app/core/rag/prompts/
| 模板文件 | 用途 |
|---|---|
ask_summary.md |
知识库问答主 Prompt |
citation_prompt.md |
引用标注规范([ID:i] 格式) |
citation_plus.md |
引用回填 Agent Prompt |
question_prompt.md |
文本生成问题 |
keyword_prompt.md |
关键词提取 |
structured_output_prompt.md |
JSON Schema 约束 |
cross_languages_*.md |
跨语言查询扩展 |
analyze_task_*.md |
任务分析与工具选择 |
加载机制:api/app/core/rag/prompts/template.py:9-20,启动时加载并缓存。
2.2 上下文组装流程
Agent 层:api/app/core/agent/langchain_agent.py:230-271
def _prepare_messages(self, message, history, context, files):
messages = []
for msg in history:
if msg["role"] == "user": messages.append(HumanMessage(...))
elif msg["role"] == "assistant": messages.append(AIMessage(...))
user_content = message
if context:
user_content = f"参考信息:\n{context}\n\n用户问题:\n{user_content}"
messages.append(HumanMessage(content=user_content))
return messages
2.3 知识检索工具中的 Chunk 拼接
源码:api/app/services/draft_run_service.py:227-255
retrieve_chunks_result = knowledge_retrieval(query, kb_config)
retrieval_knowledge = [i.page_content for i in retrieve_chunks_result]
context = '\n\n'.join(retrieval_knowledge)
return f"检索到以下相关信息:\n\n{context}"
- chunk 间用
\n\n分隔 - 引用信息(document_id、file_name、score)由外部
citations_collector收集,与上下文字符串分离 - 属于"隐式引用"策略:LLM 看不到
[ID:N],引用回填在生成后完成
2.4 Token 预算管理
源码:api/app/core/rag/prompts/generator.py:46-80
策略:
- 计算总 token;未超限直接返回
- 超限后保留
system+ 最后一条消息,丢弃中间历史 - 仍超限则按比例截断 system 或 user 内容
2.5 System / User 分层结构
system: {用户自定义 system_prompt} + {技能 Prompt} + {文档图片识别指令}
user: {历史消息...}
user: 参考信息:\n\n{chunks}\n\n用户问题:\n{query}
System Prompt 组装见 app_chat_service.py:77-96:先变量替换,再追加 skill_prompts。
3. LLM 调用
3.1 支持的模型与切换机制
核心封装:api/app/core/rag/llm/chat_model.py:52-63
Base 类基于 OpenAI 兼容 API,子类覆盖:
| 类名 | 提供商 |
|---|---|
GptTurbo |
OpenAI |
XinferenceChat |
Xinference |
HuggingFaceChat |
HuggingFace |
ModelScopeChat |
ModelScope |
AzureChat |
Azure OpenAI |
BaiChuanChat |
百川 |
LocalAIChat |
LocalAI |
VolcEngineChat |
火山引擎 |
OpenAI_APIChat |
VLLM / OpenAI-API-Compatible |
GPUStackChat |
GPUStack |
切换机制:ModelApiKeyService.get_available_api_key() 根据 model_id 从数据库读取 provider/api_key/base_url/model_name,运行时动态实例化。
3.2 流式 vs 非流式
非流式(Base._chat(),chat_model.py:122-150):
stream=False,返回(text, total_tokens)- QWQ 推理模型强制内部走流式聚合,过滤
<think>标签
流式(Base._chat_streamly(),chat_model.py:152-185):
stream=True,yield(delta, token_count)- 支持
reasoning_content提取 finish_reason == "length"时自动追加截断提示(中英文自适应)
Agent 流式(LangChainAgent.chat_stream()):
agent.astream_events(version="v2")- 处理
on_chat_model_stream/on_llm_stream - 支持多模态响应解析(OpenAI + 通义千问格式)
3.3 超时、重试、降级
源码:chat_model.py:64-89, 192-215
- 超时:
LLM_TIMEOUT_SECONDS(默认 600s) - 重试:
LLM_MAX_RETRIES(默认 5)+ 随机抖动延迟 - 仅对
RATE_LIMIT/SERVER_ERROR重试 - 降级:无自动模型降级,失败返回
"**ERROR**: ..."
3.4 函数调用 / 工具使用
源码:chat_model.py:251-303, 335-436
- 最多
max_rounds(默认 5)轮工具调用循环 - 工具参数解析使用
json_repair.loads()增强容错 - 流式工具调用:
chat_streamly_with_tools()
Agent 工具循环:LangChainAgent
create_agent(model, tools, system_prompt)max_iterations = 5 + len(tools) * 2- 单个工具最大连续调用:
max_tool_consecutive_calls = 3 _wrap_tools_with_tracking()防循环
3.5 CV 模型与序列到文本模型
CV 模型(cv_model.py):QWenCV、AzureGptV4 — 用于图片/版面分析。
序列到文本(sequence2txt_model.py):QWenSeq2txt(带时间戳 ASR)、GPTSeq2txt(Whisper)— 用于音视频预处理。
4. 生成后处理
4.1 引用回填(Citation Insertion)
源码:api/app/core/rag/nlp/search.py:489-577
流程:
- 将答案按句子切分(避开代码块
```) - 对每句话 embedding,与 chunk embeddings 计算 hybrid similarity
- 阈值从 0.63 开始动态衰减(×0.8),最低 0.3
- 每句最多引用 4 个 chunk,句末插入
[ID:N]
4.2 引用过滤与下载链接
源码:api/app/services/draft_run_service.py:474-490
features_config.citation.enabled开关控制allow_download=True时附加download_url
4.3 安全过滤
当前版本无显式敏感词过滤模块。安全依赖:
- LLM 提供商自带内容过滤
ERROR_CONTENT_FILTER错误码捕获
4.4 输出结构化(JSON Schema)
源码:api/app/core/agent/langchain_agent.py:85-92
通过 system prompt 注入 "\n请以JSON格式输出。" 实现(非 response_format API),因为 LangChain Agent 有工具时无法使用原生 API。
5. 端到端示例
场景:Agent 聊天触发知识库检索
Step 1 — 用户提问:"MemoryBear 的 Rerank 策略是什么?"
Step 2 — System Prompt 组装:
你是一个专业的 AI 知识库助手,名为 Miss R。
任务:根据知识库中的信息回答用户问题。
要求:不要编造信息;使用 Markdown;用用户提问的语言回答。
(来自 ask_summary.md)
Step 3 — LLM 判断调用 knowledge_retrieval_tool
工具内部:
retrieve_chunks_result = knowledge_retrieval(query, kb_config)
context = '\n\n'.join([i.page_content for i in retrieve_chunks_result])
return f"检索到以下相关信息:\n\n{context}"
Step 4 — 若配置 reranker_id,执行 RedBearRerank:
reranker = RedBearRerank(RedBearModelConfig(...))
reranked_docs = list(reranker.compress_documents(documents, query))
Step 5 — Agent 组装消息并调用 LLM:
system: 你是一个专业的 AI 知识库助手...
user: 参考信息:\n\nChunk 0...\n\nChunk 1...\n\n用户问题:\nMemoryBear 的 Rerank 策略是什么?
Step 6 — 输出后处理:
filtered_citations = _filter_citations(features_config, citations_collector)
最终返回:content + citations(含 document_id、file_name、score、可选 download_url)。
6. 关键源码索引
| 功能 | 文件 | 类/函数 | 行号 |
|---|---|---|---|
| Rerank 封装 | api/app/core/models/rerank.py |
RedBearRerank |
11-84 |
| 内置混合 Rerank | api/app/core/rag/nlp/search.py |
Dealer.rerank |
606-643 |
| 外部模型 Rerank | api/app/core/rag/nlp/search.py |
Dealer.rerank_by_model |
645-666 |
| rank_feature | api/app/core/rag/nlp/search.py |
_rank_feature_scores |
579-604 |
| 独立 rerank | api/app/core/rag/nlp/search.py |
rerank() |
284-343 |
| 知识检索入口 | api/app/core/rag/nlp/search.py |
knowledge_retrieval() |
36-147 |
| ES Vector rerank | api/app/core/rag/vdb/elasticsearch/elasticsearch_vector.py |
ElasticSearchVector.rerank |
560-607 |
| Workflow 节点 rerank | api/app/core/workflow/nodes/knowledge/node.py |
KnowledgeRetrievalNode.rerank |
108-155 |
| Workflow 执行 | api/app/core/workflow/nodes/knowledge/node.py |
KnowledgeRetrievalNode.execute |
303-378 |
| LLM 基类 | api/app/core/rag/llm/chat_model.py |
Base |
52-319 |
| 流式 LLM | api/app/core/rag/llm/chat_model.py |
_chat_streamly |
152-185 |
| 工具调用 | api/app/core/rag/llm/chat_model.py |
chat_with_tools |
251-303 |
| 流式工具调用 | api/app/core/rag/llm/chat_model.py |
chat_streamly_with_tools |
335-436 |
| 错误分类 | api/app/core/rag/llm/chat_model.py |
_classify_error |
69-89 |
| CV 模型 | api/app/core/rag/llm/cv_model.py |
QWenCV, AzureGptV4 |
1-497 |
| 音频转录 | api/app/core/rag/llm/sequence2txt_model.py |
QWenSeq2txt, GPTSeq2txt |
1-215 |
| Prompt 加载 | api/app/core/rag/prompts/template.py |
load_prompt |
9-20 |
| Prompt 生成器 | api/app/core/rag/prompts/generator.py |
message_fit_in 等 |
1-744 |
| Agent 封装 | api/app/core/agent/langchain_agent.py |
LangChainAgent |
26-641 |
| Agent 消息准备 | api/app/core/agent/langchain_agent.py |
_prepare_messages |
230-271 |
| 知识检索工具 | api/app/services/draft_run_service.py |
create_knowledge_retrieval_tool |
195-263 |
| 引用过滤 | api/app/services/draft_run_service.py |
_filter_citations |
474-490 |
| 聊天服务 | api/app/services/app_chat_service.py |
agnet_chat |
43-239 |
| 流式聊天 | api/app/services/app_chat_service.py |
agnet_chat_stream |
340-550 |
| 引用插入 | api/app/core/rag/nlp/search.py |
Dealer.insert_citations |
489-577 |
7. 配置项与可调参数
环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
LLM_TIMEOUT_SECONDS |
600 | LLM 超时 |
LLM_MAX_RETRIES |
5 | 最大重试 |
LLM_BASE_DELAY |
2.0 | 重试基础延迟 |
知识检索配置:
| 配置项 | 默认值 | 说明 |
|---|---|---|
retrieve_type |
participle |
participle/semantic/hybrid/graph |
similarity_threshold |
0.2 | 关键词相似度阈值 |
vector_similarity_weight |
0.3 | 向量权重 |
top_k |
4 | 单次检索 chunk 数 |
reranker_id |
None |
Rerank 模型 ID |
reranker_top_k |
4 | Rerank 后最终返回数 |
Agent 参数:
| 配置项 | 默认值 | 说明 |
|---|---|---|
max_iterations |
5 + len(tools) * 2 |
Agent 最大迭代 |
max_tool_consecutive_calls |
3 | 单工具最大连续调用 |
max_rounds |
5 | LLM 工具调用最大轮数 |
temperature |
0.7 | 生成温度 |
max_tokens |
2000 | 最大生成 token |
json_output |
False |
强制 JSON 输出 |
deep_thinking |
False |
深度思考 |
8. 边界条件与已知限制
- 外部 Rerank 延迟高:RedBearRerank 调用 Jina/DashScope API,无本地缓存。
- Token 裁剪较粗糙:
message_fit_in丢弃中间历史,可能丢失上下文;按比例截断可能切断语义。 - 引用回填非 LLM 原生:基于 embedding 相似度匹配,表述不同可能漏引。
- JSON 输出兼容性差:通过 system prompt 注入实现,可靠性低于原生
response_format。 - 无模型降级:LLM 失败返回错误文本,不自动切换备用模型。
- 混合检索融合简单:仅去重取并集,无 RRF 或加权分数融合。
- GraphRAG 结果前置:始终
insert(0, ...),优先级最高但无分数参与 rerank。
9. 优化建议与未来扩展点
- Rerank 缓存:对高频 query 做 LRU 缓存,降低外部 API 成本。
- 引用增强:将
citation_prompt.md注入 system prompt,让 LLM 生成阶段就输出[ID:N]。 - Token 预算精细化:引入
tiktoken精确计数,实现滑动窗口历史管理。 - 模型降级:在
Base.chat()中增加 fallback 模型链。 - 混合检索 RRF:在 ES 查询层面实现 Reciprocal Rank Fusion。
- 流式引用:在
on_tool_end事件中实时 emit citation 元数据。 - 输出校验中间件:对
json_output=True增加 JSON Schema 强制校验层。
以上为 [S2-T5] 初版全文,请评审。