Tool Calling at Scale: Orchestrating AI Travel Searches
Our AI agent uses a comprehensive suite of tools to search flights, check hotels, and process payments. Here is how we designed, orchestrated, and hardened tool calling.

The thing that separates a useful AI agent from a fancy autocomplete is tool calling. A language model that can only generate text is limited to talking about flights. A language model that can call tools can actually search for flights, check prices, and process bookings. The text generation is the interface. The tool calling is where value gets created.
At Nowah, our AI agent manages a comprehensive suite of tools spanning flight search, hotel search, booking execution, payment processing, itinerary generation, traveler profile management, visa checking, currency conversion, and more. Orchestrating all of that reliably, quickly, and within a conversational flow is the hardest engineering problem we've solved. Here's how.
What tool calling actually is

If you haven't built with AI tool calling before, here's the short version. You define a set of functions that the AI model can invoke. Each function has a name, a description, and a parameter schema. When the model processes a user message, it can decide to call one or more of these functions instead of (or in addition to) generating text.
The model outputs a structured tool call with the function name and arguments. Your application executes the function with those arguments, gets a result, and feeds that result back to the model. The model then uses the result to generate its response to the user.
Simple in concept. Complex in practice. The model has to decide WHICH tools to call from a large set, construct the right parameters from ambiguous natural language, handle results that might be errors or empty sets, and chain multiple tool calls together when needed. All of this happens within a conversation where the user expects near-instant responses.
What makes travel especially challenging is that tool calls have real costs and real consequences. A flight search costs money (providers charge per API call). A booking tool call moves real money. A payment tool call charges a real credit card. This isn't a sandbox. Every tool invocation has stakes, which means every misrouted or unnecessary tool call is waste.
Designing a large tool suite without overwhelming the model
More tools means more capability, but it also means more opportunity for the model to pick the wrong one. If you have fifteen tools, the model can usually figure out which one to use. When you have a comprehensive suite spanning dozens of functions, you need to think carefully about organization.
We approach this in three ways.
First, naming and description engineering. Every tool has a name that clearly communicates its purpose and a description that specifies exactly when to use it and what it returns. We treat tool descriptions like API documentation for an AI consumer. Vague descriptions lead to wrong tool selection. Vague descriptions lead to wrong tool selection. A precise description of inputs, outputs, and when to use the tool is much better.
We've found that spending an extra hour on a tool description saves days of debugging misrouted tool calls. The description is the contract between you and the model. If the contract is ambiguous, the model's behavior will be ambiguous too.
Second, taxonomy. We group tools into a small number of domains and keep naming consistent so the model can reason by category before picking a specific tool. If the user mentions flights, the model can quickly narrow to flight-related tools without considering hotel or payment tools.
Third, context-aware availability. Not every tool is relevant for every conversation turn. When a user is in the early search phase, booking tools aren't needed. When they're mid-payment, search tools aren't relevant. We only expose tools that are relevant to the current stage of the trip. This reduces the decision space and improves selection accuracy.
For example, early turns emphasize discovery; booking tools appear when the traveler is ready to commit; trip-management tools appear after confirmation. Keeping the active tool set focused reduces wrong-tool selection.
The result: the agent streams its first response tokens within a couple of seconds even with the full tool suite available. Tool selection accuracy stays high because the model has clear signals about which tool to use and when.
Parallel vs. sequential tool execution

