# 简历 · 大模型应用开发工程师（制造业版）

> 由中医知识图谱项目迁移。同一套架构（采集 → LLM 抽取 → 图谱 → Agent → 服务 → 前端 → 微调），
> 换成设备故障诊断与工艺知识检索场景。带 `<>` 的请按实际情况替换。

---

## 基本信息

| | |
|---|---|
| 姓名 | `<姓名>` |
| 岗位 | 大模型应用开发工程师 / 工业 AI |
| 经验 | 4 年（其中大模型应用方向 2 年） |
| 电话 / 邮箱 | `<电话>` / `<邮箱>` |
| 学历 | `<学校>` `<专业>` `<本科/硕士>` |

---

## 技能栏

**大模型应用**
- LangGraph 有状态编排：多节点条件路由、带上限的重试环、多轮排障记忆、流式增量产出
- LangChain 链式调用与结构化输出，OpenAI 兼容端点（DeepSeek / vLLM 厂内部署）
- Prompt 工程：schema 注入、否定式约束、多级降级解析；维修方案的强制溯源约束

**知识图谱与检索**
- Neo4j：Cypher 读写、批量事务导入、唯一约束、`EXPLAIN` 静态校验、schema 元数据导出
- FAISS + bge-large-zh-v1.5 向量召回，按实体类型过滤
- 工业术语标准化：一线口语到标准故障码的映射（"机器嗡嗡响" → "主轴异常振动"）

**模型微调**：Alpaca 数据集构建、LoRA 微调、vLLM multi-LoRA 部署

**工程能力**：Python 3.10、FastAPI（异步 / 流式 / 线程池）、Streamlit、并发采集、
`asyncio.Queue` 跨线程反压、Git / Black；产线内网离线部署

---

## 项目经验

### 设备故障诊断与工艺知识图谱问答系统 `<公司/独立项目>`

**角色**：技术负责人，负责整体方案与全链路实现，与设备科 `<N>` 名工程师协作做知识校验

**背景**：产线设备的排障知识分散在设备手册、历史工单、老师傅的经验里。新人遇到报警只能
翻纸质手册或打电话问人，停机每分钟都是钱。通用大模型的问题是会编造不存在的故障码和
维修步骤 —— 按错误步骤操作可能造成设备二次损坏或人身伤害。目标是把手册和历史工单变成
可查询的知识图谱，让排障建议可回溯到具体手册章节或历史工单编号。

**技术栈**：Python 3.10 / LangGraph / LangChain / Neo4j / FAISS / sentence-transformers /
FastAPI / Streamlit / vLLM

**七阶段流水线：**

**1. 数据采集**（设备手册 + 历史维修工单 + 工艺规程 + 备件台账）
- 按**文档顺序**遍历文档结构而非按已知字段名查找 —— 不同厂商设备手册的章节命名和层级
  完全不统一（故障排除/异常处理/Troubleshooting 混用），按顺序走开新章节才能完整保留。
  漏掉"安全注意事项"章节直接对应作业风险
- 历史工单是半结构化的：现象描述是自由文本，处理措施常带方言和简写，
  这部分交给 LLM 抽取而非规则解析
- 断点续传做在文件系统层：目标文件存在即完成；写入走 `.part` 再原子替换。
  新设备入场或手册改版后重采，续传让增量更新只做缺失部分
- 并发采集 + Session 按线程隔离

**2. 故障知识抽取**（LLM 结构化输出）
- Pydantic 定义 schema 作为全链路契约：实体为**设备 / 部件 / 故障现象 / 故障原因 /
  处理措施 / 备件**；关系为**由...引起 / 表现为 / 处置方式 / 需更换备件 / 属于 / 前置检查**
- 属性挂在实体上：设备带型号、产线、投产日期；备件带图号、库位、更换周期、供应商；
  措施带工时、所需资质、停机需求
- **安全前置条件必须单独抽取**：断电挂牌、泄压、上锁等前置动作绝不能与处理步骤混在一起，
  它们的执行顺序不可颠倒。这是本项目定义的 P0 约束
- Prompt 显式要求"现象与原因无明确关联时返回空结果" —— 模型最危险的行为是为了填满格式
  而虚构因果链，把无关的故障原因关联到现象上，空结果是正确输出
- **参数数值逐字保留，禁止换算**：扭矩、压力、温度的数值和单位原样搬运，换算在下游显式处理
- 成本约束：耗时取决于**输出**规模，长手册章节显著更慢；失败不写文件因此留在待办列表，
  重跑即重试；空结果要写，否则重跑在重复付费

**3. 图谱构建**
- **先在内存聚合再写库**：常见现象（如"异响"）出现在数千份工单里，
  逐条 MERGE 等于把同样的工作重做数千遍
- **节点主键是 `(类型, 名称)` 而非名称**：制造业跨类型同名极其常见 ——
  "轴承过热"既是故障现象也是另一个故障的原因，"液压泵"既是部件也是备件。
  只按名称去重会把它们错误合并，让"现象"查询召回备件节点
- 型号是必须入主键的维度：同名部件在不同设备型号上的规格和更换方式完全不同，
  只按部件名去重会给出错误的备件图号
- 标签、关系类型、属性键先过白名单再拼接；值一律参数化
- 属性用 `MERGE ... SET n += $attrs`：手册改版或备件替代后属性变化，写进 MERGE 模式
  会匹配失败并创建重复节点，`ON CREATE SET` 又永远不会回填已有节点
