网页端嵌入 Agent 对接前端方案
本文将深入探讨「网页端嵌入AI」的核心概念与实战技巧帮助你快速掌握关键要点。让我们开始吧网页端嵌入 Agent 对接前端方案1. 引言当前前端项目正从被动展示走向主动交互AI Agent 嵌入网页端可自动化 UI 操作、优化布局并辅助编码。本文聚焦如何在前端React/Vue3中集成 AI Agent涵盖客户端工具定义、安全通信及流式输出等核心环节。读完本文你将掌握React 集成 AG-UI 组件、Vue3 对接 Agent 流式输出、前端 Agent 安全通信实现、LangChain 前端 Agent 对接的基本方法。2. 核心概念AI Agent 在前端的运行模式2.1 网页端嵌入 AI Agent 前端方案的本质网页端嵌入 AI Agent 前端方案的本质是客户端与服务器之间的协同工作模式。负责推理和决策的 LLM 运行在服务端而前端主要负责 UI 交互和本地环境操作。Agent 在客户端与服务器间协同由服务器协调工具调用前端负责浏览器端特有的操作获取 GPS 位置、访问剪贴板、操作 DOM 元素、调用浏览器 API 等。以微软 AG-UI 框架为例Agent 实例在服务端创建但工具函数可能被标记为“前端执行”当 LLM 决策需要客户端能力时服务端会向客户端下发工具调用请求由前端执行后将结果返回。这种分工既利用了服务端的计算资源、保护了 API 密钥又保留了前端对浏览器环境的控制权限。在实际工程中服务端与前端通过标准协议如 JSON-RPC交换工具调用ID和参数前端无须直接暴露 API 密钥或 LLM 配置从而保障了安全性。2.2 React 集成 Agent UI 组件——AG-UI 的使用模式微软开源的microsoft/ag-ui-react库提供了一套开箱即用的 React 组件集合用于快速在 React 应用中嵌入 AI Agent 界面。它包含AIAgent、AgentConversation、AgentToolList等组件开发者只需在组件树中引入AIAgent传入必要属性即可使页面具备 Agent 对话与工具调用能力。AG-UI 的核心设计思路是声明式组件 工具函数自动路由。开发者在项目中预先定义前端工具函数如获取用户位置、切换主题、读取浏览器存储并用[Description]属性标注。通过AIFunctionFactory.Create将这些函数包装为AITool对象创建 Agent 实例时传入工具数组框架会自动确定哪些工具需要在前端执行并在对话期间接管调用与响应。此外AG-UI 提供了内置的 Agent 状态管理thinking / waiting / error结合 React Suspense 或自定义 Loading 组件可以显著减少状态边界处理的开发成本。2.3 前端 Agent 工具函数定义方法前端 Agent 工具函数是 Agent 在客户端环境中的可调用能力单元每个工具函数对应一个具体的浏览器端操作。定义方法主要有以下步骤函数签名工具函数必须是静态方法或独立函数返回类型为string或可被 JSON 序列化的对象。返回信息将直接作为 LLM 理解的结果。元数据标注通过[Description(...)]标注函数功能、参数含义、返回格式。服务端 LLM 会根据描述决定何时调用该工具。描述应精准简练例如[Description(获取用户当前地理位置返回经纬度字符串。)]。包装为 AITool使用AIFunctionFactory.Create(GetUserLocation)将普通函数转为AITool对象框架会提取其描述、参数类型约束等元数据。注册到 Agent创建 Agent 实例时将AITool[]数组传入tools属性Agent 即可在对话中识别并调度这些工具。重要原则工具函数尽量避免产生副作用或必须前置确认对话框输出结果应在合理长度内建议不超过 2000 字符避免 token 浪费。对于会修改页面状态的操作如切换主题通常不返回复杂对象只返回固定字符串例如Theme toggled successfully.。3. 实战React 中使用 AG-UI 集成 Agent3.1 项目初始化在现有 React 项目确保 React 版本 ≥ 17.0.2中安装 AG-UI 库npminstallmicrosoft/ag-ui-react microsoft/ag-client在应用入口处引入 Provider 组件用于提供 Agent 客户端实例// index.jsx import { ChatClientProvider } from microsoft/ag-ui-react; import { ChatClient } from microsoft/ag-client; import App from ./App; // 需替换为真实服务端 endpoint该 endpoint 负责连接 LLM 并协调工具调用 const chatClient new ChatClient({ endpoint: https://your-server.com/agent }); ReactDOM.render( ChatClientProvider client{chatClient} App / /ChatClientProvider, document.getElementById(root) );3.2 定义前端工具假设我们需要 Agent 能够获取用户 GPS 位置和切换深色模式。定义两个前端工具函数// 后端 C# / .NET 示例也可以在 JS/TS 中用类似方式[Description(Get the users current location from GPS.)]staticstringGetUserLocation(){// 实际应调用浏览器 Geolocation API此处仅做示意// 前端通过 Bridge 层JSInterop从浏览器获取数据returnAmsterdam, Netherlands (52.37°N, 4.90°E);}[Description(Toggle dark/light theme in current page.)]staticstringToggleDarkMode(){// 切换主题逻辑前端执行returnDark mode toggled to true.;}// 创建前端工具数组AITool[]frontendTools{AIFunctionFactory.Create(GetUserLocation),AIFunctionFactory.Create(ToggleDarkMode)};在实践中由于工具函数必须在前端浏览器环境执行通常通过 JSInterop例如 Blazor 场景或直接在前端 JavaScript 中定义对应函数然后将函数引用传递给 AG-UI 的AIFunctionFactory。React 组件内可直接定义纯前端函数。3.3 创建 Agent 实例并挂载在服务端或前端初始化时通过已配置好的chatClient创建 Agent 实例// App.jsx import { useChatClient, AIAgent, AgentConversation } from microsoft/ag-ui-react; function App() { const chatClient useChatClient(); // 创建 Agent 实例 const agent chatClient.AsAIAgent({ name: agui-client, description: An agent that can access client-side capabilities., tools: frontendTools // 上文定义的 frontendTools }); return ( div h2AI Agent 助手/h2 {/* AG-UI 内置组件自动处理对话与工具调用 */} AIAgent agent{agent} AgentConversation / /AIAgent /div ); }AG-UI 前端工具调用实战当用户输入“我在哪里”LLM 决定调用GetUserLocation工具服务端将工具调用请求带有tool_call_id下发给前端。AG-UI 组件自动执行对应的前端函数将结果如经度纬度回传给服务端最终以文本形式展示给用户。整个流程对开发者透明仅需关注工具函数的定义和描述。4. 实战Vue3 对接 Agent 流式输出SSE 实现4.1 为什么选择 SSEAI Agent 的响应通常以流式方式生成前端逐块展示 token提升用户体验。在 Vue3 项目中对接流式输出推荐使用 SSEServer-Sent Events。原因如下SSE 是浏览器原生支持的轻量文本流协议无需像 WebSocket 那样手动管理握手、帧解析和心跳它适用于常规的单向文本流场景——Agent 服务端向客户端流式发送生成结果。对于多数前端对话场景客户端的输入可通过常规 POST 请求发送不需要全双工通信。实现复杂度与维护成本均低于 WebSocket。此外SSE 天然支持断线重连Last-Event-ID这在 Agent 长回答场景中尤为重要。4.2 前端实现Vue3 Composition API ReadableStreamtemplate div div v-formsg in messages :keymsg.id strong{{ msg.role }}:/strong {{ msg.content }} /div button clickcancelRequest v-ifgenerating中止/button /div /template script setup import { ref } from vue; const messages ref([]); const generating ref(false); let abortController null; async function sendMessage(text) { // 将用户消息加入对话 messages.value.push({ role: user, content: text, id: Date.now() }); abortController new AbortController(); generating.value true; try { const response await fetch(/api/agent/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ message: text, history: messages.value.slice(0, -1) }), signal: abortController.signal }); if (!response.ok) { throw new Error(HTTP ${response.status}); } // 使用 ReadableStream 逐块读取 SSE 数据流 const reader response.body.getReader(); const decoder new TextDecoder(); let assistantContent ; let assistantMsgId Date.now() 1; // 创建助理消息容器先展示空内容并动态追加 messages.value.push({ role: assistant, content: , id: assistantMsgId }); const msgIndex messages.value.length - 1; while (true) { const { done, value } await reader.read(); if (done) break; const chunk decoder.decode(value, { stream: true }); // SSE 数据格式 data: {token: ...} 每行 const lines chunk.split(\n); for (const line of lines) { if (line.startsWith(data:)) { try { const json JSON.parse(line.slice(5).trim()); if (json.token) { assistantContent json.token; // 利用 Vue3 响应式特性更新消息内容 messages.value[msgIndex].content assistantContent; } } catch (e) { // 忽略解析错误如非 JSON 行 } } } } } catch (err) { if (err.name ! AbortError) { console.error(SSE 数据接收错误:, err); } } finally { generating.value false; } } function cancelRequest() { if (abortController) { abortController.abort(); } } /script要点说明使用AbortController支持用户中止请求避免 Agent 生成过长内容时无法停止。逐块解码时设置{ stream: true }保证 UTF-8 字符边界正确。SSE 数据行格式取决于后端实现这里假设每行data: {token:xxx}后跟\n\n作为事件分隔。前端按行解析、拼接到ref中触发视图更新。注意当大量 token 连续推送时频繁触发 Vue 响应式更新可能产生性能问题可在回调中加入节流或批处理比如每50ms批量更新一次。4.3 后端配合FastAPI 示例fromfastapiimportFastAPI,Requestfromfastapi.responsesimportStreamingResponseimportasyncio appFastAPI()asyncdefagent_stream(message:str,history:list):模拟 Agent 流式生成实际调用 LLM 或 agent.invoke# 假设 agent 是一个可流式调用的实例# async for token in agent.astream(input{message: message, history: history}):# yield fdata: {json.dumps({token: token})}\n\n# await asyncio.sleep(0.01) # 控制推送速率response这是模拟的流式输出内容。 forcharinresponse:yieldfdata:{json.dumps({token:char})}\n\nawaitasyncio.sleep(0.02)app.post(/api/agent/chat)asyncdefchat(request:Request):dataawaitrequest.json()messagedata.get(message)historydata.get(history,[])returnStreamingResponse(agent_stream(message,history),media_typetext/event-stream,headers{Content-Type:text/event-stream,Cache-Control:no-cache,Connection:keep-alive,})后端必须设置Content-Type: text/event-stream否则前端ReadableStream将无法按预期工作。Java Spring Boot 中可对应使用SseEmitter。提示生产环境下对 SSE 流要进行连接数控制和超时管理。可在前端实现重连逻辑指数退避初始延迟 1s最大 30s浏览器原生EventSource可简化实现但无法自定义POST请求方法。若需要POST传用户消息体较大则推荐使用fetchReadableStream方案。5. 安全通信前端 Agent 安全通信实现5.1 核心风险识别前端 Agent 工具函数暴露了浏览器端能力引入的安全风险不可忽视。主要风险包括工具函数可能被滥用读取敏感数据如navigator.cookie、localStorage、GPS 坐标。LLM 幻觉可能导致服务器错误地调度一个工具函数如果该函数涉及写操作如修改 localStorage、建 cookie、发送 HTTP 请求可能造成用户数据损坏或隐私泄漏。中间人攻击如果通信链路未加密攻击者可能篡改服务器下发的工具调用指令诱导前端执行恶意操作。5.2 前端 Agent 安全通信实现方案5.2.1 工具白名单与权限分级所有工具函数必须注册在前端明确定义的白名单中前端绝不能执行由服务端动态注入的任意函数名。权限分级建议等级描述示例工具L0无敏感信息、任意调用获取当前时间、温度转换L1读取非私有信息需一次授权获取地理位置L2读取/写入用户数据写剪贴板、改主题L3高危操作写 cookie、发送网络请求需每次确认实现上可在工具函数定义阶段附加PermissionLevel属性框架在执行工具前检查授权状态。5.2.2 通信使用 HTTPS 签名所有 Agent 与服务器间的通信必须通过 HTTPS。关键调用如工具执行结果返回可增加签名机制服务器在下发tool_call_id时附带 HMAC 签名前端执行后返回时携带签名服务器验签通过才接受结果。这样可以防止结果被篡改或者重放攻击。5.2.3 敏感操作的用户二次确认对于需要修改用户数据或触发系统副作用的工具L2 及以上前端必须在执行前弹出确认对话框如弹窗提示“助手想要修改您的主题是否允许”。用户授权结果应短时缓存例如 5 分钟内同一工具不再重复确认避免打断交互流程。5.2.4 示例AG-UI 中的权限控制在 AG-UI 中可以通过ToolPolicy扩展实现权限控制// 伪代码示意工具权限策略consttoolPolicynewToolPolicy({onBeforeExecute:async(toolName,args,permissionLevel){if(permissionLevel2){constconfirmedawaitshowConfirmDialog(允许执行${toolName}吗);returnconfirmed;}returntrue;}});createAgent({tools:frontendTools.map(t({tool:t,policy:toolPolicy})),});6. 进阶LangChain 前端 Agent 对接教程与多 Agent 协同6.1 LangChain 前端 Agent 对接的基本方法当项目需要更灵活的前端 Agent 逻辑时例如自定义 LLM 调用、状态机管理可使用 LangChain 的 JavaScript SDK 创建前端 Agent。基本模式如下import{ChatOpenAI}fromlangchain/openai;import{AgentExecutor,createReactAgent}fromlangchain/langgraph;// 定义前端工具使用 langchain/core 的 Tool 类constgetLocationToolnewTool({name:get_location,description:获取用户当前地理位置。,func:async(){// 调用浏览器 Geolocation APIreturnnewPromise((resolve,reject){navigator.geolocation.getCurrentPosition((pos)resolve(${pos.coords.latitude},${pos.coords.longitude}),(err)reject(无法获取位置));});}});// 创建 Agent 实例前端可执行模式constagentawaitcreateReactAgent({llm:newChatOpenAI({model:gpt-4o,temperature:0}),tools:[getLocationTool],});constagentExecutornewAgentExecutor({agent});// 调用constresultawaitagentExecutor.invoke({input:我在哪里});但需要注意前端直接使用 LLM 的 API key 有暴露风险。LangChain 前端 Agent 对接时建议将ChatOpenAI的调用代理到自己后端或者使用callbacks将函数调用请求发送到后端进行推理。LangChain 新增的RemoteRun模式支持这种模式前端只定义工具执行逻辑LLM 推理全部通过后端 RemoteRunnable 完成。6.2 多 Agent 协同与路由在天猫行业中后台研发场景中参考搜索资料复杂的前端任务通常需要多个 Agent 协同一个 Agent 负责 UI 扫描与实际分析一个负责布局优化一个负责组件重构。在多 Agent 架构下前端需要管理多个 Agent 实例及其工具集。实现方案服务端路由层前端仅维护一个统一的 Agent 入口通过请求中的requestType字段让服务端路由到对应下游 Agent。服务端返回的流式数据中包含agentId标识来当前响应的 Agent 身份。前端命名空间隔离每个 Agent 对应一个工具命名空间工具函数名称加上agentId前缀以避免冲突。每个 Agent 实例独立管理对话历史和状态利用 React/Vue 的Context API或状态管理库Pinia/Zustand按agentId创建独立 store。3.踩坑点上下文串扰同一页面存在多个 Agent 实例时浏览器内存中的会话历史可能被重写。根本原因在于使用了全局共享的变量或数组存储历史。解决方案为每个 Agent 创建唯一agentId历史记录、AbortController、重连定时器等全部存储在该 ID 为 key 的 Map 中避免交叉影响。延伸阅读RAG 生产部署与性能监控Agent 开发与生产级部署RAG 实战全链路系列目录
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2633236.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!