1. 核心问题与场景认知 (Core Problem & Context)

纯前端自主智能体 (In-Browser Autonomous Agent) 运行于终端用户的浏览器上下文中。与拥有全权限宿主操作系统或后端 Node.js/Python 容器的服务器端智能体不同,浏览器智能体受到浏览器的同源安全策略 (Same-Origin Policy, SOP) 与跨域资源共享机制 (Cross-Origin Resource Sharing, CORS) 的严格约束。

当智能体在无明确先验知识的情况下执行外部数据抓取(例如“获取 GitHub Trending 榜单”)时,常面临以下认知与执行障碍:

  1. 直接 Fetch 外部网页引发跨域拦截:浏览器发起直接请求时,若第三方站点未开放 Access-Control-Allow-Origin: *,请求将在底层网络协议栈被阻断,向模型抛出 TypeError: Failed to fetch。模型往往误以为是连接故障,进而产生多轮无谓盲试。
  2. 忽视开放 CORS 的结构化 API:许多大型服务(如 GitHub REST API https://api.github.com/...)天生开放 CORS 访问。模型常常执着于解析复杂难维护的 HTML 页面,而忽略直接通过公共 REST API 读取干净、高精度的 JSON 数据。
  3. 执行环境模式 (Runner Mode) 漂移与状态脱节:前端智能体通常支持多档执行沙箱(如纯计算无阻塞的 Web Worker 隔离模式,与具备 DOM、Window 及宿主命名空间操作权限的 Page / Develop 模式)。若用户在界面设置中动态切换执行档位,模型如果无法感知这一变化,便无法及时调整其代码生成策略。

2. 外部数据请求的三层策略矩阵 (Three-Tier External Data Strategy)

为了彻底解决端侧智能体的数据获取痛点,建立了明确的三层数据抓取准则,并将其固化至系统提示词 (CORE_SYSTEM_PROMPT)、动态工作区提示词 (buildDeveloperPrompt) 以及工具定义 (describeRunJs) 中:

flowchart TD
    Req[智能体接收到外部数据请求] --> Check{目标数据类型}
    
    Check -- 开放 CORS 的公共 REST API --> T1[第一层: 优先直接 Fetch]
    T1 --> R1["run_js: fetch('https://api.github.com/...')<br/>直接获取结构化 JSON,性能最高且无跨域限制"]
    
    Check -- 任意非 CORS 外部 HTML 页面 --> T2[第二层: 内置网关反向代理]
    T2 --> R2["run_js: fetch('/v1/proxy?url=' + encodeURIComponent(targetUrl))<br/>通过后端 Go 网关中转,突破 SOP 限制抓取完整 HTML"]
    
    Check -- 需要深度交互/可视化渲染 --> T3[第三层: 工作区视口与动作自动化]
    T3 --> R3["open_in_workspace(url) + browser_use<br/>在中间工作区 Tab 加载页面,执行 click / scroll / type 感知"]

详细规范对照表

策略层级适用场景代表工具 / 语法优势与限制
层级 1: 公共开放 API (Direct API Fetch)结构化公共查询(如 GitHub 热门仓库、维基百科、公开微服务)run_js: fetch('https://api.github.com/search/repositories?q=...')优:零中转延迟、原生 CORS 友好、直接获得结构化 JSON;<br/>劣:受目标 API Rate Limit 限制(如 GitHub 未认证每小时 60 次)。
层级 2: 内置网关反向代理 (Gateway Proxy)抓取非 API 外部 HTML 网页(如 github.com/trending、普通新闻网页)run_js: fetch('/v1/proxy?url=' + encodeURIComponent(url))优:彻底绕过浏览器 CORS,后端 Go 网关负责绕过同源策略;<br/>劣:需通过本地或私有网关转发。
层级 3: 工作区视觉感知 (Workspace & Browser Use)需用户可视化查看网页、复杂登录、DOM 点击与滚动翻页open_in_workspace + browser_use (get_backbone, click 等)优:提供拟人化真实页面操作体验,支持视觉感知;<br/>劣:依赖 iframe 渲染,存在多轮工具调用耗时。

3. 动态执行档位 (Runner Mode) 变更感知架构

3.1 问题定义

用户可在应用设置面板中将 run_js 执行环境在以下两档之间切换:

  • isolated(Web Worker 模式):运行在独立的 Worker 线程,安全、密集计算不阻塞 UI、死循环超时强杀,但无法访问 DOM (document)、localStorage 或 window。
  • page(主线程 Develop 模式):直接运行在页面主线程,具备完整 DOM、CSS 操作能力,并挂载宿主命名空间 window.__inpage__,但死循环会冻住页面。

若智能体正在会话进行中,用户突然开启了 Develop 模式要求“把页面按钮背景变蓝”,若不主动将此环境变更通知模型,模型往往会因前序系统设定的认知惰性而认为自己无法触及 DOM。

3.2 链路实现机制

  1. 工作区动态提示词 (buildDeveloperPrompt):
    在每轮调用上游 LLM 时动态组装 developerPrompt,明确注入当前选择的 runnerMode 及其权限边界:

    const runnerMode = getRunnerMode();
    developerText += `\n【当前 JavaScript (run_js) 执行配置与网络准则】:\n` +
      `- 用户选定档位: ${runnerMode === 'page' ? '页面主线程模式 (Develop 模式 / page)' : 'Web Worker 隔离沙箱模式 (isolated)'}\n` +
      (runnerMode === 'page'
        ? `  * 权限特性: 直接在宿主页面主线程执行,可自由访问 document、window、localStorage 及 window.__inpage__。注意死循环会阻塞 UI。\n`
        : `  * 权限特性: 在独立的 Web Worker 隔离线程中执行,安全无阻塞(超时强杀);不可访问 DOM (document) 或 localStorage。\n`);
  2. 状态快照比对与增量消息注入 (checkAndInjectRunnerModeChange):
    在 AgentRuntime 内维护会话生命周期内的 lastNotifiedRunnerMode 字段:

    • 启动新会话或载入历史会话时,重置 lastNotifiedRunnerMode = getRunnerMode()。
    • 当用户发送或入队新消息时,比对 currentMode !== this.lastNotifiedRunnerMode。
    • 若检测到用户改动了设置,则构造一段规范的 <context_badge> XML 块,注入至新发给模型的消息正文中:

      const badgeContent = `  <context_badge type="runner-mode" label="⚙️ 执行环境: ${currentMode === 'page' ? '主线程(Develop)' : 'Worker沙箱'}" preview="JavaScript 执行环境切换为 ${currentMode}">\n【系统提示:运行环境变更】\n用户已在设置中将 JavaScript (run_js) 执行环境由「${prevModeLabel}」切换为「${modeLabel}」。\n${detail}\n  </context_badge>`;
  3. UI 胶囊徽章差量渲染与文本分离:
    在 chatView.ts 的 renderUserMessageHtml 中,通过 matchAll(/<user_contexts>([\s\S]*?)<\/user_contexts>/g) 统一捕获所有上下文徽章:

    • 将徽章渲染为轻量胶囊:<span class="user-file-chip user-context-chip runner-mode">,配备齿轮图标与悬停详情 Tooltip。
    • 从原始消息正文中安全剥离 XML 标记,确保用户输入框的普通提问文本保持干净整洁。

4. 关键验证结果 (Audit & Verification Benchmark)

基于 Playwright 自动化审计测试 (app/tests/verify-runner-mode-and-github-api.mjs):

  1. 提示词与工具定义对齐:

    • 动态 developerPrompt 与 describeRunJs 均能根据切换的当前档位精确输出对应环境特征与网络请求三层准则。
  2. 环境切换追踪与徽章注入:

    • 初始发送无多余徽章 (hasBadge = false)。
    • 切换为 page 模式后发送的下一条消息精确注入 主线程(Develop) 徽章,UI 解析正常且原文字符串未受污染。
    • 未改动设置继续发言时不触发重复通知。
    • 切回 isolated 模式后,再次精准触发 Worker沙箱 变更通知。
  3. GitHub Trending 检索收敛率:

    • 优化前:模型在无外部指引下反复尝试 iframe 渲染与裸 fetch,经历 19 轮工具试错才艰难摸索到 API 路径。
    • 优化后:模型在第 1 轮工具调用中即直接使用 run_js 请求 GitHub 官方 Search API,仅耗时 1 轮(1 Turn)便产出清晰的 Markdown 榜单报表,决策效率提升逾 90%。

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps