把“选题三角”做成一个评分系统:Prompt 工程 + 多模型投票实战

写在前面:这是一篇写给程序员、算法工程师、以及任何被"AI 评分到底靠不靠谱"折磨过的工程师的"评审委员会"工程实录。

我们讲 JSON 契约、并发投票、中位数聚合、metaevaluation------评分这件事,本来就该被工程化
| 🧭

本文定位|评分链路(下游)

本文聚焦"候选选题已经摆在桌上 "之后的那一环:怎么让 LLM-as-a-Judge 给出可复现、可审计、可发表 的分数。核心关键词是 JSON Schema × 多模型投票 × 中位数聚合 × metaevaluation

姊妹篇|数据链路(上游) :CSDN | 用 Python + OpenAlex + 国产大模型,给毕业论文造一个选题侦察兵------讲怎么从两个关键词出发,靠 OpenAlex 图谱 + 共现矩阵自动生成候选选题。

一句话区分:上游负责把候选选出来,本文负责把候选打分打稳。

0. 引言:告别"导师拍脑袋打分",拥抱"可复现的评审委员会"

为了给毕业论文 / PR Review / 简历筛选 / 需求评估打一个客观分数,你试着把候选丢给 ChatGPT,让它给个"综合分"。一开始跑得很欢,但很快你发现:同一个候选连续问 5 次,分数能在 6.5~8.5 之间反复横跳;换个表达顺序,分数又能差 1.5 分;要求它"严苛一点",它给所有候选都打了 9 分。这种**"单模型一锤定音"式的评分方案**,不仅不稳定,且在可复现性与公正性上危机四伏

架构师箴言 :在评估工作流的鄙视链里,依赖"一个模型给一个分"的方案处于最底端。我们要做的不应是在 temperature 上调参治标,而是建立一套有契约、有投票、有 metaevaluation 的机制

这不仅是 prompt 的更迭,更是从"模型问答(LLM-as-Oracle)"向"工程化评估治理(Evaluation Governance)"的思维降维打击。学术圈传得最广的那句"好选题 = Gap × Feasibility × Venue",本质上是一条心法口号------它不是一个现成的系统,而是一条思考框架。

现在市面上绝大多数 LLM 辅助选题的脚本,默认走的都是单模型 + 三段式 Prompt 流水线 :生成阶段让大模型吐 3 个候选,打分阶段让它给 Gap / Feasibility / Venue 三维打分,缩小阶段在短板不及格时让它把 scope 收窄。这套流水线在 demo 里跑得很顺,但落到生产环境里,单模型方案有三个老毛病

  • 顺序偏见:生成阶段排出来的 3 个候选,谁排第一谁分高 1~2 分
  • 风格偏见:打分阶段偏爱"术语堆得多"的候选------这恰好是大模型自己最爱写的风格,等于让模型给自己打分
  • 温度抖动:同一个候选连续问 5 次,综合分能在 6.5~8.5 之间反复横跳

所以本文的工程升级思路很简单:三角 Schema(Gap × Feasibility × Venue)和短板原则原样保留,但打分环节从"一个模型一锤定音"升级成"三模型并发投票 + 中位数聚合" 。今天我们就用 JSON 契约 + 多模型并发 + 统计聚合,把这条心法落成一个可复现的开题评审委员会

1. 核心底层逻辑:用"多模型投票"构造可信评分器

在很多新手的认知里,LLM-as-a-Judge 是一个"输入候选 → 输出分数"的黑盒。但在统计学的认知里,单个模型的输出永远是带噪声的

一个健壮的、可复现的评分系统,必须被设计为一个多模型投票委员会 。每一票都是一个独立观测,N 票通过中位数 + 离群剔除聚合,才得到一个可发布的分数。

1.1 单模型评分的方差期望

假设单模型评分误差服从正态分布:Xi∼N(μ,σ2)X_i \sim \mathcal{N}(\mu, \sigma^2)Xi∼N(μ,σ2)。

对 N 个独立模型的评分取中位数,根据渐近分布理论,中位数估计量的方差约为:

Var(X~N)≈πσ22N \mathrm{Var}(\tilde{X}_N) \approx \frac{\pi \sigma^2}{2N} Var(X~N)≈2Nπσ2

代入 N=3N = 3N=3:Var≈0.52σ2\mathrm{Var} \approx 0.52 \sigma^2Var≈0.52σ2。三模型投票,方差大约下降到原来的一半

