长时程AI任务评测:顶尖模型仅达人类27.3%的原因与实现
之前做 Agent 型应用评测时,我一直在纠结一个问题:传统基准测试里跑得飞快的模型,一旦丢到需要连续操作十几个步骤的真实业务场景里,完成度立刻变得很难看。最近看到一组长时程 AI 任务评测的数据,顶尖模型综合表现大约只有人类基线水平的 27.3%,这个数字确实很扎眼。本文就从评测方法、任务设计、指标计算、代码实现和常见坑点几个角度,完整拆解“长时程 AI 任务评测”怎么做,以及为什么模型会在这种任务上被人类甩开一大截。
1. 背景与核心概念
1.1 什么是长时程 AI 任务
长时程 AI 任务(Long-Horizon AI Tasks)指的是需要模型在较长的时间跨度内,通过多轮推理、工具调用、状态判断和环境交互,最终完成一个复杂目标的任务。
举几个典型例子:
- 让 AI 根据用户邮件中的要求,完成差旅预订、日程同步、酒店确认、报销单提交。
- 让 AI 打开一个数据分析平台,上传 CSV 文件,清洗数据,跑多个图表,最后生成一份带结论的分析报告。
- 让 AI 在虚拟浏览器里完成电商后台的商品上下架、库存核对、价格调整。
这些任务和传统“单轮问答”最大的区别在于:模型不是只回答一个问题,而是要像一个实习生一样,逐步执行、反复确认、遇到失败后自己调整方案。
1.2 为什么传统评测解决不了长时程问题
传统的模型评测,比如 MMLU、GSM8K、BBH,基本是“输入问题 + 输出答案”的静态模式。模型不需要操作环境,不需要中间状态,也不需要从错误中恢复。这种评测有几个明显的局限:
第一,任务时间尺度短。模型只需要一次性推理,没有“上下文积累”的过程。
第二,没有环境反馈。模型答错了就是答错了,不会因为环境状态变化而需要重新规划。
第三,无法评估工具调用能力。真实业务任务里,模型必须使用搜索、代码执行、文件读写、API 调用等工具,而这些在传统评测里几乎不出现。
第四,忽略了错误累积效应。长时程任务里,前面一个步骤的小错误,会在后面被不断放大。传统评测很难体现这种“千里之堤溃于蚁穴”的效果。
1.3 长时程评测在 AI Agent 时代的价值
随着 AI Agent、RPA、浏览器自动化、办公助手等应用形态爆发,单纯刷分已经不能说明模型在真实业务里的可用性。长时程 AI 任务评测正是为了回答几个很现实的问题:
- 这个模型是否具备稳定完成多步任务的能力?
- 当中间步骤失败时,模型能否自己发现并纠正?
- 模型是否具备长期记忆和状态管理能力?
- 在完成任务效率和步骤规范性上,模型和人类差距有多大?
所以“顶尖模型仅达人类 27.3%”这个结论的意义,不只是告诉我们模型还不够强,更重要的是告诉开发者:评测体系必须从“单点能力”转向“连续任务能力”。
2. 为什么长时程任务这么难
在展开评测设计之前,先理解为什么长时程任务会让顶尖模型也“翻车”。只有知道难点在哪,才能设计出更有效的评测维度。
2.1 误差累积与蝴蝶效应
长时程任务里,模型往往需要执行 10 到 30 个步骤。假设单步成功率为 95%,看起来已经很高了,但连续执行 20 步后,整体成功率只有 0.95 的 20 次方,约等于 35.8%。
也就是说,单步能力再强,面对超长步骤链时,整体成功率也会被指数级拉低。这是长时程任务最核心的难点,也是评测时必须关注的数学规律。
2.2 规划与回溯能力不足
人类在长任务中会不断做两件事:规划和回溯。
- 规划:在任务开始前,先把大目标拆成子目标,并且判断子目标之间的依赖关系。
- 回溯:当某个步骤失败时,回到之前的状态,换一条路径重新尝试。
当前模型在这两方面的能力都偏弱。很多模型属于“一条路走到黑”型,一旦当前路径跑不通,就会出现重复尝试、死循环,甚至直接输出错误结论。
2.3 上下文窗口与记忆漂移
长时程任务会产生大量中间状态。模型需要在上下文里维护“当前做到哪一步了”“哪些信息是可信的”“哪些操作还没完成”。
但随着步骤增加,早期信息会逐渐淡出模型的有效注意力范围,出现“记忆漂移”。在评测中,这会表现为模型做到后半段时,忘记任务最初的目标,或者遗漏关键约束条件。
2.4 环境反馈稀疏
很多真实任务的反馈并不是每一步都有的。比如数据分析任务,模型可能前 5 步都是在准备数据、清洗数据,直到第 6 步输出图表时,才知道前面是否处理正确。
这种稀疏反馈对模型来说是巨大的挑战。没有中间奖励信号,模型很难判断自己是不是走在正确的路上。
| 难点 | 表现 | 对评测设计的影响 |
|---|---|---|
| 误差累积 | 步骤增长,成功率指数下降 | 必须记录步骤级成功率,而不是只看最终结果 |
| 规划不足 | 路径僵化,不擅于回溯 | 需要设计分支任务和意外情况 |
| 记忆漂移 | 后期忘记早期约束 | 需要评测长上下文约束保持能力 |
| 反馈稀疏 | 多步操作后才有结果 | 需要加入中途状态检查点 |
3. 长时程 AI 任务评测体系设计
3.1 评测维度的选择
一个完整的长时程 AI 任务评测,不应该只看“最终做没做完”,而应该从多个维度拆开看。我的建议是至少包含以下五个维度:
任务完成率(Task Success Rate)
模型是否在规定的步骤数内,正确完成了最终目标。这是最核心的指标,也是“27.3%”这类结论的直接来源。
步骤成功率(Step Success Rate)
把任务拆成多个子步骤,统计模型正确完成的子步骤比例。这个指标能帮助定位模型到底是在哪一步开始跑偏。
效率(Efficiency)
包括两个维度:完成时间,以及消耗的步骤数。如果一个模型用 50 步完成了人类 10 步就能完成的任务,即使最终成功了,效率也是不合格的。
错误恢复能力(Error Recovery)
在任务中故意埋入一些环境异常,比如按钮点击无效、API 返回报错、文件路径失效,观察模型能否识别异常并重新规划。
稳定性(Stability)
同一个任务运行多次,成功的概率是多少。很多模型单次表现不错,但对初始化条件非常敏感,换个时间、换个环境,表现就大幅波动。
3.2 任务设计的原则
评测任务的质量直接决定评测结论的可信度。设计长时程任务时,我总结了几个原则:
原则一:任务必须具有真实业务背景。
不要设计纯玩具任务。比如让模型“把三个数字加起来再乘二”,这不叫长时程任务。应该选择类似于“把 CSV 文件中的销售数据按季度汇总,生成一张趋势图,并写一段分析结论”这样的任务。
原则二:任务步骤数要足够长。
至少 8 步以上,推荐 12 到 25 步。只有足够长,才能体现出误差累积和规划能力差异。
原则三:任务要包含异常情况。
至少 20% 到 30% 的任务里要埋入环境异常,比如页面加载失败、参数校验不通过、中间依赖文件缺失。这样才能测出模型的恢复能力。
原则四:答案要有明确判分标准。
最终结果必须是可自动判定的。比如“最终生成的报告是否包含正确的季度销售总额”“最终是否完成了文件重命名操作”。
3.3 指标计算方式
假设评测了 N 个任务,每个任务被拆成 K 个步骤。
任务完成率:
任务完成率 = 成功完成最终目标的任务数 / 总任务数 × 100%步骤成功率:
步骤成功率 = 所有任务中正确完成的步骤总数 / 所有任务中的步骤总数 × 100%效率分(示例):
效率分 = 人工参考步骤数 / 模型实际执行步骤数值得注意的是,如果模型执行步骤数小于人工参考步骤数,说明模型可能跳过了关键步骤,不能简单认为效率更高。通常的做法是设置一个步骤数下限,低于下限视为未按规范执行。
4. 实现一个可运行的评测 Demo
下面我们从零实现一个轻量级的长时程 AI 任务评测框架。这个 Demo 不依赖复杂的 Agent 框架,核心目的是演示评测逻辑的完整链路。
4.1 环境准备
本文示例采用 Python 3.9 以上版本,只需要标准库和少量第三方库。
python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate pip install pyyaml openai说明一下:
pyyaml用于读取评测任务配置文件。openai用于调用大模型 API。如果你的模型不是 OpenAI 兼容接口,可以替换成对应的 SDK。
4.2 项目结构
long_horizon_eval/ ├── configs/ │ ├── task_categories.yaml │ └── eval_config.yaml ├── tasks/ │ ├── data_analysis_task.py │ └── customer_service_task.py ├── agents/ │ ├── mock_agent.py │ └── llm_agent.py ├── evaluator/ │ ├── metrics.py │ └── runner.py ├── results/ │ └── eval_result.json └── main.py4.3 定义评测任务
我设计一个简化版的数据分析任务。任务要求模型按步骤执行一系列操作,每一步都有明确的动作和状态变更。
# 文件路径:tasks/data_analysis_task.py from dataclasses import dataclass, field from typing import List @dataclass class TaskStep: step_id: int action: str description: str expected_state: dict @dataclass class EvalTask: task_id: str title: str max_steps: int steps: List[TaskStep] = field(default_factory=list) def add_step(self, action: str, description: str, expected_state: dict): step_id = len(self.steps) + 1 self.steps.append(TaskStep(step_id, action, description, expected_state))这里定义了两个核心数据结构:
TaskStep:任务的单个步骤,包含动作名称、步骤描述以及期望状态。EvalTask:完整评测任务,包含任务 ID、标题、最大步骤数和步骤列表。
下面构造一个具体的评测任务。我用一个模拟的“销售数据分析”场景,包含数据读取、清洗、汇总、可视化和生成报告五个阶段,总共拆成 15 个步骤。
# 文件路径:tasks/build_tasks.py from tasks.data_analysis_task import EvalTask def build_sales_analysis_task(): task = EvalTask( task_id="sales_analysis_001", title="按季度汇总销售数据并生成分析报告", max_steps=30 ) steps = [ ("read_csv", "读取销售原始数据文件", {"file_loaded": True, "row_count": 1000}), ("inspect_columns", "查看数据列名和类型", {"columns_identified": True}), ("check_missing", "检查缺失值比例", {"missing_checked": True}), ("drop_duplicates", "去除重复行", {"duplicates_removed": True, "row_count_lte": 1000}), ("fill_missing", "用中位数填充数值列缺失值", {"missing_filled": True}), ("convert_date", "将日期列转换为标准格式", {"date_converted": True}), ("extract_quarter", "从日期中提取季度字段", {"quarter_extracted": True}), ("group_by_quarter", "按季度分组", {"grouped": True}), ("sum_sales", "计算每个季度的销售额总和", {"quarterly_sum": 286000.0}), ("calc_growth", "计算季度环比增长率", {"growth_calculated": True}), ("sort_desc", "按销售额降序排列", {"sorted": True}), ("find_best_quarter", "找出销售额最高的季度", {"best_quarter": "Q4"}), ("save_csv", "保存汇总结果到文件", {"csv_saved": True}), ("create_bar_chart", "生成季度销售额柱状图", {"chart_created": True}), ("write_report", "生成包含核心结论的分析报告", {"report_gen": True}) ] for action, desc, expected in steps: task.add_step(action, desc, expected) return task4.4 实现 Mock Agent
为了能够在没有真实大模型 API 的情况下先跑通评测链路,我实现了一个简单的 Mock Agent。它内部预设了步骤执行逻辑,方便验证评测框架是否正确。
# 文件路径:agents/mock_agent.py import random class MockAgent: def __init__(self, success_prob=0.8, seed=42): self.success_prob = success_prob self.random = random.Random(seed) self.visited_steps = [] def take_action(self, observation): """ 根据环境观察,决定下一步动作。 Mock 实现里直接返回一个动作,并模拟成功/失败概率。 """ step_id = observation.get("current_step_id", 0) action = observation.get("action", "unknown") # 模拟随机失败 if self.random.random() > self.success_prob: return {"action": action, "success": False, "error": "simulated failure"} self.visited_steps.append(step_id) return {"action": action, "success": True, "result": {"ok": True}}这里需要说明的是,真实评测中应该替换为调用大模型 API 的 Agent。Mock 版本的意义是保证评测流程可以独立验证。
4.5 实现 LLM Agent 调用示例
下面给出一个真实场景下的 LLM Agent 骨架。它会把环境观察信息组织成 Prompt,调用 OpenAI 兼容接口,解析模型输出作为动作。
# 文件路径:agents/llm_agent.py import json from openai import OpenAI class LLMAgent: def __init__(self, model_name: str, base_url: str = None, api_key: str = None): self.model_name = model_name self.client = OpenAI(base_url=base_url, api_key=api_key) self.history = [] def take_action(self, observation): """ 根据当前观察和任务历史,让模型决定下一步动作。 """ system_prompt = """ 你是一个长时程任务执行助手。你会收到当前环境观察和任务目标。 请根据当前状态,决定下一步执行的动作。 输出格式必须为 JSON,包含 action 和 reasoning 两个字段。 """ user_prompt = json.dumps(observation, ensure_ascii=False, indent=2) messages = [{"role": "system", "content": system_prompt}] for item in self.history[-10:]: messages.append(item) messages.append({"role": "user", "content": user_prompt}) response = self.client.chat.completions.create( model=self.model_name, messages=messages, temperature=0.2 ) content = response.choices[0].message.content result = json.loads(content) self.history.append({"role": "user", "content": user_prompt}) self.history.append({"role": "assistant", "content": content}) return result这里的实现思路是:
- 维护最近 10 轮对话历史,模拟模型的长时程记忆。
- 环境观察以 JSON 形式传给模型。
- 要求模型输出结构化动作,便于后续自动执行和评分。
- API 地址和密钥必须通过环境变量或配置文件传入,不要硬编码在代码里。
4.6 实现评测执行器
评测执行器负责按步骤驱动任务,记录模型每一步的完成情况,并统计最终指标。
# 文件路径:evaluator/runner.py import time from typing import Dict, List class EvalRunner: def __init__(self, agent, max_steps_limit: int = 40): self.agent = agent self.max_steps_limit = max_steps_limit self.step_records = [] def run_task(self, task) -> Dict: """ 执行单个评测任务,返回步骤级和任务级结果。 """ start_time = time.time() environment_state = {} success_steps = 0 final_success = False for step in task.steps: # 构建环境观察 observation = { "task_id": task.task_id, "current_step_id": step.step_id, "action": step.action, "description": step.description, "environment_state": environment_state } # 让 Agent 执行动作 action_result = self.agent.take_action(observation) # 判断步骤是否成功 step_success = ( action_result.get("success", False) and self._check_expected_state( action_result.get("result", {}), step.expected_state ) ) if step_success: success_steps += 1 environment_state.update(action_result.get("result", {})) else: # 模拟环境状态部分更新 environment_state["error_count"] = environment_state.get("error_count", 0) + 1 self.step_records.append({ "step_id": step.step_id, "action": step.action, "success": step_success }) # 步骤数超过限制,提前终止 if len(self.step_records) >= self.max_steps_limit: break elapsed = time.time() - start_time final_success = success_steps == len(task.steps) return { "task_id": task.task_id, "final_success": final_success, "success_steps": success_steps, "total_steps": len(task.steps), "step_success_rate": success_steps / len(task.steps), "time_cost": round(elapsed, 3), "step_records": self.step_records } def _check_expected_state(self, actual: Dict, expected: Dict) -> bool: """ 检查步骤结果是否符合预期状态。 这里只做 key 级别的浅比较,真实场景需要更复杂的校验逻辑。 """ for key, value in expected.items(): if actual.get(key) != value: return False return True执行器的核心逻辑有三个:
第一,逐步骤执行任务,构造当前环境的观察信息传给 Agent。
第二,根据 Agent 返回结果和期望状态,判断当前步骤是否成功。
第三,记录每一步的状态,最终汇总出任务完成率、步骤成功率等指标。
4.7 扩展:带错误恢复的评测逻辑
真实长时程任务中,Agent 的执行顺序不一定和预设步骤完全一致。比如第 5 步失败了,Agent 可能回到第 3 步重新执行。为了处理这种情况,我们可以把“固定的步骤顺序”改成“基于环境状态的目标条件检查”。
# 文件路径:evaluator/runner.py 中的补充方法 def run_task_with_recovery(self, task) -> Dict: """ 支持错误恢复的任务执行版本。 不强制步骤顺序,而是检查每个步骤目标是否最终达成。 """ start_time = time.time() environment_state = {} completed_goals = set() attempts = 0 while attempts < self.max_steps_limit: # 找到下一个未完成的目标步骤 pending_steps = [ step for step in task.steps if step.step_id not in completed_goals ] if not pending_steps: break current_goal = pending_steps[0] observation = { "task_id": task.task_id, "pending_goals": [ {"step_id": s.step_id, "action": s.action, "description": s.description} for s in pending_steps ], "environment_state": environment_state } action_result = self.agent.take_action(observation) attempts += 1 # 判断是否完成了某个目标 for step in pending_steps: if self._check_expected_state(action_result.get("result", {}), step.expected_state): completed_goals.add(step.step_id) environment_state.update(action_result.get("result", {})) break self.step_records.append({ "attempt": attempts, "action": action_result.get("action", "unknown"), "completed_goals": sorted(completed_goals) }) final_success = len(completed_goals) == len(task.steps) elapsed = time.time() - start_time return { "task_id": task.task_id, "final_success": final_success, "completed_goals": sorted(completed_goals), "total_goals": len(task.steps), "attempts": attempts, "time_cost": round(elapsed, 3) }这个版本更适合评测真实 Agent,因为它不强制 Agent 按照预设顺序执行,而是以“目标是否最终达成”作为判定标准。它更能反映模型实际解决问题的能力。
4.8 运行评测主程序
最后,写一个主程序把整个评测串起来。
# 文件路径:main.py import json from agents.mock_agent import MockAgent from evaluator.runner import EvalRunner from tasks.build_tasks import build_sales_analysis_task def main(): # 构建评测任务 task = build_sales_analysis_task() # 创建 Agent agent = MockAgent(success_prob=0.8, seed=42) # 创建执行器 runner = EvalRunner(agent, max_steps_limit=30) # 执行评测 result = runner.run_task(task) # 输出结果 print(json.dumps(result, ensure_ascii=False, indent=2)) # 保存结果 with open("results/eval_result.json", "w", encoding="utf-8") as f: json.dump(result, f, ensure_ascii=False, indent=2) print("评测完成,结果已保存到 results/eval_result.json") if __name__ == "__main__": main()运行结果示例:
{ "task_id": "sales_analysis_001", "final_success": false, "success_steps": 11, "total_steps": 15, "step_success_rate": 0.7333, "time_cost": 0.021, "step_records": [ {"step_id": 1, "action": "read_csv", "success": true}, {"step_id": 2, "action": "inspect_columns", "success": true}, ... ] }这里模拟出了一个非常经典的评测现象:单步成功率 80%,最终 15 步全部成功的概率大约是 0.8 的 15 次方,也就是 3.5% 左右。即使在更理想的单步成功率下,长任务的最终成功率也会被明显拉低。
如果我们把这个逻辑放到真实模型评测中,就很容易理解为什么“顶尖模型综合只有人类 27.3%”了——人类在长任务中的单步成功率和错误恢复能力,远高于当前模型。
5. 评测结果解读与失败模式分析
5.1 怎么解读“27.3%”这类数字
看到“模型只有人类 27.3%”这个数据,很多人的第一反应是“模型是不是很笨”。其实不能这么简单理解。
这个 27.3% 通常是综合了多个任务的加权得分。不同任务难度差异很大,模型可能在简单的工具调用任务上已经接近人类水平,但一旦涉及跨系统信息同步、长时间规划、隐性约束推理,就会明显落后。
所以解读评测结果时,不能只看总分,还要看分项得分。比如:
- 单步工具调用准确率:可能已经到 90% 以上。
- 任务级完成率:可能只有 30% 左右。
- 错误恢复成功率:可能低于 20%。
得出“模型某类能力不足”的结论时,要基于分项数据,而不是笼统地用总分做判断。
5.2 常见的模型失败模式
在长时程评测中,模型的失败往往呈现出几种可归类的模式。
模式一:迷失初始目标
模型执行到中期,开始专注于某个子任务,忘记了最初的最终目标。比如任务是“统计各季度销售额并生成报告”,模型可能花大量时间清洗数据、调整图表样式,最后没有生成报告。
模式二:死循环
某个步骤反复失败,模型不断重试同一种方案,而不是尝试更换路径。这在 API 调用超时或页面元素定位失败时特别常见。
模式三:幻觉式完成
模型并没有真正完成某个操作,却基于猜测直接声称完成了。比如它可能没有真正保存文件,但报告中说“文件已保存到指定路径”。
模式四:忽视约束条件
任务描述中散落着一些约束条件,比如“只统计 2024 年数据”“排除退款订单”。模型在长时程任务中容易丢失这些细节约束,导致最终结果不合规。
5.3 针对失败模式优化评测设计
评测系统本身也应该针对这些失败模式做设计。一个可行的方式是在结果分析阶段增加“失败原因分类”模块,把每个失败任务归类到以上几种模式中。
# 文件路径:evaluator/classify_failure.py def classify_failure(task_result, task_steps): """ 根据步骤记录,对失败任务进行原因分类。 """ step_records = task_result.get("step_records", []) if task_result.get("final_success", False): return "success" # 检查是否出现大量重复动作 action_counts = {} for record in step_records: action = record.get("action", "unknown") action_counts[action] = action_counts.get(action, 0) + 1 if any(count >= 3 for count in action_counts.values()): return "dead_loop" # 检查是否有步骤连续失败 consecutive_failures = 0 for record in step_records: if not record.get("success", False): consecutive_failures += 1 else: consecutive_failures = 0 if consecutive_failures >= 3: return "error_accumulation" # 检查是否完成率很低 success_rate = task_result.get("step_success_rate", 0) if success_rate < 0.4: return "goal_misalignment" return "other"这种自动化分类能帮助评测方快速定位模型的能力短板。
6. 环境准备与高阶配置说明
前面我提到过两种 Agent 和两种评测执行器,实际的评测环境比 Demo 更复杂。下面是企业级长时程评测环境需要准备的核心组件:
6.1 环境组件清单
| 组件 | 作用 | 推荐工具/方案 |
|---|---|---|
| 任务环境 | 提供真实可操作的环境 | 浏览器自动化、沙箱容器、Mock 服务 |
| 数据存储 | 保存评估结果和任务配置 | MySQL、SQLite、MinIO |
| 模型接入 | 调用被测模型 | OpenAI 兼容 API、本地模型服务 |
| 评测脚本 | 驱动评测流程 | Python + Pytest |
| 可视化看板 | 展示评测结果 | Grafana、Superset、Streamlit |
| 调度系统 | 批量运行评测任务 | 定时任务、CI/CD 流水线 |
6.2 任务环境的选择
长时程任务评测最重要的就是环境真实度。三种常见方案:
方案一:真实浏览器环境
使用 Selenium、Playwright 或 Browser Use 控制真实浏览器,让模型像人类一样点击按钮、填写表单、读取页面。
优点:环境最真实,能反映模型在真实 Web 应用中的表现。
缺点:环境不稳定,页面变动会导致评测结果无法复现。
方案二:API 沙箱环境
搭建一套 Mock 后端服务,模型通过调用 API 来完成任务。比如模拟一个订单管理系统的 API,让模型通过多个 API 调用完成订单状态变更。
优点:稳定、快速、容易自动化判定。
缺点:无法评测模型的界面理解和操作能力。
方案三:混合环境
核心业务操作使用 API 沙箱,部分关键交互使用真实浏览器。这种方案既能保证评测效率,又能保留界面交互评测能力。
6.3 评测数据的一致性与隔离
评测任务执行后会产生环境状态变更。为了保证多次评测之间不互相干扰,需要注意:
第一,每个任务运行前重置环境到初始状态。
第二,使用独立的测试账号和数据目录,避免测试数据混入真实数据。
第三,在容器或虚拟化环境中执行任务,评测结束后销毁环境实例。
7. 常见问题与排查思路
这里整理一些长时程 AI 任务评测中常见的问题和排查思路。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型在某个步骤反复失败 | 动作格式不匹配 | 检查 Prompt 中的动作格式要求,增加格式校验和自动纠错 |
| 大模型 API 调用超时 | Prompt 过长或模型负载高 | 精简历史记录,限制上下文轮数,增加重试机制 |
| 评测结果不稳定 | 任务环境状态未重置 | 确保每次评测前环境初始化,使用独立容器 |
| 最终结果正确但步骤全错 | 判分维度设置不合理 | 增加“结果正确性”和“过程规范性”双维度判分 |
| 步骤成功率很高但任务成功率低 | 存在关键路径步骤 | 分析步骤依赖关系,识别不可失败的关键步骤 |
| 模型产生幻觉式完成 | 缺少环境验证机制 | 增加真实性校验,比如检查文件是否真实存在 |
| 评测耗时过长 | 单任务步骤数过多 | 设置步骤数上限,并行运行多个评测任务 |
7.1 大模型 API 接入的坑
接入真实模型时,有两个坑需要特别注意。
第一个是上下文长度。长时程任务执行过程中,历史记录会不断累积,很容易超出模型的上下文窗口。建议设置一个“滑动窗口”,只保留最近 N 轮交互,同时把更早期的关键信息以“摘要”形式注入 Prompt。
第二个是输出格式解析。模型偶尔会输出非 JSON 格式的内容,评测框架要有容错机制。比如当 JSON 解析失败时,可以提示模型重新输出,或者从输出文本中提取 JSON 片段。
# 文件路径:utils/json_utils.py import json import re def safe_json_parse(text: str): """ 安全解析模型输出中的 JSON 内容。 """ # 直接尝试解析 try: return json.loads(text) except json.JSONDecodeError: pass # 尝试提取 markdown 代码块 pattern = r"```(?:json)?\s*(.*?)\s*```" match = re.search(pattern, text, re.DOTALL) if match: try: return json.loads(match.group(1)) except json.JSONDecodeError: pass # 尝试提取第一个大括号起始的 JSON start_idx = text.find("{") if start_idx != -1: try: return json.loads(text[start_idx:]) except json.JSONDecodeError: pass raise ValueError("无法从模型输出中解析 JSON")7.2 评测环境的网络依赖问题
长时程评测经常会访问外部服务,比如模型 API、第三方数据接口、浏览器加载的 CDN 资源。网络不稳定会导致评测结果失真。
解决方案是:把网络依赖尽量可控。对于外部 API,增加超时和重试;对于浏览器资源,使用本地缓存或预加载;对于不稳定的第三方接口,使用 Mock 替代。
8. 最佳实践与工程化建议
8.1 评测任务库的建设
评测任务不能只做一次,而要形成可持续迭代的任务库。
建议按难度分层维护:
- L1:单工具、5 到 8 步的简单任务。
- L2:多工具、10 到 15 步的中等任务。
- L3:跨系统、20 步以上且包含异常恢复的复杂任务。
每次模型迭代后,跑完整任务库,生成对比报告。
8.2 评测结果的版本管理
长时程评测涉及大量中间数据,包括任务配置、Agent 日志、环境状态、步骤记录。建议把这些数据纳入版本管理。
代码、任务配置和评测脚本放入 Git 仓库管理,评测结果和日志文件可以使用专门的存储服务,并记录对应的模型版本和评测时间。
8.3 可观测性与日志记录
长时程评测最怕“出了问题找不到原因”。所以日志记录是刚需。
每条 Agent 动作日志至少包含:
- 时间戳
- 当前任务 ID 和步骤 ID
- 输入观察信息
- Agent 输出动作
- 环境执行结果
- 步骤是否判分成功
# 文件路径:utils/logger.py import json import time class EvalLogger: def __init__(self, log_file: str): self.log_file = log_file def log(self, level: str, message: str, **context): entry = { "timestamp": time.time(), "level": level, "message": message, "context": context } with open(self.log_file, "a", encoding="utf-8") as f: f.write(json.dumps(entry, ensure_ascii=False) + "\n")8.4 安全边界与合规要求
长时程评测涉及自动操作、数据处理和外部服务调用,需要特别注意安全边界:
第一,评测数据必须脱敏。不要使用真实用户数据、真实密钥作为评测输入。
第二,工具调用的权限必须收敛。评测环境中的 API 密钥只授予最小必要权限,不得授予生产中不需要的高危操作权限。
第三,对自动化操作要设置明确的终止条件。当任务步骤数达到上限,或检测到疑似死循环时,必须强制终止。
第四,涉及生产环境变更的场景,应该先在隔离的测试环境验证,并且所有变更操作保留审计日志。
8.5 自动化评测流水线
更好的做法是把长时程评测接入 CI/CD 流水线。
# 文件路径:.github/workflows/eval.yml name: Long-Horizon Eval on: push: branches: [main] workflow_dispatch: jobs: eval: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.10' - name: Install dependencies run: | pip install -r requirements.txt - name: Run evaluation env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | python main.py - name: Upload result uses: actions/upload-artifact@v4 with: name: eval-result path: results/8.6 评测指标的可解释性
最后要强调的是,工程化评测不仅要给出数字,还要让数字“可解释”。建议输出评测报告时,除了最终得分,还要附上:
- 每个任务的详细执行轨迹。
- 失败任务的分类统计。
- 模型在哪些步骤上表现最好、哪些步骤上表现最差。
- 与上一轮评测相比,哪些能力提升了、哪些能力退化了。
这样评测结果才能真正指导模型选型、Prompt 优化和 Agent 架构改进。
9. 下一步可以叠加的评测方向
长时程 AI 任务评测是一个非常活跃的方向,上面这套框架只是基础。接下来可以在以下几个方向继续叠加能力。
第一,加入多模态任务。比如让模型在长时程任务中读取图表、识别验证码、处理截图信息,这更贴近真实办公场景。
第二,加入多 Agent 协作评测。现在很多真实业务不是单个模型在工作,而是多个 Agent 分工协作。评测需要覆盖任务分配、结果汇总、沟通效率等指标。
第三,加入记忆机制评测。长时程任务天然依赖记忆能力,可以专门设计需要跨阶段记忆的评测任务,测试模型的记忆写入、检索和遗忘行为。
第四,引入在线评测平台。把任务库和评测框架部署成服务,支持随时提交新模型进行评测,并自动生成横向对比报告。
我自己的实践感受是:长时程评测比传统单轮评测要复杂得多,但它也是现阶段判断 AI Agent 是否能真正“干活”的最接近真实的手段。像 27.3% 这样的数字,看起来刺眼,其实是很有价值的参考——它告诉我们模型离真正的“可信任的长期执行体”还有不小距离。建议大家在评估自己手头模型能力时,也尽早建立一套长时程评测任务库,用连续任务和失败恢复的视角去观察模型,比单纯跑十几个单轮 benchmark 更能说明问题。
