尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
用LangChain和Playwright构建大模型驱动的测试智能体
把大模型接进自动化测试这件事我之前一直持保留态度。直到用LangChain把Playwright包成一个能自己看页面、自己点按钮、自己写断言的测试智能体之后我才意识到传统的UI自动化写法确实到了该升级的时候。这篇文章就把我搭建这个测试智能体的完整思路、核心代码和踩过的坑一次性讲清楚。如果你正在做Web自动化测试或者想给测试团队引入Agent能力这篇文章能帮你少走不少弯路。先说结论这个测试智能体的核心价值不是替代测试人员而是把读需求文档、写脚本、跑用例、查失败原因这条链路里最耗时的部分压缩掉。它读一段自然语言描述的测试用例自己调起浏览器自己定位元素自己执行操作最后把断言结果和失败原因整理成报告。整个过程只需要你给它一个任务描述剩下的交给Agent循环去推理和执行。1. 整体设计思路测试智能体到底在做什么1.1 传统UI自动化的瓶颈在哪里早期我做UI自动化最头疼的就是三件事。第一是脚本维护成本高。页面结构稍微改一下xpath或者css选择器就失效了一个用例可能花半天时间调定位。第二是断言写得稀碎。很多测试同学写断言就是元素是否出现文本是否相等真正业务意义上的用户能不能完成这个流程反而覆盖不到。第三是脚本和用例脱节。需求文档里的用例是人话代码里的用例是机器话两边对不上验收的时候全靠人肉翻译。这三点叠加在一起的结果是自动化测试的投入产出比经常是负的。你花大量时间写脚本、调脚本最后换来的只是能跑而已。更不要说每次迭代版本更新脚本报废率极高。1.2 测试智能体的工作闭环我构想的测试智能体核心是让大模型充当读用例、做决策、调工具的大脑让Playwright充当看页面、点操作、取数据的手脚。整体闭环是这样的测试人员用自然语言写一条测试用例比如用户使用正确的账号密码登录跳转到首页导航栏显示用户名。Agent把这条用例拆解成若干子任务打开登录页、输入账号、输入密码、点击登录、验证跳转、验证用户名。Agent在每一步调用Playwright工具去执行动作并把页面关键信息URL、可见文本、当前元素状态作为观察结果反馈给模型。模型根据观察结果决定下一步动作或者判定当前步骤是否已完成。全部步骤执行完后Agent汇总输出一份包含执行状态、断言结果、失败原因和截图链接的测试报告。这个闭环最大的变化是以前写自动化脚本是在翻译用例现在是让模型动态地理解用例、动态地操作页面。脚本不再是一成不变的代码而是模型在运行时生成的决策序列。1.3 为什么选LangChain而不是直接用LangGraph很多同学会问LangChain和LangGraph有什么区别我为什么选LangChain而不是LangGraph简单说LangGraph适合编排复杂的、有状态的多Agent工作流节点多、条件分支多、需要人工介入审批的场景。而LangChain的Agent机制特别是create_react_agent和工具调用模式已经能覆盖推理-行动-观察这个循环。测试智能体本质上是一个单Agent反复调用浏览器工具的过程状态管理没有复杂到必须上Graph的程度。另外LangChain的工具封装生态更成熟。tool装饰器可以直接把Playwright的异步操作包装成大模型可调用的工具函数参数的schema描述清楚就能工作。LangGraph也能做到但需要额外写状态定义和节点路由对快速验证想法来说重了一点。如果你后续要做多智能体协作比如一个Agent负责用例理解、另一个Agent负责执行、第三个Agent负责结果审查那时候迁到LangGraph是合理的。单智能体阶段LangChain足够了。2. 环境搭建与Agent工具层2.1 项目初始化与依赖我用的技术栈是Python 3.11 LangChain Playwright。选Python是因为生态里处理LLM的工具链更全调试也直观。Playwright本身支持Python和Node两套API我用的是Python版本。依赖安装命令如下pip install langchain langchain-openai playwright playwright install chromium一个容易忽略的点playwright install chromium会下载浏览器二进制文件这一步在国内网络环境下可能很慢建议提前配置好PLAYWRIGHT_DOWNLOAD_HOST镜像源。装完之后用playwright install --list确认一下浏览器版本。项目结构我按功能拆了几个模块test_agent/ ├── agent/ │ ├── browser_tools.py # 封装Playwright操作 │ ├── agent_chain.py # 组装LangChain Agent │ └── prompts.py # 提示词模板 ├── cases/ │ └── login_cases.md # 自然语言测试用例 ├── reports/ # 测试报告输出目录 └── main.py # 入口这样拆的好处是工具层、编排层、用例层分离后续想换模型或者加工具都不需要动其他模块。2.2 把Playwright变成Agent的手要让大模型能操作浏览器最关键的是把Playwright的每个动作封装成一个语义清晰的工具函数。LangChain的tool装饰器配合BaseTool的args_schema可以自动生成函数签名模型会根据函数名、参数描述来判断什么时候调用哪个工具。下面是工具层的一个核心示例import asyncio from typing import Optional from langchain_core.tools import tool from playwright.async_api import async_playwright, Page class BrowserSession: def __init__(self): self.page: Optional[Page] None self._playwright None self._browser None async def start(self): self._playwright await async_playwright().start() self._browser await self._playwright.chromium.launch( headlessFalse, args[--window-size1920,1080] ) context await self._browser.new_context(viewport{width: 1920, height: 1080}) self.page await context.new_page() async def stop(self): if self._browser: await self._browser.close() if self._playwright: await self._playwright.stop() browser_session BrowserSession() tool async def goto_url(url: str) - str: 在浏览器中打开指定的URL并返回页面当前的主要文本内容。 if not browser_session.page: await browser_session.start() await browser_session.page.goto(url, wait_untilnetworkidle) text await browser_session.page.locator(body).inner_text() return f已打开 {url}页面主要内容\n{text[:2000]}这里有个关键设计工具的返回值一定要把页面状态带回去。模型看不到浏览器它唯一能感知的就是工具返回的文本。所以每个工具我都会把页面的关键信息提取出来返回比如当前URL、可见文本、元素是否存在、按钮是否可点击。信息越完整模型的决策越准确。还有一个细节用headlessFalse开发阶段能看到浏览器真实操作方便调试。稳定之后可以切成headlessTrue跑批量回归。2.3 封装断言与状态回传你光会点按钮不算测试还得会验证结果。我封装了一套轻量级断言工具让模型能直接检查页面状态。tool async def check_element_visible(selector: str) - str: 检查指定CSS选择器的元素是否在页面上可见返回检查结果。 try: await browser_session.page.wait_for_selector(selector, timeout5000) visible await browser_session.page.is_visible(selector) return f元素 {selector} 可见性检查结果{可见 if visible else 不可见} except Exception as e: return f元素 {selector} 未找到或检查超时{str(e)} tool async def check_text_present(text: str) - str: 检查当前页面是否包含指定文本用于断言操作结果。 content await browser_session.page.content() if text in content: return f页面包含目标文本{text} return f页面不包含目标文本{text}除了正向断言我还做了一个捕获页面报错信息的工具。用Playwright监听console消息和pageerror事件一旦页面上出现JS异常直接记录到上下文里。这样模型在断言失败时能拿到真正的错误原因而不是只看元素没出现。tool async def get_page_errors() - str: 获取页面上最近发生的JS错误和控制台报错信息。 if not browser_session.page: return 浏览器未启动 errors getattr(browser_session.page, _captured_errors, []) return \n.join(errors[-5:]) if errors else 页面上没有捕获到JS报错这个工具在排查前端问题时候非常有用很多断言失败其实是前端抛了异常页面没正常渲染而不是元素定位写错了。3. Agent的核心编排链路3.1 从测试用例到任务描述Agent编排的核心是提示词。我把测试执行的目标写成一个系统提示词约束模型的行为方式SYSTEM_PROMPT 你是一名资深Web自动化测试工程师。你的任务是执行用户提供的测试用例。 你有以下工具可用 - goto_url: 打开页面 - fill_input: 在输入框中填写内容 - click_element: 点击元素 - check_element_visible: 检查元素可见性 - check_text_present: 检查文本是否存在 - get_page_errors: 获取页面JS报错 - take_detailed_screenshot: 获取页面截图描述 执行规则 1. 每一步只能调用一个工具根据工具返回的观察结果决定下一步动作。 2. 操作元素前必须先确认元素存在或页面已加载完成必要时先调用观察类工具。 3. 完成所有操作步骤后使用check_text_present或check_element_visible进行断言。 4. 如果操作失败尝试使用备选选择器或通过文本定位最多重试2次。 5. 全部完成后输出最终结论包括执行步骤摘要、每步结果、断言结果、失败原因分析、via截图文件名。 6. 如果页面出现JS报错必须在最终结论中单独说明。 这里有个容易踩的坑模型在连续操作多次失败后可能陷入死循环。我加了一个最多重试2次的约束并在编排层统计工具调用次数超过12次直接终止本轮操作把已执行步骤作为失败结果输出。任务描述这块我直接让用户写自然语言用例不强求结构化。比如输入打开登录页用admin/123456登录验证跳转到首页且导航栏显示用户昵称。模型会自己拆解步骤。如果你用例特别长可以优化成先用一个文本拆解节点做任务规划再进入执行循环但单阶段Agent对多数场景已经够用了。3.2 推理-行动-观察循环LangChain的create_react_agent会帮我们管理这个循环。我用的模型是支持工具调用的GPT-4o你也可以换Claude或者本地的Qwen等模型只要模型支持function calling就行。初始化Agent的代码如下from langchain_openai import ChatOpenAI from langchain.agents import create_react_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder llm ChatOpenAI( modelgpt-4o, temperature0, max_tokens4096 ) tools [ goto_url, fill_input, click_element, check_element_visible, check_text_present, get_page_errors, take_detailed_screenshot, ] prompt ChatPromptTemplate.from_messages([ (system, SYSTEM_PROMPT), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) agent create_react_agent(llm, tools, prompt) agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, max_iterations12, handle_parsing_errorsTrue, )verboseTrue让我能实时看到模型在想什么。handle_parsing_errorsTrue很重要模型偶尔会输出格式不正确的工具调用这个参数能兜底让重试而不是直接崩溃。3.3 生成测试脚本与回填结果Agent执行完之后我还会加一个复盘步骤。把整个执行轨迹每一步的Action和Observation喂给模型让它生成一份标准的自动化测试脚本和一份测试报告。def summarize_execution(trace: str) - dict: chain ChatOpenAI(modelgpt-4o, temperature0).bind( response_format{type: json_object} ) prompt f 根据以下Agent执行轨迹生成JSON格式的测试报告。 轨迹内容 {trace} JSON格式要求 {{status: 通过/失败, steps: [...], assertions: [...], error: ..., suggestion: ...}} resp chain.invoke(prompt) return json.loads(resp.content)这一步的价值在于把Agent的动态执行沉淀成可复用的静态资产。即使你不打算每次都用Agent跑全量回归生成的脚本也可以作为基线补充到已有的测试框架里。我从实际使用来看Agent生成脚本的可用率在简单流程场景下能达到七八成剩下的细节人工微调一下就好。4. 实战案例登录模块全流程4.1 场景拆解为了让你直观感受这套体系跑起来是什么样我拿一个典型的登录模块来演示。测试用例是这三条case1: 正确账号密码登录跳转首页导航栏显示用户名 case2: 错误密码登录提示账号或密码错误 case3: 空表单直接登录提示请输入账号和密码每一条用例的主流程都可以拆成打开页面、填写表单、触发动作、断言结果四步。传统写法三条用例至少要写十多个方法加上定位符维护。智能体写法只需要把用例文本传给入口函数。4.2 核心代码与运行实录入口函数长这样async def run_test_case(case_desc: str): await browser_session.start() try: result await agent_executor.ainvoke({input: case_desc}) trace result[output] report summarize_execution(trace) # 保存报告和截图 save_report(report, case_desc) finally: await browser_session.stop()跑起来的实时日志大概是这样的 Entering new AgentExecutor chain... Thought: 用户需要登录首先打开登录页面 Action: goto_url Action Input: {url: https://example.com/login} Observation: 已打开登录页页面包含用户登录标题包含账号输入框、密码输入框、登录按钮 Thought: 页面上有两个输入框我需要填充账号和密码 Action: fill_input Action Input: {selector: #username, value: admin} Observation: 已在#username中填入admin Thought: 继续填密码 Action: fill_input Action Input: {selector: #password, value: 123456} Observation: 填充成功 Thought: 点击登录按钮 Action: click_element Action Input: {selector: #loginBtn} Observation: 页面跳转到 https://example.com/dashboard导航栏出现欢迎admin Thought: 已跳转首页且导航栏有用户名断言通过 Action: check_text_present Action Input: {text: 欢迎admin} Observation: 页面包含目标文本欢迎admin Thought: 所有步骤执行成功测试通过 Final Answer: {status: 通过, steps: [..., assertions: [...]], error: null}这个过程中模型自然完成了选择一个合适的方式定位页面元素和失败后的重试。如果第一次点击按钮时页面还没加载好模型会尝试等待或重新执行。4.3 我踩过的三个坑第一个坑模型以为工具执行成功就等于断言通过。有次它填完表单就输出测试通过根本没验证页面是否跳转。后来我在提示词里强约束必须执行至少一次check_text_present或check_element_visible否则判定失败才解决。第二个坑多个相似工具导致模型工具调用混乱。我最初把fill_input拆成了fill_username和fill_password模型反而经常搞混。合并成一个通用工具参数里用selector和value区分反而稳定得多。第三个坑异步循环嵌套炸栈。Agent的ainvoke本身是异步的工具也是异步的如果你在主函数里不小心重复创建了事件循环会报RuntimeError: asyncio.run() cannot be called from a running event loop。统一用asyncio.run()作为最外层入口工具内部不要自己再套asyncio.run()。5. 问题速查与经验沉淀5.1 常见问题排查表我在实际跑了一个多月之后整理了下面这张问题排查表基本覆盖了日常会遇到的大部分坑。现象可能原因解决方法Agent反复调用同一个工具不前进工具返回信息不足模型无法判断下一步增大工具返回值的上下文带出页面当前URL和可见文本选择器定位不到元素前端框架渲染慢或使用Shadow DOM工具里加等待逻辑用wait_for_selector而不是直接query_selector断言结果不稳定异步渲染导致文本出现时序问题用Playwright的expect轮询机制轮询等待目标条件满足模型频繁输出无效格式模型对工具参数理解偏差切换更强的模型或显式在工具描述中补充示例值浏览器实例泄漏内存涨得快没有调用browser.close()每个用例结束后统一关闭用finally块保证清理执行到一半卡死页面弹窗、alert未处理加一个click_element的替代工具来处理对话框或注册dialog.accept事件5.2 让智能体更稳的几条原则第一工具返回的观察结果要够吃。模型不是人它没有视觉除非你接入多模态模型或者把截图转成文字描述。文本信息越充足决策越准确。我自己在工具里返回了一整套页面摘要包括URL、标题、可见按钮和输入框的placeholder文本。这些都是基础步骤省了不行。第二提示词里明确失败后怎么办。让模型遇到定位失败时怎么换路遇到断言失败时怎么取证。没有这个指引模型会一直重试同一个错误操作白白浪费迭代次数。第三限制迭代次数和总时长。我一般设置max_iterations12单个用例最多执行90秒。超过限制直接判定执行异常并保存现场截图。这样即使模型抽风也不会把整个流水线拖死。第四在外面套一层结构化的测试夹具。比如当前被测环境怎么通过账号准备、数据清理怎么处理、测试域名怎么在无痕环境里避免脏数据。这些都是Agent管不了的事情应该在外部由你控制。因为它只负责页面操作不负责数据准备外部做这一层反而让它心智更专注。第五不要指望模型第一次写出的选择器都稳定。好的做法是让Agent同时输出它操作时使用的选择器以及选择器的语义描述比如登录按钮是页面上唯一的红色主要按钮或该输入框位于登录表单内、label为密码。然后你再根据这些语义描述沉淀成稳定定位符回填到常规测试脚本里。这相当于用Agent做了一次自动化的元素勘探。5.3 关于Playwright MCP的一点看法最近Playwright MCP的热度很高很多人问这和直接写Agent有什么区别。我的理解是MCP本质上是给大模型提供了一套标准化的工具访问协议Claude等模型可以通过MCP直接调用Playwright的能力。如果你用的是LangChain的Agent体系那我个人建议直接封装工具函数因为这样你能精确控制工具返回的数据格式和错误处理逻辑。而如果你是在桌面端让AI直接辅助你操作浏览器做一次性探索那MCP更方便。两种路线不冲突。测试智能体要的是在可控环境里按确定性流程反复执行MCP更偏向开放场景下的即兴辅助。我目前的方案最终还是回到了对细粒度工具和不稳定组件行为的明确控制上这才是可工业化的。6. 这套方案的边界与后续扩展方向我也得说清楚这套方案的边界不是所有测试都适合交给智能体。纯接口测试、数据库校验、性能压测这些场景用不上浏览器Agent。UI冒烟测试、端到端流程验证、多浏览器兼容性回归才是它的主场。另外对于页面元素极度动态或者强依赖音视频的场景模型理解起来还是很吃力需要额外做截图转视觉信息或者音频转文字这类预处理成本会高不少。后续我计划做两件事。第一是把Agent执行过程中沉淀下来的稳定选择器自动汇总成页面对象模型减少重复勘探。第二是接入结果审核环节让另一个Agent专门对执行轨迹做代码走查和断言补充相当于测试的测试。这两件事做完整个回归测试的稳定性应该还能再上一个台阶。最后分享一点个人体会别被AI替代测试人员这种话带偏。我在实际使用中最明显的感受是它把测试人员从重复机械的脚本维护里解放出来让注意力重新回到业务风险和用例设计上。智能体跑出来的结果终究还是要人来判断哪些是真正的缺陷、哪些只是测试环境的噪音。工具放大你的效率但关键判断依然在你手里。
RELATED

