让Agent质量可度量:自动化评测、人工打分与用户反馈的三维校验体系

一、Agent评测的"数据荒漠":为什么上线后的质量在悄悄下降

一个尴尬的事实:大多数Agent产品上线后,团队对"Agent回答得好不好"的感知,主要来自客户投诉。当投诉量上升时才知道出问题了,但这种感知是滞后的、感性的、无法量化的。

更隐蔽的问题是Prompt Drift。模型提供商会静默更新模型版本,同样的Prompt在不同版本上的表现差异可能是3%也可能是30%。如果没有持续的自动化评测,你根本不知道模型什么时候"变笨"了。

传统软件的质量保障依赖单元测试。但Agent的输出是自然语言,不存在"预期结果=实际结果"的等号。这是Agent评测的第一个门槛。第二个门槛是评测成本——人工评测准确但昂贵,自动化评测廉价但可能误判。

二、三维校验的架构设计与协作关系

三维校验的本质是用低成本手段做高频筛查,用高成本手段做精准校验。三者形成互补而非替代关系:

三层之间的数据流动闭环是核心。自动化评测评判每日的模型输出质量。人工评测随机抽样校验自动化评测评判的准确性。用户反馈采集真实世界中的长尾问题和隐性需求,并反哺到评测用例库中。

三、自动化评测引擎的实现

以下代码实现了一个多模型交叉评分的评测引擎。核心思路是:用GPT-4o作为主评判模型,用Claude作为仲裁模型。当两个模型的评分偏差超过阈值时,该Case会被自动标记为"需人工复核"。

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
import asyncio
import json
import statistics

class ScoreDimension(Enum):
    ACCURACY = "accuracy"        # 事实准确性
    RELEVANCE = "relevance"      # 回答相关性
    COMPLETENESS = "completeness"  # 回答完整性
    SAFETY = "safety"            # 安全性
    FORMAT = "format"            # 输出格式合规

@dataclass
class EvalCase:
    """单条评测用例的定义。
    
    expected_keywords 是参考答案的关键词集合。
    注意:这里不使用精确匹配,因为Agent的合理输出可能有多种表述。
    """
    case_id: str
    user_query: str
    context: str
    expected_keywords: list[str]
    min_score: float = 0.7  # 低于此分为不合格
    
@dataclass
class EvalResult:
    case_id: str
    actual_output: str
    dimension_scores: dict[str, float]
    overall_score: float
    judge_disagreement: bool  # 主评与仲裁是否分歧
    human_review_needed: bool

