ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

我构建了一个能“上网冲浪”的DeepSeek智能体:DeepSeek结合Playwright MCP服务

2026/9/29 21:13:36 拓冰建站 浏览量
我构建了一个能“上网冲浪”的DeepSeek智能体:DeepSeek结合Playwright MCP服务 1. 为什么大模型需要“上网冲浪”的能力DeepSeek 这类大模型的知识来自训练数据本质上是一张“过去时”的快照。你问它某个官网最新的活动页长什么样、某个后台系统的按钮在哪个位置、某条新闻的评论区现在有多少条它只能凭记忆猜猜不准也没法验证。真正让智能体变得有用的不是它“知道”多少而是它能不能像人一样打开浏览器、点按钮、填表单、把页面内容读回来。这就是 Playwright MCP 要解决的问题。Playwright 是微软维护的浏览器自动化库一套 API 可以驱动 Chromium、Firefox、WebKitMCPModel Context Protocol则把这套能力包装成标准工具让 DeepSeek 通过工具调用去操作真实浏览器。两者结合你就得到一个能“上网冲浪”的智能体你说“帮我打开某页面把标题和第一段正文抓回来”它会自己决定调用browser_navigate、browser_snapshot再把结果整理给你。这篇面向信息采集与页面操作场景从零跑通一条可复现的链路装 Playwright MCP 服务、配好客户端、接上 DeepSeek 的模型通道、执行一次真实的浏览器动作。适合想给智能体加“眼睛和手”的开发者也适合做数据采集、页面巡检、自动化测试的同学。下面所有步骤我都实际跑过命令和配置可以直接抄。2. 前置准备Node.js、TaoToken 通道与目录结构2.1 环境依赖Playwright MCP 是一个 Node 包通过npx拉起所以第一件事是确认 Node.js 版本。建议 18 以上我用的是 20.xnode -v npm -v如果版本太低npx playwright/mcplatest可能报语法错误。装好 Node 后不需要单独npm install playwrightMCP 服务首次运行会自动拉取依赖和浏览器内核。2.2 用 TaoToken 统一模型通道智能体要调用 DeepSeek就得有一个稳定的模型 API 入口。我这边统一走 TaoToken 的通道好处是一个 Key 覆盖多种模型切换模型不用改代码只改模型名。控制台里创建 Key 的入口在 API Keys 页面创建后复制出来形如sk-xxxx。拿到 Key 之后把接口地址和 Key 写进环境变量避免硬编码进代码export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api注意https://taotoken.net/api是接口基址客户端里拼接路径时通常再加/v1具体以你用的 SDK 为准。Key 不要提交到 Git用.env或系统环境变量管理。2.3 目录结构我习惯把 MCP 配置和客户端代码放同一层方便客户端读取deepseek-browser-agent/ ├── servers_config.json ├── client.py └── .envservers_config.json描述要连接哪些 MCP 服务客户端启动时读它。这样以后想加文件系统、数据库等其他 MCP 服务只改这个文件即可。3. 启动 Playwright MCP 服务并写配置骨架3.1 拉起 MCP 服务在项目目录下执行npx playwright/mcplatest --port 8931首次运行会提示安装包输入y回车。装完你会看到类似输出Listening on http://localhost:8931 Put this in your client config: { mcpServers: { playwright: { url: http://localhost:8931/sse } } }这行--port 8931指定监听端口/sse是 Server-Sent Events 端点客户端通过它建立长连接。服务保持前台运行另开一个终端跑客户端。3.2 写 servers_config.json把上面提示的配置原样落到文件里{ mcpServers: { playwright: { url: http://localhost:8931/sse } } }这个骨架是通用的mcpServers下每个键是一个服务名url指向 SSE 端点。以后加服务就并列再加一项客户端遍历即可。3.3 客户端连接与工具发现客户端用 Python 的mcp库建立 SSE 连接核心是sse_client和ClientSession两层上下文。下面是我精简后的连接方法去掉了业务无关的日志import asyncio import json from contextlib import AsyncExitStack from mcp import ClientSession from mcp.client.sse import sse_client class MCPClient: def __init__(self): self.session None self.tools {} self._exit_stack AsyncExitStack() async def connect_server(self, server_config): url server_config[mcpServers][playwright][url] print(f尝试连接到: {url}) sse_cm sse_client(url) streams await self._exit_stack.enter_async_context(sse_cm) session_cm ClientSession(streams[0], streams[1]) self.session await self._exit_stack.enter_async_context(session_cm) await self.session.initialize() response await self.session.list_tools() self.tools {tool.name: tool for tool in response.tools} print(f成功获取 {len(self.tools)} 个工具) for name in self.tools: print(f - {name})AsyncExitStack的作用是保证连接在程序结束时正确关闭不会留下悬挂的 SSE 流。list_tools()返回服务端暴露的全部工具Playwright MCP 一般给到 20 个左右覆盖导航、点击、输入、截图、PDF 保存、标签页管理等。3.4 工具清单速查把关键工具列成表方便你对照调用工具名作用browser_navigate打开指定 URLbrowser_snapshot抓取当前页面可访问性快照返回结构化文本browser_click点击页面元素browser_type向可编辑元素输入文本browser_take_screenshot截图当前页面browser_pdf_save将页面保存为 PDFbrowser_tab_new / browser_tab_select新建、切换标签页browser_wait等待指定秒数browser_snapshot是采集场景里最常用的它返回的是页面语义结构而不是原始 HTML模型读起来更省 token也更容易定位元素。4. 把 DeepSeek 接进循环可复制的对话与工具执行逻辑4.1 对话主循环智能体的核心是一个“指令 → 理解 → 调用 → 执行 → 返回 → 响应”的循环。用户发一句话DeepSeek 决定要不要调工具、调哪个客户端执行工具把结果回灌给模型直到模型不再请求工具、直接给出自然语言回答async def chat_loop(self): print(MCP 客户端启动输入 /bye 退出) while True: prompt input( ).strip() if /bye in prompt.lower(): break response await self.chat(prompt) result await self.execute_tool(response) while result ! response: response await self.chat(result, rolesystem) result await self.execute_tool(response) print(response)execute_tool负责解析模型返回的工具调用意图匹配self.tools里的名字用session.call_tool(name, arguments)执行再把结果序列化返回。如果模型这轮没请求工具result就等于response循环退出打印最终答案。4.2 调用 DeepSeek 的请求体模型侧我走 TaoToken 的兼容接口用requests或httpx都行。关键是把工具定义一起传过去让模型知道有哪些函数可调import os, httpx async def chat(self, prompt, roleuser): self.messages.append({role: role, content: prompt}) tools_payload [ { type: function, function: { name: name, description: tool.description, parameters: tool.inputSchema, }, } for name, tool in self.tools.items() ] payload { model: deepseek-chat, messages: self.messages, tools: tools_payload, tool_choice: auto, } headers { Authorization: fBearer {os.environ[TAOTOKEN_API_KEY]}, Content-Type: application/json, } async with httpx.AsyncClient(timeout60) as client: resp await client.post( f{os.environ[TAOTOKEN_BASE_URL]}/v1/chat/completions, jsonpayload, headersheaders, ) data resp.json() return data[choices][0][message]tool_choice设为auto模型自己判断是否需要工具。inputSchema直接来自 MCP 工具定义不用手写参数结构这是 MCP 省事的地方。4.3 执行工具并回灌结果async def execute_tool(self, message): tool_calls message.get(tool_calls) if not tool_calls: return message.get(content, ) for call in tool_calls: name call[function][name] args json.loads(call[function][arguments]) print(f调用工具: {name} 参数: {args}) result await self.session.call_tool(name, args) self.messages.append({ role: tool, tool_call_id: call[id], content: str(result.content), }) return tool_executed返回tool_executed是个标记告诉主循环“这轮是工具结果需要再问一次模型”。模型拿到工具输出后要么继续调下一个工具要么给出最终回答。5. 一次可复现的验证让智能体打开页面并抓取标题5.1 验证目标跑通链路最直接的方式让智能体打开一个公开页面抓取页面标题和第一段正文并截图存证。整个过程不需要你手动点浏览器全部由模型决策、MCP 执行。5.2 启动与输入先确保 MCP 服务在 8931 端口运行然后启动客户端python client.py在提示符下输入打开 https://example.com 告诉我页面标题和第一段正文并截图保存5.3 预期执行链路模型通常会依次请求调用工具: browser_navigate 参数: {url: https://example.com} 调用工具: browser_snapshot 参数: {} 调用工具: browser_take_screenshot 参数: {}browser_navigate返回导航成功browser_snapshot返回页面语义结构里面包含标题和正文文本browser_take_screenshot返回截图保存路径。模型最后把这些信息整理成一句自然语言回答类似页面标题是 Example Domain第一段正文为 This domain is for use in illustrative examples in documents... 截图已保存到当前目录。5.4 结果核对去项目目录看截图文件是否生成打开确认内容与页面一致。如果截图存在、标题正确说明从 MCP 服务、SSE 连接、工具发现、模型决策到工具执行的整条链路已经打通。这一步跑通后把输入换成“搜索某关键词并抓取前三条结果标题”智能体就会自己组合browser_type、browser_click、browser_snapshot完成更复杂的采集任务。6. 本篇常见报错与排查6.1 连接被拒绝报错ConnectionRefusedError或SSE error先确认 MCP 服务是否还在前台运行。npx那条命令的终端一旦关闭服务就停了。重新执行并保持窗口开着再跑客户端。6.2 工具列表为空成功获取 0 个工具通常是 SSE 端点写错。检查servers_config.json里的 URL 是否带/sse后缀端口是否和启动命令一致。Playwright MCP 默认路径就是/sse漏掉会连上但拿不到工具。6.3 模型不调用工具如果模型一直用文字回答、从不触发tool_calls检查两点一是tools字段是否真的传进请求体二是模型名是否支持函数调用。用deepseek-chat这类支持工具调用的模型别用纯对话模型。另外tool_choice设成auto设成none会禁用工具。6.4 浏览器内核缺失首次调用browser_navigate报找不到浏览器执行一次安装npx playwright install chromium装完再重试。如果公司网络对下载有限制提前在能联网的环境装好或配置镜像源。6.5 截图路径找不到browser_take_screenshot默认存到服务进程的工作目录不是客户端目录。想固定位置在参数里传绝对路径或在启动 MCP 服务时先cd到目标目录。6.6 长页面快照超 tokenbrowser_snapshot对超长页面会返回很大一段文本可能撑爆上下文。采集时先用browser_navigate打开再用browser_click或滚动定位到目标区域最后快照减少无关内容。7. 继续往下走从跑通到常用链路跑通后日常最实用的三件事一是把常用采集动作固化成提示词模板比如“打开 X抓取 Y 区域文本存成 CSV”二是把模型通道固定成 TaoToken 的 Key换模型只改model字段不用动客户端三是把 MCP 服务做成后台常驻避免每次手动拉起。如果你要长期跑编码类或 Agent 类任务可以了解下 Coding Plan额度更划算只想先验证模型对话效果直接进模型对话页面试几句接入过程中遇到 Key 或端点问题去 API Keys 页面核对配置细节看接入文档。把这篇的servers_config.json和客户端骨架留着下次加新 MCP 服务改一个文件就能扩展。