- **工单频次入图**：关系上带历史出现次数，排障时按频次排序候选原因 ——
  这是知识图谱比纯手册检索更有价值的地方，手册不会告诉你哪个原因最常见

**4. 检索层**
- Neo4j schema 元数据导出后注入 Cypher 生成 prompt；关系描述人工补齐
  （含适用型号、频次说明），由设备工程师复核
- FAISS 索引覆盖全部实体类型，**索引本身不带类型**，召回后必须按类型过滤 ——
  否则"漏油"可能召回一个备件名并落进"现象"槽位，生成出错误的 Cypher。
  超额取 `top_k * N` 再过滤
- 分级健康检查守住索引与图谱一致性：自检索（已知实体以距离≈0 返回 top-1）证明
  向量与映射未错位；与 Neo4j 对账防止工单增量导入后索引陈旧

**5. LangGraph Agent**（9 节点、2 条件边、1 个环、3 个出口）

```
START → 语义转写 → 排障意图识别
          ├─ 非排障 ─→ 直接回答 ──────────────────────→ END
          └─ 排障  ─→ 实体抽取 → 术语匹配 → cypher生成 ←──┐
                          → cypher检查                    │
                               ├─ 全部合法 ─→ 执行 → 处置方案 → END
                               ├─ 不合法且未超 3 次 ────────┘
                               └─ 额度用尽 ─→ 直接回答 → END
```

- **语义转写排在最前**：排障天然多轮 —— 先问"3 号线冲床报 E05"，再问"换了还是不行"。
  后一句单看没有任何信息，意图识别会判成无关。转写节点结合历史补全成完整问题，
  下游才有东西可用。全图只有转写节点读原始输入，其余节点读转写结果
- **重试环的刹车靠状态计数**：路由函数只能读 state 不能记账，重试次数由生成节点自增，
  上限 3 次。重试时回喂上一轮不合法的语句，否则模型输入不变会原样再生成
- **生成的 Cypher 直连生产库，两个独立位置设闸**：① 关键词词边界扫描 + 必须有 RETURN
  且以 MATCH/WITH 开头；② `EXPLAIN` 逐条静态校验。生产环境的图谱库绝不能被
  生成的语句写坏
- **绝不把用户原话放进 WHERE**：一线说"机器嗡嗡响"，图里存的是"主轴异常振动"。
  术语匹配节点弥合这个差距 —— 这在制造业尤其重要，一线口语和手册术语几乎没有交集
- **答案生成节点的硬约束**：处置步骤必须携带来源（手册章节号 / 工单编号），
  来源只能来自图谱查询结果；安全前置条件必须置顶输出；检索不到时明确告知，
  绝不由模型编造维修步骤
- JSON 解析多级降级；Cypher 逐条执行而非批量事务，出错补空列表保持下标对齐

**6. 服务化**
- FastAPI 三接口：健康检查、同步问答、流式问答
- 图是懒加载的模块级单例，`lifespan` 启动预热（FAISS 索引 + embedding 模型约 50 秒）；
  预热失败只记日志不阻止启动 —— 产线工具不能因为预热失败就整体不可用
- `graph.invoke` 同步阻塞，走 `run_in_threadpool`，否则事件循环被占死、服务退化成单并发。
  多个班组同时排障是常态
- 流式接口用生产者-消费者：节点在工作线程产出，有界 `asyncio.Queue`（32，形成反压）
  跨回事件循环。停机场景下等待成本极高，流式让"正在检索历史工单"的进度可见
- **产线内网离线部署**：vLLM 自托管模型 + 本地 embedding + 厂内 Neo4j，不依赖外网

**7. 前端与微调**
- Streamlit 多页：常规问答 + 流式页。流式页展示检索过程（命中的设备型号、候选原因及频次、
  引用的工单号），设备工程师需要看到判断依据。移动端适配以便车间现场使用
- 抽取结果顺带产出 Alpaca 数据集用于微调；两条写入路径 —— 抽取时追加 JSONL
  （并发追加整行不会破坏性交错），另有不调 LLM 的幂等重建脚本覆盖续传跳过的历史条目
- LoRA 微调后 vLLM 厂内部署，multi-LoRA 单服务挂多个产线/设备类型适配器按需切换

**成果**
- 覆盖 `<N>` 类设备、`<M>` 份手册、`<K>` 万条历史工单，schema 6 类实体 6 类关系
- 候选故障原因按历史频次排序，把老师傅的经验沉淀成可查询的数据
- **零编造维修步骤**：所有处置方案带手册章节或工单编号，检索不到时明确告知
- 安全前置条件强制置顶，不与操作步骤混排
- 接口层 27 条离线用例（替换假图，不触达 LLM/Neo4j/FAISS，2 秒内跑完）+ 15 条 live；
  前端 49 条离线 + 11 条 live
- 全链路产线内网离线运行

---

## 行业适配要点（面试可展开）

1. **型号入主键**：同名部件在不同型号上规格不同，只按名称去重会给出错误备件图号
2. **安全前置条件独立抽取**：断电挂牌、泄压不能与处理步骤混排，顺序不可颠倒
3. **工单频次入图**：候选原因按历史频次排序，这是图谱相比手册检索的增量价值
4. **口语到故障码的映射**："嗡嗡响" → "主轴异常振动"，一线用语和手册术语几乎无交集
5. **跨类型同名**：轴承过热既是现象也是原因，主键必须是 `(类型, 名称)`
6. **内网离线部署**：工业数据不出厂，模型与向量库全部本地自托管
7. 定位为排障辅助工具，高风险操作须持证人员按规程执行
