Content: Applied Solution Showcase
Planning a trip sounds exciting, but the reality is usually stressful. Before you ever board a plane, you’re juggling dozens of questions:
What’s the weather like when I’ll be there?
Do I need a visa or any special documents?
Which neighborhoods are safe and convenient?
How do I fit in all the must-see spots without running out of time (or energy)?
How much will it actually cost once I add up flights, hotels, food, and activities?
And after all that, which booking site has the best deal?
Most of us end up bouncing between endless tabs—Google searches, weather sites, airline apps, hotel reviews, currency converters—just to piece together something that looks like a plan. It’s time-consuming, overwhelming, and easy to miss important details.
Travel agencies try to make this easier, but their process is often manual and slow. On the flip side, existing travel apps usually focus on just one thing—like booking flights or showing top attractions—without pulling the whole picture together in a way that feels truly personal.
This is where the Multi-Agent Travel Planner comes in. Instead of one person (or one app) doing it all, specialized AI agents team up—one for research, one for building your itinerary, another for budgeting, another for booking—and then combine their work into a single, clear travel brief. The goal is simple: take the hassle out of planning so you can spend less time stressing over logistics and more time looking forward to your trip.
To run and contribute to the Multi-Agent Travel Planner, you’ll need the following tools, services, and environment configurations:
(all dependencies are pinned in requirements.txt / setup.cfg)
Required keys/flags in .env:
OPENAI_API_KEY=your-openai-key LANGCHAIN_API_KEY=your-langsmith-key (optional) # General settings ENVIRONMENT=development LOG_LEVEL=INFO DEBUG=false # Security settings RATE_LIMIT_PER_MINUTE=60 MAX_INPUT_LENGTH=10000 ENABLE_CONTENT_FILTERING=true # Feature flags ENABLE_CACHING=true ENABLE_ASYNC_PROCESSING=true ENABLE_METRICS=true
Local Development: Docker Compose (docker/docker-compose.yml)
Production:
- AWS – ECS, EKS, or Lambda
- GCP – Cloud Run or GKE
- Azure – AKS or Container Instances
- Monitoring: Prometheus-compatible metrics + structured logging
CI/CD (optional): GitHub Actions, Jenkins, or similar
The Multi-Agent Travel Planner follows a modular, layered architecture with specialized agents, core orchestration, custom tools, and multiple user interface options.
Streamlit UI (streamlit_app.py) → Modern, interactive interface for end users - production environment
Gradio UI (gradio_app.py) → interface with a simple dashboard - dev environment
FastAPI Backend (api/) → Exposes REST APIs for integration with external apps
Supervisor Agent (graph/supervisor.py)
Workflow Engine (graph/workflow.py)
Each agent focuses on one core responsibility:
Research Agent (agents/research.py) → Destination info, weather, visa, transport
Itinerary Agent (agents/itinerary.py) → Day-by-day travel plan
Budget Agent (agents/budget.py) → Cost breakdowns, currency conversion
Booking Agent (agents/booking.py) → Suggests flights, hotels, transport
Finalizer Agent (agents/finalizer.py) → Merges all results into a concise travel brief
Semantic Search Integration:
Uses vector embeddings (via LangChain’s retrievers) to rank and retrieve the most relevant travel knowledge (visa requirements, weather patterns, destination guides).
Allows contextual retrieval: e.g., instead of keyword “Japan visa”, it can interpret “Do I need special documents to enter Tokyo in October?”
Custom external service integrations:
Weather Tool (tools/weather.py) → Fetches real-time weather via Open-Meteo
Foreign Exchange Tool (tools/foreign_exchange.py) → Currency conversion via Frankfurter API
Bookings Tool (tools/booking.py) → (extensible) for flight/hotel search
Handles cross-cutting concerns:
Configuration (core/config.py) → Loads environment-specific settings
Security (core/security.py) → Input validation, sanitization, rate limiting
Logging (core/logging.py) → Structured logging with correlation IDs
Error Handling (core/error_handler.py) → Centralized exception handling & recovery
Monitoring (utils/monitoring.py) → Health checks, metrics, Prometheus integration
Our project is production-grade because testing is built in at every level:
- Unit Tests (194+) → Validate each agent, tool, and utility in isolation
- Example: Research agent returns correct visa info from knowledge base
- Integration Tests → Ensure agents communicate properly via LangGraph workflows
- Example: Research → Itinerary → Budget pipeline correctness
- End-to-End (E2E) Tests → Test full user journey via Gradio/Streamlit UIs
- Example: User query → orchestrated multi-agent workflow → final travel brief JSON/UI output
Coverage Reports (71% achieved) → Helps track untested paths & reliability
Continuous Testing in CI/CD → Every commit triggers pytest with coverage & linting
Travel Request (required): Natural language trip description
Optional Preferences:
Budget, travel dates, origin city
Interests (food, culture, shopping, etc.)
Group size (adults/children)
Constraints (accommodation type, dietary needs, safety)
Trip Snapshot: Destination, dates, travelers, budget
Itinerary: Day-by-day plan with activities & meals
Budget Breakdown: Flights, hotels, food, transport, misc.
Booking Suggestions: Flight & hotel options with pros/cons
Quick Tips: Weather, safety, transit, payments
API Response: Structured JSON (for integrations)
All agents inherit from a common ToolUsingAgent
base class that provides:
class ToolUsingAgent: def __init__(self, agent_type, name, system_prompt, tools, temperature, timeout_seconds): self.agent_type = agent_type self.name = name self.llm = ChatOpenAI(model="gpt-4o", temperature=temperature) self.tools = tools self.timeout_seconds = timeout_seconds def execute(self, state: AgentState, user_input: str) -> AgentResult: # Comprehensive execution with monitoring, error handling, and timeout protection
Key Features:
Purpose: Gather comprehensive destination information including visa requirements, weather, cultural insights, and transportation options.
Implementation Highlights:
class ResearchAgent(ToolUsingAgent): def __init__(self): tools = [ DuckDuckGoSearchRun(name="duckduckgo_search"), WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()), weather_langchain_tool ] system_prompt = """ You are the Research Agent for travel planning. ROLE: Gather reliable, recent information including visa requirements, best seasons to visit, neighborhoods, transportation, and cultural insights. OUTPUT FORMAT: - Destination Overview - Visa & Entry Requirements - Best Time to Visit - Key Areas/Neighborhoods - Transportation - Cultural Notes """
Key Capabilities:
Purpose: Create detailed day-by-day travel plans based on research findings and user preferences.
Implementation Features:
Purpose: Provide comprehensive cost breakdowns with real-time currency conversion.
Key Components:
Purpose: Suggest optimal booking strategies and provide actionable recommendations.
Implementation Approach:
Purpose: Synthesize all agent outputs into a cohesive, actionable travel brief.
Key Features:
The system uses a sophisticated workflow orchestration engine built on LangGraph:
class EnhancedWorkflow: def __init__(self): self.graph = StateGraph(AgentState) self.memory = MemorySaver() # Add nodes with enhanced error handling workflow.add_node("supervisor", self._supervisor_node) workflow.add_node("research", self._research_node) workflow.add_node("itinerary", self._itinerary_node) workflow.add_node("budget", self._budget_node) workflow.add_node("booking", self._booking_node) workflow.add_node("finalizer", self._finalizer_node) # Conditional routing from supervisor workflow.add_conditional_edges("supervisor", self._route_decision, {...})
The supervisor agent makes intelligent routing decisions based on:
def _route_decision(self, state: AgentState) -> str: # Hard-stop guard: prevent infinite loops turns = state.get("shared", {}).get("turns", 0) if turns >= max_turns - 1: return "finalizer" # Completion check: if core info gathered, finalize has_research = any(msg.agent_name == "research_agent" for msg in state["messages"]) has_budget = any(msg.agent_name == "budget_agent" for msg in state["messages"]) if has_research and has_budget: return "finalizer" return state.get("next", "finalizer")
Centralized State Management:
class AgentState(TypedDict): messages: List[Message] request_id: str session_id: Optional[str] user_id: Optional[str] current_agent: Optional[str] next: Optional[str] workflow_status: WorkflowStatus max_turns: int timeout_seconds: int shared: Dict[str, Any]
Key Features:
Architecture: Robust weather service with caching and error handling
class WeatherTool(ExternalAPITool, CachedTool): def __init__(self): ExternalAPITool.__init__(self, base_url="https://geocoding-api.open-meteo.com") CachedTool.__init__(self, cache_ttl_seconds=1800) # 30-minute cache def _execute(self, city: str, country: Optional[str] = None) -> ToolResult: # Step 1: Geocode the city geocode_result = self._geocode_city(city, country) # Step 2: Get weather forecast weather_data = self._get_weather_forecast( geocode_result["latitude"], geocode_result["longitude"] ) # Step 3: Format response return self._format_weather_data(geocode_result, weather_data)
Key Features:
Implementation: Real-time currency conversion using Frankfurter API
class ForeignExchangeTool(ExternalAPITool, CachedTool): def _execute(self, amount: float, from_currency: str, to_currency: str) -> ToolResult: # Validate currencies and get current rates rates_data = self._get_exchange_rates(from_currency) converted_amount = amount * rates_data["rates"][to_currency] return { "original_amount": amount, "converted_amount": round(converted_amount, 2), "exchange_rate": rates_data["rates"][to_currency], "rate_date": rates_data["date"] }
Input Validation and Sanitization:
class SecurityManager: def validate_input(self, user_input: str) -> str: # Length validation if len(user_input) > self.max_input_length: raise SecurityError("Input too long") # Content filtering if self.enable_content_filtering: user_input = self._filter_content(user_input) # XSS prevention return bleach.clean(user_input, tags=[], strip=True)
Key Security Features:
Circuit Breaker Pattern:
class CircuitBreaker: def __init__(self, failure_threshold=5, timeout=60): self.failure_threshold = failure_threshold self.timeout = timeout self.failure_count = 0 self.last_failure_time = None self.state = "CLOSED" # CLOSED, OPEN, HALF_OPEN
Retry Mechanisms:
Implementation:
class StructuredLogger: def __init__(self): self.logger = structlog.get_logger() def log_workflow_execution(self, request_id, execution_time_ms, success): self.logger.info( "workflow_executed", request_id=request_id, execution_time_ms=execution_time_ms, success=success, timestamp=datetime.utcnow().isoformat() )
Metrics Collection:
Observability Features:
Gradio Interface (Primary):
def create_gradio_interface(): with gr.Blocks(title="Multi-Agent Travel Planner") as interface: gr.Markdown("# 🌍 Multi-Agent Travel Planner") with gr.Row(): input_text = gr.Textbox( label="Describe your travel plans", placeholder="Plan a 5-day trip to Tokyo for 2 adults, budget $3000" ) submit_btn = gr.Button("Plan My Trip", variant="primary") output_text = gr.Markdown(label="Travel Plan") submit_btn.click( fn=process_travel_request, inputs=[input_text], outputs=[output_text] )
FastAPI Backend:
@app.post("/api/v1/travel/plan") async def plan_travel(request: TravelPlanRequest): result = enhanced_workflow.execute( user_input=request.travel_request, max_turns=request.preferences.max_turns, timeout_seconds=request.preferences.timeout_seconds ) return TravelPlanResponse(**result)
Test Coverage: 71% (194+ tests)
Test Categories:
Example Test Implementation:
class TestResearchAgent: def test_destination_extraction(self): agent = ResearchAgent() context = agent._extract_research_context( "Plan a 5-day trip to Tokyo for 2 adults, budget $3000" ) assert context["destination"] == "tokyo" assert context["duration"] == 5 assert context["budget"] == "3000"
System Performance Targets:
Multi-Stage Dockerfile:
FROM python:3.11-slim as base WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt FROM base as production COPY src/ ./src/ EXPOSE 8000 CMD ["python", "-m", "travel_planner.main", "api"]
Environment-Based Configuration:
class Settings(BaseSettings): environment: str = Field(default="development", env="ENVIRONMENT") openai: OpenAIConfig = Field(default_factory=OpenAIConfig) security: SecurityConfig = Field(default_factory=SecurityConfig) monitoring: MonitoringConfig = Field(default_factory=MonitoringConfig) model_config = SettingsConfigDict( env_file=".env", case_sensitive=False )
Run Command: python .\src\travel_planner\main.py health
Run Command: python .\src\travel_planner\main.py streamlit
Run Command: python .\src\travel_planner\main.py gradio
The Multi-Agent Travel Planner demonstrates how agent-based systems combined with LLM orchestration can significantly improve the travel planning experience. Its impact extends across multiple domains:
While the system is production-ready, several challenges remain that open pathways for future work:
The Multi-Agent Travel Planner shows the power of combining specialized agents, semantic search, and real-time tools into a cohesive system. By automating the traditionally fragmented process of researching, planning, budgeting, and booking, it provides both travelers and agencies with a scalable, reliable, and intelligent solution.
The project illustrates not just the potential of LLM-driven workflows in travel, but also establishes a framework applicable to other domains requiring multi-step decision making (e.g., healthcare scheduling, event management, or financial planning).
In summary, this work represents a step forward in human-AI collaboration, where complex, multi-stage tasks are streamlined into actionable, user-friendly outputs.
This project is licensed under the MIT License.
For more details, see the LICENSE file.