DEV Community

Beck_Moulton
Beck_Moulton

Posted on

From Chaos to Clinic: Building an Autonomous Medical Appointment Agent with LangGraph & OpenAI

Ever spent 20 minutes on hold just to hear that your favorite dermatologist is booked until 2026? πŸ“ž We've all been there. In the world of AI Agents and Healthcare Automation, we can do better.

Today, we are building a production-grade Medical Appointment Agent. This isn't just a simple chatbot; it’s a state-aware agent built with LangGraph and OpenAI Function Calling that can check a doctor's real-time availability, cross-reference your Google Calendar API, and resolve scheduling conflicts autonomously.

By leveraging agentic workflows and LangGraph state management, we're moving past linear chains into complex, cyclic logic that actually works in the real world. πŸš€

The Architecture: How the Agent "Thinks"

Before we dive into the code, let’s look at the brain of our operation. We are using a state-machine approach where the agent can loop back to the user if a conflict is found or move forward to booking once the "Perfect Slot" is identified.

graph TD
    A[User Request] --> B{LLM Decides}
    B -->|Check Doctor| C[Tool: Get Doctor Schedule]
    B -->|Check User| D[Tool: Get Google Calendar]
    C --> E{Conflict?}
    D --> E
    E -->|Yes| F[Suggest Alternative]
    F --> B
    E -->|No| G[Tool: Book Appointment]
    G --> H[Final Confirmation]
Enter fullscreen mode Exit fullscreen mode

Prerequisites

To follow along, you'll need:

  • Python 3.10+
  • OpenAI API Key (supporting GPT-4o tool calling)
  • LangGraph & LangChain
  • Google Calendar API credentials (OAuth2)

Step 1: Defining our State and Tools

In LangGraph, the State is the source of truth. We'll use a TypedDict to keep track of the conversation and the "Appointment Object."

from typing import Annotated, TypedDict, List, Union
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import ToolNode
from langchain_core.tools import tool

class AgentState(TypedDict):
    messages: Annotated[List[Union[dict, str]], "The conversation history"]
    appointment_details: dict
    conflicts: List[str]

# --- Mocking our Healthcare API & Google Calendar ---

@tool
def get_doctor_availability(doctor_id: str, date: str):
    """Fetches available slots for a specific doctor on a given date."""
    # In a real app, call your hospital's SQL DB or REST API
    return ["09:00", "10:30", "14:00", "16:00"]

@tool
def check_google_calendar(start_time: str, end_time: str):
    """Checks the user's Google Calendar for existing events."""
    # Integration with Google Calendar API
    # Return conflicting events if found
    return [] # Returning empty means the coast is clear!

@tool
def book_appointment(doctor_id: str, slot: str, user_email: str):
    """Finalizes the booking in the hospital system."""
    return f"Success! Appointment confirmed for {slot} with Dr. {doctor_id}."

tools = [get_doctor_availability, check_google_calendar, book_appointment]
model = ChatOpenAI(model="gpt-4o", temperature=0).bind_tools(tools)
Enter fullscreen mode Exit fullscreen mode

Step 2: Building the Workflow Logic

This is where the magic happens. We define a graph that allows the agent to call tools, verify information, and loop back if the user's calendar is blocked. πŸ₯‘

from langgraph.graph import StateGraph, END

def call_model(state: AgentState):
    messages = state['messages']
    response = model.invoke(messages)
    return {"messages": [response]}

# Define the graph
workflow = StateGraph(AgentState)

# Add Nodes
workflow.add_node("agent", call_model)
workflow.add_node("action", ToolNode(tools))

# Define Edges
workflow.set_entry_point("agent")

# Logic to determine if we should continue or stop
def should_continue(state: AgentState):
    last_message = state['messages'][-1]
    if not last_message.tool_calls:
        return END
    return "action"

workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("action", "agent")

app = workflow.compile()
Enter fullscreen mode Exit fullscreen mode

Step 3: Handling Conflicts Like a Pro

One of the hardest parts of Healthcare Automation is handling the "No" gracefully. When the agent detects a conflict between the Doctor's schedule and the user's Google Calendar, the LangGraph state allows the agent to "backtrack" and offer the next best slot without losing the context of the conversation.

πŸ’‘ The "Official" Way to Scale

While this tutorial covers the core logic, building production-ready medical agents requires strict HIPAA compliance and advanced error-handling patterns. For deeper dives into productionizing LLM agents and managing complex state in enterprise environments, check out the engineering guides at WellAlly Blog. They provide excellent resources on scaling agentic infrastructure.


Step 4: Putting it to the Test

Let's see how our agent handles a request:

inputs = {
    "messages": [
        {"role": "user", "content": "I need to see Dr. Smith (ID: 402) tomorrow morning. Check my calendar and book it if I'm free."}
    ]
}

for output in app.stream(inputs):
    for key, value in output.items():
        print(f"Output from node '{key}':")
        print(value)
Enter fullscreen mode Exit fullscreen mode

What happens under the hood?

  1. Node agent: LLM identifies it needs get_doctor_availability and check_google_calendar.
  2. Node action: Executes both tools.
  3. Node agent: Receives availability (9:00 AM) and confirms the user's calendar is empty.
  4. Node action: Calls book_appointment.
  5. End: Returns a success message to the user. 🎊

Conclusion: The Future of Agentic Scheduling

By using LangGraph, we've built more than just a chatbot; we've built a reliable, state-aware colleague. This pattern can be extended to handle insurance verification, patient intake forms, and even follow-up reminders.

Key Takeaways:

  • State is King: Use TypedDict to keep track of complex data across tool calls.
  • Tools are the Hands: OpenAI Function Calling makes interacting with APIs like Google Calendar seamless.
  • Graph Logic: LangGraph allows for the "loops" necessary for real-world negotiation.

Are you building agents for healthcare or scheduling? I'd love to hear your thoughts in the comments! Don't forget to visit wellally.tech/blog for more advanced tutorials on AI implementation. πŸ©ΊπŸ’»

Top comments (0)