写在前面
制造现场最难解决的问题,通常不是"有没有一个大模型",而是异常发生以后,信息能不能被准确记录,工程师能不能快速找到依据,措施能不能被验证,最终责任和结论能不能追溯。
例如 A 线出现电机端盖扭矩异常,质量人员需要同时关注产线、设备、产品批次、影响数量、检验标准、历史异常、临时遏制措施、根因、纠正措施和验证结果。如果这些信息分散在表格、群聊和不同系统里,工程师只能依靠经验反复查找,管理者也很难判断哪些异常最值得优先处理。
我做的这个项目,就是围绕制造企业质量异常处理设计的一套智能运营协同平台。它以异常工单为核心对象,把管理员端的质量运营、工程师端的现场闭环、知识库与 RAG、Agent 任务编排、人工审批和审计记录连接起来。
平台中的 AI 负责检索、归纳、统计、候选组织和报告草稿生成,但不替代质量责任人做最终决定。关闭工单、放行、报废、责任认定和设备参数变更等高风险动作,必须经过业务规则和人工确认。
一、项目定位:AI 辅助质量工程,而不是自动控制生产
这个项目的目标可以概括为:
text
现场异常
-> 创建质量工单
-> 绑定产线、设备、产品和批次上下文
-> 检索授权知识与相似历史
-> 生成处置候选和根因分析线索
-> 工程师确认措施与验证计划
-> 8D/CAPA 闭环
-> 人工确认关闭
-> 审计与经验沉淀
平台主要面向两类用户。
管理员端解决的是制造质量管理问题:查看异常分布、严重等级、SLA 风险、设备和供应商风险,进行工单分派和质量任务编排。
工程师端解决的是质量工程闭环问题:接收工单、完成隔离和处置、查看与当前工单相关的证据、补充现场根因、制定纠正措施和验证计划,并通过 8D 推进结案。
这种划分很重要。设备、产线和批次直接作为工单分析上下文,质量知识库聚焦设备手册、检验标准、工艺文件和历史案例。所有能力最终都要回到工单、措施、验证和审计记录上。
二、整体技术架构
项目采用前后端分离的结构:前端使用 Vue 3、TypeScript 和 Vite,后端使用 FastAPI,业务逻辑集中在领域服务层,AI 能力通过 Provider、RAG 服务和 Agent 图进行编排。
#mermaid-svg-Iz5h2I77pk8GxKF5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Iz5h2I77pk8GxKF5 .error-icon{fill:#552222;}#mermaid-svg-Iz5h2I77pk8GxKF5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Iz5h2I77pk8GxKF5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .marker.cross{stroke:#333333;}#mermaid-svg-Iz5h2I77pk8GxKF5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Iz5h2I77pk8GxKF5 p{margin:0;}#mermaid-svg-Iz5h2I77pk8GxKF5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .cluster-label text{fill:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .cluster-label span{color:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .cluster-label span p{background-color:transparent;}#mermaid-svg-Iz5h2I77pk8GxKF5 .label text,#mermaid-svg-Iz5h2I77pk8GxKF5 span{fill:#333;color:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .node rect,#mermaid-svg-Iz5h2I77pk8GxKF5 .node circle,#mermaid-svg-Iz5h2I77pk8GxKF5 .node ellipse,#mermaid-svg-Iz5h2I77pk8GxKF5 .node polygon,#mermaid-svg-Iz5h2I77pk8GxKF5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .rough-node .label text,#mermaid-svg-Iz5h2I77pk8GxKF5 .node .label text,#mermaid-svg-Iz5h2I77pk8GxKF5 .image-shape .label,#mermaid-svg-Iz5h2I77pk8GxKF5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Iz5h2I77pk8GxKF5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .rough-node .label,#mermaid-svg-Iz5h2I77pk8GxKF5 .node .label,#mermaid-svg-Iz5h2I77pk8GxKF5 .image-shape .label,#mermaid-svg-Iz5h2I77pk8GxKF5 .icon-shape .label{text-align:center;}#mermaid-svg-Iz5h2I77pk8GxKF5 .node.clickable{cursor:pointer;}#mermaid-svg-Iz5h2I77pk8GxKF5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .arrowheadPath{fill:#333333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Iz5h2I77pk8GxKF5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Iz5h2I77pk8GxKF5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Iz5h2I77pk8GxKF5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Iz5h2I77pk8GxKF5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .cluster text{fill:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 .cluster span{color:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Iz5h2I77pk8GxKF5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Iz5h2I77pk8GxKF5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Iz5h2I77pk8GxKF5 .icon-shape,#mermaid-svg-Iz5h2I77pk8GxKF5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Iz5h2I77pk8GxKF5 .icon-shape p,#mermaid-svg-Iz5h2I77pk8GxKF5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Iz5h2I77pk8GxKF5 .icon-shape .label rect,#mermaid-svg-Iz5h2I77pk8GxKF5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Iz5h2I77pk8GxKF5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Iz5h2I77pk8GxKF5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Iz5h2I77pk8GxKF5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Vue 3 + TypeScript 管理台
FastAPI API / SSE
JWT / RBAC / 租户隔离
领域服务层
工单与质量闭环
知识库与文档服务
RAG 检索与引用生成
Agent 服务
LangGraph 五节点工作流
白名单工具 / 只读 subAgents
审计、用量与模型治理
Chroma / Milvus / JSON 回退
SQLite / PostgreSQL 检查点
MemoryStore + Repository Records
SQLite / PostgreSQL
代码职责大致如下:
| 层级 | 主要职责 |
|---|---|
| 前端 | 角色化工作台、工单处理、知识库、RAG、Agent 任务和运维展示 |
| API 层 | 登录、权限校验、请求参数、文件上传、SSE 和业务路由 |
| 领域服务 | 工单状态机、处置、根因、8D、知识库、任务、审计和持久化 |
| AI 能力层 | LLM、Embedding、Reranker、RAG Chain、Agent Graph 和 subAgents |
| 基础设施层 | Repository、向量库、对象存储、队列、检查点和降级适配器 |
一个核心设计原则是:前端不能直接改关键状态,模型也不能直接操作 PLC、MES、ERP 或任意业务数据库。AI 返回的是建议和草稿,真正的业务写入必须经过服务层的权限和状态机校验。
三、以 A 线扭矩异常看完整业务链路
假设现场发现 A 线电机端盖扭矩偏低,质量工程师在"我的异常工单"中创建工单,录入异常描述、设备、产线、批次、影响数量和严重等级,并上传现场记录。
管理员可以在异常工单中心看到这条工单的 SLA、影响范围和当前处理人,根据人员在岗状态和工作负载进行分派。工单随后进入工程师工作台,工程师先完成隔离和现场确认。
在工单的智能处置入口,系统把当前异常描述、设备、产线和批次作为检索上下文,查找已发布的质量手册、工艺文件、设备维护资料和相似历史案例。返回结果不会只是一段模型文本,而是包含文档、版本、页码、片段和相似度的证据。
工程师可以从候选措施中选择适合当前现场的方案,也可以在固定候选之外补充新的现场措施。系统要求进一步填写验证计划,例如复测扭矩、确认夹具基准、完成首件检查或观察连续批次结果。
根因分析同样不是一个写死的鱼骨图选项集合。设备、物料、方法、测量等类别用于组织候选和验证顺序,真正的根因可以来自当前检索证据、相似历史,也可以由工程师直接新增。确认根因后,平台同步保存临时措施、纠正措施、验证计划、确认人和确认时间,并追加工单事件与审计记录。
最后进入 8D/CAPA。D1 到 D8 分别对应团队、问题描述、遏制、根因、纠正措施、验证、预防和关闭。没有验证结果,工单不能被简单地当成已解决。这样,AI 的价值落在工程过程里,而不是停留在页面上生成一句"建议检查设备"。
四、RAG:先找可靠证据,再组织可执行回答
这个项目的 RAG 不是开放域聊天,而是面向制造质量场景的受控检索。它要回答的是:当前工单对应的标准怎么要求?相似问题过去怎么处理?工程师下一步应该验证什么?
4.1 第一步:受控召回与排序
RAG 请求进入后,服务层首先校验用户是否拥有 RAG_QUERY 权限,并注入当前租户、部门和知识库范围。文档必须处于已发布状态,并且不能过期或超出用户可见范围。
之后系统会对问题做制造术语改写,例如把"点检"扩展为巡检、预防性维护、校准和设备检查等相关表达,再调用 Embedding Provider 生成向量。知识库服务同时计算向量相似度和关键词近似分数,形成混合召回结果,再使用 Reranker 筛选少量高相关证据。
可以把这一步理解成:
text
用户问题
-> 权限与租户过滤
-> 查询改写
-> 向量召回
-> 关键词混合评分
-> Rerank
-> 文档、版本、页码、片段和相似度
4.2 第二步:基于引用生成答案
召回结果会进入 LangChainRagChain。链路把证据编号、文档名称、页码和文本片段组织成上下文,并通过 Prompt 约束模型:只能基于授权证据回答,结论要引用证据,处置建议要带复核和放行条件,证据不足时明确说明缺口。
如果没有命中有效资料,系统返回"当前授权知识库未找到依据,无法确认该问题",不会让模型自由编造生产结论。如果模型返回内容没有有效证据编号,服务层还会使用引用片段生成可追溯的降级回答。
这套设计解决了制造质量场景里两个很现实的问题:第一,模型不能因为"听起来合理"就给出未经授权的操作建议;第二,工程师可以回到原始文档核对答案,而不是只能相信模型。
五、Agent:用 LangGraph 组织跨工单任务
RAG 解决的是"根据证据回答当前问题",Agent 解决的是"把多个查询、统计、检索、专家分析和报告生成步骤组织起来"。例如管理员可以创建一个任务:
text
统计近 30 天 A 产线的质量工单,找出高频异常,结合质量资料生成周报草稿。
Agent 不会直接把这句话交给模型让模型自由调用工具,而是经过结构化计划、白名单校验和状态图执行。
当前 LangGraph 工作流是五个节点:
#mermaid-svg-kWsCXNW8Bow0O7lY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kWsCXNW8Bow0O7lY .error-icon{fill:#552222;}#mermaid-svg-kWsCXNW8Bow0O7lY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kWsCXNW8Bow0O7lY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kWsCXNW8Bow0O7lY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kWsCXNW8Bow0O7lY .marker.cross{stroke:#333333;}#mermaid-svg-kWsCXNW8Bow0O7lY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kWsCXNW8Bow0O7lY p{margin:0;}#mermaid-svg-kWsCXNW8Bow0O7lY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY .cluster-label text{fill:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY .cluster-label span{color:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY .cluster-label span p{background-color:transparent;}#mermaid-svg-kWsCXNW8Bow0O7lY .label text,#mermaid-svg-kWsCXNW8Bow0O7lY span{fill:#333;color:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY .node rect,#mermaid-svg-kWsCXNW8Bow0O7lY .node circle,#mermaid-svg-kWsCXNW8Bow0O7lY .node ellipse,#mermaid-svg-kWsCXNW8Bow0O7lY .node polygon,#mermaid-svg-kWsCXNW8Bow0O7lY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kWsCXNW8Bow0O7lY .rough-node .label text,#mermaid-svg-kWsCXNW8Bow0O7lY .node .label text,#mermaid-svg-kWsCXNW8Bow0O7lY .image-shape .label,#mermaid-svg-kWsCXNW8Bow0O7lY .icon-shape .label{text-anchor:middle;}#mermaid-svg-kWsCXNW8Bow0O7lY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kWsCXNW8Bow0O7lY .rough-node .label,#mermaid-svg-kWsCXNW8Bow0O7lY .node .label,#mermaid-svg-kWsCXNW8Bow0O7lY .image-shape .label,#mermaid-svg-kWsCXNW8Bow0O7lY .icon-shape .label{text-align:center;}#mermaid-svg-kWsCXNW8Bow0O7lY .node.clickable{cursor:pointer;}#mermaid-svg-kWsCXNW8Bow0O7lY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kWsCXNW8Bow0O7lY .arrowheadPath{fill:#333333;}#mermaid-svg-kWsCXNW8Bow0O7lY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kWsCXNW8Bow0O7lY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kWsCXNW8Bow0O7lY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kWsCXNW8Bow0O7lY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kWsCXNW8Bow0O7lY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kWsCXNW8Bow0O7lY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kWsCXNW8Bow0O7lY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kWsCXNW8Bow0O7lY .cluster text{fill:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY .cluster span{color:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kWsCXNW8Bow0O7lY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kWsCXNW8Bow0O7lY rect.text{fill:none;stroke-width:0;}#mermaid-svg-kWsCXNW8Bow0O7lY .icon-shape,#mermaid-svg-kWsCXNW8Bow0O7lY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kWsCXNW8Bow0O7lY .icon-shape p,#mermaid-svg-kWsCXNW8Bow0O7lY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kWsCXNW8Bow0O7lY .icon-shape .label rect,#mermaid-svg-kWsCXNW8Bow0O7lY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kWsCXNW8Bow0O7lY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kWsCXNW8Bow0O7lY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kWsCXNW8Bow0O7lY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 暂停
通过
是
否
开始
prepare 初始化或恢复
plan_task 生成并校验计划
approval_gate 风险门禁
finalize 收敛状态
execute_step 执行一步
是否还有步骤
结束
5.1 prepare:初始化执行上下文
这个节点负责初始化或恢复 AgentState,包括任务状态、当前步骤、步骤索引和已执行数量。任务使用 thread_id 作为检查点线程,失败或暂停后可以读取之前保存的状态。
5.2 plan_task:生成并校验计划
计划可以来自确定性规则,也可以由结构化模型输出生成。模型只能从服务端定义的工具白名单中选择,例如:
query_work_orderscalculate_statisticssearch_knowledgeread_attachmentretrieve_long_term_memorydelegate_*_specialistgenerate_report
服务层还会对计划做工具名校验、去重、最大步骤限制,并确保最终能够生成报告。模型不能规划 SQL、PLC 操作或任意业务写入。
5.3 approval_gate:把 HITL 放进图内
只要 Prompt 涉及关闭、写入、放行、报废、责任认定或参数变更,图内审批门禁就会把任务置为 paused,并进入 finalize 保存状态。前端展示待审批任务,审批人可以通过或驳回。
审批通过后,服务层保留原来的 thread_id 和审批结果,重新运行工作流。图从已有检查点继续,审批驳回则任务变成失败并记录审批意见。
需要注意,HITL 不等于给 AI 开放写权限。审批只是允许任务继续,工单最终关闭、8D 阶段通过和设备参数变更仍然要通过对应业务接口和状态规则。
5.4 execute_step:一次只执行一个步骤
每次执行只取计划中的一个步骤,调用服务层提供的回调。服务层负责真正的工具执行、租户过滤、ToolCall 记录、幂等键、证据追加和业务检查点。
当前监督 Agent 下有四个只读专家:质量、设备、供应商和报告。它们可以分别检索标准、关联设备履历、汇总供应商整改或整理报告,但不会直接修改工单、供应商、设备和生产设备。
5.5 finalize:统一收敛结果
工作流结束后,finalize 会统一处理 succeeded、paused、failed 和 cancelled 状态。服务层再根据结果保存报告草稿、模型用量、审计、业务检查点,并在有有效报告时写入长期记忆。
六、短期记忆、长期记忆与可恢复执行
短期记忆服务当前任务,主要由 AgentState、任务事件、ToolCall 和 LangGraph checkpoint 组成。它保存:
- 用户问题和消息。
- 已校验计划与当前步骤。
- 工具调用和检索证据。
- 报告草稿。
- 审批状态和错误信息。
它的价值不是"记住用户喜欢什么",而是让一个任务在暂停、失败、重试或 worker 重启后能够继续执行,并且前端可以展示完整时间线。
长期记忆服务跨任务复用。已完成的 Agent 报告或人工沉淀的经验会保存租户、用户、Agent 类型、来源、置信度、标签和过期时间,并写入独立的长期记忆向量集合。检索时再次做租户、范围、Agent 类型、状态和有效期过滤。
这两类记忆不能混在一起:当前任务的临时草稿不应该直接成为正式质量知识,向量索引也不应该取代工单和审计主数据。
七、数据存储:业务事实、检索索引和工作流状态分离
项目把数据大致分为三层。
7.1 业务事实
工单、分派、根因、8D、审计、用户、工具调用和长期记忆等对象由领域服务维护,并通过 MemoryStore 和 Repository Records 进行统一持久化。部署时可以使用 SQLite 或 PostgreSQL,Docker Compose 默认以 PostgreSQL 和 JSONB Repository Records 为主要持久化方式。
7.2 检索数据
知识文档原文和解析后的切片分开管理。切片会生成 Embedding,进入 Chroma、Milvus 或 JSON 回退向量存储;长期记忆使用独立集合。向量库可以重建,不应该影响工单主记录和审计事实。
7.3 工作流状态
LangGraph 的检查点由 MemorySaver 或数据库 Checkpointer 保存。数据库模式下会保存线程、版本、父检查点和 pending writes,支持按 thread_id 读取最近状态。业务侧的 AgentTask.checkpoints 负责展示和审计摘要,LangGraph 检查点负责图引擎恢复,两者职责不同。
八、可靠性与安全设计
这个项目里,AI 相关功能最重要的技术点不是"调用模型",而是控制模型的边界。
第一是多租户隔离。权限、部门、知识库发布状态和有效期在服务层过滤,不能只依赖前端传参。
第二是只读 Agent。工具白名单和业务服务共同限制模型能力,Agent 不拥有任意 SQL、PLC、MES、ERP 写权限。
第三是工具幂等。每个 ToolCall 根据任务、工具和输入生成 SHA-256 幂等键,重试时不会重复插入相同调用。
第四是模型适配器。LLM、Embedding、Reranker 和 OCR 都通过 Provider 抽象接入,真实模型不可用时可以使用 MockProvider 或本地回退路径,便于无 GPU、无外网环境演示。
第五是可观测性。任务状态、步骤、ToolCall、证据、报告、审批、用量和审计都可以在前端或运维接口查看,模型输出不是一个无法解释的黑盒结果。
九、这个项目真正解决了什么问题
从业务角度看,平台把"异常发现、工程处置、根因确认、措施验证和结案审计"串成了一条链。
从 AI 角度看,RAG 提供有权限边界的证据,Agent 负责跨对象任务拆解,subAgents 提供只读领域分析,HITL 负责把高风险结论交回人确认。
从工程角度看,系统把业务事实、向量索引和工作流状态分开存储,并提供模型、向量库、对象存储和队列的适配器与回退实现。
因此,这个平台的核心不是在页面上展示几个 AI 按钮,而是让 AI 进入质量工程流程以后,仍然能够被追溯、被暂停、被恢复、被验证和被审计。
十、当前实现边界与后续演进
当前项目已经实现的是可运行的制造质量 MVP:工单闭环、知识库、RAG、动态处置与 RCA 候选、8D/CAPA、Agent 五节点工作流、HITL、长期记忆、检查点和角色化前端。
项目内置的是带有行业语义的种子和测试数据,不应描述成合作工厂的真实生产数据。MES、ERP、PLC 和真实设备接口需要在完成现场适配与联调后再接入。
后续可以沿着几个方向演进:
- 使用 LangGraph interrupt 进一步增强人工审批和恢复租约。
- 接入真实制造数据后,补充工单、设备、批次和工艺指标的在线同步。
- 建立更系统的 RAG 评测集,监控引用准确率、拒答准确率和首 Token 延迟。
- 将当前的关键词近似检索逐步替换或补充为 BM25、Elasticsearch 等生产级全文检索。
- 在验证数据充分后,再评估更细粒度的工具参数权限和模型化工具调用。
结语
制造企业的 AI 平台最终要接受现场流程的检验:建议能不能对应当前设备和批次,根因能不能被验证,措施能不能留下责任记录,工单能不能按规则关闭。
这个项目的设计取舍是让 AI 做它擅长的事情:检索、归纳、统计、组织候选和生成草稿;让工程师继续做必须由人负责的事情:确认现场事实、选择措施、验证根因、批准结论和关闭工单。
只有把模型能力嵌入真实业务闭环,RAG、Agent、LangGraph 和 HITL 才不只是技术名词,而能真正成为制造质量系统的一部分。