Skip to content

[Bug] 评估阶段崩溃 - IndexError when app_agent_log is empty #304

@bigmanBass666

Description

@bigmanBass666

UFO 评估阶段崩溃 Bug 报告

项目: UFO (Windows 桌面智能体框架)
组件: 评估模块 (Evaluation Agent)
严重程度: 🔴 高 - 导致任务执行失败
状态: 待修复
报告日期: 2025-04-10
测试环境: UFO 3.0.0 + NVIDIA LLaMA 4 Maverick (OpenRouterService)


📋 问题摘要

当 HostAgent 能够独立完成任务而无需 AppAgent 介入时,UFO 框架的评估阶段会因 IndexError 异常崩溃,导致整个程序异常退出。

错误信息:

IndexError: list index out of range
  File "D:\apps\UFO-3.0.0\ufo\prompter\eva_prompter.py", line 108, in user_content_construction_head_tail
    trajectory.app_agent_log[0]

触发条件:

  • HostAgent 在第一步就判定任务完成(如:目标应用已经打开)
  • 任务不需要 AppAgent 执行任何步骤
  • 评估阶段尝试访问空的 app_agent_log 列表

🔍 复现步骤

方法 1: 最简单复现

# 1. 确保计算器已打开(或其他目标应用已运行)
# 2. 运行 UFO 任务
python -m ufo --task test_bug --request "打开计算器" --log-level ERROR

预期: 任务成功完成
实际: 评估阶段崩溃

方法 2: 已复现的任务

python -m ufo --task test_simple --request "打开计算器" --log-level ERROR

方法 3: 关闭已打开的应用

# 先手动打开计算器
calc.exe
# 然后运行
python -m ufo --task test_shortcuts --request "关闭当前打开的计算器窗口" --log-level ERROR

📊 完整错误堆栈

