我花了3个月,把一个终端 AI Agent 搬进了浏览器——踩坑全记录

我花了3个月,把一个终端 AI Agent 搬进了浏览器——踩坑全记录
一、为什么要把终端 AI Agent 搬进浏览器2025年初我在终端里跑通了一个基于 LangChain 的 AI Agent能自动执行代码、调用工具、处理文件。功能很强大但每次演示都要打开终端、激活虚拟环境、敲命令——同事看了直摇头「这玩意儿能不能在浏览器里点一下就跑」于是我决定花3个月时间把这个终端 AI Agent 完整地搬到浏览器里。这篇文章记录了我踩过的所有坑希望能帮你少走弯路。二、技术选型从 WebSocket 到 Web Worker第一个问题就是终端里的 Agent 是 Python 写的浏览器里跑不了 Python。怎么办方案一后端代理 WebSocket最直接的想法后端起一个 Python 进程浏览器通过 WebSocket 发送指令后端执行后把结果推回来。这个方案我用了两周踩了三个坑连接管理每个用户一个进程服务器内存直接爆炸状态同步Agent 的中间状态思考链、工具调用很难实时推给前端断连恢复浏览器刷新一下Agent 状态全丢了方案二WebAssembly Python 运行时用 Pyodide 在浏览器里直接跑 Python试了之后发现Pyodide 不支持 subprocessAgent 调不了系统命令等于废了一半。方案三前端重写 Web Worker最终方案用 TypeScript 重写 Agent 核心逻辑在 Web Worker 里运行。Worker 里跑 Agent 循环主线程只负责渲染 UI。这样既解决了进程管理问题又天然支持断连恢复——Worker 在页面关闭前一直活着。三、踩坑实录那些让我熬夜的 Bug坑1Web Worker 里的异步陷阱Agent 的核心是循环调用 LLM每次调用都是异步的。在 Worker 里写异步循环时我犯了一个经典错误// 错误写法循环里直接 await导致事件循环阻塞 while (true) { const result await callLLM(messages); messages.push(result); } // 正确写法用递归 setTimeout 让出事件循环 function agentLoop() { callLLM(messages).then(result { messages.push(result); if (!isDone) setTimeout(agentLoop, 0); }); }这个 Bug 让我排查了两天最后用 Chrome DevTools 的 Performance 面板才发现事件循环被阻塞了。坑2流式输出的渲染性能Agent 的思考过程是流式输出的每生成一个 token 就要更新一次 UI。一开始我用 React 的 setState 直接更新结果页面卡成 PPT。解决方案用requestAnimationFrame做节流每 16ms 批量更新一次 DOM。同时把长文本用contenteditable的选区操作来增量插入避免全量替换。坑3工具调用的沙箱隔离Agent 需要执行代码、读写文件但在浏览器里不能直接操作文件系统。我用了OPFSOrigin Private File System来做沙箱文件系统用iframe sandbox来执行用户代码。但 OPFS 的 API 是异步的Agent 的工具调用却是同步的至少从 Agent 的角度看。最后我封装了一个ToolBridge把异步操作包装成 PromiseAgent 通过await bridge.call(writeFile, ...)来调用。四、架构演进从单体到微前端项目做到第二个月代码量已经超过 2 万行。Agent 核心、工具系统、UI 组件、状态管理全部耦合在一起改一个地方崩一片。我做了三件事来解耦Agent 核心独立成包用agent/core管理 LLM 调用、思考循环、记忆管理工具系统插件化每个工具是一个独立的ToolPlugin通过接口注册到 AgentUI 层用微前端Agent 面板、文件浏览器、终端模拟器各自独立部署通过iframe postMessage通信五、性能优化从 5 秒到 500 毫秒搬进浏览器后最直观的问题是慢。终端里秒回的 Agent在浏览器里要等 5 秒才有反应。优化路径LLM 调用缓存相同的 prompt 组合直接走缓存减少重复请求Web Worker 预热页面加载时提前初始化 Worker用户点击「开始」时直接跑虚拟滚动Agent 的思考日志可能很长用虚拟滚动只渲染可视区域增量序列化Agent 状态用structuredClone做快照但只序列化变化的部分六、总结与建议3 个月下来我最大的感受是把终端工具搬进浏览器不是简单的「换个 UI」而是整个架构的重构。给想尝试的同学几点建议先想清楚边界哪些逻辑必须在浏览器里跑哪些可以放后端Web Worker 是你的朋友别在主线程里跑 Agent 循环做好状态持久化浏览器刷新是常态用 IndexedDB 存 Agent 状态性能监控要早做别等用户反馈卡顿才去排查最终成果是一个可以在浏览器里直接运行的 AI Agent 演示平台支持代码执行、文件操作、API 调用等 20 工具。虽然过程痛苦但看到用户在浏览器里点一下就能跑通 Agent一切都值了。