发布于 2026-01-06 0 阅读
0

OpenAI launched Atlas and I killed it with a Chrome extension DEV's Worldwide Show and Tell Challenge Presented by Mux: Pitch Your Projects!

OpenAI 发布了 Atlas,但我用一个 Chrome 扩展程序把它搞砸了。

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

OpenAI 近期推出了 ChatGPT Atlas,它是 Chromium 的一个分支,具备 Agentic 功能。它的用户界面简洁,使用 SwiftUI、AppKit 和 Metal 重新构建。但抛开这些,它的功能与 ChatGPT 网站上的功能完全相同。

在浏览器中实现代理功能真的那么难吗?真的需要为此换个浏览器吗?其实不然,Chrome 扩展程序的功能远不止解决你的问题。我花了整个周末开发了一个,下面就教你如何制作。

以下是演示:

项目代码如下:https://github.com/ComposioHQ/open-chatgpt-atlas


为什么 Chrome 扩展程序非常适合这种情况

在深入探讨构建过程之前,让我先解释一下为什么 Chrome 扩展程序是正确的选择。我首先要回答的问题是:Chrome 扩展程序能否实现 AI 浏览器所能实现的功能?

答案是肯定的,原因如下:

1. 扩展程序可以访问所有重要内容:

  • 他们可以截取当前标签页的屏幕截图。
  • 他们可以将 JavaScript 代码注入到任何页面中。
  • 他们可以监听页面导航事件
  • 他们可以创建用户界面(侧边栏、弹出窗口、上下文菜单)
  • 它们以更高的权限运行,网页没有

2. 它们更容易分发:

  • 无需安装,只需添加到 Chrome 浏览器即可。
  • 更新会自动进行。
  • 适用于任何运行 Chrome 的操作系统
  • 用户无需放弃现有的浏览器设置。

3. 建造费用更低:

  • 无需维护 Chromium 分叉
  • 无需处理浏览器级别的功能(标签页、书签、更新)
  • 完全专注于代理能力

用户界面很简单。你只需要在浏览器中添加一个侧边栏,让AI代理可以执行操作;对于代理无法或不愿通过浏览器自动化完成的任何操作,你可以使用MCP(模型上下文协议)将其路由到外部工具。


建筑学

第一步是选择LLM(机器学习模型)。有三家供应商提供顶级的模型:OpenAI、Anthropic和Google。

OpenAI 和 Anthropologie 的 API 都是收费的,没有免费版本。这意味着很多人如果不付费,就无法访​​问或基于它们进行开发。我希望其他开发者可以 fork 这个项目,进行实验,而不用担心费用问题。

另一方面,谷歌为 Gemini 模型提供了一个慷慨的免费套餐,大多数用户都可以访问并在此基础上进行开发。免费套餐为 Gemini 2.5 专业版提供每分钟 150 次请求,除非您将其用于商业用途,否则这远远超过您的实际需求。Gemini 2.5 的计算机使用功能也比 Claude 的 Sonnet 4.5 计算机使用功能更便宜、速度更快。

设置 Chrome 扩展程序其实非常简单。核心文件manifest.json定义了扩展程序的功能和所需的权限。我们需要的是一个位于侧边栏并能对打开的浏览器执行操作的 Chrome 扩展程序。这意味着我们需要:

  • 声明manifest.json权限和入口点
  • 一个background.ts作为服务工作线程运行的文件,监听来自侧边栏的消息
  • 一种content.ts被注入到网页中并能提取页面内容和执行操作的程序
  • UI 文件:sidepanel.tsx(React)、settings.tsx及其对应的 HTML/CSS

考虑到以上要求,文件目录结构如下:

atlas-extension/
├── Core Extension Files
│   ├── manifest.json             // Chrome extension config
│   ├── background.ts             // Message router & coordinator
│   ├── content.ts                // Injected into pages, executes actions
│   ├── sidepanel.tsx             // Main chat interface (React)
│   ├── types.ts                  // TypeScript interfaces
│   ├── tools.ts                  // Composio tool definitions
│   ├── settings.tsx              // API key configuration
│   ├── settings.html
│   └── sidepanel.html
├── Config Files
│   ├── package.json
│   ├── vite.config.ts            // Build tool (bundles TS → JS)
│   ├── tsconfig.json
│   └── tsconfig.node.json
├── Styling
│   ├── sidepanel.css
│   └── settings.css
└── Assets
    └── icons/
        └── icon.png

Enter fullscreen mode Exit fullscreen mode

