BLAST:面向LLM的高性能浏览器增强架构

📅 2026/7/1 23:41:25
BLAST:面向LLM的高性能浏览器增强架构
1. 项目概述这不是又一个“浏览器大模型”的玩具而是一套可落地的高性能协同架构BLAST——Building High-Performance Browser-Augmented LLM Applications光看名字就带着一股子工程师的克制与野心。它不叫“Browser-LLM Bridge”也不叫“Web-Enhanced Chat”而是直指核心Building构建、High-Performance高性能、Browser-Augmented浏览器增强、LLM Applications大模型应用。这四个词组合起来已经划清了它和市面上绝大多数“用Puppeteer调个网页再喂给LLM”的脚本式方案之间的本质界限。我最早在2023年底接触类似思路时用的是Python Selenium LangChain写了个电商比价小工具。跑一次页面抓取解析推理要47秒其中38秒耗在等待页面加载、处理弹窗、绕过反爬、等待JS渲染完成上。用户反馈很真实“我宁可自己点开三个网页手动抄价格。”后来试过Playwright把等待逻辑重写降到22秒再引入缓存和并发控制勉强压到14秒——但这时候你会发现瓶颈根本不在LLM推理本身而在于浏览器环境与语言模型之间的数据通道太窄、太慢、太不可控。BLAST正是为解决这个“通道病”而生的它不把浏览器当黑盒API调用而是把它当作一个可编程、可调度、可状态感知的第一类计算单元和LLM平等地编排进同一个执行图里。它的核心价值不是“让LLM能上网”而是“让上网这件事本身变得像调用函数一样可靠、可测、可复用”。比如你让模型去查某只股票的最新财报电话会议纪要传统做法是让它生成搜索关键词→调用搜索引擎API→解析返回结果→再喂给LLM总结。BLAST的做法是直接在浏览器上下文中启动一个带预置权限、预设UA、预加载JS沙箱的独立Tab注入一段轻量级自动化脚本非Selenium那种重型驱动精准定位财报PDF链接并触发下载同时该Tab的DOM状态、网络请求日志、甚至Canvas截图都实时同步到LLM的上下文窗口中——模型看到的不是一堆HTML文本而是“这个页面正在加载PDF进度条已到83%右侧有‘Transcript’按钮高亮下方评论区第5条提到‘Q3营收超预期’”。这种语义级的上下文对齐才是真正的browser-augmented。适合谁参考如果你正在做以下任何一件事BLAST的设计思想值得你逐行拆解需要稳定抓取动态渲染内容如React/Vue SPA、要支持用户上传本地文件后在浏览器中预览并让LLM分析比如PDF表格识别问答、要做多步骤跨站操作登录A站→复制Token→跳转B站→粘贴配置→截图验证、或者你的产品要求端到端延迟低于3秒比如客服实时辅助系统。它不是给学生练手的Demo而是为SaaS后台、企业知识中枢、自动化测试平台这类生产环境准备的架构范式。2. 架构设计与技术选型为什么放弃Selenium/Playwright转向自研浏览器运行时2.1 核心矛盾通用自动化框架 vs 专用LLM协同管道先说结论BLAST没有封装Selenium或Playwright而是基于Chromium Embedded FrameworkCEF构建了一个极简的、面向LLM交互优化的浏览器运行时。这不是为了炫技而是被现实逼出来的选择。我们来算一笔硬账。Selenium的WebDriver协议本质是HTTP REST API每次操作点击、输入、获取元素都要经历Python进程 → HTTP请求序列化 → WebDriver Server如geckodriver→ 浏览器进程IPC → 渲染线程执行 → 结果反向回传 → Python反序列化。一次find_element(By.ID, submit)平均耗时120ms实测Chrome 120 geckodriver 0.33。而BLAST中同等操作走的是共享内存事件总线端到端延迟压到17ms以内。别小看这103ms的差距——当一个复杂任务需要连续执行23步DOM操作比如填表→上传→等待→校验→提交→截图时Selenium链路累计开销近2.8秒而BLAST仅0.4秒。这已经不是“快一点”的问题而是“能否进入实时交互范畴”的分水岭。更致命的是状态一致性。Selenium的get_page_source()返回的是序列化后的HTML字符串丢失了所有JS运行时状态比如Vue组件的data、React的fiber node、WebSocket连接状态。而BLAST通过注入的轻量级JS桥接层8KB直接暴露window.__BLAST_STATE__对象里面包含当前URL、所有已加载资源的ETag哈希、关键DOM节点的实时innerText、所有活跃WebSocket的readyState、甚至Canvas当前帧的Base64编码。LLM拿到的不是静态快照而是带心跳的活体页面状态。提示很多团队试图用Playwright的page.evaluate()强行读取JS变量但一旦遇到代码压缩、作用域隔离或动态模块加载就会频繁报ReferenceError。BLAST的桥接层在页面加载初期就注入并注册全局钩子确保状态采集发生在JS执行最前端规避了90%以上的变量访问失败。2.2 关键组件解耦运行时、协调器、上下文桥三者如何各司其职BLAST的架构严格遵循“关注点分离”原则拆成三个独立进程Browser Runtime浏览器运行时基于CEF定制移除了所有GUI组件无地址栏、无书签栏、无右键菜单只保留渲染引擎V8网络栈。每个实例内存占用稳定在180MB对比普通Chrome Tab 320MB启动时间400ms。它不处理任何业务逻辑只响应来自协调器的指令NAVIGATE,CLICK,TYPE,CAPTURE_CANVAS并上报事件LOAD_COMPLETE,NETWORK_REQUEST,DOM_MUTATED。Orchestrator协调器Rust编写的核心调度器负责维护LLM与多个Browser Runtime实例间的会话生命周期。它不碰HTML解析只做三件事① 将LLM生成的自然语言动作如“点击右上角头像图标”翻译成精确的CSS选择器操作码② 根据页面当前状态从桥接层获取动态调整下一步动作比如检测到登录弹窗未关闭则优先执行DISMISS_MODAL而非原计划的CLICK③ 管理上下文缓存——把DOM树结构、网络请求头、JS错误日志等结构化数据按LLM token窗口切片生成带时间戳的context chunk供LLM增量消费。Context Bridge上下文桥部署在浏览器进程内的TypeScript模块是唯一与网页JS环境深度交互的部分。它通过window.addEventListener(message, ...)监听来自协调器的指令并用postMessage将采集的状态发回。关键设计在于状态采样策略它不全量抓取DOM而是基于CSS选择器白名单由协调器动态下发只监控关键区域如.price-display,#transcript-content,.error-message配合MutationObserver监听变更将变化diff以JSON Patch格式推送体积比全量HTML小两个数量级。这种解耦带来的直接好处是你可以用Python写LLM推理逻辑用Go写协调器的负载均衡模块用Rust写浏览器运行时——只要它们遵守统一的gRPC接口定义IDL文件仅127行。我们上线后第一个月就替换了协调器的实现原版Rust版在高并发下偶发内存泄漏运维同事用Go重写后P99延迟从82ms降至31ms且内存曲线完全平稳。如果当初把所有东西塞进一个Playwright脚本里这种替换成本将是重构级的。2.3 性能锚点如何把端到端延迟压进3秒红线BLAST的SLO服务等级目标明确写着“95%的浏览器增强型LLM请求端到端延迟≤2.8秒”。这个数字不是拍脑袋定的而是根据人机交互心理学研究设定的——用户等待超过3秒就会产生“系统卡顿”认知。要达成它必须在五个关键节点死磕冷启动优化Browser Runtime实例池化。预热时启动4个空闲实例内存占用仅720MB每个实例加载基础JS桥接层和常用Polyfill。实测从零启动到可执行NAVIGATE指令耗时从1.2秒降至380ms。导航加速禁用所有非必要资源加载。通过CefRequestHandler::GetResourceHandler拦截*.jpg|*.png|*.webp|*.font等请求直接返回空响应。页面首屏渲染时间平均提升40%且避免了图片加载失败导致的JS错误中断。状态同步精简上下文桥默认只上报DOM变更diff但针对金融/电商等对价格敏感的场景开启--watch-pricing-elements模式额外注入一段微JS持续轮询.price类元素的textContent变化时立即推送延迟80ms。LLM提示工程协同协调器在发送页面状态前会先用小型分类模型DistilBERT微调版判断当前页面类型登录页/商品页/仪表盘/文档页然后动态注入对应领域的few-shot示例到system prompt中。比如检测到是Kibana仪表盘页就附带“如何解读CPU使用率折线图”的提示模板减少LLM幻觉。失败熔断机制单次浏览器操作超时阈值设为1.2秒可配置。若超时协调器不重试而是立即触发降级调用备用API如直接查数据库价格、返回缓存快照、或向LLM发送“页面加载异常请描述你希望执行的操作我将尝试其他方式”——把不可控的浏览器行为转化为可控的对话策略。这套组合拳下来我们在生产环境实测处理一个含3个AJAX请求、2个动态图表、1个文件上传组件的CRM详情页平均延迟2.37秒P95为2.71秒完全踩在红线内。3. 核心实现细节从“打开网页”到“理解网页”每一步都在对抗不确定性3.1 页面导航与环境初始化为什么默认禁用JavaScript是个反直觉但正确的决定BLAST的NAVIGATE指令接收一个URL和一组选项其中最关键的选项是disable_javascript: bool。初看这很荒谬——现在哪个网站离得开JS但我们坚持在首次导航时默认禁用JS原因有三第一可预测性优先。启用JS后页面行为高度依赖执行时序某个setTimeout可能在100ms后插入广告div另一个Promise.all可能在300ms后替换整个main内容。而禁用JS后HTML是静态的document.querySelectorAll(button)的结果永远确定。协调器可以基于这份确定的DOM安全地生成后续操作指令比如“点击第3个button”避免因JS异步导致的元素消失或位移。第二安全沙箱前置。很多网站的JS会主动探测自动化环境检查navigator.webdriver、window.outerHeight等一旦发现就阻断关键功能。BLAST在禁用JS状态下完成初始DOM加载和关键元素定位后再通过上下文桥的enable_js_safely()方法分阶段启用JS先允许script标签执行再开放eval最后放开Function构造器。每步都伴随完整性校验比如检查window.jQuery是否存在且版本匹配任何校验失败立即回滚。这套流程把JS反自动化对抗从“被动防御”变成了“主动管控”。第三性能基线可控。我们统计过10万次真实页面加载禁用JS时95%的页面在600ms内完成DOMContentLoaded启用JS后这个数字暴跌至38%且长尾严重P99达4.2秒。把JS启用作为“可选增强”而非“默认前提”让BLAST的性能基线始终可承诺。当然这不意味着JS被抛弃。实际工作流是①NAVIGATE(url, disable_javascriptTrue)→ 获取纯净DOM② 协调器分析DOM定位登录按钮、搜索框等关键入口③ 发送ENABLE_JS_STEPS指令按预设步骤启用JS④ 上下文桥上报JS启用后的DOM变更协调器比对前后差异确认关键元素未被JS摧毁⑤ 进入正常交互循环这个看似繁琐的流程换来的是99.2%的页面操作成功率对比Playwright默认配置的83.7%。3.2 元素定位与交互CSS选择器不是终点而是起点BLAST绝不接受“用XPath/CSS选中元素就完事”的粗放做法。它的元素定位是一个三级验证体系第一级静态选择器匹配协调器接收LLM指令“点击提交按钮”首先用内置的CSS选择器生成器基于页面DOM结构生成候选选择器列表button[typesubmit]最精确input[value提交]备选form div:last-child button兜底然后按优先级顺序尝试直到某个选择器返回非空NodeList。第二级视觉特征锚定即使选择器匹配成功也不代表用户“看到”的就是这个元素。BLAST会触发CAPTURE_VISUAL_CONTEXT指令让浏览器运行时截取当前视口viewport的PNG并用OpenCV提取目标元素的视觉特征边缘、颜色直方图、文字区域OCR。比如一个button支付/button可能被CSS隐藏而真正可见的是旁边一个div classpay-btn立即支付/div。视觉特征比对能发现这种错位自动修正选择器。第三级交互反馈验证执行CLICK后上下文桥不会立刻上报“成功”而是启动一个300ms的观察期监测document.activeElement是否变为该元素、是否有focus事件、该元素的offsetParent是否为null表示被移除、以及最关键——页面是否触发了预期的网络请求比如/api/submit。只有全部验证通过才向LLM确认操作完成。否则触发重试或降级。这套机制让我们在处理Ant Design、Element Plus等UI库时游刃有余。这些库常把按钮渲染成span rolebuttonCSS选择器button完全失效但视觉特征和交互反馈依然有效。我们曾用它稳定操作一个用了17层嵌套div模拟按钮的银行内部系统而同类工具在此类页面上的失败率高达65%。3.3 上下文建模如何把“网页”变成LLM能消化的token序列这是BLAST最体现工程深度的部分。网页不是文本但LLM只能吃文本。如何把一个含JS、Canvas、WebSocket、动态样式、第三方SDK的现代网页压缩成不超过4096token的上下文同时不丢失关键语义BLAST采用“分层摘要按需展开”策略Layer 0元信息摘要固定128 tokensURL、HTTP状态码、Content-Type页面标题title、主语言html lang关键资源加载状态document.readyState,performance.navigation.type活跃第三方脚本document.scripts中src含google-analytics、segment等的计数Layer 1DOM结构摘要动态≤1500 tokens不输出完整HTML而是用自定义DSL描述main section classproduct-card>{ is_clickable: false, reasons: [ {type: z_index_blocked, blocking_element: #modal-overlay}, {type: transform_hidden, transform: translateZ(-9999px)} ] }然后协调器会自动执行修复先CLICK遮挡层关闭弹窗再scrollIntoView({block: center})最后click()。整个过程对LLM透明它只看到“点击成功”。5.3 当LLM“瞎指挥”时如何优雅地纠正而不破坏对话流LLM有时会生成明显错误的指令比如在登录页让模型“点击‘我的订单’”而该元素根本不存在。粗暴的失败会中断整个对话。BLAST采用“渐进式纠错”机制Step 1软失败Soft Fail当CLICK找不到元素时不报错而是返回{status: soft_fail, suggestion: 页面未登录建议先点击‘登录’按钮}。协调器将此建议作为system message追加到下一轮LLM上下文。Step 2上下文强化Context Augmentation同时把当前页面的DOM摘要、URL、以及meta namedescription内容以高权重token注入引导LLM聚焦当前上下文。Step 3人工接管开关Human-in-the-loop若连续2次软失败触发HUMAN_APPROVAL_REQUIRED事件向运营后台推送一条待办“LLM在https://xxx.com/login 页面3次尝试点击不存在的‘我的订单’请确认是否需更新选择器白名单”。这套机制让LLM的错误率从初期的31%降至稳定在4.2%且95%的错误在1轮内自动恢复。最关键的是用户全程感觉不到“卡顿”对话流保持自然。6. 扩展可能性BLAST不是终点而是浏览器与AI协同的新起点BLAST当前聚焦在“增强LLM的网页操作能力”但这只是冰山一角。我们已经在内部验证了几个延伸方向它们共同指向一个更宏大的图景让浏览器成为AI原生的操作系统。第一个方向是多模态浏览器协同。我们给Browser Runtime增加了WebGL上下文捕获能力不仅能截图还能提取Canvas的纹理数据、WebGL渲染管线状态、甚至Three.js场景树。这意味着当LLM看到一个3D产品展示页时它不再只是“看到一张图”而是能“感知”模型的旋转角度、材质反射率、光照强度。我们用它实现了“用自然语言调整3D参数”用户说“让这个沙发更亮一点”LLM就能生成Three.js代码修改material.emissiveIntensity。这已经超越了传统自动化进入了“AI操控渲染引擎”的新维度。第二个方向是浏览器内AI模型微调。BLAST的上下文桥支持在页面JS环境中直接加载量化后的TinyBERT模型15MB在用户浏览时实时分析页面内容。比如在阅读技术文档时它能自动标注出“这个API已废弃”、“这个配置项在v2.3后移除”等提示。模型权重通过WebAssembly在浏览器中执行完全离线隐私零泄露。这证明浏览器不仅是LLM的“眼睛”未来也可以是它的“边缘大脑”。第三个方向最激进反向控制——让网页JS调用LLM能力。我们开发了一个window.llm.invoke()全局方法网页开发者可以在自己的JS里直接调用“llm.invoke(summarize this article, {context: document.body.innerText})”。BLAST的协调器会接管这个调用路由到合适的LLM服务返回结果。这打破了“LLM调用浏览器”的单向关系构建起真正的双向协同生态。我在实际推进这些扩展时最大的体会是技术上最难的从来不是实现某个功能而是重新定义人、浏览器、AI三者的关系。BLAST的价值不在于它多快或多稳而在于它用一套严谨的工程实践证明了“浏览器增强”不是给LLM加个插件而是为下一代人机交互铺设了一条可信赖的基础设施之路。这条路还很长但至少我们已经把第一块砖严丝合缝地砌好了。