Have you ever hesitated to let an AI agent actually do something? I have. It's one thing to have an AI draft an email or summarize a document. It’s a whole different ball game to give it permission to book flights, spend money, or modify a database.
There's this "black box" problem. The AI takes your request, does… something… and spits out a result. You have no idea what it was thinking or what steps it took. Giving an agent like that real-world tools feels a bit like handing your car keys to a brilliant but unpredictable stranger.
But what if we could change that? What if, instead of a mysterious oracle, the AI acted more like a transparent teammate? Imagine you ask a new assistant to book a trip. You wouldn't just say, "Book a trip to Istanbul," and hope for the best. You'd expect them to come back with a plan first: "Here are the flights I found, the hotel I've picked, and a rough itinerary. Does this look good to you?"
Only after you give the thumbs-up would they actually go and book everything. That’s the exact kind of trustworthy, collaborative AI we're going to build today. We're going to create an agent that first plans its actions, then deliberately pauses to ask for your permission, and only executes when you give the green light. We’ll use two fantastic tools to pull this off: LangGraph for the workflow logic and Streamlit for the user-friendly interface.
Let's get started.
The Big Idea: Plan, Pause, and then Execute
The core concept here is simple but powerful. We're breaking the AI's process into three distinct steps:
- Plan: The AI takes your request (e.g., "Plan a 5-day trip to Istanbul") and thinks through the problem. Instead of taking immediate action, it drafts a structured plan of what it intends to do. This includes which tools it wants to use, like a flight search or a hotel finder.
- Approve (The Human-in-the-Loop): This is the magic step. The AI stops dead in its tracks and shows you its plan. It doesn't proceed until a human—that's you—reviews the plan, maybe tweaks it a little, and gives explicit approval.
- Execute: Only after getting your "go-ahead" does the agent actually run the tools and perform the actions it proposed.
This "Plan-Approve-Execute" model transforms the agent from an autonomous black box into a controllable, transparent partner. You're always in the driver's seat.
Setting Up Our Workshop
First things first, we need to get our environment ready. This is like laying out all your tools on the workbench before you start building. We'll need a few key Python libraries: LangGraph, OpenAI's library, Streamlit, and Pydantic.
We also need to handle our OpenAI API key securely. You never want to paste your secret keys directly into your code. A good practice, which we'll use here, is to have the script ask for it when it runs. This keeps it safe and out of sight.
Think of this step as just the necessary prep work. It’s not the exciting part, but it ensures everything that follows will run smoothly.
Giving Our Agent Some "Skills" (Defining the Tools)
An agent is only as useful as the tools it can use. For our travel agent, we'll give it three basic skills:
tool_search_flights: Finds flight options based on origin, destination, dates, and budget.tool_search_hotels: Looks for hotels based on city, length of stay, and preferences.tool_build_day_by_day: Drafts a simple daily itinerary.
Now, for this tutorial, these tools are just simple Python functions that return realistic-looking fake data. But here's the important part: you could easily swap these out to call real-world APIs like Skyscanner, Booking.com, or Google Maps. The logic of our agent wouldn't have to change at all.
We're designing these tools to be predictable and return structured data (in this case, a JSON format). This is crucial because it makes their output easy for both the AI and us humans to understand.
Teaching the Agent How to Think in a Structured Way
This is where things get really interesting. We don't want our AI just rambling about a travel plan. We want it to think in a structured, organized way. To enforce this, we'll use a Pydantic BaseModel.
Think of it like giving your assistant a very specific form to fill out for every trip request. The form has fields for "Trip Title," "Origin," "Destination," "Budget," and so on. It even has a special section called tool_calls, where the agent must list exactly which of its "skills" it plans to use.
By forcing the AI to output its plan in this rigid JSON format, we achieve two things:
- Clarity: We know exactly what to expect from the AI's output. No surprises.
- Control: The
tool_callslist is a clear declaration of intent. We can see precisely what the agent wants to do before it does it.
We then create a function that sends our request to an LLM (like GPT-4) along with instructions to fill out this "form." This function is the "Plan" step of our workflow.
Building the Workflow with LangGraph
Okay, now let's assemble our three-step process using LangGraph. LangGraph is perfect for this because it lets us define our agent's workflow as a graph of nodes, or steps.
Our graph is beautifully simple:
planNode: This is our starting point. It takes the user's request and calls the LLM to generate the structured travel plan we just talked about.approveNode: After the plan is created, the workflow moves here. This node does something special: it interrupts the graph. It essentially hits the pause button and waits for human input. This is the heart of our "human-in-the-loop" design.executeNode: This node only runs after a human has resumed the graph from theapprovenode. It checks if the plan was approved. If yes, it runs the tools listed in thetool_callssection. If not, it does nothing.
Connecting these nodes in a sequence (plan → approve → execute) creates our entire trustworthy workflow. The interrupt is the key feature from LangGraph that makes this whole thing possible. It’s our built-in "stop and ask for permission" mechanism.
Bringing It to Life with a Streamlit UI
A workflow that pauses is great, but how does the human actually interact with it? That's where Streamlit comes in. Streamlit makes it incredibly easy to build simple web apps in Python.
We'll build a dashboard with a few key components:
- A text box for you to type in your travel request.
- A button to "Generate Plan." Clicking this kicks off the LangGraph workflow, which runs until it hits the
approveinterrupt. - A display area where the agent’s proposed plan (the JSON file) shows up. We'll even make it editable, so you can tweak the budget or change the destination right there in the interface.
- "Approve" and "Reject" buttons.
- A "Resume" button. After you've made your decision, clicking this sends your approval (and any edits) back into the LangGraph workflow, allowing it to proceed to the
executenode. - Finally, a results area that shows you the output from the tools after they've run.
This simple interface bridges the gap between the agent's internal process and the user. It makes the agent's reasoning visible and gives you a concrete way to provide feedback and control.
Why This Pattern Is a Game-Changer
So, we've built a cool travel agent. But the underlying pattern here is so much bigger than just booking trips. This "Plan-Approve-Execute" model is a fundamental recipe for building responsible AI systems in any field where the stakes are high.
Think about it:
- Finance: An agent that proposes a set of trades but waits for a portfolio manager's approval before executing.
- Healthcare: An AI that suggests a patient treatment plan based on medical records, which a doctor must review and sign off on.
- Marketing: An agent that drafts an entire email campaign and ad budget but waits for a marketer to approve it before going live.
By putting a human in the loop at the most critical moment—right between planning and action—we build systems that are not just powerful, but also safe, accountable, and trustworthy. We move from hoping the AI gets it right to ensuring it does.
We're not just building tools anymore; we're building collaborators. And that, to me, is a much more exciting future for AI.




