本教程将带你全面解析RAGFlow分片引擎的核心架构与实际执行流程。从切片参数配置、任务启动触发到异步消费处理,我们将逐步拆解其底层的硬核设计理念与视觉增强实用技巧,帮助你系统掌握这一关键技术的应用方法。
背景
RAG(检索增强生成)的代码结构较为复杂,各模块环环相扣。我们将分片流程划分为以下三个核心环节:
- 切片设置:完成解析器参数设定与文档属性配置。
- 启动任务:依据配置生成并分发具体的处理任务。
- 异步消费:任务执行器以异步方式处理并完成分片操作。
注意: 以下代码基于当天更新的版本,部分功能(如视觉增强)尚未正式发布。
切片设置
查找接口
通过对比接口请求参数与界面设置,我们梳理出以下关键配置项:
doc_id: 文档的唯一标识ID。parser_config: 文档解析配置,包含若干子参数:task_page_size: 每个任务处理的页面大小。layout_recognize: 选用的解析器类型,默认使用 DeepDOC。chunk_token_num: 每个文本块的最大Token数量。delimiter: 分段标识符。auto_keywords: 是否自动抽取关键词。auto_questions: 是否自动提取问题。raptor: 召回增强RAPTOR策略配置。use_raptor: 是否启用RAPTOR机制。
graphrag: 知识图谱相关配置。use_graphrag: 是否使用知识图谱。entity_types: 实体类型列表。method: 知识图谱构建方式。community: 实体归一化与社区报告设置。
代码实现:change_parser 方法
在 documnet_app.py 文件中,找到 change_parser 方法,这是修改解析器配置的核心入口。
@manager.route('/change_parser', methods=['POST'])
@login_required
@validate_request("doc_id", "parser_id")
def change_parser():
req = request.json
# 权限校验
if not DocumentService.accessible(req["doc_id"], current_user.id):
try:
# 解析器切换验证
e, doc = DocumentService.get_by_id(req["doc_id"])
if ((doc.type == FileType.VISUAL and req["parser_id"] != "picture")
or (re.search(
r".(ppt|pptx|pages)$", doc.name) and req["parser_id"] != "presentation")):
return get_data_error_result(message="Not supported yet!")
e = DocumentService.update_by_id(doc.id,
{"parser_id": req["parser_id"], "progress": 0, "progress_msg": "",
"run": TaskStatus.UNSTART.value})
if not e:
return get_data_error_result(message="Document not found!")
if "parser_config" in req:
DocumentService.update_parser_config(doc.id, req["parser_config"])
if doc.token_num > 0:
e = DocumentService.increment_chunk_num(doc.id, doc.kb_id, doc.token_num * -1, doc.chunk_num * -1,
doc.process_duation * -1)
if not e:
return get_data_error_result(message="Document not found!")
tenant_id = DocumentService.get_tenant_id(req["doc_id"])
if not tenant_id:
return get_data_error_result(message="Tenant not found!")
if settings.docStoreConn.indexExist(search.index_name(tenant_id), doc.kb_id):
settings.docStoreConn.delete({"doc_id": doc.id}, search.index_name(tenant_id), doc.kb_id)
return get_json_result(data=True)
except Exception as e:
return server_error_response(e)
上述代码的执行流程如下:
- 权限校验: 确认当前用户是否具备操作权限。
- 解析器切换验证: 视觉文件(
FileType.VISUAL)只能使用picture解析器;PPT类文件只能使用presentation解析器。 - 更新文档状态: 将文档运行状态重置为
UNSTART(尚未启动)。 - 重置统计信息: 将
token_num、chunk_num等统计数据归零。 - 删除旧索引: 清理与文档关联的搜索索引数据。
整体流程示意图:
POST /change_parser → 权限检查 → 解析器类型验证 → 更新解析器配置 → 删除旧索引 → 返回操作结果
小提示: 在调整文档的分片策略时,务必通过 change_parser 接口先重置状态,否则旧的分片数据可能干扰新的解析流程。
启动任务
点击文档后的启动按钮,将触发任务生成逻辑。核心方法位于 api/db/services/task_service.py 中。
代码逻辑分为两段:
- 任务分割: 根据文档类型决定每个任务处理的页面量。
- 默认:每任务处理 12 页。
- 学术论文:每任务处理 22 页。
- 特殊文档:单任务处理全部页面。
- Excel文件:每任务处理 3000 行。
- 生成任务: 为每个任务生成唯一
task_digest和初始进度,并根据优先级入队。
任务入队机制: 使用 Redis 消息队列,默认队列名为 rag_flow_svr_queue。高优先级任务会使用独立的队列。
整体流程示意图:
开始 → 文档类型判断(PDF/Excel/其他) → 分片处理(PDF分片/表格分片/单任务处理) → 生成任务摘要 → 历史任务检查(是否可复用) → 数据清理 → 任务持久化 → 未任务入队 → 结束
任务消费与处理
任务执行器位于 rag/svr/task_executor.py 中,启动后会进入一个死循环,不断从Redis队列中获取并处理任务。
核心消费主循环
async def handle_task():
# 通过Redis消息队列从 `rag_flow_svr_queue` 获取任务
redis_msg, task = await collect()
if not task:
# 没有获取到任务,休眠5秒
await trio.sleep(5)
return
try:
# 状态记录
CURRENT_TASKS[task["id"]] = copy.deepcopy(task)
# 核心处理
await do_handle_task(task)
# 成功处理
DONE_TASKS += 1
except Exception as e:
# 异常处理
FAILED_TASKS += 1
set_progress(task_id, -1, str(e))
接下来,我们深入 do_handle_task 方法的核心逻辑:
# 绑定进度回调
progress_callback = partial(set_progress, task_id, ...)
# 任务状态检查
if TaskService.do_cancel(task_id):
# 主动取消
progress_callback(-1, "Task canceled")
return
根据任务类型(标准模式/GraphRAG模式/RAPTOR模式),执行不同的处理路径:
任务类型判断 → 标准分片 / GraphRAG模式(知识图谱构建) / RAPTOR模式(层次化摘要) → 初始化Chat模型 → 执行核心逻辑 → 生成原始分片 → 向量编码
默认分片中的关键方法:
# 分片,这个是核心
chunks = await build_chunks(task, progress_callback)
# 所有的分片向量化,并将向量结果写入到每个chunk的["q_%d_vec" % len(v)] = v
token_count, vector_size = await embedding(chunks, embedding_model, task_parser_config, progress_callback)
在 build_chunks 方法中,最终会调用 rag/app/naive.py 文件的 chunk 方法。该方法会根据切片配置进行精细化处理:
输入文件格式判断(DOCX/PDF/Excel/TXT/Code/Markdown/HTML/JSON)→ DOCX解析器 / PDF解析器(布局识别) / 表格解析器 / 文本分割器 / MD表格提取 / 结构化解析 → 原始分片生成 → 是否视觉增强? → 是:视觉模型处理图表 → 基础分片处理 → 分片合并 → Token化处理 → 输出结构化分片
视觉增强技巧: 在最新版本中,系统会使用视觉模型对文档中的图表进行增强处理,提取更丰富的语义信息,但该代码目前尚未发布。
整个异步处理的完整流程如下:
main入口 → 初始化系统(加载配置、设置信号处理、初始化内存追踪) → 启动监控线程 → 任务处理循环 → 检查未ACK消息 → 获取任务详情(拉取新消息) → 验证任务有效性 → 记录开始状态 → 执行核心处理(更新进度) → 记录完成状态 → 捕获错误(构造错误信息、更新失败状态) → 释放内存引用 → 发送ACK → 更新计数器 → 资源清理 → 异常处理
小提示: 如果任务处理失败,可以检查 FAILED_TASKS 计数和错误信息。常见原因包括:解析器配置错误、模型调用超时、或文档格式不兼容。
常见问题(FAQ)
1. 如果解析器类型切换错了,如何恢复?
答案: 使用 change_parser 接口,将 parser_id 参数改为正确的解析器类型,并重新设置 parser_config。系统会自动重置文档状态并清理旧索引。
2. 任务一直显示“未启动”,怎么办?
答案: 检查Redis队列是否正常运行,以及 task_executor.py 是否成功启动。若队列有堆积,可能是有任务卡住,可以手动清除 rag_flow_svr_queue 中的消息后重启执行器。
3. 如何优化分片效果(如减少文本块大小)?
答案: 调整 parser_config 中的 chunk_token_num 参数,降低其值。同时,可以调整 delimiter 分段标识符来控制分片粒度。
后记
通过本次源码解析,我们可以预见RAGFlow在后续版本中的几个重要升级方向:
Agent版本管理:最多保留20个历史版本,便于回滚与审计。Agent团队权限功能:支持多用户协作,精细化访问控制。- 视觉模型增强:针对复杂结构(图表、公式等)进行深度语义提取,提升检索质量。
掌握这些核心机制,你将能更灵活地定制RAGFlow的分片策略,为后续的检索与生成任务打下坚实基础。
