Files
bid-doctor/docs/architecture/check-eval.md
YANG JIANKUAN 08e3fe7eff
Some checks failed
ci / server (push) Has been cancelled
ci / web (push) Has been cancelled
ci / contract (push) Has been cancelled
feat(qualification): 资质库和资质匹配(查标第 4 步,规则集 2026.11-r4)
- 资质库(FR-M6-08):增删改、证书扫描件(PDF/JPG/PNG,企业级密钥加密、签名下载)、
  late_for 按进行中项目的投标截止日提醒、审计;前端资质库页和对话框,侧栏入口
- 资质匹配(FR-M3-05):证书类别词表(16 类,产品证书、人员证书不进匹配),
  QUAL.EXPIRED / LEVEL_LOW / NOT_COVERED;投标文字层按清单项定级,只有资质库记录的降一级,
  出处显示「依据:资质库记录」(查标页、报告模板 v2);一类证书一个问题;评分项不逐条找响应的也查
- 响应错位规则不再把资质表的证书名称格当成照抄的要求
- 评测:qual_defects.py 派生资质情况表,D12 3/3、D18 2/2、规矩的资质表 0 误报;开发集不退化
- 决策 QL1–QL7;方案和落地记录 docs/architecture/qualification-plan.md,评测 check-eval.md §13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 23:22:50 +08:00

42 KiB
Raw Blame History

查标评测(2026-11-04 起)

评测集规范:evals/check/GUIDELINES.md;工具:evals/check/;数据和输出在 evals/out/check/(不进 git)。 读数的前提:金标准由 Fable 复核、用户抽查 20%(决策 E1),未经全部人工复核;本文的数字都是开发集上的,只用于找问题、调实现,不能当效果证据。头条效果以留出集(风格 C)和真实国动投标文件为准,第 3 步冻结代码后才跑。

1. 试跑(第 0 步,2026-11-04)

范围:开发集 S02、S04、S10 各两份投标文件(规矩 + 马虎),都是风格 A(风格 B 的改写还没做)。查标代码是第 1 步的版本:响应匹配只有「检索 + 模型判断」,规则检查还没有。模型 DeepSeek Flash,提示词 check.match v1。

复核:马虎的投标文件共注入 82 个要求项问题,Fable 复核通过 70 个、不通过 12 个(S02 10 个:默认接受的文件里注入了漏响应、「暂不支持」套在尺寸和费用这类参数上、要求本身是可选项等)。下面只算通过的。用户抽查 17 条(随机 20%,含 Fable 判不通过的 4 条),全部同意(2026-11-04)。

1.1 结果

投标文件 清单条数 报出问题 查标召回 致命级召回 规矩响应的要求上误报 不需要响应的条目上报了问题
S02 规矩 248 104 — — 21 / 56 39
S02 马虎 248 117 8 / 16(50%) 2 / 7
S04 规矩 264 90 — — 11 / 111 52
S04 马虎 264 110 11 / 28(39%) 1 / 4
S10 规矩 305 122 — — 6 / 39 75
S10 马虎 305 142 5 / 20(25%) —
  • 合计查标召回 24 / 64(38%)。只检索不调模型的基线召回 0:基线把检索到的第一句都当作已响应,说明现在查出的问题来自模型判断,不是检索。
  • 按问题类型:漏响应(D01)9 / 14 较好;写明不支持(D05)5 / 20、负偏离未说明(D06)0 / 7、响应对象错位(D09)0 / 4 很差。
  • 每次检查调用模型 31~39 次,输入约 9~11.5 万 token、输出约 1.5~1.7 万 token(约一两毛钱)。

1.2 问题出在哪里

  1. 不需要投标人响应的条目也被报了「未找到响应」:三份规矩的投标文件报了 316 个问题,166 个落在根本不需要响应的条目上(无效情形的列举、日期、采购人义务、别的采购包),这是误报的大头。→ C12 的响应方式抽取,加上「这条要不要投标人回答」的判断和按所投采购包过滤(第 2、3 步)。
  2. 表格里的「暂不支持」「负偏离」看不见:表格按单元格切句,检索命中的是投标人照抄要求原文的那一格,同一行里写着「暂不支持」「负偏离」的格子不在模型的输入里。→ 第 3 步把整行交给模型(偏离表直取也是这个思路)。
  3. 证明材料和格式文件找不到:规矩响应的要求上的误报,主要是证明材料(扫描件页没有文字层)和格式文件(声明函、承诺书)报了「未找到响应」,以及让投标人「见附件」的要求被报成「未给出具体值」。→ C10 扫描件兜底;文件要在(presence)的要求按文件在不在判断,不逐条找响应。
  4. 级别口径:S02 的 ★ 是「核心技术参数,负偏离扣分」,不是投标无效条款;标注集记成实质性条款,查标按致命报和真实评审不一致。→ 级别要跟着招标文件对 ★ 的定义走(读标口径 Q2 已有,查标沿用)。

