构建可追溯的LLM自动评估系统:从智能体协作到全链路溯源

📅 2026/8/24 5:01:56
构建可追溯的LLM自动评估系统:从智能体协作到全链路溯源
1. 为什么我们需要一个“可追溯”的自动评估系统如果你最近在折腾大语言模型不管是微调自己的模型还是评估不同开源模型的性能大概率都经历过这个场景你写了一个评估脚本跑了几十个测试用例最后拿到一个分数比如“准确率85%”。然后你开始改模型、调参数或者换一个评估数据集再跑一次分数变成了“87%”。这时候你心里可能会冒出几个问题这2%的提升具体是哪些题目答对了之前答错的题目现在真的都解决了吗还是说只是运气好蒙对了几道新题更头疼的是如果评估结果变差了你几乎无从下手去定位问题——是模型在某个特定领域的理解能力退化了还是评估标准本身有歧义这就是当前LLM评估领域一个普遍存在的痛点“黑盒评估”。我们投入了大量算力得到了一个孤零零的数字但这个数字背后的决策过程、评分依据、甚至错误的具体类型都是一团迷雾。这种不透明性严重阻碍了模型的迭代优化和我们对模型能力的深度理解。而“One-Eval”这个系统从名字上就直击了这两个核心诉求Agentic智能体驱动和Traceable可追溯。它不是一个简单的脚本聚合工具而是一个由多个智能体协同工作的“评估大脑”。更重要的是它把评估的每一步思考、每一次判断都清晰地记录下来形成一条完整的证据链。这意味着评估结果不再是终点而是一个可以深度分析的起点。你可以像调试代码一样逐行“调试”模型的评估过程精准定位薄弱环节。这对于模型研发者、算法工程师甚至是需要向业务方解释模型能力的同学来说价值巨大。2. One-Eval 系统架构智能体如何分工协作一个高效的评估系统其核心在于如何将复杂的评估任务拆解、分配并可靠地执行。One-Eval 采用了多智能体协作的架构这比传统的“流水线”脚本要灵活和健壮得多。我们可以将其理解为一个小型的、目标明确的“评估团队”。2.1 核心智能体角色与职责这个“团队”通常由以下几个关键角色智能体构成它们各司其职通过消息传递和状态共享进行协作任务规划与分发智能体这是团队的“项目经理”。它接收用户提交的评估任务例如“评估模型A在代码生成任务上的表现”并对其进行解析和拆解。它会根据任务描述决定需要调用哪些评估能力如代码正确性、安全性、风格一致性并为每个子任务生成具体的指令和上下文。然后它将子任务分发给对应的“专家”智能体。评估执行智能体这是团队的“专家工程师”。通常会有多个每个专精于某一类评估维度。例如事实核查智能体负责判断模型回答的事实准确性可能会调用知识库或进行网络搜索在安全合规的范围内来验证信息。代码评估智能体专攻代码相关任务。它不仅能运行代码检查语法和结果正确性还能评估代码风格、复杂度甚至安全性如是否存在SQL注入风险。安全性/合规性智能体检查模型输出是否包含偏见、歧视性言论、敏感信息或其他不符合安全规范的内容。逻辑一致性智能体分析长文本或多轮对话中模型的回答是否存在前后矛盾、逻辑谬误。元评估与仲裁智能体这是团队的“质量保证专家”。当不同评估智能体对同一输出产生分歧例如事实核查认为正确但逻辑分析认为有矛盾或者当评估结果置信度不高时这个智能体会介入。它可能采用更复杂的推理、调用更权威的参考源或者设计额外的验证问题来做出最终裁定确保评估结果的可靠性。溯源与报告生成智能体这是团队的“文档工程师”也是实现“可追溯性”的关键。它不直接参与评分而是全程监听和记录其他智能体的工作流。对于每一个评估决策它都会记录哪个智能体、在什么时间、基于哪些输入和上下文、调用了什么工具或规则、得出了什么中间结论和最终结论。最终它将所有原始数据、中间过程和最终分数整合成结构化的评估报告和可视化的溯源图谱。2.2 智能体间的协作流程一个典型的评估流程可能如下所示用户提交任务“评估模型在回答历史类开放性问题时的表现。”规划智能体拆解任务生成子任务a) 事实准确性评估 b) 论述逻辑性评估 c) 语言流畅度评估。规划智能体将问题、模型回答、以及子任务指令分别发送给事实核查、逻辑一致性和基础质量评估智能体。三个执行智能体并行工作。事实核查智能体可能标记出某个日期错误逻辑一致性智能体可能认为论述结构清晰。所有中间结果和评分包括置信度汇总到元评估智能体。如果某个评分置信度低比如事实核查智能体对某个模糊历史事件无法确定元评估智能体可能发起二次核查或标记为“存疑”。溯源智能体全程记录步骤2-5中每个智能体的输入、输出、调用链和决策依据。最终系统生成一份报告不仅给出总分和各维度分还能让用户点击任何一个分数展开看到支撑这个分数的全部证据链和推理过程。这种架构的优势在于模块化和可扩展性。当你需要增加一个新的评估维度比如“创意性”你只需要训练或引入一个新的“创意性评估智能体”并将其注册到系统中规划智能体就能在合适的任务中调用它。3. 实现“自动化”与“可追溯性”的核心技术栈要让上述智能体系统流畅运行背后需要一系列技术的支撑。这里我们抛开那些庞大的基础模型聚焦在使能“自动化”和“可追溯性”的关键组件上。3.1 工作流编排与智能体调度这是系统的中枢神经系统。你需要一个可靠的框架来定义智能体之间的协作逻辑。LangGraph或微软的 AutoGen这类框架是目前的热门选择。为什么选它们因为它们原生支持将多个智能体组织成有向图可以清晰地定义控制流顺序、分支、循环。例如你可以设置一个规则“如果事实核查智能体的置信度低于0.7则路由到元评估智能体否则直接进入报告生成环节”。这完美契合了评估任务中需要条件判断和循环验证的场景。实操要点在定义工作流时务必为每个节点的输入和输出定义清晰、结构化的模式Pydantic模型非常适用。这不仅是良好工程实践更是实现可追溯性的基础——结构化的数据才能被方便地存储和查询。3.2 溯源数据的捕获与存储“可追溯性”不是一句空话它需要贯穿数据生命周期的设计。数据埋点在每个智能体的关键函数中你必须插入日志记录点。这不仅仅是打印日志而是要将完整的上下文结构化保存。这包括agent_id: 执行智能体的标识。timestamp: 操作时间戳。input: 智能体接收到的完整消息包括系统提示、用户问题、模型回答、历史上下文等。tool_calls: 智能体调用了哪些外部工具或函数如搜索API、代码执行器以及调用的参数。tool_results: 工具调用的返回结果。output: 智能体最终生成的评估判断、评分及理由。confidence: 智能体对自己判断的置信度评分。存储选型考虑到溯源数据是半结构化的且后续需要灵活的查询例如“找出所有因为日期错误而扣分的案例”时序数据库或支持JSON字段的关系型数据库如PostgreSQL的jsonb类型是比纯文档数据库更优的选择。它们能很好地支持按时间序列和复杂条件进行聚合查询。实现模式一个实用的技巧是使用装饰器Decorator。你可以创建一个traceable装饰器自动包装智能体的核心函数在函数执行前后自动捕获上述所有信息并存入数据库。这样业务代码可以保持干净溯源功能则被无缝集成。3.3 评估基准与提示工程自动化评估的质量极大程度上依赖于你给智能体设计的“评估标准”和“思考指令”。构建评估基准你需要一个高质量、多样化的测试用例集。这不仅仅是问题列表每个用例最好包含question: 输入问题。reference_answer: 可选的参考答案对于事实性问题很重要。evaluation_criteria: 针对本题的具体评分标准例如“重点考察对事件因果关系的解释是否合理”。metadata: 所属领域、难度等级、题型等标签便于后续做维度分析。设计评估提示词这是驱动评估智能体的“灵魂”。糟糕的提示词会导致评估结果不稳定或偏离目标。一个好的评估提示词应该明确角色“你是一个严谨的历史知识评估专家。”定义任务“你的任务是分析给定的模型回答并判断其事实准确性。”给出步骤“请按以下步骤思考a) 提取回答中的关键事实主张b) 逐一核对主张是否与可靠来源一致c) 对每个主张给出正确/错误/无法判断的结论及理由。”提供输出格式“最终请以JSON格式输出{“score”: 0-5, “verdict”: “correct/incorrect/partially_correct”, “details”: [{claim: “...”, “status”: “...”, “evidence”: “...”}, ...]}”加入自省要求“最后请为你自己的评估结果给出一个0-1的置信度分数并说明理由。”注意提示词工程需要反复迭代和测试。建议对同一批评估用例用不同版本的提示词跑多次人工校验结果的稳定性与合理性选择最优版本。4. 从零搭建一个简易可追溯评估系统的实战步骤理论说再多不如动手做一遍。下面我将以一个简化场景为例手把手展示如何构建一个具备核心功能事实核查溯源的评估系统。我们假设要评估模型对“科技公司成立日期”这类事实性问题的回答。4.1 环境准备与依赖安装首先创建一个干净的Python环境并安装核心库。# 创建并激活虚拟环境可选但推荐 python -m venv one-eval-env source one-eval-env/bin/activate # Linux/Mac # one-eval-env\Scripts\activate # Windows # 安装核心依赖 pip install openai langchain langgraph chromadb pydantic sqlite3 # 这里使用OpenAI API和LangChain生态你也可以替换为其他兼容的模型API。我们选择SQLite作为溯源数据库因为它轻量且无需额外服务适合原型开发。4.2 定义数据模型与溯源记录器这是保证数据一致性的基石。我们使用Pydantic来定义清晰的数据结构。from pydantic import BaseModel, Field from datetime import datetime from typing import Optional, Dict, Any, List import sqlite3 import json # 定义溯源记录的数据模型 class TraceRecord(BaseModel): trace_id: str # 整个评估流程的唯一ID node_id: str # 工作流中的节点ID如fact_checker agent_name: str timestamp: datetime input_data: Dict[str, Any] # 输入内容 output_data: Dict[str, Any] # 输出内容 metadata: Optional[Dict] None # 额外信息如置信度、工具调用详情 # 一个简单的溯源记录器使用SQLite class TraceRecorder: def __init__(self, db_pathevaluation_trace.db): self.conn sqlite3.connect(db_path) self._create_table() def _create_table(self): cursor self.conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS traces ( id INTEGER PRIMARY KEY AUTOINCREMENT, trace_id TEXT, node_id TEXT, agent_name TEXT, timestamp DATETIME, input_data TEXT, output_data TEXT, metadata TEXT ) ) self.conn.commit() def log(self, record: TraceRecord): cursor self.conn.cursor() cursor.execute( INSERT INTO traces (trace_id, node_id, agent_name, timestamp, input_data, output_data, metadata) VALUES (?, ?, ?, ?, ?, ?, ?) , ( record.trace_id, record.node_id, record.agent_name, record.timestamp.isoformat(), json.dumps(record.input_data), json.dumps(record.output_data), json.dumps(record.metadata) if record.metadata else None )) self.conn.commit() def get_traces_by_id(self, trace_id: str) - List[Dict]: cursor self.conn.cursor() cursor.execute(SELECT * FROM traces WHERE trace_id ? ORDER BY timestamp, (trace_id,)) columns [col[0] for col in cursor.description] return [dict(zip(columns, row)) for row in cursor.fetchall()]4.3 构建事实核查智能体我们创建一个专门的事实核查智能体它利用一个本地的知识库这里用Chroma向量数据库模拟来验证信息。from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.schema import Document from langchain.chat_models import ChatOpenAI class FactCheckAgent: def __init__(self, recorder: TraceRecorder, trace_id: str): self.llm ChatOpenAI(modelgpt-4, temperature0) self.recorder recorder self.trace_id trace_id # 初始化一个简单的知识库存储公司-成立年份对 self.knowledge_base { OpenAI: 2015, Google: 1998, Microsoft: 1975, Apple: 1976, Meta: 2004 } # 为了演示我们将知识库存入向量库以便检索 docs [Document(page_contentf{company} was founded in {year}., metadata{company: company}) for company, year in self.knowledge_base.items()] self.vectorstore Chroma.from_documents(docs, OpenAIEmbeddings()) def check(self, question: str, model_answer: str) - Dict: 执行事实核查。 返回格式{score: int, verdict: str, details: List, confidence: float} agent_name fact_check_agent_v1 node_id fact_check_node # 1. 提取模型回答中的关键事实主张例如公司名和年份 extraction_prompt f 请从以下回答中提取所有关于公司成立年份的事实主张。 回答{model_answer} 请以JSON列表格式输出每个元素包含company和claimed_year字段。 例如[{{company: OpenAI, claimed_year: 2015}}] extraction_result self.llm.invoke(extraction_prompt).content # 记录提取步骤 self.recorder.log(TraceRecord( trace_idself.trace_id, node_idnode_id, agent_nameagent_name, timestampdatetime.now(), input_data{step: claim_extraction, prompt: extraction_prompt, model_answer: model_answer}, output_data{extracted_claims: extraction_result}, metadata{sub_step: extraction} )) # 解析提取结果这里简化处理实际应用中需更健壮的解析 import ast try: claims ast.literal_eval(extraction_result) except: claims [] details [] correct_count 0 total_claims len(claims) # 2. 对每个主张进行核查 for claim in claims: company claim.get(company) claimed_year claim.get(claimed_year) # 从知识库中查询真实信息 real_year self.knowledge_base.get(company) is_correct (real_year claimed_year) detail { company: company, claimed_year: claimed_year, real_year: real_year, is_correct: is_correct, evidence_source: internal_knowledge_base } details.append(detail) if is_correct: correct_count 1 # 3. 计算分数和结论 score (correct_count / total_claims * 100) if total_claims 0 else 0 verdict correct if score 100 else partially_correct if score 0 else incorrect # 模拟一个置信度实际中可根据核查过程的确定性来计算 confidence 0.9 if total_claims 0 else 0.0 final_output { score: score, verdict: verdict, details: details, confidence: confidence } # 记录核查结果 self.recorder.log(TraceRecord( trace_idself.trace_id, node_idnode_id, agent_nameagent_name, timestampdatetime.now(), input_data{step: fact_verification, claims: claims, knowledge_base_lookup: True}, output_datafinal_output, metadata{sub_step: verification, total_claims: total_claims, correct_claims: correct_count} )) return final_output4.4 组装工作流与执行评估现在我们将智能体和记录器组合起来形成一个完整的评估流程。import uuid def run_evaluation_pipeline(question: str, model_answer: str): 运行一个简单的评估流水线。 # 生成本次评估的唯一追踪ID trace_id str(uuid.uuid4()) print(f开始评估流程追踪ID: {trace_id}) # 初始化溯源记录器 recorder TraceRecorder() # 初始化事实核查智能体 fact_checker FactCheckAgent(recorder, trace_id) # 执行事实核查 print(正在进行事实核查...) fact_check_result fact_checker.check(question, model_answer) # 这里可以添加更多智能体例如逻辑检查、语言质量检查等 # logic_check_result logic_agent.evaluate(...) # ... # 模拟元评估简单版本如果置信度低于阈值标记需要人工复审 needs_human_review fact_check_result.get(confidence, 1.0) 0.8 final_verdict fact_check_result.get(verdict) if needs_human_review: final_verdict needs_human_review # 生成最终报告 final_report { trace_id: trace_id, question: question, model_answer: model_answer, fact_check: fact_check_result, final_verdict: final_verdict, needs_human_review: needs_human_review, timestamp: datetime.now().isoformat() } print(\n 评估报告 ) print(json.dumps(final_report, indent2, ensure_asciiFalse)) print(\n) # 提供溯源查询入口 print(f要查看完整溯源日志可以在数据库中查询 trace_id {trace_id}) return final_report, trace_id # 运行一个示例 if __name__ __main__: sample_question OpenAI和Google分别是哪一年成立的 sample_answer OpenAI成立于2015年而Google成立于1999年。 # 故意把Google的年份写错 report, tid run_evaluation_pipeline(sample_question, sample_answer)运行这段代码你会得到一份包含分数、详细判断和最终结论的评估报告。更重要的是所有中间过程——从主张提取到知识库比对——都被完整记录在SQLite数据库的traces表中。4.5 可视化与查询溯源链评估结束后我们可以通过简单的查询将“黑盒”过程透明化。def visualize_trace(trace_id: str): 查询并打印指定trace_id的完整执行链路 recorder TraceRecorder() traces recorder.get_traces_by_id(trace_id) print(f\n 评估流程溯源图谱 (Trace ID: {trace_id})) print(*50) for i, trace in enumerate(traces): print(f\n步骤 {i1}: [{trace[node_id]}] - {trace[agent_name]}) print(f时间: {trace[timestamp]}) print(f输入: {trace[input_data]}) print(f输出: {trace[output_data]}) if trace[metadata]: print(f元数据: {trace[metadata]}) print(-*30) # 使用上面示例生成的trace_id进行查询 # visualize_trace(tid)通过这个溯源图谱你可以清晰地看到fact_check_node首先被触发输入是问题和模型回答。它执行了claim_extraction子步骤输出是提取到的[{company: OpenAI, claimed_year: 2015}, {company: Google, claimed_year: 1999}]。接着执行fact_verification子步骤输入是这些主张输出是详细的比对结果和分数。 这样一来当报告显示Google的年份错误时你不仅能知道错了还能立刻定位到是“主张提取”步骤准确地抓取到了“1999”这个信息并且在“事实核查”步骤中与知识库里的“1998”比对失败。这种透明度对于调试评估标准、理解模型错误模式至关重要。5. 避坑指南构建生产级系统必须面对的挑战上面的简易系统演示了核心概念但要将其投入实际生产服务于真正的模型迭代你会遇到一系列更复杂的问题。以下是我在实践中总结的几个关键挑战和应对思路。5.1 评估智能体本身的可靠性问题最大的讽刺在于我们用一个LLM评估智能体去评估另一个LLM被评估模型。如何保证评估者不犯错问题表现评估智能体可能误解评估标准、漏掉关键错误、或者因为提示词偏见给出不一致的评分。解决方案黄金标准测试集准备一小批有标准答案和明确评分的“黄金用例”。每次对评估系统做重大更新如修改提示词、升级基础模型时都先用这批用例跑一遍确保评估系统的输出与人工标注一致。这是校准系统的基准线。引入元评估与多数投票对于关键或模糊的评估点不要只依赖一个智能体。可以启动多个同类型的评估智能体使用不同但等效的提示词采用“多数投票”或“平均置信度加权”的方式得出最终结论。One-Eval中的“元评估智能体”正是为此而生。置信度校准要求每个评估智能体在输出评分时必须同时输出一个“置信度”。对于低置信度的评估项系统应自动标记并可以路由给更复杂的智能体进行二次评估或者直接提请人工复审。5.2 溯源数据的爆炸式增长与查询性能一个全面的评估系统每处理一个评估用例都可能产生数十条甚至上百条溯源记录。当评估用例达到万级、十万级时数据量会非常庞大。问题表现数据库查询变慢无法快速定位问题存储成本激增。解决方案分层存储与冷热分离将最近的高频查询数据如最近一周的评估详情放在高性能数据库如PostgreSQL。将历史溯源详情转移到对象存储如S3或数据湖中仅保留索引和摘要信息在关系库中供快速查询。设计高效的索引在溯源数据库表中对trace_id、node_id、agent_name以及时间戳字段建立复合索引。根据常见的查询模式如“查找所有评估失败的记录”、“查找某个智能体在某个时间段内的所有操作”来优化索引设计。聚合与摘要并非所有中间步骤的原始数据都需要永久保留。可以设计一个聚合任务定期将详细的步骤日志聚合成更高层次的“评估事件”摘要保留关键决策路径即可。5.3 评估标准的主观性与一致性对于代码风格、文章创意、对话友好度等主观性较强的维度如何定义让智能体也能理解的、一致的评估标准问题表现不同评估员或不同时间运行的同一智能体对同一回答给出差异很大的评分。解决方案量化与范例化尽可能将主观标准转化为可观测、可量化的指标。例如“对话友好度”可以拆解为是否使用问候语、是否主动澄清模糊问题、是否避免使用专业 jargon 等。为每个指标提供正面和反面的具体例子。使用评分量表与详细规则采用类似人工评估中常用的“李克特量表”如1-5分并为每个分数点提供清晰的行为描述锚点。将这些描述锚点写入评估智能体的系统提示词中。定期重校准即使有了标准漂移也可能发生。定期如每月抽取一批样本进行人工重评分将人工评分与系统评分进行对比分析。如果发现系统性偏差则需要调整评估提示词或规则。5.4 系统的可扩展性与维护成本随着评估维度的增加从事实性扩展到安全性、逻辑性、创造性等智能体种类和工作流会变得越来越复杂。问题表现添加一个新评估维度需要修改核心工作流代码牵一发而动全身智能体之间的通信协议混乱。解决方案标准化智能体接口定义所有评估智能体都必须实现的统一接口例如一个evaluate(input: EvaluationRequest) - EvaluationResult的方法。这样新的智能体可以像插件一样被接入系统。声明式工作流配置使用如LangGraph这样的框架将工作流的拓扑结构哪个智能体在什么条件下执行用配置或DSL领域特定语言来定义而不是硬编码在Python逻辑里。这样增删节点或修改路由逻辑只需改动配置文件。建立智能体注册中心维护一个所有可用智能体的注册表记录其能力描述、输入输出模式、性能指标等。任务规划智能体可以根据评估任务的需求动态地从注册中心选取和组合合适的智能体。构建一个像One-Eval这样的系统绝非一蹴而就。它更像是在搭建一个不断进化的“评估生态”。起步时可以从一个最核心的痛点比如事实准确性和一个最简单的可追溯架构做起就像我们上面的实战示例。然后在解决实际评估需求的过程中逐步引入新的智能体、优化工作流、完善溯源分析工具。这个过程的本身就是对LLM能力边界和理解深度的一次绝佳探索。当你能够清晰解释模型为什么在这里得分、在那里失分时你不仅是在评估模型更是在构建关于模型认知的“地图”。这张地图才是驱动模型真正进步的关键燃料。