相关推荐

西门子Teamcenter仿真体系建设:构建自动驾驶研发数字主线

西门子Teamcenter仿真体系建设:构建自动驾驶研发数字主线

简介:本资源系统阐述西门子在自动驾驶与智能网联汽车领域的仿真开发方法论与平台化体系建设路径,面向汽车电子工程师、ADAS/自动驾驶算法开发者、仿真流程架构师及PLM系统实施人员,解决多学科协同难、仿真数据分散、V模型全流程工具链割裂、C…

📅 2026/10/11 19:21:59
4-report-assembler 报告组装器完全指南:zeroize-audit 审计结果汇聚、置信门控与双模式报告生成

4-report-assembler 报告组装器完全指南:zeroize-audit 审计结果汇聚、置信门控与双模式报告生成

AI 技能AI 插件应用安全网络安全AI 评测 【免费下载链接】skills Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows 项目地址: https://gitcode.com/gh_mirrors/skills8/skills 点击查看 免费下载 4-report…

📅 2026/10/11 19:21:59
MacBook Neo传闻解析:苹果如何冲击低价笔记本市场?

MacBook Neo传闻解析:苹果如何冲击低价笔记本市场?

说实话,第一次看到“MacBook Neo”这个传闻的时候,我第一反应是:苹果终于想明白了一件事——光靠 MacBook Air 在八千元以上市场里自嗨,是啃不动教育市场和轻度办公那块大蛋糕的。这个被命名为“Neo”的新产品线,明显就…

