@hupan56/wlkj 3.3.13 → 3.3.15
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/bin/cli.js +0 -7
- package/package.json +29 -29
- package/templates/qoder/commands/optional/wl-spec.md +0 -8
- package/templates/qoder/commands/optional/wl-status.md +0 -8
- package/templates/qoder/commands/wl-code.md +0 -8
- package/templates/qoder/commands/wl-commit.md +0 -8
- package/templates/qoder/commands/wl-init.md +129 -129
- package/templates/qoder/commands/wl-search.md +0 -8
- package/templates/qoder/commands/wl-task.md +0 -8
- package/templates/qoder/commands/wl-test.md +0 -8
- package/templates/qoder/config.yaml +2 -3
- package/templates/qoder/contracts/insight.md +55 -55
- package/templates/qoder/hooks/pre-tool-use-commit.py +124 -124
- package/templates/qoder/hooks/session-start.py +384 -384
- package/templates/qoder/hooks/stop-eval.py +383 -383
- package/templates/qoder/scripts/capability/adapters/mcp.py +322 -322
- package/templates/qoder/scripts/capability/registry.py +245 -245
- package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +14 -0
- package/templates/qoder/scripts/deployment/setup/setup.py +0 -11
- package/templates/qoder/scripts/domain/task/wlkj_panel.py +1503 -1503
- package/templates/qoder/scripts/foundation/bootstrap.py +145 -156
- package/templates/qoder/scripts/foundation/io/context_cache.py +94 -94
- package/templates/qoder/scripts/orchestration/wlkj.py +295 -306
- package/templates/qoder/scripts/tool_guide.md +70 -70
- package/templates/qoder/scripts/validation/eval/alignment_matrix.py +176 -176
- package/templates/qoder/scripts/validation/eval/bf2_content_fidelity.py +110 -110
- package/templates/qoder/scripts/validation/eval/bf2_llmjudge.py +104 -104
- package/templates/qoder/scripts/validation/eval/bf_score.py +218 -218
- package/templates/qoder/scripts/validation/eval/code_flywheel.py +150 -150
- package/templates/qoder/scripts/validation/eval/dispatcher_ab.py +156 -156
- package/templates/qoder/scripts/validation/eval/dispatcher_ab_2026-07-21.json +23 -23
- package/templates/qoder/scripts/validation/eval/feature_fidelity_flywheel.py +143 -143
- package/templates/qoder/scripts/validation/eval/gradient_matrix.py +261 -261
- package/templates/qoder/scripts/validation/eval/gradient_matrix_baseline_2026-07-21.json +33 -33
- package/templates/qoder/scripts/validation/eval/metrics_dashboard.py +105 -105
- package/templates/qoder/scripts/validation/eval/multi_turn_flywheel.py +118 -118
- package/templates/qoder/scripts/validation/eval/prd_fidelity_flywheel.py +128 -128
- package/templates/qoder/scripts/validation/eval/prd_flywheel.py +148 -148
- package/templates/qoder/scripts/validation/eval/prototype_fidelity_flywheel.py +166 -166
- package/templates/qoder/scripts/validation/eval/recall_flywheel.py +148 -148
- package/templates/qoder/scripts/validation/eval/robustness_flywheel.py +139 -139
- package/templates/qoder/scripts/validation/eval/speed_accuracy_flywheel.py +188 -188
- package/templates/qoder/scripts/validation/eval/task_flywheel.py +124 -124
- package/templates/qoder/scripts/validation/eval/token_flywheel.py +88 -88
- package/templates/qoder/scripts/validation/metrics/eval_code_ac.py +177 -177
- package/templates/qoder/scripts/validation/metrics/lint_cases.py +170 -170
- package/templates/qoder/scripts/validation/test/test_context_cache.py +78 -78
- package/templates/qoder/scripts/validation/test/test_lint_cases.py +60 -60
- package/templates/qoder/scripts/validation/test/test_pre_tool_use_commit.py +70 -70
- package/templates/qoder/commands/wl-data.md +0 -46
- package/templates/qoder/commands/wl-fix.md +0 -47
- package/templates/qoder/commands/wl-knowledge.md +0 -41
- package/templates/qoder/commands/wl-review.md +0 -49
- package/templates/workspace/specs/REQ-TEST-CTX/.context-cache.json +0 -1
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
"""prototype_fidelity_flywheel.py — FW9 原型保真度飞轮(vs 真实 fywl-ui 设计系统)。
|
|
2
|
-
|
|
3
|
-
用户根因例子:"原型保真不保真"。本尺子量:生成原型的颜色/组件是不是 fywl-ui 真设计系统的
|
|
4
|
-
(get_design_system 返回的真色板 hsl(214,86%,59%)/真组件/真layout),而非泛泛 #409eff 蓝或编造组件。
|
|
5
|
-
bare(无设计系统接地→通用色/编造组件) vs +真设计系统接地(用真 hsl 色板/真组件)。
|
|
6
|
-
color保真率 = 原型颜色∈真色板比例;component保真率 = 真组件占比。
|
|
7
|
-
|
|
8
|
-
跑法: docker exec -i wlinkj-workspace-backend-1 python /app/scripts/validation/eval/prototype_fidelity_flywheel.py
|
|
9
|
-
"""
|
|
10
|
-
import os
|
|
11
|
-
import re
|
|
12
|
-
import sys
|
|
13
|
-
import json
|
|
14
|
-
import colorsys
|
|
15
|
-
import time
|
|
16
|
-
import urllib.request
|
|
17
|
-
import urllib.error
|
|
18
|
-
|
|
19
|
-
for _p in ("/app", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))):
|
|
20
|
-
if os.path.isdir(_p) and _p not in sys.path:
|
|
21
|
-
sys.path.insert(0, _p)
|
|
22
|
-
|
|
23
|
-
from app.routers import mcp_handlers as H # noqa: E402
|
|
24
|
-
try:
|
|
25
|
-
H._init_handlers()
|
|
26
|
-
except Exception:
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
CHAT_URL = os.environ.get("ALI_CHAT_BASE", "").rstrip("/") + "/chat/completions"
|
|
30
|
-
CHAT_KEY = os.environ.get("DASHSCOPE_API_KEY", "")
|
|
31
|
-
MODEL = "qwen-turbo"
|
|
32
|
-
PAGES = ["车辆保险列表页", "异常记录表单页", "合同维护详情页"]
|
|
33
|
-
_NEUTRAL = {(255, 255, 255), (0, 0, 0), (51, 51, 51), (102, 102, 102), (153, 153, 153),
|
|
34
|
-
(240, 240, 240), (250, 250, 250), (217, 217, 217), (232, 232, 232), (245, 245, 245)}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def chat(prompt, max_tokens=1200, timeout=90):
|
|
38
|
-
body = json.dumps({"model": MODEL, "messages": [{"role": "user", "content": prompt}],
|
|
39
|
-
"temperature": 0.2, "max_tokens": max_tokens}).encode()
|
|
40
|
-
for a in range(3):
|
|
41
|
-
try:
|
|
42
|
-
req = urllib.request.Request(CHAT_URL, data=body,
|
|
43
|
-
headers={"Authorization": f"Bearer {CHAT_KEY}", "Content-Type": "application/json"})
|
|
44
|
-
return json.loads(urllib.request.urlopen(req, timeout=timeout).read())["choices"][0]["message"]["content"]
|
|
45
|
-
except (urllib.error.URLError, TimeoutError, OSError, KeyError) as e:
|
|
46
|
-
if a < 2: time.sleep(1.0*(a+1))
|
|
47
|
-
else: return ""
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def real_design():
|
|
51
|
-
"""fywl-ui 真设计系统:色板(rgb 集) + 真组件名 + layout。"""
|
|
52
|
-
r = H.dispatch("get_design_system", {}) or {}
|
|
53
|
-
proj = next((p for p in r.get("projects", []) if p.get("project") == "fywl-ui"), {})
|
|
54
|
-
colors = proj.get("colors", {}) or {}
|
|
55
|
-
palette_rgb = set()
|
|
56
|
-
for v in colors.values():
|
|
57
|
-
if isinstance(v, str) and v.startswith("hsl"):
|
|
58
|
-
m = re.match(r"hsl\(\s*([\d.]+)[,\s]+([\d.]+)%[,\s]+([\d.]+)%", v)
|
|
59
|
-
if m:
|
|
60
|
-
h, s, l = float(m.group(1)) / 360.0, float(m.group(2)) / 100.0, float(m.group(3)) / 100.0
|
|
61
|
-
r_, g_, b_ = colorsys.hls_to_rgb(h, l, s)
|
|
62
|
-
palette_rgb.add((round(r_ * 255), round(g_ * 255), round(b_ * 255)))
|
|
63
|
-
comps = set()
|
|
64
|
-
for d in (proj.get("commonComponents", {}), proj.get("formComponents", {})):
|
|
65
|
-
if isinstance(d, dict):
|
|
66
|
-
comps.update(k.lower() for k in d.keys())
|
|
67
|
-
return palette_rgb, comps, proj
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def extract_colors(html):
|
|
71
|
-
"""提取 HTML 里的颜色(#hex/hsl/rgb)→ rgb 集合。"""
|
|
72
|
-
out = set()
|
|
73
|
-
for m in re.findall(r"#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b", html):
|
|
74
|
-
h = m if len(m) == 6 else m * 2
|
|
75
|
-
out.add((int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)))
|
|
76
|
-
for m in re.findall(r"hsl\(\s*([\d.]+)[,\s]+([\d.]+)%[,\s]+([\d.]+)%", html):
|
|
77
|
-
h, s, l = float(m[0]) / 360.0, float(m[1]) / 100.0, float(m[2]) / 100.0
|
|
78
|
-
r_, g_, b_ = colorsys.hls_to_rgb(h, l, s)
|
|
79
|
-
out.add((round(r_ * 255), round(g_ * 255), round(b_ * 255)))
|
|
80
|
-
for m in re.findall(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)", html):
|
|
81
|
-
out.add((int(m[0]), int(m[1]), int(m[2])))
|
|
82
|
-
return out
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def extract_components(html):
|
|
86
|
-
"""提取 HTML 里的组件标签(el-xxx/van-xxx/a-xxx 等)。"""
|
|
87
|
-
return set(m.lower() for m in re.findall(r"<(?:el|van|a|n|iview|ant)-([\w-]+)", html))
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def near(c1, c2, tol=40):
|
|
91
|
-
return all(abs(a - b) <= tol for a, b in zip(c1, c2))
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def color_fidelity(html, palette_rgb):
|
|
95
|
-
cols = extract_colors(html)
|
|
96
|
-
if not cols:
|
|
97
|
-
return 0.0, 0
|
|
98
|
-
real = sum(1 for c in cols if any(near(c, p) for p in palette_rgb) or c in _NEUTRAL)
|
|
99
|
-
return round(real / len(cols), 3), len(cols)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def comp_fidelity(html, real_comps):
|
|
103
|
-
comps = extract_components(html)
|
|
104
|
-
if not comps:
|
|
105
|
-
return 0.0, 0
|
|
106
|
-
if not real_comps:
|
|
107
|
-
return 1.0, len(comps) # 无真组件集则不罚
|
|
108
|
-
real = sum(1 for c in comps if c in real_comps)
|
|
109
|
-
return round(real / len(comps), 3), len(comps)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def run():
|
|
113
|
-
palette, comps, proj = real_design()
|
|
114
|
-
print(" 真色板 rgb:", list(palette)[:4], "| 真组件:", list(comps)[:8])
|
|
115
|
-
rep = {"pages": []}
|
|
116
|
-
for pg in PAGES:
|
|
117
|
-
bare = chat(f"画一个 {pg} 的 HTML 原型(单文件,含表格/表单/按钮,内联样式)。直接输出 HTML。")
|
|
118
|
-
ds = ("fywl-ui 真设计系统:主色 hsl(214,86%,59%) 成功 hsl(100,54%,49%) 警告 hsl(36,100%,64%) "
|
|
119
|
-
"危险 hsl(0,100%,68%) 圆角 0.25rem 布局 mixed-nav 侧栏 160px;"
|
|
120
|
-
"组件用 ElementPlus(el-table/el-form/el-button/el-input/el-select/el-pagination)。")
|
|
121
|
-
# BF4 杠杆:CSS 变量注入(:root 定义真色板 + 强制 var() 用色 → 颜色全是色板色)
|
|
122
|
-
cssvar = ("<style>:root{--primary:hsl(214,86%,59%);--success:hsl(100,54%,49%);"
|
|
123
|
-
"--warning:hsl(36,100%,64%);--danger:hsl(0,100%,68%);--text:#333;--border:#d9d9d9;--bg:#f5f5f5}</style>")
|
|
124
|
-
scaff = chat(f"画一个 {pg} 的 HTML 原型(单文件,内联样式)。\n"
|
|
125
|
-
f"【设计系统接地,必须保真】:{ds}\n"
|
|
126
|
-
f"⚠️ 颜色铁律(CSS 变量):把这段 {cssvar} 放在 <head>,"
|
|
127
|
-
f"所有 color/background/border 【必须用 var(--primary)/var(--success)/var(--warning)/var(--danger)/var(--text)/var(--border)/var(--bg)】,"
|
|
128
|
-
f"【禁止】写任何裸 hex/hsl 色值(#409eff 等一律不许);组件用 el-xxx。直接输出 HTML。")
|
|
129
|
-
bP, bN = color_fidelity(bare, palette)
|
|
130
|
-
sP, sN = color_fidelity(scaff, palette)
|
|
131
|
-
bC, _ = comp_fidelity(bare, comps)
|
|
132
|
-
sC, _ = comp_fidelity(scaff, comps)
|
|
133
|
-
rep["pages"].append({"page": pg, "bare_color": bP, "scaffold_color": sP,
|
|
134
|
-
"bare_comp": bC, "scaffold_comp": sC})
|
|
135
|
-
print(" %s: 颜色保真 bare=%.0f%% scaff=%.0f%% | 组件保真 bare=%.0f%% scaff=%.0f%%" % (
|
|
136
|
-
pg, bP*100, sP*100, bC*100, sC*100))
|
|
137
|
-
n = len(PAGES) or 1
|
|
138
|
-
rep["agg"] = {
|
|
139
|
-
"bare_color": round(sum(p["bare_color"] for p in rep["pages"])/n, 3),
|
|
140
|
-
"scaffold_color": round(sum(p["scaffold_color"] for p in rep["pages"])/n, 3),
|
|
141
|
-
"bare_comp": round(sum(p["bare_comp"] for p in rep["pages"])/n, 3),
|
|
142
|
-
"scaffold_comp": round(sum(p["scaffold_comp"] for p in rep["pages"])/n, 3),
|
|
143
|
-
}
|
|
144
|
-
return rep
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def main():
|
|
148
|
-
import argparse
|
|
149
|
-
ap = argparse.ArgumentParser()
|
|
150
|
-
ap.add_argument("--json", action="store_true")
|
|
151
|
-
args = ap.parse_args()
|
|
152
|
-
r = run()
|
|
153
|
-
a = r["agg"]
|
|
154
|
-
if args.json:
|
|
155
|
-
print(json.dumps(r, ensure_ascii=False, indent=2))
|
|
156
|
-
return
|
|
157
|
-
print("\n## FW9 原型保真度飞轮(vs 真实 fywl-ui 设计系统)")
|
|
158
|
-
print("| 维度 | bare(无设计接地) | +真设计系统接地 |")
|
|
159
|
-
print("|---|---|---|")
|
|
160
|
-
print("| 颜色保真(色∈真fywl-ui色板) | %.0f%% | %.0f%% |" % (a["bare_color"]*100, a["scaffold_color"]*100))
|
|
161
|
-
print("| 组件保真(用真el-组件) | %.0f%% | %.0f%% |" % (a["bare_comp"]*100, a["scaffold_comp"]*100))
|
|
162
|
-
print("\n保真=原型是 fywl-ui 真样子(真色板/真组件/真layout),非通用蓝/编造组件。bare 通用→低保真;scaffold 接真→高保真。")
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if __name__ == "__main__":
|
|
166
|
-
main()
|
|
1
|
+
"""prototype_fidelity_flywheel.py — FW9 原型保真度飞轮(vs 真实 fywl-ui 设计系统)。
|
|
2
|
+
|
|
3
|
+
用户根因例子:"原型保真不保真"。本尺子量:生成原型的颜色/组件是不是 fywl-ui 真设计系统的
|
|
4
|
+
(get_design_system 返回的真色板 hsl(214,86%,59%)/真组件/真layout),而非泛泛 #409eff 蓝或编造组件。
|
|
5
|
+
bare(无设计系统接地→通用色/编造组件) vs +真设计系统接地(用真 hsl 色板/真组件)。
|
|
6
|
+
color保真率 = 原型颜色∈真色板比例;component保真率 = 真组件占比。
|
|
7
|
+
|
|
8
|
+
跑法: docker exec -i wlinkj-workspace-backend-1 python /app/scripts/validation/eval/prototype_fidelity_flywheel.py
|
|
9
|
+
"""
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
import sys
|
|
13
|
+
import json
|
|
14
|
+
import colorsys
|
|
15
|
+
import time
|
|
16
|
+
import urllib.request
|
|
17
|
+
import urllib.error
|
|
18
|
+
|
|
19
|
+
for _p in ("/app", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))):
|
|
20
|
+
if os.path.isdir(_p) and _p not in sys.path:
|
|
21
|
+
sys.path.insert(0, _p)
|
|
22
|
+
|
|
23
|
+
from app.routers import mcp_handlers as H # noqa: E402
|
|
24
|
+
try:
|
|
25
|
+
H._init_handlers()
|
|
26
|
+
except Exception:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
CHAT_URL = os.environ.get("ALI_CHAT_BASE", "").rstrip("/") + "/chat/completions"
|
|
30
|
+
CHAT_KEY = os.environ.get("DASHSCOPE_API_KEY", "")
|
|
31
|
+
MODEL = "qwen-turbo"
|
|
32
|
+
PAGES = ["车辆保险列表页", "异常记录表单页", "合同维护详情页"]
|
|
33
|
+
_NEUTRAL = {(255, 255, 255), (0, 0, 0), (51, 51, 51), (102, 102, 102), (153, 153, 153),
|
|
34
|
+
(240, 240, 240), (250, 250, 250), (217, 217, 217), (232, 232, 232), (245, 245, 245)}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def chat(prompt, max_tokens=1200, timeout=90):
|
|
38
|
+
body = json.dumps({"model": MODEL, "messages": [{"role": "user", "content": prompt}],
|
|
39
|
+
"temperature": 0.2, "max_tokens": max_tokens}).encode()
|
|
40
|
+
for a in range(3):
|
|
41
|
+
try:
|
|
42
|
+
req = urllib.request.Request(CHAT_URL, data=body,
|
|
43
|
+
headers={"Authorization": f"Bearer {CHAT_KEY}", "Content-Type": "application/json"})
|
|
44
|
+
return json.loads(urllib.request.urlopen(req, timeout=timeout).read())["choices"][0]["message"]["content"]
|
|
45
|
+
except (urllib.error.URLError, TimeoutError, OSError, KeyError) as e:
|
|
46
|
+
if a < 2: time.sleep(1.0*(a+1))
|
|
47
|
+
else: return ""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def real_design():
|
|
51
|
+
"""fywl-ui 真设计系统:色板(rgb 集) + 真组件名 + layout。"""
|
|
52
|
+
r = H.dispatch("get_design_system", {}) or {}
|
|
53
|
+
proj = next((p for p in r.get("projects", []) if p.get("project") == "fywl-ui"), {})
|
|
54
|
+
colors = proj.get("colors", {}) or {}
|
|
55
|
+
palette_rgb = set()
|
|
56
|
+
for v in colors.values():
|
|
57
|
+
if isinstance(v, str) and v.startswith("hsl"):
|
|
58
|
+
m = re.match(r"hsl\(\s*([\d.]+)[,\s]+([\d.]+)%[,\s]+([\d.]+)%", v)
|
|
59
|
+
if m:
|
|
60
|
+
h, s, l = float(m.group(1)) / 360.0, float(m.group(2)) / 100.0, float(m.group(3)) / 100.0
|
|
61
|
+
r_, g_, b_ = colorsys.hls_to_rgb(h, l, s)
|
|
62
|
+
palette_rgb.add((round(r_ * 255), round(g_ * 255), round(b_ * 255)))
|
|
63
|
+
comps = set()
|
|
64
|
+
for d in (proj.get("commonComponents", {}), proj.get("formComponents", {})):
|
|
65
|
+
if isinstance(d, dict):
|
|
66
|
+
comps.update(k.lower() for k in d.keys())
|
|
67
|
+
return palette_rgb, comps, proj
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def extract_colors(html):
|
|
71
|
+
"""提取 HTML 里的颜色(#hex/hsl/rgb)→ rgb 集合。"""
|
|
72
|
+
out = set()
|
|
73
|
+
for m in re.findall(r"#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b", html):
|
|
74
|
+
h = m if len(m) == 6 else m * 2
|
|
75
|
+
out.add((int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)))
|
|
76
|
+
for m in re.findall(r"hsl\(\s*([\d.]+)[,\s]+([\d.]+)%[,\s]+([\d.]+)%", html):
|
|
77
|
+
h, s, l = float(m[0]) / 360.0, float(m[1]) / 100.0, float(m[2]) / 100.0
|
|
78
|
+
r_, g_, b_ = colorsys.hls_to_rgb(h, l, s)
|
|
79
|
+
out.add((round(r_ * 255), round(g_ * 255), round(b_ * 255)))
|
|
80
|
+
for m in re.findall(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)", html):
|
|
81
|
+
out.add((int(m[0]), int(m[1]), int(m[2])))
|
|
82
|
+
return out
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def extract_components(html):
|
|
86
|
+
"""提取 HTML 里的组件标签(el-xxx/van-xxx/a-xxx 等)。"""
|
|
87
|
+
return set(m.lower() for m in re.findall(r"<(?:el|van|a|n|iview|ant)-([\w-]+)", html))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def near(c1, c2, tol=40):
|
|
91
|
+
return all(abs(a - b) <= tol for a, b in zip(c1, c2))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def color_fidelity(html, palette_rgb):
|
|
95
|
+
cols = extract_colors(html)
|
|
96
|
+
if not cols:
|
|
97
|
+
return 0.0, 0
|
|
98
|
+
real = sum(1 for c in cols if any(near(c, p) for p in palette_rgb) or c in _NEUTRAL)
|
|
99
|
+
return round(real / len(cols), 3), len(cols)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def comp_fidelity(html, real_comps):
|
|
103
|
+
comps = extract_components(html)
|
|
104
|
+
if not comps:
|
|
105
|
+
return 0.0, 0
|
|
106
|
+
if not real_comps:
|
|
107
|
+
return 1.0, len(comps) # 无真组件集则不罚
|
|
108
|
+
real = sum(1 for c in comps if c in real_comps)
|
|
109
|
+
return round(real / len(comps), 3), len(comps)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def run():
|
|
113
|
+
palette, comps, proj = real_design()
|
|
114
|
+
print(" 真色板 rgb:", list(palette)[:4], "| 真组件:", list(comps)[:8])
|
|
115
|
+
rep = {"pages": []}
|
|
116
|
+
for pg in PAGES:
|
|
117
|
+
bare = chat(f"画一个 {pg} 的 HTML 原型(单文件,含表格/表单/按钮,内联样式)。直接输出 HTML。")
|
|
118
|
+
ds = ("fywl-ui 真设计系统:主色 hsl(214,86%,59%) 成功 hsl(100,54%,49%) 警告 hsl(36,100%,64%) "
|
|
119
|
+
"危险 hsl(0,100%,68%) 圆角 0.25rem 布局 mixed-nav 侧栏 160px;"
|
|
120
|
+
"组件用 ElementPlus(el-table/el-form/el-button/el-input/el-select/el-pagination)。")
|
|
121
|
+
# BF4 杠杆:CSS 变量注入(:root 定义真色板 + 强制 var() 用色 → 颜色全是色板色)
|
|
122
|
+
cssvar = ("<style>:root{--primary:hsl(214,86%,59%);--success:hsl(100,54%,49%);"
|
|
123
|
+
"--warning:hsl(36,100%,64%);--danger:hsl(0,100%,68%);--text:#333;--border:#d9d9d9;--bg:#f5f5f5}</style>")
|
|
124
|
+
scaff = chat(f"画一个 {pg} 的 HTML 原型(单文件,内联样式)。\n"
|
|
125
|
+
f"【设计系统接地,必须保真】:{ds}\n"
|
|
126
|
+
f"⚠️ 颜色铁律(CSS 变量):把这段 {cssvar} 放在 <head>,"
|
|
127
|
+
f"所有 color/background/border 【必须用 var(--primary)/var(--success)/var(--warning)/var(--danger)/var(--text)/var(--border)/var(--bg)】,"
|
|
128
|
+
f"【禁止】写任何裸 hex/hsl 色值(#409eff 等一律不许);组件用 el-xxx。直接输出 HTML。")
|
|
129
|
+
bP, bN = color_fidelity(bare, palette)
|
|
130
|
+
sP, sN = color_fidelity(scaff, palette)
|
|
131
|
+
bC, _ = comp_fidelity(bare, comps)
|
|
132
|
+
sC, _ = comp_fidelity(scaff, comps)
|
|
133
|
+
rep["pages"].append({"page": pg, "bare_color": bP, "scaffold_color": sP,
|
|
134
|
+
"bare_comp": bC, "scaffold_comp": sC})
|
|
135
|
+
print(" %s: 颜色保真 bare=%.0f%% scaff=%.0f%% | 组件保真 bare=%.0f%% scaff=%.0f%%" % (
|
|
136
|
+
pg, bP*100, sP*100, bC*100, sC*100))
|
|
137
|
+
n = len(PAGES) or 1
|
|
138
|
+
rep["agg"] = {
|
|
139
|
+
"bare_color": round(sum(p["bare_color"] for p in rep["pages"])/n, 3),
|
|
140
|
+
"scaffold_color": round(sum(p["scaffold_color"] for p in rep["pages"])/n, 3),
|
|
141
|
+
"bare_comp": round(sum(p["bare_comp"] for p in rep["pages"])/n, 3),
|
|
142
|
+
"scaffold_comp": round(sum(p["scaffold_comp"] for p in rep["pages"])/n, 3),
|
|
143
|
+
}
|
|
144
|
+
return rep
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def main():
|
|
148
|
+
import argparse
|
|
149
|
+
ap = argparse.ArgumentParser()
|
|
150
|
+
ap.add_argument("--json", action="store_true")
|
|
151
|
+
args = ap.parse_args()
|
|
152
|
+
r = run()
|
|
153
|
+
a = r["agg"]
|
|
154
|
+
if args.json:
|
|
155
|
+
print(json.dumps(r, ensure_ascii=False, indent=2))
|
|
156
|
+
return
|
|
157
|
+
print("\n## FW9 原型保真度飞轮(vs 真实 fywl-ui 设计系统)")
|
|
158
|
+
print("| 维度 | bare(无设计接地) | +真设计系统接地 |")
|
|
159
|
+
print("|---|---|---|")
|
|
160
|
+
print("| 颜色保真(色∈真fywl-ui色板) | %.0f%% | %.0f%% |" % (a["bare_color"]*100, a["scaffold_color"]*100))
|
|
161
|
+
print("| 组件保真(用真el-组件) | %.0f%% | %.0f%% |" % (a["bare_comp"]*100, a["scaffold_comp"]*100))
|
|
162
|
+
print("\n保真=原型是 fywl-ui 真样子(真色板/真组件/真layout),非通用蓝/编造组件。bare 通用→低保真;scaffold 接真→高保真。")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
main()
|
|
@@ -1,148 +1,148 @@
|
|
|
1
|
-
"""recall_flywheel.py — FW1 检索类召回飞轮(非循环 held-out gold)。
|
|
2
|
-
|
|
3
|
-
T1.0 的召回 R~80% 用 ILIKE-gold 是循环的(改非ILIKE检索提不了R)。本飞轮用**非循环 gold**:
|
|
4
|
-
held-out = 图邻居中【不含主题关键词】的实体(只有 graph/semantic 检索能找到,ILIKE 找不到)。
|
|
5
|
-
量各检索策略对此 gold 的召回 → 改检索(加图扩展→语义)→ 重量 → 直到 ≥0.85。
|
|
6
|
-
纯检索质量(无 LLM),快,可反复转飞轮。
|
|
7
|
-
|
|
8
|
-
跑法: docker exec -i wlinkj-workspace-backend-1 python /app/scripts/validation/eval/recall_flywheel.py
|
|
9
|
-
"""
|
|
10
|
-
import os
|
|
11
|
-
import sys
|
|
12
|
-
import json
|
|
13
|
-
|
|
14
|
-
for _p in ("/app", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))):
|
|
15
|
-
if os.path.isdir(_p) and _p not in sys.path:
|
|
16
|
-
sys.path.insert(0, _p)
|
|
17
|
-
|
|
18
|
-
from sqlalchemy import text, bindparam # noqa: E402
|
|
19
|
-
from app.db import SessionLocal # noqa: E402
|
|
20
|
-
|
|
21
|
-
THEMES = ["考勤", "排班", "加班", "车辆", "报警", "保险", "能耗", "预算", "导出", "审批"]
|
|
22
|
-
TARGET = 0.85
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def _q(s, sql, params=None):
|
|
26
|
-
try:
|
|
27
|
-
return s.execute(text(sql), params or {}).fetchall()
|
|
28
|
-
except Exception:
|
|
29
|
-
try:
|
|
30
|
-
s.rollback()
|
|
31
|
-
except Exception:
|
|
32
|
-
pass
|
|
33
|
-
return []
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def ilike_ids(s, theme, limit):
|
|
37
|
-
"""name/cn 关键词命中(T1.0 现状检索口径)。"""
|
|
38
|
-
return [r[0] for r in _q(s,
|
|
39
|
-
"SELECT id FROM entities WHERE (cn ILIKE :p OR canonical ILIKE :p) LIMIT :n",
|
|
40
|
-
{"p": f"%{theme}%", "n": limit})]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def heldout_gold(s, theme, max_n=25):
|
|
44
|
-
"""非循环 gold:cn_desc(描述)提及主题 但 name/cn 不含 = 只有描述/语义/图能找到,
|
|
45
|
-
关键词搜 name/cn 找不到。cn_desc 与 name/cn 是独立信号 → 公平。"""
|
|
46
|
-
rows = _q(s,
|
|
47
|
-
"SELECT id FROM entities WHERE cn_desc ILIKE :p "
|
|
48
|
-
"AND NOT (canonical ILIKE :p OR cn ILIKE :p) LIMIT :n",
|
|
49
|
-
{"p": f"%{theme}%", "n": max_n * 3})
|
|
50
|
-
return [r[0] for r in rows][:max_n]
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def strat_ilike(s, theme, limit=80):
|
|
54
|
-
"""基线:name/cn 关键词(T1.0 现状)。"""
|
|
55
|
-
return set(ilike_ids(s, theme, limit))
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def strat_ilike_desc(s, theme, limit=80):
|
|
59
|
-
"""杠杆1:name/cn + cn_desc(多搜描述列,廉价高杠杆)。"""
|
|
60
|
-
return set(r[0] for r in _q(s,
|
|
61
|
-
"SELECT id FROM entities WHERE (canonical ILIKE :p OR cn ILIKE :p OR cn_desc ILIKE :p) LIMIT :n",
|
|
62
|
-
{"p": f"%{theme}%", "n": limit}))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def strat_ilike_graph(s, theme, seed_limit=25):
|
|
66
|
-
"""杠杆2:name/cn 种子 + 1跳图扩展。"""
|
|
67
|
-
seeds = ilike_ids(s, theme, seed_limit)
|
|
68
|
-
res = set(seeds)
|
|
69
|
-
if seeds:
|
|
70
|
-
stmt = text(
|
|
71
|
-
"SELECT DISTINCT e.to_id FROM edges e WHERE e.from_id IN :ids"
|
|
72
|
-
).bindparams(bindparam("ids", expanding=True))
|
|
73
|
-
try:
|
|
74
|
-
for r in s.execute(stmt, {"ids": seeds}).fetchall():
|
|
75
|
-
if r[0]:
|
|
76
|
-
res.add(r[0])
|
|
77
|
-
except Exception:
|
|
78
|
-
try:
|
|
79
|
-
s.rollback()
|
|
80
|
-
except Exception:
|
|
81
|
-
pass
|
|
82
|
-
return res
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def recall(strategy_ids, gold):
|
|
86
|
-
if not gold:
|
|
87
|
-
return None
|
|
88
|
-
return len(set(gold) & strategy_ids) / len(gold)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def run(verbose=True):
|
|
92
|
-
s = SessionLocal()
|
|
93
|
-
per_theme = []
|
|
94
|
-
accA = accB = accC = 0.0
|
|
95
|
-
cnt = 0
|
|
96
|
-
for th in THEMES:
|
|
97
|
-
gold = heldout_gold(s, th, 25)
|
|
98
|
-
if not gold:
|
|
99
|
-
continue
|
|
100
|
-
A = strat_ilike(s, th, 80)
|
|
101
|
-
B = strat_ilike_desc(s, th, 80)
|
|
102
|
-
C = strat_ilike_graph(s, th, 25)
|
|
103
|
-
rA, rB, rC = recall(A, gold), recall(B, gold), recall(C, gold)
|
|
104
|
-
per_theme.append({"theme": th, "gold_n": len(gold),
|
|
105
|
-
"ilike": round(rA, 3), "ilike_desc": round(rB, 3), "ilike_graph": round(rC, 3)})
|
|
106
|
-
accA += rA
|
|
107
|
-
accB += rB
|
|
108
|
-
accC += rC
|
|
109
|
-
cnt += 1
|
|
110
|
-
if verbose:
|
|
111
|
-
print(" %s: gold=%d | ILIKE=%.2f | +desc=%.2f | +图=%.2f" % (th, len(gold), rA, rB, rC))
|
|
112
|
-
s.close()
|
|
113
|
-
n = cnt or 1
|
|
114
|
-
return {"per_theme": per_theme, "n_themes": cnt,
|
|
115
|
-
"ilike": round(accA / n, 3), "ilike_desc": round(accB / n, 3), "ilike_graph": round(accC / n, 3),
|
|
116
|
-
"desc_gain_pp": round((accB - accA) / n * 100, 1),
|
|
117
|
-
"graph_gain_pp": round((accC - accA) / n * 100, 1),
|
|
118
|
-
"target": TARGET}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def main():
|
|
122
|
-
import argparse
|
|
123
|
-
ap = argparse.ArgumentParser()
|
|
124
|
-
ap.add_argument("--json", action="store_true")
|
|
125
|
-
args = ap.parse_args()
|
|
126
|
-
r = run()
|
|
127
|
-
if args.json:
|
|
128
|
-
print(json.dumps(r, ensure_ascii=False, indent=2))
|
|
129
|
-
return
|
|
130
|
-
print("\n## FW1 召回飞轮(held-out = cn_desc 提及但 name/cn 不含,非循环独立 gold)")
|
|
131
|
-
print("| 检索策略 | 召回 R | 达标(≥85%%) |")
|
|
132
|
-
print("|---|---|---|")
|
|
133
|
-
print("| ILIKE name/cn(T1.0 现状) | %.1f%% | %s |" % (r["ilike"] * 100, "✓" if r["ilike"] >= TARGET else "✗"))
|
|
134
|
-
print("| ILIKE +cn_desc(杠杆1 廉价) | %.1f%% | %s |" % (r["ilike_desc"] * 100, "✓" if r["ilike_desc"] >= TARGET else "✗"))
|
|
135
|
-
print("| ILIKE +图扩展(杠杆2) | %.1f%% | %s |" % (r["ilike_graph"] * 100, "✓" if r["ilike_graph"] >= TARGET else "✗"))
|
|
136
|
-
print("| +cn_desc 增益 | %+.1fpp | — |" % r["desc_gain_pp"])
|
|
137
|
-
print("| +图扩展 增益 | %+.1fpp | — |" % r["graph_gain_pp"])
|
|
138
|
-
best = max(r["ilike_desc"], r["ilike_graph"])
|
|
139
|
-
met = best >= TARGET
|
|
140
|
-
winner = "+cn_desc" if r["ilike_desc"] >= r["ilike_graph"] else "+图扩展"
|
|
141
|
-
print("\n飞轮状态: 最佳策略(%s)召回 %.1f%% %s 85%% 目标。%s" % (
|
|
142
|
-
winner, best * 100, "达标" if met else "未达",
|
|
143
|
-
"→ 胜出杠杆该接进 wl-search 检索;召回飞轮此轮达标,转 FW2" if met
|
|
144
|
-
else "→ 下轮:组合杠杆(+desc+图) / 语义 rag_search / 提种子数,继续转"))
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if __name__ == "__main__":
|
|
148
|
-
main()
|
|
1
|
+
"""recall_flywheel.py — FW1 检索类召回飞轮(非循环 held-out gold)。
|
|
2
|
+
|
|
3
|
+
T1.0 的召回 R~80% 用 ILIKE-gold 是循环的(改非ILIKE检索提不了R)。本飞轮用**非循环 gold**:
|
|
4
|
+
held-out = 图邻居中【不含主题关键词】的实体(只有 graph/semantic 检索能找到,ILIKE 找不到)。
|
|
5
|
+
量各检索策略对此 gold 的召回 → 改检索(加图扩展→语义)→ 重量 → 直到 ≥0.85。
|
|
6
|
+
纯检索质量(无 LLM),快,可反复转飞轮。
|
|
7
|
+
|
|
8
|
+
跑法: docker exec -i wlinkj-workspace-backend-1 python /app/scripts/validation/eval/recall_flywheel.py
|
|
9
|
+
"""
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
for _p in ("/app", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))):
|
|
15
|
+
if os.path.isdir(_p) and _p not in sys.path:
|
|
16
|
+
sys.path.insert(0, _p)
|
|
17
|
+
|
|
18
|
+
from sqlalchemy import text, bindparam # noqa: E402
|
|
19
|
+
from app.db import SessionLocal # noqa: E402
|
|
20
|
+
|
|
21
|
+
THEMES = ["考勤", "排班", "加班", "车辆", "报警", "保险", "能耗", "预算", "导出", "审批"]
|
|
22
|
+
TARGET = 0.85
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _q(s, sql, params=None):
|
|
26
|
+
try:
|
|
27
|
+
return s.execute(text(sql), params or {}).fetchall()
|
|
28
|
+
except Exception:
|
|
29
|
+
try:
|
|
30
|
+
s.rollback()
|
|
31
|
+
except Exception:
|
|
32
|
+
pass
|
|
33
|
+
return []
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def ilike_ids(s, theme, limit):
|
|
37
|
+
"""name/cn 关键词命中(T1.0 现状检索口径)。"""
|
|
38
|
+
return [r[0] for r in _q(s,
|
|
39
|
+
"SELECT id FROM entities WHERE (cn ILIKE :p OR canonical ILIKE :p) LIMIT :n",
|
|
40
|
+
{"p": f"%{theme}%", "n": limit})]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def heldout_gold(s, theme, max_n=25):
|
|
44
|
+
"""非循环 gold:cn_desc(描述)提及主题 但 name/cn 不含 = 只有描述/语义/图能找到,
|
|
45
|
+
关键词搜 name/cn 找不到。cn_desc 与 name/cn 是独立信号 → 公平。"""
|
|
46
|
+
rows = _q(s,
|
|
47
|
+
"SELECT id FROM entities WHERE cn_desc ILIKE :p "
|
|
48
|
+
"AND NOT (canonical ILIKE :p OR cn ILIKE :p) LIMIT :n",
|
|
49
|
+
{"p": f"%{theme}%", "n": max_n * 3})
|
|
50
|
+
return [r[0] for r in rows][:max_n]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def strat_ilike(s, theme, limit=80):
|
|
54
|
+
"""基线:name/cn 关键词(T1.0 现状)。"""
|
|
55
|
+
return set(ilike_ids(s, theme, limit))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def strat_ilike_desc(s, theme, limit=80):
|
|
59
|
+
"""杠杆1:name/cn + cn_desc(多搜描述列,廉价高杠杆)。"""
|
|
60
|
+
return set(r[0] for r in _q(s,
|
|
61
|
+
"SELECT id FROM entities WHERE (canonical ILIKE :p OR cn ILIKE :p OR cn_desc ILIKE :p) LIMIT :n",
|
|
62
|
+
{"p": f"%{theme}%", "n": limit}))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def strat_ilike_graph(s, theme, seed_limit=25):
|
|
66
|
+
"""杠杆2:name/cn 种子 + 1跳图扩展。"""
|
|
67
|
+
seeds = ilike_ids(s, theme, seed_limit)
|
|
68
|
+
res = set(seeds)
|
|
69
|
+
if seeds:
|
|
70
|
+
stmt = text(
|
|
71
|
+
"SELECT DISTINCT e.to_id FROM edges e WHERE e.from_id IN :ids"
|
|
72
|
+
).bindparams(bindparam("ids", expanding=True))
|
|
73
|
+
try:
|
|
74
|
+
for r in s.execute(stmt, {"ids": seeds}).fetchall():
|
|
75
|
+
if r[0]:
|
|
76
|
+
res.add(r[0])
|
|
77
|
+
except Exception:
|
|
78
|
+
try:
|
|
79
|
+
s.rollback()
|
|
80
|
+
except Exception:
|
|
81
|
+
pass
|
|
82
|
+
return res
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def recall(strategy_ids, gold):
|
|
86
|
+
if not gold:
|
|
87
|
+
return None
|
|
88
|
+
return len(set(gold) & strategy_ids) / len(gold)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def run(verbose=True):
|
|
92
|
+
s = SessionLocal()
|
|
93
|
+
per_theme = []
|
|
94
|
+
accA = accB = accC = 0.0
|
|
95
|
+
cnt = 0
|
|
96
|
+
for th in THEMES:
|
|
97
|
+
gold = heldout_gold(s, th, 25)
|
|
98
|
+
if not gold:
|
|
99
|
+
continue
|
|
100
|
+
A = strat_ilike(s, th, 80)
|
|
101
|
+
B = strat_ilike_desc(s, th, 80)
|
|
102
|
+
C = strat_ilike_graph(s, th, 25)
|
|
103
|
+
rA, rB, rC = recall(A, gold), recall(B, gold), recall(C, gold)
|
|
104
|
+
per_theme.append({"theme": th, "gold_n": len(gold),
|
|
105
|
+
"ilike": round(rA, 3), "ilike_desc": round(rB, 3), "ilike_graph": round(rC, 3)})
|
|
106
|
+
accA += rA
|
|
107
|
+
accB += rB
|
|
108
|
+
accC += rC
|
|
109
|
+
cnt += 1
|
|
110
|
+
if verbose:
|
|
111
|
+
print(" %s: gold=%d | ILIKE=%.2f | +desc=%.2f | +图=%.2f" % (th, len(gold), rA, rB, rC))
|
|
112
|
+
s.close()
|
|
113
|
+
n = cnt or 1
|
|
114
|
+
return {"per_theme": per_theme, "n_themes": cnt,
|
|
115
|
+
"ilike": round(accA / n, 3), "ilike_desc": round(accB / n, 3), "ilike_graph": round(accC / n, 3),
|
|
116
|
+
"desc_gain_pp": round((accB - accA) / n * 100, 1),
|
|
117
|
+
"graph_gain_pp": round((accC - accA) / n * 100, 1),
|
|
118
|
+
"target": TARGET}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main():
|
|
122
|
+
import argparse
|
|
123
|
+
ap = argparse.ArgumentParser()
|
|
124
|
+
ap.add_argument("--json", action="store_true")
|
|
125
|
+
args = ap.parse_args()
|
|
126
|
+
r = run()
|
|
127
|
+
if args.json:
|
|
128
|
+
print(json.dumps(r, ensure_ascii=False, indent=2))
|
|
129
|
+
return
|
|
130
|
+
print("\n## FW1 召回飞轮(held-out = cn_desc 提及但 name/cn 不含,非循环独立 gold)")
|
|
131
|
+
print("| 检索策略 | 召回 R | 达标(≥85%%) |")
|
|
132
|
+
print("|---|---|---|")
|
|
133
|
+
print("| ILIKE name/cn(T1.0 现状) | %.1f%% | %s |" % (r["ilike"] * 100, "✓" if r["ilike"] >= TARGET else "✗"))
|
|
134
|
+
print("| ILIKE +cn_desc(杠杆1 廉价) | %.1f%% | %s |" % (r["ilike_desc"] * 100, "✓" if r["ilike_desc"] >= TARGET else "✗"))
|
|
135
|
+
print("| ILIKE +图扩展(杠杆2) | %.1f%% | %s |" % (r["ilike_graph"] * 100, "✓" if r["ilike_graph"] >= TARGET else "✗"))
|
|
136
|
+
print("| +cn_desc 增益 | %+.1fpp | — |" % r["desc_gain_pp"])
|
|
137
|
+
print("| +图扩展 增益 | %+.1fpp | — |" % r["graph_gain_pp"])
|
|
138
|
+
best = max(r["ilike_desc"], r["ilike_graph"])
|
|
139
|
+
met = best >= TARGET
|
|
140
|
+
winner = "+cn_desc" if r["ilike_desc"] >= r["ilike_graph"] else "+图扩展"
|
|
141
|
+
print("\n飞轮状态: 最佳策略(%s)召回 %.1f%% %s 85%% 目标。%s" % (
|
|
142
|
+
winner, best * 100, "达标" if met else "未达",
|
|
143
|
+
"→ 胜出杠杆该接进 wl-search 检索;召回飞轮此轮达标,转 FW2" if met
|
|
144
|
+
else "→ 下轮:组合杠杆(+desc+图) / 语义 rag_search / 提种子数,继续转"))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
main()
|