Skip to main content
Glama
14shi

requirement-asset-recommender

by 14shi
README.md
# 需求 → 数据资产 智能匹配系统

![python](https://img.shields.io/badge/python-3.11-blue)
![license](https://img.shields.io/badge/license-MIT-lightgrey)

> FastAPI · BM25 + 向量混合检索 · 交叉编码器精排 · 可标定判决器的智能体闭环 · MCP

系统接收自然语言描述、需求截图或任意版面的 Excel,在数据资产目录中匹配可用的表,
输出带字段级依据的推荐方案。

匹配过程是智能体闭环,而非单向调用。每轮检索完成后,判决器逐条评估候选资产与需求的
相关性;未达门槛时,系统依据检索中间态的诊断结论自主选择纠偏动作并重新检索。目录中
确无可支撑的资产时,输出**无法支撑**的判定与依据,不以近似结果填充。用户可针对返回
结果提出修正意见,系统在保留既往判决上下文的前提下继续迭代。

---

## 智能体闭环

### 自我审阅

每轮检索后,判决器逐条判定候选与需求的相关性(相关 / 部分相关 / 不相关),由代码聚合
为分数并与门槛比较;未达门槛则进入纠偏。

```text
match(检索)→ judge(逐条判相关性)→ 达标?
                                      ├ 是 → 交付
                                      └ 否 → 选纠偏动作 → 重新检索 → 再判
```

### 自主纠偏:可调整检索策略,不可调整判定标准

纠偏动作取自固定清单,权限边界由代码约束,不依赖提示词自律:

| 可自主调整 | 不可触碰 |
|---|---|
| 更换检索主题词 | 用户显式设定的过滤条件(周期 / 层级 / 域) |
| 调整检索参数(召回条数、精排深度、各路权重) | 方案接收阈值 τ、判决门槛 |
| 放宽由系统自行推断的过滤条件 | 用户勾选的必填字段 |
| 调取原始输入重新审阅 | — |

放开判定阈值等同于允许模型降低验收标准以使结果成立,将使"无法支撑"判定失效,
因此不纳入可调白名单,并由测试约束。

### 归因有据

纠偏前,代码从检索中间态计算带证据的诊断结论并提交判决器。同一现象往往对应两种病因
且处置方向相反,诊断的作用即在于区分二者:

| 现象 | 病因 A | 病因 B |
|---|---|---|
| 候选池过小 | 召回不足 → 调整参数 | 过滤过严 → 放宽推断条件 |
| 覆盖率普遍偏低 | 字段抽取有误 → 修正抽取结果 | 目录确实缺失 → 判定无法支撑 |

### 多轮协作

- **解析后确认**:抽取结果先交用户核对与增删,确认后再进入检索——纠错成本最低的环节
  置于最上游
- **结果后追问**:用户提出修正意见后,智能体携带既往会话历史继续纠偏,不重置上下文
- **会话持久化**:会话状态落盘,服务重启后 `session_id` 仍然有效

### 可审计、可中断

每一步记录 `action / reason / verdict / effect`(执行动作、决策依据、判决原文、前后
差异),随结果一并返回。首个动作固定为完整检索,因此任一时刻中断均有可交付结果,
最坏情况等价于纯检索。长任务支持协作式取消。

### 判决器须先标定

判决器进入自动决策链前,需以人工金标测量其与真实优劣的一致性(Cohen's κ),
**κ > 0.6 方可用于自动决策**。更换模型、修改提示词或调整计分规则后须重新标定。

---

## 自主优先级推荐

相关度与资产优先级(是否已订购、资产类型、数仓层级)量纲不同,直接加权需要人工调参,
且权重会随数据分布漂移而失效。系统改用**自然断点分档 + 档内字典序**,档宽由数据决定:

1. **估计可分辨最小差异(JND)**:取本次查询候选相关度降序后正间隙的中位数 ρ,
   回答"这条查询里典型的分数差有多大";
2. **自然断点切档**:从当前最高分向下扩展,直到遇到 `间隙 > gap_factor × ρ` 的显著
   断层才切开。分数紧簇(近乎并列)不切档,由优先级决定顺序;存在明显断层时相关度主导;
3. **档内硬排序**:按【优先级最差优先向量 → 相关度 → 覆盖度 → 表数更少】字典序选出。
   组合方案的档位取成员最低档,避免一张高档表把低档成员一并抬高。

档宽随数据自适应,不按查询形态预设分支——把"用户在问什么"交给预写的 if-else,
与手工权重是同一类问题。

优先级档位由「是否已订购 + 资产类型 + 数仓层级」按字典序合成,映射全部来自配置:

```yaml
# config/config.yaml → matching.ranking.priority
ordered_rank: 6         # 已订购(由订购清单 vlookup 标记,最高档)
asset_type_rank: {...}  # 资产类型 → 档位
layer_only_types: [...] # 仅这些类型内部再按数仓层级细分
layer_rank: {DWA: 5, DIM: 5, DWV: 4, DWI: 3, ODS: 2, STG: 1}
```

```yaml
# config/config.yaml → matching.layering
gap_factor: 2.0         # 间隙达 JND 几倍算断层:越大同档越宽,越偏向优先级
min_jnd: 0.02           # JND 绝对下限,仅兜底分数全等 / 单点等退化情形
```

---

## 其它能力

| 能力 | 说明 |
|---|---|
| **任意版面解析** | 文本 / 截图(视觉模型转写)/ Excel(任意版面)统一入口;区域切分由纯代码实现五级降级,未见过的版面亦保证有输出 |
| **混合检索** | 词法(BM25)+ 稠密语义 + 字段倒排三路召回 → RRF 融合 → 交叉编码器精排;分段编码与 top2 池化,避免表名语义被大量字段稀释 |
| **组合方案** | 单表覆盖不全时,按共享连接键贪心组合多张表 |
| **三种接入** | Web 面板 / REST API / MCP(六工具 + 异步任务 + 协作取消) |
| **自动降级** | 无 GPU 或权重缺失时按可用资源自动降级,质量下降而链路不中断;降级项经 `/api/health` 上报,可接入监控 |

---

## 快速开始

```bash
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt

# 可选:安装后启用语义召回 / 精排 / 本地大模型;未安装则自动降级为词法检索 + 规则解析
pip install sentence-transformers
pip install torch --index-url https://download.pytorch.org/whl/cpu

python -m uvicorn src.api.app:app --host 127.0.0.1 --port 8001
```

Web 面板位于 `http://127.0.0.1:8001`。接口调用:

```bash
# 一步式:解析 → 检索 → 自我审阅 → 交付
curl -X POST http://127.0.0.1:8001/api/agent/run \
  -F "text=分析会员复购行为,需要用户ID、订单数、支付金额"

# 多轮:对上一轮结果提出修正意见,携带历史继续纠偏
curl -X POST http://127.0.0.1:8001/api/agent/resume \
  -F "session_id=<上一轮返回的 session_id>" \
  -F "feedback=当前结果不符合预期,需要履约时效相关的资产"
```

示例目录随仓库提供(`data/samples/`,3000 张表,覆盖交易、用户、商品、履约、营销、
服务、风控、内容、位置、财务十个业务域),无需额外准备数据;CPU 环境同样可运行。

首次请求会构建检索索引并加载模型——3000 张表在 CPU 上需数分钟;索引落盘至
`data/.cache/`,之后按内容指纹命中缓存,重启不重建。

---

## 换成自有数据

系统对被推荐对象的类型不做硬编码假设:只要数据可整理为"条目 + 属性清单 + 描述"的
结构即可直接使用。数据表、文档库、商品、API、知识条目均适用,**无需改动检索、排序
与智能体骨架**。

### 1. 必换:目录数据

准备一份同结构 CSV(示例见 `data/samples/assets.sample.csv`):

| 列 | 作用 | 迁移至其它场景时的对应物 |
|---|---|---|
| `表名` | 条目唯一标识 | 文档 ID / 商品编码 / API 名 |
| `表中文名` | 展示名称,参与检索 | 文档标题 / 商品名称 |
| `字段中文名` | **属性清单**(`\|` 分隔),字段级匹配的依据 | 文档章节 / 商品属性 / API 参数 |
| `业务分类名称` | 分类,参与语义分段编码 | 自有分类体系(`一级/二级`) |
| `模型概述` | 描述文本,语义召回的主要依据 | 摘要 / 简介 |
| `技术口径` | 补充说明 | 使用条件 / 更新频率 |
| `周期` / `层级` / `数据域` | 三个硬过滤维度 | 任意三个枚举维度;无需过滤则整列留空 |
| `是否上架` / `资产类型` | 业务优先级与过滤 | 无对应概念时填固定值 |
| `系统名称` / `库名` / `是否UCX表名` | 归属与标记 | 可填固定值 |

```yaml
# config/config.yaml
data:
  assets_file: data/自有目录.csv      # 默认按 gb18030 读取
```

> 默认读取编码为 `gb18030`。若目录文件为 UTF-8,可先行转码,或修改
> `src/data_loader.py` 中的读取编码——该处是唯一与文件编码相关的耦合点。

**枚举取值必须与排序逻辑对齐。** `资产类型` / `层级` / `周期` 三列参与优先级分档与硬
过滤,取值须出现在对应映射表中,否则该行会落到最低档或永远无法被筛中:

| 列 | 取值须匹配 | 未匹配的后果 |
|---|---|---|
| `资产类型` | `matching.ranking.priority.asset_type_rank` 的键 | 档位记 0,排在所有已知类型之后 |
| `层级` | `matching.ranking.priority.layer_rank` 的键 | 层级细分失效(仅影响 `layer_only_types` 列出的类型) |
| `周期` | `src/matching/normalize.py` 的 `CYCLE_ALIAS` | 用户按周期硬过滤时该行不会被选中 |

替换目录后,将自有取值补进上述映射表,或将数据归一到既有取值,二选一。
`数据域` 需保持单一粒度(同一层级的枚举),混用粗细粒度会使按域过滤漏掉子类。
仓库内示例目录已按此对齐。

`ordered_rank`(已订购)依赖 `data.ordered_file` 指向的订购清单;示例配置未提供该文件,
该档位不会触发,接入自有清单后自动生效。

### 2. 建议更换:四份领域词表(直接影响召回质量)

| 文件 | 作用 | 沿用示例的影响 |
|---|---|---|
| `data/samples/synonyms.sample.json` | 同义词组,消解用户表述与目录命名的差异 | 跨命名差异的召回明显减弱 |
| `data/topic_aliases.json` | 口语或异名 → 规范主题词("物流轨迹" → "配送轨迹") | 口语化查询命中率下降 |
| `data/category_keywords.csv` | 业务分类 → 关键词线索,供分类推断使用 | 分类推断准确率下降 |
| `data/domain_terms.txt` | 领域专有名词,保证分词不切碎 | 多字专有名词可能被错误切分 |

仅同义词表可通过 `data.synonyms_file` 换路径;后三者的路径写死在 `pipeline.py` 与
`normalize.py` 中,按原路径替换文件内容即可。仓库内的四份均为起步规模(同义词 8 组、
分类 64 条、专名 67 条),按自有领域扩充。

其中同义词表收益最高。格式为 `{"规范词": ["别名1", "别名2"]}`,将目录字段名中同一
概念的不同写法归为一组即可;先覆盖十余组高频概念即可见效。

### 3. 可选:替换抽取提示词中的示例

`src/matching/extractor.py` 与 `src/matching/llm_parser.py` 的提示词中包含领域示例,
用于界定"何为一条需求、何为一个字段"。示例不构成逻辑分支;但在领域差异较大时,
替换为本领域的两三个示例可显著提升解析质量。

### 4. 更换后必须重新标定

- **语义阈值**:`field_match.retrieve_min_sim` 与 `min_ce` 属模型校准项,取值随嵌入
  模型与领域词汇分布变化。从本领域各取十余对"真同义"与"无关"字段,按两组分数的分界定值。
- **判决器 κ**:相关性判定依赖领域语义,跨领域沿用旧结论无效。以本领域标注集重新测量
  Cohen's κ,仍需 > 0.6 方可用于自动决策。
- **评测集**:仓库不含金标标注。指标须在本领域自建标注集上重新建立,跨领域数字不可比。

---

## 三种接入

- **Web**:`/` 单页,描述需求 → 确认草稿 → 生成方案 → 导出 Excel,支持多轮修正与
  任务取消
- **REST**:`/api/agent/run`(一步式)、`/api/agent/resume`(多轮追问)、`/api/match`
  (纯检索)、`/api/parse` + 确认(两步式);含文件的请求自动转为异步任务,支持取消
- **MCP**:`/api/mcp/`,六工具(`parse_requirement` / `revise_draft` / `match_assets` /
  `refine_results` / `submit_feedback` / `list_asset_facets`)+ 异步任务 + 协作取消,
  对话平台可自动发现工具

完整调用契约见 `docs/API接口文档.md`。

---

## 文档

| 文档 | 内容 |
|---|---|
| `docs/架构讲解.md` | 以一次请求的时间顺序说明全链路实现 |
| `docs/API接口文档.md` | REST、MCP、异步任务与认证的完整调用契约 |
| `docs/MODELS.md` | 模型权重与缓存说明 |
| `CONTRIBUTING.md` | 工程约定与变更规范 |

---

## 工程原则

- 语义判断交由模型,机械切分交由代码;不对需求文档的版面做硬编码假设
- 不做静默降级:截断、丢弃与能力降级一律经 `/api/health` 或诊断通道上报
- 判决器进入自动决策链前必须标定;能力升级仅通过配置实现,不改动代码
- 每个已修复缺陷均附带回归测试,并记录其原始失效方式

---

## 说明

本仓库提供可复用的方法与工程骨架。所含目录数据为构造的通用样本(3000 张表,结构与
统计分布与真实生产目录对齐);词表与评测数据经脱敏后完整提供。真实业务目录不包含在
内,替换为自有数据即可运行。