Some tool calls need to happen one after another. You can't book a flight before searching for one. You can't process payment before the user selects an option.
But other tool calls can run in parallel. If a user says "Find me flights to Paris and check hotel prices near the Eiffel Tower," we can dispatch the flight search and hotel search simultaneously. The results come back independently and get synthesized into one response.
Parallel execution matters a lot for latency. Travel APIs are slow. A flight search might take two to four seconds. A hotel search might take another two to four seconds. If you run them sequentially, that's four to eight seconds of dead air. If you run them in parallel, it's two to four seconds total. That difference is the line between a conversation that flows and one that drags.
We make the parallelism decision at the orchestration layer, not the model layer. The model says "I need these tools called." Our orchestration system analyzes the dependency graph between the requested tools, runs independent work concurrently where it is safe. It collects the results and feeds them all back to the model at once.
This sounds straightforward but the edge cases are messy. What if the first parallel call fails and the second succeeds? We present partial results: "I found flights but had trouble with hotel search. Here are the flight options while I try hotels again." What if one call is slow and the other is fast? We stream the fast results first and update when the slow one completes. What if the model's tool call parameters for the second tool actually depend on results from the first, but the model didn't realize that? We detect the dependency and force sequential execution.
If one call depends on another, we run them in order. If one fails, the others can still finish, and the model works with partial results. Users see progress rather than a blank wait.
Error handling when tools fail mid-conversation
This is where most AI agent implementations fall apart. The happy path is easy. User asks for flights, tool returns results, model presents them. But what happens when the tool call fails?
In a traditional application, you'd show an error modal. In a conversation, the AI has to explain what happened in natural language and figure out what to do about it. "Something went wrong" is not an acceptable response.
We categorize tool failures into three types with different recovery strategies.
Transient failures are things like network timeouts, rate limits, and temporary API outages. The strategy here is automatic retry with exponential backoff. The user sees "Let me search again..." and usually the retry succeeds. We cap retries at three attempts to avoid infinite loops. The retry happens inside the tool execution layer, invisible to the model. The model only sees the final result (success after retry) or the final failure.
Permanent failures are things like invalid routes (no flights exist between these two cities), sold-out inventory, or unsupported operations. No amount of retrying will fix these. The agent needs to explain the situation and suggest alternatives. "There are no direct flights from Austin to Reykjavik on that date. Want me to check connecting flights, or try nearby dates?" The key insight is that permanent failures need alternative suggestions, not just error messages.
Partial failures are the trickiest. The flight search returned results but the price check for one option failed. Or the search returned three pages of results but the API timed out after two. Or the booking succeeded but the seat assignment didn't go through. The agent needs to present what it has while being transparent about what's incomplete. "I found two great options. I'm still checking a third one that looked promising."
For each failure type, we have explicit recovery paths in the orchestration layer. The model doesn't have to figure out error recovery from scratch every time. It gets structured context about what failed, why, and what the recommended recovery options are. Then it translates that into natural language for the user.
Travel API per-search pricing makes unnecessary tool calls a direct cost. Every failed call that triggers a retry is money spent. Our error handling investment pays for itself by reducing wasted API calls and improving first-attempt success rates.
How the agent decides which tools to call
This is the part that feels a bit like magic but is actually a well-engineered decision pipeline.
When a user message arrives, the model processes it in the context of the full conversation history, the user's profile and preferences (from agentic memory), and the available tool definitions. It then outputs either a text response, one or more tool calls, or both.
The decision about what to do isn't hardcoded. We don't have an if-else chain that says "if the user mentions flights, call the flight search tool." The model reasons about intent, context, and tool availability to make its choice. This is what makes the experience feel conversational rather than menu-driven.
But we do provide the model with structured guidance. The model is given high-level guidance about when to act versus when to clarify. when to ask for clarification, when to present results vs. when to refine, when to suggest alternatives vs. when to proceed with the user's exact request. These heuristics act as guardrails without being rigid rules.
For example: "If the user provides a destination but no dates, ask about dates before searching." "If the user says 'cheap,' interpret based on their historical booking data if available, otherwise use the median fare for the route." "If a search returns zero results, suggest alternative dates, airports, or routes before giving up."
We also monitor tool-calling patterns in production. If we see the model frequently selecting the wrong tool for a particular type of query, we update the tool description or add a heuristic. This is a continuous improvement loop. Every conversation teaches us something about how to make tool selection better.
Benchmarking tool-call accuracy
We maintain a comprehensive eval suite specifically for tool-calling quality. The suite includes hundreds of test conversations covering:
Flight searches with varying complexity (simple one-way, round-trip, multi-city, flexible dates). Hotel searches with subjective criteria ("cozy," "trendy," "near the beach"). Mixed requests that require multiple tools in sequence or in parallel. Edge cases like ambiguous destinations, impossible routes, and nonsensical requests. Adversarial inputs designed to trick the model into calling the wrong tool or leaking data.
For each test case, we evaluate: Did the model call the right tools? Did it construct the right parameters? Did it handle errors gracefully? Did the final response accurately reflect the tool results? Was the response natural and helpful?
We run this suite on every significant change to the agent. Model updates, tool description changes, instruction updates, new tool additions. If any eval score drops below our threshold, the change doesn't ship. The team that evaluates best ships best. Without rigorous evals, tool-calling regressions are invisible until users complain, and by then you've already lost trust.
Adding new tools without regression
As the product grows, we add new tools. A currency converter. A visa requirement checker. A travel advisory lookup. A weather forecast tool. Each new tool increases capability but also increases the risk that existing tool selection breaks.
Our approach is to treat each tool addition like a library API change. We write evals for the new tool before building it. We verify that existing evals still pass after the new tool is added. We monitor production tool-calling patterns for the first week after launch to catch any unexpected behavior.
We also keep the tool interface contract consistent. Every tool returns results in the same structure: success or failure, a data payload, and optional metadata. The model knows what to expect from any tool call regardless of what the tool does internally. This consistency reduces the cognitive load on the model and makes it easier for us to add tools without changing the orchestration layer.
Caching and prompt optimization have meaningfully reduced inference cost over time. Part of that is caching tool results (a flight search for the same route within a short window returns cached results instead of hitting the provider API again). Part of it is optimizing how we present tool results to the model so it needs fewer tokens to process them. Part of it is the contextual tool filtering that reduces the number of tool definitions the model needs to process on each turn.
What this means for AI-native products generally
Tool calling is the bridge between AI that talks and AI that works. If you're building an AI-native product in any domain, the quality of your tool-calling architecture determines the quality of your product.
The patterns we've developed, clear tool taxonomy, parallel execution with dependency analysis, typed error recovery, continuous eval suites, progressive tool additions with regression testing, these aren't specific to travel. They apply to any AI agent that needs to interact with external systems.
What IS specific to travel is the combination of complexity (dozens of providers, real-time pricing, multi-step transactions) and stakes (real money, real bookings, real consequences for getting it wrong). That combination forced us to engineer tool calling to a level of reliability that simpler applications might not need.
The AI agent responds with streamed content within a couple of seconds. That number represents a massive amount of optimization across tool selection, parallel execution, caching, and response synthesis. It's the number that makes conversation feel like conversation instead of a slow terminal. And behind that two seconds is a tool-calling architecture that's been tested, evaluated, and hardened across thousands of real conversations.
Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. Plan your next trip.