|
| 1 | +# Multi-Agent Travel Planning (OpenAI Agents + OpenTelemetry) |
| 2 | + |
| 3 | +This folder now contains **two** illustrative examples of instrumented multi-agent travel planning using the OpenAI Agents API and OpenTelemetry: |
| 4 | + |
| 5 | +1. `multi_travel_planner.py` – A concise, faster single-agent orchestration that chains a few simple function tools (geocode / weather / cuisine). Good for a quick look at instrumentation wiring and a minimal trace. |
| 6 | +2. `enhanced.py` – A richer, production-style multi‑agent workflow that mirrors a LangGraph style handoff pipeline (Coordinator → Flight → Hotel → Activity → Budget → Plan Synthesizer). It demonstrates structured outputs, tool usage, deterministic handoffs, OpenTelemetry spans, and interactive fallbacks when the model asks clarifying questions. |
| 7 | + |
| 8 | +--- |
| 9 | +## Why the Enhanced Version? |
| 10 | + |
| 11 | +`enhanced.py` showcases patterns often needed in real systems: |
| 12 | + |
| 13 | +* Multiple cooperating specialist agents with explicit handoff definitions. |
| 14 | +* Structured extraction via Pydantic (`TripDetails`, `FlightRecommendation`, etc.). |
| 15 | +* Automatic tracing of each agent invocation and tool execution via `opentelemetry-instrumentation-openai-agents`. |
| 16 | +* A resilient trip detail parsing layer (JSON parsing + heuristic extraction) and an **interactive fallback prompt flow** (so a model asking for missing info doesn’t crash the pipeline). |
| 17 | +* Budget analysis + synthesis phase to create a cohesive final plan. |
| 18 | +* Per‑agent model instances (can vary temperature / deployment) while retaining a single end‑to‑end workflow trace. |
| 19 | + |
| 20 | +--- |
| 21 | +## Features Comparison |
| 22 | + |
| 23 | +| Capability | multi_travel_planner.py | enhanced.py | |
| 24 | +|------------|-------------------------|-------------| |
| 25 | +| Simple single pass | ✅ | ➖ (multi-step) | |
| 26 | +| Deterministic multi-agent chain | ❌ | ✅ | |
| 27 | +| Structured Pydantic outputs | Minimal | Extensive | |
| 28 | +| Interactive fallback for missing details | ❌ | ✅ | |
| 29 | +| Budget computation | ❌ | ✅ | |
| 30 | +| Day-by-day itinerary synthesis | ❌ | ✅ | |
| 31 | +| Rich span hierarchy | Basic | Deep (per agent + tools) | |
| 32 | + |
| 33 | +--- |
| 34 | +## Quick Start (Both Scripts) |
| 35 | + |
| 36 | +```bash |
| 37 | +cp .env.example .env # fill in Azure OpenAI endpoint, key, deployment |
| 38 | +pip install -r requirements.txt |
| 39 | +``` |
| 40 | + |
| 41 | +Ensure one of these is configured: |
| 42 | + |
| 43 | +* Azure: `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_DEPLOYMENT` |
| 44 | +* or Public OpenAI: `OPENAI_API_KEY` and (optionally) `OPENAI_MODEL` |
| 45 | + |
| 46 | +Optional OpenTelemetry exporter vars (see `.env.example`): |
| 47 | + |
| 48 | +* `OTEL_EXPORTER_OTLP_ENDPOINT` |
| 49 | +* `OTEL_EXPORTER_OTLP_HEADERS` |
| 50 | +* Set instrumentation content capture toggles such as `OTEL_INSTRUMENTATION_OPENAI_AGENTS_CAPTURE_CONTENT=true` for message/tool IO. |
| 51 | + |
| 52 | +--- |
| 53 | +## Running the Simple Planner |
| 54 | + |
| 55 | +```bash |
| 56 | +python multi_travel_planner.py --city "Paris" --date 2025-09-10 |
| 57 | +``` |
| 58 | + |
| 59 | +--- |
| 60 | +## Running the Enhanced Multi-Agent Planner |
| 61 | + |
| 62 | +Interactive mode (default): |
| 63 | +```bash |
| 64 | +python enhanced.py |
| 65 | +``` |
| 66 | + |
| 67 | +You will be shown sample requests. Press Enter to accept a sample or paste your own natural language trip description. If the coordinator agent requests clarification (e.g., missing origin or dates), the script will prompt you to enter the missing fields. |
| 68 | + |
| 69 | +Non-interactive strict mode (fail instead of prompting): |
| 70 | +```bash |
| 71 | +export INTERACTIVE_TRIP_DETAILS=0 |
| 72 | +python enhanced.py |
| 73 | +``` |
| 74 | + |
| 75 | +### Sample Natural Language Requests |
| 76 | + |
| 77 | +Copy these into the prompt (or just press Enter to use one automatically): |
| 78 | + |
| 79 | +* Business: “I need to plan a business trip to London for 3 days from Seattle, hotel near the financial district, efficient flights, budget around $3000.” |
| 80 | +* Family: “Plan a family vacation to Paris for 2 adults and 2 children for 10 days next month. Museums, parks, family-friendly activities, about $8000 total.” |
| 81 | +* Romantic: “Romantic anniversary trip to Tokyo for a week, luxury hotel, fine dining, up to $6000.” |
| 82 | + |
| 83 | +--- |
| 84 | +## Interactive Fallback Details (`enhanced.py`) |
| 85 | + |
| 86 | +If the coordinator LLM answer is a *clarifying question* rather than a structured JSON-like response, the script attempts: |
| 87 | + |
| 88 | +1. JSON parse (if the model returned JSON). |
| 89 | +2. Heuristic extraction (regex for origin/destination/dates/duration/budget/trip type). |
| 90 | +3. If still incomplete and `INTERACTIVE_TRIP_DETAILS != 0`, prompt you for the remaining fields. |
| 91 | + |
| 92 | +Disable this by setting `INTERACTIVE_TRIP_DETAILS=0` to force a hard error (useful in CI or automated evaluations). |
| 93 | + |
| 94 | +--- |
| 95 | + |
| 96 | +## Observability |
| 97 | + |
| 98 | +Both scripts rely on `OpenAIAgentsInstrumentor` which creates spans such as: |
| 99 | + |
| 100 | +* Root span: workflow invocation (`gen_ai.operation.name=invoke_agent`). |
| 101 | +* Child spans: each agent call + each function tool execution (`execute_tool`). |
| 102 | +* Attributes: model metadata, tool names, (optionally) message content and structured outputs. |
| 103 | + |
| 104 | +To view data: |
| 105 | + |
| 106 | +* Console exporter (default) prints spans to stdout. |
| 107 | +* Set OTLP exporter variables to ship to Azure Monitor / another backend. |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +## Extending `enhanced.py` |
| 112 | + |
| 113 | +Ideas: |
| 114 | + |
| 115 | +* Add real API-backed tools (live flights, hotels, weather) – instrumentation is unchanged. |
| 116 | +* Introduce retry + guardrails (ask the model to reformat invalid structured output before falling back to manual input). |
| 117 | +* Cache intermediate tool results for iterative refinement. |
| 118 | +* Emit custom span events for milestones (e.g., “flights_selected”, “budget_locked”). |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +## Troubleshooting |
| 123 | + |
| 124 | +| Issue | Possible Cause | Fix | |
| 125 | +|-------|----------------|-----| |
| 126 | +| Coordinator asks for origin/dates repeatedly | Insufficient initial prompt detail | Provide explicit origin, destination, ISO dates | |
| 127 | +| ValueError about TripDetails in strict mode | Missing required fields & fallback disabled | Remove `INTERACTIVE_TRIP_DETAILS=0` or add details | |
| 128 | +| No spans exported externally | OTLP env vars not set | Provide OTLP endpoint + headers or keep console export | |
| 129 | +| Model name not found | Wrong deployment/model env | Check `AZURE_OPENAI_DEPLOYMENT` or `OPENAI_MODEL` | |
| 130 | + |
| 131 | +--- |
| 132 | + |
| 133 | +## Next Steps |
| 134 | + |
| 135 | +* Add more specialized tools (exchange rates, safety alerts, local transit). |
| 136 | +* Integrate a vector store for preference memory across sessions. |
| 137 | +* Emit custom OpenTelemetry events for major planning milestones. |
| 138 | +* Package this example as a reusable reference for multi-agent orchestration + observability. |
| 139 | + |
| 140 | +--- |
| 141 | +Happy exploring! Feel free to adapt `enhanced.py` to your own domain—any new agent or tool automatically participates in tracing once it flows through the `Runner` and instrumentation hooks. |
0 commit comments