使其正常运行的权限

以下是我们需要从 Chrome 获得的权限,以使浏览代理正常工作:

"permissions": [
  "sidePanel",      // Create sidebar UI
  "storage",        // Save API keys, settings to chrome.storage.local
  "tabs",           // ⭐ CRUser types command in Sidepanel
  "history",        // Read browser history (for context)
  "bookmarks",      // Read bookmarks (for context)
  "webNavigation",  // Track when pages load/unload
  "scripting",      // Inject content scripts dynamically
  "contextMenus"    // Add right-click menu items
],

Enter fullscreen mode Exit fullscreen mode

最重要的功能是屏幕tabs截图。它能让你截取当前页面的屏幕截图,这对电脑使用至关重要。如果没有屏幕截图,人工智能就像盲人一样——它不知道页面实际是什么样子,因此无法做出关于点击位置或输入内容的智能决策。

权限scripting至关重要,因为它允许您content.ts动态地向任何网页注入代码。这就是您在页面上执行操作(例如点击按钮、填写表单、滚动页面等)的方式。


系统架构:消息如何流动

以下是各个部分之间的交互方式:

background.ts 文件就像中枢神经系统,它始终运行,协调所有流程。当你从侧边栏发送消息时,这个工作进程会将消息路由到正确的流程。

图1


计算机使用:浏览器自动化循环

步骤 1:代理使用 捕获当前页面状态的屏幕截图chrome.tabs.captureVisibleTab()。此屏幕截图是代理的“眼睛”——它看到您所看到的内容。

步骤 2:屏幕截图将连同您的自然语言意图(“点击登录按钮”)和页面的 DOM 结构(用于提供更多上下文)一起发送给 Gemini。

步骤 3: Gemini 分析屏幕截图,通过视觉识别登录按钮,并返回一个函数调用:

{
  "action": "click",
  "coordinates": {"x": 450, "y": 320},
  "reasoning": "Found login button at top-right of page"
}

Enter fullscreen mode Exit fullscreen mode

步骤 4: background.ts接收此操作并将其转发到content.ts当前网页上运行。

步骤 5: content.ts执行这些坐标处的点击操作,显示蓝色视觉指示器来显示发生了什么,并报告成功或失败。

步骤 6:循环重复进行,每次都截取新页面状态的屏幕截图。如果点击操作打开了一个模态框,则下一次迭代可以看到该模态框并与之交互。如果页面正在加载,则循环等待并进行相应调整。

每个任务最多重复此过程 30 次。每次迭代都会根据观察到的情况进行调整。它并非运行预设脚本,而是真正根据页面的当前状态做出反应。

content.ts 如何执行操作

background.ts收到EXECUTE_ACTION来自 Gemini 的消息(例如{type: 'EXECUTE_ACTION', action: 'click', coordinates: {x: 100, y: 200}}),它会将此消息转发给content.ts在当前网页上运行的程序。

内容脚本的executePageAction()功能可以处理 12 种不同的浏览器操作。以下是其中比较重要的几种:

1. 点击事件:用于document.elementFromPoint(x, y)查找指定坐标处的元素,然后触发点击事件。如果提供的是 CSS 选择器,则直接查询并点击该元素。

case 'click':
  const element = document.elementFromPoint(x, y);
  if (element) {
    element.click();
    return { success: true, element: element.tagName };
  }
  break;

Enter fullscreen mode Exit fullscreen mode

2. Fill:找到输入框/文本区域元素,使其获得焦点(这将触发任何 React 状态更新),然后keyboard_type()逐个字符地输入文本。这对于监听输入事件而不是仅仅检查输入框的 React 应用来说非常重要.value

case 'fill':
  const input = document.elementFromPoint(x, y);
  if (input && (input.tagName === 'INPUT' || input.tagName === 'TEXTAREA')) {
    input.focus();
    await keyboard_type(input, text);
    return { success: true };
  }
  break;

Enter fullscreen mode Exit fullscreen mode

为什么要逐个字符地修改?因为如果你只是简单地设置值.value = "text",React 并不知道值已经改变了。你必须为每个字符都分发键盘事件,这样 React 的合成事件系统才能检测到变化。这真是个令人头疼的问题,调试起来特别费时间。

3. 滚动:scrollTop通过操作或scrollLeft使用来向上/向下/向上/向下滚动页面(或特定元素).scrollIntoView()

