UltraRAG 是一个面向 RAG 应用开发的开源框架,由清华大学 THUNLP 实验室、东北大学 NEUIR 实验室、OpenBMB、面壁智能、AI9Stars 等团队联合发布。它的核心定位很明确:不要把 RAG 做成一条看不见内部细节的流水线,而是把检索、重排、生成、工具调用、多轮推理这些环节拆成可编排的组件。
RAG(Retrieval-Augmented Generation,检索增强生成)解决的是大模型不知道业务私有知识的问题。模型在回答问题前,先去知识库里检索相关资料,再把资料作为上下文交给大模型生成答案。这个思路很常见,但真正落地时经常会遇到另一个问题:流程越来越复杂,调试越来越困难。
UltraRAG 3.0 的思路是:
- 用 YAML(一种适合写配置的文本格式)描述推理逻辑;
- 用 MCP(Model Context Protocol,模型上下文协议)承载组件能力;
- 用 UI(用户界面)把流程搭建、配置生成、运行调试连接起来;
- 让 RAG 和 Agent 的每一步都能被查看、修改、复用。
这类框架适合知识库问答、DeepResearch、多轮复杂推理、企业内部文档助手等场景,尤其适合已经有一套 RAG 逻辑,但被代码耦合和黑盒链路拖慢迭代速度的团队。
RAG 应用为什么容易变成黑盒
一个最简单的 RAG 系统通常只有三步:用户提问、检索文档、生成答案。
flowchart LR
A[用户问题] --> B[知识库检索]
B --> C[拼接上下文]
C --> D[大模型生成答案]
D --> E[返回结果]
这个结构看起来很清楚,但业务一复杂,链路会迅速膨胀:
- 用户问题要不要先改写?
- 检索只查向量库,还是同时查关键词索引?
- 检索结果要不要重排?
- 召回片段太长时怎么压缩?
- 多轮对话里哪些历史消息应该保留?
- 大模型是否需要调用工具?
- 答案要不要带引用来源?
- 推理失败时如何定位是哪一步的问题?
很多 RAG 项目一开始会把这些逻辑写进 Python 代码里。短期看很快,长期会产生几个麻烦:
| 问题 | 具体表现 |
|---|---|
| 流程不透明 | 一个请求经过哪些节点、每一步输入输出是什么,很难直接看出来 |
| 调参成本高 | 想换检索器、重排模型或提示词,经常要改代码 |
| 迁移困难 | 另一套业务想复用流程,需要复制大量代码并重新适配 |
| 调试困难 | 答案错了,不知道是检索没召回、重排错了,还是生成提示词不合适 |
| 团队协作差 | 算法、后端、应用开发人员看到的是不同层面的东西,很难对齐 |
UltraRAG 3.0 想解决的正是这类“盲盒式开发”:请求进去了,答案出来了,但中间每一层到底发生了什么不够清楚。
UltraRAG 3.0 的核心结构
UltraRAG 3.0 可以理解成三层:配置层、编排层、组件层。
flowchart TB
U[用户或应用请求] --> UI[UI / API 入口]
UI --> Y[YAML 工作流配置]
Y --> O[UltraRAG 编排引擎]
O --> Q[问题改写组件]
O --> R[检索组件]
O --> RR[重排组件]
O --> C[上下文构造组件]
O --> L[大模型生成组件]
O --> T[工具调用组件]
R --> V[(向量库 / 文档库)]
L --> M[大模型服务]
T --> EXT[外部工具或业务系统]
O --> Trace[运行日志与中间结果]
Trace --> UI
这张结构图里最重要的是两条线:
-
流程由 YAML 描述
检索、重排、生成等节点如何连接,不再只藏在代码里,而是用配置表达出来。配置可以版本管理,也可以由 UI 同步生成。 -
能力由 MCP 组件承载
检索器、重排器、模型调用、工具调用都可以被封装成组件。编排引擎不需要关心组件内部如何实现,只需要知道它接收什么输入、返回什么输出。
这样做的好处不是“少写代码”,而是把 RAG 应用里最容易失控的推理逻辑显式化。流程一旦显式化,调试、替换、迁移和协作都会变得更直接。
用 YAML 描述推理逻辑
YAML 在 UltraRAG 里的作用,可以类比后端服务里的配置文件。它不负责实现检索算法,也不负责训练模型,而是负责描述“一个请求应该怎么走”。
一个简化版 RAG 工作流可以写成类似下面的形式。字段只是示意,真实项目中需要以 UltraRAG 3.0 的配置规范为准。
workflow:
name: knowledge-base-qa
input:
query: "{{ user.question }}"
steps:
- id: rewrite_query
type: query_rewrite
params:
model: qwen
enable_history: true
- id: retrieve_docs
type: retriever
depends_on:
- rewrite_query
params:
index: company_docs
top_k: 20
- id: rerank_docs
type: reranker
depends_on:
- retrieve_docs
params:
model: bge-reranker
top_k: 5
- id: build_context
type: context_builder
depends_on:
- rerank_docs
params:
max_tokens: 4000
include_source: true
- id: generate_answer
type: llm
depends_on:
- build_context
params:
model: deepseek
temperature: 0.2
prompt: |
请基于给定资料回答用户问题。
如果资料不足,请说明无法确认。
这段配置表达了一个完整链路:
- 先结合历史对话改写用户问题;
- 用改写后的问题去知识库检索;
- 对召回结果重新排序;
- 把高质量片段整理成上下文;
- 交给大模型生成答案,并要求基于资料回答。
相比把这些逻辑散落在代码里,YAML 更适合做三件事:
| 能力 | YAML 带来的变化 |
|---|---|
| 流程审查 | 打开配置就能看到完整链路,不需要追踪多层函数调用 |
| 快速调参 | top_k、模型名、提示词、上下文长度都可以直接改 |
| 版本管理 | 每次流程变更都能被 Git 记录,方便回滚和对比 |
YAML 并不意味着业务逻辑完全不用写代码。真正的检索器、重排器、模型调用仍然需要实现,YAML 只是把“怎么把它们串起来”从代码中抽出来。
MCP 组件负责把能力标准化
MCP(Model Context Protocol,模型上下文协议)可以把模型与外部工具、数据源、能力模块连接起来。在 UltraRAG 3.0 的设计里,MCP 更像是组件之间的接口层。
一个组件只要符合约定,就可以被工作流调用。比如:
- 检索组件:输入查询文本,输出候选文档片段;
- 重排组件:输入查询和候选片段,输出排序后的片段;
- 生成组件:输入上下文和提示词,输出答案;
- 工具组件:输入参数,调用外部系统后返回结果;
- 记忆组件:输入用户标识和对话内容,返回相关历史信息。
flowchart LR
A[UltraRAG 编排引擎] --> B[MCP 组件接口]
B --> C[向量检索器]
B --> D[关键词检索器]
B --> E[重排模型]
B --> F[大模型服务]
B --> G[业务工具]
B --> H[对话记忆]
C --> I[(向量数据库)]
D --> J[(全文索引)]
G --> K[业务系统 API]
组件化之后,替换某个环节会更简单。比如知识库问答效果不好,不一定要重写整条链路,可以单独替换检索组件、调整重排模型,或者修改上下文构造策略。
这对复杂 RAG 尤其重要。复杂系统往往不是某一个模型决定质量,而是多环节共同影响结果。组件边界清楚,问题定位才有抓手。
一个请求在 UltraRAG 中如何流转
从用户提问到生成答案,UltraRAG 3.0 更像一个可观察的推理工作流,而不是一次单独的大模型调用。
sequenceDiagram
participant User as 用户
participant App as 应用入口
participant UR as UltraRAG 编排引擎
participant Rewrite as 问题改写组件
participant Retriever as 检索组件
participant Reranker as 重排组件
participant LLM as 大模型组件
User->>App: 提交问题
App->>UR: 调用工作流
UR->>Rewrite: 结合上下文改写问题
Rewrite-->>UR: 返回改写后的查询
UR->>Retriever: 检索相关文档
Retriever-->>UR: 返回候选片段
UR->>Reranker: 对候选片段排序
Reranker-->>UR: 返回高相关片段
UR->>LLM: 发送问题、上下文和提示词
LLM-->>UR: 返回答案
UR-->>App: 返回答案、引用和中间日志
App-->>User: 展示结果
可观察性主要体现在中间结果可见:
- 改写后的问题是什么;
- 检索召回了哪些片段;
- 重排后哪些片段排在前面;
- 最终送给模型的上下文是什么;
- 模型生成答案时使用了哪个提示词;
- 某一步耗时多少、是否报错。
当答案不准确时,可以沿着链路逐层排查:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 答案胡编 | 检索片段不足或提示词约束太弱 | 查看召回内容和生成提示词 |
| 答案引用错资料 | 重排结果不合理 | 检查候选片段分数和排序 |
| 多轮问题理解错 | 历史上下文处理不当 | 查看问题改写结果 |
| 响应很慢 | 检索、重排或模型调用耗时高 | 查看每个组件耗时 |
| 成本过高 | 上下文过长或模型选择不合适 | 调整 top_k、max_tokens 和模型配置 |
UI 的价值:让流程和配置互相映射
UltraRAG 3.0 不只强调配置,也强调 UI。UI 的关键作用不是让系统“看起来更像产品”,而是让流程搭建和 YAML 配置能互相对应。
一种典型使用方式是:
- 在 UI 中拖出 RAG 流程;
- 给每个节点设置模型、索引、top_k、提示词等参数;
- 查看同步生成的 YAML;
- 运行测试问题;
- 根据中间结果调整节点;
- 把稳定后的配置迁移到应用环境。
这种方式对团队协作很有帮助。算法人员可以关注检索策略、重排模型、提示词;后端人员可以关注接口、运行环境、鉴权和日志;产品或业务人员也能看懂大致链路,不必深入代码细节。
内置智能助手也能降低配置理解成本。遇到 YAML 字段含义不清楚时,可以直接围绕当前流程提问,比在大量文档中搜索更快。
UltraRAG 适合什么场景
UltraRAG 3.0 适合那些“RAG 流程本身很重要”的项目。如果只是写一个很小的 demo,直接调用向量库和大模型就够了;如果要长期维护、多轮迭代、多人协作,框架化编排会更有价值。
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 企业知识库问答 | 适合 | 需要检索、重排、引用、权限和效果调试 |
| DeepResearch | 适合 | 通常包含多轮检索、信息整合和复杂推理 |
| 多轮 Agent + RAG | 适合 | 工具调用、记忆、检索链路需要清晰编排 |
| RAG 算法实验 | 适合 | 方便替换检索器、重排器和生成策略 |
| 一次性问答 demo | 不一定适合 | 直接写少量代码更快 |
| 极低延迟在线接口 | 谨慎使用 | 组件化会带来额外编排开销,需要压测 |
| 强定制底层系统 | 视情况而定 | 如果所有环节都高度定制,仍然需要写较多适配代码 |
迁移已有 RAG 流程的思路
已经有一套 RAG 代码时,不需要一次性全部推倒重来。更稳妥的方式是把链路拆开,逐步组件化。
flowchart TD
A[梳理现有 RAG 代码] --> B[拆出核心步骤]
B --> C[把检索封装成组件]
B --> D[把重排封装成组件]
B --> E[把提示词和生成封装成组件]
C --> F[用 YAML 串联流程]
D --> F
E --> F
F --> G[在 UI 中运行测试问题]
G --> H[对比旧系统答案和中间结果]
H --> I[逐步替换线上链路]
迁移时可以按这些步骤走:
-
列出当前链路
把问题改写、检索、重排、上下文构造、生成、引用等步骤列清楚,不要急着改代码。 -
确定每一步的输入输出
例如检索组件输入查询,输出文档片段;重排组件输入候选片段,输出排序结果。边界越清楚,后续越容易封装。 -
先迁移最稳定的环节
检索和生成通常比较适合先组件化,因为输入输出明确。复杂的业务权限、个性化逻辑可以晚一点迁移。 -
用 YAML 复刻旧流程
不要一开始就优化算法,先让新工作流跑出和旧系统接近的结果,再逐步调整。 -
保留对比样例
准备一批典型问题,比较旧系统和 UltraRAG 工作流的召回片段、最终答案、耗时和引用来源。
使用 UltraRAG 时需要注意的坑
1. YAML 配置要纳入工程管理
YAML 很容易改,也很容易被改坏。生产环境里应该把配置纳入 Git 管理,并配合校验流程。至少要保证:
- 配置格式合法;
- 节点依赖关系没有断;
- 模型、索引、工具名称存在;
- 关键参数有默认值或明确说明;
- 线上配置变更可以回滚。
2. 组件不要拆得过细
组件化不是把每一行逻辑都拆成一个节点。节点过多会让流程图复杂,运行开销也会上升。比较合适的粒度是“一个节点完成一个独立能力”,例如问题改写、检索、重排、上下文压缩、答案生成。
3. 检索质量仍然是 RAG 的基础
工作流透明不等于答案一定准确。RAG 的效果仍然依赖文档切分、索引构建、召回策略、重排模型和提示词设计。如果检索不到正确资料,大模型很难稳定回答。
4. 多轮推理要控制上下文长度
DeepResearch 和多轮 Agent 很容易积累大量中间信息。上下文越长,成本越高,噪声也越多。工作流里最好明确哪些信息进入最终生成,哪些只作为中间状态使用。
5. MCP 组件需要关注安全边界
如果组件能访问内部文档、数据库或业务系统,就要考虑鉴权、审计和数据脱敏。尤其是工具调用类组件,不能让大模型自由构造危险请求。
小结
UltraRAG 3.0 的重点不是又封装了一套 RAG 调用接口,而是把 RAG 应用开发中最难维护的部分——推理流程——变成可配置、可查看、可替换的工作流。
它用 YAML 表达链路,用 MCP 标准化组件,用 UI 打通流程设计和配置生成。对于知识库问答、DeepResearch、多轮复杂推理这类应用,透明的编排方式能明显降低调试和迁移成本。真正落地时,仍然要把检索质量、配置管理、组件粒度、安全边界和运行成本控制好,否则再清晰的工作流也无法弥补底层能力的问题。