🧠 LLM + Harness + Playwright

一个"大脑"、一个"调度员"、一个"手" —— 三者协作,让 AI 真正能操控浏览器、完成复杂任务。用一个故事带你理解它们的分工与协作。

SCENE 01 👤 用户

需求降临

小明是一名测试工程师,他对着屏幕叹了口气:"每天要在后台检查50个页面的UI是否正常、按钮是否可点、表单是否能提交……能不能让AI帮我干?"

"我希望说一句话,AI 就能自己打开浏览器、点击按钮、填写表单、截图对比,然后告诉我哪里有bug。"
SCENE 02 🧠 大语言模型 (LLM)

大脑登场 —— 理解与决策

大语言模型就像团队里的「首席策略师」。它不会自己动手操作浏览器,但它能理解自然语言,把模糊的需求翻译成精确的步骤计划。

🧠 "我明白了。你要我测试登录页面。让我拆解一下:
Step 1 → 打开 https://example.com/login
Step 2 → 在用户名框输入 'admin'
Step 3 → 在密码框输入 'test123'
Step 4 → 点击「登录」按钮
Step 5 → 检查页面是否跳转到 /dashboard
Step 6 → 截图留证"

LLM 的核心价值:把人类的模糊意图,翻译成机器可执行的精确指令。它还能根据页面反馈动态调整策略——比如发现按钮灰了,就换一种操作路径。

SCENE 03 ⚙️ Harness(调度中枢)

调度员登场 —— 编排与中转

Harness 就像「项目经理」「中控台」,它站在 LLM 和 Playwright 之间,负责:

⚙️ "我来翻译一下。LLM 说要'点击登录按钮',但 Playwright 需要的是
await page.click('button[type=submit]')
——这个翻译工作交给我。

另外,Playwright 执行完操作后返回的结果(成功/失败/截图),我也会整理好反馈给 LLM,让大脑做下一步决策。"

Harness 是胶水层(Glue Layer)。它解决了一个关键问题:LLM 输出的是自然语言或JSON指令,而 Playwright 需要的是代码级API调用。Harness 做了双向翻译。

SCENE 04 🎭 Playwright

"手"登场 —— 精准执行

Playwright 就像「机械臂操作员」,它直接控制真实的浏览器——Chrome、Firefox、Safari都可以。

🎭 "收到指令!我现在启动Chromium……
✅ 已打开 https://example.com/login
✅ 已定位到 #username 输入框,填入 'admin'
✅ 已定位到 #password 输入框,填入 'test123'
✅ 已点击 button[type=submit]
✅ 页面跳转到了 /dashboard
📸 截图已保存为 result.png"

Playwright 的能力:像真人一样操控浏览器,但速度更快、更稳定、可并发,而且支持无头模式(headless)——不用打开可见窗口也能跑。

SCENE 05 ⚙️ Harness

闭环反馈 —— 让AI越来越聪明

执行完成后,Harness 把 Playwright 的结果包装好反馈给 LLM:

⚙️ → 🧠 "报告老板:登录操作成功,页面已到达 /dashboard,截图如附。下一步怎么办?"
🧠 "很好。现在检查 dashboard 页面上是否显示了'欢迎, admin'。如果显示了,这条测试用例PASS;否则标记FAIL。"

这就是 Agent Loop(智能体循环)—— LLM 观察、思考、行动、再观察,循环往复,直到任务完成。而 Harness 始终在中间做翻译和调度

用户层 · Human

用自然语言描述需求:"帮我测试一下登录功能有没有bug"、"检查所有商品页的价格显示是否正确"。不需要写代码。

自然语言输入 Chat UI / CLI Prompt

智能层 · LLM (大语言模型)

接收自然语言指令,进行意图理解、任务拆解、生成结构化的操作步骤(如JSON格式的Action列表),并根据执行反馈做出下一步决策。这是整个系统的「大脑」。

GPT-4 / Claude 意图理解 任务拆解 动态决策 自然语言 → JSON Action
JSON Actions ↕ Observation

编排层 · Harness (调度中枢)

核心中间件。向上对接 LLM 的输出(解析JSON指令),向下调用 Playwright API。负责:指令解析、参数映射、错误重试、状态管理、结果格式化、截图管理、上下文拼接后回传给 LLM。

Node.js / Python JSON → API Call 状态机 错误处理 & 重试 上下文管理 Agent Loop
Playwright API ↕ Result

执行层 · Playwright

直接控制真实浏览器引擎(Chromium / Firefox / WebKit)。执行点击、输入、导航、等待、截图、获取DOM等操作,返回精确的执行结果。

