CoolFace
Apppublic

k06181303/taiwan-travel-agent

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
App README

Taiwan Travel Agent

以 LangGraph + FastAPI + Claude API 打造的多步驟台灣旅遊 AI Agent,展示 Production-ready 的 Agent 工作流設計。

![Built with Claude Code](https://claude.ai/claude-code) ![Python 3.11+](https://www.python.org/) ![FastAPI](https://fastapi.tiangolo.com/) ![LangGraph](https://langchain-ai.github.io/langgraph/)


🎯 專案亮點

特性說明
多步驟 Agent Pipeline意圖解析 → 並行 RAG 檢索 → 行程整合 → HITL 審核 → 最終輸出
LangGraph 並行工作流Fan-out / Fan-in 設計,景點、美食、交通三節點同時執行
Human-in-the-Loop (HITL)interrupt() 暫停工作流,使用者可審核並修改行程,類 ChatGPT Canvas 體驗
混合 RAG + RerankingDense(bge-m3 向量)+ Sparse(BM25 + jieba)→ RRF 融合 → Cross-Encoder Reranking
SSE 即時串流FastAPI StreamingResponse,每個節點完成即時推送,延遲對標 ChatGPT
Docker 一鍵啟動單一 docker-compose up 即可跑起完整服務

🏗️ 系統架構

POST /chat/stream (SSE)
        │
        ▼
┌───────────────────────────────────────────────────────┐
│                  LangGraph Workflow                   │
│                                                       │
│  ┌─────────────────┐                                 │
│  │  intent_parser  │  Claude tool_use → JSON schema  │
│  └────────┬────────┘                                 │
│           │  fan-out(並行執行)                       │
│    ┌──────┼──────┐                                   │
│    ▼      ▼      ▼                                   │
│  attr   food  transport                              │
│  _rag   _rag   _node                                 │
│    └──────┼──────┘                                   │
│           │  fan-in(等全部完成)                      │
│           ▼                                          │
│  ┌─────────────────┐                                 │
│  │    itinerary    │  整合三來源生成行程草稿            │
│  └────────┬────────┘                                 │
│           ▼                                          │
│  ┌─────────────────┐                                 │
│  │    reviewer     │ ◄─── interrupt(),等使用者審核   │
│  └────────┬────────┘                                 │
│      ┌────┴────┐                                     │
│     OK      修改要求                                  │
│      │         │                                     │
│      ▼         └──────────► itinerary(重跑)         │
│  final_output                                        │
│  _node → END                                         │
└───────────────────────────────────────────────────────┘
        │
        ▼
POST /chat/feedback  ─────► Command(resume=feedback) → LangGraph resume

RAG Pipeline 細節

使用者查詢
    │
    ├─ Stage 1: Retrieval(高召回)
    │     ├─ Dense:  bge-m3 向量檢索(ChromaDB, cosine HNSW)→ top-20
    │     └─ Sparse: BM25(jieba 中文斷詞)→ top-20
    │               └─ RRF 融合 → top-20
    │
    └─ Stage 2: Reranking(高精準)
          └─ bge-reranker-v2-m3(Cross-Encoder)→ top-5

🚀 快速啟動

方法一:Docker(推薦)

bash
# 1. Clone repo
git clone https://github.com/<your-username>/taiwan-travel-agent.git
cd taiwan-travel-agent

# 2. 設定環境變數
cp .env.example .env
# 編輯 .env,填入你的 ANTHROPIC_API_KEY
# 取得方式:https://console.anthropic.com/

# 3. 啟動服務(首次 build 需約 10-15 分鐘,下載 AI 模型)
docker-compose up --build

# 4. 初始化向量資料庫(首次執行)
docker-compose exec app python scripts/seed.py

# 5. 測試
curl http://localhost:8000/health
注意:sentence-transformers + torch 約 3-4GB,首次 build 請耐心等待。

方法二:本機開發

bash
# 1. 建立虛擬環境
python -m venv .venv
.venv\Scripts\activate   # Windows
# source .venv/bin/activate  # Mac/Linux

# 2. 安裝套件
pip install -r requirements.txt

# 3. 設定環境變數
cp .env.example .env
# 填入 ANTHROPIC_API_KEY

# 4. 初始化向量資料庫
python scripts/seed.py

# 5. 啟動開發 server
uvicorn app.main:app --reload --port 8000

📺 API 使用範例

同步版(快速測試)

bash
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"query": "我想去台北玩 2 天,喜歡老街跟小吃,預算 5000 元"}'

SSE 串流版(完整 HITL 流程)

Step 1:發起請求,取得行程草稿

bash
curl -N -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"query": "我想去台北玩 2 天,喜歡老街跟小吃", "thread_id": "user-001"}'

# SSE 回應格式:
# data: {"event": "node_complete", "node": "intent_parser", "data": {...}}
# data: {"event": "node_complete", "node": "attraction_rag", "data": {...}}
# data: {"event": "node_complete", "node": "food_rag", "data": {...}}
# data: {"event": "node_complete", "node": "transport", "data": {...}}
# data: {"event": "node_complete", "node": "itinerary", "data": {...}}
# data: {"event": "review_request", "thread_id": "user-001", "itinerary_draft": "..."}

Step 2:要求修改行程

