只看截图就能操控网页?MolmoWeb本地部署实测,附完整代码
上周 Ai2(Allen AI研究所)放出了 MolmoWeb,一个开源的视觉 Web Agent。跟以前那些靠解析 HTML DOM 来操作网页的方案不同,MolmoWeb 直接看截图,跟人一样看屏幕,然后决定点哪里、打什么字。
我花了一天时间把它跑通了。这篇文章记录整个过程:从环境搭建到模型加载,再到实际让它完成一个网页搜索任务。踩了几个坑,也有一些超出预期的地方。
为什么截图方案比DOM解析好用
传统的 Web Agent(比如用 Playwright + LLM 的那些方案)需要把整个网页的 HTML 结构序列化成文本,喂给大模型。问题是,一个普通网页的 DOM 树动辄上万 token,又臃肿又容易出错,网站改个 class 名你就得重新适配。
MolmoWeb 的思路简单粗暴:截一张图,丢给视觉模型,让模型自己看懂页面上有什么,然后输出下一步操作。
实际好处有两点。第一是省 token,一张 1280×720 的截图经过视觉编码器处理后,消耗的上下文远比序列化整个 DOM 少。第二是不怕页面改版,你不依赖任何 CSS selector 或 XPath,页面长什么样就看什么样。
当然也有明显的短板:纯视觉方案在遇到被遮挡的元素、需要滚动才能看到的内容时,处理起来比较笨,得像人一样先滚动、再看。后面实测部分会说到这个问题。
环境准备
MolmoWeb 有两个版本:4B 和 8B 参数。4B 版本用 4-bit 量化后大概吃 6GB 显存,一张消费级显卡就能跑。我用的是 RTX 4090,跑 8B 全精度也没压力,但这里用 4B 做演示,降低门槛。
安装依赖
pip install transformers>=4.48.0 accelerate bitsandbytes jinja2 Pillow requests torch
几个注意点: - bitsandbytes 在 Windows 上安装可能报错,建议用 WSL2 或者直接在 Linux 上搞 - transformers 版本必须 >= 4.48.0,老版本不支持 MolmoWeb 的 processor
加载模型
from transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfig
import torch
CHECKPOINT = "allenai/MolmoWeb-4B"
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForImageTextToText.from_pretrained(
CHECKPOINT,
trust_remote_code=True,
quantization_config=bnb_config,
device_map="auto",
)
processor = AutoProcessor.from_pretrained(
CHECKPOINT,
trust_remote_code=True,
padding_side="left",
)
第一次加载会从 HuggingFace 下载模型权重,4B 量化版大概 2.5GB。国内网络可能需要设 HF_ENDPOINT 镜像。
核心逻辑:看截图、想一步、做一步
MolmoWeb 的工作循环很直白:
- 给它一个任务描述(比如"在 arXiv 上搜索 attention is all you need")
- 给它当前浏览器的截图
- 它输出两样东西:一段思考过程(THOUGHT)和一个动作(ACTION)
- 执行动作,截新的图,重复上面的循环
支持的动作类型:
goto(url) # 导航到指定网址
click(x, y) # 点击屏幕坐标(归一化到 0.0-1.0)
type("text") # 在当前焦点元素里打字
scroll(direction) # 滚动页面,up 或 down
press("key") # 按键,比如 Enter、Tab
new_tab() # 开新标签页
switch_tab(n) # 切换到第 n 个标签页
go_back() # 返回上一页
send_msg("text") # 把结果告诉用户
Prompt 模板
from jinja2 import Template
MOLMOWEB_THINK_TEMPLATE = Template("""
# GOAL
{{ task_description }}
# PREVIOUS STEPS
{% for action in past_actions -%}
## Step {{ action['index'] }}
THOUGHT: {{ action['thought'] }}
ACTION: {{ action['action'] }}
{% endfor %}
# CURRENTLY ACTIVE PAGE
Page {{ page_index }}: {{ page_title }} | {{ page_url }}
# NEXT STEP
""")
这个模板把任务目标、历史操作记录和当前页面信息拼在一起。模型会根据这些上下文,决定下一步该干什么。
推理函数
import re
def run_inference(prompt, image, max_new_tokens=300):
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image", "image": image},
],
}
]
inputs = processor.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt",
return_dict=True,
padding=True,
)
inputs = {k: v.to(model.device) for k, v in inputs.items()}
with torch.inference_mode(), torch.autocast("cuda", dtype=torch.bfloat16):
output = model.generate(**inputs, max_new_tokens=max_new_tokens)
generated_tokens = output[0, inputs["input_ids"].size(1):]
return processor.decode(generated_tokens, skip_special_tokens=True)
def parse_thought_and_action(raw_output):
thought = ""
action = ""
thought_match = re.search(r"THOUGHT:\s*(.+?)(?=\nACTION:|\Z)", raw_output, re.DOTALL)
action_match = re.search(r"ACTION:\s*(.+?)(?=\n|$)", raw_output, re.DOTALL)
if thought_match:
thought = thought_match.group(1).strip()
if action_match:
action = action_match.group(1).strip()
return {"thought": thought, "action": action}
实测:让它在 arXiv 上搜论文
我截了一张 arXiv 首页的图,让 MolmoWeb 完成"搜索 attention is all you need 这篇论文"的任务。
from PIL import Image
# 加载 arXiv 首页截图
screenshot = Image.open("arxiv_homepage.png")
prompt = build_prompt(
task_description="Find the paper 'Attention Is All You Need' on arXiv",
page_title="arXiv.org",
page_url="https://arxiv.org",
page_index=0,
)
raw_output = run_inference(prompt, screenshot)
result = parse_thought_and_action(raw_output)
print(f"思考: {result['thought']}")
print(f"动作: {result['action']}")
实际输出:
思考: I can see the arXiv homepage. I need to find the search box to search for the paper.
动作: click(0.82, 0.06)
它准确找到了右上角的搜索框位置。接下来输入关键词、按回车、从结果列表里找到目标论文,整个流程走了 5 步。
踩坑记录
第一个坑是截图分辨率。我一开始用 640×480 的截图,模型经常点错位置。换成 1280×720 之后明显好了。Ai2 官方建议用 1280×720 或更高分辨率。
第二个坑是中文网页识别率偏低。MolmoWeb 的训练数据主要是英文网站。我试了百度搜索页面,模型能认出搜索框,但对中文搜索结果的理解比较差,有时候会点错链接。如果你的应用场景主要是中文网页,可能还得等社区做中文微调版本。
第三个坑是长任务容易迷路。超过 10 步的任务,模型偶尔会忘记自己在干什么,重复之前的操作。在 prompt 里加更详细的历史记录能缓解,但会增加 token 消耗。
跟其他方案对比
我也用过 Playwright + GPT-4o 的方案做 Web 自动化。简单对比一下:
| 维度 | MolmoWeb 4B | Playwright + GPT-4o |
|---|---|---|
| 部署成本 | 本地跑,免费 | 按 API 调用计费 |
| 速度 | 4B 量化约 2-3 秒/步 | 看网络,通常 1-5 秒/步 |
| 中文支持 | 较差 | GPT-4o 中文好 |
| 页面适应性 | 不依赖 DOM 结构 | 依赖 selector,改版就挂 |
| 复杂任务 | 10 步以内比较稳 | 上下文窗口大,长任务更稳 |
MolmoWeb 的优势在于零成本、不依赖外部 API、不怕页面改版。劣势是模型小,复杂推理能力不如 GPT-4o,中文场景也差一截。
训练数据也开源了
Ai2 把训练数据也公开了,叫 MolmoWebMix。里面有三部分。
第一部分是 36K 条人类操作轨迹,众包工人用 Chrome 插件录制的真实浏览行为,覆盖 1100 多个网站。第二部分是合成轨迹,用 accessibility tree agent 自动生成的操作路径,数量比人类数据大得多。第三部分是 220 万条截图问答对,用来教模型理解网页截图里的内容。
这是目前公开的最大的 Web Agent 训练数据集。如果你想自己微调一个 Web Agent,这份数据省了大量标注成本。
谁适合用
做内部测试自动化的可以试试,不想维护一堆 CSS selector 的 E2E 测试场景很合适。做数据采集的也值得看看,特别是对页面结构不稳定的网站做信息提取。另外 RPA 原型验证也行,快速验证某个流程能不能自动化,再决定要不要投入做完整方案。
不建议直接用在生产环境的关键流程里。4B 模型的推理能力有限,偶尔会犯低级错误(比如把"取消"按钮当成"确认"来点)。
快速上手命令汇总
# 克隆示例代码
git clone https://github.com/allenai/molmoweb-examples.git
cd molmoweb-examples
# 安装依赖
pip install -r requirements.txt
# 跑官方 demo
python run_agent.py --task "Search for 'transformer architecture' on Google Scholar" --screenshot initial_page.png
模型权重在 HuggingFace 上:allenai/MolmoWeb-4B 和 allenai/MolmoWeb-8B。训练数据和评测代码也一并公开了。
MolmoWeb 不是什么完美的产品。中文支持差,长任务不够稳,4B 模型的推理能力也有上限。但模型权重、训练数据、评测工具全部公开,开发者可以拆开来研究和改进。大厂的 Web Agent 都是黑盒卖 API,MolmoWeb 给了你一个能动手改的底座。
用不用取决于你的场景。不过代码和数据都放出来了,下载下来玩一下不亏。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)