如果再做 trimmed mean(去掉最高最低),N=5N = 5N=5 时方差能压到 0.3σ20.3 \sigma^20.3σ2 以下:

Pstable=1−∏i∈{M1,M2,M3}(1−pi) P_{\text{stable}} = 1 - \prod_{i \in \{M_1, M_2, M_3\}} \left(1 - p_i\right) Pstable=1−i∈{M1,M2,M3}∏(1−pi)

其中 pip_ipi 是单模型给出可信分数的概率。三模型并联,整体可用性轻松冲到 99%+------和单点爬虫与多源 API 的对比是同一个数学

这本质上是统计学问题,不是 prompt 工程问题

1.2 多模型投票的状态机

#mermaid-svg-15IMdAp3F3oKb1IR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-15IMdAp3F3oKb1IR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-15IMdAp3F3oKb1IR .error-icon{fill:#552222;}#mermaid-svg-15IMdAp3F3oKb1IR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-15IMdAp3F3oKb1IR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-15IMdAp3F3oKb1IR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-15IMdAp3F3oKb1IR .marker.cross{stroke:#333333;}#mermaid-svg-15IMdAp3F3oKb1IR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-15IMdAp3F3oKb1IR p{margin:0;}#mermaid-svg-15IMdAp3F3oKb1IR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-15IMdAp3F3oKb1IR .cluster-label text{fill:#333;}#mermaid-svg-15IMdAp3F3oKb1IR .cluster-label span{color:#333;}#mermaid-svg-15IMdAp3F3oKb1IR .cluster-label span p{background-color:transparent;}#mermaid-svg-15IMdAp3F3oKb1IR .label text,#mermaid-svg-15IMdAp3F3oKb1IR span{fill:#333;color:#333;}#mermaid-svg-15IMdAp3F3oKb1IR .node rect,#mermaid-svg-15IMdAp3F3oKb1IR .node circle,#mermaid-svg-15IMdAp3F3oKb1IR .node ellipse,#mermaid-svg-15IMdAp3F3oKb1IR .node polygon,#mermaid-svg-15IMdAp3F3oKb1IR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-15IMdAp3F3oKb1IR .rough-node .label text,#mermaid-svg-15IMdAp3F3oKb1IR .node .label text,#mermaid-svg-15IMdAp3F3oKb1IR .image-shape .label,#mermaid-svg-15IMdAp3F3oKb1IR .icon-shape .label{text-anchor:middle;}#mermaid-svg-15IMdAp3F3oKb1IR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-15IMdAp3F3oKb1IR .rough-node .label,#mermaid-svg-15IMdAp3F3oKb1IR .node .label,#mermaid-svg-15IMdAp3F3oKb1IR .image-shape .label,#mermaid-svg-15IMdAp3F3oKb1IR .icon-shape .label{text-align:center;}#mermaid-svg-15IMdAp3F3oKb1IR .node.clickable{cursor:pointer;}#mermaid-svg-15IMdAp3F3oKb1IR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-15IMdAp3F3oKb1IR .arrowheadPath{fill:#333333;}#mermaid-svg-15IMdAp3F3oKb1IR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-15IMdAp3F3oKb1IR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-15IMdAp3F3oKb1IR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-15IMdAp3F3oKb1IR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-15IMdAp3F3oKb1IR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-15IMdAp3F3oKb1IR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-15IMdAp3F3oKb1IR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-15IMdAp3F3oKb1IR .cluster text{fill:#333;}#mermaid-svg-15IMdAp3F3oKb1IR .cluster span{color:#333;}#mermaid-svg-15IMdAp3F3oKb1IR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-15IMdAp3F3oKb1IR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-15IMdAp3F3oKb1IR rect.text{fill:none;stroke-width:0;}#mermaid-svg-15IMdAp3F3oKb1IR .icon-shape,#mermaid-svg-15IMdAp3F3oKb1IR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-15IMdAp3F3oKb1IR .icon-shape p,#mermaid-svg-15IMdAp3F3oKb1IR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-15IMdAp3F3oKb1IR .icon-shape .label rect,#mermaid-svg-15IMdAp3F3oKb1IR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-15IMdAp3F3oKb1IR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-15IMdAp3F3oKb1IR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-15IMdAp3F3oKb1IR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 校验失败
校验通过


候选选题 JSON
Prompt 构造器