4. 键盘输入:dispatchEvent(new KeyboardEvent('keydown'))使用 ` \n` 和 `\s`逐个字符输入文本dispatchEvent(new KeyboardEvent('keyup')),模拟真实打字。这实际上比设置 `\n` 更快,.value因为它不会导致 React 在每个字符输入时都重新渲染整个组件树。

5. 按键操作:通过触发键盘事件来按下单个按键(例如 Enter、Tab、Esc 等)。可用于提交表单或在界面间导航。

6. 组合键:同时按下多个键(例如 Ctrl+A、Cmd+C 等)以实现复杂的键盘快捷键。例如,您可以使用组合键让代理复制/粘贴或选择所有文本。

7. 拖放:mousedown通过从源坐标到目标坐标分发 `<DragOn> `、 `<DragOn> mousemove` 和 ` <DragOn>` 事件来模拟拖放操作mouseup。可用于拖动滑块或重新排序列表。

8. 悬停:将鼠标光标移动到指定坐标并触发mouseover事件mousemove。这对于触发仅在鼠标悬停时显示的下拉菜单或工具提示非常有用。每个操作都会将一个结果对象(例如,{success: true, element: 'BUTTON'})返回background.ts到侧边栏,以便 Gemini 可以查看发生了什么并决定下一步操作。内容脚本还会创建一个视觉指示器——在操作位置显示一个蓝色轮廓和闪烁的圆圈——该指示器会在 600 毫秒后消失。这可以让你实时了解代理正在执行的操作,这对于建立信任至关重要。如果没有这种视觉反馈,代理就会像一个黑盒子一样。

流程概要:

侧边栏调用 streamWithGeminiComputerUse()

→ Background.ts 捕获屏幕截图

→ Gemini API 接收屏幕截图 + DOM

→ Gemini 返回函数调用

→ Background.ts 转发到 content.ts

→ content.ts 执行操作

→ 重复最多 30 次

工具路由:外部 API 集成

使用电脑进行浏览器自动化操作非常方便,但如果你需要发送 Slack 消息呢?或者创建 GitHub 问题呢?或者搜索你的 Gmail 邮件呢?

这时,工具路由就派上用场了。它无需循环执行屏幕截图和浏览器操作,而是通过 Composio 的 500 多个集成工具,将工作直接交给专业的外部服务。

关键区别在于:计算机的使用是迭代式和可视化的(截图→分析→操作→重复),而工具路由器只需调用一次外部服务的 API。当您需要“发送 Slack 消息”时,工具路由器会连接到 Slack API,发送一个请求,任务就会在 Slack 服务器上完成。

工具路由器处理三个关键功能:

1. 发现:搜索所有可用工具,查找符合您任务要求的工具。返回相关的工具包及其描述、架构和连接状态。例如,如果您说“发送电子邮件”,它会搜索并找到相应的工具包GMAIL_SEND_MESSAGEOUTLOOK_SEND_EMAIL并返回它们及其参数,以便 Gemini 知道要调用哪个工具。

2. 身份验证:检查您是否已连接到所需的工具包。如果没有连接,它会创建一个身份验证配置,并使用 Composio 的身份验证链接返回一个连接 URL。您可以通过此链接完成身份验证,您的凭据将被安全存储。

3. 执行:将已认证的工具加载到上下文中并执行它们。支持跨多个工具并行执行,以提高效率。例如,如果您说“查找 Bob 发送的所有电子邮件并创建一个摘要文档”,它可以:- 并行搜索 Gmail - 处理结果 - 调用 Google Docs API 创建摘要 - 所有操作都在一个流程中完成

这种双管齐下的方法(计算机使用 + 工具路由)的妙处在于可以灵活组合。你可以先用计算机导航到某个页面并提取信息,然后使用工具路由将这些信息通过 Slack 发送出去。代理会根据任务选择使用哪种方法。

侧边栏:您实际使用的地方

sidepanel.tsx是你与代理交互的地方。它是一个 React 组件,会在 Chrome 的侧边栏(从浏览器右侧滑出的面板)中渲染。

它的功能如下:

1. 聊天界面:您可以输入自然语言命令(“点击登录按钮”、“用我的详细信息填写此表单”、“将此页面的摘要发送到 Slack”)。

2. 实时对话历史记录:显示您与客服人员之间的来回对话,包括客服人员采取的操作及其原因。

3. 模式切换器:在两个系统之间切换:

  • 计算机用途(Gemini):用于直接浏览器自动化

  • 工具路由(Composio):用于对 Gmail、Slack、GitHub 等外部 API 的调用。

