构建可靠的计算机使用代理:能够熬过凌晨3点的架构

发布: (2026年3月8日 GMT+8 19:17)
6 分钟阅读
原文: Dev.to

I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have the article text, I’ll translate it into Simplified Chinese while preserving all formatting, markdown, and technical terms.

我们将构建的内容

在本教程结束时,您将拥有一个面向生产环境的计算机使用代理架构,能够处理演示中从未展示的故障。我们将实现四种具体模式:

  1. 视觉状态验证循环 – 在每一次操作前后对屏幕状态进行分类。
  2. 分层重试编排器 – 在升级到人工介入之前使用确定性的回退方案。
  3. 成本防护栏 – 通过硬性上限防止预算失控。
  4. 幂等任务设计 – 在运行中途崩溃时仍能避免重复的副作用。

前置条件

  • 熟悉 Python asyncio
  • 对 LLM 视觉 API(Claude、GPT‑4V 或类似)有基本了解
  • 具备使用任意浏览器或桌面自动化工具(Playwright、Selenium、pyautogui)的经验
  • 对凌晨 3 点的静默失败保持足够的警惕

可视状态验证循环

Gotcha: 永远不要只相信单张截图。模型通常知道该怎么做,但它无法确认实际所在位置。

关键的洞察是 对状态进行分类,而不是对单个元素进行判断。与其问 “提交按钮是否可见?”,不如问 “我们是否在确认页面上?”。状态分类对布局迁移和异步渲染具有更强的韧性,而这些正是导致大多数生产故障的根源。

async def verified_action(agent, action, expected_state, max_attempts: int = 3):
    for attempt in range(max_attempts):
        screenshot = await agent.capture_screen()
        current_state = await agent.classify_state(screenshot)

        if current_state != expected_state.precondition:
            await agent.recover_to_state(expected_state.precondition)
            continue

        await agent.execute(action)
        post_screenshot = await agent.capture_screen()
        post_state = await agent.classify_state(post_screenshot)

        if post_state == expected_state.postcondition:
            return Success(post_state)

    return Failure(current_state, expected_state)

为什么进行状态分类?

  • 处理布局变化和异步渲染。
  • 将不稳定的失败率从 60‑70 % 降低到可管理的水平。

分层重试编排器

将相同的 LLM 方法重试五次既昂贵又常常无效。使用三层不同的策略:

class RetryOrchestrator:
    async def execute_with_fallback(self, task):
        # L1: LLM 视觉推理(约 85 % 的运行在此解决)
        result = await self.llm_agent.attempt(task, retries=2)
        if result.success:
            return result

        # L2: 通过 DOM/a11y 树的确定性自动化(捕获约 12 %)
        if task.has_scripted_path:
            result = await self.scripted_agent.attempt(task)
            if result.success:
                return result

        # L3: 人工升级队列(约 3 % 会到达此层)
        return await self.escalation.queue(task, context=result.debug_info)
  • 如果没有 L2,人工升级比例会从约 3 % 上升到约 15 %。
  • 为常见工作流编写确定性路径;让 LLM 处理边缘情况。

成本防护措施

一个困惑的代理每分钟可能会触发数十次视觉 API 调用。使用装饰器强制硬性限制:

@cost_guardrail(
    max_cost_usd=0.50,
    max_actions=25,
    timeout_seconds=180,
    rate_limit_window_seconds=300,   # 5‑minute sliding window
    max_calls_per_window=50
)
async def fill_invoice_form(agent, invoice_data):
    # Your agent logic here
    # The decorator aborts execution if any limit is breached
    ...

需要强制执行的四项限制:

  1. 每任务预算上限
  2. 操作次数上限
  3. 硬性超时
  4. 滑动窗口速率限制

请像对待向外部消费者公开的 API 速率限制一样,对这些限制保持同等严格。

幂等任务设计

将每个任务设计为可以安全地重新运行:

  • Pre‑check 在开始之前检查任务是否已经完成。
  • 使用 idempotency tokens 为提交打标签。
  • 为每个操作记录时间戳,以便恢复时准确知道从哪里继续。

如果代理重复提交同一表单,任何 LLM 智能都无法修复由此产生的数据完整性问题。

常见故障陷阱与缓解措施

故障类型典型症状缓解措施
异步渲染在页面加载前截取截图 → 产生不稳定的失败在捕获之前添加状态就绪检查。
模态框/弹窗劫持意外的对话框会立即中断上下文全局模态框关闭处理程序,在每个操作之前运行。
任务中途身份验证过期会话静默失效,导致重复重试在验证层检测登录页面并触发重新认证。
预算消耗卡住的流水线会在一夜之间消耗数百美元实施成本防护;持续监控限额。

结论

先构建 state verification layer ——它消除了最大类别的故障。然后添加 layered fallbacks 而不是更深的重试,最后在任何生产部署之前设置 hard cost guardrails

在计算机使用代理领域,竞争优势不再是模型本身;而是包裹它的可靠性工程。先构建枯燥的基础设施,你的凌晨 3 点的自己会感激你的。

0 浏览
Back to Blog

相关文章

阅读更多 »