基于MCP与RAG的AI编码副驾驶:实现浏览器实时调试与智能代码辅助
1. 项目概述一个能“看见”并“思考”的AI编码副驾驶最近在折腾一个挺有意思的东西我把它叫做“能看见的AI编码副驾驶”。这玩意儿不是简单的代码补全工具而是一个能真正理解你当前浏览器里在干什么然后帮你写代码、调试甚至操作网页的智能体。核心思路是让AI比如Claude不再是个“盲人”它通过一个叫MCPModel Context Protocol的服务器能实时获取你浏览器DevTools里的信息比如DOM结构、网络请求、控制台日志甚至能模拟点击、输入。这样一来你就不用再费劲地截图、复制粘贴错误信息了直接告诉AI“帮我看看这个按钮为啥点不了”它就能自己“看”页面分析问题并给出可执行的修复方案或代码。这项目特别适合前端开发者、测试工程师或者任何需要频繁与网页交互、调试复杂前端问题的朋友。想象一下你在排查一个只在生产环境出现的诡异样式问题或者一个难以复现的交互Bug。传统方式可能需要反复切换标签页、截图、描述。而现在你只需要在终端里用自然语言描述问题这个智能体就能接管你的浏览器像一位经验丰富的同事一样帮你定位元素、检查样式、执行测试步骤最后把问题根源和修复代码直接给你。它把RAG检索增强生成用在了“实时浏览器上下文”上让AI的编码和调试能力有了质的飞跃。2. 核心架构与工具选型解析这个项目的核心是搭建一个让AI模型Agent与真实世界你的浏览器安全、高效交互的桥梁。整个架构可以拆解为几个关键部分每一部分的技术选型都经过了深思熟虑。2.1 智能体Agent核心Claude与Agentic-Coding范式我选择了Anthropic的Claude模型作为智能体的大脑。原因有几个首先是它在代码生成、逻辑推理和遵循复杂指令方面的能力非常突出这对于需要理解调试上下文、生成准确操作指令的场景至关重要。其次Claude API的稳定性好上下文窗口足够大能容纳较长的浏览器状态信息。更重要的是这里采用了“Agentic-Coding”范式。这不是让AI一次性生成所有代码而是设计了一个具备“思考-行动-观察”循环的智能体。它会将你的复杂任务如“修复登录表单的提交错误”分解为一系列子任务Subagents例如1. 检查表单HTML结构2. 查看控制台错误3. 检查网络请求4. 修改JavaScript代码。每个子任务都是一个独立的“行动”智能体执行后会“观察”结果浏览器状态变化再决定下一步。这种范式让处理复杂、动态的网页调试问题成为可能。2.2 上下文桥梁MCP服务器与浏览器自动化这是项目的技术核心。MCPModel Context Protocol是一个新兴的开放协议它定义了AI模型如何安全地访问工具和数据源。在这里我们需要一个MCP服务器专门负责与浏览器对话。我选择了Puppeteer作为浏览器自动化的底层驱动。为什么不选SeleniumPuppeteer是Node.js原生支持与Chrome/Chromium深度集成启动速度快API现代且强大能直接访问完整的Chrome DevTools Protocol。这对于我们需要实时获取DOM、网络、性能等精细数据的需求来说是更轻量、更高效的选择。这个MCP服务器本质上是一个Rust或Node.js程序它利用Puppeteer启动或连接到一个浏览器实例并将Puppeteer的能力如截图、获取DOM、执行脚本、模拟交互包装成一系列标准的“工具”Tools暴露给Claude。例如当Claude需要“查看当前页面的所有按钮”时它会调用MCP服务器提供的get_dom_elements工具并附带一个CSS选择器参数button。MCP服务器收到请求后通过Puppeteer执行page.$$eval(button, ...)将结果结构化后返回给Claude。这样Claude就“看见”了页面。2.3 本地知识库增强RAG与向量数据库浏览器当前状态是实时上下文但很多时候解决问题还需要项目本身的代码知识。比如AI看到了一个React组件渲染错误它需要知道这个组件的源码、它用到的工具函数、项目的类型定义等。这就是RAG检索增强生成发挥作用的地方。我会在项目初始化阶段将整个代码库排除node_modules,.git等进行切片和嵌入存储到一个本地的向量数据库中。这里我倾向于使用ChromaDB或LanceDB它们轻量、易嵌入适合桌面应用场景。当Claude在分析问题时如果涉及到项目代码它可以先通过MCP服务器查询这个本地向量数据库“检索与‘用户登录认证’相关的代码文件”。MCP服务器执行语义搜索返回最相关的代码片段作为额外上下文提供给Claude。这相当于给AI配备了一个随时可查、过目不忘的项目代码手册。2.4 终端交互与任务协调Shell与Zsh集成整个智能体的控制中心在终端。我用Zsh配合一些Shell脚本来启动和管理整个系统。一个主控制脚本会负责1. 启动MCP服务器2. 加载本地代码向量数据库3. 初始化Claude会话并配置好可用的工具列表4. 提供一个交互式命令行界面。你可以在终端里输入coding-agent --task “测试首页轮播图在移动端的滑动功能”。Shell脚本会解析这个命令构造一个包含任务描述的初始消息发送给Claude智能体。随后智能体开始它的循环思考决定调用哪个工具 - 通过MCP服务器执行 - 观察结果 - 继续思考。所有的交互日志、AI的“内心独白”、工具调用和结果都会流式输出在终端让你对整个调试过程一目了然。注意工具链的选择强调本地化和可控性。所有组件Claude API调用除外都运行在本地你的代码和浏览器数据不会未经允许发送到第三方。MCP服务器的权限也被严格限定通常只能操作一个特定的、为调试而打开的浏览器窗口不会影响你其他正在工作的浏览器会话。3. 环境搭建与核心组件部署实操理论说再多不如动手搭一遍。下面我以macOS为主要环境带你一步步把这个“编码副驾驶”给跑起来。整个过程涉及多个组件我们按依赖关系逐个击破。3.1 基础环境准备Rust、Node.js与浏览器首先确保你的机器上有以下基础软件Node.js (v18及以上)和 npm这是Puppeteer和可能的MCP服务器Node版的运行时。# 使用nvm管理Node版本是个好习惯 nvm install 18 nvm use 18Rust 工具链如果你选择用Rust编写高性能的MCP服务器这是必须的。curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/envChrome/ChromiumPuppeteer默认会下载一个Chromium但为了更好的兼容性和性能我建议使用系统已安装的Chrome。确保Chrome已安装并记下其可执行文件路径通常在/Applications/Google Chrome.app/Contents/MacOS/Google Chrome。3.2 构建MCP服务器Rust版本示例我更喜欢用Rust来写MCP服务器因为其性能和无畏并发特性非常适合这种需要处理大量实时I/O和长时间连接的服务。我们使用mcp-rs这个库来简化开发。首先创建一个新的Rust项目cargo new browser-mcp-server --bin cd browser-mcp-server编辑Cargo.toml添加依赖[package] name browser-mcp-server version 0.1.0 edition 2021 [dependencies] tokio { version 1, features [full] } serde { version 1.0, features [derive] } serde_json 1.0 anyhow 1.0 mcp 0.1 # 假设有mcp库实际可能需要从git引入 # 我们需要一个Puppeteer的Rust绑定例如 puppeteer-rs请注意这是一个假设的库实际可能需要使用Node.js子进程或WebSocket # 这里为了示例我们假设通过调用Node.js子进程来驱动Puppeteer [target.cfg(target_os macos).dependencies]由于目前Rust生态中成熟的Puppeteer绑定较少一个更务实的方法是让Rust MCP服务器通过stdin/stdout 或 WebSocket与一个Node.js子进程通信由Node.js进程实际运行Puppeteer。这样既能利用Rust构建稳健的MCP服务又能使用成熟的Puppeteer Node.js API。核心思路Rust主进程启动一个Node.js子进程运行一个Puppeteer脚本。两者之间建立简单的基于JSON行的进程间通信IPC。Rust MCP服务器收到AI的请求如{“tool”: “screenshot”, “args”: {}}将其转发给Node子进程。Node子进程用Puppeteer执行对应操作将结果如图片的base64编码返回给Rust进程。Rust进程将结果格式化为MCP标准响应返回给AI。这种架构虽然增加了一层IPC但实现了技术栈的最佳搭配并且将不稳定的浏览器自动化逻辑隔离在子进程中即使Node进程崩溃Rust主服务也能感知并重启它。3.3 构建本地代码检索器RAG引擎这部分我们使用Node.js和ChromaDB来实现因为它更贴近JavaScript/TypeScript生态。初始化项目并安装依赖mkdir code-rag-engine cd code-rag-engine npm init -y npm install chromadb types/node typescript ts-node openai axios glob fast-glob npm install --save-dev types/node这里假设使用OpenAI的嵌入模型text-embedding-3-small你需要准备一个OPENAI_API_KEY。当然你也可以选择本地嵌入模型如all-MiniLM-L6-v2通过xenova/transformers库运行速度会慢一些但完全离线。编写代码索引脚本 创建一个index.ts脚本它的工作是遍历你的项目源代码将每个文件按函数、类或一定行数切片调用嵌入模型生成向量然后存入ChromaDB集合。import { ChromaClient } from chromadb; import { OpenAIEmbeddingFunction } from chromadb; import * as fs from fs/promises; import * as path from path; import { glob } from glob; const client new ChromaClient(); const embedder new OpenAIEmbeddingFunction({ openai_api_key: process.env.OPENAI_API_KEY!, openai_model: text-embedding-3-small }); const collection await client.getOrCreateCollection({ name: project_code, embeddingFunction: embedder }); // 遍历代码文件 const files await glob(**/*.{js,ts,jsx,tsx,py,go,rs}, { ignore: [node_modules/**, dist/**, build/**, .git/**] }); for (const file of files) { const content await fs.readFile(file, utf-8); // 简单的按行切片更高级的可以按AST语法树切分 const chunks chunkContent(content, 200); // 每200行一个块 const metadatas chunks.map((_, index) ({ source: file, chunk: index })); await collection.add({ ids: chunks.map((_, idx) ${file}_${idx}), metadatas: metadatas, documents: chunks }); } console.log(代码索引完成);这个脚本只需在项目代码有重大更新时运行。编写查询接口 再创建一个query.ts作为MCP服务器查询代码库的接口。它接收一个自然语言问题返回最相关的代码片段。// ... 初始化client和collection同上 export async function queryCode(question: string, nResults 3): Promisestring[] { const results await collection.query({ queryTexts: [question], nResults: nResults }); // 将检索到的文档片段合并为上下文字符串 return results.documents[0].map((doc, idx) 来自文件: ${results.metadatas[0][idx].source}\n代码片段:\n${doc} ); }3.4 集成与启动Zsh脚本编排最后我们需要一个“总指挥”脚本把MCP服务器、RAG查询服务、以及Claude的对话流程串起来。创建一个coding-agent.zsh脚本#!/bin/zsh # 设置环境变量 export OPENAI_API_KEYyour_key_here export ANTHROPIC_API_KEYyour_claude_key_here # 定义项目路径 PROJECT_ROOT/path/to/your/project CODE_DB_PATH./chroma_db # 1. 启动RAG查询服务后台运行 echo 启动代码检索服务... node ./code-rag-engine/dist/query_server.js RAG_PID$! # 2. 启动浏览器MCP服务器后台运行 echo 启动浏览器MCP服务器... cd ./browser-mcp-server cargo run --release MCP_PID$! cd .. # 3. 等待服务就绪 sleep 5 # 4. 启动主Agent对话循环 echo 启动编码智能体... # 这里使用一个Python或Node.js脚本作为主控它连接MCP服务器和Claude API python3 main_agent.py --task $1 # 脚本结束时清理后台进程 trap kill $RAG_PID $MCP_PID 2/dev/null; echo 服务已停止 EXIT这个脚本做了几件事设置关键API密钥、启动后台服务、运行主智能体逻辑并确保在退出时清理进程。main_agent.py是这个系统的“大脑”它负责与Claude API对话并根据Claude的思考决定调用哪个MCP工具浏览器操作或代码检索。4. 核心工作流程与智能体交互实录环境搭好了我们来实战看看这个智能体是如何工作的。我模拟一个真实的前端调试场景带你走一遍完整的交互流程。4.1 场景设定调试一个失败的登录按钮假设你正在开发一个React应用用户报告登录按钮有时点击没反应。你已经在本地复现了这个问题但一眼看不出原因。现在你打开终端运行智能体。./coding-agent.zsh “请帮我诊断并修复项目根目录下localhost:3000登录页面的登录按钮点击无响应的问题。”4.2 智能体的“思考-行动”循环分解第一轮探索与信息收集智能体思考“用户报告登录按钮点击无反应。我需要先了解页面当前状态。我应该先获取页面的DOM找到那个登录按钮并检查其HTML结构和基本属性。”智能体行动调用MCP服务器的get_page_html工具或许附带一个粗略的选择器button或input[typesubmit]。MCP执行 观察MCP服务器通过Puppeteer获取到页面HTML并高亮找到的所有按钮将它们的HTML、ID、类名、以及是否可见、是否禁用等状态返回。智能体分析“找到了三个按钮。其中一个ID是login-submit看起来是主要的登录按钮。它的HTML是button id\login-submit\ class\btn-primary\ disabled登录/button。啊哈它有一个disabled属性。但这可能是初始状态我需要知道点击时发生了什么。”第二轮深入检查与交互测试智能体思考“按钮被禁用。我需要检查是什么逻辑控制了这个disabled状态。是表单验证吗我先看看这个按钮上的事件监听器以及它所在的表单。”智能体行动调用get_element_listeners工具传入#login-submit。同时调用get_js_property工具获取该元素的disabled属性值是静态的true还是某个JavaScript变量的值。MCP执行 观察返回信息显示按钮没有直接绑定点击事件事件可能委托在父级表单上。disabled属性值是true。智能体思考“属性是静态的true这意味着按钮在HTML里就被写死了禁用。这不对。我需要查看相关的JavaScript代码特别是处理登录表单和这个按钮的逻辑。”第三轮结合代码库知识RAG介入智能体思考“我需要找到控制登录按钮状态的源代码。我应该检索项目中与‘login’、‘submit’、‘disabled’相关的代码。”智能体行动调用RAG服务的query_code工具查询“login button disabled state React component”。RAG执行 观察向量数据库返回了3个最相关的代码片段片段1来自LoginForm.jsx其中有一个isFormValid状态控制按钮的disabled属性。片段2来自validation.js里面有一个validateEmail函数。片段3来自api/auth.js是提交登录的API调用函数。智能体分析“关键在LoginForm.jsx。按钮的disabled状态绑定到!isFormValid。而isFormValid依赖于邮箱和密码字段的验证。我需要检查这两个字段的当前值和验证状态。”第四轮实时状态诊断智能体行动调用get_element_property工具获取邮箱和密码输入框的value。同时调用execute_script工具在浏览器控制台运行window.validateEmail?.(邮箱值)来模拟验证函数调用。MCP执行 观察返回邮箱值为“userexample”缺少.com密码框为空。模拟验证函数返回false。智能体推理“问题找到了邮箱格式不正确导致isFormValid为false所以按钮一直被禁用。但用户可能输入了完整邮箱后误删了部分或者我们的验证逻辑有误。我需要进一步检查1. 验证逻辑本身是否正确2. 是否有其他因素如网络状态错误地影响了isFormValid。”第五轮验证与修复建议智能体行动仔细审查RAG返回的validation.js代码片段。发现validateEmail函数使用了一个非常严格的正则表达式漏掉了某些有效格式如带加号的邮箱。智能体总结与输出智能体在终端流式输出最终诊断报告和修复建议## 问题诊断完成 **根本原因**登录按钮点击无响应是因为按钮的 disabled 属性被设置为 true。 **根本原因**按钮的禁用状态由 LoginForm 组件的 isFormValid 状态控制该状态为 false。 **直接原因**isFormValid 为 false 是因为邮箱输入框的值 “userexample” 未通过 validateEmail 函数校验。 **深层原因**validateEmail 函数位于 src/utils/validation.js:15使用的正则表达式过于严格拒绝了部分有效邮箱格式如包含“”号的邮箱。 ## 建议的修复方案 1. **立即缓解**在浏览器控制台手动执行 document.getElementById(‘login-submit’).disabled false 可临时启用按钮。 2. **代码修复**修改 src/utils/validation.js 第15行的正则表达式。建议改用更通用的标准例如 javascript // 替换原有的严格正则 function validateEmail(email) { return /^[^\s][^\s]\.[^\s]$/.test(email); } 3. **增强体验**在 LoginForm.jsx 中考虑在按钮附近添加实时验证错误提示让用户明确知道为何按钮不可用。 **已执行的检查**DOM状态、事件监听器、表单值、相关源代码检索、验证函数模拟执行。整个过程中你无需手动切换窗口、复制错误信息或搜索代码。智能体像一位不知疲倦的助手自动完成了从现象观察、信息搜集、代码关联到根因分析的全链条工作。5. 高级技巧、避坑指南与性能优化用了一段时间后我积累了不少实战经验也踩过一些坑。这里分享几个关键点能帮你把这个工具用得更加顺手和高效。5.1 精准控制浏览器上下文与权限问题智能体操作的是真实的浏览器如果权限过大可能误关闭重要标签页或意外修改生产环境数据。解决方案使用独立的浏览器用户数据目录在启动Puppeteer时指定一个全新的userDataDir。这能确保调试会话的Cookie、缓存和历史记录与你的主浏览器完全隔离。// 在Node.js Puppeteer脚本中 const browser await puppeteer.launch({ userDataDir: ‘/tmp/coding-agent-profile’, headless: false // 调试时建议设为false观察过程 });严格限制操作范围MCP服务器工具设计上应只对通过它启动的特定page对象生效。避免提供“获取所有浏览器窗口”这类危险工具。操作确认与沙盒对于非读操作如点击、输入、导航可以在工具层实现一个简单的确认机制或者先在about:blank页面或一个沙盒iframe内测试操作脚本确认无误后再应用到目标页面。5.2 优化RAG检索质量与速度问题代码检索返回不相关片段或者检索速度慢影响交互体验。解决方案智能代码分块不要简单按行或按固定字符数切割。使用像Tree-sitter这样的解析器按语法树节点如函数、类、方法进行分块。这能保证代码片段的语义完整性极大提升检索准确率。混合检索策略结合语义搜索向量检索和关键词搜索如BM25。先用关键词快速过滤出可能相关的文件再在这些文件中进行更耗时的语义相似度匹配。ChromaDB等库已支持混合检索。缓存与索引更新为代码向量数据库建立缓存层。如果文件未修改通过git status或文件哈希判断则直接使用缓存的结果。可以设置一个git post-commit钩子在每次提交后自动增量更新向量索引。5.3 管理智能体“幻觉”与错误操作问题AI可能会误解浏览器状态或提出错误的操作序列例如在元素加载完成前就去点击它。解决方案强化工具反馈的结构化确保MCP服务器返回的数据不仅是成功的执行结果还要包含丰富的元数据和可能的错误信息。例如click_element工具在失败时应返回“元素未找到”、“元素不可交互”、“被其他元素遮挡”等具体原因而不仅仅是false。实现自动重试与状态检查在工具层面封装健壮的逻辑。比如click_element工具内部可以先检查元素是否存在、是否可见、是否可点击如果不满足条件先等待一小段时间或滚动到视图中再进行操作。这模仿了优秀测试框架的行为。设置“护栏”与超时在智能体的主循环中设置单次任务的最大步骤数比如50步和总超时时间比如5分钟。防止智能体陷入无限循环或长时间无意义的尝试。当达到限制时强制终止并总结已发现的信息。5.4 提升终端交互体验与可观测性问题智能体的思考过程在终端刷屏难以追踪关键信息容易被淹没。解决方案结构化日志输出不要简单打印JSON。使用像clack或ink这样的库来构建漂亮的终端UI。用不同颜色和图标区分“用户输入”、“AI思考”、“工具调用”、“工具结果”、“最终答案”。引入“检查点”与手动确认对于关键操作比如要修改源码文件可以让智能体暂停并输出一个差异对比diff询问用户“是否应用此修改(y/n)”。这给了你最终的控制权。会话历史与回放将整个对话、工具调用和结果序列化保存到文件如JSONL格式。这样你可以事后复盘智能体的决策过程或者将成功的调试会话作为案例库用于未来类似问题的快速启动。5.5 性能开销与资源管理问题同时运行浏览器、MCP服务器、向量数据库和AI对话对内存和CPU消耗不小。解决方案按需启动浏览器不要一直开着浏览器实例。可以设计成当收到第一个需要浏览器上下文的工具调用时才懒启动Puppeteer。在一段时间无操作后自动关闭浏览器以释放资源。优化嵌入模型如果使用本地嵌入模型选择更轻量的模型如all-MiniLM-L6-v2。虽然效果略逊于大型模型但对于代码检索任务通常足够且速度快、资源占用低。流式响应与渐进式思考让Claude使用其API的流式输出功能。这样你可以实时看到它的思考过程而不必等待完整的、可能很长的响应生成完毕。这提升了交互的响应感。这个“能看见的编码副驾驶”项目其价值不在于替代开发者而在于放大开发者的能力。它处理了调试中那些繁琐、重复的信息搜集和上下文切换工作让你能更专注于真正的逻辑思考和架构设计。从我的使用体验来看它最适合那些上下文复杂、需要跨多个文件或实时界面状态进行分析的任务。对于简单的语法错误传统的Linter或IDE提示可能更快。但随着你不断优化它的工具集和提示词它会越来越像一个真正理解你项目和开发习惯的资深搭档。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2576685.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!