A FastAPI + Streamlit project that recommends flight and hotel combinations for corporate travel, validates policy and factual consistency, and routes low-confidence responses to human review.
- Corporate trip recommendation pipeline (flights + hotels)
- Deterministic policy checks (tier budgets, preferred vendors, inventory)
- LLM recommendation and verification agents
- Confidence scoring and route selection:
auto_suggestsuggest_with_cautionhuman_review
- Human-in-the-loop approval workflow for flagged recommendations
- Mock inventory and knowledge base for repeatable testing
- Streamlit chat UI and FastAPI endpoints
- Python 3.10+
- FastAPI
- Streamlit
- Pydantic / pydantic-settings
- LangChain + LangGraph (StateGraph orchestration)
- Azure OpenAI
The pipeline is built as an AI harness — everything around the model that makes it trustworthy:
- Context engineering — retrieval + rerank, with an optional relevance floor
(
retrieval_min_score) that drops weak matches so they don't pollute context. - Deterministic guardrails — a composable hard-cap registry
(
app/validation/hard_caps.py): policy / price / claim / inventory / hallucinated-citation / no-evidence signals force confidence to a ceiling the LLM cannot argue past. - Agent loop — a bounded self-repair loop (
app/orchestrator/graph.py): a recoverable defect (a fabricated citation) triggers a re-ask with corrective feedback, capped bymax_agent_iterations; hard fails escalate immediately. - Verification & evals — the offline golden-set routing harness (
evals/, CI-gated) plus optional live RAGAS RAG-quality metrics (python -m evals.run_evals --live --ragas). - Telemetry — local-first spans, token counts, and USD cost per run
(
app/telemetry.py); no third-party SaaS by default (optional OpenTelemetry export; LangSmith is an opt-in env flag away).
app/
agents/ # Recommendation + verification agents
mock/ # Mock inventory + knowledge base seed data
models/ # Request/response domain models
orchestrator/ # Retrieval, reranking, routing, full pipeline
validation/ # Policy/fact/response verification logic
approval_store.py
config.py
main.py
chatbot.py # Streamlit chat assistant UI
test_request.py # Quick API smoke test
test/ # Scenario docs and test cases
- Python 3.10 or newer
- Azure OpenAI resource with:
- chat deployment
- embedding deployment
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCopy .env.example to .env and fill in your Azure settings:
cp .env.example .envRequired values:
AZURE_OPENAI_API_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_CHAT_DEPLOYMENTAZURE_OPENAI_EMBEDDING_DEPLOYMENT
Optional runtime settings (already defaulted in code):
- retrieval/agent timeouts
- routing thresholds
- retrieval/rerank top-k
uvicorn app.main:app --reloadBase URL: http://localhost:8000
Useful endpoints:
GET /healthPOST /recommendGET /approvals/pendingGET /approvals/{approval_id}POST /approvals/{approval_id}/approvePOST /approvals/{approval_id}/reject
streamlit run chatbot.pyThe UI includes:
- trip profile controls (tier, destination, dates, preferences)
- verification toggle and confidence threshold slider
- quick scenario buttons (Tokyo, Bangkok, New York)
- escalation flow for human review
curl -X POST "http://localhost:8000/recommend" \
-H "Content-Type: application/json" \
-d '{
"traveler": {
"employee_id": "EMP-001",
"name": "Alice Johnson",
"department": "Engineering",
"org_policy_tier": "standard"
},
"origin": "SFO",
"destination": "Tokyo",
"departure_date": "2026-04-01",
"return_date": "2026-04-05",
"trip_purpose": "business",
"preferences": ["non_stop", "hotel_gym"]
}'The pipeline computes confidence from policy, inventory, evidence quality, freshness, and risk margin, then maps to a route:
>= 0.85->auto_suggest0.60 - 0.84->suggest_with_caution< 0.60->human_review
Hard caps are applied when critical checks fail (for example inventory failure or policy violations).
When route is suggest_with_caution or human_review:
- Recommendation is marked
approval_required=true - A pending approval record is created with an
approval_id - Reviewer can approve/reject through approval endpoints
Note: approvals are stored in-memory (app/approval_store.py) for MVP use.
Unit tests for the deterministic guardrails (offline, no Azure cost):
python -m pytest -qevals/ adds a golden-set harness that runs the real pipeline (router,
policy/fact checkers, hard caps, freshness) with the LLM agents and vector store
faked, to measure routing precision/recall and threshold calibration:
python -m evals.run_evals # offline, deterministic, zero Azure spend
python -m evals.run_evals --live # real Azure OpenAI; measures grounding rateIt gates CI on the deterministic hard-cap scenarios and reports calibration
divergences on the soft ones. See evals/README.md.
Run the API smoke script:
python test_request.pyReference docs:
test/TEST_CASES.md— confidence/routing test cases. Note: the inventory cheat sheet in this file is stale (it lists a New York / JFK inventory that no longer exists inseed_data.py, which now uses Sydney). The eval golden set is built from the live seed data and is the source of truth.test/test_scenarios.mdtest/sample_questions.md
- Data sources are mocked (inventory + knowledge base)
- Approval store is in-memory and resets on restart
- This project is an MVP and not production-hardened
401or auth errors: verify Azure OpenAI key/endpoint/deployment names in.env- Empty or low-quality recommendations: confirm embedding + chat deployments are valid
- API does not start: ensure dependencies are installed and the virtual environment is active