每一组一个新库。 这条规则是整个目录存在的理由。
此前连着三轮在同一个库上调检索,而那个库带着前几轮的改类结果——容易的实体早已
精化,拒绝理由里直接写着 already correctly typed as pharmacy。后两轮的数字跟
第一轮根本不可比,却被当成依据改了两次代码。复用一个库省下的几分钟,换来的是
一整段无效的结论。
node scripts/bench/run.mjs --corpus pharma --label seeds-only
node scripts/bench/run.mjs --corpus pharma --ontology /tmp/schemaorg.ttl --label schemaorg
前置:utopia-server 已启动、连着一个能写的库、工作区配好了对话与嵌入模型。
环境变量见 run.mjs 头部。
corpora/*.json—— 固定语料。实体跨文档反复出现是刻意的:单篇语料里每个 实体只有一两条事实,画像基本只剩名字,量不出消解的真实水平。truth/*.json—— 每个实体期望落到哪个类。key 是名字的一个足以认出它的片段 (抽取给的名字每次略有出入,全等匹配会把这种变化算成失败);值是可接受的类, 任一命中算对。空数组 = 本体里没有对得上的类,此时正确行为是不动它。truth/*.wikidata.json—— 不经人手的答案卷(0016 的 C1):维基百科语料里每个 实体在 Wikidata 上的 P31(instance of),经p31-to-classes.json映射到 schema.org 包的类。*.wikidata.raw.json是抓下来的原始材料(QID、P31、类落在哪些锚下), 可重抓、可 diff;答案卷由它生成,不要手改——改映射或重抓。p31-to-classes.json—— 人的判断只进这一张表:Wikidata 的锚类(人、企业、软件、 城市……)→ 本体里可接受的类。空数组沿用上面的语义(正确行为是不动它); 一个锚都落不到的实体不写进答案卷,不知道就不猜。run.mjs—— 一组:新建库 → 灌语料 → 可选导入本体 → 跑消解 → 打分。--truth <file>换一份答案卷:同一组结果对手填答案与 Wikidata 答案各打一次分。fetch-wikidata-truth.mjs—— 抓 Wikidata 答案的原始材料:条目主题与正文里出现过的 链接条目(导航框里的几百个不算)的 QID 与 P31,P31 类顺着 P279 归到锚类。make-truth.mjs—— 原始材料 + 映射表 →truth/<corpus>.wikidata.json。fetch-ai-timeline.mjs—— 抓条目的当前版(prop=extracts)。fetch-wiki-history.mjs—— 抓历史快照(action=parse&oldid)。演认知时间靠它: 同一条目的多张快照按doc_time灌进去,图会真的改主意。subset-corpus.mjs—— 从一份语料里挑几个条目做成新语料。整条目取, 因为supersedes只在同一条目的相邻快照之间发生,随机抽块会把时态那根轴废掉。subset.mjs—— 把 schema.org 的 TTL 切成前 N 个类,给退化曲线用。recall.mjs/fetch-sec-filings.mjs/truth/nvda-public-docs.json—— 召回的台子: 文档里该有的东西进图了没有(见下面「召回的测量台」)。
recall.mjs 量的是另一件事:这篇文档里该有的东西,进图了没有。
run.mjs 问「实体归到哪个类」,temporal.mjs 问「两根轴答得对不对」,
这一个问「金额、容量、期限、票数、职务丢了多少」。
判据是人读原文列出来的一张表(truth/nvda-public-docs.json,52 条),
不是 extraction_drops / ontology_misses 那两张信号表——它们只看得见
「抽出来了没落地」,看不见「根本没抽」,而后者是大头:一份 8-K 的收购价、
留任池、交割时点全都不在图里的时候,那两张表是空的。
语料是四份真实 SEC 文件(fetch-sec-filings.mjs 抓,不入库存),各压一类形态:
收购公告(一句话三个数)、多方新闻稿(七方、四位高管带职务)、财报新闻稿
(行列关系全在表格里)、投票结果(二十一张无表头的表,十位董事各四类票数)。
node scripts/bench/fetch-sec-filings.mjs # 一次就够
node scripts/bench/recall.mjs --kb <id> # 一轮:清空 → 重抽 → 打分
node scripts/bench/recall.mjs --kb <id> --score # 只打分
node scripts/bench/recall.mjs --kb <id> --reprocess # 改了解析器:连分块一起重来
node scripts/bench/judge_open.mjs --kb <id> --sample 200 # 开放陈述有多少不是原文说的(门槛 2%)
量「后面的分块看不到前面的分块认下了什么」对输出的影响(#588,分块并发调模型之前要知道的数):
服务端带 UTOPIA_EXTRACT_KNOWN_IN_PROMPT=false 起,照常跑 recall.mjs,与不带时的几轮比。
这个开关只动提示词,落库时按名字认回前面分块的实体照旧。
# 服务端照常起:每轮记一份
node scripts/bench/recall.mjs --kb <id> --known shown --out runs/588
# 服务端带 UTOPIA_EXTRACT_KNOWN_IN_PROMPT=false 重起:同样几轮
node scripts/bench/recall.mjs --kb <id> --known empty --out runs/588
# 按 known 分组排表
node scripts/bench/recall.mjs --table runs/588
--known 只是标签,台子查不到服务端的开关,两边对不上那一轮就作废。每轮除了总分还记每篇的
分块、事实、实体、跨块认回(一个实体出现在这篇两个以上分块的事实里)、排给裁决的对(这一轮进了
resolution_reviews 的疑似同一对,#877;提示词里没有 known 时同一个东西换个写法再列一遍,落在这里而不是静默合并。
不分召回通道:一对裁过之后 reason 被裁决改写,name_vector| 留不下来。全库总数另按待裁 / 合并 / 分开和现在的
reason 前缀记;只算这一轮排队之后排的对,--score 没有排队时刻,算的是库里现有的——每轮开头删实体时它们随之删掉)、丢弃账(extraction_drops
按原因)和排队到最后一块抽完的秒数。抽完之后还要等对齐、治理、时间消解、裁决这些任务收尾(它们还在补事实、裁对子),
等到没有该跑的任务才打分,不然每轮记的是抽完那一刻的快照;等了多久记成 settleSeconds,卡住十五分钟没收尾的轮次
--table 会单独点名。没抽完的轮次(端点整段不可用时抽取任务一个个失败、队列就空了,收尾等待立刻满足)记下来但
complete: false,--table 不把它算进任何一组,只在表下点名——它的分说的是端点那天的状态,不是这一轮的配置。
--table 给每组的均值 ± 标准差,再给事实集合(去重的主/谓/宾)
的重合度:组内两两比是运行间的抖动,跨组两两比是 known 的影响——跨组落在组内的范围里,空 known 就没把
输出挪出方差。
抽取写的是开放图谱(0044 决定 2,没有带本体的第二条路):陈述按原文短语落成 layer='open' 的
事实行,限定挂在 statement_qualifiers,时间词进 time_mentions;打分口径照旧(谓词取
proposed_predicate,限定也拼进那一行),所以下表里带本体那些轮次的分数仍然可比。judge_open.mjs 是
反面的尺子:抽样让一个裁判模型读原文判 stated / misworded / not_stated;裁判端点用
BENCH_JUDGE_BASE / BENCH_JUDGE_KEY / BENCH_JUDGE_MODEL,不给就用工作区的对话模型
(和抽取同一个模型,数字要打折看)。
--kb 要一个装了本体包、向量已补齐的库:装一次 schema.org 要嵌 2500 条向量、
二十分钟,而这个台子量的不是本体。库里除了本体没有跨轮状态——事实、实体、信号
每轮都清空,自动扩本体上一轮长出来的关系也删掉(留着就进下一轮的提示词)。
52 个条目、九成命中率,一个标准差 ≈ 2.7 条。 单轮差一两条不是证据;
同一份代码重跑一遍再说。结构性的改善要看别的:object_missing 的计数、
某一类(比如「四位高管的职务」)是不是整类进来了。
2026-09-09 那一轮(dev @ cb2bab7 + 九处修改,DeepSeek-V3.2 + bge-m3):
| 轮次 | 改了什么 | 分数 |
|---|---|---|
| 基线 | — | 33/52 |
| r1 | 字面值通道放行 | 29/52 ← 回归 |
| r2 | +表格保住行列 +关系地板 +主语兜底 | 44/52 |
| r3 | +角色规则 +空列裁剪 | 43/52 |
| r4 | +空表头让位 | 44/52 |
| r5 | +名单是名单 | 49/52 |
| r6 | 代码一字不改,重跑 | 49/52 |
r5 与 r6 漏的不是同一批(交集为空),剩下的是抽样噪声。 r1 那次回归最值钱:放开字面值之后,主语解析比关系通道严,一轮丢掉 113 条—— 这个 bug 只有在放开字面值之后才暴露得出来。
govern.mjs 量的是 agent 替人裁重复项裁得对不对、还剩多少等人。真值在
truth/ai-timeline.duplicates.json:把八篇互相咬合的条目(OpenAI 那场风波、Anthropic、
DeepMind、Mistral、Inflection、SSI、ChatGPT)灌进一个治理开着的新库,消解器提出的
615 对、411 个名字对,2026-09-07 按两侧的事实与原文逐对手标:same 同一个东西;
different 两个东西,含版本、部门、子公司、只是含着这个名字的一句话;unknown 一侧
没有事实、名字本身定不了的(光秃秃的「judge」「Time」),人也定不了。按两个名字键
(不分左右、不分大小写);同名的一对只有在那次导入里每一对都同一个答案时才带标签。
node scripts/bench/govern.mjs --fresh # 新库、灌语料、跑完打分(约一小时)
node scripts/bench/govern.mjs --kb <id> # 已有的库:撤掉 agent 的决定、再跑、打分(约二十分钟)
node scripts/bench/govern.mjs --kb <id> --score # 只打分
node scripts/bench/govern.mjs --kb <id> --score --stuck # 连留给人的那些一起列出来
--kb 那条路不重新抽取:--reset 用 revert_merge 同一套还原把 agent(和模拟的人)做的
合并撤掉、分开的重开、建议删掉,直接在库里做而不经 API——经 API 会在台账上留下
merge.revert,下一轮 agent 会把它当成人的先例。所以改一次判断、二十分钟出一次数。
读数:decided_on_its_own 是它自己裁的;agreed_with_labels 是其中与标注一致的;
wrong_merges 是最要紧的那个数——合错了要人去撤;left_for_people 是留给人的建议,
后面跟着按标注人会合几对、分几对;unlabeled 是这次导入抽出来、真值里没有的名字对,
不算对也不算错。语料重抽一次名字会略有出入,那一栏不为零是正常的。
同一份语料上的对照(2026-09-06,闸门还是「没先例不合」那版):治理关着老裁决器自动合 146、留 50 给人;治理开着一对不合、留 200。这个数就是记录 0025 决定 4 修订的起因。
mappings.mjs 量的是探索从数据库 schema 提议的口径,对不对、漏了多少。
node scripts/bench/mappings.mjs --fresh # 新库 → 挂源 → 探索 → 打分
node scripts/bench/mappings.mjs --fresh --no-comments # 同上,语料不带列注释
node scripts/bench/mappings.mjs --kb <id> --score # 只打分,不动库
打分不看名字,看数。 治理那边真值按两个名字键,因为它判的是二分类;这里概念名 是模型自己起的,「Revenue」与「已支付 GMV」按名字对不上任何一条。所以真值一条是 「一个业务口径 + 一条 gold SQL」,打分把提议真跑一遍,跟 gold 的结果比数——数一样 就是同一个口径。省掉逐条手标,判据还是客观的。
四栏分开读:covered 是真值里被算出来的有几条(漏没漏);right 是提议里跑得通
且对上某条真值的;wrong 是跑得通但一条都对不上的,附它算出的数与最接近的真值;
broken 是跑不通的。要看的是 wrong。 跑不通的提议无害,它失败得很响,人一眼
看得见;跑得通而算错的才是全部风险——问数会拿它印出一个看起来完全正常的数字。这一栏
也是 #504 能不能默认开的唯一依据。
traps_hit 数的是落到陷阱列上的提议:整数外键求和、o_shippriority 这种恒为 0 的列、
把一段自由文本当维度。它们都跑得通。
语料在 schemas/<corpus>.sql,真值在 truth/<corpus>.mappings.json。
- 口径不是我们定的。 TPC-H 的 22 条查询里写死了「收入」在这个 schema 上就是
sum(l_extendedprice * (1 - l_discount)),真值从那儿抄。自己拟一份口径来量自己的 探索,量出来的是自我一致。 - 行是
generate_series造的,不按 TPC 的生成规范。 探索只读 schema 不读数据, 打分时 gold 与提议跑在同一批行上,比的是两个数一不一样——那份规范值钱的是 schema 与查询,不是它的数据分布。setseed固定,两轮之间语料不变。 - 列注释单独一个文件,因为它是一个自变量。 真 TPC-H 一条注释都没有,而真实库里 注释是探索最主要的线索(提示词专门要求 citing column comments)。加载与不加载各跑 一轮,两个分数之差就是注释值多少分。注释只描述列,不描述口径——写「折后收入 = extendedprice × (1 - discount)」等于把 gold SQL 抄给模型。
- 每一组一个新库在这里还多一层理由:
propose的ON CONFLICT … WHERE status = 'proposed'让第二轮探索继承第一轮的行,同一个库上跑两次,第二次的分不是第二次的。
ask.mjs 量的是端到端:人问一句话,拿回来的数对不对。
node scripts/bench/ask.mjs --kb <id> # 跑全部问题
node scripts/bench/ask.mjs --kb <id> --only disc_revenue
node scripts/bench/ask.mjs --kb <id> --seed # 先把真值写成确认口径(上界)
node scripts/bench/ask.mjs --kb <id> --confirm # 先确认探索提的那些(产品路径)
node scripts/bench/ask.mjs --kb <id> --replay # 不重问,拿库里上一轮的回答重判
node scripts/bench/ask.mjs --kb <id> --parallel 4 # 同时问四题:一题 2–6 个模型回合、串行半小时
node scripts/bench/ask.mjs --kb <id> --conventions # 先把真值里的 conventions 写进库(#570)
node scripts/bench/ask.mjs --kb <id> --recall 8 # 只量检索:那条对的口径在不在前 8(#574),几秒
口径是按问题挑的,不是全塞(#574):--recall K 不问,只看检索前 K 条里有没有那条对的
口径——答案卷就是 mapped 那一步按数对上的行。要撑爆老的 30 上限,用
mappings.mjs --fresh --corpus wide --also tpch 把两个源挂进同一个库,再各 seed 一份真值
(45 条)。量过:seed 的说明是占位符时 wide recall@8 13/18、问数 15/18;说明换成真的
(真值里的 summary,用提问的语言)之后 recall 18/18、问数 18/18;tpch 两次都是 23/24 与
24/24。嵌进去的那句说明就是检索的全部,reranker 目前没有它该修的漏。
mappings.mjs --fresh --conventions 同理,只是写在探索之前——探索的提示词也读它。wide 上
量过的阶梯(chat right):什么都没有 2/18;探索生成的描述 2/18;描述 + 六条约定 11/18;
约定 + 十八条口径写成一页散文靠检索 14/18;二十七条确认口径进 prompt 17/18。探索覆盖:
没有约定 0/18,有约定 3/18——错的那几条也都带上了 is_test != 1,差在选错列。
与 mappings.mjs 量的不是一回事,一个也推不出另一个。 口径确认得再准,
答案照样可能错——模型会挑错源、join 错、按错的日期列过滤,或者压根不看语义层,
照着 schema 文档自己写 SQL。反过来,一个一条确认映射都没有的库照样答得出问题,
而且有时是对的。
判分材料只有两样,因为 query_data 记得很少(step 里只有源名与用途):助手最后
那段话,以及 tool_exchange 里模型真正跑过的 SQL。后者是有用的那个——
把它跑过的 SQL 重跑一遍,跟 gold 比数。SQL 很短,逃得过 tool_exchange 的截断,
而它的输出逃不过。
于是两栏而不是一栏:sql_right 是它跑的那条算的就是问题问的数,answer_right
是它印出来的数就是那个数。两者会分家——查对了却把单位说错、四舍五入错、
或者转述成另一个数字,在只看 SQL 的分里是对的,而人读到的答案是错的。判等用
lib.mjs 的 roughly(比 same 松两个量级):模型说「约 8.63 亿」与
862793473.48 是同一个答案,判成错的话,量的就不是问数准不准,是模型肯不肯把
小数点后八位抄全。
问题在 truth/tpch.questions.json,按口径的 id 键,与 tpch.mappings.json
共用 gold SQL。这不只是省事:一道题答错时,脚本据此说得出它需要的那条口径有没有
确认映射——mapped / UNMAPPED。闭环就在这一句上:
- 跑一轮,看哪些错;
- 错的题里,口径没配映射的 → 覆盖率的问题,去探索或手写;
- 配了还错的 → 提示词、工具或口径本身的问题;
- 再跑。
mapped_definitions 这一栏满了,「映射全」就有了确定的意思,剩下的错都不再是
覆盖率的事。
lib.mjs 是两个测量台共用的地基——判等必须是同一份,各写一份 same()
迟早漂移,而一旦漂移,「提议对了几条」与「答案对了几条」就不是同一把尺子量出来的。
SQL 的空字段(psql 默认显示的 NULL、空字符串)与纯空白不参与数值判等,不能当成 0。
firstRow() 仍取第一行各列的数;value() 只读第一列,第一列为空就返回空,不取后面的数。
回归测试不需要模型服务;第二条额外验证真实 PostgreSQL 的输出,只执行 SELECT:
node --test scripts/bench/lib.test.mjs
BENCH_TEST_PSQL="psql -X -h 127.0.0.1 -p 1517 -U utopia -tAc" BENCH_TEST_DB=utopia PGPASSWORD=utopia \
node --test scripts/bench/lib.pg.test.mjscompetency.mjs 把一个库接受了的能力问题按人在 chat 里问的方式问一遍(走 /kbs/{id}/chat,
不另造引擎),判答没答上,把结果写回问题(last_result),再读服务端算的两个数:
BENCH_BASE=http://127.0.0.1:1524 BENCH_PSQL="docker exec ... -d utopia_bench4 -tAc" \
BENCH_JUDGE_BASE=... BENCH_JUDGE_KEY=... BENCH_JUDGE_MODEL=... \
node scripts/bench/competency.mjs --kb <kb-id> --seed scripts/bench/truth/redocred-typed.questions.json
- 有期望答案的问题交给裁判模型判"回答里说了期望答案没有";没有的只查它需要的形状
(
needs里的类与属性)是否都在、属性是否有类型化事实。后者弱得多——一条开放图谱就能答的问题 不需要本体,这是 0061 的开放问题。 - 回答经没经过图谱也记下来(
via:graph / text / both / none,看 chat 的 step 事件里 facts、neighbors、 timeline、path 这些图谱工具有没有拿到事实,search、document 有没有读正文)。报告里"答上"之外另给 "经过图谱"和"只靠图谱"两个数:只靠正文答上的不需要本体,这个数才是本体自己的。 - 第二个数从
ontology_proposals算:代理提的里人表过态的,有几条被拒或改过再采纳。 --seed把写好的问题灌进库(同一句跳过),--only-report只读数不问。truth/redocred-typed.questions.json是给typed.mjs那份 100 篇 Re-DocRED 库写的十一条:十条有期望答案 (其中两条要代理采纳过的bordered_by、p40才答得上),一条只有形状。换一个库要另写。
agent.mjs 在同一个库状态、同一批形状上各臂跑一轮:每臂开跑前把代理没采纳的提案和看过的形状记录删掉
(所以只在测量库上用,要显式给 --reset),从服务端日志读失败批次、坏项及原因、token,再让裁判拿着
全词表判每条新提案是不是已有元素的重复或反向,判每条「已有」答案对不对、方向对不对。
POST /ontology/propose 的 glossary: full 是给全词表那一臂用的旋钮,产品路径不开。
BENCH_BASE=http://127.0.0.1:1524 BENCH_PSQL="docker exec ... -d utopia_bench4 -tAc" \
BENCH_SERVER_LOG=/path/to/server.log BENCH_JUDGE_BASE=... BENCH_JUDGE_KEY=... BENCH_JUDGE_MODEL=... \
node scripts/bench/agent.mjs --kb <kb-id> --db utopia_bench4 --reset --arms trimmed,full,trimmed,full
2026-09-27,bench4(100 篇 Re-DocRED,98 条属性),gemini-3.5-flash,每轮 120 条形状 + 69 个类别词、12 次调用:
| 全词表 | 按结构裁(#963) | 按结构裁 + 意思最近 5 条 | |
|---|---|---|---|
| 轮数 | 4 | 7 | 4 |
| 失败批次 | 0 / 48 | 0 / 84 | 0 / 48 |
| 提示 token / 次 | 7.1k | 4.3k | 5.0k |
| 一轮 token | 111k | 78k | 87k |
| 新元素提案 | 135 | 292 | 178 |
| 其中重复或反向已有属性 | 1(0.7%) | 18(6.2%) | 6(3.4%) |
| 「已有」答案判对 | 44 / 65(68%) | 60 / 85(71%) | 44 / 56(79%) |
- 裁词表不让调用失败,也不让模型提已存在的键;让它重提定义被裁掉的属性。按结构裁时重的集中在 positionHeld、workLocation、performer、awardReceived:形状一端没类型或宾语是字面值,结构上对不上, 定义就没送。再按意思带上最近的 5 条,重复降了一半,多花 0.7k token 一次。
- 每轮固定出现的十来个坏项是"existing 条目没有形状",两臂都有,数目等于库里的问题数:模型把"这条属性 服务某个问题"写进了 existing。解析时丢掉,无害;提示词里已补一句。
- 同一臂两轮之间的差别比两臂之间大:同样的输入、温度 0,两轮只有一半提案键相同。单轮对比说明不了 质量,至少四轮合起来看。
- 提案旁边显示的"最近的已有元素"(按向量取两条)只罩住了被判重复的 16 条里的 6 条,是给人看的线索, 不是防线。
timewords.mjs 把 truth/timewords.json 里七篇写好的文档(五篇中文、两篇英文,39 句)各传进一个新库,
抽取、解析之后逐句对:这句话抽出来没有、它的时间说法记成时间词没有、起点落在期望的区间里没有、
没写时间的句子有没有被硬给一个起点、「截至」对不对,以及几遍之间每句话的结果一不一样。每一遍建一个
新库,不删任何东西。
BENCH_BASE=http://127.0.0.1:1524 BENCH_PSQL="docker exec ... -d utopia_bench4 -tAc" \
BENCH_SERVER_LOG=/path/to/server.log node scripts/bench/timewords.mjs --db utopia_bench4 --runs 3
句子按种类分:absolute(写明的日期)、relative_now(相对文本说话的那一刻:三个月后、上周、today)、
relative_event(相对一件有日期的事:上市半年后)、relative_undated_event(相对一件没日期的事,期望
不写起点)、section(时间在节标题上)、none(没写时间,期望没有起点,「截至」来自上下文)。
语料里有三篇是为了跨块写的:发出比开会晚一个月的会议纪要(起算点选错看得出来)、两份周报汇编成的
一篇(每一节有自己的提报日期)、季度写在节标题上而且离开头很远的年度回顾。
2026-09-28,gemini-3.5-flash,各三遍(三遍的数用 / 隔开):
| dev(第 2 刀之前) | 0064 第 2 刀 | 0064 第 3 刀 | |
|---|---|---|---|
| 句子抽到了(39) | 36 / 36 / 39 | 37 / 38 / 37 | 39 / 36 / 34 |
| 时间说法记成了时间词(29) | 18 / 19 / 20 | 28 / 29 / 27 | 29 / 27 / 25 |
| 起点对:写明的(4) | 4 / 4 / 4 | 3 / 4 / 4 | 4 / 3 / 3 |
| 起点对:相对此刻(15) | 9 / 9 / 9 | 14 / 15 / 13 | 14 / 12 / 11 |
| 起点对:相对有日期的事(3) | 3 / 3 / 3 | 3 / 3 / 3 | 3 / 3 / 3 |
| 起点对:节标题上的时间(6) | 0 / 0 / 0 | 6 / 6 / 6 | 6 / 6 / 6 |
| 没写时间的没被给起点 | 10/10 ×3 | 9/9、9/9、10/10 | 10/10、9/9、9/9 |
| 「截至」对(10) | 0 / 0 / 0 | 0 / 0 / 0 | 10 / 9 / 9 |
| 每块 token | 6,490 / 5,744 / 7,306 | 6,142 / 7,204 / 8,470 | 6,963 / 6,621 / 7,682 |
| 三遍结果一致的句子 | 34/39 | 34/39 | 33/39 |
- 之前丢的四种:计划类的句子时间词进了宾语(「码表二代 — 发布 → 将在三个月后」);「上周」记下了但
解释被当成坏条目丢掉(模型照字报粒度 week,阶梯上没有这一档);汇编里第二份周报的「上周」从第一份的
提报日期起算;节标题上的季度到不了它下面的句子。第 2 刀之后剩下的错几乎都是那句话整句没抽到
(
?),是抽取本身的波动,不是时间。 - 「截至」一栏第 3 刀才动:之前没写时间的陈述拿到的是处理文档的那一刻;第 3 刀之后是它所在那一节里 文本说话的那一刻(会议纪要是开会那天,不是发出那天),没对上的那一条是那句话整句没抽到。
- gemini 的渠道当天下午下线,换 claude-haiku-4-5 把 dev 与第 2、3 刀各重跑三遍(提示词已压短): 时间说法记成时间词 12–13/29 对 23–25;起点对,相对此刻 6/15 对 11–13,节标题上 0/6 对 4–6; 「截至」0/10 对 9–10;每块 token 7.2k–7.4k 对 7.6k–8.8k。模型换了,前后的差距没变。
- 第 3 刀没动抽取,三遍之间「句子抽到了」从 39 掉到 34 是抽取本身的波动:同一份代码、同一份文档。 这张表上凡是跟着「抽到了」一起动的数(时间词、起点)都要这样读。
- 每块 token 多了一成上下:提示词多了两段规则、回复多了
t,少了事后读开头的那一次调用。
prompt_tokens_est是本体段的估算,不是整个提示词。实测 4.0 字符 ≈ 1 token (377,735↔81,855、396,716↔99,041)。真实 token 数在 LLM 客户端里,穿出来要改 一路签名;这里要量的是"本体规模",比例稳定就够用。for_review按没改算进 miss。它确实还没改——算成命中就是把人的活记在机器账上。absent= 标准答案里有、但抽取压根没抽出这个实体。它不是消解的错,单独一栏。- 命中 = 可接受类或它的子类(按库里的类层级算)。答案卷给的是锚(organization、 place),引擎答的常常更具体(research_organization、city)——精化正是要它做的事。
- 手填的答案卷按子串匹配名字,生成的(
match: "exact")按全名精确匹配。 score.tiers:分档打分。auto是自动落地那一档对答案卷的命中,review是待人工那一档 若盲目照收会怎样——放不放开自动跑看的是前者。
第一次跑就写窄了一个:心血管健康论坛 只写了 business_event|event_series,
而系统给的 conference_event 是对的。答案错了要改答案——但要在结果出来之后
才改、且写清楚为什么,否则这份答案就变成了"系统这次答了什么"的记录,量不出任何东西。
两个文件:corpora/x.json 与 truth/x.json。语料换行业是有意的——同一套判断在
两个领域上都成立,才谈得上不是过拟合到某一批词上。
有人在 discussion #298 问"能不能用 GLiNER 代替 LLM 做实体抽取"。量了一次,四套语料、 四种设置,结论和数字都在这里,下次再问直接给链接。
- 我们这边:schema-org 包(965 类),每套语料一个新库,DeepSeek-V3.2 抽取。"抽取时"是
抽取一轮的类型,"跑完类型消解"是再跑一次
POST /kbs/{id}/ontology/type-resolution。 - GLiNER:urchade/gliner_multi-v2.1,CPU,阈值 0.3,
gliner_compare.py。中文按字切开再喂 (它按空白分词,不切的话整句是一个 token)。 - 四种标签设置:
- 只给答案里的类(二十来个)。这是它的上限,相当于提前知道答案的类空间。
- 965 类分 39 批,同一片段取各批里的最高分。这是同等难度。
- 965 类一次塞进去。看它面对整个本体时到底会怎样。
- 语料:
pharma、tech是原有的中文语料;pharma-en、tech-en是逐句对译的英文版, 答案键对应改成英文名。四份答案键的类完全一致。 - 读数:
找到= 答案里的实体有多少被抽出(片段包含匹配);类型正确的分母是找到且 答案里有类的实体,各行自己算——所以一行 11/11 只说明"找到的都判对了",不说明找得多。 两列要一起看。
| pharma 找到 | pharma 类型正确 | tech 找到 | tech 类型正确 | |
|---|---|---|---|---|
| 我们,抽取时 | 22/22 | 11/20 | 15/16 | 3/13 |
| 我们,跑完类型消解 | 22/22 | 16/20 | 15/16 | 10/13 |
| GLiNER,只给答案里的类 | 18/22 | 16/17 | 12/16 | 10/10 |
| GLiNER,965 类分批 | 20/22 | 9/19 | 13/16 | 5/11 |
| GLiNER,965 类一次塞 | 0/22 | – | 0/16 | – |
| pharma 找到 | pharma 类型正确 | tech 找到 | tech 类型正确 | |
|---|---|---|---|---|
| 我们,抽取时 | 21/22 | 17/20 | 15/16 | 9/13 |
| 我们,跑完类型消解 | 21/22 | 19/20 | 15/16 | 12/13 |
| GLiNER,只给答案里的类 | 22/22 | 17/20 | 13/16 | 11/11 |
| GLiNER,965 类分批 | 22/22 | 13/20 | 16/16 | 4/14 |
| GLiNER,965 类一次塞 | 4/22 | 2/3 | 2/16 | – |
耗时:GLiNER 给二十个标签时每套语料一秒左右;分 39 批约 40 秒;一次塞 965 个约 70 秒。 我们每套 40 到 100 秒,取决于模型端排队。
- 候选类少的时候,它判得又准又快。 二十个标签下类型精度和我们抽取时打平甚至略高, 而成本低两个数量级。
- 面对整个本体,类型精度掉到一半以下。 它认得出"这是个组织",分不清 government_organization 和 medical_organization;amlodipine 给了 product 和 substance,drug 没赢;DeepBlue 3.0 判成 drug。它靠标签名的字面相似,没有类描述,也没有上下文推理,类一多近邻就分不开。输出里 同时混进日期、碎片和"踝部→brain_structure"这类噪声,条数翻倍。
- 一次塞进全部标签,它就瞎了。 编码器窗口几百个 token,标签排在正文前,965 个标签把 窗口填满,正文被截掉,模型没看到文章。它不报错,安静地给一个几乎空的结果——这比慢 更危险。所以"直接给它整个本体"这条路在技术上不存在。
- 中文长名字它结构性地找不到。 按字切开后最大片段宽度 12 token 就是 12 个字, 浙江大学医学院附属第一医院这类名字切不出来。英文没有这个问题,两套英文语料在分批设置 下一个不漏,召回确实好。
- 我们在英文上明显强于中文(pharma 抽取时 11/20 对 17/20)。抽取提示词里的类描述是 英文,对英文原文更贴。这个差距本身值得单独记一笔。
- 以上只是实体和类型。关系、有效期、同名区分,GLiNER 不做。
不是替代,是一条候选预扫的线:把分块检索出的几十个候选类交给它打一遍,再把(片段,类型) 作为提示喂给抽取,有机会把抽取时的类型精度抬到消解后的水平、省掉一轮消解调用;它找到而 我们没找到的,直接进 drop signal 做漏抽信号。这个实验还没做。
node scripts/bench/temporal.mjs --label rc5
上面那个台子量的是类型消解。这一个量的是这个产品真正围绕着造的那件事: 按某个日期回答问题,且在事实变过之后仍答对。
在它之前,仓库能引用的数字只有 Ontology2SQL 在 BIRD Mini-Dev 上的成绩。别人家的 记忆基准(LongMemEval、DMR)测的是对话回忆,没有一个会问「2023 年三月这个项目是谁 在管」,而语料里那个答案还变过两次。在别人的基准上拿个中游名次,说明的东西还不如 把那个缺失的基准公布出来。
这是这份题目里别处没有的一维:
| 轴 | 参数 | 问的是 |
|---|---|---|
| world | at |
那时世界是什么样 |
| record | as_of |
那时我们以为世界是什么样(0019) |
同一个实体、同一个日期,两根轴的正确答案可以不同——aurora-lead-record-wave1-at-2024-08
就是这么一道:世界轴问 2024 年八月(那时李四已接手),记录轴停在我们还没读到交接
备忘的那一刻(那时只知道张三)。答成李四,就是拿今天的认知去答当时。
语料分两波灌,第一波灌完记下一个时刻(wave-1),第二波才带来交接、薪资更正与
一次文档删除。所有 as_of: "wave-1" 的题目问的就是那一刻。这样量到的是产品真实
走过的路——一次真的摄入、一次真的抽取、一次真的删除——而不是 UPDATE 出来的场面。
- 判据是「这个实体在那一刻挂着的东西里,有没有
expect,有没有not里的任何一个」, 不认谓词的名字:本体在不同库里长得不一样(works_for / employed_by),而这个台子 量的是时间,不是词汇。 expect: null表示那时不该有答案(项目还没开始、人还没入职、事实已被撤回)。 把开区间读成「自古如此」是双时态最容易犯的错,所以专门留了三道。absent(抽取压根没抽出这个实体)单独一档,不算时态答错——与上面那个台子同理。--chat再跑一遍对话:模型带着工具自己去问。账本那一路量的是账本,对话那一路 量的是 agent 那一层,两者的差就是工具用得好不好。对话判分只做一件归一:千位分隔符 (模型写 28,000,题上写 28000)。ask里的{wave-N}跑分时换成那一波灌完的时间戳。- 对话的回答看题目问的那个名字:
expect得出现,而且not里的哪一个都不在它 前面。对的回答常顺带说出前任、后任或后来改成的值——「李四管到 2025-09-01,那天 周七接手」——这不算答错(#986 的评审)。子串判分分不出的还有两样:先说对了名字、 后面又说错了别的,照样记对;expect: null的题没有先后可比,not里的名字一出现 就记错,否定句也一样——自然语言判分的已知弱点,下面单独有数。这条是 2026-09-28 改的,下面「对话那一路」的数是之前按「not里的名字一出现就记错」判的。
属性事实(薪资、职位)不是边,得从实体面板取,而那个接口今天只有 as_of,没有 at
——世界轴那一半由脚本自己按 valid_from / valid_to 过滤。图谱两个接口两根轴都在
服务端。这个不对称照实记在这里,不藏进分数里。
37 道题(两道是已知缺口,不进主分),一个虚构公司,三波文档。每一波灌完(含这一波的删除、更正、合并)记一个时刻
wave-N,记录轴上的题目以它们为界。
| 场景 | 它量的是什么 |
|---|---|
| 三任接力 A→B→C | 唯一性闭合,在同一条链上发生两次 |
| 薪资更正 28000 → 32000 | 属性事实的闭合,世界轴与记录轴各答各的 |
| 入职早于说出它的文档 | 世界轴靠文档写明的起点,不靠它到达的时间 |
| 删除一篇文档 | 撤回:记录轴倒回去看得见,今天看不见(#268 的墓碑) |
| 人改一条事实的起点(#311) | 改之后世界轴翻转;记录轴倒回改之前看得见旧区间 |
| 人合并两个拼法 "L. Si" → "Li Si"(#337) | 合并之前的世界:被并掉的实体带着自己的事实重新长回来 |
| 只知道「2024 年」入职 | 年精度:年内成立,年外不成立 |
| 「不再担任,日期不详」 | valid_to_precision = unknown——已知缺口,见 #345 |
| 「加薪由平台组批准」——没有起点的事实 | 世界轴把没有起点读成自古就有:入职前五个月问,答出 2024 年才出现的边——已知缺口,见 #352 |
| 三道答案是空的题 | 项目开始前、入职前、撤回后:把开区间读成「自古如此」是最容易犯的错 |
known_gap: true 的题目不进主分,单独一栏。它们钉住的是已知还没做对的行为,
修好那天自己翻绿;让主分一直背着一个我们已经知道的数,只会让人不再看它。
每一组都带着几条没裁的消解审核项(同名的 Meridian Systems / Project Aurora 分成了两三个 实体,宁分勿合,等人)。脚本不替人裁,题目按名字取第一个匹配的实体——这是这份数字的 一个已知噪音源,不藏。
| 配置 | 主分 | 世界轴 | 记录轴 | 已知缺口 |
|---|---|---|---|---|
| 声明了唯一性公理 | 35 / 35 | 21 / 21 | 14 / 14 | 0 / 2 |
本体自己长(--no-declare) |
28 / 35 | 15 / 21 | 13 / 14 | 1 / 2 |
本体自己长,灌完再声明、对账(--no-declare --reconcile) |
34 / 35 | 21 / 21 | 13 / 14 | 1 / 2 |
两组的差落在需要自动闭合的那几题上:三任接力(谁在管 Aurora 的四个时刻)和
薪资更正(两个时刻)。原因只有一个:自动闭合按 functional / inverse_functional
跑,而这两位永不自动推断(bootstrap_ontology.rs 写了理由)。没有声明的库里,
接任不会闭合前任——账本变成
Zhang San | leads | Project Aurora | from 2023-02-01 | (无终点) | live
Li Si | leads | Project Aurora | from 2024-07-05 | (无终点) | live
Zhou Qi | leads | Project Aurora | from 2025-09-01 | (无终点) | live
三个人同时在管一个项目。问「2025 年六月谁在管」,三个都在。新用户开箱后的库 就是这个样子,见 #341。
记录轴几乎不受影响(13/14 vs 14/14):它不依赖任何声明,只看写入时就记下的两列。 声明那一组里,合并倒回与更正倒回都是满分——#337 与 #311 两刀在真实摄入 路径上是对的,不只是在连库测试里对。
第三行是 #341 那一刀之后新用户走的路:先灌、本体自己长、然后有人接受声明。
GET /ontology/uniqueness 报出「哪条谓词的哪一端挂着两个以上开放值」,跑分脚本拿语料的
公理表当那个人——只接受语料本来就声明了的那一端——PATCH 打开它、POST reconcile 把账上
已有的行按年表对一遍。世界轴回到满分;记录轴那一题(adviser-record-wave1)与声明无关:
advises 只出现过一次,自动扩展没采纳它,那条事实从来没落过账。
全收过一次,分数反而更歪。 第一版脚本把候选全接受了——leads 的主语侧(一人只管
一个项目)、works_for 的宾语侧(一家公司只有一个员工)也被打开,李四的 Aurora 被
Helios 闭合,张三反而止于周七。候选是证据,不是判决;这正是产品把这一步留给人的原因,
bootstrap_ontology.rs 里那句「functional 永不自动」在这里被量了一次。
先等队列清空再记时刻。 文档 done 之后本体自动扩展还在另一个任务里跑:把本体没认下
的谓词建出来、把那些事实改写过去。前两次 --reconcile 报了零条候选,是因为记时刻、
算候选时 leads 这条谓词还不存在;同一个原因也让灌完的记录轴时刻落在事实之前——
之前 --no-declare 那一组的 28 与 25 之间的抖动,一部分就是它。现在每一波都等
jobs 里这个库的任务清空再记时刻。
第一版(25 题、没有更正/合并/三任接力)的数字是 25/25 对 15/25,第二版(36 题主分)
是 36/36 对 29/36,都留在 git 历史里。第三版只是把 lin-zhao-employer-2023-01 挪进
已知缺口(它的 not 里补了 Platform Group,见 #352),主分的分母跟着少一。
同一个库,同一批题,改成在 Chat 里问(--chat)。账本那一路量的是账本,这一路量的
是 agent 带着工具能不能问到。已知缺口的两题不进这个数:对话问的就是这本账,不可能
比账本答得更对。
这个数是在 #349(模型看得见字面值)与 #350(工具面有了 as_of)之后量的。 之前是
24 / 37,差的 13 题里 7 题是记录轴没法问、6 题是薪资没法看见——两处代码,两刀,都合了。
合完第一次重跑,数字纹丝不动,原因不在产品:模型写 "28,000 CNY",判分找 "28000"。
千位分隔符归一之后,薪资六题全绿。
还差的 7 题:
| 堆 | 题数 | 是什么 |
|---|---|---|
| 判分读不懂否定句 | 3 | 答案是对的:「没有记录表明李四那时与 Helios 有关」「交接备忘之前我们以为是张三,后来才改成李四」。not 里的名字出现了,子串判分记成错。要把这一路当正式数看,得换成让模型判卷——expect / not 这套词表是给账本写的 |
| 模型把工具调用当正文吐出来 | 2 | 回复里是 <|tool▁call▁begin|>function…,一次工具都没调。DeepSeek-V3 经 SiliconFlow 偶发,同一题重跑就好。计错,不遮 |
| 「…之前」的题 | 2 | 「调薪单到之前」「第三任宣布之前」——模型该去 changes 里找那一刻;一题反问用户要日期,一题把计划叙述了一遍没调工具。就算它去找,changes 只印到天,而更正与首次灌入在同一天(#351) |
记录轴 9 / 14,之前 7 / 14。模型现在会带 as_of,题目给了时间戳它就原样传(轨迹里
2 facts as recorded by 2026-09-05,回答里复述了 2026-09-05T02:43:53.382Z;轨迹那一行
只印到天,也记在 #351 里)。所以 ask 里「第几波灌完」改成了
{wave-N} 占位符,跑分时填成真实时刻:「as of the second ingest」是卷子内部的说法,
模型无从知道它是哪一刻,只会反问,那样的题量不到产品。「…之前」那类题故意不给戳,
量的是模型会不会自己去找。
同一题两次跑答案会不同(前后差 ±2 题),单次数字不要当精确值。--only a,b 只重问
几题,工具轨迹(steps)留在结果里——一题是产品没答上还是模型没问对,看轨迹比看正文快。
8/37 那个数作废过一次:第一版探针读错了 SSE 字段(.delta 而不是 .text),
每题拿到的都是空串,而空串不含 not 里的名字,八道 expect: null 的题就这样被记成
通过。现在空回复一律记 error 不计分,接口失败也单独记。写在这里,因为它说明
对话那一路的判分要先验证"真的拿到了回复",否则一个解析错误会长得像一个分数。
跑出来的其他东西,都记在这里而不是藏进分数:
at不给 = 不过滤世界轴,不是「现在」。as_of不给才是「现在」。两根轴的 缺省口径不对称,aurora-lead-unfiltered这道题把它钉住了。- 「不再担任,日期不详」被读成仍然成立(#345):账本专门留了
valid_to_precision = unknown这个状态,而每一处世界轴过滤都按valid_to IS NULL判活。known_gap那一栏 0/1 就是它。 - 判分脚本自己犯过一次错:一跳邻域里含邻居之间的边,第一版把它们两端的名字都算成 "看见的",于是「李四 2023 年在管 Aurora」被误判出来。现在只看碰到主语的边。 这类错会把产品的正确行为报成失败,比漏报更坏,所以写在这里。
- 一条
salary值被抽取丢掉过一次(extraction_drops里的malformed_item): 声明了number之后,模型写成 "28000 CNY" 的那一次没能通过校验。宁缺勿脏是 写死的取舍,这里只记它发生过。
typed.mjs 量的是 0044 §Measurement 里「Typed graph」那一行:对齐把开放陈述算成类型化事实之后,
金标召回了多少、裁判认多少是对的。 语料是 Re-DocRED(MIT)测试集抽的 100 篇,它的 95 条属性当
已批准的本体;fetch-redocred.mjs 生成语料、答案卷和本体文件,原始数据不进仓库。
属性的定义域/值域从训练集统计(truth/redocred-ontology.json),不留空:不声明的属性对每条
签名都是候选,95 条一齐进候选就超过对齐器的上限,每条签名都溢出成 undecided。训练集学、
测试集评。值域只有时间/数值的属性建成 attribute,别的建成 relation。
node scripts/bench/fetch-redocred.mjs --n 100 --seed 1 # 一次:生成 corpora/ 与 truth/ 下的三份文件
node scripts/bench/typed.mjs --label run1 --judge 200 # 一组:新库 → 本体 → 语料 → 抽取 → 对齐 → 打分
node scripts/bench/typed.mjs --label run2 --judge 200 # 再来一组:门槛按两轮报
node scripts/bench/typed.mjs --kb <id> --score # 只重新打分
加 --errata 就在对齐之后排一次勘误 agent(0044 决定 7):报它看了多少、撤改加各几条、留给人几条、
花了多少 token,再打一次分;带 --judge 时裁判也判撤掉的行——判 stated 的就是撤错的。0044 §7 的
度量正是这两个数:precision gained against correct facts removed(原型:76.1% → 89.5%,撤 278 条,
约四分之一是对的)。
报的数:gold recall(同句与跨句分开,门槛只看同句;跨句的等派生规则)、judged precision (裁判抽样;金标漏标严重,精度只信裁判)、entity-pair recall(开放陈述那一层)、绑定的 bound / none / undecided。0044 的门槛:裁判精度不低于完整原型的 75.3%,同句召回不低于完整原型, 两轮各报一次,每篇文档的 token 不到原型的五分之一。
裁判与抽取是同一个模型,精度要打折看。--approve-rules 替审核人把对齐器提的规则全批了,
量的是蕴含机制的上限;真人会驳回一部分。
| 组 1 | 组 2 | |
|---|---|---|
| 开放陈述 / 实体 | 1855 / 1854 | 1778 / — |
| 签名 bound / none / undecided | 214 / 927 / 48 | 409 / 1074 / 70(打分中又跑了一轮对齐,从 312 涨到 409) |
| 类型化(按绑定) | 358 | 411 → 629(第二轮对齐后) |
| gold recall 勘误前(同句 / 跨句) | 6.0%(8.7% / 3.7%) | 6.5%(9.6% / 4.3%) |
| 规则:提 / 批 → 读数 / 隐含行 | 112 / 112 → 88 / 75 | 159 / 159 → 146 / 164 |
| gold recall 批规则后、勘误前 | 6.6%(9.4% / 4.1%) | 9.6%(13.7% / 6.2%) |
| 裁判精度 勘误前(200 抽样) | 96.9% | 92.5% |
| 勘误:看 / 撤 / 改 / 加 / 拒 | 429 / 53 / 24 / 463 / 49 | 963 / 135 / 97 / 1146 / 124(两遍累计) |
| 撤改的行里裁判判 stated | 34 / 37 | 72 / 110(另 34 条 misworded) |
| gold recall 勘误后 | 11.9%(17.7% / 7.0%) | 17.1%(24.6% / 10.7%) |
| 裁判精度 勘误后(全量) | 96.7%(547 条) | 96.4%(700 条) |
| entity-pair recall(开放层) | 15.0% | 13.7% |
读数:精度远高于原型勘误前的 75.3%;召回远低于原型(同句 8.7% 与 9.6% 对比原型整体 15.3%)。短板在对齐的 覆盖:1189 条签名里 927 条判「无」,P17(国家)565 条金标只中 1 条,P27 国籍、P150 下辖为 0——这些 属性靠蕴含规则,而规则要人批;全批之后隐含 75 行,召回只涨 0.6 个点,因为读数只答出 36 / 88。勘误 这一刀的账与原型相反:撤掉的 37 条里 34 条裁判认为原文说了(撤错),加的 300 多条精度与其余持平 (全量 96.7%),召回因此从 6.0% 到 11.9%。每篇 token 这一轮量不出:apexin 的流每一帧都带累计用量, 服务端按帧记了日志;从这个 PR 起每次回复只记一行,下一轮能按阶段加总。
第一次真跑每篇 13.6 万 token,正文只有 300。按调用类型拆开(服务端从 #893 起每次回复记一行用量) 之后逐刀改,每刀用同一批 20 篇(735 条金标)验证,同一个裁判模型:
| 样本 | 配置 | 绑定 bound/none/undecided | 勘误前 召回(同句)/ 精度 | 勘误后 召回(同句) | 全量精度 | 每篇 token |
|---|---|---|---|---|---|---|
| smoke5 | 全 minimal,短名单,共享属性表 | 120/150/39 | 10.7%(20.8%)/ 69% | 13.2%(24.4%) | 74.4% | ~10 万* |
| smoke6 | 对齐按默认强度思考 | 77/163/16 | 11.0%(19.2%)/ 88% | 13.7%(24.0%) | — | ~5.3 万 |
| smoke8b | + 标签当键、批次并行 | 98/150/15 | 12.8%(22.7%)/ 83% | 15.2%(26.0%) | 82.1% | ~5.6 万 |
| smoke10 | 对齐按 low | 120/163/34 | 11.6%(23.1%)/ 70–75% | 17.1%(27.9%) | 76.3% | ~3.9 万 |
*smoke5 还带着提规则每项整张属性表的巨无霸请求(一次 5.7 万)。
刀与理由:
- 候选短名单:结构对得上的候选超过十条时,签名的文本嵌入后取最近的十条(
embed_ontology的向量), 标签对上短语的一律保留;短名单进判定指纹。一次请求从 1.8 万降到 4 千。 - 属性表一批只写一遍(短语对齐与提规则),每项只列键。提规则的类别词项从前每项整张表。
- 模型答标签也认:这个本体的键是
p569,模型十有八九答dateOfBirth;第一次真跑 1189 条签名里 586 条因此判成坏票。标签唯一对上就认它的键。 - 推理强度按任务分:抽取、读数、勘误照原文写 JSON,用工作区设的
minimal(思考 token 归零、答案 不变);对齐是判断题,全关时 misworded 31%,默认强度 12%,low 折中在 76% 精度;提规则按 low。 (2026-10-03 起不再按任务分,每一种调用都用工作区设的强度,见「对齐不再另外想」一节。) - 批次并行:对齐与提规则四批同飞,20 篇的对齐从 29 分钟到 5 分钟;台子的裁判也四篇并行。
- 只问绑上的签名提规则、基准库关掉治理 agent(它在第三轮花了约 500 次调用)、勘误只带文档 最近的 24 条属性。
- 撤销要两票加一个结构报的理由:第三轮 100 篇整轮零错撤(撤 2 改 8,全部第二票确认);加的放开 (文档里出现的新名字可以建实体、没类型化行的文档也看一次)把召回从 9.3% 推到 18.4%,代价是加得多 之后全量精度从 96% 到 90%。
跳过的签名(第三轮 586、之后每轮 60 上下)里坏票修掉之后剩下的是结构上一条属性都对不上的:宾语是 值而本体只有 9 条属性型,或那对类没有任何属性声明。那是这份本体的覆盖,不是解析。
第三轮 100 篇(两票撤销,老成本)的完整数:勘误前 670 条、召回 9.3%(同句 13.1%)、精度 93.9%; 勘误后 973 条、15.9%(22.7%)、97.0%;全批 166 条规则隐含 149 行,再勘误累计加 790、留人 167, 1203 条、18.4%(26.5%),全量裁判 90.2%。
两组各一个新库,--judge 200 --errata,裁判与抽取同一个模型。这个二进制在 #906(短名单、属性表
一批一写、只问绑上的签名、勘误两票)之前,所以它是上面那张小批量表的 100 篇对照,不是 #906 之后的分。
| 组 1 | 组 2 | |
|---|---|---|
| 开放陈述 / 实体 | 1927 / 1917 | 2214 / 2194 |
| 签名 bound / none / undecided | 263 / 880 / 48 | 434 / 1426 / 80 |
| 类型化 勘误前 → 后 | 487 → 664 | 753 → 869 |
| gold recall 勘误前(同句 / 跨句) | 7.8%(11.3% / 4.8%) | 9.7%(13.2% / 6.8%) |
| 裁判精度 勘误前(200 抽样) | 91.0% | 88.5% |
| 勘误:看 / 撤 / 改 / 加 / 拒 | 75 篇 723 条:67 / 31 / 437 / 63(两遍累计) | 99 篇 762 条:162 / 34 / 449 / 47 |
| 撤改的行里裁判判 stated | 72 / 98 | 164 / 196 |
| gold recall 勘误后(同句 / 跨句) | 12.8%(18.6% / 7.8%) | 15.9%(22.4% / 10.4%) |
| 裁判精度 勘误后(200 抽样) | 96.0% | 96.5% |
| entity-pair recall(开放层) | 15.7% | 14.5% |
| 用时 | 抽取 11 分,对齐 2 时 29 分,勘误加裁判 24 分 | 共 284 分 |
按 0044 的门槛读:裁判精度两轮都在 75.3% 之上;同句召回勘误前 11.3% / 13.2%,仍低于原型整体的 15.3%,勘误后 18.6% / 22.4% 过了,但这个二进制的勘误撤的多半是原文说了的(72 / 98、164 / 196), #906 的两票撤销就是冲它来的;每篇 token 远超"原型五分之一"这一条,见下。
token 按阶段拆(服务端每次回复一行用量,按时间窗归到阶段;治理 agent 与对齐同时在跑, 归在同一格里):
| 阶段 | 组 1 调用 / token / 每篇 | 组 2 调用 / token / 每篇 |
|---|---|---|
| 抽取 | 333 / 174 万 / 1.7 万 | 389 / 228 万 / 2.3 万 |
| 对齐 + 提规则 + 治理 agent | 2226 / 1302 万 / 13.0 万 | 2089 / 1497 万 / 15.0 万 |
| 勘误 + 裁判 | 131 / 109 万 / 1.1 万 | 122 / 104 万 / 1.0 万 |
| 合计每篇 | 15.8 万 | 18.3 万 |
那一大格里有三样东西,两样 #906 已经砍了(提规则每项整张属性表,一次 5.5 万 prompt;短语对齐 每项一份候选清单加两票),第三样是治理 agent 的并发重判:每篇文档抽完都排一个治理任务,排队 去重只挡排着的、不挡在跑的,十个任务同时读同一个队头——组 1 里 1421 个对被裁了 9481 次(一个对 38 秒内被十个任务各判一次),组 2 里 2153 个对被裁了 8714 次;粗算占整轮三分之一的 token。#916 给每个库加了一把治理运行锁。#906 之后的二进制该在同一份语料上再跑两组,那才是 cut 2 的正式度量。
两个跑台子的注意:裁判端点要显式给 BENCH_JUDGE_BASE / _KEY / _MODEL——库里的密钥是封印过的,
脚本从 llm_settings 读出来的是密文,拿它去调用回的是 401;治理 agent 从 #906 起在基准库里关掉。
第四次真跑:#906 与 #916 之后的 100 篇,两组(2026-09-25,dev @ b9e3aae,gemini-3.5-flash 经 apexin.net,bge-m3,chat_reasoning_effort = minimal)
与上一节同一份语料、同一个模型、同一个裁判,两组各一个新库,--judge 200 --errata。这是 cut 2 门槛的正式度量。
| 组 3 | 组 4 | |
|---|---|---|
| 开放陈述 / 实体 | 1576 / 1636 | 1498 / 1575 |
| 签名 bound / none / undecided | 426 / 1178 / 178 | 442 / 1332 / 142 |
| 类型化 勘误前 → 后 | 689 → 825 | 713 → (两篇勘误没跑完) |
| gold recall 勘误前(同句 / 跨句) | 9.3%(14.2% / 5.1%) | 9.8%(14.3% / 6.1%) |
| 裁判精度 勘误前(200 抽样) | 81.0% | 79.0% |
| 勘误:看 / 撤 / 改 / 加 / 留人 / 拒 | 100 篇 702 条:2 / 1 / 213 / 116 / 14 | 92 篇 682 条:1 / 0 / 214 / 123 / 9 |
| 撤改的行里裁判判 stated | 0 / 3 | 0 / 1 |
| gold recall 勘误后(同句 / 跨句) | 12.2%(17.8% / 7.5%) | 12.2%(17.1% / 8.0%) |
| 裁判精度 勘误后(200 抽样) | 83.0% | 80.5% |
| entity-pair recall(开放层) | 17.4% | 16.7% |
| 用时 | 47 分 | 48 分 |
token 按阶段拆(服务端日志,按时间窗;裁判走脚本直连端点,不在里面):
| 阶段 | 组 3 调用 / token / 每篇 | 组 4 调用 / token / 每篇 |
|---|---|---|
| 抽取 | 234 / 61 万 / 0.6 万 | 376 / 88 万 / 0.9 万 |
| 对齐 + 提规则 | 682 / 222 万 / 2.2 万 | 679 / 232 万 / 2.3 万 |
| 勘误 | 139 / 26 万 / 0.3 万 | 95 / 18 万 / 0.2 万 |
| 合计每篇 | 3.1 万 | 3.4 万 |
按 0044 的门槛读,两轮各报一次:
- 裁判精度 ≥ 75.3%:过(81.0% / 79.0% 勘误前,83.0% / 80.5% 勘误后)。比上一节的基线低约十个点,
差的几乎全是 misworded(33 / 39 对 17 / 21):
minimal关掉思考 token 后抽取的措辞更糙。 - 同句召回不低于完整原型(15.3%):勘误前 14.2% / 14.3% 差一点,勘误后 17.8% / 17.1% 过。勘误这一刀 现在只加不撤(撤 2 与 1,且没有撤错),加的 213 / 214 条把同句召回抬了三个多点。
- 每篇 token 不到原型的五分之一(约 6 千):不过。3.1 万 / 3.4 万,是基线的五分之一,仍是门槛的五倍。 七成在对齐加提规则(每篇 2.2 万);这一段按签名摊、不按文档摊,一个新库 100 篇是它最贵的样子。 要量产品里的每篇成本,得在同一个库上再灌一批新文档看边际 token,台子还没有这个口径。
对照上一节:撤回从 67 / 162 条到 2 / 1 条,撤错从 72 / 164 到 0;用时从三到五小时到 47 分钟;
每篇 token 从 15.8 万 / 18.3 万到 3.1 万 / 3.4 万。组 4 有两篇文档的勘误回复不是合法 JSON,重试三次后
放弃,那两篇没勘误,任务记为失败(jobs.last_error)。
--into <kb> --corpus redocred-100b:fetch-redocred.mjs --seed 2 --name redocred-100b --exclude corpora/redocred-100.json
抽的第二批 100 篇(与第一批零重叠,3600 条金标全在库里那 95 条属性上),灌进组 3 跑完的库,只排新文档的
抽取,对齐照常(已判过、指纹没变的签名不重问),只对新文档打分,token 从服务端日志按阶段算
(BENCH_SERVER_LOG)。裁判只抽本批文档有证据的事实——全库抽样会抽到第一批的事实,脚本正文表里没有它们,
模型读到空正文就判 not_stated(第一次跑就是这么得出 24.6% 的)。
| 第二批 | 值 |
|---|---|
| 开放陈述 / 全库实体 | 1491 / 3217 |
| 全库签名 bound / none / undecided(第一批跑完时 426 / 1178 / 178) | 674 / 1698 / 277 |
| 类型化 勘误前 → 后 | 486 → 684 |
| gold recall 勘误前 → 后(同句) | 5.6%(7.7%)→ 8.3%(11.7%) |
| 裁判精度(勘误后,200 抽样) | 80.0% |
| 勘误 | 看了全库 200 篇 1209 条:撤 7 / 改 2 / 加 499 / 留人 221 |
| token:抽取 / 对齐 / 勘误 / 合计 | 68 万 / 142 万 / 39 万 / 255 万 |
| 每篇 | 2.5 万(新库 3.1 万) |
| 用时 | 67 分 |
读数:温库只省了 18%,对齐从每篇 2.2 万到 1.4 万,没有摊薄多少——第二批 100 篇带来约 800 条新签名 (绑定 +248,判无 +520),和第一批的约 1000 条差不多。Re-DocRED 是维基百科各领域的条目,短语签名跨文档 几乎不重复;每条签名约 1.4 千 token,每篇 8 到 10 条。同一领域的语料重复率会高得多,那是摊薄能兑现 的地方,这份语料量不出来。第二批召回低于第一批(同句 7.7% 对 14.2%),因为库里已经判"无"的签名不再重问, 第一批判错的"无"第二批照样错——温库就是这样工作的。勘误在温库上复查了全部 200 篇:新绑定给旧文档也添了 类型化事实,所以旧文档也在它的清单里,每篇边际里的勘误那 0.4 万有一半是复查旧文档。
组 3 的日志里短语对齐判了 1847 次而签名只有约 1000 条:第二轮类别词对齐(562 个词)和第一轮短语对齐 同时在跑,类别词绑完改了实体的类,签名指纹全变,713 条重判。#926 让类别词对齐只在最后一轮才排短语 对齐,短语对齐开跑前若发现类别词任务还排着就推迟半分钟。同一语料、同一模型、同一裁判:
| 组 5(#926) | 组 6(#926) | 组 7(dev 对照,同一时段) | |
|---|---|---|---|
| 签名 bound / none / undecided | 419 / 362 / 165 | 414 / 377 / 166 | 420 / 1405 / 165 |
| 类型化 勘误前 → 后 | 739 → | 694 → | 707 → |
| gold recall 勘误前(同句) | 9.4%(14.2%) | 8.7%(13.4%) | 9.4%(14.2%) |
| gold recall 勘误后(同句) | 12.4%(17.5%) | 12.1%(17.5%) | — |
| 裁判精度 勘误前,200 抽样 | 75.5% | 70.6% | 78.5% |
| 裁判精度 勘误后,200 抽样 | 78.5% | 75.0% | 74.0% |
| 裁判精度 勘误后,600 抽样(种子 7) | 77.2% | 81.8% | 82.0%(组 4 同口径 81.7%) |
| 每篇 token | 3.1 万 | 2.9 万 | 3.2 万 |
读数:
- 签名干净了:dev 上判"无"的 1405 条里约 1000 条是类别词还在变时生成的过渡签名,#926 之后没有了; 短语判定从 1847 次回到 980 次。召回不变。
- token 几乎没省(每篇 3.1 / 2.9 万对 3.2 万):被重判的签名便宜。对齐的大头是提规则——组 5 问了 1506 次 提出 101 条(类别词 621 问 32 提,短语 411 问 69 提)——和两票本身。
- 200 条裁判太粗:同一个库 200 条与 600 条能差十个点(组 6 的 70.6% 对 81.8%),裁判自己也是模型,
两次判同一批也不一样。门槛 75.3% 与实际水平(80% 上下)只差五个点,200 条分不出来。
--judge缺省 改成 600;这一节之前的精度都是 200 条的,读的时候按 ±5 个点看。 - 600 条口径下 #926 与 dev 没有可分辨的差别(77.2 / 81.8 对 81.7 / 82.0)。
按语句数过滤提规则不该做:提出的 101 条规则里 80 条来自单语句签名。类别词那 621 次询问命中 5%, 是能砍的;条件第二票再砍一成多。三样都做每篇也在 2.3 万上下:对齐按签名计费,这份语料每篇 9 到 10 条 新签名、每条约 1.4 千 token,这就是它的地板。0044 的 token 门槛在 Re-DocRED 上要么换口径(每条新签名 的成本),要么换同领域语料再量。
20 篇按调用分(typed.mjs 的 token 表):短语对齐的两票占 38%,抽取 20%,提规则 14%,类别词对齐 9%。
短语对齐一次调用的输入约 4600 token,其中属性表将近一半——按到来次序切批时,同批签名的候选几乎不重叠。
三处改动:
- 按候选分批:候选相近的签名排进同一批。只改排法,每条签名看到的候选不变。
- 第一票说没有的不投第二票:第二票防的是「选第一个」冒充一致;第一票说没有,第二票怎么答都绑不上。
- 只有中心词的类别词不问规则:类别词规则的宾语从类别词自己的字里读(「british film」读出英国)。 基线一轮问了 159 个类别词,127 个是单个词,提出的 8 条规则(「state」→ 国家)没有一条读得出宾语。
两轮完整的 20 篇之间抽取自己就不一样(签名 229 对 210,只有 137 条相同),整轮的数字分不出对齐的 变化。所以在同一个库的同一批陈述上把绑定清掉重判,210 条签名,每种构建各判一遍或两遍:
| 基线 | 基线 再一遍 | 分批 | 分批 再一遍 | 三处都改 | |
|---|---|---|---|---|---|
| 短语对齐调用 | 46 | 47 | 36 | 40 | 32 |
| 输入 token | 190572 | 199086 | 128338 | 143900 | 103412 |
| 输出 token | 46537 | 45422 | 35809 | 36644 | 29703 |
| 合计 | 237109 | 244508 | 164147 | 180544 | 133115 |
| 签名 bound / none / undecided | 53 / 110 / 47 | 66 / 108 / 36 | 69 / 108 / 33 | 67 / 109 / 34 | 63 / 119 / 28 |
| 类型化事实 | 82 | 87 | 99 | 92 | 84 |
读数:
- 分批省短语对齐的三成(24.1 万 → 17.2 万),加上条件第二票省四成五(→ 13.3 万)。
- 模型自己的波动比改动大:同一个构建、同一批签名、温度 0,两遍判定完全相同的只有 166 / 210(基线) 和 163 / 210(分批)。基线对分批是 146 到 159。分批让判定多变了约十条,方向两边都有(绑上的数和 类型化行数没有变少);20 篇整轮的裁判精度 79.3% 对 78.8%。
- 条件第二票的代价:它记成「无」的 98 条,在另外四遍里 81 到 86 条本来也是「无」,8 到 12 条是
「拿不定」(第二票答了一条属性),4 到 5 条绑上了(那一遍第一票答的不一样,是波动)。「拿不定」的那
十条上下不再进人的队列,
votes.reason = "first_vote_none"查得到。 - 20 篇整轮(只有分批):合计 82.1 万 → 62.6 万,每篇 4.1 万 → 3.1 万;其中约一半来自分批,其余是 这一轮抽出的签名少、重问少。
台子从前让每篇抽两遍。 配了对话模型的库,文档解析完管线自己排抽取;typed.mjs 和 timewords.mjs
随后又对每篇调一次手动抽取,而手动抽取是强制全量(解雇在跑的任务、从头再抽)。20 篇 24 个分块,抽取调用
45 次。现在只补管线没排上的。这一节之前的每篇 token 都多算了将近一遍抽取,召回也可能受它影响(在跑的
那一遍被中途顶替):这一轮同句召回 20.1%,实体对召回 18.0%,只有 20 篇,要在 100 篇上再量。
| 调用 | 次数 | 每次输入 | 每次输出 | 每篇 |
|---|---|---|---|---|
| 短语对齐 | 38 | 3283 | 240 | 6695 |
| 抽取 | 26 | 2517 | 1152 | 4770 |
| 类别词对齐 | 24 | 2947 | 647 | 4314 |
| 提规则 | 14 | 4061 | 122 | 2929 |
| 时间解释 | 20 | 1770 | 141 | 1912 |
| 本体代理 | 5 | 4966 | 2021 | 1747 |
| 实体裁决 | 9 | 2504 | 503 | 1354 |
| 提问题 | 1 | 7603 | 1466 | 453 |
合计每篇 24175,输入占 85%。类型化 138,绑定 105 / 98 / 27,裁判精度 79.7%。
抽取的系统消息约 2380 token,一篇 Re-DocRED 文档约 270。 试了三处删减,每处单独量:31 个没有表格 的段落(这 20 篇的 24 个分块加时间台子的 7 篇),每种系统消息各抽三遍,回复用服务端的解析器读,对金标 的实体对和时间台子的期望打分:
| 系统消息 | 每次输入 | 金标实体对(三遍) | 同句(三遍) | 时间词记下 | 修复后只剩一条陈述的回复 |
|---|---|---|---|---|---|
| 原样 | 2488 | 27.0 / 27.6 / 28.6% | 42.6 / 44.6 / 47.0% | 28 / 28 / 27 | 0 / 93 |
| 不带表格的规则 | 2339 | 28.6 / 28.4 / 28.6% | 47.0 / 46.2 / 46.2% | 27 / 27 / 27 | 0 / 93 |
| 再去掉规则 6(引文的位置,规则 2 与 7 说过) | 2296 | 29.0 / 27.4 / 26.5% | 49.4 / 47.4 / 43.4% | 28 / 27 / 28 | 3 / 93 |
| 再去掉结尾的例子 | 2182 | 27.9 / 23.3 / 27.6% | 44.2 / 41.4 / 45.0% | 28 / 29 / 28 | 0 / 93 |
- 表格的规则只随有表格的段落带:没有表格的段落上分数不降,有表格的段落系统消息与从前逐字相同。落地。
- 规则 6 重复,却在管格式:去掉之后 93 次里 3 次括号写错,解析器修到最后一个完整对象,整段只剩一条 陈述。不去。
- 结尾的例子:三遍里一遍实体对掉到 23.3%,解析没有出错。分不清是波动还是损失,不去。
- 同一条系统消息、温度 0,两遍抽出的陈述(主语、短语、宾语)只有六成相同。逐条比对陈述量不出提示词的 改动,要用有标准答案的指标。
不合法的回复逐条读(同一天)。 上面那 372 份回复里 7 份整体解不开,没有一份是被截断的
(finish_reason = stop):模型写坏了括号。从前的修补退到坏处之前,之后的全丢:
| 回复 | 系统消息 | 从前留下 实体 / 陈述 / 日期 | 逐条读 |
|---|---|---|---|
| zh-compiled.md | 原样 | 28 / 21 / 0 | 28 / 21 / 2 |
| redocred-013 | 去掉规则 6 | 24 / 1 / 0 | 24 / 16 / 0,别名 6 |
| redocred-002 | 去掉规则 6 | 14 / 1 / 0 | 14 / 8 / 0,别名 2 |
| redocred-003 | 去掉规则 6 | 19 / 1 / 0 | 19 / 9 / 0,别名 3 |
| 另外 3 份(坏在结尾) | 不变 | 不变 |
整体合法的 365 份,新旧解析逐条相同。
类别词对齐每篇 4314 token。一批二十个词,每个词下面各列一遍候选类的定义:一个词约 145 token 的输入里 约 120 是它。改成定义表一批写一遍、各项只列候选的键(与短语对齐同一个办法),判断的规则不动。
在第七次那个库上(20 篇,176 个类别词,实体不动)把类别词的绑定清掉重判,新旧各两遍。正确率是库里的实体 按名字对上金标实体之后,类别词绑到的类与金标类型是否一致(216 个对得上、类型不含糊的实体):
| 从前 | 从前 再一遍 | 定义表写一遍 | 再一遍 | |
|---|---|---|---|---|
| 调用 | 18 | 18 | 18 | 18 |
| 输入 token | 61382 | 61389 | 29142 | 29138 |
| 输出 token | 19977 | 16361 | 13748 | 14571 |
| 绑定 bound / none / undecided | 163 / 2 / 11 | 162 / 3 / 11 | 157 / 1 / 18 | 166 / 2 / 8 |
| 实体 对 / 错 / 没绑上 | 210 / 4 / 2 | 210 / 5 / 1 | 207 / 6 / 3 | 209 / 6 / 1 |
| 绑上的里面对的 | 98.1% | 97.7% | 97.2% | 97.2% |
- 输入少一半多(6.1 万 → 2.9 万),合计 8.0 万 → 4.3 万。
- 四遍里判得不一样的 25 个词,没有一个是两遍绑到了不同的类:全是绑上与拿不定之间来回。同一个构建两遍 相同的 166 与 160 个,新旧之间 157 到 164 个,分不出来。
- 正确率差一个实体上下(错 4、5 对 6、6),在这个量上也分不出来;本体只有六个类,候选多、定义长的 本体省得更多,也更该在那样的库上再量一次。
第九次真跑:#906 之后的 100 篇,两组,换一个模型(2026-09-30,dev @ 798fb24,deepseek-flash 经 DeepSeek 官方接口,bge-m3 经 OpenRouter,裁判 gemini-3.5-flash 经 OpenRouter)
第四次真跑的重复:同一份语料、同一个裁判模型、两组各一个新库、--judge 200 --errata,抽取模型换成
deepseek-flash。目的有两个:0044 cut 2 的三条门槛要"两轮各报一次",第四次之后 dev 又改了七刀
(#906 之后到 #1013),在当前的 dev 上再量一次;另一个是看门槛过不过取决于模型还是管线。
三处与第四次不同,读数时要记着:
- 抽取的推理强度是
none,不是minimal。 deepseek-flash 默认思考,minimal关不掉(试探请求仍有 思考 token),只有none能关;设置接口和库的 CHECK 只认 minimal / low / medium / high,这一轮在 测量库上去掉了那条 CHECK 直接写none。对齐与提规则在代码里固定用low,deepseek 在low下每次 调用输出七八千 token 的思考,gemini 只有几百——每篇 token 因此不能和第四次直接比,下面按调用拆开。 - 嵌入走 OpenRouter 的 bge-m3(SiliconFlow 的余额用完了)。同一个模型,向量与库里 SiliconFlow 算的 余弦 0.9999,本体向量不用重建。
- 裁判从台子直连,Node 自己的
fetch不读代理变量:直连出口被 OpenRouter 按地区拒掉 gemini(403), 要NODE_USE_ENV_PROXY=1。裁判四篇并行又撞上新账号的每分钟限速(429),两组各丢了一半样本;typed.mjs的裁判调用从这一轮起对 429 和 5xx 退避重试,两个库用它重新打分,200 条各判满。
| 组 1 | 组 2 | |
|---|---|---|
| 开放陈述 / 实体 | 1495 / 2100 | 1519 / 2113 |
| 签名 bound / none / undecided | 277 / 692 / 33 | 283 / 677 / 54 |
| 类型化 勘误前 → 后 | 406 → 642 | 444 → 676 |
| gold recall 勘误前(同句 / 跨句) | 5.1%(7.1% / 3.4%) | 6.4%(8.4% / 4.8%) |
| 勘误:看 / 撤 / 改 / 加 / 留人 / 拒 | 100 篇 407 条:0 / 1 / 246 / 52 / 9 | 100 篇 445 条:0 / 0 / 260 / 50 / 6 |
| gold recall 勘误后(同句 / 跨句) | 8.4%(12.3% / 5.1%) | 9.6%(13.2% / 6.6%) |
| 裁判精度 勘误后(200 条判满,重新打分) | 86.5%(stated 173 / misworded 22 / not_stated 5) | 89.0%(178 / 18 / 4) |
| entity-pair recall(开放层) | 10.7% | 10.8% |
| 用时 | 105 分 | 114 分 |
token 按阶段拆(服务端日志,按时间窗;裁判不在里面):
| 阶段 | 组 1 调用 / token / 每篇 | 组 2 调用 / token / 每篇 |
|---|---|---|
| 抽取 | 220 / 67 万 / 0.7 万 | 229 / 69 万 / 0.7 万 |
| 对齐 + 提规则 | 344 / 332 万 / 3.3 万 | 339 / 355 万 / 3.6 万 |
| 勘误 | 129 / 34 万 / 0.3 万 | 141 / 43 万 / 0.4 万 |
| 合计每篇 | 4.4 万 | 4.8 万 |
按调用(两组相近,取组 2):短语对齐 142 次、每篇 1.7 万;类别词对齐 76 次、0.9 万;提规则 38 次、
0.6 万;抽取 126 次、0.4 万;本体代理 26 次、0.4 万;实体裁决 102 次、0.3 万;勘误 110 次、0.2 万;
时间解释 85 次、0.1 万。对齐三项合计 3.2 万,其中输出 token 占四分之三——那是 low 下的思考。
按 0044 的门槛读,两轮各报一次:
- 裁判精度 ≥ 75.3%:过(86.5% / 89.0%)。与第四次的 83.0% / 80.5% 同一水平;misworded 占错的大半, 与第四次一样。
- 同句召回不低于完整原型(15.3%):不过,勘误后 12.3% / 13.2%。第四次 gemini 是 17.8% / 17.1%。 差在抽取那一层:实体对召回 10.7% / 10.8% 对 17.4% / 16.7%,绑上的签名 277 / 283 对 426 / 442—— deepseek-flash 在开放抽取上比 gemini-3.5-flash 少抽三分之一的实体对,后面每一步按比例缩小。 这条门槛过不过取决于抽取模型,不是管线:同一份代码在 gemini 上过、在 deepseek-flash 上不过。
- 每篇 token 不到原型的五分之一(约 6 千):不过,4.4 万 / 4.8 万。第四次 3.1 万 / 3.4 万。两次真跑 的管线相同,多出来的一万三是 deepseek 在对齐上的思考(对齐输出 243 万 / 268 万 token,第四次的 对齐整个才 222 万 / 232 万)。四次 100 篇真跑没有一次接近这条门槛:gemini 五倍,deepseek 八倍。 它按文档摊对齐的成本,而对齐按签名收费,一个新库 100 篇是最贵的形态(第四次已指出)。要么按 签名重定,要么记下"不过"接受——这是 0044 的决定,台子只给数。
两组之间很一致:同句召回差 0.9 个点,实体对差 0.1 个点,每篇 token 差 4 千。运行间的波动小于 两个模型之间的差。勘误这一刀两组都只加不撤(撤 0 / 0,改 1 / 0),加的 246 / 260 条把同句召回 抬了五个点,判满之后精度 86.5% / 89.0%。
费用:deepseek-flash 两组加 20 篇试跑共 ¥28.7(输入 $0.15 / 百万、输出 $0.60 / 百万,思考 token 按输出计); 裁判约 600 次调用、每次 $0.0045(gemini 没关思考,每次三四百个思考 token),合计 $3 上下。
第九次真跑留下的口子是 token 门槛:四次 100 篇真跑没有一次接近,而新库 100 篇是对齐最贵的形态。这一次量
另一头:--into <第九次组 2 的库> --corpus redocred-100b --judge 200 --errata,同一个模型、同一份设置
(抽取 none,对齐与提规则固定 low),和 2026-09-25 gemini 的那次温库同一个做法。
| 第二批 | 值 |
|---|---|
| 开放陈述 / 全库实体 | 1488 / 4092 |
| 全库签名 bound / none / undecided(第一批跑完时 283 / 677 / 54) | 478 / 1396 / 92 |
| 类型化 勘误前 → 后 | 367 → 603 |
| gold recall 勘误前 → 后(同句) | 3.7%(4.8%)→ 6.9%(9.6%) |
| entity-pair recall(开放层) | 9.2% |
| 裁判精度 勘误前 / 后 | 89.2%(判了 186,14 条请求失败)/ 87.5%(200 条判满) |
| 勘误 | 看了全库 200 篇 822 条:撤 0 / 改 1 / 加 521 / 留人 96 / 拒 14 |
| 每篇 token | 4.2 万(新库 4.8 万) |
按调用,和第九次组 2 的新库并排(每篇,调用次数在括号里):
| 调用 | 新库 | 温库第二批 |
|---|---|---|
| 短语对齐 | 1.7 万(142) | 1.35 万(111) |
| 提规则 | 0.6 万(38) | 0.60 万(34) |
| 类别词对齐 | 0.9 万(76) | 0.58 万(54) |
| 实体裁决 | 0.3 万(102) | 0.58 万(208) |
| 抽取 | 0.4 万(126) | 0.48 万(137) |
| 勘误(复查 + 核对) | 0.2 万(110) | 0.25 万(123,全库 200 篇) |
| 本体代理 | 0.4 万(26) | 0.21 万(12) |
| 时间解释 | 0.1 万(85) | 0.14 万(84) |
| 合计 | 4.8 万 | 4.2 万 |
读数:
- 温库只省了 13%(gemini 那次 18%)。第二批 100 篇带来 952 条新签名(绑定 +195,判无 +719, 未定 +38),第一批是 1014 条:签名跟着文档线性长,不是跟着库收敛。短语对齐每条新签名约 1.4 千 token (新库 1.7 千),和 gemini 量到的一样。
- 光是抽取加时间解释就到门槛了:0.48 万 + 0.14 万 = 0.62 万,门槛是约 0.6 万。对齐一个 token 不花, 这条门槛在这套管线上也过不了——它是照紧凑原型(一次抽取调用、类型映射走缓存)定的,而这里每篇 约 1.4 次抽取调用(100 篇 137 次),每次带着整份抽取契约。
- 对齐三项 2.5 万,占六成,其中输出占八成(短语对齐输入 32 万、输出 103 万;类别词 8 万、49 万;
提规则 16 万、44 万)。那是 deepseek 在固定的
low下的思考,gemini 同一步每次只有几百。 - 实体裁决随库变大:208 次对 102 次。库里的实体从两千到四千,同名候选多了;这一项在温库上是涨的。
- 第二批召回低于第一批(同句 9.6% 对 13.2%),原因同 gemini 那次:库里判过"无"的签名不再重问。
对着原文看:这份语料每篇约 200 个词、270 个 token。温库每篇 4.2 万是原文的约 160 倍,新库 4.8 万约 180 倍;光抽取 0.48 万就是 18 倍,门槛 0.6 万是 22 倍。文档越短这个倍数越难看——每次调用的提示词 (契约、本体、候选)是固定开销,不随正文变短。
所以「按签名重定」救不了这条门槛:签名数跟文档数成正比,换个分母,每篇的数还是那么多。能动的是两处,
都要另外量:对齐在 deepseek 上的思考(low 换成关掉,gemini 上关掉时错判从 12% 到 31%,deepseek 没量过),
和进模型之前先筛掉一部分签名。否则就是记下「不过」接受它。这是 0044 的决定,台子只给数。
这一轮的台子出过一次岔子,读数时要知道。 评测脚本 03:00 起了一次,上传完之后进程没了(runs.log
里没有它的退出行),04:06 又起了一次,原因没查出来;服务端一直在跑,文档只传了一遍,第二次接上时抽取
已经做完。脚本自己的 token 表只算它自己那一段(04:06 之后,每篇 1.6 万,没有抽取),不能用;上面的数
是服务端日志从 03:00:49 到 04:38:24 整段按 call= 归的。短语对齐因此分两段跑(04:06 之前 65 次,之后
46 次),判定数前后是接着涨的(2664 → 3236),没有看到重问。
费用:180 万输入、239 万输出,约 $1.70(余额少了 ¥10.6);裁判约 400 次调用,$2 上下。用时 98 分。
从 2026-09-24 起对齐、提规则、本体代理固定用 low(上面「推理强度按任务分」那一条):gemini 上全关时
misworded 从 4% 到 31%。在 deepseek-flash 上这条规矩的账是另一个样:low 每次调用想七八千 token,对齐
三项占每篇 token 的六成、其中八成是思考(温库那一节)。这一刀把固定的 low 去掉,这几种调用和抽取一样
用工作区设的强度;设置接口和库多认一个 none(迁移 0105),DeepSeek 只有它关得掉思考。
量法:--corpus redocred-20 --judge 200 --errata,新库。全关两组是这一刀的二进制、工作区设 none;
low 那一组是 2026-09-30 的试跑(dev @ 798fb24,抽取 none、对齐固定 low,裁判重新打分的那一次)。
两边的抽取设置相同,差别只在对齐、提规则这几步想不想。
对齐 low(09-30) |
全关 组 1 | 全关 组 2 | |
|---|---|---|---|
| 签名 bound / none / undecided | 75 / 120 / 10 | 80 / 107 / 23 | 52 / 131 / 24 |
| 类型化 勘误前 → 后 | 113 → 157 | 119 → 156 | 78 → 107 |
| 裁判精度 勘误后(判了) | 91.7%(157) | 83.3%(156) | 89.7%(107) |
| misworded(勘误后) | 9 条,5.7% | 24 条,15.4% | 8 条,7.5% |
| 同句召回 勘误后 | 19.2% | 14.3% | 12.0% |
| entity-pair recall(开放层,对齐碰不到) | 14.0% | 11.0% | 12.9% |
| 每篇 token | 4.7 万 | 2.2 万 | 1.9 万 |
| 其中短语对齐 / 类别词对齐 / 提规则 | 2.1 万 / 1.0 万 / 0.65 万 | 0.60 万 / 0.18 万 / 0.21 万 | 0.43 万 / 0.18 万 / 0.12 万 |
| 用时 | 28 分 | 6 分 | 4 分 |
- 每篇 token 少了一半多,对齐三项从 3.8 万到 0.7–1.0 万。 短语对齐的输出从 32 万 token 到 4 千:
输入几乎没变(10 万对 12 万),少掉的全是思考。全关那两组里本体代理占了每篇 0.27 万,
low那一组 的时间窗里没有它;去掉它是 1.6–1.9 万。用时四到六分钟对二十八分钟。 - 精度两组 83.3% / 89.7%,
low是 91.7%,都过 75.3% 的门槛。misworded 一组 15%、一组 7.5%,low是 5.7%:方向和 gemini 上量到的一样(不想的时候它挑「相近」而不是「就是」的属性),幅度小得多——gemini 是 4% 到 31%。 - 全关之后两组之间差得更大:绑上的签名 80 对 52,同句召回 14.3% 对 12.0%。两票都不想的时候,同一条
签名这一次绑上、下一次判无的更多。
low只有一组,它自己的波动没量。 - 同句召回
low那一组高出五到七个点,一半在抽取(实体对 14.0% 对 11.0% / 12.9%,对齐碰不到这一层), 100 篇上low是 12.3% / 13.2%——20 篇的召回要这样读。
这是用精度和稳定换 token 和时间,换不换是工作区的选择:设 low,这几步和从前一样想;设 none 或
minimal,全关。没有哪一步再替工作区另定一个强度。按 0044 的 token 门槛读,1.9–2.2 万仍是门槛的三倍多。
费用:全关两组共 ¥1.0,裁判约 $1。