{"slug": "tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright", "title": "Tired of Refreshing? Building a Smart Medical Appointment Agent with Playwright and LLM Function Calling 🏥🤖", "summary": "A developer built an AI agent that combines Playwright Python with LLM function calling to automate medical appointment booking on clunky hospital portals. The agent uses a ReAct pattern to observe page state, reason with an LLM, and execute actions via Playwright, making it more resilient than traditional browser automation scripts. The system also leverages Redis for session caching and queue management in high-concurrency scenarios.", "body_md": "We’ve all been there: waking up at 6:00 AM, frantically refreshing a hospital’s booking page, only to find that the \"Expert Specialist\" slots vanished in milliseconds. Traditional **browser automation** often fails here because hospital portals are notoriously clunky, filled with dynamic pop-ups, and inconsistent UI layouts.\n\nIn this guide, we are going to build a next-generation **AI Agent** for **intelligent task automation**. By combining the raw power of **Playwright Python** with **LLM Function Calling**, we’ll create a system that doesn't just \"click\" but \"understands\" the appointment flow. This approach moves us from brittle CSS selectors to resilient, reasoning-based automation.\n\nUnlike traditional scripts that break when a button's ID changes from `submit-01`\n\nto `btn-confirm`\n\n, our agent uses a **ReAct (Reason + Act)** pattern. It observes the page, sends the simplified HTML/Accessibility tree to the LLM, and decides which tool to use next.\n\n``` php\ngraph TD\n    A[User Request: Book Dr. Smith] --> B{Agent Controller}\n    B --> C[LLM Reasoning Engine]\n    C -->|Decides Tool| D[Playwright Executor]\n    D -->|Interaction| E[Hospital Portal]\n    E -->|Page Content/Screenshot| D\n    D -->|Observation| B\n    B -->|State Storage| F[(Redis)]\n    C -->|Final Confirmation| G[User Notified]\n```\n\nTo follow this advanced tutorial, you'll need:\n\nWe need to give our LLM \"hands.\" We do this by defining functions that Playwright will execute. The LLM won't write code; it will output JSON matching our function signatures.\n\n``` python\nimport asyncio\nfrom playwright.async_api import async_playwright\n\nclass MedicalAgentTools:\n    def __init__(self, page):\n        self.page = page\n\n    async def navigate_to_department(self, dept_name: str):\n        \"\"\"Navigates to a specific hospital department link.\"\"\"\n        links = await self.page.get_by_role(\"link\").all()\n        for link in links:\n            text = await link.inner_text()\n            if dept_name in text:\n                await link.click()\n                return f\"Successfully navigated to {dept_name}\"\n        return \"Department not found.\"\n\n    async def fill_patient_info(self, name: str, id_number: str):\n        \"\"\"Fills the appointment form with patient details.\"\"\"\n        await self.page.fill('input[placeholder=\"Patient Name\"]', name)\n        await self.page.fill('input[name=\"id_card\"]', id_number)\n        return \"Patient info filled successfully.\"\n```\n\nThe core logic involves sending the current page \"state\" (a simplified DOM) to the LLM. We use **LLM Function Calling** to let the model choose between navigating, filling forms, or solving a CAPTCHA.\n\n``` python\nimport openai\n\nasync def run_agent_step(agent_tools, user_prompt):\n    messages = [\n        {\"role\": \"system\", \"content\": \"You are a medical booking assistant. Use tools to complete the user's request.\"},\n        {\"role\": \"user\", \"content\": user_prompt}\n    ]\n\n    # Define the tools for OpenAI\n    tools = [\n        {\n            \"type\": \"function\",\n            \"function\": {\n                \"name\": \"navigate_to_department\",\n                \"parameters\": {\n                    \"type\": \"object\",\n                    \"properties\": {\"dept_name\": {\"type\": \"string\"}}\n                }\n            }\n        }\n        # ... other tools\n    ]\n\n    response = await openai.chat.completions.create(\n        model=\"gpt-4o\",\n        messages=messages,\n        tools=tools\n    )\n\n    # Execute the function call via Playwright\n    # (Implementation of tool execution logic goes here)\n```\n\nIn high-concurrency scenarios (like when a doctor’s schedule opens), you don't want to spawn 1000 browsers. We use **Redis** to cache session cookies and manage a queue of booking requests to prevent IP bans.\n\n``` python\nimport redis\n\nr = redis.Redis(host='localhost', port=6379, db=0)\n\nasync def save_session(context):\n    state = await context.storage_state()\n    r.set(\"medical_session_user_1\", str(state))\n\nasync def load_session(context):\n    state = r.get(\"medical_session_user_1\")\n    if state:\n        await context.add_cookies(eval(state)['cookies'])\n```\n\nWhile this script works for personal use, scaling AI-driven automation for enterprise healthcare or high-traffic systems requires robust error handling, proxy rotation, and advanced DOM parsing.\n\nFor more production-ready patterns and deep dives into AI Agent design, I highly recommend checking out the technical deep-dives at ** WellAlly Blog**. They cover advanced topics like \"Multi-Agent Orchestration\" and \"Long-context DOM Processing\" which were the inspiration for this architecture. 🥑\n\nBy combining **Playwright**'s reliability with **LLM Function Calling**, we've built a system that handles the unpredictability of modern web UIs. This \"Agentic\" approach is the future of **Intelligent Task Automation**, turning complex, multi-step workflows into simple natural language prompts.\n\n**What's next?**\n\n**Did you find this helpful?** Drop a comment below if you've tried building agents for web automation! 🚀💻", "url": "https://wpnews.pro/news/tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright", "canonical_source": "https://dev.to/wellallytech/tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright-and-llm-function-69j", "published_at": "2026-07-26 01:20:00+00:00", "updated_at": "2026-07-26 01:31:23.611112+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models", "machine-learning"], "entities": ["Playwright", "OpenAI", "Redis", "GPT-4o"], "alternates": {"html": "https://wpnews.pro/news/tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright", "markdown": "https://wpnews.pro/news/tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright.md", "text": "https://wpnews.pro/news/tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright.txt", "jsonld": "https://wpnews.pro/news/tired-of-refreshing-building-a-smart-medical-appointment-agent-with-playwright.jsonld"}}