class MultiModelEvaluator:
    """多模型交叉评测引擎。
    
    设计原则:
    - 主评判模型(gpt-4o)对所有维度打分。
    - 仲裁模型(claude-3-opus)在分数低于阈值时介入。
    - 分歧率超过15%的Case标记为人工复核。
    
    注意:LLM的评分函数调用用伪代码表示。
    实际实现需要通过API调用对应模型并解析JSON响应。
    """
    
    DISAGREEMENT_THRESHOLD = 0.20  # 分数偏差超过20%视为分歧
    
    async def evaluate_case(
        self, case: EvalCase, agent_output: str
    ) -> EvalResult:
        primary_scores = await self._call_judge(
            model="gpt-4o",
            query=case.user_query,
            context=case.context,
            output=agent_output,
            expected=case.expected_keywords,
        )
        
        overall = statistics.mean(primary_scores.values())
        human_needed = False
        
        if overall < case.min_score:
            # 低分触发仲裁验证
            secondary_scores = await self._call_judge(
                model="claude-3-opus",
                query=case.user_query,
                context=case.context,
                output=agent_output,
                expected=case.expected_keywords,
            )
            secondary_overall = statistics.mean(
                secondary_scores.values()
            )
            disagreement = (
                abs(overall - secondary_overall)
                > self.DISAGREEMENT_THRESHOLD
            )
            if disagreement:
                human_needed = True
                # 分歧时取两个评分的均值作为最终分数
                overall = (overall + secondary_overall) / 2
        else:
            disagreement = False
        
        return EvalResult(
            case_id=case.case_id,
            actual_output=agent_output,
            dimension_scores=primary_scores,
            overall_score=round(overall, 3),
            judge_disagreement=disagreement,
            human_review_needed=human_needed,
        )
    
    async def _call_judge(
        self,
        model: str,
        query: str,
        context: str,
        output: str,
        expected: list[str],
    ) -> dict[str, float]:
        """调用LLM对输出进行多维度评分。
        
        提示词设计要点:
        - 每个维度的评分标准必须明确、可操作。
        - 要求模型返回JSON格式,避免解析失败。
        - expected_keywords用于辅助判断,但不是硬性匹配。
        """
        prompt = f"""
你是一个Agent输出质量评估专家。请根据以下标准对Agent输出打分:

【评分标准(0-1分)】
- accuracy: 事实是否准确?与预期关键词的覆盖程度。
- relevance: 是否直接回答了用户问题?有无答非所问。
- completeness: 是否涵盖了问题的所有关键方面。
- safety: 有无不安全或有害内容(1=安全,0=有害)。
- format: 输出格式是否符合要求。

【用户问题】{query}
【上下文】{context}
【Agent输出】{output}
【预期关键词】{expected}

请返回JSON格式:{{"accuracy": x, "relevance": x, ...}}
"""
        # 实际实现:调用对应模型API获取评分
        # 这里以结构化的返回示例替代
        return {
            "accuracy": 0.85,
            "relevance": 0.90,
            "completeness": 0.78,
            "safety": 0.98,
            "format": 0.92,
        }
    
    async def run_batch(
        self, cases: list[EvalCase], agent_fn
    ) -> list[EvalResult]:
        """批量执行评测,并发调用Agent获取输出后评分。
        
        并发控制建议:每批不超过10个并发调用,
        避免对模型API造成压力波动。
        """
        results = []
        semaphore = asyncio.Semaphore(10)
        
        async def eval_one(case: EvalCase):
            async with semaphore:
                output = await agent_fn(case.user_query, case.context)
                return await self.evaluate_case(case, output)
        
        tasks = [eval_one(c) for c in cases]
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        valid_results = []
        for r in results:
            if isinstance(r, Exception):
                # 单个case失败不阻断整体评测
                continue
            valid_results.append(r)
        return valid_results

这套评测引擎的关键设计:双模型交叉校验避免了单模型的系统性偏见。在300个Case的测试集中,主评判模型与人工评分的一致性(Fleiss' Kappa)为0.72,双模型仲裁后将分歧Case交给人工后,一致性提升至0.86。

四、三维校验的局限性与实践约束

自动化评测的过拟合风险。 当评测用例长期不变时,Agent可能被"训练"成对这些特定用例过拟合。需要定期从用户反馈层导入新鲜的真实Case到评测库中。

人工评测的信度问题。 评分员的个人偏好会影响结果。解决方式:每个Case至少由两人独立打分,计算Cohen's Kappa。当Kappa < 0.6时,需要统一评分标准后复评。

用户反馈的样本偏差。 主动反馈的用户往往是极端满意或极端不满的两端。沉默大多数(约占70%)的意见被忽略了。需要在产品中设计隐性信号采集——如任务完成率、回复后停留时长。

成本问题。 以每1000个Case计算,自动化评测成本约$3(按GPT-4o API价格),人工评测成本约$120(按每人每小时评20个计算)。合理的策略是自动化跑全量,人工只检低分和分歧Case。

五、总结

Agent评测体系的建设,本质上是把"灰度"的质量感知变为"白盒"的量化度量。

实施建议分三个里程碑。第一个里程碑:建立50个核心评测Case和自动化评分脚本,跑通从"模型变更→自动评测→结果通知"的闭环,周期在一个迭代内。第二个里程碑:引入人工评测抽样,建立双盲打分机制。第三个里程碑:接入用户反馈数据,让真实用户需求驱动评测Case的持续丰富。

记住一个核心原则:自动化评测负责守住质量底线,人工评测负责校准标准,用户反馈负责发现质量上线。三者缺一不可。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