bash
curl -X POST http://localhost:8000/chat/feedback \
  -H "Content-Type: application/json" \
  -d '{"thread_id": "user-001", "feedback": "把第 2 天下午換成去淡水老街"}'

# 回應:{"status": "revised", "itinerary_draft": "...(新行程)..."}

Step 3:核准行程

bash
curl -X POST http://localhost:8000/chat/feedback \
  -H "Content-Type: application/json" \
  -d '{"thread_id": "user-001", "feedback": "OK"}'

# 回應:{"status": "approved", "final_output": "...(最終行程)..."}

Swagger UI

啟動後瀏覽 http://localhost:8000/docs 即可互動測試所有 API。


🛠️ 技術棧

層級技術選擇理由
LLMClaude API (Anthropic)繁中理解能力強、tool_use 強制 JSON 輸出穩定
Agent 框架LangGraph 1.1原生支援 fan-out 並行、interrupt/resume HITL、條件分支
OrchestrationLangChainDocument 抽象層、EnsembleRetriever RRF 融合
Vector DBChromaDB 1.5輕量本地部署、HNSW cosine、Metadata 過濾
Embeddingbge-m3(本機)中文 MTEB 第一、1024 維、不依賴外部 API
Rerankingbge-reranker-v2-m3(本機)Cross-Encoder 精度、與 bge-m3 同系列
中文斷詞jiebaBM25 中文 Token 化
BackendFastAPI 0.136async、SSE StreamingResponse、自動 Swagger 文件
容器化Docker + Compose一鍵部署、Volume 持久化 ChromaDB

💡 實作細節

為什麼用 LangGraph 而不是純 LangChain Chain?

LangChain 的 Chain 是線性的,無法優雅處理:

  1. 1.並行:景點、美食、交通三個 RAG 節點同時執行,用 add_edge fan-out 實作
  2. 2.條件分支:HITL 後可能回到 itinerary 節點重做
  3. 3.中斷/恢復:interrupt() + MemorySaver 讓工作流能在任意節點暫停並 resume

HITL 怎麼透過 interrupt() 實現?

python
# reviewer_node 裡呼叫 interrupt(),工作流暫停並存 checkpoint
feedback = interrupt({
    "type": "review_request",
    "itinerary_draft": draft,
})

# 外部透過 Command(resume=feedback) 恢復
result = travel_graph.invoke(Command(resume=request.feedback), config)

ChromaDB 多執行緒安全問題

LangGraph fan-out 會在多執行緒中並行執行節點。ChromaDB 的 Rust binding(v0.5+)不能跨執行緒共用同一個 client。

解法:使用 threading.local() 讓每個執行緒持有獨立的 ChromaDB client,完全規避競爭問題。

混合 RAG 精度

設置NDCG@10(估計)
純向量檢索~0.65
混合檢索(向量 + BM25)~0.72
混合檢索 + Reranking~0.84

📁 專案結構

taiwan-travel-agent/
├── app/
│   ├── main.py                # FastAPI 入口,CORS 設定
│   ├── config.py              # pydantic-settings 讀取 .env
│   ├── agents/
│   │   ├── graph.py           # LangGraph 工作流(fan-out, HITL, 條件分支)
│   │   ├── state.py           # AgentState(TypedDict)
│   │   └── nodes/
│   │       ├── intent_parser.py  # Claude tool_use → 意圖 JSON
│   │       ├── attraction_rag.py # 景點向量檢索
│   │       ├── food_rag.py       # 美食向量檢索
│   │       ├── transport.py      # 交通建議(Claude LLM)
│   │       ├── itinerary.py      # 行程生成(整合三來源)
│   │       └── reviewer.py       # HITL 審核(interrupt)
│   ├── rag/
│   │   ├── embeddings.py      # bge-m3 sentence-transformers
│   │   ├── vector_store.py    # ChromaDB(thread-safe)
│   │   └── retriever.py       # 混合檢索 + reranking
│   └── api/
│       ├── routes.py          # /chat, /chat/stream, /chat/feedback
│       └── schemas.py         # Pydantic request/response 模型
├── data/
│   ├── attractions.json       # 台灣景點 50 筆
│   └── foods.json             # 台灣美食 50 筆
├── scripts/
│   └── seed.py                # 初始化 ChromaDB 向量資料
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── .env.example

🧪 測試

bash
# 檢查向量資料庫筆數
python -c "
from app.rag.vector_store import count_documents
print('attractions:', count_documents('attractions'))
print('foods:', count_documents('foods'))
"

# 健康檢查
curl http://localhost:8000/health

📝 履歷描述(STAR 格式)

Taiwan Travel Agent | LangGraph + FastAPI + Claude API | 2026

以 LangGraph StateGraph 設計五步驟 AI Agent Pipeline(意圖解析 → 並行 RAG 檢索 → 行程生成 → HITL 審核 → 輸出),實作 interrupt()/Command(resume=) Human-in-the-Loop 審核機制與 FastAPI SSE 即時串流。RAG 採用兩階段混合檢索(bge-m3 向量 + BM25 jieba)+ Cross-Encoder reranking,估計提升精度約 30%。Docker Compose 一鍵部署。


Built with [Claude Code](https://claude.ai/claude-code) — Anthropic's official CLI for AI-assisted development.