2026-08-04 17:15:02 +08:00
|
|
|
|
# iAOP-Core · LLM 网关(LLM Gateway)
|
|
|
|
|
|
|
2026-08-04 18:02:00 +08:00
|
|
|
|
对应 PRD 5.4「④ LLM 网关 + RAG」与 EPIC #6:
|
2026-08-04 17:15:02 +08:00
|
|
|
|
本地 70B(敏感/核心)+ 云端 API(脱敏/通用)**混合**,安全分级路由,
|
|
|
|
|
|
**敏感数据本地闭环,仅脱敏/公开内容可走云端 API**(数据不出厂)。
|
|
|
|
|
|
|
|
|
|
|
|
## 模块结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
core/llm-gateway/
|
2026-08-04 18:02:00 +08:00
|
|
|
|
├── __init__.py 包入口(导出各模块 API)
|
2026-08-04 17:15:02 +08:00
|
|
|
|
├── dlp.py DLP 敏感数据拦截引擎(Issue #48)
|
2026-08-04 18:02:00 +08:00
|
|
|
|
├── router.py 敏感度路由规则引擎(Issue #43 雏形)
|
2026-08-04 23:15:39 +08:00
|
|
|
|
├── prompts.py Prompt 版本管理(Issue #47)
|
|
|
|
|
|
├── hallucination.py 幻觉/事实性校验中间件(Issue #47)
|
|
|
|
|
|
├── evaluate_hallucination.py 幻觉/事实性评测报告脚本(Issue #47)
|
2026-08-04 18:02:00 +08:00
|
|
|
|
├── gateway.py 混合网关主编排(EPIC #6 主体交付)
|
2026-08-04 17:15:02 +08:00
|
|
|
|
├── config/
|
2026-08-04 18:02:00 +08:00
|
|
|
|
│ ├── dlp.template.yaml 模板 DLP 规则资产(ti-cl4 示例)
|
|
|
|
|
|
│ ├── router.template.yaml 模板敏感度路由规则资产
|
|
|
|
|
|
│ └── prompts.template.yaml 模板提示词版本库资产
|
2026-08-04 17:15:02 +08:00
|
|
|
|
└── tests/
|
|
|
|
|
|
├── _bootstrap.py 测试引导(目录含连字符,挂载包名 llm_gateway)
|
2026-08-04 18:02:00 +08:00
|
|
|
|
├── test_dlp.py DLP 引擎单元测试
|
|
|
|
|
|
├── test_router.py 路由引擎单元测试
|
|
|
|
|
|
├── test_prompts.py Prompt 版本库单元测试
|
|
|
|
|
|
├── test_hallucination.py 幻觉/事实性校验单元测试
|
|
|
|
|
|
└── test_gateway.py 网关主编排端到端单元测试
|
2026-08-04 17:15:02 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## DLP 敏感数据拦截(Issue #48)
|
|
|
|
|
|
|
|
|
|
|
|
出站防线:任何要发往**云端**的内容(用户 query / RAG 检索到的 context /
|
|
|
|
|
|
模型输出)先经 `DlpEngine.check_outbound()` 检查,**命中任一 block 规则
|
|
|
|
|
|
即整包拦截**(fail-closed),并落结构化审计日志(全量)。
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from llm_gateway.dlp import DlpEngine
|
|
|
|
|
|
|
|
|
|
|
|
engine = DlpEngine.from_template_config("config/dlp.template.yaml")
|
|
|
|
|
|
result = engine.check_outbound({
|
|
|
|
|
|
"query": user_query, # 用户提问
|
|
|
|
|
|
"context": rag_context, # RAG 命中文档片段
|
|
|
|
|
|
"output": llm_answer, # 模型生成结果
|
|
|
|
|
|
})
|
|
|
|
|
|
if result.blocked:
|
|
|
|
|
|
# 不发往云端:转本地处理 / 转人工确认 / 拒绝(PRD 5.4 异常时转人工)
|
|
|
|
|
|
engine.drain_audit() # 取走审计记录(对接外部审计管道)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 语义(目标 DLP 拦截率 100%)
|
|
|
|
|
|
|
|
|
|
|
|
- **命中即拦截**:`decision="block"`、`reason="hit"`;
|
|
|
|
|
|
- **未配置即拦截**:引擎无任何规则(含内置保底)且 `fail_closed=True` 时
|
|
|
|
|
|
`reason="no_rules"`——未配置 = 不安全,保守拒绝出站;
|
|
|
|
|
|
- **审计不落明文敏感内容**:命中明细只记录规则名 / 类别 / 所属 part /
|
|
|
|
|
|
位置与 `<category>` 脱敏占位。
|
|
|
|
|
|
|
|
|
|
|
|
### 规则来源
|
|
|
|
|
|
|
|
|
|
|
|
1. **内置保底**(`DLP_DEFAULT_RULES`,内核自带):通用 PII 与凭证
|
|
|
|
|
|
(身份证、手机号、邮箱、IPv4、云访问密钥 AK、密钥键值对)+ 示例工艺词;
|
|
|
|
|
|
2. **模板资产**(`config/dlp.template.yaml`):行业敏感资产(工艺参数 /
|
|
|
|
|
|
配方 / 关键设备 / 人员岗位),同名规则覆盖内置实现模板定制。
|
|
|
|
|
|
|
|
|
|
|
|
规则两种匹配方式:`keyword`(大小写不敏感子串)与 `regex`(正则)。
|
|
|
|
|
|
|
|
|
|
|
|
### 验收对照(PRD 5.4 / 父 Issue #6)
|
|
|
|
|
|
|
|
|
|
|
|
| 验收项 | 实现 |
|
|
|
|
|
|
|--------|------|
|
|
|
|
|
|
| DLP 拦截率 100% | fail-closed:命中即 block;未配置规则也 block |
|
|
|
|
|
|
| 敏感数据本地闭环 | 出站(云端通道)必经 check_outbound 检查 |
|
|
|
|
|
|
| 敏感词/DLP 规则为配置点 | `config/dlp.template.yaml`,换行业只改资产 |
|
|
|
|
|
|
| 审计日志全量(NFR 安全-数据) | 每次检查落一条结构化审计,可 drain 对接管道 |
|
|
|
|
|
|
|
|
|
|
|
|
## 运行测试
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd core/llm-gateway
|
|
|
|
|
|
python -m unittest discover -s tests -v
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 18:02:00 +08:00
|
|
|
|
## 混合网关主编排(EPIC #6 主体)
|
|
|
|
|
|
|
|
|
|
|
|
`LLMGateway.ask()` 串起完整闭环:**敏感度路由 → 本地/云端生成 → 引用溯源校验
|
|
|
|
|
|
→ DLP 出站防线**,覆盖 PRD 5.4 用户操作流程(提问 → 路由判断敏感级 →
|
|
|
|
|
|
本地/云端生成 → RAG 溯源校验 → 返回带引用的答案;异常转人工)。
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from llm_gateway import LLMGateway
|
|
|
|
|
|
from llm_gateway.dlp import DlpEngine
|
|
|
|
|
|
from llm_gateway.router import SensitivityRouter
|
|
|
|
|
|
from llm_gateway.prompts import PromptRegistry
|
|
|
|
|
|
|
|
|
|
|
|
gw = LLMGateway(
|
|
|
|
|
|
dlp=DlpEngine(),
|
|
|
|
|
|
router=SensitivityRouter.from_template_config("config/router.template.yaml"),
|
|
|
|
|
|
prompts=PromptRegistry.from_template_config("config/prompts.template.yaml"),
|
|
|
|
|
|
high_stakes_names=["alarm_explain"], # 高利害模板启用信度阈值
|
|
|
|
|
|
)
|
|
|
|
|
|
result = gw.ask("炉温偏高怎么处理", rag_context=["沸腾氯化炉异常处置SOP"])
|
|
|
|
|
|
print(result.route.target) # local / cloud / block
|
|
|
|
|
|
print(result.verdict.action) # pass / human_review / unsupported
|
|
|
|
|
|
if result.needs_human:
|
|
|
|
|
|
... # 转人工确认(PRD 5.4 异常时转人工)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- **敏感度路由**(router.py,Issue #43 雏形):模板配置驱动,DLP 拦截
|
|
|
|
|
|
fail-closed 强制 block,未知内容保守走本地(数据不出厂);
|
2026-08-04 23:15:39 +08:00
|
|
|
|
- **Prompt 版本管理**(prompts.py,Issue #47):semver 版本库、
|
2026-08-04 18:02:00 +08:00
|
|
|
|
运行时绑定(可复现)、一键回滚、变更审计;
|
2026-08-04 23:15:39 +08:00
|
|
|
|
- **幻觉/事实性校验**(hallucination.py,Issue #47):`[来源: X]`
|
|
|
|
|
|
引用溯源强制校验 + 高利害信度阈值 → 人工确认,并与 Prompt 版本库联动
|
|
|
|
|
|
(评测按 `name@version` 分解,Prompt 变更后可对比各版本事实一致性);
|
2026-08-04 18:02:00 +08:00
|
|
|
|
- **推理后端抽象**(gateway.py 内 `InferenceBackend`):业务代码只依赖
|
|
|
|
|
|
接口,本地 70B / 云端 API 具体接入由子任务 #44 / #45 实现。
|
|
|
|
|
|
|
2026-08-04 23:15:39 +08:00
|
|
|
|
## Prompt 版本管理 + 幻觉/事实性校验(Issue #47)
|
|
|
|
|
|
|
|
|
|
|
|
对应 PRD 5.4「Prompt 版本管理 + 幻觉/事实性校验」。
|
|
|
|
|
|
|
|
|
|
|
|
### Prompt 版本管理(prompts.py)
|
|
|
|
|
|
|
|
|
|
|
|
所有提示词模板纳入版本库(semver),变更须评审并记录(同版本号覆盖报错),
|
|
|
|
|
|
支持一键回滚;生产流程运行时按 `(name, version)` 绑定,可复现。
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from llm_gateway.prompts import PromptRegistry
|
|
|
|
|
|
|
|
|
|
|
|
reg = PromptRegistry.from_template_config("config/prompts.template.yaml")
|
|
|
|
|
|
pv = reg.get("qa", version="1.0.0") # 显式绑定旧版本:行为不受后续变更影响
|
|
|
|
|
|
rendered = pv.render(query="炉温偏高怎么处理")
|
|
|
|
|
|
reg.promote("qa", "1.0.1")
|
|
|
|
|
|
reg.rollback("qa") # 一键回滚
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 幻觉/事实性校验(hallucination.py)
|
|
|
|
|
|
|
|
|
|
|
|
RAG 答案强制引用溯源:输出中所有 `[来源: X]` 声明必须命中本次 RAG 检索的
|
|
|
|
|
|
文档片段,否则判 `unsupported`(幻觉嫌疑);高利害输出(处置建议 / 报警解释)
|
|
|
|
|
|
要求信度 ≥ 阈值,否则 `human_review` 转人工确认。
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from llm_gateway.hallucination import HallucinationGuard
|
|
|
|
|
|
|
|
|
|
|
|
guard = HallucinationGuard(default_threshold=0.8)
|
|
|
|
|
|
v = guard.check(
|
|
|
|
|
|
answer="建议降温。[来源: 沸腾氯化炉异常处置SOP]",
|
|
|
|
|
|
sources=["沸腾氯化炉异常处置SOP"],
|
|
|
|
|
|
confidence=0.95, high_stakes=True,
|
|
|
|
|
|
prompt_name="alarm_explain", prompt_version="1.0.0", # 与版本库联动
|
|
|
|
|
|
)
|
|
|
|
|
|
print(v.action) # pass / human_review / unsupported
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 定期评测报告脚本(evaluate_hallucination.py)
|
|
|
|
|
|
|
|
|
|
|
|
PRD 5.4「定期用评测集检验事实一致性」:评测集 JSON + 版本库配置 →
|
|
|
|
|
|
Markdown 评测报告(按 `name@version` 分解,Prompt 变更后可对比各版本幻觉率)。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd core/llm-gateway
|
|
|
|
|
|
python evaluate_hallucination.py --demo --output reports/hallucination.md
|
|
|
|
|
|
python evaluate_hallucination.py --samples eval_set.json --output report.md
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 17:15:02 +08:00
|
|
|
|
## 后续子任务(EPIC #6 拆分,待扩展)
|
|
|
|
|
|
|
2026-08-04 18:02:00 +08:00
|
|
|
|
- 敏感度路由调优与路由准确率评估脚本(Issue #49,本版已提供评估入口);
|
|
|
|
|
|
- 本地 70B 模型接入与推理封装(Issue #44);
|
2026-08-04 23:15:39 +08:00
|
|
|
|
- 云端 API(Qwen/DeepSeek)接入与安全网关(Issue #45)。
|