告别手动刷新:使用 Playwright 和 LLMs 构建 AI 医疗预约代理 🏥🤖

发布: (2026年2月28日 GMT+8 09:15)
6 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容,我将按照要求保留源链接、格式和技术术语,仅翻译文本部分。

介绍

我们都有过这样的经历:凌晨 6:00 醒来,疯狂刷新医院挂号页面,却发现“可预约”时段在毫秒之间变成了“已满额”。传统的自动化脚本常常失效,因为现代网页界面是动态的,充斥着 Shadow DOM,并且受到反机器人措施的保护。

在本教程中,我们将构建一个下一代的 AI Agent 用于 浏览器自动化。通过结合 PlaywrightLLMs(大型语言模型)Redis 的强大能力,我们将创建一个不仅仅是点击按钮的代理——它能够 理解 页面布局,从而执行复杂的医疗预约工作流。如果你一直在关注 LLM 自动化自主代理,本指南适合你。

架构:Agent 如何“观察”和“行动”

不同于依赖脆弱 XPath 的传统 Selenium 脚本,我们的 Agent 使用 LLM 来解释 DOM 结构并决定下一步最佳操作。

graph TD
    A[User Goal: Book Cardiologist] --> B{Agent Brain - LLM}
    B --> C[Playwright: Capture DOM/Screenshot]
    C --> D[State Manager - Redis]
    D --> B
    B --> E[Action: Click/Type/Select]
    E --> F{Success?}
    F -- No --> B
    F -- Yes --> G[Notify User via SMS/Email]

前置条件

  • Python 3.10+
  • Playwright – 可靠端到端测试的现代标准。
  • OpenAI API Key(或任何 LLM 提供商)– 充当代理的大脑。
  • Redis – 用于处理会话持久化和任务队列。

第一步:设置浏览器环境

首先,让我们初始化我们的环境。我们使用 Playwright,因为它比其前身更好地处理异步操作和现代 Web 框架。

import asyncio
from playwright.async_api import async_playwright

async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)  # Keep it visible for debugging
        context = await browser.new_context()
        page = await context.new_page()
        await page.goto(url)

        # Extract only the interactive elements to save token costs
        content = await page.evaluate("() => document.body.innerText")
        await browser.close()
        return content

第2步:LLM “Planner” 逻辑

我们 AutoGPT‑style 代理 的核心是推理循环。我们将简化的 DOM 结构输入到 LLM,并让它生成下一个 Playwright 命令。

import openai

def generate_action(dom_structure, objective):
    prompt = f"""
    You are an expert web automation agent.
    Objective: {objective}
    Current Page Content: {dom_structure}

    Return a JSON object with the 'action' (click, type, wait) and 'selector'.
    """
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

第 3 步:使用 Redis 处理状态 🏎️

在处理高流量的注册期间时,我们需要确保如果脚本重新启动,代理不会执行冗余操作。我们使用 Redis 来缓存当前步骤和会话 Cookie。

import redis

r = redis.Redis(host='localhost', port=6379, db=0)

def save_session_state(user_id, step_data):
    # Store the progress so the agent can resume if blocked
    r.set(f"session:{user_id}", step_data, ex=3600)

def get_current_step(user_id):
    return r.get(f"session:{user_id}")

第 4 步:整体整合(循环)

代理进入循环:它观察页面,决定下一步操作,通过 Playwright 执行动作,并检查是否已达成目标。

async def run_appointment_agent(target_url, goal):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()
        await page.goto(target_url)

        completed = False
        while not completed:
            # 1. Take a “snapshot” of the interactive UI
            ui_elements = await page.query_selector_all("button, input, a")

            # 2. Ask LLM for the next move
            plan = generate_action(ui_elements, goal)

            # 3. Execute action
            if plan['action'] == 'click':
                await page.click(plan['selector'])
            elif plan['action'] == 'type':
                await page.fill(plan['selector'], plan['text'])

            # Check for success condition
            if "Success" in await page.content():
                completed = True
                print("🚀 Appointment secured!")

Going Beyond the Basics: Production Patterns

构建本地脚本很容易,但要将其扩展到处理成千上万的并发注册尝试,则需要复杂的架构模式。您需要处理代理轮换、CAPTCHA 验证以及复杂的重试逻辑。

想获取更多面向生产环境的示例以及在扩展基于 LLM 的代理时的高级模式,我强烈推荐查看 WellAlly Tech Blog。他们提供了精彩的 AI 工程深度解析,帮助我将代理的延迟优化了 40%。

挑战与伦理 🛡️

  • 速率限制 – 始终使用 asyncio.sleep() 来模拟人类行为。
  • 反机器人措施 – 尊重网站服务条款;负责任地使用代理,并考虑法律后果。

使用 playwright-stealth 避免 Cloudflare 检测

  • 伦理:确保在医疗提供者服务条款的法律范围内使用自动化。本项目用于教育目的,展示 AI Agents 如何简化复杂的 UI 交互。

结论

通过从硬编码选择器转向 LLM 驱动的推理循环,我们创建了一个能够抵御 UI 变化并能够处理复杂“仅限人类”工作流的代理。

接下来怎么办?
您可以集成视觉模型(如 GPT‑4o),实际“看到”屏幕而不是解析 DOM,从而使其更加稳健。

**您在构建浏览器代理吗?在评论区聊聊吧! 👇

0 浏览
Back to Blog

相关文章

阅读更多 »

当工作成为心理健康风险时

markdown !Ravi Mishrahttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...