dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Independent offline evaluation of the Bocha Jev decision model in a web-search evidence pipeline (vs. rule baseline and Laya): tasks, metadata-only snapshots, LLM-draft labels, judge outputs, reports
English summary. Independent, offline experiments (October 2026) on whether the hosted Bocha Jev decision model (
bocha-jev-v1) is worth using inside a web-search evidence pipeline (candidate filter, evidence-block scorer, coverage judge), compared with a plain lexical rule baseline and the local Laya model. They were run while building thedsh-web-search-proplugin: 100 tasks (60 for tuning, 40 held out), about 2.2k search candidates, LLM-draft labels. What we saw: (1) for the fast title/snippet filter, rules are about as discriminative as Jev (AUC 0.91 vs 0.92) and Jev is better calibrated; (2) Jev's real value is scoring evidence blocks (nDCG@5 0.565 vs 0.378 for rules); (3) asking relevance and constraint satisfaction as separate questions is more robust than one mixed question; (4) a hybrid that sends only borderline / cross-language pairs to Jev gave the best need-hit rate at about half the requests of full Jev scoring; (5) a Jev coverage judge removes some false "covered" claims, but modestly; (6) zero-shot Laya multilingual was near random. Caveats: labels are unreviewed DeepSeek drafts, samples are small, harvests are single snapshots (2026-10-01 / 2026-10-02), one Jev model version, independent work not affiliated with Bocha, and this is not a general benchmark. Data are metadata only (no page text is redistributed). The headline r1 numbers can be recomputed withnpm run verify.
| Headline (r1, 60 tasks, DeepSeek-draft labels) | Rule | Jev | Laya |
|---|---|---|---|
| S4 filter AUC, relevance question (1368 candidates) | 0.909 | 0.915 | 0.555 |
| S4 filter calibration error (ECE, lower is better) | 0.220 | 0.050 | 0.504 |
| S4 test split: positive recall / candidates dropped (threshold chosen on calibration for recall ≥ 0.95) | 94.6% / 44.7% | 94.2% / 50.3% | 94.2% / 9.9% |
| S6 evidence-block scoring, nDCG@5 | 0.378 | 0.565 | 0.310 |
| Task-profile accuracy | 60.0% | n/a (all 422) | 26.7% |
| Held-out v2 (36-task Jev-comparable subset) | Need hit | Claimed-coverage precision | Jev requests (cold) |
|---|---|---|---|
| Rules + cross-lingual alignment | 79.8% | 71.8% | 0 |
| Hybrid: language-mismatch + borderline pairs | 83.0% | 76.0% | 74 |
| Full Jev scoring | 78.7% | 76.5% | 148 |
dsh-web-search-pro 是 DSH 宿主的搜索插件。0.2.0 的核心是一条证据管线:把多个来源的搜索结果去重、过滤、读取、分块、评分,在预算内选出带出处的证据摘录,并报告“哪些需求已覆盖、哪些还有缺口”,而不是把十条链接和全文丢给主模型。
管线里有几处需要“判断”:这个候选相关吗?它满足“只要 Node 22 以后的官方文档”这类语义约束吗?这个文本块是否直接回答了某个需求?这些摘录够回答吗?规则(词法重叠、正则、URL)能做一部分,但跨语言、同名实体、版本条件这类场景它会吃力。博查(Bocha)提供托管的决策模型 Jev(POST /v1/systemone,问题类型 noul 真值概率 / score 等级期望 / choice 选一个,输出是一次前向、不生成文字),开源的 Laya 提供了相同形状的本地版本。
本仓库回答的问题是:在这条管线里,Jev 在哪些环节比规则基线更好?好多少?花多少请求和延迟?本地的 Laya 能不能替代它? 它是一次独立评测,与博查无隶属关系,也不是通用基准。
flowchart LR
T[TaskSpec 与约束编译] --> R[S2 召回]
R --> N[S3 归一化/去重/硬过滤]
N --> S4{{S4 快速过滤<br/>标题+摘要}}
S4 --> F[S5 读取与分块]
F --> S6{{S6 证据评分<br/>需求×文本块}}
S6 --> K[S7 预算内选择]
K --> S8{{S8 覆盖判定}}
S8 -->|缺口且有预算| R
S8 -->|够了或达限| O[EvidencePack]
noul):只看标题 + 摘要,判断相关 / 满足语义约束 / 是否导航页;只丢高置信无关项,保召回。score,0–3 档):对每个(需求,文本块)对打分,决定哪些块进入证据包。noul):对规则声称“已覆盖”的需求,问“这些摘录本身是否足以回答”,用来减少假覆盖。规则基线始终可用;模型步骤失败或超额时回退规则。详见 docs/experiment-design.md。
| 实验 | 问题 | 数据 | 判定器 | 结果 |
|---|---|---|---|---|
| E0 | Jev 的真实接口与文档一致吗?单一相关性问题会怎样? | 一个样例(5 题) | jev | docs/e0-api-contract.md |
| r1 | S4 过滤、逐条约束、导航页、S6 评分、profile 分类,谁更好? | v1(60 任务,1368 候选,237 金标块) | rule / laya / jev | results/r1-20261001/ |
| M2b | 完整证据包管线(S3–S8)比“前 8 条 + 全文”好多少? | v1 | rule(+ jev 评分对照) | pack-m2b、pack-m2b-v2 |
| M2c | 摘录质量(IDF 预排序、取窗) | v1 | rule / jev | pack-m2c |
| M3a | 跨语言对齐;混合评分(只把部分对交给 Jev) | v1 | rule / hybrid / jev | pack-m3a |
| M3b | 通用标识符造成的假覆盖 | v1 | rule / hybrid / jev | pack-m3b |
| gatefix | S4 门限的跨语言修复 | v1、v2 | rule / hybrid / jev | v1、v2 |
| v2 留出 | 冻结参数后在没见过的 40 个任务上还成立吗? | v2(40 任务,865 候选,271 金标块) | rule / hybrid / jev | pack-v2-heldout |
| M9 | 覆盖判定能不能减少“假覆盖”? | v1 + v2 | jev(cover.sufficient.v1) | pack-m9-v1、pack-m9-v2 |
| 0.2.0 | 发布后复算;独立验收与摘录修复 | v1 + v2 | rule(+ 历史 Jev 缓存) | pack-020-*、independent-*、fixed-* |
| Laya | 本地模型能替代 Jev 吗? | E0 样例 + r1 | laya | docs/laya.md |
每个运行目录的说明在 results/INDEX.md;全部结果表见 docs/results.md;时间线见 docs/timeline.md。
以下全部基于未经人工复核的 LLM 初稿标注、小样本、单次采集、一个 Jev 版本;数字只用来排定开发顺序。
PRAGMA busy_timeout)被混合问题压到 0.033;r1 里 mixed 语言任务上,拆开问的正例召回 93.9%,混问 75.8%(总体 94.2% 对 90.8%)。但 zh 上混问略好,所以是“更稳”,不是“总是更好”。DatabaseSync)曾让 9 个无关块评 2 分并把需求显示为“已覆盖”;一个大块支持两个需求时,摘录丢了第二个需求的支持句却仍标已覆盖(独立验收发现,现有按块 ID 的指标看不出来)。见 docs/lessons.md。r1(60 个任务,所有 S4 四套题 + S6 + S1,来自 report.md,可用 npm run verify 复核):
| 判定器 | 请求数 | 输入 token | 平均批量 | 延迟 p50 / p95 |
|---|---|---|---|---|
| Jev(托管) | 486 | 4,558,926 | 19.4 | 632 / 2,288 ms |
| Laya(本地 MPS) | 484 | 1,771,962 | 19.5 | 564 / 1,127 ms |
score 问题按等级展开计费。token_budget_exceeded:4 个请求(2 个 profile 分类批、2 个 S6 批)被拒绝,服务返回的 counted_tokens 略高于 32,768,共 84 个失败行;服务不截断。官方文档写的是“每个问题连同共享 state”的上限,而这些请求里单个问题远小于此,看起来实际按整个请求的展开量计——这是我们的推断,未向博查确认(见 docs/e0-api-contract.md)。集成时发送前必须按预算切批、裁剪 state 与块长度。data/labels.*/ledger.summary.json)。不发布任何金额或账户余额。零依赖,Node ≥ 18:
npm run verify # node scripts/verify-metrics.mjs
npm run check # node scripts/check-publication.mjs(发布前检查:无路径、密钥、账户数据、页面正文)
verify 用 results/r1-20261001/results.jsonl.gz(逐条判定输出)和 data/labels.v1/(标注)重新计算 r1 的:gate 的 AUC(relevance / single 两套题,rule / laya / jev)、在 calibration 上取“召回 ≥ 0.95”的阈值、test 上的召回与丢弃比例与含金标准块候选的召回、S6 的 Spearman 与 nDCG@5,以及请求数、token、批量、延迟 p50/p95,并与 report.json 逐项比较,超出容差(默认 1e-6)退出码非 0。当前 84 / 84 项一致。
能复核什么,不能复核什么:r1 的全部数字可以复核。pack-* 系列的数字依赖页面文本块(评分、选择、金标匹配),而本仓库不含页面正文,所以只能阅读报告,不能重算;块哈希(data/candidates.* 里的 hash)让你在自己重新采集后检查页面是否漂移。
完整的 bench(采集、标注、判定器、报告)是公开的,在插件仓库 tag v0.2.0 的 bench/:https://github.com/anweat/dsh-web-search-pro/tree/v0.2.0/bench(它的 README 有全部参数说明)。
git clone https://github.com/anweat/dsh-web-search-pro && cd dsh-web-search-pro
git checkout v0.2.0 && pnpm install # Node 24
# 1. 采集(免费引擎,礼貌限速;搜索结果不可复现,结果会与本仓库的快照不同)
node --experimental-transform-types bench/src/harvest.ts --task-set v1 --fetch-top 4
node --experimental-transform-types bench/src/harvest.ts --task-set v2 --fetch-top 4
# 2. 标注初稿(付费,需要你自己的 DeepSeek key;设花费上限与余额下限守卫)
DEEPSEEK_API_KEY=... node --experimental-transform-types bench/src/label-llm.ts --task-set v1 --effort low --max-spend-cny <N> --min-balance-cny <M>
# 3. 判定器对照 r1(需要你自己的 Jev key;laya 需先启动本地 sidecar,见 docs/laya.md)
BOCHA_JEV_API_KEY=... node --experimental-transform-types bench/src/run-judges.ts --judges rule,laya,jev --split all --max-jev-requests 600 --run-id my-r1
node --experimental-transform-types bench/src/report.ts --run my-r1
# 4. 证据包离线评测(只读缓存;缺口才发请求,--allow-jev N 设上限)
BOCHA_JEV_API_KEY=... node --experimental-transform-types bench/src/eval-pack.ts --run-id my-pack --allow-jev 40
要点:
BOCHA_JEV_API_KEY 读取,只进 Authorization 头,不会被打印或缓存。脚本有硬性的请求次数上限和按条目缓存(重跑不重复计费)。pnpm run ... -- --flags 里多余的 -- 传给脚本,出现 unknown argument: --;直接用上面的 node --experimental-transform-types ... 命令。rubrics/,任务集在 tasks/,与 tag v0.2.0 的 bench/ 里的文件一致;只想验证接口契约可以跑 BOCHA_JEV_API_KEY=... node scripts/e0-probe.mjs(约 2.5k 输入 token;--dry-run 只打印请求)。results/judge-outputs/)只含输出,不含输入,不能直接重放(见 docs/results.md §8)。这是什么
tasks/:两套任务集(v1 60 个用于调参,v2 40 个留出),JSONL。data/candidates.v1|v2/:元数据快照——搜索结果的 URL、标题、摘要(snippet)、引擎状态与耗时,以及每个被抓取页面的抓取时间、状态、正文长度和每个文本块的 blockId / start / end / hash / length。不含任何页面正文、块文本、块标题和页面标题(scripts/strip-snapshots.mjs,脚本在 npm run check 里也被检验:没有 text 字段、没有超过 600 字符的字符串)。data/labels.v1|v2/:标注(候选相关度 0–3、逐约束 yes/no/unknown、导航页标记、每个需求的金标准证据块)与标注者元数据;ledger.summary.json 只有请求数与 token 总数。note 字段是标注模型写的一句话说明,规则是“≤ 80 字符才保留,否则删除”,实际最长 47 字符,没有删除任何一条。results/:各次运行的报告;r1 的逐条结果压缩为 results.jsonl.gz;results/judge-outputs/ 是三个判定缓存的打包(输出,按哈希键)。data/strip-summary.json):v1 删除页面文本约 292 万字符、块文本约 287 万字符;v2 约 258 万 / 255 万字符;搜索结果标题 / 摘要里的 2 个电子邮件地址(均在 v2)被替换为 [email]。报告里没有页面摘录,没有删除任何报告章节。限制(请务必读)
deepseek-flash,effort low)的未复核初稿,指标反映的是“与这份初稿的一致性”,不是与真值的一致性。标注输入与判定器同源,词法规则可能被高估。bocha-jev-v1(E0 时 API 报告的 checkpoint id 为 bocha-jev-v03);托管模型以后可能更新。-cached 报告里的 Jev 数字是历史缓存的重放,不是新鲜测量。