微信扫码
添加专属顾问
我要投稿
深入了解IBM RAG挑战赛冠军方案,掌握企业级长文档问答系统的构建技巧。 核心内容: 1. 企业RAG知识库落地的三种主流技术路径解析 2. IBM RAG挑战赛规则及评分模型概览 3. 冠军方案Ilry Rice的构建流程与技术细节分享
今天在给 n8n 的 RAG 日报工作流进行信源测试的时候,注意到一条新闻提到 IBM WatsonX AI 赞助一场企业 RAG 挑战赛,用 100 份企业年报做 RAG 问答检验不同架构在真实企业级长文档场景下的效果。
https://abdullin.com/erc/
这个赛事的前两场已经结束,这篇以其中第二场的冠军 Ilya Rice 公开 Blog 中分享的构建 RAG 系统过程中遇到的困难、积累的经验和采用的技巧为基础,我按照实际的系统流程(解析、注入、检索、增强、生成)和各位一起拆解学习下。
https://abdullin.com/ilya/how-to-build-best-rag/
以下,enjoy:
1
三种技术选型回顾
老规矩,在正式开始介绍前,我们再来回顾下当前市场上企业 RAG 知识库落地的三种主流路径。
1.1
直接使用高层级开源框架
这类框架如 RAGFlow, dify, FastGPT 等,主要特点是提供相对完整、开箱即用的 RAG 工作流,目标是简化 RAG 应用的搭建过程,降低开发门槛。反之,劣势主要是定制化和灵活性受限,深度优化和集成特定组件时复杂度较高。
1.2
底层开发框架自主开发
这类框架包括 LangChain, LlamaIndex, Haystack 等,都提供了一系列模块化的构建块、工具和接口。开发者可以根据需求灵活组合和编排 RAG 流程的各个环节(如数据加载、文本分割、嵌入、向量存储、检索策略、LLM 调用、记忆管理、Agent 构建等)。
优势很明显就是灵度灵活,定制化能力强,能够针对特定业务场景进行深度优化和集成。适合对 RAG 流程有精细化控制需求的企业。反之劣势就是需要更多的开发工作量和技术深度。
1.3
云厂商 MaaS 平台方案
如阿里云百炼, 百度智能云千帆, AWS Bedrock, Google Vertex AI Search 等的私有化部署方案,无论是国内还是国外的这些云服务商,都是把 RAG 相关的能力封装成服务或提供私有化部署包,通常与自家的大模型、计算资源、数据存储等深度集成。一般也会提供模型选择、微调、部署、监控等一站式服务。
采用这种方案通常能提供稳定的基础设施、便捷的模型管理和部署、以及与其他云服务的良好兼容性。对于已经深度使用特定云生态的企业来说,集成成本较低。但劣势就如同使用大模型一体机一样,可能存在厂商锁定的风险,跨云迁移或集成非该厂商的服务可能会比较复杂。当然,费用和灵活性也需要考虑。
总结来说,实际生产场景中以上三种选择并非完全互斥,例如以底层框架为基础,但借助云厂商的部分模型服务或基础设施也是中目前常见的组合。
2
比赛规则概况
2.1
任务目标与评分模型
Enterprise RAG Challenge 目标是检验不同 RAG 架构对 100 份上市公司年报 所提出 100 道随机问题 的自动问答能力。每道题必须返回结构化 JSON:value + references,其中 references 至少包含 PDF sha1 + page_index,用来人工复核。
总分 = Retrieval Score (R) ÷ 3 + Generation Score (G),满分 133;设计初衷是让生成质量占据约 3/4 的权重,促使选手在“找得到”与“答得好”之间平衡。
注:这个测评方式各位也可以在企业实践中参考使用
2.2
数据规模与来源
2.3
比赛难点分析
做完这个难点梳理,我想确实这个比赛的冠军方案十分值得好好拆解下。
3
Ilya Rice 的总体架构
首先需要说明的是,Ilya 这个项目采用 “底层库自研 + 多路由 + LLM Rerank” 路线,没有依赖 Ragflow/Dify 等一站式框架。他把整个系统代码开源 (RAG-Challenge-2 on GitHub),代码库有 4500 多行,也从侧面印证了其自主开发的深度。
上面这张是Blog中的贴图,下面我手动整理了一张更直观些
具体来说,每个环节的做法可以拆解如下:
3.1
解析 (Parsing)
财报 PDF 解析的复杂性很有代表性。难点包括: 保留表格结构。 保留关键格式元素(如标题、列表)。 识别多栏文本。 处理图表、图像、公式、页眉页脚等。 表格旋转 90 度导致解析混乱的问题。 字体编码问题方面,有些文档视觉上正常,但复制或解析出来的文本是乱码(后来发现是凯撒密码变体,每个词 ASCII 码位移不同)。 他尝试了大约 24 种 PDF 解析器(小众的、知名的、基于 ML 的、专有 API 的),结论是目前没有解析器能完美处理所有 PDF 细节并完整返回文本内容而不丢失重要信息。
选择与定制解析器: 他最终选择了相对知名的 Docling(由 IBM 开发)。尽管 Docling 表现优秀,但仍缺乏某些关键功能或这些功能存在于无法组合的独立配置中。他深入研究其源码并重写了几个方法,以获得包含所有必要元数据的 JSON 输出。
格式转换与优化: 基于解析得到的 JSON,作者构建了 Markdown 文档(修正了格式)和 HTML 格式(对后续的表格处理非常重要,能近乎完美地转换表格结构)。
处理速度: Docling 虽然快,但在个人笔记本上处理 1.5 万页内容仍无法在 2.5 小时内完成。他租用了带有 4090 GPU 的虚拟机(每小时 70 美分),利用 GPU 加速解析,最终在约 40 分钟内解析完 100 个文档,速度应该说是非常快了。
文本清理: 对于 PDF 解析错误产生的特定语法,使用十几个正则表达式进行清理,以提高可读性和意义。
表序列化方面,在大型表格中,水平标题通常距离垂直标题太远,从而削弱了语义连贯性。 垂直和水平标题之间有 1,500 个不相关的标记。这显著降低了块在向量搜索中的相关性(更不用说表格无法完全放入一个块的情况了)。此外,LLM 很难将指标名称与大型表格中的标题匹配,因此可能会返回错误的值。在对提示符和结构化输出模式进行了大量实验之后,他找到了一个解决方案,即使是 GPT-4o-mini 也能几乎无损地序列化大型表格。最初,他以 Markdown 格式将表格输入到 LLM,但后来切换到了 HTML 格式(事实证明,这种格式很有用)。语言模型对 HTML 格式的理解要好得多,而且它还允许描述包含合并单元格、副标题和其他复杂结构的表格。
3.2
注入 (Ingestion)
竞赛规则要求指定包含相关信息的页面,系统也采用此方法验证模型答案非幻觉。除了将每页文本切分为 300 个 token(约 15 句话)的块。并增加 50 个 token 的重叠的基础操作外。还设置了元数据,给每个 chunk 存储其 ID 和父页面编号。
3.3
向量化
创建了 100 个 FAISS 向量数据库,每个文档一个数据库。他的理由是答案的目标信息总是在单个文档内,无需将所有公司信息混在一起再分离。数据库格式使用了 IndexFlatIP 方法。优点是向量“按原样”存储,无压缩或量化,搜索采用暴力法,精度更高。缺点是计算和内存密集。因将文档分到不同索引,数据量不大,可以使用 Flat 数据库。
相似度计算方面,IP(内积)通过余弦相似度计算相关性得分,通常比 L2(欧氏距离)效果好。嵌入模型使用经典的 text-embedding-3-large。各位常规处理中文文档时,可以选择中文版本的分支。
3.4
检索 (Retrieval)
他采用了 LLM 重排,核心方法是将文本和问题传递给 LLM,询问“此文本对回答问题是否有帮助?帮助程度如何?从 0 到 1 评分。” 以前因为 token 成本问题这种做法开销实在太高,他这次选择使用 GPT-4o-mini,当然是在向量搜索初步筛选后应用。据说是使用 GPT-4o-mini 重排成本低于每问题 1 美分。校正后的相关性得分使用加权平均:vector_weight = 0.3, llm_weight = 0.7。父页面检索方面,找到 top_n 相关块后,不直接使用这些块,而是将其用作指向完整页面的指针,然后将完整页面内容放入上下文。
他的方案里最终检索器步骤可以总结为:向量化查询→基于查询向量找到 top 30 相关块(去重)→通过块元数据提取页面→将页面传递给 LLM 重排器→调整页面相关性得分→返回 top 10 页面,每页前加上页码,合并为单个字符串。
3.5
增强 (Augmentation)
他选择把提示词存储在专用的 prompts.py 文件中,并拆分为以下四种逻辑块: 1、核心系统指令。 2、定义 LLM 预期响应格式的 Pydantic 模式。 3、用于创建 one-shot/few-shot 提示的示例问答对。4、 插入上下文和查询的模板。
这种做法的灵活性在于一个小函数根据需要将这些块组合成最终的提示配置,方便灵活测试不同配置。 同时也有很高的可维护性,重复指令放入共享块,在多个提示中复用,避免同步更新的麻烦和错误。这种做法也算是目前业界的有共识的最佳实践了,大家可以参考下。
3.6
生成 (Generation)
注:这部分细节很多,但都很重要。
因为每个报告有其独立的向量数据库,问题生成器设计使得公司名称总是在问题中明确出现。他有一个公司名称列表,通过 re.search()从查询中提取公司名称,并将其匹配到相应的数据库。这样就让搜索空间缩小 100 倍。
提示词路由方面,因为竞赛要求答案格式简洁且严格符合数据类型(int/float, bool, str, list[str])。每种类型都有 3-6 个细微差别需要考虑。给 LLM 过多规则会导致其忽略某些规则。 由于预期响应类型是明确给出的,因此仅根据答案类型向提示词提供相关的指令集(写了 4 个提示变体,用 if/else 选择)。
复合查询路由方面, 比较多家公司指标的复杂问题(如“苹果和微软谁的收入更高?”)不适合简单查询的范式。 而是设计成了模仿人类处理方式, 将初始比较问题传递给 LLM,要求其创建更简单的子问题,以分别提取每家公司的指标(例如“苹果的收入是多少?”和“微软的收入是多少?”)。 通过标准流程分别处理这些简单子问题。 将收集到的各公司答案传入上下文,以回答原始问题。
思维链这部分对于多跳问题确实是刚需,他在脚本中明确指导模型如何推理(解释推理步骤、目标、提供示例)。根据提示指令明确构建推理步骤可显著增强规则遵循性,实测确实显著减少了幻觉。
结构化输出的设计目的是强制模型以严格定义的格式响应(通常作为 API 的单独参数,如 Pydantic 或 JSON 模式)。 好处就是保证模型始终返回严格遵守所提供模式的有效 JSON。字段描述也可以包含在响应模式中,作为提示的一部分。在生成过程中,模型有一个专门用于推理的字段和一个用于最终答案的独立字段。他主模式包含四个字段: step_by_step_analysis (CoT 本身)、 reasoning_summary (前一字段的浓缩摘要,便于跟踪)、 relevant_pages (答案引用的报告页码) 、final_answer (按竞赛要求格式化的简洁答案,根据不同答案类型变化) 。在上述基础上还有个 SO Reparser (SO 解析修正器)的设计,考虑到并非所有 LLM 都支持保证完全遵守模式的 SO,他选择编写一个回退方法,使用 schema.model_validate(answer)验证模型响应是否符合模式。如果验证失败,则将响应发送回 LLM,提示其遵从模式。据说是这个方法使模式符合率恢复到 100%,即使是 8b 模型。这看起来也是个最佳实践了。
class RetrievalRankingSingleBlock(BaseModel): """Rank retrieved text block relevance to a query.""" reasoning: str = Field( description=( "Analysis of the block, identifying key information and how it " "relates to the query" ) ) relevance_score: float = Field( description=( "Relevance score from 0 to 1, where 0 is Completely Irrelevant " "and 1 is Perfectly Relevant" ) )
这是 LLM 重新排名的 Pydantic 模式
一次性提示 (One-shot Prompts)方面,他在每个提示中添加一个“问题 -> 答案”对(答案采用 SO 定义的 JSON 格式)。这种做法会有很多好处,既可以演示逐步推理过程,也可以 进一步澄清在挑战性案例中的正确行为(帮助校准模型偏见),也说明模型答案应遵循的 JSON 结构(对缺乏原生 SO 支持的模型特别有用)。 我个人经验来看,精心制作示例答案确实至关重要,示例质量对响应质量实测是有直接影响的。
指令优化 (Instruction Refinement)的核心是理解客户需求(问题和答案要求), 他在这一步的工程化努力在于,手动创建了验证集。因为赛前一周问题生成器代码公开,他生成了 100 个问题和验证集。手动回答问题虽然繁琐,但有助于客观衡量系统改进。 将所有澄清作为指令集纳入提示。例如,数字类型答案如何处理单位(千、百万)、负数括号表示法;名称类型答案只返回职位名称等。 对于模型难以遵循的指令(如数字单位转换),用简短示例补充指令。这个细节也是非常值得学习的。
系统处理响应方面,竞赛规则要求 10 分钟内回答 100 个问题。他充分利用 OpenAI 的 TPM 限制(Tier 2: GPT-4o-mini 200 万 TPM, GPT-4o 45 万 TPM),估计了每个问题的 token 消耗,并以 25 个问题为一批进行处理。系统在 2 分钟内完成了所有 100 个问题。拆解到这里,不得不说,这哥们能拿冠军确实还是下了真功夫的。
4
写在最后
4.1
Ilya Rice 夺冠的核心因素
总结来说,Ilya Rice 的并非依赖“终极模型”或“单一技巧”,而是靠面向任务的系统工程 + 可度量的迭代实验。
系统性方法论
解决方案覆盖 Parsing → Cleaning → Ingestion → Retrieval → Rerank → Routing → Generation → Evaluation 的全链路,并为每一步预留可替换配置
深度理解赛题与数据
他洞悉官方评测「R ÷ 3 + G」配比,把大部分精力投向提升生成分,同时用「一文一库」+ 正则路由保证检索基础分不丢。
精细化组件调优
Docling 二次开发,实现 1.5 万页 40 min 解析;Top-30 向量检索后采用 GPT-4o-mini LLM Rerank(0.7 × LLM + 0.3 × embed),单问成本 < $0.01 且显著提召回。
严谨的实验与评估流程
公开 repo 中内置多套 config,附带官方 rank.py 可本地跑分;通过自建验证集 A/B 切换表格序列化、Hybrid Search 等实验,最终确定最优组合 。
class RunConfig: use_serialized_tables: bool = False parent_document_retrieval: bool = False use_vector_dbs: bool = True use_bm25_db: bool = False llm_reranking: bool = False llm_reranking_sample_size: int = 30 top_n_retrieval: int = 10 api_provider: str = "openai" answering_model: str = "gpt-4o-mini-2024-07-18"
4.2
对 RAG 实践的启发
内容比较多,整个表格对照参考:
4.3
实践才是硬道理
光说不练假把式, Ilya Rice的完整方案实现已开源,包含示例数据与CLI 脚本,适合边读边复现。
Anyway,耐心、细节与量化,才是把 RAG 做到可用、好用、能在企业里落地的真正“配方”。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-10-27
2024-09-04
2024-05-05
2024-07-18
2024-06-20
2024-06-13
2024-07-09
2024-07-09
2024-05-19
2024-07-07
2025-05-16
2025-05-15
2025-05-14
2025-05-14
2025-05-13
2025-05-11
2025-05-08
2025-05-05