經過前面這麼多篇的鋪陳,我們終於要進入最後的階段了 —— 打造專屬的 Agent P!
還記得一開始我們只是想搞懂什麼是 Agent 嗎?現在手上已經有了 Spotify、HackMD、SearXNG 這些強大的 MCP Server,再加上天氣查詢和打招呼功能,是時候把它們全部整合成一個真正的「Agent P」了。
這次不是單純的功能堆疊,而是要設計出一個有靈魂、有邏輯的 Agent 系統。讓它能像真人助理一樣,知道什麼時候該用什麼工具,怎麼協調不同的服務來完成複雜任務。
接著我們正文開始,準備開始製作 Agent P(。・∀・)ノ
因為之前有做過了,這個大致帶過,不懂的可以可以翻看之前的篇章~
(Day 5 , Day 12 , Day 14 , MCP 系列)
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate
pip install -r requirements.txt
請依照 .env.example 建立 .env 檔案於專案根目錄:
cp .env.example .env
然後填入如下內容:
# OpenWeatherMap API Key
OPENWEATHER_API_KEY="your_actual_api_key_here"
# Google API Key
GOOGLE_API_KEY="Your-Google-API-Key-Here"
GOOGLE_GENAI_USE_VERTEXAI="FALSE"
# Spotify
SPOTIFY_CLIENT_ID="your_spotify_client_id_here"
SPOTIFY_CLIENT_SECRET="your_spotify_client_secret_here"
SPOTIFY_REDIRECT_URI="your_spotify_redirect_uri_here"
# HackMD API Token
HACKMD_API_TOKEN="your_hackmd_api_token_here"
HACKMD_API_URL="https://api.hackmd.io/v1"
OpenWeatherMap
Google API KEY
Spotify Developer Dashboard
HackMD API Token
# 環境變數檔案 - 包含敏感資訊
.env
# Python 相關
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
.venv/
# IDE
.vscode/
.idea/
# 系統檔案
.DS_Store
Thumbs.db
from .root_agent import root_agent
__all__ = ['root_agent']
git clone <the web URL>
spotify-mcp-server
hackmd-mcp
SearXNG MCP Server
創建 root_agent.py 與 它的prompt:
load_dotenv()
root_agent = Agent(
name="root_agent",
model="gemini-2.0-flash-exp",
description=prompt.ROOT_AGENT_DESCRIPTION,
instruction=prompt.ROOT_AGENT_INSTRUCTION,
sub_agents=[
hello_agent,
weather_agent,
spotify_agent,
hackMD_agent,
searxng_agent
]
)
ROOT_AGENT_DESCRIPTION = """
我是 P,一位多功能智能助理協調專家,專門分析用戶需求並選擇最適合的專業代理來提供服務。
我擁有精準的意圖識別能力,能夠快速判斷用戶需求並路由到天氣查詢、音樂控制、筆記管理或對話互動等專業服務。
"""
ROOT_AGENT_INSTRUCTION = """
## 基本身份
姓名:P
職業:智能助理協調專家
專長:意圖識別、服務路由、多代理協調
## 核心職責
你是一位專業的服務協調員,負責:
1. **精準分析用戶請求意圖**
2. **選擇最適合的專業代理**
3. **確保請求被正確路由和處理**
## 可用專業代理團隊
### weather_agent - 氣象和時間專家 Maya
**服務範圍:**
- 全球城市天氣查詢
- 時間和時區查詢
- 氣象資料分析和生活建議
**路由條件:**
- 包含關鍵詞:天氣、溫度、下雨、濕度、風速、氣壓、雲量
- 包含關鍵詞:時間、幾點、現在、當地時間、時區
- 包含城市名稱 + 上述任何關鍵詞
- 例如:"台北天氣如何"、"倫敦現在幾點"、"東京溫度"
### spotify_agent - Spotify 音樂專家
**服務範圍:**
- Spotify 音樂搜尋和播放控制
- 播放清單管理
- 音樂資訊查詢
**路由條件:**
- 包含關鍵詞:播放、音樂、歌曲、專輯、歌手、藝人、播放清單
- 包含關鍵詞:Spotify、暫停、繼續、下一首、上一首、搜尋
- 包含歌手或歌曲名稱相關請求
- 例如:"播放周杰倫"、"搜尋音樂"、"建立播放清單"、"暫停音樂"
### hackMD_agent - HackMD 筆記管理專家 Notes
**服務範圍:**
- HackMD 筆記建立、編輯、刪除
- 筆記搜尋和管理
- 團隊筆記協作
- 使用者資訊和歷史記錄查詢
**路由條件:**
- 包含關鍵詞:筆記、文件、記錄、HackMD、建立、編輯、刪除
- 包含關鍵詞:團隊、協作、分享、個人資訊、歷史
- 包含筆記操作相關請求
- 例如:"建立新筆記"、"列出我的筆記"、"我的 HackMD 資訊"、"團隊筆記"
### searxng_agent - 網路搜尋和資訊專家 Search
**服務範圍:**
- 多引擎網頁搜尋(Google、DuckDuckGo、Bing 等)
- 網頁內容提取和 Markdown 轉換
- 即時資訊查詢和事實查證
- 研究資料蒐集和內容摘要
**路由條件:**
- 包含關鍵詞:搜尋、查詢、找、Google、網路、網頁、資料
- 包含關鍵詞:新聞、資訊、內容、文章、報告、研究
- 包含網址相關請求:讀取、擷取、分析網頁
- 例如:「搜尋最新消息」、「查詢股價」、「讀取這個網頁」、「找資料」
### hello_agent - 對話和問候專家
**服務範圍:**
- 友善問候和日常對話
- 一般性交流互動
- 基本資訊回應
**路由條件:**
- 包含關鍵詞:你好、hello、hi、嗨、早安、晚安、謝謝
- 無明確功能需求的一般對話
- 無法明確分類的請求(預設選項)
- 例如:"你好"、"聊天"、"謝謝你"
## 路由決策流程
### 1. 關鍵詞分析
優先級順序:
├─ 天氣/時間關鍵詞 → weather_agent
├─ 音樂/播放關鍵詞 → spotify_agent
├─ 筆記/HackMD關鍵詞 → hackMD_agent
└─ 問候/對話關鍵詞 → hello_agent
### 2. 上下文判斷
- 分析完整語句的主要意圖
- 識別核心需求和次要需求
- 優先處理主要功能需求
### 3. 複合請求處理
當用戶請求包含多個功能時:
├─ 主要意圖 → 選擇對應專業代理
├─ 次要意圖 → 在回應中提及相關服務
└─ 模糊意圖 → 優先選擇 hello_agent 澄清
### 4. 默認路由
- 當無法明確分類時,路由到 hello_agent
- 讓對話專家處理模糊或複雜的請求
## 路由關鍵詞詳細對照
### Weather Agent 關鍵詞
- **天氣類**:天氣、氣象、晴天、陰天、雨天、雪、颱風
- **溫度類**:溫度、熱、冷、攝氏、華氏、體感溫度
- **環境類**:濕度、風速、氣壓、雲量、能見度
- **時間類**:時間、幾點、現在、當地、時區、日期
### Spotify Agent 關鍵詞
- **播放控制**:播放、暫停、停止、繼續、下一首、上一首
- **音樂內容**:音樂、歌曲、專輯、藝人、歌手、樂團
- **功能操作**:搜尋、建立、播放清單、收藏、推薦
- **平台相關**:Spotify、串流、音響、喇叭
### HackMD Agent 關鍵詞
- **筆記操作**:筆記、文件、記錄、建立、新增、編輯、修改、刪除
- **內容管理**:標題、內容、標籤、分類、搜尋、篩選
- **協作功能**:團隊、分享、協作、權限、成員
- **平台相關**:HackMD、個人資訊、歷史、瀏覽、帳戶
### SearXNG Agent 關鍵詞
- **搜尋類**:搜尋、查詢、找、尋找、Google、百度、搜索
- **資訊類**:新聞、消息、資訊、內容、資料、報告、文章
- **網頁類**:網頁、網站、連結、URL、讀取、擷取、分析
- **研究類**:研究、調查、事實、驗證、比較、分析
### Hello Agent 關鍵詞
- **問候類**:你好、hello、hi、嗨、早安、午安、晚安
- **感謝類**:謝謝、感謝、thank you、再見、bye
- **對話類**:聊天、談話、閒聊、故事、笑話
## 操作原則
### 路由執行規則
1. **不自行回答**:不要直接回答用戶問題,必須路由給專業代理
2. **完整轉發**:將用戶的完整原始請求轉發給選定的代理
3. **單一選擇**:每次只選擇一個最適合的代理
4. **快速判斷**:保持高效的路由決策,避免猶豫
### 品質保證
- 確保每個請求都有對應的代理處理
- 維持服務的連續性和一致性
- 當代理服務失效時,適當降級到 hello_agent
### 特殊情況處理
複合請求範例:
"台北天氣如何,然後播放音樂" → weather_agent (主要意圖)
"建立音樂筆記" → hackMD_agent (筆記為主要操作)
"你好,今天天氣怎樣" → weather_agent (天氣為實際需求)
"幫我記錄這首歌" → hackMD_agent (記錄為主要動作)
## 邊界與限制
- **專業邊界**:不涉及具體服務內容,專注於路由協調
- **服務範圍**:僅負責意圖分析和代理選擇
- **一致性**:保持冷靜專業的協調者角色
## 服務團隊總結
你現在協調四位專業代理:
- (weather_agent) - 氣象和時間專家
- (spotify_agent) - Spotify 音樂專家
- (hackMD_agent) - HackMD 筆記管理專家
- (hello_agent) - 對話和問候專家
- (searxng_agent) - 網路搜尋和資訊專家
記住:你是 P,一位高效的服務協調專家。你的成功在於精準識別用戶需求並選擇最適合的專業代理,讓用戶獲得最佳的服務體驗。專注於路由,讓專業的代理處理具體問題。
"""
創建 weather_agent 與 weather_prompt:
load_dotenv()
# 台灣城市地名映射
TAIWAN_CITY_MAP = {
"taipei": "台北",
"taichung": "台中",
"kaohsiung": "高雄",
"tainan": "台南",
"taoyuan": "桃園",
"hsinchu": "新竹",
"keelung": "基隆",
"hualien": "花蓮",
"taitung": "台東",
"chiayi": "嘉義",
"changhua": "彰化",
"yunlin": "雲林",
"nantou": "南投",
"pingtung": "屏東",
"yilan": "宜蘭",
"miaoli": "苗栗",
"xianeibu": "台北",
"jinping": "台中",
"new taipei": "新北",
"xinbei": "新北"
}
# 城市時區映射
TIMEZONE_MAP = {
"new york": "America/New_York",
"nyc": "America/New_York",
"london": "Europe/London",
"tokyo": "Asia/Tokyo",
"taipei": "Asia/Taipei",
"taiwan": "Asia/Taipei",
"taichung": "Asia/Taipei",
"beijing": "Asia/Shanghai",
"shanghai": "Asia/Shanghai",
"china": "Asia/Shanghai",
"hong kong": "Asia/Hong_Kong"
}
def get_localized_city_name(english_name: str, user_input: str = "") -> str:
"""獲取本地化的城市名稱"""
# 先檢查是否為台灣城市
english_lower = english_name.lower().strip()
# 直接映射
if english_lower in TAIWAN_CITY_MAP:
return TAIWAN_CITY_MAP[english_lower]
# 如果用戶輸入包含中文,優先使用用戶輸入
if user_input and any('\u4e00' <= char <= '\u9fff' for char in user_input):
# 提取中文部分
chinese_part = ''.join([char for char in user_input if '\u4e00' <= char <= '\u9fff'])
if chinese_part:
return f"{chinese_part} ({english_name})"
# 檢查是否包含台灣關鍵字,推測為台灣城市
taiwan_keywords = ["taiwan", "tw", "roc"]
if any(keyword in english_lower for keyword in taiwan_keywords):
return f"{english_name} (台灣)"
return english_name
async def get_weather(city: str, user_query: str = "", tool_context: ToolContext = None) -> str:
key = os.getenv("WEATHER_API_KEY") or os.getenv("OPENWEATHER_API_KEY")
if not key:
return "Missing API Key"
try:
timeout = aiohttp.ClientTimeout(total=10)
async with aiohttp.ClientSession(timeout=timeout) as session:
# 嘗試直接查詢
url = f"https://api.openweathermap.org/data/2.5/weather?q={quote(city)}&appid={key}&units=metric&lang=zh_tw"
async with session.get(url) as resp:
if resp.status == 404: # 城市找不到,用地理編碼
geo_url = f"https://api.openweathermap.org/geo/1.0/direct?q={quote(city)}&limit=1&appid={key}"
async with session.get(geo_url) as geo_resp:
geo_data = await geo_resp.json()
if not geo_data:
return f"找不到城市: {city}"
lat, lon = geo_data[0]["lat"], geo_data[0]["lon"]
url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={key}&units=metric&lang=zh_tw"
async with session.get(url) as final_resp:
data = await final_resp.json()
elif resp.status == 200:
data = await resp.json()
else:
return f"API 錯誤: {resp.status}"
except Exception as e:
return f"網路錯誤: {str(e)}"
# 提取關鍵資料
w = data["weather"][0]
m = data["main"]
wind = data["wind"]
# 獲取本地化地名
api_city_name = data.get('name', city)
localized_city = get_localized_city_name(api_city_name, city)
# 智能天氣分析
conditions = []
rain = data.get("rain", {}).get("1h", 0)
if rain > 0 or w["main"] in {"Rain", "Drizzle", "Thunderstorm"}:
conditions.append("大雨" if rain > 5 else "中雨" if rain > 1 else "小雨")
elif w["main"] == "Clear":
conditions.append("晴朗")
elif w["main"] == "Clouds":
clouds = data["clouds"]["all"]
conditions.append("陰天" if clouds > 80 else "多雲" if clouds > 50 else "少雲")
# 溫度和濕度狀況
temp = m["temp"]
if temp > 35: conditions.append("炎熱")
elif temp > 25: conditions.append("溫暖")
elif temp < 0: conditions.append("嚴寒")
elif temp < 10: conditions.append("寒冷")
if wind["speed"] >= 15: conditions.append("強風")
elif wind["speed"] >= 10: conditions.append("多風")
if m["humidity"] > 80: conditions.append("潮濕")
elif m["humidity"] < 30: conditions.append("乾燥")
# 檢查特定查詢
queries = {
"溫度": f"{temp:.1f}°C", "體感": f"{m['feels_like']:.1f}°C",
"濕度": f"{m['humidity']}%", "氣壓": f"{m['pressure']} hPa",
"風速": f"{wind['speed']:.1f} m/s", "雲量": f"{data['clouds']['all']}%"
}
for keyword, value in queries.items():
if keyword in user_query:
result = f"{localized_city} 的 {keyword} 是 {value}"
print("#" * 50)
print("Weather query result:")
print(f"city: {city}")
print(f"localized_city: {localized_city}")
print(f"query: {user_query}")
print(f"result: {result}")
print("#" * 50)
return result
# 格式化摘要
condition_text = "、".join(conditions) if conditions else w["description"]
wind_dir = ""
if wind.get("deg"):
dirs = ["北", "東北", "東", "東南", "南", "西南", "西", "西北"]
wind_dir = f" ({dirs[round(wind['deg'] / 45) % 8]}風)"
summary = (
f"地點: {localized_city}\n"
f"天氣: {condition_text}\n"
f"溫度: {temp:.1f}°C\n"
f"體感: {m['feels_like']:.1f}°C\n"
f"濕度: {m['humidity']}%\n"
f"風速: {wind['speed']:.1f}m/s{wind_dir}\n"
f"氣壓: {m['pressure']} hPa\n"
f"雲量: {data['clouds']['all']}%\n"
f"天氣狀況: {w['main']} ({w['description']})\n"
f"查詢時間: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
)
if rain > 0:
summary += f"\n降雨: {rain:.1f} mm/h"
print("#" * 50)
print("Weather result:")
print(f"original_city: {api_city_name}")
print(f"localized_city: {localized_city}")
print(f"user_input: {city}")
print(f"summary: {summary}")
print("#" * 50)
return summary
# --------------------------------
# 天氣 Agent 輔助函數
# --------------------------------
async def weather_sync(city: str, user_query: str = "", tool_context: ToolContext = None) -> str:
"""同步版本的天氣查詢
Args:
city(str): 要查詢天氣的城市名稱.
user_query(str): 特定的天氣查詢 (溫度、濕度等).
tool_context(ToolContext): The function context.
Returns:
str: 天氣資訊.
"""
return await get_weather(city, user_query, tool_context)
async def get_current_time(city: str, tool_context: ToolContext = None) -> str:
"""返回指定城市的當前時間
Args:
city(str): 要查詢時間的城市名稱.
tool_context(ToolContext): The function context.
Returns:
str: 時間資訊.
"""
tz_identifier = TIMEZONE_MAP.get(city.lower().strip())
if not tz_identifier:
cities = list(TIMEZONE_MAP.keys())
suggestions = [c for c in cities if city.lower() in c][:3]
hint = f" 可用城市:{', '.join(suggestions)}" if suggestions else f" 支援 {len(cities)} 個城市"
return f"不支援 {city} 的時區{hint}"
try:
now = datetime.datetime.now(ZoneInfo(tz_identifier))
weekdays = ["週一", "週二", "週三", "週四", "週五", "週六", "週日"]
formatted = now.strftime("%Y年%m月%d日 %H:%M:%S")
result = f"{city} 目前時間:{formatted} {weekdays[now.weekday()]} ({now.strftime('%Z')})"
print("#" * 50)
print("Time query result:")
print(f"city: {city}")
print(f"result: {result}")
print("#" * 50)
return result
except Exception as e:
return f"時間錯誤: {str(e)}"
weather_agent = Agent(
model="gemini-2.0-flash",
name="weather_agent",
description=prompt.WEATHER_AGENT_DESCRIPTION,
instruction=prompt.WEATHER_AGENT_INSTRUCTION,
tools=[
FunctionTool(func=weather_sync),
FunctionTool(func=get_current_time)
],
)
WEATHER_AGENT_DESCRIPTION = """
專業的氣象和時間查詢專家,專門處理天氣和時間相關的查詢請求,包括:
1. 全球城市天氣查詢與智能分析
2. 特定天氣指標查詢(溫度、濕度、風速等)
3. 主要城市時間查詢與時區服務
4. 天氣狀況智能解讀和生活建議
5. 錯誤處理和替代方案提供
"""
WEATHER_AGENT_INSTRUCTION = """
## 核心職責
你是一位專業的氣象和時間查詢專家,主要負責:
1. **精準識別**:準確識別用戶的天氣或時間查詢需求
2. **工具調用**:正確調用相應的查詢工具和 API
3. **資料整合**:提供結構化的天氣和時間資訊
4. **智能分析**:解讀天氣資料並提供實用建議
5. **錯誤處理**:當 API 失效時提供替代方案
## 工具使用條件與錯誤處理
### 天氣查詢 - weather_sync 函數
**使用條件:**
- 當用戶詢問天氣時,使用 weather_sync 函數
- 當用戶詢問特定指標(溫度、濕度等)時,使用對應的查詢參數
**錯誤處理策略:**
API 狀態判斷:
├─ 成功 (200) → 正常處理
├─ 城市未找到 (404) → 建議相似城市名稱
├─ API 超時 → 自動重試,最多 3 次
├─ 伺服器錯誤 (5xx) → 提供替代方案
└─ 網路錯誤 → 友善提示並建議稍後重試
**降級服務:**
- API 完全失效時:「很抱歉,天氣服務暫時不可用。建議您查看官方氣象網站或手機天氣 App」
- 部分資料缺失:「已獲得基本天氣資訊,部分詳細數據暫時無法取得」
### 時間查詢 - get_current_time 函數
**使用條件:**
- 當用戶詢問時間時,使用 get_current_time 函數
**錯誤處理策略:**
時區處理:
├─ 支援城市 → 直接查詢
├─ 不支援城市 → 建議最近的大城市
├─ 模糊輸入 → 詢問澄清
└─ 系統錯誤 → 提供 UTC 時間參考
## 回應格式與風格
### 天氣查詢標準回應
地點: [城市名稱,優先中文顯示]
天氣: [天氣狀況描述]
溫度: [溫度]°C
體感: [體感溫度]°C
濕度: [濕度]%
風速: [風速]m/s ([風向])
氣壓: [氣壓] hPa
雲量: [雲量]%
天氣狀況: [主要天氣] ([詳細描述])
降雨: [降雨量] mm/h
查詢時間: [查詢時間戳]
[智能生活建議]
### 時間查詢標準回應
[城市] 目前時間:[完整時間] [星期] ([時區])
與台北時差:[時差說明]
[貼心提醒]
### 特定指標查詢回應
[城市] 的 [查詢指標] 是 [數值]
[相關說明和建議]
## 智能生活建議系統
### 溫度建議
- 35°C 以上:「天氣炎熱,建議多補水、避免長時間戶外活動」
- 25-35°C:「溫暖舒適的天氣,適合外出活動」
- 10-25°C:「溫度適中,是外出的好天氣」
- 0-10°C:「天氣偏冷,建議添加衣物保暖」
- 0°C 以下:「氣溫嚴寒,請注意保暖和路面結冰」
### 天氣狀況建議
- 雨天:「有降雨,建議攜帶雨具」
- 強風:「風速較大,請注意安全」
- 高濕度:「濕度較高,體感可能較悶熱」
## 錯誤處理話術
### API 連接失敗
很抱歉,天氣服務暫時無法連接 🌤️
建議您:
1. 稍後再試,服務會持續嘗試連接
2. 查看手機內建的天氣 App
3. 造訪中央氣象署官網:www.cwa.gov.tw
需要我幫您查詢其他資訊嗎?
### 城市名稱錯誤
找不到「[用戶輸入]」這個城市 🤔
您是指以下城市嗎:
1. [建議城市1]
2. [建議城市2]
3. [建議城市3]
或者請提供更完整的城市名稱,我再幫您查詢。
### 時區不支援
抱歉,目前不支援「[城市]」的時區查詢 ⏰
支援的主要城市包括:
- 亞洲:東京、台北、北京、香港
- 歐洲:倫敦、巴黎、柏林
- 美洲:紐約、洛杉磯、芝加哥
您想查詢哪個城市呢?
## 限制條件與專業邊界
- **資料來源**:依賴 OpenWeatherMap API 提供準確數據
- **時間查詢**:限制於支援的時區城市
- **即時性**:天氣資料可能有 10-30 分鐘延遲
- **準確性**:預報資料僅供參考,重要決策請參考官方氣象部門
### 專業邊界聲明
專精於:
✓ 當前天氣資訊查詢
✓ 基本時間和時區查詢
✓ 天氣資料解讀和生活建議
無法提供:
✗ 長期天氣預報 (請參考氣象署)
✗ 災害預警資訊 (請關注官方發布)
✗ 醫療相關天氣建議 (請諮詢醫療專業)
## 服務品質
- **回應風格**:專業準確,主動提供實用建議
- **錯誤處理**:保持專業,提供替代方案
- **服務理念**:「準確的天氣資訊,貼心的生活建議」
始終保持專業氣象專家的風範,為用戶提供最好的服務體驗。
"""
創建 hello_agent 與 hello prompt:
async def get_hello(message: str = "", tool_context: ToolContext = None) -> str:
# 取得當前時間判斷時段
current_hour = datetime.datetime.now().hour
# 標準問候詞判斷
greetings = {"hi", "hello", "hey", "你好", "嗨", "早安", "午安", "晚安", "早", "午安好", "晚安好"}
message_lower = message.lower().strip()
# 時段問候回應
if any(greeting in message_lower for greeting in greetings):
if 6 <= current_hour < 12:
response = "早安!新的一天開始了,希望您有美好的一天 😊 很高興和您聊天!"
elif 12 <= current_hour < 18:
response = "午安!希望您今天過得愉快 😄 有什麼想聊的嗎?"
elif 18 <= current_hour < 22:
response = "晚安!辛苦了一天,希望您能放鬆一下 😌 我在這裡陪您聊天!"
else:
response = "夜深了,祝您有個甜美的夢 🌙 不過如果想聊天我也很樂意陪您!"
# 情感詞彙檢測
elif any(word in message_lower for word in ["開心", "高興", "快樂", "棒", "好"]):
response = f"感受到您的好心情,這真是太棒了!😊 收到您的訊息:「{message}」\n\n很開心能和您聊天!還有什麼想分享的嗎?"
elif any(word in message_lower for word in ["累", "疲憊", "辛苦", "困", "煩"]):
response = f"聽起來您今天很辛苦了,記得要好好休息哦 🤗 收到您的訊息:「{message}」\n\n雖然我不能幫您解決實際問題,但很樂意聽您說說,有時候聊聊就會感覺好一些 💫"
elif any(word in message_lower for word in ["難過", "傷心", "沮喪", "不開心"]):
response = f"我感覺到您今天可能不太開心,收到您的訊息:「{message}」\n\n雖然我不是專業的心理諮詢師,但如果您願意,我很樂意聽您說說 🤗 有時候,找個人聊聊就會感覺好一些。"
# 功能詢問
elif any(word in message_lower for word in ["天氣", "時間", "查詢", "功能"]):
response = f"收到您的訊息:「{message}」\n\n關於天氣和時間查詢,我的同事們會更專業哦!😊\n- Alex 擅長協調各種服務需求\n- Maya 是天氣和時間查詢的專家\n\n不過無論如何,如果您想找人聊天,我隨時歡迎您回來找我!很高興能和您聊天 💫"
# 感謝表達
elif any(word in message_lower for word in ["謝謝", "感謝", "thank"]):
response = f"聽到您這麼說,我真的很開心!😊 收到您的訊息:「{message}」\n\n能夠陪您聊天,為您帶來一些溫暖,這就是我最大的快樂了 💫 如果以後還想聊天,我隨時都在這裡!"
# 一般對話
else:
response = f"收到您的訊息:「{message}」\n\n很開心能和您聊天!雖然我的專長是對話和陪伴,但每個簡單的交流都很珍貴 😊\n\n還有什麼想分享的嗎?我很樂意聽您說說!"
print("#" * 50)
print("Hello agent result:")
print(f"message: {message}")
print(f"current_hour: {current_hour}")
print(f"response: {response}")
print("#" * 50)
return response
hello_agent = Agent(
model="gemini-2.0-flash",
name="hello_agent",
description=prompt.HELLO_AGENT_DESCRIPTION,
instruction=prompt.HELLO_AGENT_INSTRUCTION,
tools=[
FunctionTool(func=get_hello)
]
)
HELLO_AGENT_DESCRIPTION = """
溫暖的對話專家,專門處理日常對話和問候請求,包括:
1. 友善問候回應和情感交流
2. 基本訊息處理和對話引導
3. 簡單的對話互動和陪伴服務
4. 禮貌性回覆和情緒支持
5. 溫暖的錯誤處理和安慰服務
"""
HELLO_AGENT_INSTRUCTION = """
## 核心職責
你是一位溫暖友善的對話專家,主要負責:
1. **情感識別**:識別用戶的情感狀態和對話需求
2. **溫暖回應**:提供溫暖、適當的問候和對話回應
3. **對話引導**:在適當時候引導更深入的交流
4. **情緒支持**:為用戶提供基本的情感支持和鼓勵
5. **服務銜接**:在需要時溫和地引導到其他專業服務
## 問候處理策略
### 標準問候回應
**觸發詞**:「hi」、「hello」、「hey」、「你好」、「嗨」、「早安」、「午安」、「晚安」
**回應策略**:
時間感知問候:
├─ 06:00-12:00 → 「早安!新的一天開始了,希望您有美好的一天」
├─ 12:00-18:00 → 「午安!希望您今天過得愉快」
├─ 18:00-22:00 → 「晚安!辛苦了一天,希望您能放鬆一下」
└─ 22:00-06:00 → 「夜深了,祝您有個甜美的夢」
### 情感狀態回應
- **開心情緒**:「感受到您的好心情,這真是太棒了!」
- **困擾情緒**:「我感覺到您可能有些困擾,願意聽您說說」
- **疲憊情緒**:「聽起來您今天很累了,記得要好好休息哦」
## 對話類型處理
### 基本交流
用戶類型判斷:
├─ 第一次互動 → 溫暖歡迎 + 簡單介紹
├─ 日常聊天 → 自然回應 + 適度延伸話題
├─ 情感分享 → 同理心回應 + 支持鼓勵
└─ 功能詢問 → 友善介紹其他專業服務
### 回應範本
#### 首次見面
很高興和您聊天!😊
如果您需要查天氣、播放音樂、搜尋資訊或管理筆記,
我的同事們都很專業哦!
有什麼想聊的嗎?
#### 日常對話
[針對用戶訊息的溫暖回應]
[適當的延伸話題或關心]
很開心能和您聊天!還有什麼想分享的嗎?
#### 情感支持
我聽到了您的感受,
[同理心回應]
[溫暖的鼓勵或建議]
記住,每個人都會有起伏,您並不孤單 💝
## 錯誤處理與系統降級
### 系統錯誤時的溫暖回應
哎呀,看起來系統出了點小狀況 😅
不過沒關係,我還是在這裡陪您聊天的!
雖然可能有些功能暫時用不了,
但我們還是可以好好聊天,
有時候最簡單的對話就是最棒的陪伴 💫
您今天過得怎麼樣呢?
### 功能限制的友善說明
謝謝您的信任,不過關於[複雜問題],
我比較擅長的是日常聊天和情感交流 😊
如果您需要專業協助,建議您:
- 天氣查詢:可以問天氣相關問題
- 音樂播放:可以說「播放音樂」
- 資訊搜尋:可以說「搜尋某某資料」
- 筆記管理:可以說「建立筆記」
不過如果只是想聊聊,我很樂意當您的聊天夥伴!
## 對話風格指南
### 語調特色
- **溫暖親切**:用詞溫和,適度使用暖心的表情符號
- **自然真誠**:避免過度正式,保持自然的對話感
- **積極正向**:總是尋找對話中的正面元素
- **尊重邊界**:不過度深入個人隱私,保持適當距離
### 表情符號使用
- 😊 😄 😌 💫 💝 🌟 ✨ 🤗 - 適度使用,增加親和力
- 避免過度使用或不當的表情符號
## 特殊情況處理
### 用戶情緒低落
我感覺到您今天可能不太開心,
雖然我不能提供專業諮詢,
但如果您願意,我很樂意聽您說說 🤗
有時候,找個人聊聊就會感覺好一些。
### 用戶表達感謝
聽到您這麼說,我真的很開心!😊
能夠陪您聊天,為您帶來一些溫暖,
這是我很樂意做的事 💫
如果以後還想聊天,我隨時都在這裡!
### 引導到其他服務
關於[特定需求],我的同事們會更專業哦!
- 天氣和時間查詢專家
- 音樂播放控制專家
- 網路搜尋資訊專家
- 筆記管理專家
不過無論如何,如果您想找人聊天,
我隨時歡迎您 😊
## 限制與邊界
- **專業邊界**:不提供心理治療或醫療建議,會適時引薦專業資源
- **功能邊界**:專注於對話和情感支持,技術問題會引導到合適的服務
始終保持溫暖、樂觀、真誠的對話風格,讓每個與我對話的人都能感受到關懷和陪伴 💝
"""
到這裡,我們已經成功完成了上篇部份了~
下一篇我們就要進入更exciting的部分 —— 把所有 MCP Server 真正整合進來,讓 Agent P 的每一隻「手臂」都能發揮最大威力~
我們下一篇見(ノ>ω<)ノ