登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

大模型回答怎么设计成对评测减少位置偏差

来源:17golang原创

时间:2026-10-05 02:20:15 314浏览 收藏

大模型回答做成对评测时,减少位置偏差最实用的设计不是“提醒裁判不要偏向第一个”,而是让同一对回答分别以 A-B、B-A 两种顺序评两次,再把裁判输出还原到原始回答身份。两次都指向同一个回答才判胜;顺序一换结论就翻转,则标记为不确定、平局或转人工复核。这样能把回答质量与呈现位置拆开,代价是裁判调用量大约增加一倍。

官方评测指南:https://developers.openai.com/api/docs/guides/evaluation-best-practices

位置校准研究:https://aclanthology.org/2024.acl-long.511/

OpenAI 的评测最佳实践把成对比较列为 LLM 裁判常用且相对可靠的形式,同时明确把回答顺序造成的位置偏差、偏爱长回答的冗长偏差列为挑战。ACL 论文进一步展示了:即使提示词要求裁判忽略顺序,交换候选回答的位置仍可能改变结果;论文给出的平衡位置校准思路,就是让每个候选都出现在两个位置,并合并两次评测。

单次 A/B 判断为什么不够

我第一次搭成对评测时,数据表里只保存了 winner=A、winner=B 或 tie。这种结构看起来简单,却把两个不同概念混在了一起:

  • 回答身份:哪一个候选模型或版本生成了这段内容;
  • 展示位置:本次提示词中它被放在 Candidate A 还是 Candidate B。

如果永远把基线放在 A、把新版本放在 B,裁判对首位或末位的偏好就会持续叠加到模型胜率上。更隐蔽的问题是:只有质量接近的回答容易翻转,而这些样本通常又最能决定一次模型升级是否真实有效。

评测设计调用次数能否发现顺序翻转适合用途
固定 A-B 单次判断1不能不建议用于模型胜率结论
随机单次顺序1只能在大样本上稀释系统偏差低成本粗筛
A-B 与 B-A 双向判断2可以定位到每个样本回归评测、模型对比
双向判断加人工复核2+复核可以处理冲突样本高风险或高价值任务

把同一对回答放进两个对称视图

一个评测样本至少保留四个稳定字段:问题、原始回答 answer_a、原始回答 answer_b、样本 ID。构造裁判输入时再生成两个视图:

  • 正序视图:Candidate A = answer_a,Candidate B = answer_b;
  • 逆序视图:Candidate A = answer_b,Candidate B = answer_a。

这里故意把“原始身份”和“界面标签”分开。裁判只能看到中性的 Candidate A、Candidate B,不应看到模型名、版本号、供应商、价格或“新方案”之类会暗示预期结论的信息。

from dataclasses import dataclass


@dataclass(frozen=True)
class JudgeView:
    sample_id: str
    order: str
    candidate_a: str
    candidate_b: str
    # 记录界面标签对应的原始回答,聚合时不能直接拿 A/B 当答案身份。
    identity_map: dict[str, str]


def build_symmetric_views(sample_id: str, answer_a: str, answer_b: str) -> list[JudgeView]:
    # 同一个样本生成两个完全对称的展示视图。
    return [
        JudgeView(
            sample_id=sample_id,
            order="AB",
            candidate_a=answer_a,
            candidate_b=answer_b,
            identity_map={"A": "answer_a", "B": "answer_b"},
        ),
        JudgeView(
            sample_id=sample_id,
            order="BA",
            candidate_a=answer_b,
            candidate_b=answer_a,
            identity_map={"A": "answer_b", "B": "answer_a"},
        ),
    ]
成对评测正序与逆序视图的静态依赖关系
成对评测对称视图的原创静态结构图,展示两种位置视图如何关联到统一答案身份,不是运行截图。

两个视图必须使用同一问题、同一裁判模型、同一采样参数、同一评判标准和同一输出结构。唯一允许改变的是两段回答的位置。否则即使结果不同,也无法判断是顺序、采样还是提示词变化造成的。

评判标准要先固定,再让裁判输出结构化结论

成对比较并不等于一句“哪个更好”。评判标准越模糊,裁判越容易被篇幅、语气、格式和位置牵着走。实用的标准应绑定任务,例如知识问答可以拆为:

  • 准确性:关键事实是否正确,是否出现无依据结论;
  • 任务完成度:是否真正解决用户提出的问题;
  • 相关性:是否围绕问题,是否包含大量无关扩写;
  • 清晰度:结构是否便于读者理解和执行;
  • 简洁性:在完成任务的前提下,是否避免冗长。