📅 2026/10/11 19:21:59
MORE NEWS

更多资讯

📰

Flink/PyFlink CSV读写实战:Schema声明与参数配置避坑

先说个我上个月接手的真实任务:一批传感器历史数据以 CSV 文件存在对象存储里,需要灌进 Flink 流作业做实时指标计算。文件不大,三十来个分区,每分区几万行,字段也就四五个。我当时觉得这是最没技术含量的一步&#xf…

📰

LingBot-World 2.0能商用吗?CC BY-NC-SA 4.0许可证解读:14B权重的使用边界与风险清单

【免费下载链接】lingbot-world-v2 Infinite Worlds with Versatile Interactions 项目地址: https://gitcode.com/gh_mirrors/li/lingbot-world-v2 点击查看 免费下载 LingBot-World 2.0(LingBot-World-Infinity)是一个"以多样化交互生…

📰

响应式实时数据处理:从概念到落地的完整技术链路

1. 从“rea”这个模糊词根说起:它到底指向什么第一次看到“rea”这个标题的时候,我盯着屏幕愣了几秒。没有正文,没有关键词,没有摘要,就孤零零三个字母。这种输入条件放在任何一个技术社区里,都像是有人扔了…

📰

基于YOLOv8的路面裂缝检测系统:中英文双版实战

1. 路面裂缝检测这个方向,为什么值得用YOLOv8重做一遍道路养护这个行当里,裂缝检测一直是个绕不开的活。早些年靠老师傅拿粉笔在路面上画框、拿本子记桩号,后来有了半自动的图像处理工具,但真正让一线养护队头疼的问题始终没变&am…

📰

Portabase数据库恢复教程:如何从备份快照快速找回丢失的数据

【免费下载链接】portabase Portabase - Database backup & restore tool for PostgreSQL, MySQL, MsSQL, MariaDB, Firebird SQL, SQLite, MongoDB, Redis and Docker Volume 项目地址: https://gitcode.com/gh_mirrors/por/portabase 点击查看 免费下载 Por…

📰

cosmos-sdk 系统测试入门:从查询、JSON 断言到 Genesis 与交易驱动的状态测试

区块链 【免费下载链接】cosmos-sdk Framework for building performant, customizable blockchains with native interoperability 项目地址: https://gitcode.com/gh_mirrors/co/cosmos-sdk 点击查看 免费下载 本指南基于 cosmos-sdk 仓库中的 tools/systemtests…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