# 简历 · 大模型应用开发工程师（土木/建筑行业版）

> 由中医知识图谱项目迁移。同一套架构（采集 → 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>` 名注册结构/建造师协作做条文校核

**背景**：施工现场遇到技术问题要查规范，而规范体系庞杂（国标/行标/地标/图集），条文之间
互相引用、还有新旧版本替代关系。现场人员翻纸质规范效率极低，而通用大模型回答规范问题时
会**编造条号和限值** —— 给出一个"《混凝土结构设计规范》第某条规定保护层厚度为 X mm"，
条号和数值都似真非真。规范限值错误直接对应结构安全与验收不合格。目标是把规范条文变成
可查询的知识图谱，让每一条引用和每一个限值都能回溯到真实条文。

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

**七阶段流水线：**

**1. 数据采集**（国标/行标/地标规范全文 + 标准图集 + 施工工艺标准 + 质量验收标准）
- 按**文档顺序**遍历文档结构而非按已知字段名查找 —— 规范的层级（篇/章/节/条/款/项）
  和条文说明的排布因标准而异，按顺序走开新章节才能保住条文的从属关系。
  这在规范场景尤为关键：**条文脱离所属章节含义会变**，同一句限值在"一般规定"下
  和在"抗震设计"下的适用范围完全不同
- **强制性条文单独标记**：黑体字条文（强条）必须与一般条文区分，它们不可通过论证变通
- 断点续传做在文件系统层：目标文件存在即完成；写入走 `.part` 再原子替换。
  规范修订后重采，续传让增量更新只做缺失部分
- 并发采集 + Session 按线程隔离

**2. 条文结构化抽取**（LLM 结构化输出）
- Pydantic 定义 schema 作为全链路契约：实体为**规范标准 / 条文 / 构件 / 材料 /
  技术指标 / 施工工序**；关系为**规定 / 适用于 / 引用 / 替代 / 前置工序 / 检验要求**
- 属性挂在实体上：条文带条号、是否强制性、实施日期、废止日期；技术指标带限值、
  单位、适用条件（环境类别、抗震等级、结构形式）；工序带验收节点和隐蔽工程标记
- **限值必须连同适用条件一起抽取**：脱离条件的限值毫无意义且危险 ——
  保护层厚度随环境类别变化，同一个数值在不同环境下可能合规也可能违规。
  这是本项目定义的 P0 约束，限值与条件必须绑定为一个整体，不允许拆开存储
- **条文原文逐字保留，禁止改写**：任何摘要都会让引用失去技术依据意义
- **数值与单位逐字保留，禁止换算**：MPa/kN/mm 原样搬运，换算在下游显式处理
- Prompt 显式要求"条文之间无明确引用关系时返回空结果" —— 模型最危险的行为是虚构
  条文之间的引用，空结果是正确输出
- 成本约束：耗时取决于**输出**规模，长条文（如荷载规范）显著更慢；失败不写文件因此
  留在待办列表，重跑即重试；空结果要写，否则重跑在重复付费

**3. 图谱构建**
- **先在内存聚合再写库**：常见构件（如"梁""柱"）出现在数千条条文里，
  逐条 MERGE 等于把同样的工作重做数千遍
- **节点主键是 `(类型, 名称)` 而非名称**：土木领域跨类型同名极其常见 ——
  "混凝土"既是材料也是分部工程，"沉降"既是技术指标也是质量缺陷现象。
  只按名称去重会把它们错误合并
- **条号必须绑定所属标准编号才唯一**：`第 4.1.3 条` 在几十本规范里都存在，
  只按条号去重会把不同规范的同号条文错误合并，这是致命错误。
  主键实际是 `(标准编号, 版本年份, 条号)`
- 标签、关系类型、属性键先过白名单再拼接；值一律参数化
- 属性用 `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
```

- **语义转写排在最前**：技术咨询天然多轮 —— 先问"梁的保护层厚度要求"，再问"那二类环境呢"。
  后一句单看没有任何信息，意图识别会判成无关。转写节点结合历史补全成完整问题，
  下游才有东西可用。全图只有转写节点读原始输入，其余节点读转写结果。
  **同时负责补全适用条件**：现场提问常省略环境类别和抗震等级，这两个条件不补全，
  查出来的限值就是错的
- **重试环的刹车靠状态计数**：路由函数只能读 state 不能记账，重试次数由生成节点自增，
  上限 3 次。重试时回喂上一轮不合法的语句，否则模型输入不变会原样再生成
- **生成的 Cypher 直连生产库，两个独立位置设闸**：① 关键词词边界扫描 + 必须有 RETURN
  且以 MATCH/WITH 开头；② `EXPLAIN` 逐条静态校验
- **绝不把用户原话放进 WHERE**：现场说"钢筋绑得太稀"，图里存的是"箍筋间距超限"。
  术语匹配节点弥合这个差距
- **答案生成节点的四条硬约束**：
  ① 结论必须携带标准编号 + 版本年份 + 条号，且只能来自图谱查询结果，
     宁可回答"未检索到相关条文"也不编造条号；
  ② **限值必须连同适用条件一起输出**，不允许给出无条件的裸数值；
  ③ 命中强制性条文时明确标注"强条"；
  ④ 涉及已废止版本时提示现行有效版本
- JSON 解析多级降级；Cypher 逐条执行而非批量事务，出错补空列表保持下标对齐

**6. 服务化**
- FastAPI 三接口：健康检查、同步问答、流式问答
- 图是懒加载的模块级单例，`lifespan` 启动预热（FAISS 索引 + embedding 模型约 50 秒）；
  预热失败只记日志不阻止启动
- `graph.invoke` 同步阻塞，走 `run_in_threadpool`，否则事件循环被占死、服务退化成单并发
- 流式接口用生产者-消费者：节点在工作线程产出，有界 `asyncio.Queue`（32，形成反压）
  跨回事件循环。工地网络条件差，流式让首个反馈在 1 秒内到达，也更耐受连接不稳

**7. 前端与微调**
- Streamlit 多页：常规问答 + 流式页。流式页展示检索过程（识别的构件和条件、命中的规范、
  引用条号），技术人员必须看到引用依据才敢采信。移动端适配以便现场使用
- 抽取结果顺带产出 Alpaca 数据集用于微调；两条写入路径 —— 抽取时追加 JSONL
  （并发追加整行不会破坏性交错），另有不调 LLM 的幂等重建脚本覆盖续传跳过的历史条目
- LoRA 微调后 vLLM 部署，multi-LoRA 单服务挂多个专业适配器（结构 / 施工 / 验收）按需切换

**成果**
- 覆盖 `<N>` 本规范标准、`<M>` 万条条文，schema 6 类实体 6 类关系
- **零编造条号与限值**：所有引用带标准编号 + 版本 + 条号，检索不到时明确告知
- 限值强制连同适用条件输出，杜绝脱离条件的裸数值
- 强制性条文标注，版本替代关系可查，支持既有项目按开工时规范查询
- 接口层 27 条离线用例（替换假图，不触达 LLM/Neo4j/FAISS，2 秒内跑完）+ 15 条 live；
  前端 49 条离线 + 11 条 live

---

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

1. **限值与适用条件绑定**：脱离环境类别/抗震等级的裸数值毫无意义且危险，P0 约束
2. **条号主键**：`第 4.1.3 条` 在几十本规范里都有，主键必须是 `(标准编号, 版本, 条号)`
3. **强制性条文标记**：黑体强条不可论证变通，答案中必须标注
4. **版本替代链入图**：在建项目按开工时规范执行，不能一律给最新版
5. **条文原文逐字保留**：改写会让引用失去技术依据意义
6. **转写节点补全适用条件**：现场提问常省略环境类别，不补全查出的限值就是错的
7. **跨类型同名**：混凝土既是材料也是分部工程，主键必须是 `(类型, 名称)`
8. 定位为规范检索辅助工具，设计与验收结论须注册执业人员签认