带 Schema 锁
DeepSeek 评审
通义 Qwen 评审
智谱 GLM 评审
Schema 校验

pydantic
聚合器

trimmed mean + 中位数
短板检查

min ≥ 7?
输出立项卡

  • 全模型快照
    MVR 缩小器

触发 Prompt B

每一个节点都可独立替换:换模型、换 schema、换聚合策略------主干不变。

2. 三驾马车:评审委员会的基础设施

构造一个工业级的评分器,有三个核武器级别的基础设施。

2.1 JSON Schema:让模型"不敢"乱说话

大模型最大的不可控就是"输出形态飘忽"。所以我们先用 pydantic 锁死 schema:

python 复制代码
from pydantic import BaseModel, Field, field_validator
from typing import Literal

class DimScore(BaseModel):
	score:     float     = Field(ge=0, le=10)
	reason:    str       = Field(min_length=20)   # 强制写够字,杜绝"很有意义"
	red_flags: list[str] = Field(default_factory=list)

class Review(BaseModel):
	gap:                DimScore
	feasibility:        DimScore
	venue:              DimScore
	gap_type:           Literal["contextual", "data", "method", "theory"]
	shrink_suggestions: list[str] = Field(min_length=2, max_length=5)
	cnki_keywords:      list[str] = Field(min_length=2, max_length=5)

	@field_validator("shrink_suggestions", "cnki_keywords")
	@classmethod
	def strip_empty(cls, v):
		return [s.strip() for s in v if s.strip()]

这里的几个反作弊心机

  • reason 强制 ≥ 20 字 → 杜绝"这个选题很好"的空话
  • gap_typeLiteral 枚举 → 模型必须四选一,不能编新词
  • shrink_suggestions 强制 2~5 条 → 杜绝偷懒只给一条

2.2 多模型并发:抗个体偏见的"北斗导航"

单模型打分有三个硬伤

  1. 顺序偏见(Position bias):调换候选顺序,分数差 1~2 分。LLM-as-a-Judge 的论文实测过。
  2. 风格偏见(Style bias):模型偏爱"术语堆得多"的候选------这恰好是大模型自己生成内容的特征,等于让模型给自己打分,左脚踩右脚原地起飞。
  3. 温度噪声 :你以为 temperature=0 就稳定了?同一个 prompt 连续跑 10 次仍有 0.5~1 分的抖动,因为底层有 batch、缓存、时间戳进 logit 的工程实现。

并发调用 DeepSeek / Qwen / GLM 三家------它们来自不同训练数据、不同 RLHF 偏好、不同对齐策略,偏见近似正交。三票聚合,偏见相互抵消。

2.3 中位数 + 离群剔除:聚合器的"VIP 门票"

为什么不是平均?因为平均对离群值零防御 。一个模型抽风给 2 分,平均分立刻被拉低。中位数 + trimmed mean 才是工程上正确的聚合策略

2.4 【实战代码】asyncio.gather 三模型并发投票

python 复制代码
import asyncio
import json
import os
from statistics import median
from openai import AsyncOpenAI

MODELS = [
	{"name": "deepseek-chat", "base": "https://api.deepseek.com",                          "key": "DEEPSEEK_API_KEY"},
	{"name": "qwen-plus",     "base": "https://dashscope.aliyuncs.com/compatible-mode/v1", "key": "DASHSCOPE_API_KEY"},
	{"name": "glm-4",         "base": "https://open.bigmodel.cn/api/paas/v4",              "key": "ZHIPU_API_KEY"},
]

SYSTEM = """你是严苛的开题评审专家。规则:
1. 评分前必须先列 red_flags。
2. 任何一维 score >= 9 必须有 >= 2 条具体证据。
3. 任何一维 score <= 5 必须给 shrink_suggestions。
4. 不允许编造文献。
5. 严格 JSON 输出。"""

async def review_one(model_cfg: dict, candidate: dict) -> dict:
	client = AsyncOpenAI(
		api_key  = os.environ[model_cfg["key"]],
		base_url = model_cfg["base"],
	)
	resp = await client.chat.completions.create(
		model    = model_cfg["name"],
		messages = [
			{"role": "system", "content": SYSTEM},
			{"role": "user",   "content": json.dumps(candidate, ensure_ascii=False)},
		],
		temperature     = 0.1,
		response_format = {"type": "json_object"},
	)
	return json.loads(resp.choices[0].message.content)

