本节摘要:评测集 = 一组 (查询, 金标) 对,金标是 {chunk ID: 相关度} 的字典。查询三来源:①Agent 工具调用日志(6.3 埋的钩子)——查询分布天然真实,且带隐式反馈(搜索后模型 read 了哪个文件,哪个就是弱金标);②开发者访谈——问同事"你上次想找什么没找到",半小时能攒十条高价值难题;③git 历史弱标注——commit 首行当查询、变更文件当弱金标,量大但噪声高,必须人工复核。金标纪律:三级相关度(9.1)双人独立标注、分歧仲裁;金标指向 4.2 稳定 chunk ID 而非行号;上线前抽样人审金标对(金标错比检索错更隐蔽)。配比与规模:起步 50~100 条(经验值),标识符型/意图型/混排型三类的配比贴近查询日志的实际分布——7.4 表 3 已经证明过权重甜点随查询类型漂移,评测集的配比就是把这个信息带进调参。评测集构造的通用方法论(抽样、标注协议、一致性检验)详见《Evals 实战》第 3 章,本节聚焦代码检索特有:chunk 级对齐、Agent 日志挖掘与 git 弱标注。
阅读完本节,你应当能够:
{"qid": "q001", "query": "处理用户注销时删了哪些东西", "type": "intent", "gold": {"demo_repo/auth/session.py:3-8:kill_session": 3, "demo_repo/storage/token_store.py:1-4:revoke_refresh_token": 2}} {"qid": "q002", "query": "upload_with_retry", "type": "identifier", "gold": {"demo_repo/tasks/upload_task.py:3-10:upload_with_retry": 3}} {"qid": "q003", "query": "revokeToken 在哪被调用", "type": "mixed", "gold": {"demo_repo/storage/token_store.py:1-4:revoke_refresh_token": 3, "demo_repo/auth/session.py:3-8:kill_session": 2}}
字段说明:type 三分类(identifier/intent/mixed)——7.4 表 3 证明过不同类型的参数甜点不同,打标后指标可以分组看;gold 的键是 7.2 的稳定 chunk ID(path:start-end:symbol),值是 9.1 的三级相关度。金标不写行号:行号随编辑漂移,ID 至少跟着符号与区间走;仓库演进后按 ID 复核金标,比按行号追着改便宜一个量级。
| 来源 | 做法 | 信噪比 | 备注 |
|---|---|---|---|
| Agent 工具日志(6.3) | search_code 每次调用的 query + 返回命中 + 后续 read 的文件 |
高:真实分布 + 隐式反馈 | 隐式反馈要谨慎:read 了 ≠ 相关,需人审确认 |
| 开发者访谈 | "你上次想找什么、最后在哪找到的" | 高:难题富集 | 半小时约 10 条;适合补充日志里没覆盖的类型 |
| git 历史弱标注 | commit 首行当查询、变更文件当弱金标 | 低:量大噪声大 | 只当候选池,人工复核后才入集 |
# weak_label.py — 从 git 历史造弱金标候选(写法示意:subprocess 调 git,需人工复核) import subprocess def commits_touching(repo: str, since: str = "6 months ago") -> list[tuple[str, list[str]]]: """返回 (commit 首行, 变更文件列表)。合并提交与空首行会被朴素解析漏掉—— 弱标注只求量,不求全。写法示意,以 git 文档为准。""" out = subprocess.run( ["git", "-C", repo, "log", f"--since={since}", "--name-only", "--pretty=%s", "--no-merges"], capture_output=True, text=True, check=True).stdout pairs, subject, files = [], None, [] for line in out.splitlines(): if not line.strip(): # 空行 = 一条 commit 结束 if subject and files: pairs.append((subject, files)) subject, files = None, [] elif subject is None: subject = line.strip() else: files.append(line.strip()) if subject and files: pairs.append((subject, files)) return pairs
弱标注的使用姿势:跑出几百条候选 → 按类型分层抽样 ~50 条 → 人工判断"这个 commit 首行像不像一次真实的代码检索查询"(fix: typo 类直接丢)→ 像的再定金标。全程人工的那步不可省——弱标注是候选池,不是评测集。
标注协议(可直接抄给两位标注者):
💡 金标是评测集里唯一"手工且持续"的部分。仓库演进会让金标漂移(函数改名 → ID 失效):把"金标复核"排进每次嵌入模型或切分参数升级的流程里(9.3 的循环里有这个检查点),漂移的 ID 在
metas.jsonl里对不上号时就该处理——评测脚本应当对"金标 ID 找不到 chunk"报警,而不是默默跳过。
尺子(9.1)与被测物(9.2)都齐了。下一节把两者装进循环:跑评测、记历史、一次一变量地迭代,再用回归护栏守住阵地。