1.3 评测集自身的问题(已修 / 待修)

问题 状态
分项报价平均摊,一项超过单价上限,规矩的投标文件自带致命问题(S10) 已修:按分项上限比例分摊
偏离表有「设备名称」列,按固定列写会错位(S04) 已修:按表头决定列
写死的落款日期晚于投标截止日(S04) 已修:取截止日前 3 天
同一参数列在两张表里,只删一张表的行不算漏响应(S04) 已修:漏响应在所有表里都删
符合性条件响应表的一格被算成 11 个问题 已修:按表级问题记一个
标注集同一要求有两个单元(两个类别、或表格一行拆成几条),一个问题算两次 已修:评分按句子重叠合并
「暂不支持」套在尺寸、费用、打印方式这类参数上,不像真实写法 待修:按参数类型选注入方式
默认接受的文件里注入漏响应(S02 另加了一张逐条的技术规格表,脚本推响应方式时被它带偏) 待修:响应方式以档案的 modes 为准,不从表格推
「提供某文件」类要求被当成参数注入偏离 待修:推响应方式时识别 presence
风格 B 的改写(截断、同义替换、只写值)还没做;所有数字都是风格 A 的 待做

2. 开发集第一版(2026-11-04)

范围:开发集 7 份招标文件各两份投标文件,共 14 份:S02、S05、S08、S10 是 A 规矩 + B 马虎,S01、S04、S07 是 B 规矩 + A 马虎(GUIDELINES §4)。生成器修了试跑的待修项(「暂不支持」不再套在数值参数上、表格响应方式以档案为准、「提供……文件」不注入参数类问题),风格 B 由模型改写、数字对不上的改写丢弃。查标代码仍是第 1 步的版本。

复核:注入的要求项问题两批共 222 个,Fable 复核通过 188 个。第二批 140 个里不通过 22 个,其中 14 个在 S07:S07 须知要求逐条标明,格式注又写未列入视作接受,且只有 ★ 项写明未响应无效,非 ★ 参数删一行算不算问题拿不准,金标准从严不算(查标侧仍按 C12 取更严的逐条)。用户抽查第一批 17 条全部同意;第二批抽查 28 条(含 Fable 判不通过的 4 条)也全部同意。两批合计抽查 45 条,和 Fable 的判断一致。

2.1 结果

指标 结果
查标召回(复核通过的问题) 51 / 128(40%);风格 A 25 / 70(36%),风格 B 26 / 58(45%)
端到端召回(含读标漏抽) 51 / 132(39%)
致命级召回 18 / 37(49%)
不带标志词 / 带标志词 40 / 81(49%)/ 11 / 51(22%)
连续一段 / 单点 7 / 12(58%)/ 44 / 120(37%)
规矩的投标文件报出的问题 清单 2049 条,报出 699 个
其中规矩响应的要求上的误报 153 / 620(每 100 条 24.7)
其中不需要响应的要求上报的 334 个(占 48%)
干扰项误报 默认接受的要求没复述(T06)39,改写后的要求(T02)20,响应写在别的分册(T01)3
费用 14 次检查输入 150 万 token、输出 25 万 token

按问题类型:资格证明缺失(D11)9 / 14、评分材料缺失(D13)9 / 12、漏响应(D01)15 / 23 较好;负偏离未说明(D06)0 / 20、响应对象错位(D09)1 / 14、证明材料缺失(D02)2 / 9、写明不支持(D05)11 / 31 很差。

2.2 读法

  • 试跑的四个判断都成立,而且更清楚了:「带标志词」的问题(写明不支持、负偏离)召回只有 22%,比不带的还低,正是表格里同一行的响应格、偏离格不在模型输入里;风格 B 反而比 A 高,因为 A 照抄要求原文,检索更容易命中照抄的那一格。规矩的投标文件上近一半的问题落在不需要响应的要求上,默认接受的要求被报了 39 次。
  • 第 2、3 步按这个顺序改收益最大:① 整行上下文 / 偏离表直取(直接对应 D05、D06、D09,51 个问题里的 45 个);② 响应方式和「这条要不要投标人回答」(C12,对应 334 + 39 个误报);③ 扫描件兜底和 presence 判断(证明材料、格式文件类误报)。

2.3 评测集还要改的