async def vote(candidate: dict) -> dict:
	tasks   = [review_one(m, candidate) for m in MODELS]
	results = await asyncio.gather(*tasks, return_exceptions=True)
	valid   = [r for r in results if isinstance(r, dict)]
	if len(valid) < 2:
		raise RuntimeError("少于 2 个模型返回有效结果,拒绝聚合")

	def agg(dim: str) -> float:
		scores = sorted(v[dim]["score"] for v in valid)
		if len(scores) >= 3:
			scores = scores[1:-1]            # trimmed: 去掉最高最低
		return round(median(scores), 1)

	g, f, v = agg("gap"), agg("feasibility"), agg("venue")
	return {
		"gap":         g,
		"feasibility": f,
		"venue":       v,
		"overall":     round(0.4*g + 0.3*f + 0.3*v, 1),
		"pass_floor":  min(g, f, v) >= 7,
		"per_model":   valid,
	}

几个工程细节:

  • asyncio.gather:三模型一起跑,总耗时 ≈ 单模型耗时。CSDN 上很多教程是串行的,慢得没必要。
  • return_exceptions=True:某个模型挂了不影响其他两个,聚合时再过滤。
  • 少于 2 票直接报错,绝不容忍"一票通过"------这是评审委员会的底线。

3. 避坑指南:分清"打分"与"通过"的陷阱

带过新人的都知道,初级工程师最容易犯的错误,就是混淆了**"综合分高"与"短板通过"**。

打个比方,你招聘一个工程师,三项打分:技术 9 / 沟通 9 / 道德 2。综合分 (0.4×9+0.3×9+0.3×2)=7.5(0.4 \times 9 + 0.3 \times 9 + 0.3 \times 2) = 7.5(0.4×9+0.3×9+0.3×2)=7.5 看起来还行------但道德 2 分这种人你敢招吗?

3.1 短板检查必须是 hard constraint

很多人写聚合器的伪代码是:

python 复制代码
overall = 0.4*g + 0.3*f + 0.3*v
return overall >= 7    # ❌ 错误

错! 必须先做短板检查:

python 复制代码
if min(g, f, v) < 7:
	return False, "短板不及格"        # ✅ 正确
return overall >= 7, "综合达标"

架构师警示 :在评分系统里,短板原则必须是 hard constraint,不是 soft penalty 。三角法则里那一行 min⁡(G,F,V)≥7\min(G, F, V) \geq 7min(G,F,V)≥7 在工程上必须写成一个 if,不是一个加权扣分项。混淆这两者,你的评分器会放过一堆"看上去 7.5 分但其实根本做不出来"的候选。

4. 跨场景选型:为不同评估任务定制的"评分器模式"

这套架构其实和"选题"本身没什么关系 。同一套设计模式可以套到任何"多维评估 + 文本理解"的场景------下面这张表特意以评分场景为主轴,与姊妹篇《选题侦察兵》的"数据采集场景"表形成互补:

评分场景 评分维度 短板阈值(hard gate) 需要几人票委员会 关键调整
毕业论文选题审 Gap / Feasibility / Venue 三维同时 ≥ 7 3 模型 必须挂 MVR 缩小器,Gap 需区分情境/数据/方法/理论空白
期刊初审 / 送审前自检 方法严谨 / 贡献新颖 / 写作清晰 方法 ≥ 7 3--5 模型 plagiarism / AI 检测为前置;ventue 要映射到期刊标签
项目申报书评审 创新点 / 可行性 / 政策医合 / 预算合理性 创新点 ≥ 7 且预算 ≥ 6 3 模型 + 专家人评 1 票 必须距离 7 天内 +跟一轮人评 metaevaluation
简历筛选 / HR 技术匹配 / 项目深度 / 文化契合 技术 ≥ 6 3 模型,同背景不同训练 必须加反偏见检查(性别/馆校/技术栈)
PR Code Review 正确性 / 可读性 / 性能影响 正确性 ≥ 8 2 模型 + 1 人 正确性是 hard gate,顺位偏见用 diff hash 冲冲冷
产品需求评估 用户价值 / 技术成本 / 商业回报 / 风险 价值 ≥ 6 且风险 ≤ 7 3 模型 风险维度要独立评估,不能被价值抵消

Architect Pro-tip :千万不要直接把"选题评审"的 prompt 抄到"简历筛选"。领域知识必须重新注入------否则你会得到一个对 React 简历偏好、对 Vue 简历压分的奇怪偏见。这种偏见你 debug 都 debug 不出来,因为它藏在 prompt 的字里行间。
| 🟡

