@furongjun1999/dsh-memory 0.4.11 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +552 -465
- package/codebuddy/CODEBUDDY.md +11 -3
- package/codebuddy/README.md +92 -90
- package/codebuddy/mcp.json +27 -27
- package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -169
- package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -144
- package/docs/README.md +143 -111
- package/docs/discipline/harnesses.yaml +244 -226
- package/docs/discipline/templates/full.md.tmpl +61 -61
- package/docs/discipline/templates/rules.mdc.tmpl +68 -0
- package/docs/discipline/templates/skill.md.tmpl +23 -23
- package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md +299 -299
- package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md +239 -239
- package/docs/eval/bench_lingshu_self/bench_self.py +140 -0
- package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
- package/docs/eval/bench_lingshu_self//347/201/265/346/236/242/350/207/252/345/272/223/347/253/257/345/210/260/347/253/257/346/243/200/347/264/242/345/256/236/346/265/213_v1.0.md +38 -0
- package/docs/eval//344/270/215/345/217/257/351/235/240/346/200/247/350/220/275/345/234/260_P0_v1.0.md +185 -0
- package/docs/eval//345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md +174 -174
- package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +422 -0
- package/docs/eval//346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md +223 -223
- package/docs/eval//347/253/257/345/210/260/347/253/257LoCoMoQA/345/220/214/345/217/243/345/276/204/345/257/271/347/205/247_v1.0.md +100 -0
- package/docs/eval//347/253/257/345/210/260/347/253/257/345/271/262/346/211/260/346/261/240/350/257/204/346/265/213_/347/241/256/345/256/232/346/200/247/350/243/201/345/206/263vsLLM_judge_v1.1.md +197 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v1.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v10.md +210 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v11.md +227 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v12.md +203 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v13.md +233 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v14.md +191 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v15.md +213 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v16.md +214 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v17.md +199 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v2.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v3.md +152 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v4.md +128 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v5.md +114 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v6.md +192 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v7.md +187 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v8.md +207 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v9.md +203 -0
- package/docs/{mdcg → hive}//344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md +165 -160
- package/docs/hive//344/273/244/347/211/214/350/257/255/344/271/211/344/277/256/346/255/243_/344/273/262/350/243/201/344/275/215_v0.1.md +76 -0
- package/docs/{mdcg → hive}//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.5.md +236 -236
- package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +202 -0
- package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -43
- package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +85 -0
- package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +102 -102
- package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +47 -0
- package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +519 -503
- package/docs/hive//350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +85 -85
- package/docs/hive//350/234/202/345/267/242/350/256/276/350/256/241_/347/220/206/350/256/272/345/257/271/351/275/220_v0.1.md +191 -0
- package/docs/hive//350/234/202/345/267/242/350/277/255/344/273/243_/345/256/217/350/247/202/344/270/216/347/276/244/344/275/223/350/260/203/345/272/246_v0.1.md +90 -0
- package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
- package/docs/images/lingshu-moonlight-covenant-poster.png +0 -0
- package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -216
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
- package/docs/mdcg/lingshu_tutorial.html +14449 -14449
- package/docs/mdcg/release_v0.4.11.md +49 -0
- package/docs/mdcg/release_v0.4.5.md +55 -55
- package/docs/mdcg/tool_table_v0.3.0.md +117 -117
- package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -600
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
- package/docs/mdcg//345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +275 -275
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
- package/docs/mdcg//346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +130 -130
- package/docs/mdcg//347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md +278 -278
- package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +172 -172
- package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +491 -491
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md +340 -340
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +588 -588
- package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -176
- package/docs/plans//345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +81 -81
- package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
- package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -242
- package/docs/theory//344/270/215/345/217/257/351/235/240/345/256/232/347/220/206/344/270/216/345/244/261/346/225/210/344/274/230/345/205/210/346/241/206/346/236/266_v0.3.md +365 -0
- package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -129
- package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -134
- package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -145
- package/docs/theory//347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +144 -144
- package/docs/theory//347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +198 -198
- package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -221
- package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -237
- package/docs//344/270/215/345/217/257/351/235/240/346/200/247/347/220/206/350/256/272_v0.1.md +343 -0
- package/docs//345/217/221/345/270/203/344/273/266/345/233/236/346/272/257/350/257/264/346/230/216_v0.1.md +82 -82
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +28 -2
- package/dsh/README.md +82 -82
- package/dsh/cordis.yml.example +139 -139
- package/dsh/update-lingshu.bat +11 -11
- package/lib/bridge.d.ts +9 -0
- package/lib/bridge.js +35 -0
- package/lib/hooks.js +36 -2
- package/lib/index.js +7 -1
- package/lib/lib/roleplay_web.js +116 -29
- package/lib/lib/token_store.d.ts +7 -1
- package/lib/lib/token_store.js +12 -3
- package/md_cg/__init__.py +7 -7
- package/md_cg/audit.py +379 -368
- package/md_cg/autonomy.py +287 -287
- package/md_cg/backfill.py +1328 -1327
- package/md_cg/backfill_bigdomain.py +34 -34
- package/md_cg/backfill_bucket_zh.py +35 -0
- package/md_cg/bench6_arms.py +410 -410
- package/md_cg/bench6_common.py +230 -230
- package/md_cg/bench6_competitors.py +212 -212
- package/md_cg/bench_axis_domain.py +257 -257
- package/md_cg/bench_blind_comp.py +308 -308
- package/md_cg/bench_e2e_judge.py +532 -0
- package/md_cg/bench_e2e_locomo_qa.py +368 -0
- package/md_cg/bench_e2e_qa.py +256 -0
- package/md_cg/bench_en_atoms_public.py +230 -230
- package/md_cg/bench_governance.py +348 -348
- package/md_cg/bench_lme_zh.py +410 -410
- package/md_cg/bench_locomo.py +121 -121
- package/md_cg/bench_locomo_zh.py +450 -450
- package/md_cg/bench_locomo_zh_public.py +147 -147
- package/md_cg/bench_longmem.py +112 -112
- package/md_cg/bench_membench.py +632 -632
- package/md_cg/bench_p0.py +149 -149
- package/md_cg/bench_progressive.py +287 -287
- package/md_cg/bench_role_views.py +238 -238
- package/md_cg/bench_task_ab.py +243 -243
- package/md_cg/bench_task_ab_llm.py +408 -408
- package/md_cg/bench_unified_en.py +204 -204
- package/md_cg/bench_zh_mad.py +601 -601
- package/md_cg/blindspot_tickets.py +123 -123
- package/md_cg/branches.py +301 -285
- package/md_cg/build_postings.py +73 -73
- package/md_cg/ccgc.py +1006 -948
- package/md_cg/census.py +132 -132
- package/md_cg/chain.py +315 -300
- package/md_cg/codeindex.py +531 -531
- package/md_cg/coldverify.py +292 -292
- package/md_cg/comment_gate.py +337 -337
- package/md_cg/cond_compose.py +190 -190
- package/md_cg/cond_facts.py +154 -154
- package/md_cg/cond_template.json +106 -106
- package/md_cg/condition_anchor.py +142 -142
- package/md_cg/conformance.py +726 -726
- package/md_cg/consistency.py +717 -717
- package/md_cg/consolidate.py +1537 -1439
- package/md_cg/corpus.py +110 -110
- package/md_cg/crosscheck.py +1098 -1097
- package/md_cg/crypto.py +3 -1
- package/md_cg/d_meta.py +310 -310
- package/md_cg/datapath.py +78 -18
- package/md_cg/docindex.py +473 -473
- package/md_cg/eval_common.py +575 -575
- package/md_cg/evidence.py +4 -2
- package/md_cg/evolution.py +477 -477
- package/md_cg/export.py +222 -220
- package/md_cg/forgetting.py +581 -581
- package/md_cg/fsutil.py +377 -329
- package/md_cg/hotcache.py +48 -7
- package/md_cg/hyperedge.py +251 -251
- package/md_cg/identity.py +390 -390
- package/md_cg/insight.py +500 -500
- package/md_cg/interop.py +338 -0
- package/md_cg/judgment_manifest.py +177 -0
- package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
- package/md_cg/lexicon/build_standard_en.py +171 -171
- package/md_cg/lexicon/expand_en_zh.py +211 -211
- package/md_cg/lifecycle.py +272 -272
- package/md_cg/linkref.py +280 -280
- package/md_cg/links.py +140 -107
- package/md_cg/mcp_server.py +403 -55
- package/md_cg/md_whitebox.py +345 -345
- package/md_cg/mdcg.py +783 -233
- package/md_cg/mdcos.py +500 -70
- package/md_cg/metacognition.py +591 -591
- package/md_cg/migrate.py +119 -119
- package/md_cg/migrate_aeis.py +221 -221
- package/md_cg/migrate_roleplay.py +293 -293
- package/md_cg/migrate_wisdom_graph.py +360 -360
- package/md_cg/mreview/__init__.py +25 -25
- package/md_cg/mreview/__main__.py +110 -110
- package/md_cg/mreview/bundle.py +178 -178
- package/md_cg/mreview/candidates.py +262 -262
- package/md_cg/mreview/govern.py +694 -693
- package/md_cg/mreview/locate.py +939 -939
- package/md_cg/mreview/pipeline.py +728 -728
- package/md_cg/mreview/rules/duplication.json +21 -21
- package/md_cg/mreview/rules/field_coverage.json +54 -54
- package/md_cg/mreview/rules/source_license.json +21 -21
- package/md_cg/mreview/rules/template_flow.json +21 -21
- package/md_cg/mreview/ruleset.py +252 -252
- package/md_cg/nodefile.py +575 -575
- package/md_cg/pooling.py +484 -472
- package/md_cg/postings.py +300 -298
- package/md_cg/predict.py +1100 -1100
- package/md_cg/progressive.py +123 -123
- package/md_cg/protect.py +272 -272
- package/md_cg/protocol/md_cg_gate.proto +33 -33
- package/md_cg/protocol.py +372 -372
- package/md_cg/provenance.py +582 -582
- package/md_cg/reach.py +453 -453
- package/md_cg/readcache.py +143 -0
- package/md_cg/reconcile.py +228 -0
- package/md_cg/refindex.py +833 -833
- package/md_cg/refine.py +604 -604
- package/md_cg/review_cli.py +170 -0
- package/md_cg/roleviews.py +89 -89
- package/md_cg/routing.py +393 -365
- package/md_cg/run_tests.py +211 -0
- package/md_cg/scrub.py +13 -3
- package/md_cg/security.py +128 -18
- package/md_cg/self_state.py +1029 -1029
- package/md_cg/selfreport.py +152 -151
- package/md_cg/semantic/__init__.py +10 -10
- package/md_cg/semantic/canonical.py +122 -122
- package/md_cg/semantic/en_normalizer.py +364 -364
- package/md_cg/semantic/en_zh_map.json +28694 -0
- package/md_cg/semantic/export_en_zh_map.py +64 -0
- package/md_cg/semantic/unify.py +45 -0
- package/md_cg/semantic/zh_en_atoms.py +139 -139
- package/md_cg/signer.py +7 -4
- package/md_cg/sources.py +816 -582
- package/md_cg/statushdr.py +179 -179
- package/md_cg/stg.py +54 -37
- package/md_cg/subgraph.py +729 -729
- package/md_cg/sustain.py +35 -5
- package/md_cg/tasks.py +470 -470
- package/md_cg/test_access_hints.py +147 -0
- package/md_cg/test_action_derive.py +203 -203
- package/md_cg/test_audit_rotate.py +270 -270
- package/md_cg/test_autonomy.py +143 -143
- package/md_cg/test_bench_governance.py +102 -102
- package/md_cg/test_blindspot_tickets.py +166 -166
- package/md_cg/test_branch_discard_tombstone.py +136 -0
- package/md_cg/test_branches.py +13 -3
- package/md_cg/test_ccg_perturb.py +184 -184
- package/md_cg/test_ccgc.py +433 -433
- package/md_cg/test_census_prune.py +81 -81
- package/md_cg/test_chain_read_isolate.py +168 -0
- package/md_cg/test_cond_compose_anchors.py +76 -76
- package/md_cg/test_cond_match.py +165 -165
- package/md_cg/test_condition_anchor.py +81 -81
- package/md_cg/test_d_meta.py +412 -412
- package/md_cg/test_datapath_device_name.py +203 -0
- package/md_cg/test_datapath_root.py +199 -199
- package/md_cg/test_emit_negtail_cache.py +156 -0
- package/md_cg/test_en_pipeline.py +22 -2
- package/md_cg/test_gain_gate.py +212 -212
- package/md_cg/test_govern_directread.py +421 -0
- package/md_cg/test_health_scale.py +173 -173
- package/md_cg/test_hive_ingest.py +285 -0
- package/md_cg/test_hot_cold.py +215 -215
- package/md_cg/test_hyperedge.py +245 -245
- package/md_cg/test_i26_empty_first_write.py +116 -0
- package/md_cg/test_i27_e041_identity.py +128 -0
- package/md_cg/test_i28_hotcache_prodpath.py +122 -0
- package/md_cg/test_i32_hotcache_env_key.py +218 -0
- package/md_cg/test_identity_attribution.py +96 -15
- package/md_cg/test_index_durability.py +17 -3
- package/md_cg/test_interop.py +95 -0
- package/md_cg/test_interop_judgment.py +228 -0
- package/md_cg/test_issue39_utf8_stdio.py +273 -0
- package/md_cg/test_lifecycle.py +309 -309
- package/md_cg/test_linkref.py +306 -306
- package/md_cg/test_links_concurrent_write.py +188 -0
- package/md_cg/test_lock.py +43 -43
- package/md_cg/test_md_access_parity.py +255 -255
- package/md_cg/test_md_writepath.py +345 -345
- package/md_cg/test_mdstore_search_parity.py +160 -0
- package/md_cg/test_merge_upsert.py +168 -0
- package/md_cg/test_mr_m2.py +587 -587
- package/md_cg/test_mr_m3.py +710 -710
- package/md_cg/test_mr_m4.py +485 -485
- package/md_cg/test_n123_derive_expiry_chain.py +205 -0
- package/md_cg/test_n130_verify_falsified_protect.py +185 -0
- package/md_cg/test_n131_merge_gate.py +205 -0
- package/md_cg/test_p0.py +250 -250
- package/md_cg/test_p1.py +316 -316
- package/md_cg/test_p10_identity.py +173 -173
- package/md_cg/test_p11_consistency.py +233 -233
- package/md_cg/test_p12_metacognition.py +212 -212
- package/md_cg/test_p13_encryption.py +241 -241
- package/md_cg/test_p14_sustain.py +249 -249
- package/md_cg/test_p15_scrub.py +280 -280
- package/md_cg/test_p16_self_state.py +301 -301
- package/md_cg/test_p17_predict.py +354 -354
- package/md_cg/test_p18_whitebox.py +171 -171
- package/md_cg/test_p19_migrate_roleplay.py +149 -149
- package/md_cg/test_p1x_ref_root.py +160 -0
- package/md_cg/test_p20_evolution.py +315 -315
- package/md_cg/test_p21_tokens.py +293 -270
- package/md_cg/test_p22_theory.py +175 -175
- package/md_cg/test_p23_links.py +311 -311
- package/md_cg/test_p24_evidence.py +227 -227
- package/md_cg/test_p25_weights.py +156 -156
- package/md_cg/test_p26_refindex.py +416 -416
- package/md_cg/test_p27_docindex.py +16 -7
- package/md_cg/test_p28_refcheck.py +305 -305
- package/md_cg/test_p29_session_ingest_export.py +354 -333
- package/md_cg/test_p2_mcp.py +3 -0
- package/md_cg/test_p3.py +11 -2
- package/md_cg/test_p30_maintain.py +330 -330
- package/md_cg/test_p31_insight.py +534 -534
- package/md_cg/test_p32_backfill.py +7 -1
- package/md_cg/test_p33_ccg_wiring.py +293 -293
- package/md_cg/test_p34_crosscheck.py +331 -331
- package/md_cg/test_p35_conditioned_claim.py +252 -252
- package/md_cg/test_p36_kp_align.py +230 -230
- package/md_cg/test_p37_condition_space.py +248 -248
- package/md_cg/test_p38_concurrent_flush.py +102 -0
- package/md_cg/test_p38_contextualize.py +273 -273
- package/md_cg/test_p39_verify_flow.py +153 -0
- package/md_cg/test_p39_vision_evidence.py +369 -369
- package/md_cg/test_p40_refine_worklist.py +241 -241
- package/md_cg/test_p41_evolve_patrol.py +224 -224
- package/md_cg/test_p42_provenance.py +269 -269
- package/md_cg/test_p43_pooling.py +412 -398
- package/md_cg/test_p44_md_whitebox.py +231 -231
- package/md_cg/test_p45_session_identity.py +219 -219
- package/md_cg/test_p46_unit_scope.py +272 -272
- package/md_cg/test_p47_session_view.py +316 -0
- package/md_cg/test_p4_fuzzy.py +223 -223
- package/md_cg/test_p5_semantic.py +226 -226
- package/md_cg/test_p6_consolidate.py +440 -387
- package/md_cg/test_p7_goals_recent.py +202 -202
- package/md_cg/test_p8_subgraph_chain.py +200 -200
- package/md_cg/test_p9_forget_protect.py +231 -231
- package/md_cg/test_predict_beta.py +135 -135
- package/md_cg/test_preflight_failclosed.py +100 -100
- package/md_cg/test_progressive.py +146 -146
- package/md_cg/test_propose_tail_index.py +157 -0
- package/md_cg/test_protocol.py +243 -243
- package/md_cg/test_reach.py +378 -378
- package/md_cg/test_reach_keys.py +201 -201
- package/md_cg/test_read_clip.py +141 -141
- package/md_cg/test_read_scope_b27.py +277 -0
- package/md_cg/test_readcache_default_on.py +168 -0
- package/md_cg/test_readcache_precise_inval.py +270 -0
- package/md_cg/test_readcache_prodpath.py +203 -0
- package/md_cg/test_reconcile_v0.py +294 -0
- package/md_cg/test_retr_gates_prodpath.py +140 -0
- package/md_cg/test_retr_s1.py +344 -340
- package/md_cg/test_retr_s1b.py +276 -209
- package/md_cg/test_retr_s3.py +194 -194
- package/md_cg/test_retr_s4.py +163 -163
- package/md_cg/test_retr_s5.py +200 -200
- package/md_cg/test_retr_s6.py +157 -157
- package/md_cg/test_retr_s7.py +392 -384
- package/md_cg/test_retr_s8_time.py +369 -316
- package/md_cg/test_retr_s9_edges.py +286 -286
- package/md_cg/test_retr_s9_entity_ctx.py +9 -3
- package/md_cg/test_retr_score_once.py +208 -0
- package/md_cg/test_review_conformance.py +367 -367
- package/md_cg/test_review_onepass.py +170 -0
- package/md_cg/test_role_views.py +354 -354
- package/md_cg/test_rrf_graph_seed_cache.py +154 -0
- package/md_cg/test_security_audit.py +155 -0
- package/md_cg/test_security_audit_b26.py +161 -0
- package/md_cg/test_security_audit_v21.py +250 -0
- package/md_cg/test_sem_noise.py +242 -242
- package/md_cg/test_semantic_canonical.py +16 -2
- package/md_cg/test_session_isolation.py +168 -0
- package/md_cg/test_snapshot_autoclose.py +187 -0
- package/md_cg/test_subproc_encoding.py +192 -192
- package/md_cg/test_sustain_mutual.py +153 -153
- package/md_cg/test_tail_watermark_race.py +208 -0
- package/md_cg/test_tasks.py +409 -409
- package/md_cg/test_tenant_env_override_warn.py +139 -0
- package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
- package/md_cg/test_tool_face.py +189 -189
- package/md_cg/test_transfer.py +180 -180
- package/md_cg/test_trust.py +361 -361
- package/md_cg/test_twophase.py +286 -286
- package/md_cg/test_v14_fixes.py +38 -20
- package/md_cg/test_validity_filter.py +280 -280
- package/md_cg/test_verify_answer.py +138 -138
- package/md_cg/test_verify_dirty_reconcile.py +157 -0
- package/md_cg/test_wisdom_md_store.py +292 -292
- package/md_cg/test_writelimit.py +197 -197
- package/md_cg/test_writepipe.py +214 -214
- package/md_cg/theory.py +6 -3
- package/md_cg/tokens.py +85 -14
- package/md_cg/tool_face.py +260 -260
- package/md_cg/trust.py +986 -950
- package/md_cg/twophase.py +231 -231
- package/md_cg/units.py +668 -667
- package/md_cg/vision_evidence.py +667 -666
- package/md_cg/weights.py +624 -624
- package/md_cg/whitebox.py +527 -527
- package/md_cg/whitebox_kb/__init__.py +37 -37
- package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
- package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
- package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
- package/md_cg/whitebox_kb/engine.py +310 -310
- package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
- package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
- package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
- package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
- package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
- package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
- package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
- package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
- package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
- package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
- package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
- package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
- package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
- package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
- package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
- package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
- package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
- package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
- package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
- package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
- package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
- package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
- package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
- package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
- package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
- package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
- package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
- package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
- package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
- package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
- package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
- package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
- package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
- package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
- package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
- package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
- package/md_cg/writelimit.py +356 -356
- package/md_cg/writepipe.py +20 -8
- package/package.json +101 -96
- package/skills/plugin.json +54 -54
- package/skills/skills/designer-perspective/SKILL.md +158 -158
- package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
- package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
- package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
- package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
- package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
- package/skills/skills/designer-perspective/scripts/designer.py +545 -545
- package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
- package/skills/skills/designer-perspective/tests/selftest.py +61 -61
- package/skills/skills/lingshu-browser/SKILL.md +60 -60
- package/skills/skills/lingshu-compiler/SKILL.md +56 -56
- package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
- package/skills/skills/lingshu-graph/SKILL.md +63 -63
- package/skills/skills/lingshu-net/SKILL.md +48 -48
- package/skills/skills/lingshu-os/SKILL.md +64 -64
- package/skills/skills/lingshu-pylang/SKILL.md +71 -71
- package/src/bridge.ts +33 -0
- package/src/hooks.ts +38 -2
- package/src/index.ts +526 -518
- package/src/lib/datapath.ts +326 -326
- package/src/lib/mdcg_client.ts +413 -413
- package/src/lib/mutual.ts +428 -428
- package/src/lib/prompt_safety.ts +62 -62
- package/src/lib/python_path.ts +71 -71
- package/src/lib/roleplay_web.ts +116 -29
- package/src/lib/token_store.ts +13 -3
- package/src/tools.ts +212 -212
- package/zcode/AGENTS.md +11 -3
- package/zcode/README.md +41 -41
- /package/docs/{mdcg → hive}//344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md" +0 -0
package/md_cg/bench6_arms.py
CHANGED
|
@@ -1,411 +1,411 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""六系统横评(bench6)· 主进程臂:灵枢 / 纯向量 RAG + 统一评分。
|
|
3
|
-
|
|
4
|
-
四家 LLM 竞品(mem0/Graphiti/GraphRAG/Letta)依赖互斥,跑在各自 venv 的独立
|
|
5
|
-
脚本里(外部评测工作区的 bench6 适配脚本),只回吐 {qid: [id...]} 的 JSON;本模块
|
|
6
|
-
读回后与灵枢/向量臂走**同一个** bc.rows_from_hits → ec.summarize,保证六家同口径
|
|
7
|
-
(排名判据复用 ec.first_evidence_rank,指标复用 ec.summarize,均不重造)。
|
|
8
|
-
|
|
9
|
-
灵枢三种检索口径(同一份中文层 + 英文原文,只变检索路):
|
|
10
|
-
lex : 单词法路,且建库不加 tags/condition_space——复现公开参考量级
|
|
11
|
-
(词法 hit@1≈0.936)的**回归锚**,用于确认本次口径没有漂移
|
|
12
|
-
rrf4 : 四路 RRF(lexical,bucket,entity,graph)+ 传 context——用户选定口径
|
|
13
|
-
rrf4_noref : 四路 RRF 不传 context——名义四路,量化条件约束路的净效应
|
|
14
|
-
|
|
15
|
-
## 为什么灵枢要建两个库而不是一个
|
|
16
|
-
lex 臂必须与 `bench_locomo_zh_public.build_pool` **逐字同口径**(无 tags、无
|
|
17
|
-
condition_space)才能作回归锚;而 rrf4 臂按用户口径要喂 entity 路(tags)与
|
|
18
|
-
bucket 路(condition_space)。建库参数不同 → 目录不同 → 拆成两个 ROOT,避免
|
|
19
|
-
"复用已建库"逻辑把两种口径混成一个。
|
|
20
|
-
|
|
21
|
-
## 诚实边界
|
|
22
|
-
locomo-zh-500 是**单域**会话语料,且查询侧是**无情境标注**的关键词串。bucket 路
|
|
23
|
-
要求读写两侧 `route_key` 同构(routing.py 模块头「风险2」)——写侧有域、读侧
|
|
24
|
-
没有,故条件路由在本语料上预期无区分力。这一点由实测的桶健康度取证,不预设。
|
|
25
|
-
"""
|
|
26
|
-
from __future__ import annotations
|
|
27
|
-
|
|
28
|
-
import json
|
|
29
|
-
import math
|
|
30
|
-
import os
|
|
31
|
-
import shutil
|
|
32
|
-
import sys
|
|
33
|
-
import time
|
|
34
|
-
import urllib.error
|
|
35
|
-
import urllib.request
|
|
36
|
-
|
|
37
|
-
HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
38
|
-
for _p in (HERE, os.path.join(HERE, "md_cg")):
|
|
39
|
-
if _p not in sys.path:
|
|
40
|
-
sys.path.insert(0, _p)
|
|
41
|
-
|
|
42
|
-
from md_cg import bench6_common as bc # noqa: E402
|
|
43
|
-
from md_cg import eval_common as ec # noqa: E402
|
|
44
|
-
|
|
45
|
-
ROOT_BASE = os.path.join(HERE, "_md_cg_eval_bench6") # .gitignore 的 /_md_cg_eval_*/ 已覆盖
|
|
46
|
-
|
|
47
|
-
# 条件约束路的查询侧情境:所有题共用同一份默认情境(查询串本身无情境标注)。
|
|
48
|
-
# 与建库侧 condition_space 同构 → route_key 两侧落在同一键上。这是 bucket 路能被
|
|
49
|
-
# 开启的唯一合法构造方式;若查询侧能精确给出每题的场景/域,那已是使用 qrels 作弊。
|
|
50
|
-
QUERY_CONTEXT = {
|
|
51
|
-
"observation_position": "会话陈述",
|
|
52
|
-
"observation_tool": "会话记录",
|
|
53
|
-
"existence_constraint": "公开",
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# 生效条件:形参 c 若提供映射接口,则取 c["zh_fields"](缺失或假值回落 {})再取其 "condition"(缺失或假值回落 {}),返回三槽 observation_position/observation_tool/existence_constraint,各自以 cond.get(中文键, "") 取值——中文键缺失时回落空串,键存在而值为 None 时结果即为 None(不回落)。
|
|
58
|
-
def cond_of(c):
|
|
59
|
-
"""zh_fields.condition(中文三槽)→ mdcos 期望的英文槽名。
|
|
60
|
-
|
|
61
|
-
只映射 zh_fields 里**真实存在**的三槽,不臆造 time_window(写入侧会自行补)。
|
|
62
|
-
"""
|
|
63
|
-
cond = (c.get("zh_fields") or {}).get("condition") or {}
|
|
64
|
-
return {"observation_position": cond.get("观测位置", ""),
|
|
65
|
-
"observation_tool": cond.get("观测工具", ""),
|
|
66
|
-
"existence_constraint": cond.get("存在约束", "")}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# 生效条件:形参 c 若提供映射接口,则 f = c["zh_fields"] 为假值(缺失/None/{})时当作 {},返回 [str(f["identity"] 或 "")] + [str(t) for t in (f["terms"] 或 [])]:identity 缺失或假值时首元素为空串(列表恒有 1 项),terms 缺失或假值时只有首元素。
|
|
70
|
-
def tags_of(c):
|
|
71
|
-
"""喂 entity 路的裸词 tags = identity + terms。
|
|
72
|
-
|
|
73
|
-
刻意不加 `ent:` 前缀:`mdcos._path_entity` 的判据是 `t in query or query in t`,
|
|
74
|
-
带前缀的标签在自然查询下永不命中(既有实测教训)。也不加 `domain:`——那会
|
|
75
|
-
劫持 route_key 的 domain 分支,把 bucket 路变成按场景分桶,而查询侧无法复现
|
|
76
|
-
同一场景键(见模块头「诚实边界」)。
|
|
77
|
-
"""
|
|
78
|
-
f = c.get("zh_fields") or {}
|
|
79
|
-
return [str(f.get("identity") or "")] + [str(t) for t in (f.get("terms") or [])]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# 生效条件:类无 __init__,实例化无需任何形参;其 describe_ingest(nids) 对任意 nids(含空)恒返回 [],而 reset()、add(nid, text)、search(query, k=5) 对任意实参一律抛 NotImplementedError。
|
|
83
|
-
class Adapter:
|
|
84
|
-
"""统一适配接口。六家一律只回吐 id 列表,指标计算交回 bench6_common。"""
|
|
85
|
-
name = "adapter"
|
|
86
|
-
|
|
87
|
-
# 生效条件:无可选/必需形参,任何调用一律抛 NotImplementedError(基类接口桩)。
|
|
88
|
-
def reset(self):
|
|
89
|
-
raise NotImplementedError
|
|
90
|
-
|
|
91
|
-
# 生效条件:对任意 nid 与 text 一律抛 NotImplementedError(形参不参与任何判断)。
|
|
92
|
-
def add(self, nid, text):
|
|
93
|
-
raise NotImplementedError
|
|
94
|
-
|
|
95
|
-
# 生效条件:对任意 query 与任意 k(默认 5)一律抛 NotImplementedError,不返回结果。
|
|
96
|
-
def search(self, query, k=5):
|
|
97
|
-
raise NotImplementedError
|
|
98
|
-
|
|
99
|
-
# 生效条件:对任意 nids(包括空列表或 None)都直接返回空列表 [],不读取任何存储。
|
|
100
|
-
def describe_ingest(self, nids):
|
|
101
|
-
"""回读真实存储内容样本,用于取证「入库语言与入库形态」。"""
|
|
102
|
-
return []
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
# 生效条件:必须以 rows、variant、paths 三个必需形参构造(context 默认 None、with_meta 默认 False、rebuild 默认 False 可选),构造后 search(query, k=5) 是否向 search_rrf 传 context 由 context 是否为 None 决定,describe_ingest(nids)/bucket_health() 的取证内容取决于 variant 对应 root 库的索引状态。
|
|
106
|
-
class LingshuAdapter(Adapter):
|
|
107
|
-
"""灵枢臂:进程内 MdCGOS。
|
|
108
|
-
|
|
109
|
-
with_meta=True 时三口径共用一库(lex 需与公开脚本同库,故 lex 单独建)。
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
name = "lingshu"
|
|
113
|
-
|
|
114
|
-
# 生效条件:root 固定为 os.path.join(ROOT_BASE, variant);rebuild 为真且 os.path.isdir(root) 为真时先 rmtree,索引中已有节点数 ≥ len(rows) 时直接 return(幂等复用、不写库),否则按 rows 逐条 add(with_meta 为真时同时补 tags=tags_of(c)、condition_space=cond_of(c))后 flush。
|
|
115
|
-
def __init__(self, rows, variant, paths, context=None, with_meta=False,
|
|
116
|
-
rebuild=False):
|
|
117
|
-
from md_cg.bench_locomo_zh_public import body_of
|
|
118
|
-
from md_cg.mdcos import MdCGOS
|
|
119
|
-
|
|
120
|
-
self.variant = variant
|
|
121
|
-
self.paths = tuple(paths)
|
|
122
|
-
self.context = context
|
|
123
|
-
self._body_of = body_of
|
|
124
|
-
root = os.path.join(ROOT_BASE, variant)
|
|
125
|
-
self.root = root
|
|
126
|
-
if rebuild and os.path.isdir(root):
|
|
127
|
-
shutil.rmtree(root, ignore_errors=True)
|
|
128
|
-
self.cg = MdCGOS(root, autoflush=500)
|
|
129
|
-
if len(self.cg.index["nodes"]) >= len(rows):
|
|
130
|
-
return # 幂等复用
|
|
131
|
-
t0 = time.time()
|
|
132
|
-
for c in rows:
|
|
133
|
-
kw = {}
|
|
134
|
-
if with_meta:
|
|
135
|
-
kw["tags"] = tags_of(c)
|
|
136
|
-
kw["condition_space"] = cond_of(c)
|
|
137
|
-
self.cg.add(c["id"], body_of(c), layer="knowledge",
|
|
138
|
-
eval_src="bench6:locomo-zh-500",
|
|
139
|
-
verification_basis="data", **kw)
|
|
140
|
-
self.cg.flush()
|
|
141
|
-
print(" [lingshu/%s] 建库 %d 节点 %.1fs"
|
|
142
|
-
% (variant, len(self.cg.index["nodes"]), time.time() - t0))
|
|
143
|
-
|
|
144
|
-
# 生效条件:给定 query 与 k(默认 5)即调用 self.cg.search_rrf(k=k、paths=self.paths、judge=False、record=False),仅当 self.context 不为 None 时附加 context 参数,返回每个结果 r 的 r[0]["id"] 组成的列表。
|
|
145
|
-
def search(self, query, k=5):
|
|
146
|
-
kw = {"context": self.context} if self.context is not None else {}
|
|
147
|
-
res, _meta = self.cg.search_rrf(query, k=k, paths=self.paths,
|
|
148
|
-
judge=False, record=False, **kw)
|
|
149
|
-
return [r[0]["id"] for r in res]
|
|
150
|
-
|
|
151
|
-
# 生效条件:只遍历 nids[:2],节点索引中 .get(nid) 为假值(缺失)的 nid 被跳过,其余按 os.path.join(self.cg.root, e["path"]) 读文件头 300 字符,抛 OSError 时 file_head 保持空串,输出各字段用 e.get(缺键为 None)。
|
|
152
|
-
def describe_ingest(self, nids):
|
|
153
|
-
"""回读真实落盘内容(索引元数据 + 文件头),取证入库语言与形态。
|
|
154
|
-
|
|
155
|
-
不走 `cg.get`:其返回形状随层不同,且读缓存会介入;直接按索引 path 读
|
|
156
|
-
文件是最贴近"磁盘上真实存了什么"的取证方式。
|
|
157
|
-
"""
|
|
158
|
-
out = []
|
|
159
|
-
for nid in nids[:2]:
|
|
160
|
-
e = self.cg.index["nodes"].get(nid)
|
|
161
|
-
if not e:
|
|
162
|
-
continue
|
|
163
|
-
head = ""
|
|
164
|
-
try:
|
|
165
|
-
with open(os.path.join(self.cg.root, e["path"]), encoding="utf-8") as f:
|
|
166
|
-
head = f.read()[:300]
|
|
167
|
-
except OSError:
|
|
168
|
-
pass
|
|
169
|
-
out.append({"id": nid, "layer": e.get("layer"), "tags": e.get("tags"),
|
|
170
|
-
"bucket": e.get("bucket"),
|
|
171
|
-
"condition_space": e.get("condition_space"),
|
|
172
|
-
"file_head": head})
|
|
173
|
-
return out
|
|
174
|
-
|
|
175
|
-
# 生效条件:无参数,遍历 self.cg.index["nodes"] 各节点的 e.get("bucket"),其缺失或为假值(None/空串等)时归入 "<none>" 计数,再把计数字典交 routing.bucket_health 并返回其结果。
|
|
176
|
-
def bucket_health(self):
|
|
177
|
-
"""桶健康度自检(routing.bucket_health):取证条件路由是否有区分力。"""
|
|
178
|
-
from md_cg import routing
|
|
179
|
-
counts = {}
|
|
180
|
-
for e in self.cg.index["nodes"].values():
|
|
181
|
-
b = e.get("bucket") or "<none>"
|
|
182
|
-
counts[b] = counts.get(b, 0) + 1
|
|
183
|
-
return routing.bucket_health(counts)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
# 生效条件:无必需构造形参,base 为假值(None/空串)时先回落 os.environ["BENCH6_EMBED_BASE"]、再回落 "http://127.0.0.1:1234/v1" 并 rstrip("/"),model 为假值时回落 os.environ["BENCH6_EMBED_MODEL"]、再回落空串 "",timeout 缺省为 30。
|
|
187
|
-
class VectorRagAdapter(Adapter):
|
|
188
|
-
"""纯向量 RAG 基线(零 LLM):英文原文直嵌入 + 余弦 Top-k。
|
|
189
|
-
|
|
190
|
-
作为**下界锚**:无结构化、无图、无实体/条件路。embedding 走本地
|
|
191
|
-
127.0.0.1:1234(OpenAI 兼容),与既有竞品探针同源,不引入新依赖。
|
|
192
|
-
"""
|
|
193
|
-
|
|
194
|
-
name = "vector_rag"
|
|
195
|
-
|
|
196
|
-
# 生效条件:base 依次按 base 形参 → os.environ.get("BENCH6_EMBED_BASE") → "http://127.0.0.1:1234/v1" 取值(每级为空串/None 均继续回落)再去掉尾部 "/",model 依次按 model 形参 → os.environ.get("BENCH6_EMBED_MODEL") → "" 取值(空串也回落),timeout 直接取形参(含 0),ids/vecs 置 []、_dim 置 0。
|
|
197
|
-
def __init__(self, base=None, model=None, timeout=30):
|
|
198
|
-
self.base = (base or os.environ.get("BENCH6_EMBED_BASE")
|
|
199
|
-
or "http://127.0.0.1:1234/v1").rstrip("/")
|
|
200
|
-
self.model = model or os.environ.get("BENCH6_EMBED_MODEL") or ""
|
|
201
|
-
self.timeout = timeout
|
|
202
|
-
self.ids = []
|
|
203
|
-
self.vecs = []
|
|
204
|
-
self._dim = 0
|
|
205
|
-
|
|
206
|
-
# 生效条件:以 self.base + path 为 URL、method="POST"、JSON 编码的 payload 为 body、Content-Type: application/json、超时 self.timeout 发出请求,返回响应体按 UTF-8 解码后 json.loads 的对象。
|
|
207
|
-
def _post(self, path, payload):
|
|
208
|
-
req = urllib.request.Request(
|
|
209
|
-
self.base + path, method="POST",
|
|
210
|
-
data=json.dumps(payload).encode("utf-8"),
|
|
211
|
-
headers={"Content-Type": "application/json"})
|
|
212
|
-
with urllib.request.urlopen(req, timeout=self.timeout) as r:
|
|
213
|
-
return json.loads(r.read().decode("utf-8"))
|
|
214
|
-
|
|
215
|
-
# 生效条件:self.model 为真值时直接返回;否则请求 self.base + "/models",从 data.get("data") 筛出 id 非空的模型名列表,该列表为空时抛 RuntimeError,否则优先取名字含 embed/bge/gte/m3 的第一个,无匹配则取 ids[0],写入 self.model 后返回。
|
|
216
|
-
def resolve_model(self):
|
|
217
|
-
"""未显式指定时,从 /models 取第一个 embedding 模型。"""
|
|
218
|
-
if self.model:
|
|
219
|
-
return self.model
|
|
220
|
-
req = urllib.request.Request(self.base + "/models")
|
|
221
|
-
with urllib.request.urlopen(req, timeout=15) as r:
|
|
222
|
-
data = json.loads(r.read().decode("utf-8"))
|
|
223
|
-
ids = [m.get("id") for m in (data.get("data") or []) if m.get("id")]
|
|
224
|
-
if not ids:
|
|
225
|
-
raise RuntimeError("embedding 服务未返回任何模型:%s" % self.base)
|
|
226
|
-
# 优先明显是 embedding 的模型名
|
|
227
|
-
for mid in ids:
|
|
228
|
-
if any(k in mid.lower() for k in ("embed", "bge", "gte", "m3")):
|
|
229
|
-
self.model = mid
|
|
230
|
-
break
|
|
231
|
-
else:
|
|
232
|
-
self.model = ids[0]
|
|
233
|
-
return self.model
|
|
234
|
-
|
|
235
|
-
# 生效条件:对任意 text 以 self.model 调 _post("/embeddings", {"model":…, "input": text}),取 d["data"][0]["embedding"],令 self._dim 等于该向量长度并返回该向量。
|
|
236
|
-
def embed(self, text):
|
|
237
|
-
d = self._post("/embeddings", {"model": self.model, "input": text})
|
|
238
|
-
v = d["data"][0]["embedding"]
|
|
239
|
-
self._dim = len(v)
|
|
240
|
-
return v
|
|
241
|
-
|
|
242
|
-
# 生效条件:按 batch(默认 32)把 texts 切片,每片整批 POST /embeddings 成功时按 x.get("index", 0) 排序后依次收集 r["embedding"],该片抛任何异常时改为对片内每条调 self.embed 回退,self._dim 为 0 且有结果时置为最后一条向量长度,最后返回 out。
|
|
243
|
-
def embed_many(self, texts, batch=32):
|
|
244
|
-
"""批量嵌入(服务不支持 batch 时逐条回退)。"""
|
|
245
|
-
out = []
|
|
246
|
-
for i in range(0, len(texts), batch):
|
|
247
|
-
chunk = texts[i:i + batch]
|
|
248
|
-
try:
|
|
249
|
-
d = self._post("/embeddings", {"model": self.model, "input": chunk})
|
|
250
|
-
rows = sorted(d["data"], key=lambda x: x.get("index", 0))
|
|
251
|
-
out.extend([r["embedding"] for r in rows])
|
|
252
|
-
except Exception:
|
|
253
|
-
out.extend([self.embed(t) for t in chunk])
|
|
254
|
-
if self._dim == 0 and out:
|
|
255
|
-
self._dim = len(out[-1])
|
|
256
|
-
return out
|
|
257
|
-
|
|
258
|
-
# 生效条件:无前置;把 self.ids 与 self.vecs 同时清空(二者下标耦合,必须成对重置),self._dim 保留原值不动;
|
|
259
|
-
def reset(self):
|
|
260
|
-
self.ids, self.vecs = [], []
|
|
261
|
-
|
|
262
|
-
# 生效条件:对任意 nid 与 text,把 nid 追加到 self.ids、把 self.embed(text) 的向量追加到 self.vecs,二者按下标一一对应,不查重、不返回。
|
|
263
|
-
def add(self, nid, text):
|
|
264
|
-
self.ids.append(nid)
|
|
265
|
-
self.vecs.append(self.embed(text))
|
|
266
|
-
|
|
267
|
-
# 生效条件:self.vecs 为空时直接返回 [];否则嵌入 query 并对每条候选计算余弦相似度(qn 或 vn 为 0 时用 1.0 兜底),按相似度降序、同分按 id 升序排序后返回前 k 个 nid。
|
|
268
|
-
def search(self, query, k=5):
|
|
269
|
-
if not self.vecs:
|
|
270
|
-
return []
|
|
271
|
-
qv = self.embed(query)
|
|
272
|
-
qn = math.sqrt(sum(x * x for x in qv)) or 1.0
|
|
273
|
-
scored = []
|
|
274
|
-
for i, v in enumerate(self.vecs):
|
|
275
|
-
vn = math.sqrt(sum(x * x for x in v)) or 1.0
|
|
276
|
-
s = sum(a * b for a, b in zip(qv, v)) / (qn * vn)
|
|
277
|
-
scored.append((s, self.ids[i]))
|
|
278
|
-
scored.sort(key=lambda x: (-x[0], x[1]))
|
|
279
|
-
return [nid for _s, nid in scored[:k]]
|
|
280
|
-
|
|
281
|
-
# 生效条件:对任意 nids 都只取前 2 项(nids[:2]),各返回 {"id": nid, "form": "原样英文文本 → embedding", "lang": "en", "dim": self._dim},不读磁盘内容。
|
|
282
|
-
def describe_ingest(self, nids):
|
|
283
|
-
return [{"id": nid, "form": "原样英文文本 → embedding",
|
|
284
|
-
"lang": "en", "dim": self._dim} for nid in nids[:2]]
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
# ------------------------------------------------------------------ 套件与评分
|
|
288
|
-
|
|
289
|
-
# 生效条件:lang 等于 "zh" 时逐题取 q["question_zh"],lang 为其它任何值(含 "en")时取 q["question_en"],对 questions 每项调 adapter.search(query, k=k),verbose 为真且序数能被 50 整除时打印进度,返回 {qid: 检索结果列表}。
|
|
290
|
-
def run_suite(adapter, questions, lang, k=5, verbose=True):
|
|
291
|
-
"""一套查询语言跑一遍 → {qid: [id...]}(顺序即相关性降序)。"""
|
|
292
|
-
key = "question_zh" if lang == "zh" else "question_en"
|
|
293
|
-
hits, t0 = {}, time.time()
|
|
294
|
-
for i, q in enumerate(questions, 1):
|
|
295
|
-
hits[q["qid"]] = adapter.search(q[key], k=k)
|
|
296
|
-
if verbose and i % 50 == 0:
|
|
297
|
-
print(" [%s] %d/%d(%.0fs)" % (lang, i, len(questions),
|
|
298
|
-
time.time() - t0))
|
|
299
|
-
return hits
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
# 生效条件:对 langs 中每个 lang 依次跑 run_suite(adapter, questions, lang, k=k)、bc.rows_from_hits 与 ec.summarize,结果写入 out["langs"][lang];最后取 questions 前 2 条的 qid 调 adapter.describe_ingest 存入 out["ingest_probe"] 并返回 out。
|
|
303
|
-
def evaluate(arm, adapter, questions, k=5, langs=("zh", "en")):
|
|
304
|
-
"""一套库 × 两种查询语言 → 指标 + per-question 明细 + 回读取证。"""
|
|
305
|
-
out = {"arm": arm, "k": k, "langs": {}}
|
|
306
|
-
for lang in langs:
|
|
307
|
-
hits = run_suite(adapter, questions, lang, k=k)
|
|
308
|
-
rows = bc.rows_from_hits(questions, hits, k=k)
|
|
309
|
-
s = ec.summarize(rows, k=k)
|
|
310
|
-
out["langs"][lang] = {"summary": s, "rows": rows, "hits": hits}
|
|
311
|
-
print(" [%s/%s] hit@1=%.1f%% hit@%d=%.1f%% MRR=%.4f"
|
|
312
|
-
% (arm, lang, s["hit@1"] * 100, k, s["hit@%d" % k] * 100, s["mrr"]))
|
|
313
|
-
out["ingest_probe"] = adapter.describe_ingest([q["qid"] for q in questions[:2]])
|
|
314
|
-
return out
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
# 生效条件:model 依次按 model 形参 → os.environ.get("BENCH6_EMBED_MODEL") → "text-embedding-bge-m3" 取值(形参为空串/None、环境变量缺失或为空串都会继续回落),随后 resolve_model(),再把 pool 中每条的 t["id"]、t["ingest"] 分别装进 vec.ids 与批量嵌入结果 vec.vecs 后返回 vec。
|
|
318
|
-
def build_vector_rag(pool, model=None):
|
|
319
|
-
"""向量基线:池内英文原文批量嵌入(零 LLM、无结构化)。"""
|
|
320
|
-
vec = VectorRagAdapter(model=model or os.environ.get("BENCH6_EMBED_MODEL")
|
|
321
|
-
or "text-embedding-bge-m3")
|
|
322
|
-
vec.resolve_model()
|
|
323
|
-
t0 = time.time()
|
|
324
|
-
vec.ids = [t["id"] for t in pool]
|
|
325
|
-
vec.vecs = vec.embed_many([t["ingest"] for t in pool])
|
|
326
|
-
print(" [vector_rag] 模型=%s dim=%d 嵌入 %d 条 %.0fs"
|
|
327
|
-
% (vec.model, vec._dim, len(vec.vecs), time.time() - t0))
|
|
328
|
-
return vec
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
# 生效条件:argv 为 None 时取 sys.argv[1:],其中出现 "--rebuild" 则各臂以 rebuild=True 建库,非 "-" 开头的项构成 only 白名单,仅当 only 为空或臂名在 only 中时执行对应臂(only 为空时额外执行 2×2 消融块),跑完返回含 manifest/results/elapsed_s 的 payload。
|
|
332
|
-
def main(argv=None):
|
|
333
|
-
argv = sys.argv[1:] if argv is None else argv
|
|
334
|
-
rebuild = "--rebuild" in argv
|
|
335
|
-
only = [a for a in argv if not a.startswith("-")]
|
|
336
|
-
t_all = time.time()
|
|
337
|
-
|
|
338
|
-
data = bc.load()
|
|
339
|
-
questions, pool, man = data["questions"], data["pool"], data["manifest"]
|
|
340
|
-
print("[bench6] 题 %d / 池 %d(口径固化于 %s)"
|
|
341
|
-
% (len(questions), len(pool), man["created_at"]))
|
|
342
|
-
|
|
343
|
-
# 评测口径:与既有公开基准一致,否则与参考量级不可比(见 eval_common 注释)
|
|
344
|
-
ec.unlock_global_cap()
|
|
345
|
-
ec.use_jaccard()
|
|
346
|
-
|
|
347
|
-
corpus_by_id = {c["id"]: c for c in ec.iter_jsonl(bc.CORPUS567)}
|
|
348
|
-
rows = [corpus_by_id[t["id"]] for t in pool]
|
|
349
|
-
results, table = {}, {}
|
|
350
|
-
|
|
351
|
-
# 生效条件:形参 name 出现在外层 main 的 only 白名单中时返回 True;only 为空(假值)时对任何 name 都返回 True;only 非空且不含 name 时返回 False。
|
|
352
|
-
def _want(name):
|
|
353
|
-
return not only or name in only
|
|
354
|
-
|
|
355
|
-
# (1) 灵枢单词法路 = 回归锚。建库刻意**不加** tags/condition_space,与
|
|
356
|
-
# bench_locomo_zh_public.build_pool 逐字同口径;须复现 hit@1≈0.936,
|
|
357
|
-
# 否则说明本次口径已漂移,后续所有四路数字都不可信。
|
|
358
|
-
if _want("lingshu_lex"):
|
|
359
|
-
lex = LingshuAdapter(rows, "lex", paths=("lexical",), with_meta=False,
|
|
360
|
-
rebuild=rebuild)
|
|
361
|
-
ec.install_read_cache(lex.cg)
|
|
362
|
-
results["lingshu_lex"] = evaluate("lingshu_lex", lex, questions)
|
|
363
|
-
table["灵枢·单词法"] = results["lingshu_lex"]["langs"]["zh"]["summary"]
|
|
364
|
-
|
|
365
|
-
# (2) 灵枢四路:真开 bucket(传 context)vs 名义四路(不传),单变量对照。
|
|
366
|
-
if _want("lingshu_rrf4"):
|
|
367
|
-
rrf = LingshuAdapter(rows, "rrf4", paths=ec.PATHS, with_meta=True,
|
|
368
|
-
rebuild=rebuild)
|
|
369
|
-
ec.install_read_cache(rrf.cg)
|
|
370
|
-
health = rrf.bucket_health()
|
|
371
|
-
print(" [lingshu] 桶健康度 %s" % json.dumps(health, ensure_ascii=False))
|
|
372
|
-
rrf.context = QUERY_CONTEXT
|
|
373
|
-
results["lingshu_rrf4"] = evaluate("lingshu_rrf4", rrf, questions)
|
|
374
|
-
rrf.context = None
|
|
375
|
-
results["lingshu_rrf4_noref"] = evaluate("lingshu_rrf4_noref", rrf, questions)
|
|
376
|
-
table["灵枢·四路(真开bucket)"] = results["lingshu_rrf4"]["langs"]["zh"]["summary"]
|
|
377
|
-
table["灵枢·四路(名义)"] = results["lingshu_rrf4_noref"]["langs"]["zh"]["summary"]
|
|
378
|
-
results["bucket_health"] = health
|
|
379
|
-
|
|
380
|
-
# (2b) 2×2 消融:隔离「建库补 meta(tags/condition_space)」与「检索从 1 路变
|
|
381
|
-
# 4 路」两个变量。rrf4(81%) 与 lex(99%) 之间混了这两个变量,不隔离就
|
|
382
|
-
# 无法归因下降来自哪一侧。两个臂都复用已建好的库,只改检索参数,0 成本。
|
|
383
|
-
if not only:
|
|
384
|
-
rrf.paths = ("lexical",)
|
|
385
|
-
results["lingshu_lex_meta"] = evaluate("lingshu_lex_meta", rrf, questions)
|
|
386
|
-
rrf.paths = ec.PATHS # 复原
|
|
387
|
-
lex.paths = ec.PATHS
|
|
388
|
-
lex.context = QUERY_CONTEXT
|
|
389
|
-
results["lingshu_rrf4_nometa"] = evaluate("lingshu_rrf4_nometa", lex, questions)
|
|
390
|
-
lex.paths, lex.context = ("lexical",), None # 复原
|
|
391
|
-
table["灵枢·词法+meta"] = results["lingshu_lex_meta"]["langs"]["zh"]["summary"]
|
|
392
|
-
table["灵枢·四路(无meta)"] = results["lingshu_rrf4_nometa"]["langs"]["zh"]["summary"]
|
|
393
|
-
|
|
394
|
-
# (3) 纯向量 RAG 基线(零 LLM,下界锚)
|
|
395
|
-
if _want("vector_rag"):
|
|
396
|
-
vec = build_vector_rag(pool)
|
|
397
|
-
results["vector_rag"] = evaluate("vector_rag", vec, questions)
|
|
398
|
-
table["纯向量RAG"] = results["vector_rag"]["langs"]["zh"]["summary"]
|
|
399
|
-
|
|
400
|
-
payload = {"manifest": man, "results": results,
|
|
401
|
-
"elapsed_s": round(time.time() - t_all, 1)}
|
|
402
|
-
ec.save_result("bench6_arms_result.json", payload)
|
|
403
|
-
if table:
|
|
404
|
-
ec.print_table("bench6 主进程臂 · 中文查询(池 %d / 题 %d)"
|
|
405
|
-
% (len(pool), len(questions)), table, k=5)
|
|
406
|
-
print("\n[bench6] 主进程臂完成,用时 %.0fs" % (time.time() - t_all))
|
|
407
|
-
return payload
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if __name__ == "__main__":
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""六系统横评(bench6)· 主进程臂:灵枢 / 纯向量 RAG + 统一评分。
|
|
3
|
+
|
|
4
|
+
四家 LLM 竞品(mem0/Graphiti/GraphRAG/Letta)依赖互斥,跑在各自 venv 的独立
|
|
5
|
+
脚本里(外部评测工作区的 bench6 适配脚本),只回吐 {qid: [id...]} 的 JSON;本模块
|
|
6
|
+
读回后与灵枢/向量臂走**同一个** bc.rows_from_hits → ec.summarize,保证六家同口径
|
|
7
|
+
(排名判据复用 ec.first_evidence_rank,指标复用 ec.summarize,均不重造)。
|
|
8
|
+
|
|
9
|
+
灵枢三种检索口径(同一份中文层 + 英文原文,只变检索路):
|
|
10
|
+
lex : 单词法路,且建库不加 tags/condition_space——复现公开参考量级
|
|
11
|
+
(词法 hit@1≈0.936)的**回归锚**,用于确认本次口径没有漂移
|
|
12
|
+
rrf4 : 四路 RRF(lexical,bucket,entity,graph)+ 传 context——用户选定口径
|
|
13
|
+
rrf4_noref : 四路 RRF 不传 context——名义四路,量化条件约束路的净效应
|
|
14
|
+
|
|
15
|
+
## 为什么灵枢要建两个库而不是一个
|
|
16
|
+
lex 臂必须与 `bench_locomo_zh_public.build_pool` **逐字同口径**(无 tags、无
|
|
17
|
+
condition_space)才能作回归锚;而 rrf4 臂按用户口径要喂 entity 路(tags)与
|
|
18
|
+
bucket 路(condition_space)。建库参数不同 → 目录不同 → 拆成两个 ROOT,避免
|
|
19
|
+
"复用已建库"逻辑把两种口径混成一个。
|
|
20
|
+
|
|
21
|
+
## 诚实边界
|
|
22
|
+
locomo-zh-500 是**单域**会话语料,且查询侧是**无情境标注**的关键词串。bucket 路
|
|
23
|
+
要求读写两侧 `route_key` 同构(routing.py 模块头「风险2」)——写侧有域、读侧
|
|
24
|
+
没有,故条件路由在本语料上预期无区分力。这一点由实测的桶健康度取证,不预设。
|
|
25
|
+
"""
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
import math
|
|
30
|
+
import os
|
|
31
|
+
import shutil
|
|
32
|
+
import sys
|
|
33
|
+
import time
|
|
34
|
+
import urllib.error
|
|
35
|
+
import urllib.request
|
|
36
|
+
|
|
37
|
+
HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
38
|
+
for _p in (HERE, os.path.join(HERE, "md_cg")):
|
|
39
|
+
if _p not in sys.path:
|
|
40
|
+
sys.path.insert(0, _p)
|
|
41
|
+
|
|
42
|
+
from md_cg import bench6_common as bc # noqa: E402
|
|
43
|
+
from md_cg import eval_common as ec # noqa: E402
|
|
44
|
+
|
|
45
|
+
ROOT_BASE = os.path.join(HERE, "_md_cg_eval_bench6") # .gitignore 的 /_md_cg_eval_*/ 已覆盖
|
|
46
|
+
|
|
47
|
+
# 条件约束路的查询侧情境:所有题共用同一份默认情境(查询串本身无情境标注)。
|
|
48
|
+
# 与建库侧 condition_space 同构 → route_key 两侧落在同一键上。这是 bucket 路能被
|
|
49
|
+
# 开启的唯一合法构造方式;若查询侧能精确给出每题的场景/域,那已是使用 qrels 作弊。
|
|
50
|
+
QUERY_CONTEXT = {
|
|
51
|
+
"observation_position": "会话陈述",
|
|
52
|
+
"observation_tool": "会话记录",
|
|
53
|
+
"existence_constraint": "公开",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# 生效条件:形参 c 若提供映射接口,则取 c["zh_fields"](缺失或假值回落 {})再取其 "condition"(缺失或假值回落 {}),返回三槽 observation_position/observation_tool/existence_constraint,各自以 cond.get(中文键, "") 取值——中文键缺失时回落空串,键存在而值为 None 时结果即为 None(不回落)。
|
|
58
|
+
def cond_of(c):
|
|
59
|
+
"""zh_fields.condition(中文三槽)→ mdcos 期望的英文槽名。
|
|
60
|
+
|
|
61
|
+
只映射 zh_fields 里**真实存在**的三槽,不臆造 time_window(写入侧会自行补)。
|
|
62
|
+
"""
|
|
63
|
+
cond = (c.get("zh_fields") or {}).get("condition") or {}
|
|
64
|
+
return {"observation_position": cond.get("观测位置", ""),
|
|
65
|
+
"observation_tool": cond.get("观测工具", ""),
|
|
66
|
+
"existence_constraint": cond.get("存在约束", "")}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# 生效条件:形参 c 若提供映射接口,则 f = c["zh_fields"] 为假值(缺失/None/{})时当作 {},返回 [str(f["identity"] 或 "")] + [str(t) for t in (f["terms"] 或 [])]:identity 缺失或假值时首元素为空串(列表恒有 1 项),terms 缺失或假值时只有首元素。
|
|
70
|
+
def tags_of(c):
|
|
71
|
+
"""喂 entity 路的裸词 tags = identity + terms。
|
|
72
|
+
|
|
73
|
+
刻意不加 `ent:` 前缀:`mdcos._path_entity` 的判据是 `t in query or query in t`,
|
|
74
|
+
带前缀的标签在自然查询下永不命中(既有实测教训)。也不加 `domain:`——那会
|
|
75
|
+
劫持 route_key 的 domain 分支,把 bucket 路变成按场景分桶,而查询侧无法复现
|
|
76
|
+
同一场景键(见模块头「诚实边界」)。
|
|
77
|
+
"""
|
|
78
|
+
f = c.get("zh_fields") or {}
|
|
79
|
+
return [str(f.get("identity") or "")] + [str(t) for t in (f.get("terms") or [])]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# 生效条件:类无 __init__,实例化无需任何形参;其 describe_ingest(nids) 对任意 nids(含空)恒返回 [],而 reset()、add(nid, text)、search(query, k=5) 对任意实参一律抛 NotImplementedError。
|
|
83
|
+
class Adapter:
|
|
84
|
+
"""统一适配接口。六家一律只回吐 id 列表,指标计算交回 bench6_common。"""
|
|
85
|
+
name = "adapter"
|
|
86
|
+
|
|
87
|
+
# 生效条件:无可选/必需形参,任何调用一律抛 NotImplementedError(基类接口桩)。
|
|
88
|
+
def reset(self):
|
|
89
|
+
raise NotImplementedError
|
|
90
|
+
|
|
91
|
+
# 生效条件:对任意 nid 与 text 一律抛 NotImplementedError(形参不参与任何判断)。
|
|
92
|
+
def add(self, nid, text):
|
|
93
|
+
raise NotImplementedError
|
|
94
|
+
|
|
95
|
+
# 生效条件:对任意 query 与任意 k(默认 5)一律抛 NotImplementedError,不返回结果。
|
|
96
|
+
def search(self, query, k=5):
|
|
97
|
+
raise NotImplementedError
|
|
98
|
+
|
|
99
|
+
# 生效条件:对任意 nids(包括空列表或 None)都直接返回空列表 [],不读取任何存储。
|
|
100
|
+
def describe_ingest(self, nids):
|
|
101
|
+
"""回读真实存储内容样本,用于取证「入库语言与入库形态」。"""
|
|
102
|
+
return []
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# 生效条件:必须以 rows、variant、paths 三个必需形参构造(context 默认 None、with_meta 默认 False、rebuild 默认 False 可选),构造后 search(query, k=5) 是否向 search_rrf 传 context 由 context 是否为 None 决定,describe_ingest(nids)/bucket_health() 的取证内容取决于 variant 对应 root 库的索引状态。
|
|
106
|
+
class LingshuAdapter(Adapter):
|
|
107
|
+
"""灵枢臂:进程内 MdCGOS。
|
|
108
|
+
|
|
109
|
+
with_meta=True 时三口径共用一库(lex 需与公开脚本同库,故 lex 单独建)。
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
name = "lingshu"
|
|
113
|
+
|
|
114
|
+
# 生效条件:root 固定为 os.path.join(ROOT_BASE, variant);rebuild 为真且 os.path.isdir(root) 为真时先 rmtree,索引中已有节点数 ≥ len(rows) 时直接 return(幂等复用、不写库),否则按 rows 逐条 add(with_meta 为真时同时补 tags=tags_of(c)、condition_space=cond_of(c))后 flush。
|
|
115
|
+
def __init__(self, rows, variant, paths, context=None, with_meta=False,
|
|
116
|
+
rebuild=False):
|
|
117
|
+
from md_cg.bench_locomo_zh_public import body_of
|
|
118
|
+
from md_cg.mdcos import MdCGOS
|
|
119
|
+
|
|
120
|
+
self.variant = variant
|
|
121
|
+
self.paths = tuple(paths)
|
|
122
|
+
self.context = context
|
|
123
|
+
self._body_of = body_of
|
|
124
|
+
root = os.path.join(ROOT_BASE, variant)
|
|
125
|
+
self.root = root
|
|
126
|
+
if rebuild and os.path.isdir(root):
|
|
127
|
+
shutil.rmtree(root, ignore_errors=True)
|
|
128
|
+
self.cg = MdCGOS(root, autoflush=500)
|
|
129
|
+
if len(self.cg.index["nodes"]) >= len(rows):
|
|
130
|
+
return # 幂等复用
|
|
131
|
+
t0 = time.time()
|
|
132
|
+
for c in rows:
|
|
133
|
+
kw = {}
|
|
134
|
+
if with_meta:
|
|
135
|
+
kw["tags"] = tags_of(c)
|
|
136
|
+
kw["condition_space"] = cond_of(c)
|
|
137
|
+
self.cg.add(c["id"], body_of(c), layer="knowledge",
|
|
138
|
+
eval_src="bench6:locomo-zh-500",
|
|
139
|
+
verification_basis="data", **kw)
|
|
140
|
+
self.cg.flush()
|
|
141
|
+
print(" [lingshu/%s] 建库 %d 节点 %.1fs"
|
|
142
|
+
% (variant, len(self.cg.index["nodes"]), time.time() - t0))
|
|
143
|
+
|
|
144
|
+
# 生效条件:给定 query 与 k(默认 5)即调用 self.cg.search_rrf(k=k、paths=self.paths、judge=False、record=False),仅当 self.context 不为 None 时附加 context 参数,返回每个结果 r 的 r[0]["id"] 组成的列表。
|
|
145
|
+
def search(self, query, k=5):
|
|
146
|
+
kw = {"context": self.context} if self.context is not None else {}
|
|
147
|
+
res, _meta = self.cg.search_rrf(query, k=k, paths=self.paths,
|
|
148
|
+
judge=False, record=False, **kw)
|
|
149
|
+
return [r[0]["id"] for r in res]
|
|
150
|
+
|
|
151
|
+
# 生效条件:只遍历 nids[:2],节点索引中 .get(nid) 为假值(缺失)的 nid 被跳过,其余按 os.path.join(self.cg.root, e["path"]) 读文件头 300 字符,抛 OSError 时 file_head 保持空串,输出各字段用 e.get(缺键为 None)。
|
|
152
|
+
def describe_ingest(self, nids):
|
|
153
|
+
"""回读真实落盘内容(索引元数据 + 文件头),取证入库语言与形态。
|
|
154
|
+
|
|
155
|
+
不走 `cg.get`:其返回形状随层不同,且读缓存会介入;直接按索引 path 读
|
|
156
|
+
文件是最贴近"磁盘上真实存了什么"的取证方式。
|
|
157
|
+
"""
|
|
158
|
+
out = []
|
|
159
|
+
for nid in nids[:2]:
|
|
160
|
+
e = self.cg.index["nodes"].get(nid)
|
|
161
|
+
if not e:
|
|
162
|
+
continue
|
|
163
|
+
head = ""
|
|
164
|
+
try:
|
|
165
|
+
with open(os.path.join(self.cg.root, e["path"]), encoding="utf-8") as f:
|
|
166
|
+
head = f.read()[:300]
|
|
167
|
+
except OSError:
|
|
168
|
+
pass
|
|
169
|
+
out.append({"id": nid, "layer": e.get("layer"), "tags": e.get("tags"),
|
|
170
|
+
"bucket": e.get("bucket"),
|
|
171
|
+
"condition_space": e.get("condition_space"),
|
|
172
|
+
"file_head": head})
|
|
173
|
+
return out
|
|
174
|
+
|
|
175
|
+
# 生效条件:无参数,遍历 self.cg.index["nodes"] 各节点的 e.get("bucket"),其缺失或为假值(None/空串等)时归入 "<none>" 计数,再把计数字典交 routing.bucket_health 并返回其结果。
|
|
176
|
+
def bucket_health(self):
|
|
177
|
+
"""桶健康度自检(routing.bucket_health):取证条件路由是否有区分力。"""
|
|
178
|
+
from md_cg import routing
|
|
179
|
+
counts = {}
|
|
180
|
+
for e in self.cg.index["nodes"].values():
|
|
181
|
+
b = e.get("bucket") or "<none>"
|
|
182
|
+
counts[b] = counts.get(b, 0) + 1
|
|
183
|
+
return routing.bucket_health(counts)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# 生效条件:无必需构造形参,base 为假值(None/空串)时先回落 os.environ["BENCH6_EMBED_BASE"]、再回落 "http://127.0.0.1:1234/v1" 并 rstrip("/"),model 为假值时回落 os.environ["BENCH6_EMBED_MODEL"]、再回落空串 "",timeout 缺省为 30。
|
|
187
|
+
class VectorRagAdapter(Adapter):
|
|
188
|
+
"""纯向量 RAG 基线(零 LLM):英文原文直嵌入 + 余弦 Top-k。
|
|
189
|
+
|
|
190
|
+
作为**下界锚**:无结构化、无图、无实体/条件路。embedding 走本地
|
|
191
|
+
127.0.0.1:1234(OpenAI 兼容),与既有竞品探针同源,不引入新依赖。
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
name = "vector_rag"
|
|
195
|
+
|
|
196
|
+
# 生效条件:base 依次按 base 形参 → os.environ.get("BENCH6_EMBED_BASE") → "http://127.0.0.1:1234/v1" 取值(每级为空串/None 均继续回落)再去掉尾部 "/",model 依次按 model 形参 → os.environ.get("BENCH6_EMBED_MODEL") → "" 取值(空串也回落),timeout 直接取形参(含 0),ids/vecs 置 []、_dim 置 0。
|
|
197
|
+
def __init__(self, base=None, model=None, timeout=30):
|
|
198
|
+
self.base = (base or os.environ.get("BENCH6_EMBED_BASE")
|
|
199
|
+
or "http://127.0.0.1:1234/v1").rstrip("/")
|
|
200
|
+
self.model = model or os.environ.get("BENCH6_EMBED_MODEL") or ""
|
|
201
|
+
self.timeout = timeout
|
|
202
|
+
self.ids = []
|
|
203
|
+
self.vecs = []
|
|
204
|
+
self._dim = 0
|
|
205
|
+
|
|
206
|
+
# 生效条件:以 self.base + path 为 URL、method="POST"、JSON 编码的 payload 为 body、Content-Type: application/json、超时 self.timeout 发出请求,返回响应体按 UTF-8 解码后 json.loads 的对象。
|
|
207
|
+
def _post(self, path, payload):
|
|
208
|
+
req = urllib.request.Request(
|
|
209
|
+
self.base + path, method="POST",
|
|
210
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
211
|
+
headers={"Content-Type": "application/json"})
|
|
212
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as r:
|
|
213
|
+
return json.loads(r.read().decode("utf-8"))
|
|
214
|
+
|
|
215
|
+
# 生效条件:self.model 为真值时直接返回;否则请求 self.base + "/models",从 data.get("data") 筛出 id 非空的模型名列表,该列表为空时抛 RuntimeError,否则优先取名字含 embed/bge/gte/m3 的第一个,无匹配则取 ids[0],写入 self.model 后返回。
|
|
216
|
+
def resolve_model(self):
|
|
217
|
+
"""未显式指定时,从 /models 取第一个 embedding 模型。"""
|
|
218
|
+
if self.model:
|
|
219
|
+
return self.model
|
|
220
|
+
req = urllib.request.Request(self.base + "/models")
|
|
221
|
+
with urllib.request.urlopen(req, timeout=15) as r:
|
|
222
|
+
data = json.loads(r.read().decode("utf-8"))
|
|
223
|
+
ids = [m.get("id") for m in (data.get("data") or []) if m.get("id")]
|
|
224
|
+
if not ids:
|
|
225
|
+
raise RuntimeError("embedding 服务未返回任何模型:%s" % self.base)
|
|
226
|
+
# 优先明显是 embedding 的模型名
|
|
227
|
+
for mid in ids:
|
|
228
|
+
if any(k in mid.lower() for k in ("embed", "bge", "gte", "m3")):
|
|
229
|
+
self.model = mid
|
|
230
|
+
break
|
|
231
|
+
else:
|
|
232
|
+
self.model = ids[0]
|
|
233
|
+
return self.model
|
|
234
|
+
|
|
235
|
+
# 生效条件:对任意 text 以 self.model 调 _post("/embeddings", {"model":…, "input": text}),取 d["data"][0]["embedding"],令 self._dim 等于该向量长度并返回该向量。
|
|
236
|
+
def embed(self, text):
|
|
237
|
+
d = self._post("/embeddings", {"model": self.model, "input": text})
|
|
238
|
+
v = d["data"][0]["embedding"]
|
|
239
|
+
self._dim = len(v)
|
|
240
|
+
return v
|
|
241
|
+
|
|
242
|
+
# 生效条件:按 batch(默认 32)把 texts 切片,每片整批 POST /embeddings 成功时按 x.get("index", 0) 排序后依次收集 r["embedding"],该片抛任何异常时改为对片内每条调 self.embed 回退,self._dim 为 0 且有结果时置为最后一条向量长度,最后返回 out。
|
|
243
|
+
def embed_many(self, texts, batch=32):
|
|
244
|
+
"""批量嵌入(服务不支持 batch 时逐条回退)。"""
|
|
245
|
+
out = []
|
|
246
|
+
for i in range(0, len(texts), batch):
|
|
247
|
+
chunk = texts[i:i + batch]
|
|
248
|
+
try:
|
|
249
|
+
d = self._post("/embeddings", {"model": self.model, "input": chunk})
|
|
250
|
+
rows = sorted(d["data"], key=lambda x: x.get("index", 0))
|
|
251
|
+
out.extend([r["embedding"] for r in rows])
|
|
252
|
+
except Exception:
|
|
253
|
+
out.extend([self.embed(t) for t in chunk])
|
|
254
|
+
if self._dim == 0 and out:
|
|
255
|
+
self._dim = len(out[-1])
|
|
256
|
+
return out
|
|
257
|
+
|
|
258
|
+
# 生效条件:无前置;把 self.ids 与 self.vecs 同时清空(二者下标耦合,必须成对重置),self._dim 保留原值不动;
|
|
259
|
+
def reset(self):
|
|
260
|
+
self.ids, self.vecs = [], []
|
|
261
|
+
|
|
262
|
+
# 生效条件:对任意 nid 与 text,把 nid 追加到 self.ids、把 self.embed(text) 的向量追加到 self.vecs,二者按下标一一对应,不查重、不返回。
|
|
263
|
+
def add(self, nid, text):
|
|
264
|
+
self.ids.append(nid)
|
|
265
|
+
self.vecs.append(self.embed(text))
|
|
266
|
+
|
|
267
|
+
# 生效条件:self.vecs 为空时直接返回 [];否则嵌入 query 并对每条候选计算余弦相似度(qn 或 vn 为 0 时用 1.0 兜底),按相似度降序、同分按 id 升序排序后返回前 k 个 nid。
|
|
268
|
+
def search(self, query, k=5):
|
|
269
|
+
if not self.vecs:
|
|
270
|
+
return []
|
|
271
|
+
qv = self.embed(query)
|
|
272
|
+
qn = math.sqrt(sum(x * x for x in qv)) or 1.0
|
|
273
|
+
scored = []
|
|
274
|
+
for i, v in enumerate(self.vecs):
|
|
275
|
+
vn = math.sqrt(sum(x * x for x in v)) or 1.0
|
|
276
|
+
s = sum(a * b for a, b in zip(qv, v)) / (qn * vn)
|
|
277
|
+
scored.append((s, self.ids[i]))
|
|
278
|
+
scored.sort(key=lambda x: (-x[0], x[1]))
|
|
279
|
+
return [nid for _s, nid in scored[:k]]
|
|
280
|
+
|
|
281
|
+
# 生效条件:对任意 nids 都只取前 2 项(nids[:2]),各返回 {"id": nid, "form": "原样英文文本 → embedding", "lang": "en", "dim": self._dim},不读磁盘内容。
|
|
282
|
+
def describe_ingest(self, nids):
|
|
283
|
+
return [{"id": nid, "form": "原样英文文本 → embedding",
|
|
284
|
+
"lang": "en", "dim": self._dim} for nid in nids[:2]]
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# ------------------------------------------------------------------ 套件与评分
|
|
288
|
+
|
|
289
|
+
# 生效条件:lang 等于 "zh" 时逐题取 q["question_zh"],lang 为其它任何值(含 "en")时取 q["question_en"],对 questions 每项调 adapter.search(query, k=k),verbose 为真且序数能被 50 整除时打印进度,返回 {qid: 检索结果列表}。
|
|
290
|
+
def run_suite(adapter, questions, lang, k=5, verbose=True):
|
|
291
|
+
"""一套查询语言跑一遍 → {qid: [id...]}(顺序即相关性降序)。"""
|
|
292
|
+
key = "question_zh" if lang == "zh" else "question_en"
|
|
293
|
+
hits, t0 = {}, time.time()
|
|
294
|
+
for i, q in enumerate(questions, 1):
|
|
295
|
+
hits[q["qid"]] = adapter.search(q[key], k=k)
|
|
296
|
+
if verbose and i % 50 == 0:
|
|
297
|
+
print(" [%s] %d/%d(%.0fs)" % (lang, i, len(questions),
|
|
298
|
+
time.time() - t0))
|
|
299
|
+
return hits
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
# 生效条件:对 langs 中每个 lang 依次跑 run_suite(adapter, questions, lang, k=k)、bc.rows_from_hits 与 ec.summarize,结果写入 out["langs"][lang];最后取 questions 前 2 条的 qid 调 adapter.describe_ingest 存入 out["ingest_probe"] 并返回 out。
|
|
303
|
+
def evaluate(arm, adapter, questions, k=5, langs=("zh", "en")):
|
|
304
|
+
"""一套库 × 两种查询语言 → 指标 + per-question 明细 + 回读取证。"""
|
|
305
|
+
out = {"arm": arm, "k": k, "langs": {}}
|
|
306
|
+
for lang in langs:
|
|
307
|
+
hits = run_suite(adapter, questions, lang, k=k)
|
|
308
|
+
rows = bc.rows_from_hits(questions, hits, k=k)
|
|
309
|
+
s = ec.summarize(rows, k=k)
|
|
310
|
+
out["langs"][lang] = {"summary": s, "rows": rows, "hits": hits}
|
|
311
|
+
print(" [%s/%s] hit@1=%.1f%% hit@%d=%.1f%% MRR=%.4f"
|
|
312
|
+
% (arm, lang, s["hit@1"] * 100, k, s["hit@%d" % k] * 100, s["mrr"]))
|
|
313
|
+
out["ingest_probe"] = adapter.describe_ingest([q["qid"] for q in questions[:2]])
|
|
314
|
+
return out
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
# 生效条件:model 依次按 model 形参 → os.environ.get("BENCH6_EMBED_MODEL") → "text-embedding-bge-m3" 取值(形参为空串/None、环境变量缺失或为空串都会继续回落),随后 resolve_model(),再把 pool 中每条的 t["id"]、t["ingest"] 分别装进 vec.ids 与批量嵌入结果 vec.vecs 后返回 vec。
|
|
318
|
+
def build_vector_rag(pool, model=None):
|
|
319
|
+
"""向量基线:池内英文原文批量嵌入(零 LLM、无结构化)。"""
|
|
320
|
+
vec = VectorRagAdapter(model=model or os.environ.get("BENCH6_EMBED_MODEL")
|
|
321
|
+
or "text-embedding-bge-m3")
|
|
322
|
+
vec.resolve_model()
|
|
323
|
+
t0 = time.time()
|
|
324
|
+
vec.ids = [t["id"] for t in pool]
|
|
325
|
+
vec.vecs = vec.embed_many([t["ingest"] for t in pool])
|
|
326
|
+
print(" [vector_rag] 模型=%s dim=%d 嵌入 %d 条 %.0fs"
|
|
327
|
+
% (vec.model, vec._dim, len(vec.vecs), time.time() - t0))
|
|
328
|
+
return vec
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# 生效条件:argv 为 None 时取 sys.argv[1:],其中出现 "--rebuild" 则各臂以 rebuild=True 建库,非 "-" 开头的项构成 only 白名单,仅当 only 为空或臂名在 only 中时执行对应臂(only 为空时额外执行 2×2 消融块),跑完返回含 manifest/results/elapsed_s 的 payload。
|
|
332
|
+
def main(argv=None):
|
|
333
|
+
argv = sys.argv[1:] if argv is None else argv
|
|
334
|
+
rebuild = "--rebuild" in argv
|
|
335
|
+
only = [a for a in argv if not a.startswith("-")]
|
|
336
|
+
t_all = time.time()
|
|
337
|
+
|
|
338
|
+
data = bc.load()
|
|
339
|
+
questions, pool, man = data["questions"], data["pool"], data["manifest"]
|
|
340
|
+
print("[bench6] 题 %d / 池 %d(口径固化于 %s)"
|
|
341
|
+
% (len(questions), len(pool), man["created_at"]))
|
|
342
|
+
|
|
343
|
+
# 评测口径:与既有公开基准一致,否则与参考量级不可比(见 eval_common 注释)
|
|
344
|
+
ec.unlock_global_cap()
|
|
345
|
+
ec.use_jaccard()
|
|
346
|
+
|
|
347
|
+
corpus_by_id = {c["id"]: c for c in ec.iter_jsonl(bc.CORPUS567)}
|
|
348
|
+
rows = [corpus_by_id[t["id"]] for t in pool]
|
|
349
|
+
results, table = {}, {}
|
|
350
|
+
|
|
351
|
+
# 生效条件:形参 name 出现在外层 main 的 only 白名单中时返回 True;only 为空(假值)时对任何 name 都返回 True;only 非空且不含 name 时返回 False。
|
|
352
|
+
def _want(name):
|
|
353
|
+
return not only or name in only
|
|
354
|
+
|
|
355
|
+
# (1) 灵枢单词法路 = 回归锚。建库刻意**不加** tags/condition_space,与
|
|
356
|
+
# bench_locomo_zh_public.build_pool 逐字同口径;须复现 hit@1≈0.936,
|
|
357
|
+
# 否则说明本次口径已漂移,后续所有四路数字都不可信。
|
|
358
|
+
if _want("lingshu_lex"):
|
|
359
|
+
lex = LingshuAdapter(rows, "lex", paths=("lexical",), with_meta=False,
|
|
360
|
+
rebuild=rebuild)
|
|
361
|
+
ec.install_read_cache(lex.cg)
|
|
362
|
+
results["lingshu_lex"] = evaluate("lingshu_lex", lex, questions)
|
|
363
|
+
table["灵枢·单词法"] = results["lingshu_lex"]["langs"]["zh"]["summary"]
|
|
364
|
+
|
|
365
|
+
# (2) 灵枢四路:真开 bucket(传 context)vs 名义四路(不传),单变量对照。
|
|
366
|
+
if _want("lingshu_rrf4"):
|
|
367
|
+
rrf = LingshuAdapter(rows, "rrf4", paths=ec.PATHS, with_meta=True,
|
|
368
|
+
rebuild=rebuild)
|
|
369
|
+
ec.install_read_cache(rrf.cg)
|
|
370
|
+
health = rrf.bucket_health()
|
|
371
|
+
print(" [lingshu] 桶健康度 %s" % json.dumps(health, ensure_ascii=False))
|
|
372
|
+
rrf.context = QUERY_CONTEXT
|
|
373
|
+
results["lingshu_rrf4"] = evaluate("lingshu_rrf4", rrf, questions)
|
|
374
|
+
rrf.context = None
|
|
375
|
+
results["lingshu_rrf4_noref"] = evaluate("lingshu_rrf4_noref", rrf, questions)
|
|
376
|
+
table["灵枢·四路(真开bucket)"] = results["lingshu_rrf4"]["langs"]["zh"]["summary"]
|
|
377
|
+
table["灵枢·四路(名义)"] = results["lingshu_rrf4_noref"]["langs"]["zh"]["summary"]
|
|
378
|
+
results["bucket_health"] = health
|
|
379
|
+
|
|
380
|
+
# (2b) 2×2 消融:隔离「建库补 meta(tags/condition_space)」与「检索从 1 路变
|
|
381
|
+
# 4 路」两个变量。rrf4(81%) 与 lex(99%) 之间混了这两个变量,不隔离就
|
|
382
|
+
# 无法归因下降来自哪一侧。两个臂都复用已建好的库,只改检索参数,0 成本。
|
|
383
|
+
if not only:
|
|
384
|
+
rrf.paths = ("lexical",)
|
|
385
|
+
results["lingshu_lex_meta"] = evaluate("lingshu_lex_meta", rrf, questions)
|
|
386
|
+
rrf.paths = ec.PATHS # 复原
|
|
387
|
+
lex.paths = ec.PATHS
|
|
388
|
+
lex.context = QUERY_CONTEXT
|
|
389
|
+
results["lingshu_rrf4_nometa"] = evaluate("lingshu_rrf4_nometa", lex, questions)
|
|
390
|
+
lex.paths, lex.context = ("lexical",), None # 复原
|
|
391
|
+
table["灵枢·词法+meta"] = results["lingshu_lex_meta"]["langs"]["zh"]["summary"]
|
|
392
|
+
table["灵枢·四路(无meta)"] = results["lingshu_rrf4_nometa"]["langs"]["zh"]["summary"]
|
|
393
|
+
|
|
394
|
+
# (3) 纯向量 RAG 基线(零 LLM,下界锚)
|
|
395
|
+
if _want("vector_rag"):
|
|
396
|
+
vec = build_vector_rag(pool)
|
|
397
|
+
results["vector_rag"] = evaluate("vector_rag", vec, questions)
|
|
398
|
+
table["纯向量RAG"] = results["vector_rag"]["langs"]["zh"]["summary"]
|
|
399
|
+
|
|
400
|
+
payload = {"manifest": man, "results": results,
|
|
401
|
+
"elapsed_s": round(time.time() - t_all, 1)}
|
|
402
|
+
ec.save_result("bench6_arms_result.json", payload)
|
|
403
|
+
if table:
|
|
404
|
+
ec.print_table("bench6 主进程臂 · 中文查询(池 %d / 题 %d)"
|
|
405
|
+
% (len(pool), len(questions)), table, k=5)
|
|
406
|
+
print("\n[bench6] 主进程臂完成,用时 %.0fs" % (time.time() - t_all))
|
|
407
|
+
return payload
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
if __name__ == "__main__":
|
|
411
411
|
main()
|