Chromium Firefox WebKit click / fill / goto screenshot waitForSelector Headless Mode

浏览器层 · Real Browser

真实渲染的网页,和用户平时看到的完全一样。Playwright 通过 CDP(Chrome DevTools Protocol)等协议与浏览器通信。

Chrome DevTools Protocol DOM Network Console
01

👤 用户输入

"帮我检查 example.com 的登录功能,用admin/test123登录,看看能不能成功跳转。"

02

🧠 LLM 理解 & 拆解

LLM 解析用户意图,输出结构化的 Action 列表:
{ action: "goto", url: "https://example.com/login" }
{ action: "fill", selector: "#username", value: "admin" }
{ action: "fill", selector: "#password", value: "test123" }
{ action: "click", selector: "button[type=submit]" }
{ action: "assert_url", expected: "/dashboard" }

03

⚙️ Harness 解析指令

逐条读取 JSON Action,映射到 Playwright 的具体 API:
gotopage.goto(url)
fillpage.fill(selector, value)
clickpage.click(selector)
同时处理等待策略、超时重试、异常捕获。

04

🎭 Playwright 执行

在真实浏览器中逐步执行操作:打开页面 → 填写表单 → 点击按钮 → 等待跳转 → 截图保存。每步操作都返回成功/失败状态。

05

⚙️ Harness 收集结果

将 Playwright 的执行结果(当前URL、页面标题、DOM变化、截图Base64等)格式化为 LLM 能理解的 Observation 文本。

06

🧠 LLM 判断 & 决策

LLM 收到 Observation,判断:"当前URL包含 /dashboard ✅,任务完成"或者"URL还在 /login ❌,可能密码错了,换一个试试"——然后输出下一步 Action 或最终报告。

07

📋 返回结果

最终生成人类可读的测试报告:✅ 登录成功 / ❌ 登录失败,附带截图、操作日志和建议修复方案。整个过程无需编写一行测试代码。

以下是一个极简示意,展示三者如何在代码层面协作。实际项目中 Harness 会更复杂,包含完整的状态机、重试机制和上下文管理。
harness.js — 调度中枢核心逻辑
const { chromium } = require('playwright');
const { callLLM } = require('./llm-client');

async function agentLoop(userTask) {
  // 1. 启动浏览器 (Playwright)
  const browser = await chromium.launch();
  const page = await browser.newPage();

  // 2. 初始化对话上下文
  let messages = [
    { role: 'system', content: '你是一个浏览器自动化助手...' },
    { role: 'user', content: userTask }
  ];

  // 3. Agent Loop — 循环:思考 → 行动 → 观察
  while (true) {
    // 🧠 LLM 思考下一步
    const llmResponse = await callLLM(messages);
    const action = JSON.parse(llmResponse);

    // 🏁 任务完成?
    if (action.type === 'done') {
      console.log('✅ 报告:', action.summary);
      break;
    }

    // ⚙️ Harness 翻译 → 🎭 Playwright 执行
    let observation;
    try {
      if (action.type === 'goto')
        await page.goto(action.url);
      else if (action.type === 'fill')
        await page.fill(action.selector, action.value);
      else if (action.type === 'click')
        await page.click(action.selector);
      else if (action.type === 'screenshot')
        await page.screenshot({ path: 'result.png' });

      // 收集页面状态作为 Observation
      observation = {
        url: page.url(),
        title: await page.title(),
        status: 'success'
      };
    } catch (err) {
      observation = { status: 'error', message: err.message };
    }

    // ⚙️ 把结果反馈给 LLM
    messages.push({
      role: 'assistant',
      content: JSON.stringify(action)
    });
    messages.push({
      role: 'user',
      content: 'Observation: ' + JSON.stringify(observation)
    });
  }

  await browser.close();
}

// 启动!
agentLoop('请测试 example.com 的登录功能');
关键理解:上面的 while(true) 就是 Agent Loop。每一轮循环里,LLM 思考(输出 Action),Harness 翻译并调用 Playwright 执行,然后把 Observation 反馈给 LLM。如此往复,直到 LLM 认为任务完成。
三者的比喻总结:

🧠 LLM = 大脑(决定"做什么")
⚙️ Harness = 神经系统(翻译"怎么做"、传递信号)
🎭 Playwright = 双手(在浏览器里"真正去做")

三者缺一不可:没有 LLM,系统不能理解人类意图;没有 Harness,LLM 的指令无法到达浏览器;没有 Playwright,一切计划都只是纸上谈兵。