数据截至 (上游 commit 610bac85d242)
第 2 章 · 三模型分工:为什么要拆成三个
这章讲本项目最核心的架构决策:一个 computer-use agent,用三个模型。读完你能说清每个模型管什么、输入输出是什么、在
config.py里怎么配、以及为什么这么拆能让「任意开源模型」都能拼进来。
2.1 它要解决的小问题
操作电脑其实是三种截然不同的能力:
- 看懂屏幕——这上面有啥窗口、图标、按钮?
- 规划动作——为了完成目标,下一步该点还是该打字,调哪个工具?
- 精确定位——「那个登录按钮」到底在第几个像素?
一个模型要同时精通这三样很难,尤其是第 3 项(精确到像素的坐标)几乎所有通用大模型都做不好。与其等一个全能模型,不如分而治之:谁擅长干哪样就用谁。
2.2 三个角色一览
| 角色 | 输入 | 输出 | 默认用谁 | 在哪调用 |
|---|---|---|---|---|
| vision(看图) | 截图 + 记忆 + 模板 prompt | 屏幕描述 + 是否完成 + 建议下一步(纯文本) | OpenRouterProvider("qwen-2.5-vl") | append_screenshot |
| action(定动作) | 系统提示 + 记忆 + vision 描述 + tools | 思考文本 + 工具调用 | GroqProvider("llama-3.3") | run 主循环 |
| grounding(定位) | 一句描述 + 截图 | 屏幕坐标 (x, y) | OSAtlasProvider() | click_element |
默认组合来自 os_computer_use/config.py:5-21。注意默认 action 模型 llama-3.3 是纯文本模型——它自己看不见图,全靠 vision 模型把屏幕「讲」给它听。这正是三分法的精髓:让不会看图的强推理模型,也能操作电脑。
2.3 图示:三个模型在一圈循环里的接力
怎么读:一圈循环里,信息像接力棒一样在三个模型间传递。vision 把画面变成文字,action 把文字变成动作意图,grounding 只在「点击」时才上场把描述变成坐标。
截图 ──▶ ① vision 模型 ──▶ 「屏幕上有 Firefox 图标…下一步点它」(文字)
│
▼
② action 模型(可以是纯文本模型)
│ 决定: click(query="Firefox 图标")
▼
是「点击」类工具吗?
│是 │否(打字/跑命令)
▼ ▼
③ grounding 模型 直接执行
「Firefox 图标」→(812, 47)
│
▼
沙箱 move_mouse(812,47) + click
2.4 每个角色细看
vision(看图 → 文字)
只做描述,不做决策。它被强制按固定模板输出(见 01-agent-loop.md §1.5),核心是把像素画面翻译成 action 模型能读的文字。代码:SandboxAgent.append_screenshot(sandbox_agent.py:152-169),内部调 vision_model.call([...])(不传 tools,所以只返回纯文本,见 04-providers.md §4.5)。
action(文字 → 动作)
带着 tools 调用(sandbox_agent.py:181-196),返回工具调用。它是唯一「做决定」的模型,也是唯一决定何时 stop 的模型。因为动作空间是离散的一组工具,纯推理模型也能胜任,不需要看图。
grounding(描述 → 坐标)
只在点击类动作被触发时才调用(click_element,sandbox_agent.py:118-129)。它是专门训练来做「GUI 元素定位」的小模型(OS-Atlas / ShowUI),拿一句话 + 截图,吐出坐标。整章 3 专讲它。
2.5 真实实现:config 就是装配表
三个模型在 os_computer_use/config.py 里以模块级变量定义,sandbox_agent.py:1 直接 import 使用:
# 真实源码 config.py:5-21(省略被注释的备选)
grounding_model = providers.OSAtlasProvider()
vision_model = providers.OpenRouterProvider("qwen-2.5-vl")
action_model = providers.GroqProvider("llama-3.3")
换模型 = 改这三行。文件里大量被注释的备选(OpenAIProvider("gpt-4o")、AnthropicProvider("claude-3.5-sonnet")、ShowUIProvider() …)就是「菜单」——取消注释即可切换。只要新 provider 实现了统一的 call() 接口,agent 主循环一行都不用改(见 04-providers.md)。
2.6 巧妙之处
- 能力解耦 = 模型自由。 因为定位被独立成 grounding,action 模型不必看图、不必会定位,任何能调工具的文本模型都能当大脑。这是「支持 10+ 模型」的结构性原因。
- vision 与 action 可以是同一个也可以拆开。 config 允许把二者都设成同一个多模态模型(如都用
gpt-4o),也允许拆成「便宜看图 + 强推理定动作」的组合,成本/能力自由权衡。
2.7 边界与局限
- 三次模型调用 / 每步。 一圈循环最多打三次不同的 LLM(vision + action + grounding),延迟叠加、成本叠加。
- 信息在 vision→action 之间「压成文字」有损。 action 模型看不到原图,只能信 vision 的描述;vision 描述漏了的东西,action 就无从决策。
- grounding 与 vision 各看各的截图。 定位时
click_element会重新截一张图再交给 grounding(sandbox_agent.py:120-121),若两次截图间画面变了可能错位。
2.8 横向对比
主流闭源 computer-use(如 Anthropic computer use)多是单个多模态大模型端到端输出动作和坐标。本项目的三分法是另一条路:
| 维度 | 单模型端到端 | 本项目三模型分工 |
|---|---|---|
| 定位能力 | 靠大模型自身 | 外挂专用 grounding 模型 |
| 能用的模型 | 需要强多模态 + 定位 | 任意能调工具的模型即可当大脑 |
| 调用次数/步 | 1 | 最多 3 |
| 可替换性 | 换模型难 | 改 config 三行即可 |
定位这一环的深挖见 03-grounding.md。
2.9 本章代码地图
| 主题 | 文件 | 符号 |
|---|---|---|
| 三模型装配 | os_computer_use/config.py | vision_model、action_model、grounding_model |
| vision 调用点 | os_computer_use/sandbox_agent.py | SandboxAgent.append_screenshot |
| action 调用点 | os_computer_use/sandbox_agent.py | SandboxAgent.run |
| grounding 调用点 | os_computer_use/sandbox_agent.py | SandboxAgent.click_element |