问题 状态
「暂不支持」「可选配置」仍会套在证书、供货清单、服务义务、文档交付这类非功能要求上(两批共 12 条被复核拒掉) 待修:注入前按「功能类要求」过滤
同一要求被两个标注单元挂了同一个问题(实质性 + 技术参数、资格 + 符合性,第二批约 20 对);「第二十二条总述」这类伞状单元和具体条目不重叠 待修:注入前按 anchor 重叠合并标注单元;伞状单元不挂问题
条件性要求(「如依法免税则须提供」)被当作必须提供的材料挂 D11 待修:按投标人情况排除
低密度(每份 5~8 个问题)的投标文件还没做 待做:选 3 份

3. 第一轮改进:整行上下文(2026-11-04)

改了什么:候选句在表格里时,把同一行的单元格一起交给模型,也可以引用(check/match.py);提示词 check.match v2 说明怎么读一行(要求格 / 响应格 / 偏离格)。对应 §2.2 的第 ① 项。v2 的规则写法避开了开发集注入词库里的说法(重合的只有「负偏离」「完全响应」,是招标文件格式自带的用语)。

评测集同时修了 §2.3 的前三项(「暂不支持」只套功能类要求、伞状单元和条件性要求不挂问题),7 份马虎的投标文件用原来的种子重新生成,另加 3 份低密度的,共 17 份。新目标 55 个由 Fable 复核(通过 54 个),用户抽查 11 个全部同意(三批合计抽查 56 个,全部同意)。因为注入的问题换了一批(「负偏离未说明」多了、「暂不支持」少了),下表的「旧做法」要和同一批投标文件比,不能和 §2 的数字直接比。

指标(17 份,复核通过的问题) 旧做法(v1、不带整行) 新做法(v2 + 整行)
查标召回 43 / 145(30%) 73 / 145(50%)
致命级召回 9 / 31(29%) 15 / 31(48%)
带标志词 1 / 65(2%) 35 / 65(54%)
负偏离未说明 D06 / 写明不支持 D05 / 数值不满足 D03 0 / 58、1 / 7、3 / 7 28 / 58、7 / 7、6 / 7
漏响应 D01 / 响应对象错位 D09 18 / 27、3 / 14 14 / 27、0 / 14(变差)
规矩的投标文件报出的问题 699 639
规矩响应的要求上的误报 153 / 620(24.7 / 100) 132 / 620(21.3 / 100)
不需要响应的要求上报的问题 334 329
输入 / 输出 token 189 万 / 32 万 273 万 / 28 万

读法:整行上下文解决了「看不见响应格、偏离格」的问题,带标志词的问题从几乎查不出到过半;误报略降。代价是输入 token 多 44%。两处变差:漏响应(D01)和响应对象错位(D09)。推测是同一行或相邻行的内容让模型更容易「找到点什么就判已响应」:漏掉的那一行不在了,检索命中的是相邻要求的行;错位的那一行响应格写的是另一条参数,模型没比对参数名。下一轮在提示词里要求先核对响应格说的是不是同一个参数 / 设备,并单独看 D01、D09 的漏报明细。不需要响应的要求上的误报(329)没有变化,要靠第 ② 项(C12)。

4. 第二轮:评测集纠错 + 响应方式和「要不要回答」(2026-11-04)

评测集纠错:§3 里漏响应、响应对象错位「变差」,逐条看漏报后发现多数是生成器的错,不是查标的错:读标清单有重复条目、S04 同一参数列在两张表里、技术方案散文也复述了要求,注入器只改了其中一处,别处还留着正确的响应,模型找到它是对的。改为同一要求的所有表格行一起改;在散文、附件、格式文件里也响应了的要求不挂漏响应 / 数值不满足 / 错位;错位响应必须是另一个参数的。马虎的投标文件按原种子重新生成,新目标 45 个由 Fable 复核(通过 40 个),用户抽查 9 个全部同意(四批合计抽查 65 个,全部同意)。

查标改了什么(第 2 步的 C12 部分):

  • checklist/response_mode.py:按类别(技术 / 商务)识别招标文件的响应方式,规则优先;冲突按逐条,认不出按逐条并标明。开发集 7 份的识别结果和档案一致。(还没存进清单、没做清单页的显示和修改。)
  • check/applicability.py:不需要投标人回答的条目不逐条找响应,写进覆盖范围(无效情形 —— 但 ★ / 斜体下划线标注的条款照常找、日期与递交、没要求附材料的评分标准、无需提供证明或由采购人查询的资格)。要求附证明材料按原文判断(读标的 evidence_required 常常是空的),中标后才交的不算。
  • 默认接受的要求没找到响应:一般要求记「按招标文件默认接受」、不出问题;实质性要求出提示级「请人工核对」;要附证明材料的不免(迁移 0006 加了两种结论)。
