pgvector 语义检索 RAG 实战:让 AI 拥有永不遗忘的故障记忆

> 工厂最宝贵的知识不在系统里——在老师傅的脑子里。EAMX 的故障知识库用两条自动路径将维修经验沉淀为可语义检索的向量知识:工单关闭时自动提取知识对 → embedding 写入 pgvector;故障提交时异步相似检索 → 附注历史方案。本文拆解完整的 RAG 管线实现。

1. 架构:知识闭环

``<br>故障报修<br> ↓<br>异步相似检索(事前)→ 维修参考附注:"3号注塑机去年10月同样故障,张工换了接触器修好的"<br> ↓<br>工程师维修(参考历史经验)<br> ↓<br>工单关闭<br> ↓<br>LLM 提取知识对(事后)→ { faultPattern, rootCause, solution, keyParts }<br> ↓<br>embedText() → pgvector write<br> ↓<br>下次类似故障 → 检索命中<br>``

每一次维修都在让下一次维修更简单。

2. 向量生成

EAMX 使用 OpenAI text-embedding-3-small (1536 维):

``typescript<br>// rag.ts — embedText()<br>export async function embedText(text: string): Promise<number[] | null> {<br> if (!text || text.trim().length < 3) return null;<br> const resp = await openai.embeddings.create({<br> model: "text-embedding-3-small",<br> input: text.slice(0, 8000), // 模型上限保护<br> dimensions: 1536, // 显式指定维数<br> });<br> return resp.data[0]?.embedding ?? null;<br>}<br>``

为什么选 1536 维而非更大的 3072? 1536 维在精准度与存储/查询性能之间达到了工程上的甜点。3072 维提升有限但存储与查询开销翻倍。

3. pgvector 存储与检索
3.1 存储

``typescript<br>// rag.ts — saveEmbedding()<br>export async function saveEmbedding(opts: SaveEmbeddingOpts): Promise<void> {<br> // 幂等:同一 source_id 不重复写入<br> const exists = await pool.query(<br> SELECT id FROM knowledge_embeddings WHERE source_id = $1 LIMIT 1`,<br> [opts.sourceId],<br> );<br> if ((exists.rowCount ?? 0) > 0) return;

const vector = await embedText(opts.content);<br> if (!vector) return;

await pool.query(<br> INSERT INTO knowledge_embeddings<br> (tenant_id, source_type, source_id, content, embedding)<br> VALUES ($1, $2, $3, $4, $5::vector),<br> [opts.tenantId, opts.sourceType, opts.sourceId,<br> opts.content.slice(0, 2000), [${vector.join(",")}]],<br> );<br>}<br>```

3.2 语义检索

``typescript<br>// rag.ts — searchSimilarFaultSolutions()<br>const rows = await pool.query(<br> SELECT<br> ak.id AS knowledge_id,<br> 1 - (ke.embedding <=> $1::vector) AS similarity,<br> ak.equipment_name, ak.fault_symptom, ak.root_cause, ak.solution<br> FROM knowledge_embeddings ke<br> JOIN agent_knowledge ak ON ak.id = ke.source_id<br> WHERE ke.tenant_id = $2<br> AND ke.source_type IN ('fault_solution', 'external_knowledge')<br> AND 1 - (ke.embedding <=> $1::vector) >= $3 -- 阈值过滤<br> ORDER BY ke.embedding <=> $1::vector -- 按距离排序<br> LIMIT $4,<br> [pgVecStr, tenantId, threshold, limit],<br>);<br>``

关键点:

3.3 异步调度

``typescript<br>// fire-and-forget,不阻塞主业务流程<br>export function scheduleEmbedding(opts: SaveEmbeddingOpts): void {<br> setImmediate(() => {<br> saveEmbedding(opts).catch(err =><br> aiLog.warn([RAG] scheduleEmbedding error: ${err.message}));<br> });<br>}<br>``

4. 知识生成两条路径
路径一:外部知识查询触发

```typescript<br>// external-knowledge.agent.ts — queryKnowledge()<br>const { text } = await generateText({<br> system: "你是一位工业设备领域的高级专家...",<br> prompt: context, // 用户问题 + 设备上下文<br> maxOutputTokens: 1500,<br>});

// 异步写入 agent_knowledge + embedding<br>if (saveToKnowledge) {<br> await pool.query(INSERT INTO agent_knowledge (...) VALUES (...));<br> scheduleEmbedding({ tenantId, sourceType: "external_knowledge",<br> sourceId: knowledgeId, content: ${context} ${text} });<br>}<br>```

路径二:工单关闭自动提取

当维修工单关闭时,LLM 从维修过程中提取结构化知识对:

```<br>工单内容:<br> 故障:料筒温度偏高,PID调节无效<br> 维修:检查传感器正常 → 接触器触点烧蚀(根因)→ 更换CJX2-2510 → 校准PID

→ LLM 提取:<br>{<br> "faultPattern": "料筒温度偏高,PID调节无效",<br> "rootCause": "加热器接触器触点烧蚀",<br> "solution": "更换接触器(CJX2-2510),校准PID参数",<br> "keyParts": ["CJX2-2510接触器"],<br> "repairDuration": "45分钟"<br>}<br>→ embedText(faultPattern + rootCause + solution) → pgvector write<br>```

5. 语义检索 vs 关键词检索

传统搜索靠关键词——搜"温度偏高"找不到"温控异常"。pgvector 语义检索:

```<br>用户问:"料筒温度老是偏高,自动调不过来怎么办?"

→ 向量化查询 → 余弦相似度搜索<br>→ 命中:<br> 0.93 "料筒温度偏高,PID调节无效 — 接触器触点烧蚀"<br> 0.87 "加热区温度异常偏高 — 加热器功率控制器故障"<br> 0.72 "温控系统不稳定 — 传感器信号受干扰"<br>```

用户不需要匹配精确关键词。 语义级别的匹配意味着"怎么说都行"。

6. 核心文件索引

| 文件 | 行数 | 职责 |<br>|---|---|---|<br>| agents/rag.ts | 184 | embedText + saveEmbedding + searchSimilarFaultSolutions |<br>| agents/external-knowledge.agent.ts | 477 | LLM 生成行业知识 + 写入 knowledge embedding |<br>| agents/fault.agent.ts | — | 工单关闭时触发知识提取 |<br>| knowledge_embeddings 表 | — | pgvector 向量存储 |<br>| agent_knowledge 表 | — | 知识对元数据(可追溯源工单) |

下一篇:DynamicForm 置信度着色——AI 填好的表单,用户怎么在 3 秒内判断信任度?

作者:白杨,十余年设备资产管理从业经验,EAMX 产品负责人。