feat(server): 参考 BidEngine 补五项:原因码、截断重跑、项目信息逐项表态、占位符、提示词规则对应校验

- 待确认记原因码(extract.FAILURES,存在 ai_values.failures),解析结果按原因计数
  (verify_failures);前端待确认条目显示具体原因
- 相邻分块重叠约 800 字;模型输出被截断或不是合法 JSON 时对半重跑(最多 3 层),
  拆到底仍不完整记 output_incomplete。修复:以前截断时整块条目被当成「没有结果」悄悄丢掉
- 项目基本信息提示词 v2:12 个字段逐项表态 found / ambiguous / not_found,跨分块合并为
  found / absent / needs_review(info_fields)
- 「____元」「××」「( )」「待填」等占位符不算取值
- 提示词 substantive v4,qualification / scoring / schedule / tech_param v3:每条禁止事项
  对应一个原因码,对照表在 prompts/README.md
- 顾问(Fable)深读参考项目的结论补进 ref-bid-engine-analysis.md §5;架构 §13 SK12
- 待确认:国动 4 → 2,S02 13 → 3,S06 57 → 55

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-03 21:59:12 +08:00
parent e3f234ca0b
commit f99bb8b358
22 changed files with 884 additions and 81 deletions

View File

@@ -214,3 +214,46 @@
- 数据库表结构用迁移工具管理。
- 租户隔离在数据层统一强制;管理端接口单独挂一层鉴权中间件。
- 任何「本地开发免登录」的开关,都不能出现在生产构建里。
## 5. 解析流水线深读(2026-11-03 补)
> 用户要求再读一次,聚焦「模型 + 规则」解析招标文件和检查投标文件。由 Fable 模型做顾问走查源码,关键结论对照源码抽查过(饱和对半重跑、段落级出处、not_found 分两类、直抽「找不到逐字引文就不要输出」、条款允许简明摘录)。只读、未运行。路径相对 `bid-engine-backend/pkg/handler/`。
### 5.1 结论
1. **组织方式比单个技巧更值得学**:抽取分两条车道——按章节开放式找条款(`bidanalysisv3/extraction.go`),和按固定字段表逐项过全文、每个字段必须表态 found / ambiguous / not_found(`bidanalysisv3/fixed_field_extraction.go`)。模型输出后有十余条确定性校验,每条失败都记原因码并按原因计数(`extraction.go:757-893`)。
2. **分块比我们细**:按章节打包,包与包之间带一个重叠块,超大表格单独成包;输出被截断(finish_reason=length)或条数正好碰到上限时,把这一包对半重跑,最多 4 层(`bidanalysisv3/extraction_schema.go:257-401`)。
3. **章节识别三级**:强正则 → 弱正则候选交模型消歧(只能删、改名、分类,不能新增,必须保留第一个,服务端核对编号和顺序)→ 每 20 页兜底(`bidanalysisv3/chapter_identification.go`、`extraction.go:207-317`)。章节类型用来分派任务。
4. **出处只到段落**:`pkg/repo/docling/adapter.go` 注释写明「溯源高亮精度从逐字精确变为段落级覆盖,已确认可接受」,引文就是整块文本;Docling 返回的粗体斜体、表头、合并单元格都没用,表格压成纯文本矩阵;条款允许「简明摘录」(`bidanalysisv3/fields.go:109`)。★ / 斜体下划线标注会全部漏掉。**这一层不学**。
5. **查标学框架、不学判定**:检查项来源分层(预设 / 从解读映射 / 企业规则 / 版式项),致命项逐条、其余按类别批量,检索不到直接给「未找到,需人工确认」不调模型,版式用规则扫描分硬 / 软证据(`bidreview/`)。判定结果的页码和引文不校验,pass 不要求证据,违反红线 2。
### 5.2 值得学的具体做法
- **固定字段逐项表态**:漏答、found 却无值、证据定位不到一律降为待核验并记原因;所有分块都答完才允许定 not_found;最终 not_found 再分「文件本身没写」(info)和「抽取异常」(warning)(`bidanalysisv3/fixed_field_service.go:183-217`)。
- **占位符不算值**:`___`、`××`、待填、TBD 等匹配为占位符(`extraction.go:29, 796-800`)。
- **标准化由服务端做**:金额、日期、单位在服务端解析,提示词禁止模型输出标准化值。
- **重复候选合并取证据并集**;多值冲突交模型裁决但只能缩减,没表态的默认全保留,不同标段 / 主体的值必须保留多个(`bidanalysisv3/consolidation.go`)。
- **每页质量指标**:字数、是否 OCR,平均不到 40 字 / 页判扫描页并 OCR 重跑,页数核对不符判失败(`bidanalysisv3/document.go:410-473`)。
- **告警三级**:critical(基础设施)/ warning(内容质量)/ info(文件本身缺),同类合并计数,基础设施错误直接停整个阶段。
### 5.3 提示词亮点
- 安全规则编号放在最前,声明输入是不可信数据并列举注入形式;用户消息只放数据标签 + JSON,能不给的原文就不给(章节消歧只给标题、页码、编号)。
- **否定清单具体、每条对应一条服务端校验**:not_found 不得带证据;占位符不算值;不同主体、标段、预算与限价不能混成一个值;不要为凑数编造;不得输出标准化值。
- JSON Schema 锁 enum、条数上限、引用编号格式;固定字段的条数下限 = 上限 = 字段数。
- 裁决类提示词「只能缩减」。
- 查标直抽:「quote 必须是该页文本中的连续原文……找不到逐字引文就不要输出」(`bidreview/tender_direct.go:23-25`),是全仓库最接近我们红线的一条。
- 没有正反例、没有版本号、没有评测集。
### 5.4 对标博士的取舍
顾问的 13 条建议里,「引文对不上时在同一块里找到原句、改挂出处」不采纳:它是在迁就模型的错误输出(2026-11-03 用户定的原则:规则只修真正的缺陷,模型输出不合理的改提示词)。只采纳其中「记原因码」的部分。
- **S01–S10 标注集评测之前做**(只改抽取、分块和提示词,不动数据结构):
1. 待确认条目记原因码,按原因计数;
2. 分块加重叠,检测输出截断并对半重跑;
3. 项目基本信息逐项表态,区分「文件本身没写」和「抽取出错」;
4. 识别占位符;
5. 提示词的禁止事项和服务端校验一一对应。
- **评测之后做**(涉及文字层数据结构):顶级章节识别并按章节类型分派任务;每页质量指标和扫描件判定;表格按行生成证据单元、带表头(解决两栏表、竖排文字串行)。
- **留到 M3 设计**:检查项来源分层、判定分层、检索不到不调模型、版式规则扫描;必须补投标侧引文逐字校验,pass 必须有校验通过的证据。检索用 PostgreSQL 的 pg_trgm / 全文检索,不自建倒排。