指标(17 份,复核通过的问题) v1 v2 + 整行 + 响应方式和「要不要回答」
查标召回 48 / 150(32%) 102 / 150(68%) 97 / 150(65%)
致命级召回 9 / 32 20 / 32 21 / 32
规矩的投标文件报出的问题 699 639 229
规矩响应的要求上的误报 24.7 / 100 21.3 / 100 12.4 / 100
不需要响应的要求上报的问题 334 329 77
默认接受的要求被报(T06) 39 35 1
输入 token 189 万 273 万 224 万

按问题类型(最后一列):漏响应 19 / 24、写明不支持 13 / 14、数值不满足 4 / 4、负偏离未说明 39 / 59、评分材料缺失 9 / 14、错位 6 / 13;证明材料缺失 1 / 17。

读法:规矩的投标文件上的问题少了三分之二,召回只掉了 3 个点(掉的主要是只在默认接受的文件里、被正确判为「默认接受」的条目,以及证明材料)。证明材料缺失几乎查不出:资格证明、检测报告多是扫描件页,没有文字层,规矩的投标文件上同样报「未找到」——这是下一项(C10 扫描件兜底 + 文件要在的判断)。

一处要说明的:调响应方式识别时,打印结果里顺带出现了留出集 S03、S06、S09(招标文件本身,不是投标文件)的识别结果,其中 S03、S09 和规范 §2 的记录不一致。没有据此改任何规则,留到留出集正式评测时再看。

5. 第三轮:扫描件兜底、文件要在、响应方式存进清单(2026-11-04)

改了什么:

  • 文件要在(check/presence.py):「提供《授权委托书》」「须提交投标函」这类要求,从原文取出文件名,在投标文件里找写着它的标题;找到就算已响应(出处是那个标题),不调模型。
  • 扫描件兜底(C10):要附证明材料的要求没找到、而投标文件里有扫描件页时,不报「未找到响应」,改成提示级「可能在扫描件里,请人工核对」。没有 OCR 时,扫描件里有没有这份材料分不出来。
  • 响应方式存进清单(迁移 0008):解析时识别、带依据句子存下来;清单页显示,可以改(人工确认点,写审计,重新解析不覆盖人工改过的);查标用存下来的。
指标(17 份) 上一轮(mode) 本轮(scan)
查标召回 98 / 150(65%) 92 / 150(61%)
致命级召回 22 / 32 22 / 32
规矩的投标文件报出的问题 229(致命 120、重要 58、提示 51) 235(致命 51、重要 14、提示 170)
规矩响应的要求上的误报 12.4 / 100 13.5 / 100

读法:问题的个数没变,变的是级别:规矩的投标文件上的致命问题少了一半多(120 → 51),多出来的是「请到扫描件里核对」的提示,致命级召回不变。总召回掉了 4 个点,主要是批次变化带来的波动(文件要在的条目不再进模型,同一批里的组合变了),以及几条漏响应被「标题里出现了文件名」误判为已响应——要盯着。评测集里证明材料全是扫描件页,所以证明材料缺失(D02)照旧查不出、扫描件兜底也分不出缺没缺;真正查出来要靠 OCR / 多模态(S5)。

6. 第四轮:规则检查(报价形式、形式要件)(2026-11-04)