建议裁判只返回 A、B、TIE 三种结论,再给简短依据和按维度的理由。不要让它自由发明“基本胜出”“略微更好”等难以解析的标签。

JUDGE_TEMPLATE = """
你是回答质量评测员。请仅依据下面的任务要求比较两个候选回答。

任务要求:{rubric}
用户问题:{question}

Candidate A:
{candidate_a}

Candidate B:
{candidate_b}

先分别核对准确性、完成度、相关性、清晰度和简洁性。
忽略候选的展示顺序、名称与文风,不因篇幅更长而自动加分。
只返回 winner、reason、criterion_notes 三个字段;winner 只能是 A、B、TIE。
"""


def render_judge_prompt(question: str, rubric: str, view: JudgeView) -> str:
    # 两个方向复用同一模板,避免提示词差异成为额外变量。
    return JUDGE_TEMPLATE.format(
        rubric=rubric,
        question=question,
        candidate_a=view.candidate_a,
        candidate_b=view.candidate_b,
    )

提示词中的“忽略顺序”仍然值得保留,但它只是约束,不是消除偏差的证据。真正的控制来自交换位置后再次判断,以及对两次结果的显式合并。

先还原答案身份,再合并两次判定

最容易写错的地方,是把两个视图返回的字母直接比较。逆序视图里的 A 实际代表原始 answer_b,因此必须先做身份归一。

from typing import Literal

PositionWinner = Literal["A", "B", "TIE"]
FinalWinner = Literal["answer_a", "answer_b", "tie", "uncertain"]


def normalize_winner(view: JudgeView, winner: PositionWinner) -> str:
    # 平局没有位置身份,直接保留为 tie。
    if winner == "TIE":
        return "tie"
    return view.identity_map[winner]


def merge_pairwise_results(forward: str, reverse: str) -> FinalWinner:
    # 两个方向都支持同一原始回答时,才给出明确胜者。
    if forward == reverse and forward in {"answer_a", "answer_b"}:
        return forward

    # 两个方向都判平,保留平局,不强行制造胜者。
    if forward == reverse == "tie":
        return "tie"

    # 其余组合都暴露了位置敏感或边界不清,升级为不确定。
    return "uncertain"

这个合并规则偏保守:一次判 A 胜、一次判平,也不会直接认定 A 胜。生产系统可以按任务风险放宽,例如用多次采样投票或概率平均,但必须在上线前固定规则,不能看完结果后临时挑选对某个模型有利的聚合方式。

一致才定胜负,冲突就升级

交换位置后出现冲突,不意味着样本无用。恰恰相反,它告诉你这对回答可能质量接近、评判标准不够清晰,或者裁判模型对表述、长度和格式过于敏感。可以按下面的方式分层处理:

  1. 双向一致:计入明确胜负或平局;
  2. 胜负翻转:标记为位置冲突,不计入单边胜率;
  3. 胜负与平局混合:标记为边界样本,可增加一次独立裁判;
  4. 输出解析失败:单独记录为评测基础设施错误,不算模型质量;
  5. 高价值或高风险样本:交给盲化的人类评审,并保存最终标签。
评判标准、双向裁决与人工复核的静态关系
评判标准与冲突升级的原创静态关系图,突出双向证据共同受同一规则约束,不是运行结果。

如果业务最终必须给出单一胜率,可以同时报告“保守胜率”和“冲突率”。例如保守胜率只统计双向一致的明确样本;冲突率则表示交换位置后,归一化结论不一致的样本比例。把冲突样本静默丢进某一方,会让位置偏差重新回到总分里。

最少要监控哪几个指标

只有总体胜率不足以判断评测是否稳定。至少同时保存以下指标:

指标含义异常时先检查
位置一致率正序和逆序归一后结论一致的比例裁判提示词、候选长度、模型采样
位置冲突率交换顺序后明确胜者发生翻转的比例答案质量是否接近、标准是否含糊
平局率两次都判定为平局的比例平局定义是否过宽或过窄
解析失败率裁判没有返回合法结构的比例结构化输出约束、重试策略
人工一致率自动裁判与盲化人工标签的一致程度裁判能力、标准示例、任务分层
def position_metrics(rows: list[dict]) -> dict[str, float]:
    # rows 中每项已经完成位置标签到原始回答身份的归一。
    total = len(rows)
    if total == 0:
        return {"position_consistency": 0.0, "conflict_rate": 0.0}

    consistent = sum(row["forward"] == row["reverse"] for row in rows)
    conflicts = sum(
        row["forward"] in {"answer_a", "answer_b"}
        and row["reverse"] in {"answer_a", "answer_b"}
        and row["forward"] != row["reverse"]
        for row in rows
    )

    # 一致率和冲突率分开报告,避免只看最终胜率掩盖顺序敏感性。
    return {
        "position_consistency": consistent / total,
        "conflict_rate": conflicts / total,
    }