AI 是"副驾驶",不是"代驾"。 评审委员会的职责是指出候选哪里站不住 ,不是给一个高分代替你拍板。一旦你把评委会的分数当"结论"而不是"诊断",它就重新退化成一个"三模型拍脑袋"的黑盒。

5. 巨头博弈:解锁多模型 API 的"工程纪律"

如果你要让 DeepSeek / 通义 / 智谱 三家同时并发,那么这些 API 的对接就进入了深水区

LLM-as-a-Judge 接入三要素:

  1. 准入门槛(Auth):通常是 API Key,但部分高级模型(GLM-4-air、Qwen-Max-Longcontext)要求企业认证起步。
  2. 严苛的系统约束(Rate Limits & Schema)
    • DeepSeek 个人 ≈ 60 RPM
    • 通义 Qwen 单租户限速更细分
    • 强行突破 → 429 → 整个并发任务挂掉
    • asyncio.Semaphore(2) 是工程纪律,不是可选项
  3. 价值对价(Cost Bound) :批量评审场景对成本极敏感。必须把 token 账本写进代码注释
python 复制代码
# 单候选三模型并发投票成本估算 (写进注释,杜绝成本失控):
# system   :   400 tokens
# user     :   800 tokens
# response :   600 tokens
# 单模型    :  1800 tokens per model
# 三模型    :  5400 tokens ≈ ¥0.01
# 三轮迭代  : ≈ ¥0.03 ~ ¥0.05
# 1000 候选 : ¥30 ~ ¥50

5.1 Prompt 工程:anchoring inversion 的妙用

核心思路:先让它说为什么扣分,再让它给分数。这个顺序很重要------人类心理学和大模型一样,先承诺再给分,给分会更克制。

python 复制代码
SYSTEM = """你是一位严苛的开题评审专家。
规则(必须严格遵守):
1. 评分前必须先列出 red_flags(扣分点),列不出来才能给高分。
2. 任何一维 score >= 9 必须有至少 2 条具体证据。
3. 任何一维 score <= 5 必须给出 shrink_suggestions。
4. 不允许编造文献、作者、DOI。
5. 必须输出严格 JSON。
"""

| 📌

"先 red_flags 再 score"是反作弊的关键。

如果你直接问"打几分",大模型倾向于给 8 分;如果你先逼它说"这选题有什么问题",它会自己把分数往下拉到合理区间。

这个 trick 叫 anchoring inversion,在 Constitutional AI 和很多 reward modeling 论文里都被验证过。

6. 工程化闭环:metaevaluation 与持续治理

一个令人清醒的现实是:在一个优秀的评分系统里,"评分代码"只占不到 20% 的工程量 ,剩下的 80% 都在评估这个评分器自身 ------也就是 metaevaluation

如何证明你的评分器对你这个领域是有判别力的?三个粗暴但有效的做法。

6.1 标准答案对齐(Spearman ρ)

找 20 个结果已知的真实候选------比如已被高校通过的开题、已发表的 SSCI 论文、被毙掉的开题报告。脱敏后喂给评分系统:

python 复制代码
import scipy.stats as st
predictions  = [vote(c)["overall"]            for c in benchmark]
ground_truth = [c["actual_outcome_score"]    for c in benchmark]
rho, p = st.spearmanr(predictions, ground_truth)
print(f"Spearman ρ = {rho:.3f}, p = {p:.4f}")

Spearman 比 Pearson 更稳健------你不在意分数绝对值,只在意排序是否一致。ρ > 0.6 才算这个评分器对你这个领域"有判别力"

