Skip to main content

Command Palette

Search for a command to run...

Building Agent with litellm - Travel Desk Agent as example

Published
4 min read

Building a Travel Desk Agent using LiteLLM.

This guide helps create a functional agent capable of "using tools" to search for flights and hotels—the core requirement for a travel desk.

Why LiteLLM?

LiteLLM is ideal for this because it provides a unified interface. You can write your agent code once and switch between OpenAI, Anthropic, Azure, or Google models just by changing a string.


Step 1: Setup and Installation

First, install the library.

pip install litellm

You will need an API key. We will use OpenAI for this example, but LiteLLM supports 100+ providers.

import os
# Replace with your actual key or load from a .env file
os.environ["OPENAI_API_KEY"] = "sk-..."

Step 2: Define Your "Real World" Tools

A travel agent needs access to data. LLMs cannot browse live flight data by default, so we use Function Calling. We define:

  1. The Python Function: The code that actually fetches data (mocked for this tutorial).

  2. The Tool Schema: A JSON definition telling the LLM how to use the function.

import json

# --- 1. Python Implementations (Mock Data) ---
def search_flights(origin, destination, date):
    """Mock function to search for flights."""
    if "london" in destination.lower():
        return json.dumps({"airline": "British Airways", "price": "600 USD", "duration": "7h"})
    elif "paris" in destination.lower():
        return json.dumps({"airline": "Air France", "price": "550 USD", "duration": "8h"})
    else:
        return json.dumps({"error": "No flights found for this route."})

def search_hotels(city, check_in):
    """Mock function to search for hotels."""
    return json.dumps([
        {"name": "Grand Hotel", "price": "200 USD/night", "rating": 4.5},
        {"name": "Budget Inn", "price": "80 USD/night", "rating": 3.0}
    ])

# Map function names to the actual python callables
available_functions = {
    "search_flights": search_flights,
    "search_hotels": search_hotels,
}

# --- 2. Tool Schema (OpenAI Format) ---
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_flights",
            "description": "Finds flight options between cities.",
            "parameters": {
                "type": "object",
                "properties": {
                    "origin": {"type": "string"},
                    "destination": {"type": "string"},
                    "date": {"type": "string"},
                },
                "required": ["origin", "destination", "date"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_hotels",
            "description": "Finds hotels in a specific city.",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string"},
                    "check_in": {"type": "string"},
                },
                "required": ["city", "check_in"]
            }
        }
    }
]

Step 3: The Agent Loop (The Brain)

This is the most critical part. We need a loop that allows the model to:

  1. Receive user input.

  2. Decide if it needs to use a tool.

  3. If yes: Execute the tool and feed the result back to itself.

  4. If no: Answer the user.

Here is the complete, runnable script:

from litellm import completion

def run_travel_agent():
    # System prompt defines the persona and behavior
    messages = [{
        "role": "system", 
        "content": (
            "You are a helpful Travel Desk Agent. "
            "Use the provided tools to find flights and hotels when asked. "
            "If you need more details (like dates or cities), ask the user politely. "
            "Summarize options clearly."
        )
    }]

    print("✈️  Travel Desk Agent Initialized. (Type 'quit' to exit)")

    while True:
        user_input = input("\nUser: ")
        if user_input.lower() in ["quit", "exit"]:
            break

        # Append user message to history
        messages.append({"role": "user", "content": user_input})

        # 1. First Call: Send history + tools to the LLM
        response = completion(
            model="gpt-3.5-turbo",  # Change to "anthropic/claude-3-opus" etc. as needed
            messages=messages,
            tools=tools,
            tool_choice="auto",
        )

        response_msg = response.choices[0].message
        tool_calls = response_msg.tool_calls

        # 2. Check if the model wants to call a tool
        if tool_calls:
            # Add the model's "intent" to call a tool to history
            messages.append(response_msg)

            print(f"🤖 (Agent is consulting external tools...)")

            for tool_call in tool_calls:
                function_name = tool_call.function.name
                function_args = json.loads(tool_call.function.arguments)

                # Execute the actual Python function
                function_to_call = available_functions.get(function_name)
                if function_to_call:
                    function_response = function_to_call(**function_args)

                    # Add the "Result" to history so the model sees it
                    messages.append({
                        "tool_call_id": tool_call.id,
                        "role": "tool",
                        "name": function_name,
                        "content": function_response,
                    })

            # 3. Second Call: Get the final natural language response
            # The model now sees: User Input -> Its own tool call -> The Tool Result
            final_response = completion(
                model="gpt-3.5-turbo",
                messages=messages
            )
            agent_reply = final_response.choices[0].message.content

        else:
            # Model didn't use a tool, just replied normally
            agent_reply = response_msg.content

        # Add final answer to history and print
        messages.append({"role": "assistant", "content": agent_reply})
        print(f"Agent: {agent_reply}")

if __name__ == "__main__":
    run_travel_agent()

How to use this Agent

  1. Run the script.

  2. Ask incomplete questions:

    • You: "I want to go to London."

    • Agent: "I can help with that! Where are you flying from and when do you plan to travel?" (It won't call the tool yet because it knows it needs parameters).

  3. Ask complete questions:

    • You: "I want to fly from NYC to London on May 5th."

    • Agent: (Calls search_flights) "I found a flight with British Airways for 600 USD..."

Advanced: Changing Providers

The power of LiteLLM is that you can switch the intelligence behind your agent easily.

To use Anthropic's Claude, for example:

  1. Set os.environ["ANTHROPIC_API_KEY"] = "sk-ant..."

  2. Change the model string in the completion calls:

     model="anthropic/claude-3-5-sonnet-20240620"
    

Everything else (the loop, the tool schemas, the message history) remains exactly the same.