人工标签不需要覆盖全部数据。可以先做一批分层抽样:双向一致的明显样本、质量接近的冲突样本、不同领域和不同长度区间都要包含。官方评测指南同样建议先把 LLM 裁判与专家人工标签对齐,再考虑扩大规模和优化成本。

兼容不同评测平台时保留哪些字段

无论使用托管 Evals、内部工作流还是自建批处理,数据层都应保留可追溯的中立字段,而不是绑定某家 API 的临时请求格式:

  • sample_id:同一问题与回答对的稳定标识;
  • answer_a_id、answer_b_id:原始回答身份,不等于展示位置;
  • order:本次是 AB 还是 BA;
  • rubric_version、judge_model、judge_prompt_version:可复现配置;
  • raw_winner:裁判返回的 A、B、TIE;
  • normalized_winner:还原后的 answer_a、answer_b、tie;
  • final_decision:合并后的胜者、平局或 uncertain;
  • reason 与按维度记录:用于抽查,不直接替代结构化结论。

平台只要支持提交两次相同裁判任务并返回结构化标签,就能实现这套设计。如果平台暂时不能做双向任务,最低限度应在数据集层随机化 A/B 位置并记录映射,但这只能降低整体系统偏差,不能识别单个样本的翻转。

成本、性能和数据安全的取舍

双向评测会让裁判调用接近翻倍,因此不一定要对所有阶段使用相同强度。一个实用分层是:

  • 开发期先用小型代表集做全量双向评测,快速修正标准;
  • 回归门禁对高价值、易混淆样本保持双向评测;
  • 大规模离线评测先随机单次粗筛,再对接近阈值的样本补双向判断;
  • 冲突样本进入更强裁判或人工复核,不反复无限调用同一配置。

数据安全方面,送给裁判的用户问题与回答可能包含个人信息、内部代码或业务数据。进入评测前应做最小化、脱敏和权限隔离,并明确日志保留期限。不要因为评测是“离线任务”就默认可以复制生产数据全集。

常见误区

只在提示词里写“不要受顺序影响”可以吗?

不够。提醒可以保留,但交换位置仍可能改变结论。应通过双向呈现和身份归一实际测出顺序敏感性。

随机一次 A/B 顺序和双向评测有什么区别?

随机一次能在大样本上让两个模型平均出现在不同位置,降低固定位置造成的系统偏差;双向评测则能发现同一个样本是否因换位而翻转。前者偏向总体控制,后者兼顾样本诊断。

两次结果不一致时可以多数投票吗?

只有两次时不存在真正多数。可以增加独立采样或不同裁判形成奇数票,但仍应保留“位置冲突”标记,不能用第三票把偏差证据抹掉。

需要让两个回答长度完全相同吗?

不必机械截成同长度,但要避免某一系统通过无关扩写获得优势。标准中加入简洁性和任务完成度,按长度区间监控结果,并把明显的冗长偏差纳入人工样本。

成对评测能替代人工评测吗?

不能。它适合规模化比较和回归门禁,但裁判自身仍有位置、长度、风格和领域偏差。上线前应使用盲化人工标签校准,并持续抽查分歧样本。

落地检查清单

  1. 原始回答身份与展示位置分开存储。
  2. 每个回答对构造 AB、BA 两个视图。
  3. 两个视图使用完全相同的裁判配置与评判标准。
  4. 裁判只返回 A、B、TIE 等有限标签和结构化理由。
  5. 先把位置标签还原为原始回答身份,再合并结论。
  6. 胜负翻转与胜负/平局混合统一标为不确定。
  7. 同时报告胜率、位置一致率、冲突率和人工一致率。
  8. 高风险、冲突和解析异常样本有明确的人工升级路径。

这套方案的价值不是承诺“裁判从此公平”,而是把位置偏差变成一个可以观察、记录和处理的变量。只要回答身份、展示位置和最终结论没有混在一起,后续无论换裁判模型、换平台还是增加人工复核,都能沿着同一份评测记录继续改进。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>