4. 视觉反馈:显示操作执行情况,显示代理正在分析的屏幕截图(如果需要),并清晰地报告错误。

界面设计得非常简洁。既然所有工作都由智能代理完成,就不需要复杂的界面:只需要一个文本输入框和一个对话记录即可。


AI编码工具成本

我先买了Claude Sonnet 4.5的Cursor版本。我设定了50美元的预算,想着至少够用一个星期。结果三天就用完了。

Sonnet 的问题不在于它的代码写得不好——它的代码写得非常出色。问题在于它太消耗令牌了。以下是令牌的去向:

1. 冗余的文档文件: Sonnet 喜欢创建TECHNICAL_IMPLEMENTATION.md`<script>`、 `<script>` ARCHITECTURE.mdCHANGELOG.md`<script>` 和其他 Markdown 文件,这些文件除了可能给 Claude 提供一些关于其所做更改的背景信息之外,几乎没有任何实际用途。当你试图快速完成项目时,这会非常低效。

2. 冗长的解释:每次代码更改都附带三段文字的更改原因解释。这有利于理解,但严重影响代码效率。

3. 全文件重写: Sonnet 通常会重写整个文件,而不是进行局部修改。例如,如果您有一个 500 行的文件,需要修改其中一个函数,Sonnet 会重新生成所有 500 行。这意味着会生成 500 个输出标记,而不是 20 个。

以下是我在 Sonnet 4.5 中使用光标的情况:

光标仪表板

头三天,我的50美元预算就几乎花光了。我切换到作曲家模式(虽然速度慢,但更注重思考)来节省开支,但即使这样也无法持续。

然后 Anthropic 推出了 Haiku 4.5,它的性能与 Sonnet 4 相同。我对此表示怀疑——通常“性能相同”意味着“在特定任务中达到 80% 的性能水平”——但我当时很绝望。

项目进行到一半时,我换用了 Haiku 4.5 版本。剩下的工作我总共花了 30 美元。

区别在于:

图3

主要观察结果:

俳句 4.5:

  • 更集中的更改,每次编辑所需的标记更少
  • 很少创建不必要的文档文件
  • 进行针对性修改,而不是重写整个文件
  • 建议的采纳率实际上更高(因为建议更精准)。

十四行诗 4.5:

  • 更擅长高层架构决策
  • 更详细的解释(有利于学习,但会增加预算)
  • 更有可能重写所有内容
  • 建议采纳率较低(因为每次编辑建议的更改更多)

结论:对于扩展开发——或者任何你大致知道需要构建什么的项目——Haiku 4.5 的性能达到原版的 95%,而成本仅为原版的 30%。

Sonnet 比 Haiku 更胜一筹的 5% 场景是什么呢?是最初的架构决策、构建从未构建过的系统以及调试特殊问题。但对于“实现这个功能”或“修复这个 bug”这类任务,Haiku 就绰绰有余了。


克劳德错在哪里(免得你像我一样浪费时间)

让我来帮你省去一些麻烦,我列出了 Claude Code 完全无法胜任的地方。这些并非 Claude 本身的 bug,而是它对 Chrome 扩展程序架构和 Gemini API 理解上的不足。

问题 1:文本输入无法正常工作

症状:该代理可以点击按钮、滚动页面和切换屏幕,但无法在输入框中输入文本。每次尝试输入文本,都没有任何反应。

克劳德的诊断(前 10 次尝试): “坐标肯定错了。让我换个方法计算一下。”

克劳德的诊断(接下来的 10 次尝试): “也许输入没有聚焦。让我先添加一个聚焦事件。”

克劳德的诊断(接下来的 10 次尝试): “时机可能不对。让我增加按键之间的延迟。”

实际问题: Gemini 要求用户在执行某些敏感任务(例如输入文本)时必须获得授权。默认情况下,它会完全阻止文本输入操作,除非用户明确指示允许。

// In your Gemini API config
const response = await fetch('<https://generativelanguage.googleapis.com/v1beta/>...', {
  method: 'POST',
  body: JSON.stringify({
    contents: [...],
    tools: [...],
    safety_settings: [
      {
        category: "HARM_CATEGORY_DANGEROUS_CONTENT",
        threshold: "BLOCK_NONE"  // ← This is what you need
      }
    ]
  })
});

Enter fullscreen mode Exit fullscreen mode

您还可以手动降低 Gemini 默认启用的防护措施。有一个safety_settings参数可以让您控制模型对“危险”行为的保守程度。