6.2 人评 vs 机评一致性(Cohen's Kappa)

请你导师 / 资深同事抽 10 个候选独立 打分(事先盲掉 AI 分数),算 Cohen's Kappa:

Kappa 区间 解读
< 0.2 几乎没一致性,系统不可信
0.2 -- 0.4 弱一致,慎用
0.4 -- 0.6 中等一致,可参考
0.6 -- 0.8 实质一致,可主用
> 0.8 近乎完全一致

我自己跑过的样本上,三模型投票版稳定在 0.55~0.7,比单模型版(约 0.3)高出整整一个台阶

6.3 稳定性测试(stdev)

同一个候选灌进系统 5 次,看综合分的标准差:

python 复制代码
import statistics as stats
scores = [vote(candidate)["overall"] for _ in range(5)]
print(f"mean={stats.mean(scores):.2f}, stdev={stats.stdev(scores):.2f}")

经验值:stdev > 0.5 说明系统在抽风,需要调低 temperature、加更多模型、或把 prompt 锁得更死。如果 stdev < 0.2,恭喜------你可以把这个评分系统写进毕业论文的方法论章节当 contribution。

6.4 结构化日志:归因的生命线

做完前三件事,你必须把每一次评审完整存盘------否则下次跑出来的分数和今天不一样,你不知道是模型变了、prompt 变了、还是温度变了:

python 复制代码
# 基于 SQLAlchemy 的评审日志模型
from sqlalchemy import Column, String, Float, JSON, DateTime, Boolean
from sqlalchemy.ext.declarative import declarative_base
import datetime

Base = declarative_base()

class ReviewLog(Base):
	__tablename__ = "review_committee_log"

	review_id    = Column(String(64), primary_key=True)
	candidate_id = Column(String(64), nullable=False)

	# 三维分数 + 综合分 + 短板通过
	score_gap         = Column(Float,   nullable=False)
	score_feasibility = Column(Float,   nullable=False)
	score_venue       = Column(Float,   nullable=False)
	score_overall     = Column(Float,   nullable=False)
	pass_floor        = Column(Boolean, nullable=False)

	# 可追溯性
	per_model_snapshot = Column(JSON,        nullable=False, comment="每个模型的完整 JSON 输出")
	model_versions     = Column(JSON,        nullable=False, comment="model name + version")
	prompt_hash        = Column(String(32),  nullable=False, comment="prompt 模板 md5")
	schema_version     = Column(String(32),  nullable=False, comment="pydantic Schema 版本号")

	# 审计时间戳
	created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)

这些字段必须 Non-nullable ,因为它们是事后归因(Attribution)的生命线 :一年后你做 metaevaluation 时,要能回放每一票的来源、每一版 prompt 的影响、每一个模型版本切换的副作用。没有这张表,你的评分系统只是一个永远在"现在"的占卜机器

7. 结语与前瞻:为评估这件事建立"工程标准"

当 LLM-as-a-Judge 的论文每周以几十篇 的速度涌现,当多模型投票被工程界默认接受为评估范式,"AI 评分"正在从玄学走向工程

此时,我们不妨做一个思考:

