制造业里的 RAG 项目跟互联网场景最大的区别在于它没有一个“宽松的容错率”。你让一个通用问答机器人去回答“今天天气怎么样”说错了没人找你麻烦。但你要是让一个设备维护助手把故障代码 AL-401 的排查步骤讲错了产线停一天损失就是几十万老师傅的脸色比停机报警灯还难看。所以当我在某制造企业的数字化团队里把“设备手册问答”这件事从零做到能落地又把这套能力抽出来写成开源框架 MaRAGManufacturing RAG 的缩写时最核心的设计原则从来不是“模型有多聪明”而是“答案能被溯源、逻辑能被约束、错误能被兜底”。这篇内容我就把这套框架从需求拆解、架构设计到关键实现、踩坑记录完整捋一遍。适合正在做制造知识库、设备故障诊断助手或者想在企业里落地 RAG 的工程师参考也适合准备把 RAG 从演示 demo 推向生产环境的人。1. 先聊为什么做这件事制造业 RAG 到底难在哪1.1 通用 RAG 在车间里翻车的三个场景先说三个真实场景都是我在做项目时反复遇到的。第一设备手册是 PDF 扫描件。某进口数控系统的操作手册一共 600 多页全是扫描图OCR 出来的文本中英文夹着表格全乱。通用 RAG 拿这种文档做知识库检索出来的片段经常是“半句话加一个断裂的表格行”模型看一眼就蒙了生成的回答自然也不可用。第二故障代码要“精确匹配”不是“语义相似”。故障码 E3042 和 E3204 长得像但一个是伺服过载一个是编码器断线。语义检索按向量相似度排序很容易把这两个混淆。产线老师傅要的不是“大概意思是”的答案而是“查表可知你得先看哪个 LED 灯”的确定性。第三安全相关的内容不能“自由发挥”。比如某个操作步骤里明确规定“维护前必须切断主电源并等待 5 分钟”如果模型在生成时把“5 分钟”说成“5 秒”这个错误在纯文本对话里看起来不起眼但在车间里就是安全事故。这三个场景概括下来就是制造业 RAG 的三个特殊性文档形态复杂、语义精度要求高、输出安全约束强。1.2 设备手册类文档的特殊性设备手册跟通用知识库里的文章有个本质区别它是一本“操作契约”不是一篇“科普文章”。科普文章允许模糊比如“适当调整参数”“根据实际情况选择”设备手册必须精确比如“调整参数 P201 至 1200~1500r/min若超过 1500 需先确认齿轮箱油温低于 60℃”。这种差异决定了 RAG 的处理方式完全不同。从文本结构来看设备手册通常包含章节层级第几章第几节、编号体系部件号、故障码、参数号、表格数据参数表、报警表、扭矩表、图表引用见图 3-7、警告标识警告/注意/提示。这些结构化特征是通用文档没有的也是普通 RAG 最容易丢失的信息。我自己总结过一个比值一份 500 页的设备手册里能被“直接按段落切割 向量化”有效利用的文本通常不到 30%。剩下 70% 的信息在表格里、在编号的关联关系里、在章节的上下文中。如果你不针对这个特点做处理RAG 的“R”检索从一开始就是瘸的。1.3 框架要解决的核问题清单在动手写框架之前我把需求整理成了四句话能把扫描版 PDF、Excel 参数表、维修记录、操作 SOP 全部吃进去并且不乱在面对故障代码、参数核验这类问题时能“按图索骥”而不是“凭感觉说”生成的回答必须带出处定位到页码、章节、表格行方便老师傅复核对安全相关的内容宁可拒绝回答也不能编造。这套需求清单其实就是 MaRAG 的设计目标后面所有的代码、模块、配置项都是围绕这四句话展开的。如果你也在做类似的项目建议开场先把需求写成这样可验收的条目而不是“做一个智能问答系统”这种空话。2. 架构设计把制造业 RAG 拆成四层管线2.1 文档接入层的“格式战争”第一层要做的事情是解决“吃文档”的问题。制造业的知识资产几乎涵盖了你能想到的所有格式PDF含扫描件、Word 操作流程、Excel 参数表、PPT 培训材料、图片格式的电路图、甚至老的 txt 维修记录。我的处理原则很简单能转到文本的就转转不动的走 OCR所有表格单独走表格解析通道。这一层在框架里叫 ingest。具体来说可复制文本的 PDF用现成的 PDF 解析库提取文本但要额外做“版面分析”把页眉页脚、目录、正文、表格区域区分开。扫描 PDF先转成高清图片再用 OCR 识别识别时要按“从上到下、从左到右”的阅读顺序排列文本块。Excel 参数表不整表向量化而是拆成“表头 行记录”的结构化数据每条记录带上工作表名和单元格位置。维修记录这些往往是纯文本但内容脏有错别字、口语化说法、时间格式混乱需要规则清洗。我把不同格式的处理策略整理成了一张表方便你对照文档类型处理方式输出形态文本型 PDF提取文本 版面分析段落切片、表格识别坐标扫描型 PDF图像预处理 OCR坐标排序后的段落文本Excel 参数表表头识别 行记录拆分结构化字段记录Word SOP段落解析 标题层级提取带章节路径的文本切片维修记录规则清洗 关键信息抽取结构化事件记录2.2 知识构建层的“结构化优先”原则文档解析完之后第二步不是直接切片丢进向量库而是先做一轮“知识结构化”。这是制造业 RAG 与通用 RAG 最不一样的地方。我称之为“结构化优先”原则凡是能从文档中抽出结构化信息的优先抽成结构化数据只有那些无法结构化的描述性段落才退化为纯文本切片。比如设备参数表抽出来就是字段参数编号、名称、取值范围、单位、适用工况、备注。每一条记录都是一个独立条目而不是一段文本里的半句话。故障代码表抽出来就是故障码、故障名称、可能原因列表、排查步骤、相关 LED 或指示灯状态。其中“排查步骤”还需要按顺序编号。这样做有几个直接好处检索时可以在结构化字段上做精确过滤比如“只查参数 P201 的取值范围”生成时可以让模型基于结构化的行数据来回答显著减少“把表格说错”的概率溯源时可以直接定位到“表 3-2 第 4 行”而不是“某段落某句”。在实际操作中知识库我存了两份一份是结构化数据库存参数表、故障表、备件表一份是向量数据库存段落级描述文本。两份之间通过“设备型号 章节编号 部件编号”建立关联。2.3 检索层的混合策略第三层是检索。我采用的方案是“BM25 关键词检索 向量语义检索 结构化字段过滤”三路混合然后做一个轻量的重排。为什么不能只用向量检索因为在故障码场景里“E3042”和“伺服过载”这两个词前者是精确标识符后者是语义描述。向量模型做语义可以做精确标识符的匹配不够可靠。BM25 对关键词匹配则非常稳定。结构化字段过滤则能处理类似“只看型号为 XH-200 的设备”这种条件约束。检索流程大致是收到问题后先用规则提取问题里的设备型号、故障码、参数号等关键实体然后用这些实体做结构化过滤缩小候选范围再用关键词和向量双路召回最后用一个重排模型把最相关的几个片段排在前面。我在框架里用的重排是“双塔精排 规则加权”的轻量组合没有上很重的排序模型因为在生产环境里稳定性和速度一样重要。2.4 推理层的约束生成最后一层是生成。这里我没用“把检索片段一股脑塞给模型”的简单做法而是引入了两个约束机制。第一个约束是“引用约束”要求模型在回答中必须标注每个事实的出处来源文档、页码、表格位置。如果某句话没有出处支撑模型要明确说“手册中未提供该信息”。我通过 Prompt 模板和后处理规则双重保证这一点。第二个约束是“安全兜底”如果问题涉及安全操作维护、检修、带电操作且检索结果中找不到明确步骤模型必须拒绝回答并提示操作人员参考现场挂牌、持证要求等规定而不是尝试编造。这个约束在代码里是一组“安全主题关键词 输出重试机制”实现的。四层管线的设计并不复杂但每层都解决一个通用 RAG 没有考虑到的问题。下面拆解这四层管线组合起来的具体能力。3. 核心能力拆解从手册问答到故障诊断的跃迁3.1 设备手册问答让 RAG 学会“指哪打哪”框架的第一类能力是设备手册问答。它的用户场景是车间技术员在巡检时发现某个参数异常问“主轴转速上限在哪设置”系统要能回答“在参数 P202 中设置取值范围 0~8000r/min具体位置为主轴参数组第 5 页”。这类问题的关键是“定位”而不是“解释”。我在实现时做了两个处理一是段落切分时保留“章节路径”。每个切片都带上“第 3 章 主轴系统 3.2 参数设置 表 3-1”这样的路径元信息检索后不仅能返回内容还能返回定位信息。这样老师傅拿到回答后可以直接翻手册核验而不是对着一个孤零零的文本片段发愣。二是对参数类问题走了结构化查询。框架先尝试从问题里识别参数编号比如 P202如果命中就直接查结构化参数表把参数名、范围、单位、备注一并取出再让模型用自然语言组织回答。这一步绕过了向量检索的不确定性准确率从 78% 提升到了 96% 左右。3.2 故障代码诊断精确匹配与上下文推理故障诊断是制造业 RAG 最有价值也最难的能力。难点在于故障诊断不是“查到一个表”就完事而是“查表 多因素推理”的结合。举个例子报警代码 AL-401 可能同时出现在主轴驱动器过温、电机风扇故障、环境温度过高三种情况下。手册里给出的排查步骤是“先检查风扇是否运转再测量环境温度若都正常则检查驱动器温度传感器”。一个合格的故障诊断助手不仅要把这段步骤检索出来还要结合设备当前的状态信息比如该设备最近 3 天有 2 次过温报警记录来给出排序建议。MaRAG 在实现时对故障代码做了三层设计第一层是故障码词典从手册和维修记录中抽取“故障码 - 名称 - 现象 - 原因列表 - 排查步骤”的结构化数据支持精确查表。第二层是关联线索库把每个故障码关联到相关参数、相关部件、常见维修记录。这部分数据是从维修工单里挖掘的能补全手册里没有的“现场经验”。第三层是推理模板当检索到的故障码有多条可能原因时模板引导模型按“先检查现象 A再测量参数 B若不符合再排查部件 C”的方式生成回答避免模型自由发挥。实测下来故障码查得准诊断推理也基本能跟上老师傅的思路是这套框架里效果提升最明显的一部分。3.3 参数核验与安全规范检查除了问答和诊断还有两类偏“核验”的能力在企业里非常常用。参数核验指的是操作人员提供一个参数值和场景系统判断这个值是否在允许范围内。比如“在高速切削工况下设置主轴转速 8500r/min 可以吗”系统查参数表发现上限是 8000于是回答“不可行超过上限 500r/min建议降至 8000 以下”。这类能力的关键是“数值比较 工况匹配”本质上是结构化查询不依赖大模型的想象力。安全规范检查指的是当用户询问操作步骤时系统自动检查回答中是否遗漏了安全前置条件。我在生成阶段加了一道“安全条件核查”子模块如果检索到的原文里有“警告”“注意”标识的句子系统会强制要求模型在回答开头引用这些句子。比如步骤正文是“松开夹紧螺栓”但原文警告“操作前必须泄压”那生成的回答必须把泄压放在最前面。这个细节做与不做直接决定了系统能不能过企业安全管理制度评审。3.4 多设备对比与变更追溯这是拓展功能但经常被企业点名。企业里有多种型号的设备同一个故障码在不同型号上的处理方式可能不同设备手册还会升级某个操作步骤在新版手册里改了。RAG 如果只做单文档问答这些问题都答不好。多设备对比的实现是在结构化知识里加了“适用型号”字段对比类问题“A 型号和 B 型号的润滑周期一样吗”可以同时查多台设备的结构化表然后把差异列出来。变更追溯则依赖“文档版本号 变更记录”元信息当用户在提问时指定“按 2023 版手册”时检索会强制过滤到对应版本。这块我在框架里预留了数据模型没有做得太重因为不同企业的变更管理流程差异很大。4. 开源框架的实现细节目录结构、关键模块与配置4.1 项目目录设计与核心流程说完了能力聊聊代码。MaRAG 用 Python 编写核心流程是“管道-插件”模式。项目目录大致如下MaRAG/ ├── ingest/ # 文档接入与解析 │ ├── pdf_parser.py # PDF 解析含扫描件 │ ├── excel_parser.py # Excel 参数表解析 │ ├── ocr_engine.py # OCR 封装 │ └── schema.py # 数据模型定义 ├── knowledge/ │ ├── builder.py # 知识构建与入库 │ ├── struct_store.py # 结构化数据存储SQLite │ └── vector_store.py # 向量库封装 ├── retrieval/ │ ├── hybrid.py # BM25 向量 结构化过滤 │ ├── rerank.py # 轻量重排 │ └── entity.py # 设备型号/故障码/参数号实体识别 ├── generation/ │ ├── prompt.py # 带约束的 Prompt 模板 │ ├── constraints.py # 安全兜底与引用约束 │ └── generator.py # 模型调用与后处理 ├── app/ │ ├── api.py # FastAPI 接口 │ └── cli.py # 命令行交互 └── config.yaml # 全局配置核心流程是ingest 负责把文档转成中间结构knowledge 负责把中间结构写入存储retrieval 负责从存储里查候选generation 负责把候选变成有约束的回答。每个模块都定义了接口可以替换实现。比如你不想用 SQLite可以换 PostgreSQL不想用开源向量库可以换企业级向量数据库。4.2 关键模块一多格式文档解析器ingest 里的解析器是第一个难点。这里我分享一个关键实现思路解析器不追求把文档“完美还原”而是追求“别丢结构”。以 Excel 参数表为例直接读取单元格不难难的是知道哪些行是表头、哪些列是连续的参数块、哪些空行表示分节。我的处理是先按“非空行”分块再用一个简单的启发式如果某行的第二列是数字、第三列是单位r/min、mm、kW就认为这一行是一条参数记录如果某行的单元格里全是汉字且没有数字就认为它是分节标题。这样解析出来的结构90% 的情况是准确的剩下 10% 我会在可视化工具里让人工修正。扫描版 PDF 的处理要更重一些。我的经验是OCR 之前先做一次图像预处理转灰度、去黑边、增强对比度识别率能提升不少。OCR 之后要按坐标重建阅读顺序简单做法是把识别出的文本块按 y 坐标排序同一行内按 x 坐标排序再拼成段落。虽然比不上专业的版面还原算法但对设备手册这种版式相对固定的文档已经够用。4.3 关键模块二故障知识图谱的轻量构建故障诊断需要跨表格、跨文档的关联信息。我没上重型知识图谱框架而是用几张关联表实现的“轻量图谱”。表结构大致是故障码表: 故障码, 名称, 可能原因(json列表), 排查步骤(json有序列表), 适用型号, 关联参数, 手册来源, 页码 部件表: 部件编号, 名称, 所属系统, 常见故障码列表, 维护周期 维修记录表: 设备型号, 故障码, 处理内容, 处理人员(脱敏), 日期这三张表之间通过“故障码”和“设备型号”关联。检索时如果问题命中故障码系统可以把三张表的数据拼装成一个上下文包一并交给生成模块。比如用户问“AL-401 怎么处理”系统返回的上下文包括故障码定义、手册里的排查步骤、维修记录里常见处理方式、关联参数。这样生成的回答既有手册依据又有现场经验。做这个模块时我最大的体会是轻量数据结构只要设计得当比所谓的大规模知识图谱更实用因为维护成本低解析文档时就能自动成表。4.4 关键模块三混合检索器retrieval 里的 hybrid.py 是最核心的一个模块。它的输入是问题文本输出是排序后的候选上下文列表。我实现的伪代码逻辑如下def hybrid_search(question): entities extract_entities(question) # 提取型号/故障码/参数号 candidates set() # 路径1: 结构化精确过滤 if entities[fault_code]: records struct_store.query_fault(entities[fault_code]) candidates.update(records) # 路径2: 关键词检索(BM25) bm25_hits bm25_index.search(question, top_k20) candidates.update(bm25_hits) # 路径3: 向量语义检索 vec_hits vector_store.search(embed(question), top_k20) candidates.update(vec_hits) # 重排: 结构化命中的排最前, 再按语义相关度排序 ranked rerank(question, candidates) return ranked关键在于结构化命中永远是最高优先级因为它是“查表”结果可信度最高BM25 和向量检索结果作为补充。重排时我加上了一个规则如果候选中包含与问题故障码完全一致的记录其他候选的得分全部降 0.3 个档位。这个规则简单粗暴但确实把精确匹配的效果拉满。4.5 关键模块四受约束的生成器生成模块的核心是一个带 JSON 约束的 Prompt 模板和一套后处理规则。Prompt 模板要求模型按固定格式输出{ answer: 自然语言回答, citations: [来源1, 来源2], confidence: high|medium|low, refusal: null }其中 refusal 字段专门用于安全兜底如果判断问题涉及安全操作但上下文不足模型置 refusal 为“手册未提供明确安全步骤请参考现场规定”系统检测到该字段后直接返回拒绝话术不再把 answer 展示给用户。这个设计避免了模型硬着头皮编造答案。citations 字段的格式是“文档名 章节路径 页码”。为了让模型能准确输出这些信息我在输入上下文的每个片段前都加了元信息前缀例如[来源: 操作手册2023版, 第7章 主轴维护, 第82页]模型只需要原样引用前缀这比让模型自己回忆来源可靠得多。4.6 部署与配置参考最后是部署层面。框架本身不限模型我测试时用的是一块普通 GPU 上能跑的开源模型效果已经能用如果追求更高准确率可以换成更强的商用模型接口Prompt 模板不需要改。向量库用的开源实现结构化存储直接用的是 SQLite一个小型制造企业的知识库几百份文档、几十万条参数和故障记录完全放得下。config.yaml 里比较关键的配置项有ingest: ocr_lang: chi_simeng table_detect: true knowledge: struct_db: sqlite:///data/kb.db vector_store_path: ./data/vector_store retrieval: use_struct_filter: true bm25_weight: 0.4 vector_weight: 0.6 rerank: true generation: model: local safety_keywords: [断电, 泄压, 挂牌, 上锁] citation_required: true其中 safety_keywords 值得多说一句它不只是一个词汇列表而是和检索结果联动的。只有命中安全关键词且检索上下文里找不到对应安全说明时系统才会拒绝回答。如果手册里明确写了安全步骤系统仍然会正常回答但会强制把安全步骤放在最前面。5. 踩坑实录与调试经验5.1 解析环节的经典翻车现场解析这层我踩的坑最多列几个典型的。第一个坑PDF 表格用文本解析读出来是“一行一行散开的字”。文字版 PDF 的表格在纯文本流里根本没有行列信息必须用坐标判断“哪些词在同一行、同一列”。我一开始没做这个参数表解析出来全是乱的检索出来的“参数取值”经常是“1200 1500 r/min”这种东西混在一起。后来改成按坐标聚类问题解决。第二个坑扫描件 OCR 出来的英文数字串很不可靠。故障代码里最常见的混淆是“0”和“O”、“1”和“l”、“8”和“B”。我加了一层“故障码合法性校验”凡是 OCR 结果里出现的故障码如果不在手册已有的故障码集合里就标记为“疑似识别错误”并尝试用编辑距离纠偏。这个环节把故障码识别准确率从 85% 提到了 97%。第三个坑Excel 解析时合并单元格。很多参数表有合并表头直接按行列读会得到一堆空值。我的处理是“向前填充”策略合并单元格的值其实只存在左上角一个单元格里读取时遇到空值就用同列上一行的值补上。很基础但很管用遇到带合并单元格的参数表一定要记得处理。5.2 检索效果不理想的排查顺序如果你跑起来发现答非所问我建议按这个顺序排查。一是先看“检索出来的是什么”。很多人直接看最终回答其实问题大概率出在检索环节。我会先打印检索出的候选片段如果候选里根本没有正确答案那就别怪模型先去修切分或解析。这个习惯能帮你省掉大量无效调参时间。二是再看“检索排序对不对”。候选里有正确答案但排在第 10 名说明重排策略不行。对制造业场景我建议优先把“结构化字段命中”作为排序第一特征语义相关度只能作为第二特征。先把能查表的查对再考虑语义。三是最后才看“生成环节”。模型把正确答案说错了通常是 Prompt 约束不够。我的经验是把需要模型遵守的规则从 20 条砍到 5 条每条都用“必须/禁止”明确表达效果好过冗长的规则清单。约束越多模型越容易犯糊涂精简反而更可靠。5.3 故障诊断准确率低时的改进路径如果故障诊断的准确率一直上不去我的经验是不要先折腾模型而是先补数据。制造业 RAG 的效果上限很大程度取决于你喂给它的数据质量而不是模型能力。具体补数据的顺序是先把故障码词典补全确保每个报警码都有对应的原因和步骤再把维修记录清洗入库这是现场经验的重要来源最后才考虑要不要加更多文档。多数情况下前两步做完准确率就能有看得见的提升。还有一个小细节故障码在不同的设备手册里可能含义不同如果你的知识库里有多个型号的设备一定要在结构化表里把“适用型号”字段填完整。否则系统会拿 A 型号的故障排查步骤去回答 B 型号的问题这在车间里是很危险的。5.4 一条通用的评估清单最后整理一个我在项目验收时用的评估清单你可以直接拿去用。测试类型输入示例通过标准参数类问题“主轴转速上限多少”给出参数号和范围带单位带出处故障码类问题“AL-401 怎么处理”包含原因列表、排查步骤、相关部件安全类问题“如何更换刀头”回答开头包含安全前置条件上下文不足时拒绝回答多设备问题“A 型和 B 型润滑周期一样吗”区分适用型号给出差异负例测试“手册里不存在的功能怎么用”明确说“未找到”不编造这套评估清单不用凑得很复杂但它能把 RAG 系统从“看起来能聊”推进到“能上产线用”。我在项目里每次迭代完都会拿这五类问题跑一遍速度很快但能拦住绝大多数回归问题。框架做下来我最大的感触是制造业 RAG 的难点从来不在“大模型”这一环而在文档解析、结构化抽取、精确检索这些看起来不起眼的基础环节。我跟几个同行交流时发现很多团队一开始都把精力花在调 Prompt、换大模型上结果效果上不去回头才发现是解析阶段就把表格弄丢了。MaRAG 这个框架本质上是把我在这些基础环节上踩过的坑和总结出的做法固化成了代码。最后再分享一个小技巧别把“故障诊断”做成一个孤立的问答功能尽量跟企业现有的报修流程结合。比如让系统在给出诊断建议的同时自动带上“建议检查的部件编号”和“可能需要更换的备件编码”一线人员可以直接拿着这个信息去领料。这样一来RAG 就从一个“会说话的知识库”变成了真正能帮车间节省时间的工具。这个改动不复杂但价值非常大我建议所有做同类项目的朋友都试一试。
阅读完成 · 觉得有帮助?