改了什么(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. 第 2 步收尾:需人工核对、分项上限(2026-11-04)

需人工核对(FR-M3-04、决策 P2,check/manual.py):份数、密封、递交、CA 签章加密、解密、保证金这些投标文件里看不出来的要求,从正式清单里挑出来(技术参数、评分项、资格条件不算;写明免收保证金的不列;点名要交的文件归「文件要在」),按主题合并成最多 5 条(开发集 7 份招标文件每份 3~4 条,原始条目 12~48 条),带招标原文出处;查标页勾选,按项目存、写勾选人和时间,复查后还在。接口 GET / PUT /projects/{id}/manual-checks,check_key 用 rule:MANUAL.<主题>,清单改了勾选也还在。不生成「问题」,覆盖范围里写明列了几条。

分项 / 单价上限(C7,checklist/price.py + 规则 PRICE.OVER_CEILING_ITEM):读标时从采购需求的清单表(表头有「名称」和「单价上限 / 分项限价」两栏,表前一句写采购包)逐行读出名称、数量、上限,作为「报价」类正式条目并入清单,出处是表格那一行,不调模型;采购包一级的表不算。查标时这类条目不交给模型,规则拿分项报价表里同名分项的单价比,超了报致命,挂招标侧出处和清单项。名称要求很严(完全相同、去掉括注后相同,或重合度 ≥ 0.8),对不上的写进覆盖范围。开发集只有 S10 有分项上限,5 条全部读对;散文写法(「单价不得超过 × 元」)还不认。

评测集:从规矩的投标文件派生 4 份只带报价问题的(evals/check/price_defects.py:只改一个分项单价,合价、合计、大小写跟着改,算术一致):S01-B-p01、S04-B-p01(超总价限价 1 元 / 1%)、S10-A-p02(超采购包限价 1%)、S10-A-p03(分项单价超上限 1%)。S10 的分项上限加起来就是采购包限价,总价超限必然有分项超上限,生成器把这条一并记进金标准。21 份上规则问题 62 / 62 查出、误报 0;同样只说明规则和生成器对得上。

8. 第五轮:偏离栏直读、响应错位、复查复用和预算(2026-11-04)

改了什么(check/deviation.py,都在模型判断之后、不调模型):

  • 偏离栏直读:模型判「已响应 / 只写满足」的条目,看它引的证据句所在的表格行;同一行有单元格整格写着「偏离 / 负偏离 / 部分满足 / 未完全响应」这类字样,改判负偏离,证据带上那一格。只写「偏离」两字的要是识别出单元格框的格(跨页无框的行抽字时「无偏离」会被拆成「无」「偏离」,规矩的 S07-B 上出过一次)。漏掉的 D06 多数就是这种:响应格照抄要求「满足,……」、偏离格写「偏离」,提示词已经要求读整行,模型还是漏。
  • 响应错位(D09):模型判「已响应」、引的证据全是照抄的要求格,同一行右边的响应格写的是别的内容(「显示器升降行程:150mm」「1位」),且和要求没有一个字对 / 数字字母串重合 → 改判「响应可能对不上」,说明里写出响应格原文。笼统的「支持 / 具备」、「详见……」、只写「满足」、要求太短(汉字少于 8 个)的不判。条件很严,宁可漏。
  • 复查复用(C2,check/reuse.py):每条清单项按「提示词版本 + 要求 + 候选句和同一行的单元格原文」算缓存键,和模型那一层的原始结论(后处理之前)一起存进 check_item_result;复查时键相同、证据句在本次投标文件里原样找得回来的,直接沿用,不调模型;响应方式、偏离栏直读这些后处理照常重算。覆盖范围写沿用了几条。
  • 硬预算(C2):每次检查送给模型的字数上限 120 万字(开发集平均约 5 倍),按批次顺序分配,超出的批次不调模型,条目记「超出预算」列为请人工核对,覆盖范围另写。
指标(17 份) 第三轮(scan) + 偏离栏直读 + 响应错位(本轮)
查标召回 92 / 150(61%) 107(71%) 109 / 150(73%)
致命级召回 22 / 32 24 / 32 24 / 32
D06 负偏离未说明 38 / 59(64%) 53 / 59(90%) 53 / 59(90%)
D09 响应对象错位 5 / 13 5 / 13 7 / 13
规矩的投标文件报出的问题 235 236 235
模型调用 — 全部命中缓存 全部命中缓存

读法:两项都是确定的规则,没有改提示词、没有多花 token。响应错位报了 3 处(2 个单元),全对,规矩的投标文件上没有改判;第一版报错的 4 处(「13.56MHz」没算数字字母重合、「支持」当成别的内容、要求太短)修掉后才是这个数。偏离栏直读依赖投标文件的偏离栏写法,真实文件里偏离栏常写「无」「—」「见说明」,这些不会改判(不算不满足),只有明确写了不满足的字样才改。

9. 第六轮:同一行按单元格、业绩条款不再误跳、重复条目只合并显示(2026-11-04)

改了什么:

  • 送给模型的「同一行」按单元格分行(有框线的表格;正文句子照旧按上下重叠):垂直居中的格子、折行的长格不再串到上下行。要重跑模型(17 份约 225 万 token)。
  • 「以合同签订时间为准」不再当作「签订合同时才交」:applicability 判断证明材料是不是中标后才交的正则把它也认成了「签订合同时」,业绩评分项(「需提供合同复印件……以合同签订时间为准」)因此被当作「没要求附材料」跳过。评分项的业绩条款几乎都这样写。
  • 重复条目(决策 C5 修订):每条照常单独判断;问题接口给出同一次检查里问题类型相同、要求原文完全相同的其他问题(duplicate_ids),查标页同组只显示一条,注明「清单里出现 N 处」,处理和撤销对整组生效。
  • 致命项重问(C3)先不做:开发集 17 份上证据没通过校验的只有 5 条,致命级 0 条,C3 定的「不超过致命问题的 10%」已经满足,开发集上没有可测的对象;等真实投标文件上看到再做。
  • 评测集裁定 1 条(adjudication/S10-B-sloppy.md):t20 的漏响应不成立,技术方案正文完整响应了(生成器没认出风格 B 改写过的正文复述);问题总数 150 → 149。另核实了 3 条疑似错误、不改:S10-A-low t16 正文只响应了一半;S04-A s21 / s22 是同一条认证要求在几台设备下各写一遍、投标文件漏了其中一台——清单把几台设备的同一要求合成了一条,按条目查看不出哪一台漏了,这是现在的局限。
指标(17 份,按 149 个问题重算) 第五轮(mismatch) + 同一行按单元格(cellrow) + 业绩条款(award,本轮)
查标召回 109(73%) 108(72%) 111 / 149(74%)
致命级召回 24 / 32 25 / 32 25 / 32
D06 / D09 / D13 53 / 7 / 9 53 / 5 / 9 54 / 5 / 10
规矩响应的要求上的误报 84 / 620 81 / 620 81 / 620
干扰项误报 30 27 24
规矩的投标文件报出的问题 235 236 239
输入 token(17 份) 221 万 225 万 225 万

读法:按单元格分行和上一轮基本持平(召回 -1、致命 +1、误报略少),在一次模型重跑的波动范围内,结构上更对,保留。D09 少的 2 条是响应错位判断依赖模型引用「照抄的要求格」,模型换了引用就不触发——它是补漏,不是主力。业绩条款的修正带来 D13 +1、D01 +1;规矩的投标文件上多了 3 个提示(新查的业绩评分项)。

10. 第 3 步冻结(2026-11-04)

查标代码冻结在 a60d16e(规则集 2026.11-r2、提示词 check.match v2)。之后跑留出集(S03、S06、S09,风格 B 规矩 + 风格 C 马虎)和国动真实投标文件各一次,结果只记录,不据此调规则和提示词(GUIDELINES §8);留出集上发现的生成器错误按「响应清单错误」单独记数。

11. 留出集结果(冻结代码 a60d16e,跑一次,2026-11-04)

留出集怎么做的:S03、S06、S09 各一份风格 B 规矩 + 一份风格 C 马虎,共 6 份。招标档案由三个代理按 prompts/profile.md 写(S03、S06 各有 1100~1300 多条正式条目,是开发集最大的 2~3 倍);风格 B 改写由代理逐行手写(第一版用脚本批量生成,质量不够,返工);风格 C 由封存一侧的会话按封存说明在 build.py / mutate.py 里实现(开发集风格 A / B 输出逐字节不变),注入用留出集词库。96 个注入问题由 Fable 复核,通过 79、不通过 17(18%,开发集约 10%~15%:风格 C 生成器的「别处已响应就不注入」判断不够严,漏响应 6、可选加分当成缺证明 5、偏离行错位 3、删错材料 2、错位 1);用户抽查 19 条(含不通过 4 条)全部同意。

指标(只算复核通过的问题) 开发集 17 份(调过) 留出集 6 份(冻结代码原样) S03 人工确认响应方式后
查标召回 111 / 149(74%) 40 / 74(54%) 12 / 21(57%)
致命级召回 25 / 32(78%) 23 / 41(56%) 7 / 10
D06 负偏离未说明 54 / 59(92%) 5 / 20(25%) —
D01 / D03 / D05 / D09 74% / 100% / 86% / 38% 58% / 90% / 100% / 80% —
D02 / D11 证明材料、资格材料缺失 6% / 100% 50% / 33% —
规矩的投标文件报出的问题 239(7 份) 1134(3 份),其中 S03-B 1094 S03-B 45
规则问题查出 57 / 57 13 / 20(65%):P10 0 / 3、P12 0 / 3 —
规则问题误报 0 3(都是「没填的地方」) 0

读法:开发集上的分数有相当一部分是调出来的。 留出集召回比开发集低 20 个点,致命级低 22 个点,这更接近真实水平(留出集也仍是同一个生成器写的虚构文件,真实文件还要看国动)。具体失效在哪里:

  1. 响应方式识别过度触发(影响最大):response_mode 的「逐条响应」写法里有「逐一」,S03 声明函的填写说明「逐一、准确填写产品名称……」被认成要求逐条响应,和「未列入偏离的视为接受」冲突,按 C12 冲突就按逐条处理,1028 条技术参数在规矩的投标文件上全部报了提示级「未找到响应」。产品里响应方式是人工确认点,清单页会显示识别出的方式和依据原文(这条依据一看就不对),人工改成「只列偏离」后 S03-B 降到 45 个提示。要修:识别「逐条响应」要求限定在偏离表、响应表的说明里,声明函填写说明不算;冲突时在清单页上提醒确认。
  2. 偏离栏直读只认开发集的写法:留出集偏离栏写「不完全一致 / 与要求有出入 / 接近要求」,不在「偏离 / 负偏离 / 部分满足」这组词里,模型也没读出来。D06 92% → 25%。要修:偏离栏的取值按「是否完全一致」判断(「无偏离 / 完全响应 / 满足」以外的非空值都请人核对),不靠枚举不满足的说法。
  3. 附加条件、另报价的写法枚举(事先就判断最需要留出集检验):「以双方另行签订的服务协议约定为准」「保留调整报价的权利」「备选配置总价」「如同意延长交货期,可将总报价调整为……」「愿以 × 元作为最终让利价格」(金额在关键词前面)都没认出。要修:这两类改成「投标函、报价相关章节里出现第二个总价金额」「报价、付款、交货条款里出现保留 / 另行 / 调整」这种结构化判断,再配措辞;或者交给模型判断一次。
  4. 空白栏规则:技术要求里的「精确到年月日」被当成没填的日期,误报 3 次。要修:「年月日」前后是「精确到 / 格式 / 显示」这类说明性字样时不算。
  5. PDF 字形:渲染出的文字层把「户」读成「戶」(康熙部首 / 兼容字),回填位置时定位不到;真实文件里招标侧和投标侧字形不一致时检索和引文核对都会受影响。要修:文字层做兼容字归一(读标的 _char 已经处理了一部分部首,要补全)。

这些修完以后,留出集已经测不出修复效果(看过了),报告里的留出集数字以本节为准。国动真实投标文件仍然用冻结代码跑一次,之后再修。

12. 修留出集暴露的 5 处(2026-11-04,用户决定先修再跑真实文件,决策 E2)

规则集 2026.11-r3。

  1. 响应方式识别(checklist/response_mode.py):「逐条响应」那句话要说的是要求、条款、参数、偏离、采购需求,声明函填写说明里的「逐一、准确填写……」(10 份招标文件里 7 份都有这句套话)不算;「默认接受」的写法里,「视为」后面紧跟「无效 / 不 / 未 / 非」的(「否则视为无效响应」)是不响应的后果,不算。10 份招标文件的识别结果和档案一致(S03 → 默认接受,S09 → 逐条),S05 商务仍是「没写明」(原文确实没写)。
  2. 偏离栏按「是不是明确满足」判断(check/deviation.py):按表头认出偏离栏和响应情况栏,两栏合起来判断——任一栏明确写了不满足(短的一段里有「负偏离 / 部分响应 / 不满足」,长的一段开头就是这些)就是负偏离;偏离栏写的不是「无偏离 / 满足 / 符合」的其他短写法(「不完全一致 / 接近要求 / 基本一致」)请人核对,级别最高到重要;「响应情况」栏写的常是响应内容(「支持」「3 年」),只认明确的不满足。窄栏折成两段的「无偏」「离」合起来认。认不出表头时退回原来的整行明确写法。响应表规则用同一套判断,表体序号认「技-86」「C-3」「(一)」这类写法(原来只认纯数字,风格 B / C 的表整张被跳过)。
  3. 另报价、附加条件按结构判断(check/rules.py):另报价看「报价字样或备选 / 优惠 / 让利 / 如……调整为,加上一个和投标总价不同、不低于总价三成的金额」(金额在前在后都算),「备选 / 替代 / 方案二 / 第二套」致命,其余重要;业绩合同金额、限价、保证金不算。附加条件补「保留……权利」「另行签订」「以另行 / 实际 / 届时……为准」「调整报价」「价格波动」,商务语境补「交付 / 供货 / 服务期 / 售后 / 协议」,「不以任何理由……」算承诺。
  4. 空白栏:「精确到 / 格式为 / 显示」后面的「年月日」、后面跟「时」的不算没填。
  5. 异体字:比对时把「戶 / 戸 → 户」这类异体码位和 CJK 兼容汉字折叠(text_layer.norm、检索分词),原文照存。

每处都有开发集、留出集以外写法的单元测试;中间一版偏离栏判断把「投标响应」栏的响应内容和折行碎片当成了要核对的值,开发集上冒出几十个误报,改成两栏分开判断、按段判断后回落。

指标 开发集 修前 → 修后 留出集 冻结代码 → 修后(已看过,仅参考)
查标召回 111 / 149(74%)→ 112(75%) 40 / 74(54%)→ 51(69%)
致命级召回 25 / 32 → 25 / 32 23 / 41 → 26 / 41
D06 负偏离未说明 92% → 93% 25% → 80%
规矩的投标文件报出的问题 239 → 239 1134 → 82
规则问题查出 57 / 57 → 57 / 57 13 / 20 → 19 / 20
规则问题误报 0 → 4(规矩的投标文件上 1,都是「没读到响应情况」的重要级提示) 3 → 0

留出集的正式成绩仍以 §11(冻结代码)为准:修的时候看过留出集的漏报,修后的数字有过拟合成分。

13. 资质匹配(查标第 4 步,2026-11-04)

规则集 2026.11-r4,方案 qualification-plan.md(决策 QL1–QL7)。只改规则,开发集上的模型结论全部走缓存。

1. 开发集不退化:17 份投标文件(空资质库)的全部指标和 §12 修后一致:召回 112 / 149(75%)、致命级 25 / 32、规矩的投标文件报出问题 239、规则问题 57 / 57。资质问题 0 个:开发集的证书全在扫描件页上,空资质库什么都不报(QL3)。

2. 类别识别(S01–S10 读标结果里资格条件、评分项中带「证书 / 资质 / 认证」的条目):认出类别 14 条,产品证书、人员证书排除 9 条(节能 / 环境标志产品认证、项目经理和技术人员资质),没认出 2 条(S03「认证证书(3 分)」、S05「数据库兼容证书」,都是产品类,正确地不判)。营业执照、法人证书、联合体规则不算资质要求。读标留出集的 S03、S06、S09 里没有可核对有效期和等级的企业资质。

3. 模拟资质库的噪音(开发集 17 份,run_check.py --library):

资质库 资质问题 说明
空 0
每类一条、有效、等级最高 4 个提示 都是 S01 的「CCRC 服务类别」:要求写了「安全集成」,模拟记录的名称里没写
只有 ISO 9001 16 个重要 S01 两份的资格条件和评分项「资质库里没有这类资质」,每份 8 个(含同一要求抽成两条的重复,一条评分项里两类证书各一个)
每类一条、2020 年过期 29 个重要 S01(每份 8)、S04(每份 3 类 ISO)、S07(每份 ITSS、CS 两类)「按资质库记录已过期」

真实用户的资质库介于「全有效」和「缺几类」之间:规矩的投标文件上,资质库录全了几乎不出问题;录了一部分时,没录的那几类在扫描件条目上会出「未覆盖」(重要)。

4. 派生的资质情况表(evals/check/qual_defects.py):在 S01-B、S04-B、S07-B 的资格证明一章开头插一张文字的「企业资质情况表」(虚构证书,写法故意和词表别名不完全一样),q00 全部有效、q01 注入 D12(有效期早于截止日)和 D18(等级低一级)。

指标 结果
D12 有效期早于截止日 3 / 3(S01 资格条件致命,S04、S07 评分项重要)
D18 等级低于要求 2 / 2
q00 规矩的资质表上的资质问题 0(空资质库、全有效资质库都是 0)

调试中修的两处:一条评分项写了两类证书时合成一个问题,规则编号只能取一个(S07 的 CS2 被 ITSS 过期吞掉)→ 改为一类证书一个问题;证书编号「CS3-3201-…」排在等级栏前面,整行读成了 CS3 → 先看短的等级格。同一要求在清单里抽成两条时各报一个,评分按「同规则 + 同出处」算一个。

插表以后,响应匹配的候选句变了,13 + 8 + 12 次模型调用没有命中缓存:S01 有 5 条扫描件兜底的「请人工核对」因为文字表里能找到而消失(应当如此);S07 有 3 条条目的结论变了(1 条新的「请人工核对」、1 条从「请人工核对」变成「疑似不满足」、1 条新的「疑似不满足」),是模型看到资质表后的判断,没有逐条复核。

局限:资质情况表和词表是同一个人对着同一批样本写的,分数说明不了泛化;真实投标文件的资质表写法、扫描件比例都没测。国动真实投标文件到了以后,请用户按公司的真实证书录资质库再跑一次(qualification-plan.md §5)。

14. 下一步

  1. 分项报价表和采购需求清单逐项对照(P13)暂缓:在开发集 7 份招标文件上试读「名称 + 数量」的采购清单表,S02、S08(服务类)没有这种表;S04 把「是否进口」一栏读成了名称;S10 采购包 2 的表跨页、第二页没有表头,漏了大半;S01 9 行里能和投标文件的分项对上名称的只有 7 行。P13 是致命级,按这个抽取质量在真实文件上会大量误报「缺项」,评测集里也没有注入过,先不上,覆盖范围里照写「还没有上线」。散文写法的单价上限同样暂缓。
  2. 第 3 步冻结前:确认各项改动的单元测试都有开发集以外的反例;冻结后跑留出集(S03、S06、S09,风格 B + C)和国动真实投标文件,各一次。
  3. 第 3 步:D09(响应对象错位)、D06(负偏离未说明)的提示词 v3,token 预算、复查复用、重复条目分组。
  4. 留出集(S03、S06、S09,风格 B + C,封存的词库)和真实国动投标文件,在第 3 步冻结代码后只跑一次。