当未来 AI 评审委员会的可信度(Cohen's Kappa)稳定超过 0.7 时,毕业论文还需要导师亲自打分吗?或者说,导师的角色会不会从"评审"变成"评审的评审"(meta-reviewer)?

或许,作为新一代工程师,我们的根本任务早已不是"让模型给一个答案 ",而是"为每一类决策建立一个有契约、有投票、有 metaevaluation 的工程化评估系统"。

放弃单模型一锤定音,拥抱多模型投票 + Schema 校验 + 持续 metaevaluation------这不仅是技术升级,更是保护你输出可信度、确保下游决策质量的唯一红线

下面这张图,是这个评审委员会的全貌------不是给你看的,是给你照着抄的
#mermaid-svg-K4Sj5jqJKwxnAVom{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-K4Sj5jqJKwxnAVom .error-icon{fill:#552222;}#mermaid-svg-K4Sj5jqJKwxnAVom .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-K4Sj5jqJKwxnAVom .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-K4Sj5jqJKwxnAVom .marker{fill:#333333;stroke:#333333;}#mermaid-svg-K4Sj5jqJKwxnAVom .marker.cross{stroke:#333333;}#mermaid-svg-K4Sj5jqJKwxnAVom svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-K4Sj5jqJKwxnAVom p{margin:0;}#mermaid-svg-K4Sj5jqJKwxnAVom .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom .cluster-label text{fill:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom .cluster-label span{color:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom .cluster-label span p{background-color:transparent;}#mermaid-svg-K4Sj5jqJKwxnAVom .label text,#mermaid-svg-K4Sj5jqJKwxnAVom span{fill:#333;color:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom .node rect,#mermaid-svg-K4Sj5jqJKwxnAVom .node circle,#mermaid-svg-K4Sj5jqJKwxnAVom .node ellipse,#mermaid-svg-K4Sj5jqJKwxnAVom .node polygon,#mermaid-svg-K4Sj5jqJKwxnAVom .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-K4Sj5jqJKwxnAVom .rough-node .label text,#mermaid-svg-K4Sj5jqJKwxnAVom .node .label text,#mermaid-svg-K4Sj5jqJKwxnAVom .image-shape .label,#mermaid-svg-K4Sj5jqJKwxnAVom .icon-shape .label{text-anchor:middle;}#mermaid-svg-K4Sj5jqJKwxnAVom .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-K4Sj5jqJKwxnAVom .rough-node .label,#mermaid-svg-K4Sj5jqJKwxnAVom .node .label,#mermaid-svg-K4Sj5jqJKwxnAVom .image-shape .label,#mermaid-svg-K4Sj5jqJKwxnAVom .icon-shape .label{text-align:center;}#mermaid-svg-K4Sj5jqJKwxnAVom .node.clickable{cursor:pointer;}#mermaid-svg-K4Sj5jqJKwxnAVom .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-K4Sj5jqJKwxnAVom .arrowheadPath{fill:#333333;}#mermaid-svg-K4Sj5jqJKwxnAVom .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-K4Sj5jqJKwxnAVom .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-K4Sj5jqJKwxnAVom .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K4Sj5jqJKwxnAVom .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-K4Sj5jqJKwxnAVom .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K4Sj5jqJKwxnAVom .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-K4Sj5jqJKwxnAVom .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-K4Sj5jqJKwxnAVom .cluster text{fill:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom .cluster span{color:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-K4Sj5jqJKwxnAVom .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-K4Sj5jqJKwxnAVom rect.text{fill:none;stroke-width:0;}#mermaid-svg-K4Sj5jqJKwxnAVom .icon-shape,#mermaid-svg-K4Sj5jqJKwxnAVom .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K4Sj5jqJKwxnAVom .icon-shape p,#mermaid-svg-K4Sj5jqJKwxnAVom .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-K4Sj5jqJKwxnAVom .icon-shape .label rect,#mermaid-svg-K4Sj5jqJKwxnAVom .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K4Sj5jqJKwxnAVom .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-K4Sj5jqJKwxnAVom .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-K4Sj5jqJKwxnAVom :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输出层
治理层
闭环层
聚合层
推理层
契约层
输入层




候选 JSON
领域知识

评分锚点
资源约束

预算 / 延迟
pydantic Schema
Prompt 模板

  • md5 hash
    温度 / 模型版本锁
    DeepSeek 评审
    Qwen 评审
    GLM 评审
    ≥ 2 票有效?
    Schema 校验
    trimmed mean
    中位数
    短板 ≥ 7?
    MVR 缩小器
    最多 3 轮迭代
    结构化日志

per-model 快照
Spearman ρ
Cohen's Kappa
stdev 稳定性
立项卡 JSON
雷达图 PNG
Notion / DB

三个月后回头看,你会发现真正让评分稳定的,从来不是某个模型多强,而是这张图上每一条治理回路都被你认真打磨过一遍


💡 互动话题:你在用 LLM 做评估时,踩过最大的"打分坑"是什么?欢迎在评论区留言讨论!

相关推荐
深圳市机智人激光雷达1 小时前
时空解算与图优化:激光雷达 3D 建图的技术原理与实现流程
人工智能·3d·机器人·自动化·自动驾驶·激光雷达
数幄科技1 小时前
电力装备制造业智能化转型】【数据基础设施篇】【5】数据采集 ETL 的可靠性设计
大数据·人工智能·算法·数据治理·数幄科技
海伯森技术1 小时前
海伯森3D线光谱共焦精密测量技术及产业化应用
大数据·人工智能·3d
莱歌数字1 小时前
服务器风扇转速越高,散热就越好吗?
人工智能·制造·散热
happyprince1 小时前
19-Hugging Face Transformers之Qwen3.5-MoE 系列详解:混合专家 + 线性注意力 + 多模态的完整生命周期
人工智能
Coovally AI模型快速验证1 小时前
上海 AI Lab联合发布无需人工标注的TrackRef3D:全自动3D指代分割,mIoU达38.8领跑SOTA
人工智能·3d
怪兽学LLM1 小时前
Agent Skill 完全指南:从 SKILL.md 到实战开发,打造属于你的 AI 能力插件
人工智能
米小虾1 小时前
2026年6月AI行业全景:从百模大战到Agent元年,这30天发生了什么?
人工智能
米小虾1 小时前
AI Agent全面爆发:2026年最值得关注的Agent框架与实战选择指南
人工智能