@furongjun1999/dsh-memory 0.4.8 → 0.4.9
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 +54 -26
- package/codebuddy/CODEBUDDY.md +196 -195
- package/codebuddy/README.md +13 -1
- package/codebuddy/mcp.json +9 -0
- 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 -0
- package/docs/README.md +1 -1
- package/docs/discipline/harnesses.yaml +18 -7
- package/docs/discipline/templates/full.md.tmpl +4 -3
- package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
- package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
- package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
- package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
- package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
- package/docs/hive//345/244/232/347/253/257harness/351/200/232/344/277/241/345/245/221/347/272/246_v0.1.md +42 -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 -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 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S1b/344/270/216/345/217/254/345/233/236/346/235/203/350/241/241_v0.1.md +57 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S7/345/200/222/346/216/222/345/200/231/351/200/211/345/261/202_v0.1.md +126 -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 +503 -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 -0
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
- package/docs/mdcg//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_/345/245/221/347/272/246_v0.1.md +82 -0
- 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 -0
- 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 +47 -45
- package/docs/mdcg//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/{206_v0.4.md → 206_v0.5.md} +92 -4
- 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 -0
- package/docs/mdcg//347/216/257/344/272/214_/347/231/275/347/256/261/345/241/253/345/205/205/346/265/201/346/260/264/347/272/277_v0.1.md +31 -0
- package/docs/mdcg//350/267/250/347/253/257/351/252/214/350/257/201/344/270/216/345/220/214/346/255/245/345/215/217/350/256/256_v0.1.md +93 -0
- 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 +2 -2
- 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 +3 -3
- 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 +2 -2
- 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 +434 -433
- package/docs//347/201/265/346/236/242/350/207/252/346/210/221/346/224/271/350/277/233/345/267/245/344/275/234/350/256/241/345/210/222_/345/244/226/351/203/250/347/240/224/347/251/266/347/263/273/345/210/227/345/220/270/346/224/266_v1_20260919.md +286 -0
- package/dsh/README.md +33 -0
- package/dsh/cordis.yml.example +13 -7
- package/dsh/hive-mcp-probe.mjs +94 -0
- package/dsh/hive-mcp.example.yml +62 -0
- package/dsh/update-lingshu.bat +11 -0
- package/dsh/update-lingshu.ps1 +337 -0
- package/lib/hooks.d.ts +3 -0
- package/lib/hooks.js +17 -23
- package/lib/index.d.ts +4 -2
- package/lib/index.js +29 -6
- package/lib/lib/datapath.d.ts +76 -1
- package/lib/lib/datapath.js +199 -13
- package/lib/lib/mdcg_client.d.ts +6 -3
- package/lib/lib/mdcg_client.js +6 -5
- package/lib/lib/mutual.js +4 -4
- package/lib/lib/token_store.js +4 -5
- package/md_cg/audit.py +17 -2
- package/md_cg/autonomy.py +86 -15
- package/md_cg/backfill.py +36 -1
- package/md_cg/backfill_bigdomain.py +34 -0
- package/md_cg/bench6_arms.py +28 -1
- package/md_cg/bench6_common.py +10 -1
- package/md_cg/bench6_competitors.py +6 -1
- package/md_cg/bench_axis_domain.py +9 -1
- package/md_cg/bench_blind_comp.py +7 -1
- package/md_cg/bench_en_atoms_public.py +9 -0
- package/md_cg/bench_governance.py +348 -0
- package/md_cg/bench_lme_zh.py +16 -1
- package/md_cg/bench_locomo.py +2 -1
- package/md_cg/bench_locomo_zh.py +16 -1
- package/md_cg/bench_locomo_zh_public.py +4 -1
- package/md_cg/bench_longmem.py +2 -1
- package/md_cg/bench_membench.py +27 -1
- package/md_cg/bench_p0.py +4 -1
- package/md_cg/bench_progressive.py +13 -1
- package/md_cg/bench_role_views.py +238 -0
- package/md_cg/bench_task_ab.py +8 -1
- package/md_cg/bench_task_ab_llm.py +13 -1
- package/md_cg/bench_unified_en.py +6 -1
- package/md_cg/bench_zh_mad.py +20 -1
- package/md_cg/blindspot_tickets.py +123 -0
- package/md_cg/branches.py +12 -1
- package/md_cg/build_postings.py +73 -0
- package/md_cg/ccgc.py +67 -2
- package/md_cg/census.py +5 -1
- package/md_cg/chain.py +24 -3
- package/md_cg/codeindex.py +134 -17
- package/md_cg/coldverify.py +265 -0
- package/md_cg/comment_gate.py +338 -0
- package/md_cg/cond_compose.py +190 -0
- package/md_cg/cond_facts.py +155 -0
- package/md_cg/cond_template.json +107 -0
- package/md_cg/condition_anchor.py +143 -0
- package/md_cg/conformance.py +69 -4
- package/md_cg/consistency.py +24 -1
- package/md_cg/consolidate.py +53 -2
- package/md_cg/corpus.py +4 -0
- package/md_cg/crosscheck.py +42 -2
- package/md_cg/crypto.py +35 -1
- package/md_cg/d_meta.py +310 -0
- package/md_cg/datapath.py +201 -26
- package/md_cg/docindex.py +122 -1
- package/md_cg/eval_common.py +29 -1
- package/md_cg/evidence.py +27 -1
- package/md_cg/evolution.py +21 -1
- package/md_cg/export.py +11 -1
- package/md_cg/forgetting.py +23 -1
- package/md_cg/fsutil.py +18 -1
- package/md_cg/hotcache.py +214 -0
- package/md_cg/hyperedge.py +251 -0
- package/md_cg/identity.py +18 -1
- package/md_cg/insight.py +17 -1
- package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
- package/md_cg/lexicon/build_standard_en.py +171 -168
- package/md_cg/lexicon/expand_en_zh.py +6 -0
- package/md_cg/lifecycle.py +12 -1
- package/md_cg/linkref.py +281 -0
- package/md_cg/links.py +29 -1
- package/md_cg/mcp_server.py +362 -43
- package/md_cg/md_whitebox.py +53 -1
- package/md_cg/mdcg.py +1003 -27
- package/md_cg/mdcos.py +558 -36
- package/md_cg/metacognition.py +37 -2
- package/md_cg/migrate.py +4 -0
- package/md_cg/migrate_aeis.py +221 -213
- package/md_cg/migrate_roleplay.py +8 -0
- package/md_cg/migrate_wisdom_graph.py +14 -1
- package/md_cg/mreview/__main__.py +3 -0
- package/md_cg/mreview/bundle.py +8 -0
- package/md_cg/mreview/candidates.py +9 -0
- package/md_cg/mreview/govern.py +21 -1
- package/md_cg/mreview/locate.py +34 -0
- package/md_cg/mreview/pipeline.py +29 -1
- package/md_cg/mreview/ruleset.py +16 -1
- package/md_cg/nodefile.py +233 -3
- package/md_cg/pooling.py +23 -1
- package/md_cg/postings.py +298 -0
- package/md_cg/predict.py +89 -9
- package/md_cg/progressive.py +3 -0
- package/md_cg/protect.py +14 -1
- package/md_cg/protocol.py +372 -0
- package/md_cg/provenance.py +262 -0
- package/md_cg/reach.py +453 -0
- package/md_cg/refindex.py +47 -2
- package/md_cg/refine.py +20 -1
- package/md_cg/roleviews.py +89 -0
- package/md_cg/routing.py +76 -0
- package/md_cg/scrub.py +63 -2
- package/md_cg/security.py +26 -1
- package/md_cg/self_state.py +64 -1
- package/md_cg/selfreport.py +151 -0
- package/md_cg/semantic/canonical.py +5 -0
- package/md_cg/semantic/en_normalizer.py +364 -355
- package/md_cg/semantic/zh_en_atoms.py +139 -136
- package/md_cg/signer.py +41 -1
- package/md_cg/sources.py +583 -547
- package/md_cg/statushdr.py +179 -0
- package/md_cg/stg.py +59 -18
- package/md_cg/subgraph.py +23 -0
- package/md_cg/sustain.py +56 -1
- package/md_cg/tasks.py +26 -2
- package/md_cg/test_autonomy.py +26 -0
- package/md_cg/test_bench_governance.py +102 -0
- package/md_cg/test_blindspot_tickets.py +166 -0
- package/md_cg/test_ccgc.py +10 -0
- package/md_cg/test_codeindex.py +338 -0
- package/md_cg/test_comment_gate.py +187 -0
- package/md_cg/test_cond_compose_anchors.py +76 -0
- package/md_cg/test_condition_anchor.py +82 -0
- package/md_cg/test_d_meta.py +412 -0
- package/md_cg/test_datapath_root.py +188 -0
- package/md_cg/test_gain_gate.py +47 -1
- package/md_cg/test_hot_cold.py +187 -0
- package/md_cg/test_hyperedge.py +245 -0
- package/md_cg/test_linkref.py +306 -0
- package/md_cg/test_md_access_parity.py +15 -3
- package/md_cg/test_mr_m1.py +108 -18
- package/md_cg/test_mr_m3.py +8 -1
- package/md_cg/test_p26_refindex.py +49 -20
- package/md_cg/test_p27_docindex.py +236 -2
- package/md_cg/test_p2_mcp.py +1 -1
- package/md_cg/test_p31_insight.py +24 -0
- package/md_cg/test_p44_md_whitebox.py +14 -1
- package/md_cg/test_protocol.py +243 -0
- package/md_cg/test_reach.py +378 -0
- package/md_cg/test_reach_keys.py +201 -0
- package/md_cg/test_reach_meta_exits.py +145 -0
- package/md_cg/test_read_clip.py +8 -4
- package/md_cg/test_retr_s1.py +340 -0
- package/md_cg/test_retr_s1b.py +209 -0
- package/md_cg/test_retr_s3.py +194 -0
- package/md_cg/test_retr_s4.py +163 -0
- package/md_cg/test_retr_s5.py +200 -0
- package/md_cg/test_retr_s6.py +157 -0
- package/md_cg/test_retr_s7.py +385 -0
- package/md_cg/test_retr_s8_time.py +316 -0
- package/md_cg/test_retr_s9_edges.py +286 -0
- package/md_cg/test_retr_s9_entity_ctx.py +175 -0
- package/md_cg/test_review_conformance.py +59 -2
- package/md_cg/test_role_views.py +354 -0
- package/md_cg/test_trust.py +361 -0
- package/md_cg/test_units_poll.py +71 -0
- package/md_cg/test_v14_fixes.py +397 -0
- package/md_cg/test_validity_filter.py +280 -0
- package/md_cg/test_wisdom_md_store.py +7 -3
- package/md_cg/test_writepipe.py +5 -1
- package/md_cg/theory.py +16 -1
- package/md_cg/tokens.py +40 -8
- package/md_cg/tool_face.py +13 -2
- package/md_cg/trust.py +943 -0
- package/md_cg/twophase.py +12 -1
- package/md_cg/units.py +129 -10
- package/md_cg/vision_evidence.py +24 -1
- package/md_cg/weights.py +24 -1
- package/md_cg/whitebox.py +32 -1
- package/md_cg/whitebox_kb/data/verify_cache.json +21210 -365
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +5078 -0
- package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
- package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
- package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
- package/md_cg/writelimit.py +18 -4
- package/md_cg/writepipe.py +178 -7
- package/package.json +2 -2
- package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
- package/skills/skills/designer-perspective/scripts/designer.py +17 -1
- package/skills/skills/designer-perspective/tests/selftest.py +3 -1
- package/src/hooks.ts +17 -21
- package/src/index.ts +33 -6
- package/src/lib/datapath.ts +211 -13
- package/src/lib/mdcg_client.ts +12 -8
- package/src/lib/mutual.ts +411 -411
- package/src/lib/token_store.ts +4 -5
- package/zcode/AGENTS.md +196 -195
- package/zcode/README.md +4 -0
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-shm +0 -0
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-wal +0 -0
package/md_cg/bench6_arms.py
CHANGED
|
@@ -54,6 +54,7 @@ QUERY_CONTEXT = {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
# 生效条件:形参 c 若提供映射接口,则取 c["zh_fields"](缺失或假值回落 {})再取其 "condition"(缺失或假值回落 {}),返回三槽 observation_position/observation_tool/existence_constraint,各自以 cond.get(中文键, "") 取值——中文键缺失时回落空串,键存在而值为 None 时结果即为 None(不回落)。
|
|
57
58
|
def cond_of(c):
|
|
58
59
|
"""zh_fields.condition(中文三槽)→ mdcos 期望的英文槽名。
|
|
59
60
|
|
|
@@ -65,6 +66,7 @@ def cond_of(c):
|
|
|
65
66
|
"existence_constraint": cond.get("存在约束", "")}
|
|
66
67
|
|
|
67
68
|
|
|
69
|
+
# 生效条件:形参 c 若提供映射接口,则 f = c["zh_fields"] 为假值(缺失/None/{})时当作 {},返回 [str(f["identity"] 或 "")] + [str(t) for t in (f["terms"] 或 [])]:identity 缺失或假值时首元素为空串(列表恒有 1 项),terms 缺失或假值时只有首元素。
|
|
68
70
|
def tags_of(c):
|
|
69
71
|
"""喂 entity 路的裸词 tags = identity + terms。
|
|
70
72
|
|
|
@@ -77,24 +79,30 @@ def tags_of(c):
|
|
|
77
79
|
return [str(f.get("identity") or "")] + [str(t) for t in (f.get("terms") or [])]
|
|
78
80
|
|
|
79
81
|
|
|
82
|
+
# 生效条件:类无 __init__,实例化无需任何形参;其 describe_ingest(nids) 对任意 nids(含空)恒返回 [],而 reset()、add(nid, text)、search(query, k=5) 对任意实参一律抛 NotImplementedError。
|
|
80
83
|
class Adapter:
|
|
81
84
|
"""统一适配接口。六家一律只回吐 id 列表,指标计算交回 bench6_common。"""
|
|
82
85
|
name = "adapter"
|
|
83
86
|
|
|
87
|
+
# 生效条件:无可选/必需形参,任何调用一律抛 NotImplementedError(基类接口桩)。
|
|
84
88
|
def reset(self):
|
|
85
89
|
raise NotImplementedError
|
|
86
90
|
|
|
91
|
+
# 生效条件:对任意 nid 与 text 一律抛 NotImplementedError(形参不参与任何判断)。
|
|
87
92
|
def add(self, nid, text):
|
|
88
93
|
raise NotImplementedError
|
|
89
94
|
|
|
95
|
+
# 生效条件:对任意 query 与任意 k(默认 5)一律抛 NotImplementedError,不返回结果。
|
|
90
96
|
def search(self, query, k=5):
|
|
91
97
|
raise NotImplementedError
|
|
92
98
|
|
|
99
|
+
# 生效条件:对任意 nids(包括空列表或 None)都直接返回空列表 [],不读取任何存储。
|
|
93
100
|
def describe_ingest(self, nids):
|
|
94
101
|
"""回读真实存储内容样本,用于取证「入库语言与入库形态」。"""
|
|
95
102
|
return []
|
|
96
103
|
|
|
97
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 库的索引状态。
|
|
98
106
|
class LingshuAdapter(Adapter):
|
|
99
107
|
"""灵枢臂:进程内 MdCGOS。
|
|
100
108
|
|
|
@@ -103,6 +111,7 @@ class LingshuAdapter(Adapter):
|
|
|
103
111
|
|
|
104
112
|
name = "lingshu"
|
|
105
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。
|
|
106
115
|
def __init__(self, rows, variant, paths, context=None, with_meta=False,
|
|
107
116
|
rebuild=False):
|
|
108
117
|
from md_cg.bench_locomo_zh_public import body_of
|
|
@@ -132,12 +141,14 @@ class LingshuAdapter(Adapter):
|
|
|
132
141
|
print(" [lingshu/%s] 建库 %d 节点 %.1fs"
|
|
133
142
|
% (variant, len(self.cg.index["nodes"]), time.time() - t0))
|
|
134
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"] 组成的列表。
|
|
135
145
|
def search(self, query, k=5):
|
|
136
146
|
kw = {"context": self.context} if self.context is not None else {}
|
|
137
147
|
res, _meta = self.cg.search_rrf(query, k=k, paths=self.paths,
|
|
138
148
|
judge=False, record=False, **kw)
|
|
139
149
|
return [r[0]["id"] for r in res]
|
|
140
150
|
|
|
151
|
+
# 生效条件:只遍历 nids[:2],节点索引中 .get(nid) 为假值(缺失)的 nid 被跳过,其余按 os.path.join(self.cg.root, e["path"]) 读文件头 300 字符,抛 OSError 时 file_head 保持空串,输出各字段用 e.get(缺键为 None)。
|
|
141
152
|
def describe_ingest(self, nids):
|
|
142
153
|
"""回读真实落盘内容(索引元数据 + 文件头),取证入库语言与形态。
|
|
143
154
|
|
|
@@ -161,6 +172,7 @@ class LingshuAdapter(Adapter):
|
|
|
161
172
|
"file_head": head})
|
|
162
173
|
return out
|
|
163
174
|
|
|
175
|
+
# 生效条件:无参数,遍历 self.cg.index["nodes"] 各节点的 e.get("bucket"),其缺失或为假值(None/空串等)时归入 "<none>" 计数,再把计数字典交 routing.bucket_health 并返回其结果。
|
|
164
176
|
def bucket_health(self):
|
|
165
177
|
"""桶健康度自检(routing.bucket_health):取证条件路由是否有区分力。"""
|
|
166
178
|
from md_cg import routing
|
|
@@ -171,6 +183,7 @@ class LingshuAdapter(Adapter):
|
|
|
171
183
|
return routing.bucket_health(counts)
|
|
172
184
|
|
|
173
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。
|
|
174
187
|
class VectorRagAdapter(Adapter):
|
|
175
188
|
"""纯向量 RAG 基线(零 LLM):英文原文直嵌入 + 余弦 Top-k。
|
|
176
189
|
|
|
@@ -180,6 +193,7 @@ class VectorRagAdapter(Adapter):
|
|
|
180
193
|
|
|
181
194
|
name = "vector_rag"
|
|
182
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。
|
|
183
197
|
def __init__(self, base=None, model=None, timeout=30):
|
|
184
198
|
self.base = (base or os.environ.get("BENCH6_EMBED_BASE")
|
|
185
199
|
or "http://127.0.0.1:1234/v1").rstrip("/")
|
|
@@ -189,6 +203,7 @@ class VectorRagAdapter(Adapter):
|
|
|
189
203
|
self.vecs = []
|
|
190
204
|
self._dim = 0
|
|
191
205
|
|
|
206
|
+
# 生效条件:以 self.base + path 为 URL、method="POST"、JSON 编码的 payload 为 body、Content-Type: application/json、超时 self.timeout 发出请求,返回响应体按 UTF-8 解码后 json.loads 的对象。
|
|
192
207
|
def _post(self, path, payload):
|
|
193
208
|
req = urllib.request.Request(
|
|
194
209
|
self.base + path, method="POST",
|
|
@@ -197,6 +212,7 @@ class VectorRagAdapter(Adapter):
|
|
|
197
212
|
with urllib.request.urlopen(req, timeout=self.timeout) as r:
|
|
198
213
|
return json.loads(r.read().decode("utf-8"))
|
|
199
214
|
|
|
215
|
+
# 生效条件:self.model 为真值时直接返回;否则请求 self.base + "/models",从 data.get("data") 筛出 id 非空的模型名列表,该列表为空时抛 RuntimeError,否则优先取名字含 embed/bge/gte/m3 的第一个,无匹配则取 ids[0],写入 self.model 后返回。
|
|
200
216
|
def resolve_model(self):
|
|
201
217
|
"""未显式指定时,从 /models 取第一个 embedding 模型。"""
|
|
202
218
|
if self.model:
|
|
@@ -216,12 +232,14 @@ class VectorRagAdapter(Adapter):
|
|
|
216
232
|
self.model = ids[0]
|
|
217
233
|
return self.model
|
|
218
234
|
|
|
235
|
+
# 生效条件:对任意 text 以 self.model 调 _post("/embeddings", {"model":…, "input": text}),取 d["data"][0]["embedding"],令 self._dim 等于该向量长度并返回该向量。
|
|
219
236
|
def embed(self, text):
|
|
220
237
|
d = self._post("/embeddings", {"model": self.model, "input": text})
|
|
221
238
|
v = d["data"][0]["embedding"]
|
|
222
239
|
self._dim = len(v)
|
|
223
240
|
return v
|
|
224
241
|
|
|
242
|
+
# 生效条件:按 batch(默认 32)把 texts 切片,每片整批 POST /embeddings 成功时按 x.get("index", 0) 排序后依次收集 r["embedding"],该片抛任何异常时改为对片内每条调 self.embed 回退,self._dim 为 0 且有结果时置为最后一条向量长度,最后返回 out。
|
|
225
243
|
def embed_many(self, texts, batch=32):
|
|
226
244
|
"""批量嵌入(服务不支持 batch 时逐条回退)。"""
|
|
227
245
|
out = []
|
|
@@ -237,13 +255,16 @@ class VectorRagAdapter(Adapter):
|
|
|
237
255
|
self._dim = len(out[-1])
|
|
238
256
|
return out
|
|
239
257
|
|
|
258
|
+
# 生效条件:无前置;把 self.ids 与 self.vecs 同时清空(二者下标耦合,必须成对重置),self._dim 保留原值不动;
|
|
240
259
|
def reset(self):
|
|
241
260
|
self.ids, self.vecs = [], []
|
|
242
261
|
|
|
262
|
+
# 生效条件:对任意 nid 与 text,把 nid 追加到 self.ids、把 self.embed(text) 的向量追加到 self.vecs,二者按下标一一对应,不查重、不返回。
|
|
243
263
|
def add(self, nid, text):
|
|
244
264
|
self.ids.append(nid)
|
|
245
265
|
self.vecs.append(self.embed(text))
|
|
246
266
|
|
|
267
|
+
# 生效条件:self.vecs 为空时直接返回 [];否则嵌入 query 并对每条候选计算余弦相似度(qn 或 vn 为 0 时用 1.0 兜底),按相似度降序、同分按 id 升序排序后返回前 k 个 nid。
|
|
247
268
|
def search(self, query, k=5):
|
|
248
269
|
if not self.vecs:
|
|
249
270
|
return []
|
|
@@ -257,6 +278,7 @@ class VectorRagAdapter(Adapter):
|
|
|
257
278
|
scored.sort(key=lambda x: (-x[0], x[1]))
|
|
258
279
|
return [nid for _s, nid in scored[:k]]
|
|
259
280
|
|
|
281
|
+
# 生效条件:对任意 nids 都只取前 2 项(nids[:2]),各返回 {"id": nid, "form": "原样英文文本 → embedding", "lang": "en", "dim": self._dim},不读磁盘内容。
|
|
260
282
|
def describe_ingest(self, nids):
|
|
261
283
|
return [{"id": nid, "form": "原样英文文本 → embedding",
|
|
262
284
|
"lang": "en", "dim": self._dim} for nid in nids[:2]]
|
|
@@ -264,6 +286,7 @@ class VectorRagAdapter(Adapter):
|
|
|
264
286
|
|
|
265
287
|
# ------------------------------------------------------------------ 套件与评分
|
|
266
288
|
|
|
289
|
+
# 生效条件:lang 等于 "zh" 时逐题取 q["question_zh"],lang 为其它任何值(含 "en")时取 q["question_en"],对 questions 每项调 adapter.search(query, k=k),verbose 为真且序数能被 50 整除时打印进度,返回 {qid: 检索结果列表}。
|
|
267
290
|
def run_suite(adapter, questions, lang, k=5, verbose=True):
|
|
268
291
|
"""一套查询语言跑一遍 → {qid: [id...]}(顺序即相关性降序)。"""
|
|
269
292
|
key = "question_zh" if lang == "zh" else "question_en"
|
|
@@ -276,6 +299,7 @@ def run_suite(adapter, questions, lang, k=5, verbose=True):
|
|
|
276
299
|
return hits
|
|
277
300
|
|
|
278
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。
|
|
279
303
|
def evaluate(arm, adapter, questions, k=5, langs=("zh", "en")):
|
|
280
304
|
"""一套库 × 两种查询语言 → 指标 + per-question 明细 + 回读取证。"""
|
|
281
305
|
out = {"arm": arm, "k": k, "langs": {}}
|
|
@@ -290,6 +314,7 @@ def evaluate(arm, adapter, questions, k=5, langs=("zh", "en")):
|
|
|
290
314
|
return out
|
|
291
315
|
|
|
292
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。
|
|
293
318
|
def build_vector_rag(pool, model=None):
|
|
294
319
|
"""向量基线:池内英文原文批量嵌入(零 LLM、无结构化)。"""
|
|
295
320
|
vec = VectorRagAdapter(model=model or os.environ.get("BENCH6_EMBED_MODEL")
|
|
@@ -303,6 +328,7 @@ def build_vector_rag(pool, model=None):
|
|
|
303
328
|
return vec
|
|
304
329
|
|
|
305
330
|
|
|
331
|
+
# 生效条件:argv 为 None 时取 sys.argv[1:],其中出现 "--rebuild" 则各臂以 rebuild=True 建库,非 "-" 开头的项构成 only 白名单,仅当 only 为空或臂名在 only 中时执行对应臂(only 为空时额外执行 2×2 消融块),跑完返回含 manifest/results/elapsed_s 的 payload。
|
|
306
332
|
def main(argv=None):
|
|
307
333
|
argv = sys.argv[1:] if argv is None else argv
|
|
308
334
|
rebuild = "--rebuild" in argv
|
|
@@ -322,6 +348,7 @@ def main(argv=None):
|
|
|
322
348
|
rows = [corpus_by_id[t["id"]] for t in pool]
|
|
323
349
|
results, table = {}, {}
|
|
324
350
|
|
|
351
|
+
# 生效条件:形参 name 出现在外层 main 的 only 白名单中时返回 True;only 为空(假值)时对任何 name 都返回 True;only 非空且不含 name 时返回 False。
|
|
325
352
|
def _want(name):
|
|
326
353
|
return not only or name in only
|
|
327
354
|
|
|
@@ -381,4 +408,4 @@ def main(argv=None):
|
|
|
381
408
|
|
|
382
409
|
|
|
383
410
|
if __name__ == "__main__":
|
|
384
|
-
main()
|
|
411
|
+
main()
|
package/md_cg/bench6_common.py
CHANGED
|
@@ -53,6 +53,7 @@ BOUNDARIES = [
|
|
|
53
53
|
]
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
# 生效条件:rows 为含 qtype 的行列表、n 取默认 N_QUESTIONS、seed 取默认 SEED 时(rows 为空则分组与配额皆空、out 为空列表;n=0 时各型配额与 out 皆为空/0),按 int(n*组大小/总行数) 定配额并把余数按小数部分降序补足,逐型用 random.Random("%d:%s"%(seed,qt)) 抽 min(配额,组大小) 条,返回按 qid 排序的 (out, quota)
|
|
56
57
|
def stratified_sample(rows, n=N_QUESTIONS, seed=SEED):
|
|
57
58
|
"""按 qtype 比例分层抽样(最大余额法)。
|
|
58
59
|
|
|
@@ -78,6 +79,7 @@ def stratified_sample(rows, n=N_QUESTIONS, seed=SEED):
|
|
|
78
79
|
return out, quota
|
|
79
80
|
|
|
80
81
|
|
|
82
|
+
# 生效条件:sample 为含 qid 与 evidence_turns 的题列表、corpus_by_id 为 id→池行的映射时,把不在 corpus_by_id 中的 evidence_turns 逐题记为 {"qid":…,"missing":[…]} 收入 dangling,其余去重后返回 (按 id 排序的 corpus_by_id 行列表, dangling)
|
|
81
83
|
def build_pool(sample, corpus_by_id):
|
|
82
84
|
"""池 = 抽中题的 gold 引用 turn 去重。返回 (pool, dangling)。
|
|
83
85
|
|
|
@@ -94,6 +96,7 @@ def build_pool(sample, corpus_by_id):
|
|
|
94
96
|
return [corpus_by_id[i] for i in sorted(pool_ids)], dangling
|
|
95
97
|
|
|
96
98
|
|
|
99
|
+
# 生效条件:c 为含 text 键的映射时取其去空白文本,date 非空则返回 "文本 [date]",date 为空则只返回 text。
|
|
97
100
|
def ingest_text_en(c):
|
|
98
101
|
"""六家共用的英文写入文本:原始陈述 + 会话时间。
|
|
99
102
|
|
|
@@ -107,6 +110,7 @@ def ingest_text_en(c):
|
|
|
107
110
|
return "%s [%s]" % (text, date) if date else text
|
|
108
111
|
|
|
109
112
|
|
|
113
|
+
# 生效条件:c 含 "id" 键时返回 {'id': c["id"], 'speaker'/'date'/'text' 为 c.get(键) or ""(键缺失或值为 None/""/0/[] 等假值均落空串), 'ingest': ingest_text_en(c)};缺 "id" 键时 c["id"] 抛 KeyError
|
|
110
114
|
def turn_rec(c):
|
|
111
115
|
"""池行 → 落盘行(六家共用的英文侧视图)。"""
|
|
112
116
|
return {"id": c["id"], "speaker": c.get("speaker") or "",
|
|
@@ -114,6 +118,7 @@ def turn_rec(c):
|
|
|
114
118
|
"ingest": ingest_text_en(c)}
|
|
115
119
|
|
|
116
120
|
|
|
121
|
+
# 生效条件:sample 每题的 qid 在 en_by_qid 中且中英 evidence_turns 逐字相等时返回按 sample 顺序的 {qid, qtype, question_zh, question_en, evidence_turns} 列表;en_by_qid.get(qid) 为 None 抛 KeyError,两列表不等抛 AssertionError
|
|
117
122
|
def align_queries(sample, en_by_qid):
|
|
118
123
|
"""中英双查询词面按 qid join,断言 evidence_turns 逐字一致。
|
|
119
124
|
|
|
@@ -133,6 +138,7 @@ def align_queries(sample, en_by_qid):
|
|
|
133
138
|
return out
|
|
134
139
|
|
|
135
140
|
|
|
141
|
+
# 生效条件:ids 为 id 序列、evidence 为证据 id 集合时,把 ids 包装成 [({"id": x}, 0.0)] 后原样返回 ec.first_evidence_rank 的结果
|
|
136
142
|
def rank_of(ids, evidence):
|
|
137
143
|
"""首个证据 id 的排名(1-based;未命中 0)。
|
|
138
144
|
|
|
@@ -143,6 +149,7 @@ def rank_of(ids, evidence):
|
|
|
143
149
|
return ec.first_evidence_rank(res, set(evidence))
|
|
144
150
|
|
|
145
151
|
|
|
152
|
+
# 生效条件:questions 每题含 qid,hits_by_qid 缺该 qid 或其值为假值(含空列表)时按空 id 列表处理,取前 k=K 条后返回每题 {qid, qtype, rank, top1_score(ids 非空为 1.0 否则 0.0), n_res} 的行列表
|
|
146
153
|
def rows_from_hits(questions, hits_by_qid, k=K):
|
|
147
154
|
"""把任一家的 id 列表统一转成 ec.summarize 的明细行。
|
|
148
155
|
|
|
@@ -159,6 +166,7 @@ def rows_from_hits(questions, hits_by_qid, k=K):
|
|
|
159
166
|
return rows
|
|
160
167
|
|
|
161
168
|
|
|
169
|
+
# 生效条件:force 为假且 os.path.exists(MANIFEST) 与 os.path.exists(QUESTIONS_JSONL) 均为真时读回 MANIFEST 直接返回(verbose 为真时打印复用信息);否则重建口径、写 POOL_JSONL/QUESTIONS_JSONL/MANIFEST 后返回该 man
|
|
162
170
|
def prepare(force=False, verbose=True):
|
|
163
171
|
"""固化口径层产物(幂等)。返回 manifest。"""
|
|
164
172
|
if not force and os.path.exists(MANIFEST) and os.path.exists(QUESTIONS_JSONL):
|
|
@@ -211,6 +219,7 @@ def prepare(force=False, verbose=True):
|
|
|
211
219
|
return man
|
|
212
220
|
|
|
213
221
|
|
|
222
|
+
# 生效条件:无参调用时读 MANIFEST 常量并返回 {'questions': QUESTIONS_JSONL 行列表, 'pool': POOL_JSONL 行列表, 'manifest': 该 JSON 对象}
|
|
214
223
|
def load():
|
|
215
224
|
"""读回已固化的口径层产物。六家适配器只经此取题与池。"""
|
|
216
225
|
man = json.load(open(MANIFEST, encoding="utf-8"))
|
|
@@ -219,4 +228,4 @@ def load():
|
|
|
219
228
|
|
|
220
229
|
|
|
221
230
|
if __name__ == "__main__":
|
|
222
|
-
prepare(force="--force" in sys.argv)
|
|
231
|
+
prepare(force="--force" in sys.argv)
|
|
@@ -54,11 +54,13 @@ MAIN_ARMS = [
|
|
|
54
54
|
LANGS = ("zh", "en")
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
# 生效条件:questions、hits、k 三者给定即成立,以 hits 结合 k 经 bc.rows_from_hits 生成 rows,再返回 (ec.summarize(rows, k=k), rows)。
|
|
57
58
|
def _score_hits(questions, hits, k):
|
|
58
59
|
rows = bc.rows_from_hits(questions, hits, k=k)
|
|
59
60
|
return ec.summarize(rows, k=k), rows
|
|
60
61
|
|
|
61
62
|
|
|
63
|
+
# 生效条件:manifest_note 传入但源码未使用该形参,结果只取决于模块常量 ec.RESULTS 下 bench6_arms_result.json——该路径不存在时打印警告并返回 {},路径可读时返回 json.load 结果 .get('results') or {}(results 键缺失或该值为假值时同样得到 {})。
|
|
62
64
|
def load_main(manifest_note):
|
|
63
65
|
"""读主进程臂结果(含灵枢 5 口径 + 向量基线)。"""
|
|
64
66
|
path = os.path.join(ec.RESULTS, "bench6_arms_result.json")
|
|
@@ -69,6 +71,7 @@ def load_main(manifest_note):
|
|
|
69
71
|
return json.load(f).get("results") or {}
|
|
70
72
|
|
|
71
73
|
|
|
74
|
+
# 生效条件:由 arm 拼出模块常量 ARM_OUT 下 <arm>.json,该路径不存在时返回 (None, '缺文件 …(该臂未跑或跑失败)');路径可读时用 questions 与 k 对遍历模块常量 LANGS 各语言的 hits 评分(raw['langs']、某语言块、其 hits 缺失或为假值时按 {} 处理,errors 缺失或为假值时按 [] 处理),返回 (out, None)。
|
|
72
75
|
def load_competitor(arm, questions, k):
|
|
73
76
|
path = os.path.join(ARM_OUT, "%s.json" % arm)
|
|
74
77
|
if not os.path.exists(path):
|
|
@@ -94,6 +97,7 @@ def load_competitor(arm, questions, k):
|
|
|
94
97
|
return out, None
|
|
95
98
|
|
|
96
99
|
|
|
100
|
+
# 生效条件:遍历 rows 的每个 (label, r),仅当 r['langs'] 对模块常量 LANGS 每个语言都存在真值时,才用 k 读 s['hit@k'] 并打印 hit@1/hit@k/MRR 及未回收率(unmapped_rate 为 None 时显示 n/a);否则只打印 label 加「—」占位行,不打印数值。
|
|
97
101
|
def print_matrix(rows, k):
|
|
98
102
|
"""六家 × 两语言主表(hit@1 / hit@k / MRR)。"""
|
|
99
103
|
head = ("系统", "zh hit@1", "zh hit@%d" % k, "zh MRR",
|
|
@@ -119,6 +123,7 @@ def print_matrix(rows, k):
|
|
|
119
123
|
print(" ".join(c.ljust(wi) for c, wi in zip(cells, w)))
|
|
120
124
|
|
|
121
125
|
|
|
126
|
+
# 生效条件:argv 为 None 时改读 sys.argv[1:] 解析 --k,随后按 MAIN_ARMS 与 COMPETITOR_ARMS 各自装载结果,返回含 k、arms、missing 的 payload。
|
|
122
127
|
def main(argv=None):
|
|
123
128
|
argv = sys.argv[1:] if argv is None else argv
|
|
124
129
|
k = 5
|
|
@@ -205,4 +210,4 @@ def main(argv=None):
|
|
|
205
210
|
|
|
206
211
|
|
|
207
212
|
if __name__ == "__main__":
|
|
208
|
-
main()
|
|
213
|
+
main()
|
|
@@ -88,6 +88,7 @@ PATHSETS = (("lexical",), ("lexical", "bucket"),
|
|
|
88
88
|
|
|
89
89
|
# ------------------------------------------------------------------ 写入侧加工
|
|
90
90
|
|
|
91
|
+
# 生效条件:c 含 'zh_fields' 且其中 identity/time/summary/terms/condition 均存在时,返回按身份、时间、摘要、词、条件及 c['text'] 拼成的正文,缺任一键则抛 KeyError;
|
|
91
92
|
def body_of(c):
|
|
92
93
|
"""正文:与 bench_zh_mad.build_arm 的 a0 臂**逐字一致**(无意图行/无承接行)。"""
|
|
93
94
|
f = c["zh_fields"]
|
|
@@ -102,6 +103,7 @@ def body_of(c):
|
|
|
102
103
|
])
|
|
103
104
|
|
|
104
105
|
|
|
106
|
+
# 生效条件:c 含 'zh_fields',terms 可迭代且 summary 经 str() 后参与空白切分时,将 terms 与切分词合并后交 routing.big_domain_classify 返回域判定结果;
|
|
105
107
|
def write_domain(c):
|
|
106
108
|
"""写入侧域判定:只读 turn 自身的 zh_fields(盲于查询集)。"""
|
|
107
109
|
f = c["zh_fields"]
|
|
@@ -109,11 +111,13 @@ def write_domain(c):
|
|
|
109
111
|
return routing.big_domain_classify(terms)
|
|
110
112
|
|
|
111
113
|
|
|
114
|
+
# 生效条件:q 含 question 字段时,返回 mg.expand_query_terms(q["question"]) 的词列表经 routing.big_domain_classify 得到的域分类。
|
|
112
115
|
def query_domain(q):
|
|
113
116
|
"""查询侧域判定:与写入侧共用同一份 routing 词表(两侧同构)。"""
|
|
114
117
|
return routing.big_domain_classify(list(mg.expand_query_terms(q["question"])))
|
|
115
118
|
|
|
116
119
|
|
|
120
|
+
# 生效条件:mode 为 'base' 时返回 [];mode 为 'bare' 时返回 bz.normalize_terms(c, df) 的列表;其余 mode 下取 doms.get(c['id']) 得 d,d 为真值时返回 ['domain:'+d],否则返回 [];
|
|
117
121
|
def arm_tags(c, mode, df, doms):
|
|
118
122
|
if mode == "base":
|
|
119
123
|
return []
|
|
@@ -124,6 +128,7 @@ def arm_tags(c, mode, df, doms):
|
|
|
124
128
|
return [f"domain:{d}"] if d else []
|
|
125
129
|
|
|
126
130
|
|
|
131
|
+
# 生效条件:传入 corpus/name/mode/df 时先清空 HERE+ARM_PREFIX+name 同名目录再建 MdCGOS 并返回 (cg, doms);mode 为 'shuf' 时把有域节点的域随机重排,verbose 为假值时跳过桶健康输出;
|
|
127
132
|
def build_domain_arm(corpus, name, mode, df, verbose=True):
|
|
128
133
|
"""按臂建库。四臂唯一差异是 tags 内容(layer/正文/edges 全同)。"""
|
|
129
134
|
import shutil
|
|
@@ -158,6 +163,7 @@ def build_domain_arm(corpus, name, mode, df, verbose=True):
|
|
|
158
163
|
|
|
159
164
|
# ------------------------------------------------------------------ 主流程
|
|
160
165
|
|
|
166
|
+
# 生效条件:不适用(无必需形参与模块级常量)
|
|
161
167
|
def main():
|
|
162
168
|
corpus = list(ec.iter_jsonl(CORPUS567))
|
|
163
169
|
questions = list(ec.iter_jsonl(QUESTIONS500))
|
|
@@ -175,6 +181,7 @@ def main():
|
|
|
175
181
|
n_ctx = sum(1 for v in qctx.values() if v)
|
|
176
182
|
print(f"查询侧落域 {n_ctx}/{len(questions)} = {n_ctx / len(questions):.1%}")
|
|
177
183
|
|
|
184
|
+
# 生效条件:q 含 'qid' 键时返回查询上下文映射中该 qid 对应的值,映射缺该键时 .get 返回 None(q 缺 'qid' 则抛 KeyError);
|
|
178
185
|
def context_of(q):
|
|
179
186
|
return qctx.get(q["qid"])
|
|
180
187
|
|
|
@@ -218,6 +225,7 @@ def main():
|
|
|
218
225
|
ec.save_result("axis_domain_locomo_zh.json", out)
|
|
219
226
|
|
|
220
227
|
# ---- 裁决摘要 ----
|
|
228
|
+
# 生效条件:a 与 p 以 '|' 拼成键后,在结果字典的 cells 映射中取该键,含键时返回其值,缺键时 .get 返回 {};
|
|
221
229
|
def cell(a, p):
|
|
222
230
|
return out["cells"].get(f"{a}|{p}", {})
|
|
223
231
|
|
|
@@ -247,4 +255,4 @@ def main():
|
|
|
247
255
|
|
|
248
256
|
|
|
249
257
|
if __name__ == "__main__":
|
|
250
|
-
main()
|
|
258
|
+
main()
|
|
@@ -122,10 +122,12 @@ D_TPL = [
|
|
|
122
122
|
DISTRACT_POOL = ["马", "鱼", "狗", "鸟", "羊", "猪", "鸭", "肉", "奶", "蛋", "油", "米"]
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
# 生效条件:s 为字符串时返回其全部相邻二元组集合;当 len(s) 小于 2 时返回空集合。
|
|
125
126
|
def _bigrams(s):
|
|
126
127
|
return {s[i:i + 2] for i in range(len(s) - 1)}
|
|
127
128
|
|
|
128
129
|
|
|
130
|
+
# 生效条件:无参调用且 ATOMS_PATH 载入 atoms 后,逐条确认 UNSEEN 各组合词不在其中文集合、其相邻字符对均为原子,并确认 UNSEEN 无重复、set(COMP_EN)==set(UNSEEN)、set(COMP_L3)<=set(UNSEEN),全部成立才静默通过,任一断言不成立即 AssertionError。
|
|
129
131
|
def assert_material():
|
|
130
132
|
"""盲测纪律的机器化:素材在/不在 atoms + 组合词互相不冲突。"""
|
|
131
133
|
atoms = json.load(open(ATOMS_PATH, encoding="utf-8"))["atoms"]
|
|
@@ -139,6 +141,7 @@ def assert_material():
|
|
|
139
141
|
assert set(COMP_EN) == set(UNSEEN) and set(COMP_L3) <= set(UNSEEN)
|
|
140
142
|
|
|
141
143
|
|
|
144
|
+
# 生效条件:以 SEED 初始化 random.Random 后对 UNSEEN 每词按 G_TPL 取模板生成含 gold 的篇目,再对 j=0..21 用 DISTRACT_POOL 随机取两个不同词按 D_TPL 造文,50 次重试内首次出现不含 UNSEEN 任何组合词的文本即 break 并 append,22 篇齐备后返回 corpus,50 次全冲突则 raise AssertionError。
|
|
142
145
|
def gen_corpus():
|
|
143
146
|
"""33 篇受控语料:11 gold + 22 干扰。确定性,断言内嵌。"""
|
|
144
147
|
rng = random.Random(SEED)
|
|
@@ -160,6 +163,7 @@ def gen_corpus():
|
|
|
160
163
|
return corpus
|
|
161
164
|
|
|
162
165
|
|
|
166
|
+
# 生效条件:对 UNSEEN 中每个 c 生成 L1 与 L2 题;当 c 属于 L3_SET 时,用 assert 强制其 COMP_L3 问句与 g_c 的 gold 文本 bigram 零交集,失败抛 AssertionError,通过后追加 L3 题。
|
|
163
167
|
def gen_questions():
|
|
164
168
|
"""33 题。L3 生成时校验 query×gold bigram 零交集(纪律4)。"""
|
|
165
169
|
questions = []
|
|
@@ -184,6 +188,7 @@ def gen_questions():
|
|
|
184
188
|
CORPUS = None # gen_questions 需引用语料正文(L3 校验),main 内先建语料
|
|
185
189
|
|
|
186
190
|
|
|
191
|
+
# 生效条件:以 cg/questions/tag/en_atoms 与默认 semantic=False 调用时,en_atoms 为真则设 os.environ["MDCG_EN_ATOMS"]="1"、为假则 pop,semantic 为真则设 MDCG_SEMANTIC="1" 且仅当 semantic=="norm" 时把带真值 q_atoms 的题替换为 q_atoms 文本、semantic=="raw" 保持原句、semantic 为假则 pop,随后在 lexical 路径以 k=5 评测并返回 (按 ALL/L1_surface/L2_crosslingual/L3_semantic 分型的 by_type, 仅 en_atoms 为真时按 L2_crosslingual 题收集中文语素的 probe)。
|
|
187
192
|
def run_arm(cg, questions, tag, en_atoms, semantic=False):
|
|
188
193
|
"""单臂评测:臂差异只在查询侧环境开关展开。返回 (summary_by_type, l2_probe)。
|
|
189
194
|
|
|
@@ -223,6 +228,7 @@ def run_arm(cg, questions, tag, en_atoms, semantic=False):
|
|
|
223
228
|
return by_type, probe
|
|
224
229
|
|
|
225
230
|
|
|
231
|
+
# 生效条件:无参调用时先 assert_material 再经 gen_corpus/gen_questions 得到语料与题,os.path.isdir(ARM_ROOT) 为真则删除该目录,以 ARM_ROOT 建 cg 并写入 CORPUS 全部篇目,os.path.isdir(ARM_ROOT+"_b2") 为真则删除该目录、以该路径建 cg2 并仅对 gold 为真值的篇目附加 semantic=" ".join(gold) 后写入,再依次以 (cg,b0_legacy,False,False)/(cg,b1_enatoms,True,False)/(cg2,b2_comp,False,"norm")/(cg2,b3_unified,False,"raw") 四臂调 run_arm 汇总指标与 b1 的 L2 探针,最后 ec.save_result 写出 blind_comp_baseline.json 并在 out 中记录 seed/n_corpus/n_q/arms/l2_probe/elapsed_s/boundaries。
|
|
226
232
|
def main():
|
|
227
233
|
global CORPUS
|
|
228
234
|
t0 = time.time()
|
|
@@ -300,4 +306,4 @@ def main():
|
|
|
300
306
|
|
|
301
307
|
|
|
302
308
|
if __name__ == "__main__":
|
|
303
|
-
main()
|
|
309
|
+
main()
|
|
@@ -68,6 +68,7 @@ NOISE_ZH = "天气 音乐 旅行"
|
|
|
68
68
|
WRONG_POOLS = ["经济 历史 音乐", "天体 地理 化学", "科技 法律 医学"]
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
# 生效条件:text 非空且 mode 为 drop20/noise3/wrong20 时按 idx 错位扰动并返回新串;text 为空返回 text or "",mode 不在三者之内时原样返回 text。
|
|
71
72
|
def perturb_kw(text, mode, idx):
|
|
72
73
|
"""②路 query 关键词扰动(确定性规则,验证归一噪声灵敏度)。
|
|
73
74
|
|
|
@@ -89,6 +90,7 @@ def perturb_kw(text, mode, idx):
|
|
|
89
90
|
return text
|
|
90
91
|
|
|
91
92
|
|
|
93
|
+
# 生效条件:CHAR_ATOMS 可读时按 data.get("lexicon") or {} 取词库,lexicon 缺失或为假值即返回空字典,否则逐键返回 {ch: str(v.get("en") or "")}(v 缺 "en" 或 "en" 为假值时该键值为空串)。
|
|
92
94
|
def load_char_atoms():
|
|
93
95
|
"""字级英文原子库:{中文字: 英文短语}。"""
|
|
94
96
|
with io.open(CHAR_ATOMS, encoding="utf-8") as f:
|
|
@@ -97,6 +99,7 @@ def load_char_atoms():
|
|
|
97
99
|
return {ch: str(v.get("en") or "") for ch, v in lex.items()}
|
|
98
100
|
|
|
99
101
|
|
|
102
|
+
# 生效条件:以 text or "" 逐字符、char_atoms 为字级映射表——字符落在 ZH_RANGE 内时取 char_atoms.get(ch, "")(缺键回落空串),其余字符原样保留,返回 normalize_en(" ".join(parts));text 为假值(None/空串)时按空串返回 normalize_en("")。
|
|
100
103
|
def zh_map_en(text, char_atoms):
|
|
101
104
|
"""中文逐字→英文短语映射串;英文/数字原样保留(交 normalize_en 归一)。"""
|
|
102
105
|
lo, hi = ZH_RANGE
|
|
@@ -109,6 +112,7 @@ def zh_map_en(text, char_atoms):
|
|
|
109
112
|
return normalize_en(" ".join(parts))
|
|
110
113
|
|
|
111
114
|
|
|
115
|
+
# 生效条件:以 normalize_en(str(c.get("text") or "")).split() 为基词集,body_only 为真时只返回该集合的 frozenset;body_only 为假(默认 False)时再并入 zh_map_en(str(c.get("zh") or ""), char_atoms) 拆出的词,返回合并后的 frozenset。
|
|
112
116
|
def node_atom_set(c, char_atoms, body_only=False):
|
|
113
117
|
"""doc 侧节点原子集:中文五槽字级映射 ∪ 英文正文归一词(双语双路 doc 侧)。
|
|
114
118
|
|
|
@@ -121,6 +125,7 @@ def node_atom_set(c, char_atoms, body_only=False):
|
|
|
121
125
|
return frozenset(toks)
|
|
122
126
|
|
|
123
127
|
|
|
128
|
+
# 生效条件:a 或 b 为假值(None/空集)时返回 0.0,否则交集非空返回 len(a & b)/len(a | b)、交集为空亦返回 0.0。
|
|
124
129
|
def jaccard(a, b):
|
|
125
130
|
if not a or not b:
|
|
126
131
|
return 0.0
|
|
@@ -128,10 +133,12 @@ def jaccard(a, b):
|
|
|
128
133
|
return inter / len(a | b) if inter else 0.0
|
|
129
134
|
|
|
130
135
|
|
|
136
|
+
# 生效条件:对 st.items() 每个值取 round(v, 1) 组成同键字典,st 为空字典时返回空字典。
|
|
131
137
|
def round_dict(st):
|
|
132
138
|
return {k: round(v, 1) for k, v in st.items()}
|
|
133
139
|
|
|
134
140
|
|
|
141
|
+
# 生效条件:遍历 questions 逐问评测——qatoms_of(q) 为假值时仅累加 st["n"] 不计命中,否则按 jaccard 对 docs 降序(同分按 nid 升序)排序、以首个 nid 落在 q.get("evidence_turns") or [] 中的 rank 累加 hit@1/5/10 与 1/rank 的 MRR,打印后返回 {k: v/max(st["n"],1)(rr 项)或 v*100.0/max(st["n"],1)}。
|
|
135
142
|
def run_arm(questions, docs, qatoms_of, label):
|
|
136
143
|
"""单臂评测:全池 Jaccard 排序,hit@1/5/10 + MRR。"""
|
|
137
144
|
st = {"h1": 0, "h5": 0, "h10": 0, "rr": 0.0, "n": 0}
|
|
@@ -160,6 +167,7 @@ def run_arm(questions, docs, qatoms_of, label):
|
|
|
160
167
|
return {k: (v / n if k == "rr" else v * 100.0 / n) for k, v in st.items()}
|
|
161
168
|
|
|
162
169
|
|
|
170
|
+
# 生效条件:CORPUS、QUESTIONS、CHAR_ATOMS 与 b6.EN_QUESTIONS 均可读(en_rows 由 ec.iter_jsonl 读取 b6.EN_QUESTIONS 构建)时,载入语料与题、构建 docs 与 docs_body、逐臂 run_arm 并打印锚点,返回 0。
|
|
163
171
|
def main():
|
|
164
172
|
t0 = time.time()
|
|
165
173
|
with io.open(CORPUS, encoding="utf-8") as f:
|
|
@@ -190,6 +198,7 @@ def main():
|
|
|
190
198
|
# 臂④ 机械归一端到端下界:英文问句 → 词表直译为中文词(CEDICT 28294 键
|
|
191
199
|
# ∪ EN_ZH 手工层,无 AI)→ ②同链路。与②唯一差异 = query 归一来源:
|
|
192
200
|
# ②=AI 理解式归一的输出形态(标注关键词),④=机械查表归一。
|
|
201
|
+
# 生效条件:以 en_rows.get(q.get("qid"), "")(qid 缺键回落空串)取英文题面,经 normalize_en_query 取出的 terms 拼接后由 zh_map_en 映射,返回 frozenset(zh_map_en(" ".join(terms), char_atoms).split());terms 为空时返回空 frozenset。
|
|
193
202
|
def e4(q):
|
|
194
203
|
terms, _ = normalize_en_query(en_rows.get(q.get("qid"), ""))
|
|
195
204
|
return frozenset(zh_map_en(" ".join(terms), char_atoms).split())
|