iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0
生成式 AI

Multi-Agent 實戰:開發多代理智慧小幫手系列 第 20

【Day 20】 小專案 - 飯店比較 Agent(上)

  • 分享至 

  • xImage
  •  

在上一篇中,我們已經完成了 飯店搜尋 Agent,可以根據城市查詢飯店資訊。
接下來,我們要進一步完成 飯店比較 Agent,可以針對兩間指定飯店,比較價格或評價,並輸出推薦結果。

這支 Agent 也會先使用 FastAPI 來模擬行為,方便之後轉換成 ADK Sub-Agent。

功能介紹

這個 Agent 的功能主要有:

  1. 輸入兩間飯店名稱
    使用者只需提供兩間飯店名稱(不需要城市),Agent 就能找到對應資料。
  2. 比較條件
    • cheapest:比較哪一間價格較便宜
    • best_rating:比較哪一間評價較高(星級)
  3. 輸出結論
    • 最便宜的比較結果會用「哪一間 < 哪一間」的方式呈現
    • 評價最高的比較結果會用「哪一間 > 哪一間」的方式呈現
    • 比較結果若相等會用「哪一間 = 哪一間」的方式呈現
    • 同時回傳兩間飯店的詳細資訊
    • 回傳推薦飯店(價格最便宜或評價最高)

注意:這裡使用 模擬資料庫,不會串接真實 API。

使用 FastAPI 建立飯店比較 Agent

1. 建立 FastAPI 與資料庫

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import List, Literal

app = FastAPI(
    title="飯店比較 Agent API",
    description="使用 Pydantic 的版本,可比較兩間飯店的價格或評價並輸出結論。",
    version="2.0.0",
)

# 模擬飯店資料庫
HOTEL_DATABASE = {
    "Taipei": [
        {"name": "Taipei Grand Hotel", "stars": 5, "price": 4000},
        {"name": "Hotel Proverbs Taipei", "stars": 4, "price": 3000},
        {"name": "Cosmos Hotel Taipei", "stars": 3, "price": 2000},
        {"name": "Caesar Park Hotel", "stars": 4, "price": 3500},
    ],
    "Tokyo": [
        {"name": "Park Hyatt Tokyo", "stars": 5, "price": 50000},
        {"name": "Shinjuku Granbell Hotel", "stars": 4, "price": 20000},
        {"name": "Hotel Sunroute Plaza", "stars": 3, "price": 15000},
    ],
    "New York": [
        {"name": "The Plaza", "stars": 5, "price": 700},
        {"name": "Pod 51 Hotel", "stars": 3, "price": 200},
        {"name": "Arlo SoHo", "stars": 4, "price": 350},
    ],
}

先建立一個簡單的資料庫,方便模擬查詢。

2. 定義 Pydantic 輸入模型

Pydantic 可以幫助我們驗證輸入資料的型別與格式:

class CompareRequest(BaseModel):
    hotel_names: List[str] = Field(..., min_items=2, max_items=2, example=["Hotel A", "Hotel B"])
    criterion: Literal["cheapest", "best_rating"] = Field(
        "cheapest", description="比較條件,可選 'cheapest' 或 'best_rating'"
    )
  • hotel_names:必須提供兩間飯店
  • criterion:比較條件,可選價格最便宜 (cheapest) 或評價最高 (best_rating)

3. 建立搜尋工具函式

def find_hotel_by_name(name: str):
    """從資料庫中搜尋飯店名稱"""
    for city, hotels in HOTEL_DATABASE.items():
        for hotel in hotels:
            if hotel["name"].lower() == name.lower():
                return hotel
    return None

這個函式會遍歷所有城市,找到符合名稱的飯店,如果找不到就回傳 None

4. API 端點

@app.post("/compare_hotels")
def compare_hotels(request: CompareRequest):
    """
    呼叫飯店比較 Agent。
    功能:
      - 輸入兩間飯店名稱
      - 從資料庫搜尋資料
      - 比較「最便宜」或「最佳評價」
      - 最便宜輸出結論:「哪一間 < 哪一間」
      - 最佳評價的輸出結論:「哪一間 > 哪一間」
    """
    try:
        hotel1_name, hotel2_name = request.hotel_names
        criterion = request.criterion

        hotel1 = find_hotel_by_name(hotel1_name)
        hotel2 = find_hotel_by_name(hotel2_name)

        if not hotel1 or not hotel2:
            missing = [n for n, h in zip(request.hotel_names, [hotel1, hotel2]) if h is None]
            raise HTTPException(status_code=404, detail=f"Hotel(s) not found: {', '.join(missing)}")

        if criterion == "cheapest":
            if hotel1["price"] == hotel2["price"]:
                comparison = f"{hotel1['name']} 與 {hotel2['name']} 價格相同 ({hotel1['price']} = {hotel2['price']})"
                better = hotel1
            else:
                better = min([hotel1, hotel2], key=lambda x: x["price"])
                worse = hotel2 if better == hotel1 else hotel1
                comparison = f"{better['name']} 的價格較便宜 ({better['price']} < {worse['price']})"
        elif criterion == "best_rating":
            if hotel1["stars"] == hotel2["stars"]:
                comparison = f"{hotel1['name']} 與 {hotel2['name']} 評價相同 ({hotel1['stars']} stars = {hotel2['stars']} stars)"
                better = hotel1 
            else:
                better = max([hotel1, hotel2], key=lambda x: x["stars"])
                worse = hotel2 if better == hotel1 else hotel1
                comparison = f"{better['name']} 評價較高 ({better['stars']} stars > {worse['stars']} stars)"

        return {
            "status": "success",
            "criterion": criterion,
            "hotels_compared": [hotel1, hotel2],
            "comparison_result": comparison,
            "recommended_hotel": better,
        }

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
  • 資料驗證:確保兩間飯店都存在
  • 比較邏輯
    • cheapest:找價格低的飯店
    • best_rating:找評價高的飯店
  • 回傳結果
    • hotels_compared:兩間飯店詳細資料
    • comparison_result:文字結論
    • recommended_hotel:推薦飯店

實際測試

  • API
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456bcb6f87FgQ.png
  • 比較最便宜
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456nppPbDatLv.png
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456YO5DLQGHQy.png
  • 比較評價最高
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456n5lj7fr0oN.png
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456esQUS2TZyq.png
  • 評價相同時
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456QlZYxWdYo2.png
    https://ithelp.ithome.com.tw/upload/images/20251004/20168456M01cd2NjDS.png

上一篇
【Day 19】 小專案 - 飯店搜尋 Agent(下)
系列文
Multi-Agent 實戰:開發多代理智慧小幫手20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言