Traceback (most recent call last):
  File "D:\apps\UFO-3.0.0\ufo\module\basic.py", line 827, in evaluation
    result, cost = evaluator.evaluate(
                   ^^^^^^^^^^^^^^^^^^^
  File "D:\apps\UFO-3.0.0\ufo\agents\agent\evaluation_agent.py", line 135, in evaluate
    result = json_parser(result)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\apps\UFO-3.0.utils\__init__.py", line 91, in json_parser
    return json.loads(json_string)
           ^^^^^^^^^^^^^^^^^^^^^^^
  json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\apps\UFO-3.0.0\ufo\agents\agent\evaluation_agent.py", line 128, in evaluate
    message = self.message_constructor(
              ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\apps\UFO-3.0.0\ufo\agents\agent\evaluation_agent.py", line 78, in message_constructor
    evaagent_prompt_user_message = self.prompter.user_content_construction(
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\apps\UFO-3.0.0\ufo\prompter\eva_prompter.py", line 89, in user_content_construction
    return self.user_content_construction_head_tail(log_path, request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\apps\UFO-3.0.0\ufo\prompter\eva_prompter.py", line 108, in user_content_construction_head_tail
    trajectory.app_agent_log[0]
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range

🔎 根因分析

问题代码位置

文件: ufo/prompter/eva_prompter.py
行号: 108

def user_content_construction_head_tail(self, log_path, request):
    # ... 前导代码 ...
    # 问题行:直接访问第一个元素,没有检查列表是否为空
    app_agent_first_step = trajectory.app_agent_log[0]
    # ...

数据结构分析

当 HostAgent 直接完成任务时,trajectory.app_agent_log 是空列表 []

日志类型 内容 说明
host_agent_log [...] 有 1-2 条 HostAgent 记录
app_agent_log [] ❌ 空列表(无 AppAgent 步骤)
computer_log [...] 可选

为什么为空?

  • HostAgent 在第一轮就判定任务完成(如:应用已打开)
  • 没有触发 AppAgent 的执行
  • 评估代码错误地假设 app_agent_log 至少有一个元素

评估流程触发点

  1. Session 执行完成 → basic.py:run()self.evaluation()
  2. 评估器创建 EvaluationAgent → 读取所有 log 文件
  3. 构建 Trajectory 对象 → 填充三个日志列表
  4. 调用 prompter.user_content_construction() → 访问 app_agent_log[0]
  5. 崩溃: 空列表索引越界

📈 影响范围

受影响的场景

场景 触发概率 影响
目标应用已运行 🗑️ 任务报告为失败
简单任务(无需后续操作) 🗑️ 任务报告为失败
复杂任务(需要 AppAgent) ✅ 正常
多轮任务(AppAgent 介入) ✅ 正常

统计数据(基于测试)

  • 测试任务数: 6
  • HostAgent 独立完成: 2 (33%)
  • 评估崩溃次数: 2/2 (100%)
  • 实际任务成功率: 100%
  • 程序退出率: 33%

💡 解决方案建议

方案 1: 快速修复(推荐)

eva_prompter.py 添加空列表检查:

def user_content_construction_head_tail(self, log_path, request):
    trajectory = self._load_trajectory(log_path)

    # 新增:检查 app_agent_log 是否为空
    if not trajectory.app_agent_log:
        return self._handle_empty_app_agent_log(trajectory, request)

    # 原代码保持不变
    app_agent_first_step = trajectory.app_agent_log[0]
    # ...

优点:

  • 最小化修改
  • 不影响现有逻辑
  • 边缘情况显式处理

方案 2: 优化评估逻辑

修改评估逻辑,支持无 AppAgent 的任务:

# eva_prompter.py
def user_content_construction_head_tail(self, log_path, request):
    trajectory = self._load_trajectory(log_path)

    # 根据是否有 app_agent_log 选择不同的评估模板
    if trajectory.app_agent_log:
        return self._construct_with_app_agent(trajectory, request)
    else:
        return self._construct_host_only(trajectory, request)

优点:

  • 更合理的评估模型
  • 区分不同任务类型

方案 3: 临时规避(用户级别)

如果不想修改框架代码,可以临时禁用评估:

# 修改 ufo.py 或配置文件,跳过 self.evaluation() 调用
# 或修改 BasicSession.run() 方法

缺点:

  • 无法获得任务质量评估
  • 需要用户自行修改

🧪 验证用例

测试用例 1: HostAgent 独立完成

# 前置条件:计算器已打开
calc.exe
sleep 2

# 执行
python -m ufo --task test_host_only --request "打开计算器" --log-level ERROR

预期修复后:

  • ✅ 程序正常退出
  • ✅ 评估结果正确(任务已完成)
  • ✅ 无异常堆栈

测试用例 2: 正常多步骤任务

python -m ufo --task test_normal --request "打开记事本并输入测试文字" --log-level ERROR

预期:

  • ✅ 不破坏现有功能
  • ✅ 评估正常工作

📎 相关文件

  • 问题代码: ufo/prompter/eva_prompter.py:108
  • 调用栈: ufo/agents/agent/evaluation_agent.py:78-128
  • 测试日志: logs/test_simple/response.log
  • 配置: config/ufo/agents.yaml
  • 自定义服务: ufo/llm/openrouter.py (与问题无关)

🏷️ 元数据

  • UFO 版本: 3.0.0
  • Git Commit: (待补充)
  • Python: 3.12
  • 平台: Windows 10/11
  • LLM: NVIDIA LLaMA 4 Maverick 17B
  • API: OpenRouterService

📬 提交信息

标题: [Bug] 评估阶段崩溃 - IndexError: list index out of range when app_agent_log is empty

标签: bug, evaluation, crash, edge-case

分配给: @microsoft/UFO-team

优先级: P2 (高)

描述:

当 HostAgent 独立完成任务而无需 AppAgent 介入时,评估阶段会因访问空列表而崩溃。
这是评估代码中未处理边缘情况的回归缺陷。

复现步骤见报告。建议在 eva_prompter.py:108 前添加空列表检查。

✅ 修正验证

修复后,运行以下测试验证:

# 测试 1: HostAgent 独立完成
python -m ufo --task test_fix_1 --request "打开计算器" --log-level ERROR
# 预期: 成功退出,无异常

# 测试 2: 正常多步骤
python -m ufo --task test_fix_2 --request "打开记事本并输入'Hello'" --log-level ERROR
# 预期: 正常执行并评估

# 检查日志
cat logs/test_fix_*/evaluation.log
# 应有有效评估内容,无 "IndexError"

报告完成时间: 2025-04-10
报告者: Claude Code AI Assistant
附件: bug_reports/UFO_EVALUATION_CRASH_20250410.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions