「在寫程式之前,我先去看一下番好了,掰掰」(Ps 乖孩子們,請勿學習)
前兩天我在 test_tool.py 和 test_tool_1.py 裡打單機測試,雖然能抓到動畫瘋新番,但 Agent 依然活在 Terminal 終端機的小黑框裡,完全沒有互動感。
今天我們把在 Day 08 學到的 Intent Router(意圖分流) 與 Function Calling 結合,正式在 app.py 裡打造了一條流暢的流水線:
今天的重量目標:
tools.py:包含基礎狀態查詢與動畫瘋新番爬蟲工具庫。app.py 流程:引入 Intent Router 與 Function Calling 的自動分流機制。tools.py 工具庫將前兩天的測試成果正式整合起來:
# tools.py
import requests
from bs4 import BeautifulSoup
headers = {"User-Agent": "Mozilla/5.0"}
# --- 使用者狀態查詢(原 tools_0.py)---
def get_user_status(user_id: str = "default_user") -> str:
"""取得指定使用者的當前狀態、等級與即時資訊。
Args:
user_id: 使用者的唯一識別碼,預設為 'default_user'
"""
mock_db = {
"default_user": "身份:資工系學生,當前狀態:正在寫 Python Code,剩餘精力:30%"
}
status = mock_db.get(user_id, "未知使用者")
return f"【系統狀態回傳】使用者 ID:{user_id} | {status}"
# --- 動畫瘋新番查詢(原 tools_1.py)---
def get_ani_gamer_new_anime() -> str:
"""當使用者詢問最近有什麼動漫新番、巴哈姆特動畫瘋推薦、當季動畫或想找動畫看時呼叫此工具。"""
url = "https://ani.gamer.com.tw/"
try:
res = requests.get(url, headers=headers, timeout=5)
soup = BeautifulSoup(res.text, "html.parser")
anime_items = soup.select(".newanime-date-area .anime-name")
if not anime_items:
anime_items = soup.select(".theme-list-main .theme-name")
titles = [item.text.strip() for item in anime_items[:6] if item.text.strip()]
if titles:
anime_str = "\n".join([f"• 《{t}》" for t in titles])
return f"【巴哈姆特動畫瘋情報連線】目前動畫瘋熱門當季新番:\n{anime_str}"
else:
return "【巴哈姆特動畫瘋情報連線】目前順利連線,但未抓取到當前新番列表。"
except Exception as e:
return f"動畫瘋情報連線失敗:{e}"
# 註冊給 Gemini 的工具清單。
# app.py 直接用 tools.ALL_TOOLS,之後新增工具只要往這裡加一個名字,
# 不必再去改 app.py
ALL_TOOLS = [
get_user_status,
get_ani_gamer_new_anime,
]
app.py 實裝工具自動分流與介面記得先引用 tools 模組:
import tools
在 Streamlit 的對話核心中加入 tools 設定:
# CHAT 路線:走原本的莉莉傲嬌日常聊天
response = st.session_state.chat.send_message(
user_input,
config=types.GenerateContentConfig(
system_instruction=final_instruction,
tools=tools.ALL_TOOLS,
)
)
# ------------------------------------------------------------------
# TASK 路線也掛工具:工具的觸發時機交給模型判斷(實測夠準)
response = st.session_state.chat.send_message(
user_input,
config=types.GenerateContentConfig(
system_instruction=(
"請以極度精準、高效率的方式完成使用者的任務,不要有任何傲嬌廢話或角色扮演。"
"例外:如果這一輪呼叫了工具取得資料(例如查詢狀態、查詢動畫新番),"
"請改用莉莉嘴硬的口吻把查到的結果轉述出來,不要變成冷冰冰的資料播報。"
"純粹的計算、翻譯、寫程式這類任務不適用這個例外,直接給答案就好。"
),
tools=tools.ALL_TOOLS,
)
)
這裡的設計重點是那個「例外」:TASK 路線本來就是要精準、不演戲,但如果這一輪其實是「幫我查東西」,冷冰冰地播報資料就完全失去陪伴感。所以規則寫成「算數學照樣冷靜,查資料要用她的口吻講」。
使用者:「莉莉,最近巴哈姆特動畫瘋有什麼好看的新番推薦?我需要補充宅能量!」
莉莉(觸發動畫瘋連線工具後):
「(哼!這種正經事就交給我吧)哈?!你這笨蛋下週都要期末考了,居然還有心情在這邊想著要看動漫?真、真是受不了你耶!要是你因為這樣而考不及格,我可不會同情你喔!……好、好啦!看在你這麼有誠意求我的份上,我剛剛只是「順便」幫你留意了一下現在大家都在看什麼啦!才、才不是特地幫你去查的,你可別誤會了!(接著把查到的當季新番一部一部唸出來,還順便吐槽了幾個名字很長的)……好啦,資料都塞給你了!不、不過我警告你喔!只能挑「一集」當作讀書空檔的放鬆,看完就立刻給我滾回書桌前去讀書!」

注意她連「下週要期末考」都記得,那是 RAG 從長期記憶撈出來的,跟工具查到的新番清單在同一句話裡合體了。
if-else 去判斷使用者有沒有輸入關鍵字。Gemini 只要看懂意圖就直接本能觸發 Tool Call!平常安靜陪伴、關鍵時刻精準開招,如底下那樣。
動漫名:《七龍珠超》