浪费时间:多次会话共计超过 2 小时

关键是:谷歌的Gemini电脑使用指南里明明有提到这一点,但克劳德却从未想过要去查阅。他一直坚信这是坐标或时间上的问题。

教训:在使用计算机用户模型时,务必在花费数小时调试之前,先查阅其相关文档,了解权限和安全设置。模型可能并非无法执行某些操作,而是拒绝执行。

第二期:截图地狱

症状:计算机使用循环启动,发送第一个屏幕截图,Gemini 会做出响应,然后扩展程序在尝试捕获第二个屏幕截图时崩溃。

克劳德的诊断(尝试 1-5): “截图可能太大了。我试试压缩一下。”

克劳德的诊断(尝试 6-10): “可能是格式错了。我试试把 PNG 转换成 JPG。”

克劳德的诊断(第 11-15 次尝试): “让我试试 JPG → PNG 格式。”

Claude 的诊断(尝试 16-30):上述情况的变体,尝试不同的质量设置、不同的压缩库、不同的编码方法。

实际问题: Chrome 扩展程序无法从侧边栏上下文中截取屏幕截图。侧边栏运行在独立的上下文中,无法访问主窗口的视觉内容。

错误的方法(克劳德一直尝试的方法):

// This doesn't work from sidepanel context
const screenshot = await chrome.tabs.captureVisibleTab();
// Error: No tab found

Enter fullscreen mode Exit fullscreen mode

正确的方法:

// You need to query for the main window's active tab first
const tabs = await chrome.tabs.query({active: true, currentWindow: true});
if (tabs[0]) {
  const screenshot = await chrome.tabs.captureVisibleTab(tabs[0].windowId, {
    format: 'png'
  });
}

Enter fullscreen mode Exit fullscreen mode

区别虽细微,却至关重要。侧边栏不像内容脚本那样有“当前窗口”的概念。您必须显式查询活动标签页并指定其窗口 ID。

浪费时间: 1小时以上,尝试了30多种不同的方法

恍然大悟:我终于在 2019 年 GitHub 的一个 issue 里找到了答案,有人遇到了完全相同的问题。Chrome 的官方文档里并没有提到这一点。

教训: Claude 无法识别 Chrome 扩展程序的上下文边界。如果它无法捕获应该正常工作的内容,请检查您是否处于正确的上下文中(背景、内容、侧边栏或弹出窗口)。

经过长时间的调试,我尝试了屏幕截图 API 的各种可能变体,但始终无法理解根本问题所在,而这个特定的修复解决了我的困扰。

问题 3:权限清单混淆

症状:某些 Chrome API 在开发环境中可以正常工作,但在打包扩展程序后在生产环境中会失败。

克劳德的诊断: “清单权限肯定不完整。让我添加更多权限。”

Claude 所做的:添加了所有听起来稍微相关的权限activeTab,,,,等等tabs<all_urls>webRequest

实际问题: Chrome 对 MV3(Manifest V3)扩展程序和 MV2 扩展程序的权限要求不同。Claude 一直建议使用 MV2 模式,因为 Stack Overflow 上的大多数答案都来自 MV2 时代。

解决方法:了解 MV3 的服务工作线程和 MV2 的后台页面之间的区别,并相应地调整清单文件。

浪费时间: 30分钟

教训:务必检查你使用的清单版本,并确保 Claude 的建议与该版本匹配。API 类似,但权限模型不同。


自己动手试试

我已经将代码开源,地址是github.com/composiohq/open-chatgpt-atlas。以下是入门指南:

设置(5分钟):

  1. 克隆仓库:git clone ...

  2. 安装依赖项:npm install

  3. 构建扩展程序:npm run build

  4. 在 Chrome 中加载:前往 [此处] chrome://extensions,启用开发者模式,点击“加载解压后的文件”,选择dist文件夹

  5. 获取 Gemini API 密钥:https://ai.google.dev/

  6. 打开扩展程序,转到“设置”,粘贴您的 API 密钥

第一个任务:打开任意网页,点击扩展程序图标,然后尝试:“点击搜索按钮并输入‘AI浏览器代理’”。

注意观察每次操作时蓝色指示灯的闪烁情况。如果操作失败,请检查控制台中的错误信息(右键单击扩展程序 → 检查)。

感谢阅读。这是代码仓库;欢迎点赞。

文章来源:https://dev.to/composiodev/openai-launched-atlas-and-i-killed-it-with-a-chrome-extension-1cfb