feat(check): 规则检查(报价形式、形式要件、响应表),表格按单元格分行

- check/rules.py(规则集 2026.11-r1,不调模型):大小写金额、分项合计、超最高限价、
  多个报价、别的项目名称、没填的地方、落款日期、投标有效期、附加条件、响应表里的未响应;
  每条挂投标原文,有依据的挂招标侧出处;缺限价、截止时间、有效期要求时写进覆盖范围
- 文字层的句子带上单元格框,表格按单元格上沿分行
- 按 Fable 审读意见收紧致命级:认不准的降为重要或提示
- 评测:score.py 评规则问题;P07 注入记录改为空白处前后原文,剔除注入到人员表的 D10
- 上传页的检查范围文案同步

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-04 16:44:22 +08:00
parent 47c6a1258e
commit db1b1f6f9f
17 changed files with 1792 additions and 20 deletions

View File

@@ -144,7 +144,40 @@
**读法**:问题的个数没变,变的是级别:规矩的投标文件上的致命问题少了一半多(120 → 51),多出来的是「请到扫描件里核对」的提示,致命级召回不变。总召回掉了 4 个点,主要是批次变化带来的波动(文件要在的条目不再进模型,同一批里的组合变了),以及几条漏响应被「标题里出现了文件名」误判为已响应——要盯着。评测集里证明材料全是扫描件页,所以证明材料缺失(D02)照旧查不出、扫描件兜底也分不出缺没缺;真正查出来要靠 OCR / 多模态(S5)。
## 6. 下一步
## 6. 第四轮:规则检查(报价形式、形式要件)(2026-11-04)
1. 第 2 步(投标侧结构识别、规则、C12 响应方式抽取)和第 3 步(整行上下文、偏离表直取、presence 判断)按 §2.2 的顺序改,每改一轮在开发集 14 份上重跑对比。
**改了什么**(`check/rules.py`,规则集 `2026.11-r1`,不调模型):
- **投标侧结构**:按坐标把句子分成行、按表头归栏,认三种表——开标一览表(「投标总报价」那一栏)、分项报价表(数量 / 单价 / 合价三栏,可以跨页接续)、响应表(有「响应情况 / 偏离情况」一栏);再加落款日期、格式文件的填写位、页眉。
- **规则**:大写和小写金额(P04)、分项算术和合计(P05)、超最高限价(P01 / P02,按所投采购包取限价)、多个报价(P12)、页眉和填写位里的别的项目名称 / 编号 / 采购人(P06)、没填的地方(P07)、落款日期晚于截止或写错(P08)、投标有效期短于要求(P09)、附加条件(P10)、响应表里写「未完全响应 / 负偏离」或空着(D10)。响应匹配已经对同一句报了负偏离的,规则不重复报。
- 每条问题挂投标原文;有依据的挂招标侧出处(限价、截止时间、项目名称来自项目基本信息,有效期要求来自清单项)。缺项目侧的值(限价、截止时间、有效期要求)或认不出开标一览表时不报,写进覆盖范围。
- 说明只写读到的数字和依据,不写「应改为多少」(红线 6)。
**顾问审读后的修改**(请 Fable 从真实政府采购投标文件的角度审读,只给代码不给结论)。它指出的主要风险是真实版式上的致命误报,按「宁可让人核对,不让规矩的投标文件挂致命」改了:
- **表格分行改按单元格**:文字层原来就用 pdfplumber 找出了单元格框,但没存到句子上;现在句子带上单元格框(可选字段,旧的文字层没有就按句子重叠分行),同一行按单元格上沿分。垂直居中的短格、折成几句的长格、纵向合并的格不再串行或错位。
- **开标一览表认得更严**:总价那一栏下面恰好一个金额才算总价,分项表、多年度报价表的金额栏叫「投标报价」也不会被当成「多个总价」;不同位置写的总价不一致改为重要级的「投标总价前后写的不一致」,不再按致命的「两个报价」报。
- **另报价按把握分级**:「备选方案 / 方案二 / 第二套」致命;「优惠价 / 让利后」重要;金额等于投标总价(开标一览表或分项合计)的不报;否定看整个分句。
- **分项表**:「硬件小计」这类分组小计不进明细;同一栏读到两个数的行(无框线表格的合并格)不核对;下一页重复表头接着算同一张表;说明写「相差多少元」。
- **响应表**:一条记录从序号行到下一个序号行;「空着」一律按重要报(可能是版面没认准);认「否」(「是否响应 / 满足」栏)、「不响应(见说明)」这类写法。
- **投标有效期**:只在投标函、开标一览表那一页上的按致命报,别处按提示;复述的招标原文不算;「本报价有效期」(原厂报价单)不算;要求有几条时取最少的天数;认表格写法(「投标有效期」一格、旁边或下面一格写天数)。
- **别的项目名称**:页眉要像项目名称(以「项目 / 工程 / 采购 / 标段」结尾或带编号),章节页眉不算;招标文件里出现过的名称、编号(代理机构编号、简称)不算;「致:贵单位」不算。
- **附加条件**:复述判断先去掉编号、用前后 20 字;「不影响合同价款」这类不算;技术分册里的按提示报。
- **大写金额**:前后两句都找、只认写着「小写 / ¥ / 报价 / 合计」的句子,任何一处相等就不报。
- 落款日期认汉字数字(「二〇二六年十一月十七日」)和「日 期:」;说明里去掉「……的投标无效」这类绝对说法,改为「通常会导致投标无效,请核对」。复查对齐的目标改为原文前缀 + 摘要,前缀相同的两句不会互相吞掉。
- 每类都加了开发集以外的反例单元测试(`test_check_rules.py`)。
**评测集修正**:P07 的注入记录改成空白处前后的原文(原来记段落开头,空白在同段后一句时对不上);S07-A-sloppy 的 D10 注入在人员表里(不是响应表),剔除,生成器改为只往表头有「响应」的表里注入。score.py 加了规则问题的评分:规则编号对上、投标侧出处里有注入的原文才算查出。
| 指标(17 份) | 结果 |
|---|---|
| 规则问题查出 | 57 / 57(P04 8、P05 7、P06 7、P07 10、P08 7、P09 1、P10 7、P12 7、D10 3) |
| 规则问题误报 | 0(规矩的投标文件 7 份上 0) |
| 规则问题的级别 | 致命 8(备选方案类另报价 6、投标函上的有效期 1、符合性响应表 1)、重要 32、提示 17 |
| 响应匹配 | 不变(召回 92 / 150,致命级 22 / 32) |
**读法:这个满分基本说明不了泛化。** 规则是在知道生成器怎么注入、见过开发词库措辞的情况下写的,投标文件版式也都出自同一个生成器。附加条件(P10)和多个报价(P12)的开发词库措辞直接落在规则的写法里,最需要留出集检验。为此做了两件事:规则按招投标文件的通用写法归纳(单元测试和 `bid-mini-forms.pdf` 都用开发词库以外的措辞);评测集里没有的情形(超限价、跨页分项表、万元单位)只有单元测试。真实投标文件的合并单元格、扫描页、各地模板差异,要等国动真实投标文件来看。P01 / P02 / P03 / P11 / P13–P18 评测集里还没有注入。
## 7. 下一步
1. 第 2 步剩下的:需人工核对的条目(份数、密封、递交方式)和 `manual-checks` 接口;「报价」类清单项和分项 / 单价上限(C7、P03);评测集补注入 P01、P02、P13。
2. 第 3 步:D09(响应对象错位)、D06(负偏离未说明)的提示词 v3,token 预算、复查复用、重复条目分组。
3. 留出集(S03、S06、S09,风格 B + C,封存的词库)和真实国动投标文件,在第 3 步冻结代码后只跑一次。