跳到主要內容

AG Day 27 MCP 進階:resources、prompts 與多工具 server

AG Day 27 MCP 進階:resources、prompts 與多工具 server

執行需求:CPU 可跑。昨天的 AG Day 26 第一個 MCP server:用 FastMCP(原文連結)我們用 FastMCP 把昨天的最小骨架升級成正式的 MCP server,並示範了 echo 與 add 兩個 tool。今天要把 server 的另外兩種能力補齊:resources(可被客戶端存取的資料,例如研究筆記、設定檔、知識快照)與 prompts(預先設計好的提示範本,可帶參數)。把這三種能力組合起來,server 就不再只是「員工」,而是「員工加圖書館加顧問公司」。我們會把 AG Day 23 引用與出處(原文連結)建立的 SQLite 知識庫包成 resource、把研究報告模板包成可重複使用的 prompt,並設計一個包含三種能力的完整 server。本篇完全在本機 CPU 上執行,不需要任何 API 金鑰。

引言

昨天的 server 只能「做事」——呼叫工具就執行一段邏輯、回傳結果。但在真實的研究助理場景裡,使用者經常會需要「讀資料」:他想看看昨天抓了哪些來源、某個主題曾經寫過哪些報告、儲存的引用清單長什麼樣子。這些需求用 tool 來實作當然可以(fetch_note、fetch_report),但規格已經為這種「客戶端主動拉取」的需求設計了一個更合適的能力:resource。

同樣地,研究助理也經常會需要「套用對話策略」:當使用者要求「寫一份正式報告」,我們可能想套用「結論先行、引述加註、不確定要坦白」這套策略;當使用者要求「快速摘要」,策略又完全不同。如果每次都要在 system prompt 重新描述這些規則,會很冗長也容易漏寫。MCP 的 prompt 能力正好解決這個問題:伺服器可以預先設計好幾套帶參數的範本,客戶端或使用者直接挑選套用。

今天的目標是把這三種能力放在同一個 server 裡,讓一個伺服器同時具備「做事、讀資料、給建議」三種角色。程式碼會比昨天略長,但每一段都會對應到一個明確的能力,讀完之後你應該能直接把這套模式套到你自己的應用領域(客服、財務報表、法律書狀⋯⋯)。

原理/觀念

Resource:帶 URI 的可存取資料

在 MCP 規格裡,resource 用「URI」作為識別:notes://research/last-week 可能代表「上週所有研究筆記的清單」,report://2026-08-05 可能代表「2026-08-05 那一天產出的報告」。URI 可以是任何合理的字串,常見的慣例是用 scheme(notes://、reports://、config://)區分資料類型,路徑部分用動態參數(例如日期、編號)做變化。

Resource 與 tool 的差異有兩個重點。第一,resource 通常不是由模型主動呼叫,而是由客戶端根據上下文決定要不要讀取:例如「使用者開啟了某個檔案」「使用者提到了上週的會議」這類觸發條件,由客戶端判斷後主動 resources/read。第二,resource 的內容通常較大且較靜態:它是「資料」而不是「動作」,可以被快取、可以分頁、可以訂閱變更(規格有列出 resources/subscribe,但實作細節依版本而異)。

FastMCP 用 @mcp.resource(uri) 裝飾器把函式註冊成 resource。函式的回傳值會被自動包成 resource 內容物件,內容可以是純文字、JSON 編碼後的字串、或二進位資料的 base64 表示。今天我們只示範文字與 JSON 兩種,圖片與其他型別依需求再擴充。

Prompt:可重複使用的對話範本

Prompt 是「預先寫好的提示範本」。與 resource 不同,prompt 通常帶有參數,使用時可以根據當下情境填入。例如一個「研究助理報告」prompt 可能長這樣:

請依下列主題撰寫研究報告:
主題:{topic}
引用規則:每個事實性敘述後面加上 [n],n 為引用編號
長度限制:1500 字以內

當使用者說「幫我寫一份關於邊緣運算功耗的報告」,客戶端可以把 topic 填入「邊緣運算功耗」,再把整段 prompt 餵給模型。這個模式的價值是「把對話策略集中管理」:客戶端不需要知道每個 prompt 的細節,只需要呼叫 prompts/list 取得清單,再根據使用者需求選用。

FastMCP 用 @mcp.prompt() 裝飾器註冊 prompt。函式簽名裡的參數會自動成為 prompt 的輸入欄位;函式回傳的字串就是 prompt 內容。今天我們會示範兩個 prompt:研究報告與摘要改寫。

三種能力該怎麼選

「這個東西到底應該做成 tool、resource 還是 prompt?」是 MCP 設計裡最常見的取捨問題。一個粗略的判斷原則是:有副作用、需要執行某段邏輯 → tool;是被讀取的靜態或半靜態資料 → resource;是對話策略或使用流程 → prompt。但這條界線不是死的:一段「把資料庫內容摘要給模型」的邏輯既可以做成 tool(summarize_notes(topic))也可以做成 resource(notes://{topic}/summary)。選哪個,取決於「誰觸發它」——由模型決定觸發的,比較像 tool;由客戶端或使用者根據上下文觸發的,比較像 resource。

多工具 server 的命名空間紀律

當一個 server 同時提供十幾個工具、幾個 resource、幾個 prompt 時,命名空間就會開始碰撞。常見的紀律有兩條:第一,工具名稱用動詞開頭(fetch_page、search_web、add_numbers),讓模型一看就知道這是做什麼;第二,resource URI 用 scheme 前綴(notes://、reports://),讓客戶端能用前綴區分資料來源;prompt 則用領域前綴(research_report、chat_summarize),避免不同領域的 prompt 名稱混雜。

第二條紀律在多個 server 並存時更重要:當你同時掛了三個 MCP server,工具名稱可能重複(echo、echo_text 都是合理的命名)。FastMCP 在單一 server 內不允許同名工具,但你可以在 name 裡加上副檔名或前綴(research-agent-basic、research-agent-notes),讓客戶端在呼叫時依 server 區分。今天的範例會在 server name 加上 -research 後綴,示範這個命名空間設計。

完整實作

接下來在昨天建立的 basic_server.py 基礎上,加入 resources 與 prompts。先安裝額外依賴、再擴充 server、最後用官方客戶端驗證三種能力都能正常運作。

第一步,先把我們需要的依賴安裝好。今天會用到 pydantic 做資源內容的結構化驗證,以及昨天的 FastMCP:

cd research-agent
uv add fastmcp pydantic
uv lock

段落說明:FastMCP 在內部已經把 pydantic 列為依賴,這裡再 add pydantic 是為了顯式控制版本,讓團隊其他人能直接看到我們用了什麼 Pydantic(v2 系列)。如果你的環境裡已經有 Pydantic,uv add 不會降級,只會鎖定到與目前 FastMCP 相容的版本。版本具體為何請以 uv.lock 為準。

第二步,建立存放 resources 與 prompts 的子模組。為了讓 server 主檔保持簡潔,我們把這兩種能力拆到獨立的檔案:

touch research-agent/src/research_agent/mcp_servers/resources.py
touch research-agent/src/research_agent/mcp_servers/prompts.py

段落說明:拆檔的理由是「關注點分離」:server 主檔負責啟動與模組組裝,resources 模組只負責資料暴露,prompts 模組只負責對話範本。之後若要新增工具、資源或 prompt,只要在對應的檔案裡加一個函式與一個裝飾器即可,主檔不需修改。

第三步,建立 resource。我們的 resource 會從 AG Day 23 建立的 data/knowledge.db 讀取文獻清單與單一文獻內容。注意資源內容需要是可序列化的純資料:

"""research-agent/src/research_agent/mcp_servers/resources.py
暴露 SQLite 知識庫的內容作為 MCP resources。
"""
import sqlite3
from pathlib import Path

from basic_server import mcp

DB_PATH = Path("data/knowledge.db")


@mcp.resource("research://documents/index")
def documents_index() -> str:
    """列出所有已抓取的文獻(id、標題、抓取時間)。"""
    if not DB_PATH.exists():
        return "[]"
    conn = sqlite3.connect(DB_PATH)
    try:
        rows = conn.execute(
            "SELECT id, title, fetched_at FROM documents ORDER BY fetched_at DESC LIMIT 50"
        ).fetchall()
    finally:
        conn.close()
    import json

    return json.dumps(
        [
            {"id": row[0], "title": row[1] or "(未命名)", "fetched_at": row[2]}
            for row in rows
        ],
        ensure_ascii=False,
    )


@mcp.resource("research://documents/{doc_id}")
def document_detail(doc_id: str) -> str:
    """取得單一文獻的標題與抓取時間;doc_id 是文獻識別。"""
    if not DB_PATH.exists():
        return "{}"
    conn = sqlite3.connect(DB_PATH)
    try:
        row = conn.execute(
            "SELECT id, title, fetched_at FROM documents WHERE id = ?",
            (doc_id,),
        ).fetchone()
    finally:
        conn.close()
    if row is None:
        return "{}"
    import json

    return json.dumps(
        {"id": row[0], "title": row[1] or "(未命名)", "fetched_at": row[2]},
        ensure_ascii=False,
    )

段落說明:research:// 是我們為這個 server 選定的 scheme,讓客戶端能用前綴區分這是研究助理提供的資源。資源 URI 內的 {doc_id} 是 FastMCP 的動態參數語法,客戶端呼叫 resources/read 時可以代入實際值,FastMCP 會把這個值傳給函式。我們刻意把 import json 放在函式內部而非模組頂層,這是為了讓資源函式在 SQLite 不存在時也能被 import(不會拋 FileNotFoundError)。實務上若你的 SQLite 一定存在,可以把 import 提到頂層。

第四步,建立 prompt。我們設計兩個 prompt:研究報告(需要 topic 參數)與摘要改寫(需要 text 與 target_length 兩個參數):

"""research-agent/src/research_agent/mcp_servers/prompts.py
研究助理專用的提示範本,集中管理對話策略。
"""
from basic_server import mcp


@mcp.prompt()
def research_report(topic: str) -> str:
    """產生研究報告的提示範本;topic 為研究主題。"""
    return (
        "你是一名研究助理,請根據使用者提供的來源段落,"
        f"撰寫一份關於「{topic}」的研究報告。\n"
        "規則:\n"
        "1. 每個事實性敘述後面加上 [n] 編號,n 為引用編號。\n"
        "2. 一句話可引用多個來源,例如 [1][3]。\n"
        "3. 若來源不足請明確寫『來源不足』,不要臆測。\n"
        "4. 結論放在報告開頭,論點依重要性排列。\n"
        "5. 全文使用繁體中文 Markdown,長度控制在 1500 字以內。"
    )


@mcp.prompt()
def chat_summarize(text: str, target_length: int = 200) -> str:
    """把一段對話或文章摘要成指定字數。"""
    return (
        "請把下列文字摘要成約 " + str(target_length) + " 個繁體中文字:\n\n"
        + text
    )

段落說明:research_report 接收一個 topic 參數,函式把參數嵌入 prompt 字串後回傳。FastMCP 會把這個函式連同它的參數清單一起暴露給客戶端,客戶端在使用時填入實際值。chat_summarize 則展示「帶預設值的參數」:target_length 預設 200,但客戶端可以覆寫。把這兩個 prompt 放在同一個檔案是為了「對話策略集中管理」;未來新增 prompt 只要在同一個檔案裡加函式即可。

第五步,把 resources 與 prompts 模組 import 進主檔,讓 server 啟動時自動收集所有能力:

"""research-agent/src/research_agent/mcp_servers/basic_server.py
包含三種能力的 FastMCP server:tools、resources、prompts。
"""
from fastmcp import FastMCP

mcp = FastMCP(name="research-agent-basic")


@mcp.tool()
def echo(text: str) -> str:
    """回傳收到的字串;用於驗證通訊是否正確。"""
    return text


@mcp.tool()
def add(a: int, b: int) -> int:
    """把兩個整數相加並回傳結果。"""
    return a + b


# 匯入其他模組;副作用是把它們的 @mcp.tool / @mcp.resource / @mcp.prompt 收集進來
from . import resources  # noqa: E402, F401
from . import prompts  # noqa: E402, F401


if __name__ == "__main__":
    mcp.run()

段落說明:這是昨天介紹過的「模組化 import」慣例的延伸版。當一個檔案同時引入多個子模組時,請用註解說明這個 import 是為了觸發註冊,而不是真的要用這個符號,否則下一個讀你程式碼的人會以為是 bug 而把它刪掉。noqa 註解跟昨天一樣用來忽略 lint 警告。

第六步,用客戶端測試三種能力。我們擴充昨天的 stdio_client.py,把 list 與 read 工具/資源、取得 prompt 都跑一次:

"""research-agent/scripts/mcp_min/full_client.py
測試 basic_server 的三種能力:tools、resources、prompts。
"""
import asyncio

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


async def main() -> None:
    params = StdioServerParameters(
        command="python",
        args=["src/research_agent/mcp_servers/basic_server.py"],
    )
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            tools = await session.list_tools()
            resources = await session.list_resources()
            prompts = await session.list_prompts()

            print("=== Tools ===")
            for tool in tools.tools:
                print(f"- {tool.name}: {tool.description}")

            print("=== Resources ===")
            for resource in resources.resources:
                print(f"- {resource.uri}: {resource.name}")

            print("=== Prompts ===")
            for prompt in prompts.prompts:
                print(f"- {prompt.name}: {prompt.description}")

            # 讀取資源
            content = await session.read_resource("research://documents/index")
            print("=== 文獻清單 ===")
            print(content.contents[0].text)

            # 取得 prompt
            prompt = await session.get_prompt(
                "research_report",
                {"topic": "邊緣運算功耗"},
            )
            print("=== research_report prompt ===")
            print(prompt.messages[0].content.text)


if __name__ == "__main__":
    asyncio.run(main())

段落說明:list_resources() 回傳所有 resource 的 URI 與名稱;read_resource() 接受一個 URI 並回傳資源內容。get_prompt() 則需要傳入 prompt 名稱與參數字典;回傳的 messages 結構遵循 MCP 規格,每個 message 帶有 role 與 content,內容物件可以是文字或圖片。今天我們只用到文字內容。執行後你會看到類似以下的輸出:

uv run python scripts/mcp_min/full_client.py
=== Tools ===
- echo: 回傳收到的字串;用於驗證通訊是否正確
- add: 把兩個整數相加並回傳結果
=== Resources ===
- research://documents/index: documents_index
- research://documents/{doc_id}: document_detail
=== Prompts ===
- research_report: 產生研究報告的提示範本;topic 為研究主題
- chat_summarize: 把一段對話或文章摘要成指定字數
=== 文獻清單 ===
[{"id": "https://example.invalid/edge-power", "title": "(示範頁面)", "fetched_at": "2026-08-07T..."}]
=== research_report prompt ===
你是一名研究助理,請根據使用者提供的來源段落,撰寫一份關於「邊緣運算功耗」的研究報告。
規則:
1. 每個事實性敘述後面加上 [n] 編號,n 為引用編號。
2. 一句話可以引用多個來源,例如 [1][3]。
...

段落說明:上面看到的資源內容是 dry-run 與示意資料:你的 SQLite 若還沒有真實抓取紀錄,會得到空清單或預設值。Prompt 內容則是我們剛剛設計的範本,topic 被順利代入「邊緣運算功耗」。這個端到端測試確認了三件事:tools、resources、prompts 都被正確註冊;resource 能讀到 SQLite 資料;prompt 的參數能被正確填入。

第七步,做權限與範圍的最小區隔。雖然 MCP 規格本身不包含存取控制,但實務上你會希望「某些資源只能給特定使用者讀取」。最簡單的做法是在 resource 函式內部加上檢查:

"""research-agent/src/research_agent/mcp_servers/resources.py(節錄)
把權限檢查包裝成裝飾器,所有 resource 共用同一套邏輯。
"""
from functools import wraps

from basic_server import mcp


def require_role(role: str):
    """簡單的角色檢查裝飾器;正式產品請改用真實的身分驗證。"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            current = kwargs.pop("_current_role", "anonymous")
            if current != role:
                return "{\"error\": \"權限不足\"}"
            return func(*args, **kwargs)
        return wrapper
    return decorator


@mcp.resource("research://admin/audit")
@require_role("admin")
def audit_log() -> str:
    """回傳最近的審查紀錄;僅限 admin 角色讀取。"""
    return "[]"

段落說明:require_role 是教學用的極簡實作,它用一個隱含的 _current_role 參數決定是否放行。真正的權限檢查應該依賴外部的身分驗證系統(例如 OAuth、JWT),而不是把角色藏在函式參數裡。今天的範例只是示範「資源函式可以加上存取邏輯」,正式產品請把權限邏輯交給你的身分驗證層。這與 AG Day 37 談 prompt injection 與工具防護時會再次碰到的「信任邊界」主題有關。

第八步,把今天的進度記錄下來,並為明天的 client 章節預備。我們把 server 的三種能力整理成一張表,方便之後查閱:

"""research-agent/src/research_agent/mcp_servers/manifest.py
伺服器能力清單,供客戶端與部署工具使用。
"""
CAPABILITIES = {
    "tools": [
        {"name": "echo", "description": "回傳收到的字串"},
        {"name": "add", "description": "把兩個整數相加"},
    ],
    "resources": [
        {"uri": "research://documents/index", "name": "documents_index"},
        {"uri_pattern": "research://documents/{doc_id}", "name": "document_detail"},
        {"uri": "research://admin/audit", "name": "audit_log", "role": "admin"},
    ],
    "prompts": [
        {"name": "research_report", "params": ["topic"]},
        {"name": "chat_summarize", "params": ["text", "target_length"]},
    ],
}


def render() -> str:
    import json
    return json.dumps(CAPABILITIES, ensure_ascii=False, indent=2)


if __name__ == "__main__":
    print(render())

段落說明:這個 manifest 不是 MCP 規格的一部分,它是我們自己寫的「對外公告」。當客戶端需要知道「這個 server 提供哪些能力」的靜態描述時,可以直接讀這個檔;當部署工具(例如 CI 流程或安全掃描)需要知道 server 暴露的表面積時,也可以用它來審查。把 manifest 與實際註冊保持同步是個工程紀律,可以在 server 啟動時自動產生,避免手動維護造成的落差。

常見錯誤與踩雷

第一個錯誤是 resource 的 URI 太通用了。像是 notes://all 這種 URI 看起來簡潔,但客戶端無法依 URI 模式做自動化處理;請用「scheme://類型/識別」的結構(例如 notes://user/2026-08-05),保留足夠的命名空間深度。

第二個錯誤是把 prompt 寫成純字串模板卻忘了帶參數。如果 prompt 裡寫了 {topic} 卻沒在函式簽名宣告 topic: str,客戶端不會知道要代入什麼。請把參數宣告與使用視為同一件事,缺一就會出現「客戶端送參數、伺服器忽略」或「客戶端沒送參數、伺服器拋例外」兩種失敗模式。

第三個錯誤是 resource 函式回傳值無法序列化。MCP 規格要求資源內容是可序列化的純資料。如果你回傳了一個 ORM 物件或自訂類別實例,序列化會失敗。請把資料先轉成 dict/list/基本型別,再用 JSON 字串包起來(範例裡用 json.dumps(...) 就是為了這個)。

第四個錯誤是忘記處理資源不存在。當客戶端送來 research://documents/no-such-id,我們的函式若沒處理「查不到」的情況,會回傳空字串或拋例外。請在函式內部處理空值並回傳明確的錯誤結構,例如 {"error": "not_found"},讓客戶端能區分「資源不存在」與「伺服器錯誤」。

第五個錯誤是 prompt 內容太長。prompt 會被整段塞進模型上下文,寫了一萬字的「完整對話策略」反而會擠壓後續訊息的空間。請把 prompt 控制在合理長度(通常一千字以內),把細節放在工具說明或 system prompt 裡。

第六個錯誤是把工具、資源、提示三者的命名混用。例如把 fetch_note 同時做成 tool 與 resource,客戶端就搞不清楚該用 tools/call 還是 resources/read。三種能力各有其使用情境,請在設計時先決定歸屬,事後才發現衝突要改的話,所有客戶端都會受影響。

第七個錯誤是 server name 沒換。當你複製 basic_server.py 改成另一個 server 卻忘記改 name,兩個 server 會在客戶端用相同名字出現,造成混淆。請把 server name 視為版本的一部分,每次改 server 都 bump 一下。

效能與實務提醒

先談 resource 的存取成本。讀 SQLite 通常很快,但若資源函式會觸發昂貴的計算(例如把整個知識庫做摘要),請考慮兩件事:第一,把昂貴的部分事先算好、存成另一個 resource URI(例如 research://summaries/2026-08-07),讓客戶端讀的是快取版本;第二,把昂貴運算移到背景行程,不要在 resource 函式內同步執行。這對應到 AG Day 31 的長任務主題。

再談 prompt 的快取。同一個 prompt 被大量重複使用時,可以考慮把填好參數的版本快取起來,避免每次都要重新拼接字串。但快取的代價是「如果 prompt 內容改了,已快取的版本不會自動失效」——請用 server name 或版本號作為快取鍵的一部分。

第三是權限與審查。當 server 同時提供公開資源與內部資源時,請在程式裡明確標示哪些資源是敏感的,並考慮加上審查紀錄(誰在什麼時候讀了什麼)。這個紀錄在 AG Day 35 談 Langfuse 時會再次出現,今天先把架構預留好。

第四是錯誤回傳的一致性。Resource 函式可以回傳「空字串」也可以回傳「{"error": "..."} JSON」,但請在所有 resource 函式裡遵守同一個約定。例如我們這裡選擇「錯誤也用 JSON 包」,這樣客戶端只要解析一次就知道結果。這個紀律對客戶端的程式碼複雜度影響很大。

第五是多 server 的負載平衡。當一台機器上同時跑了多個 MCP server,每個 server 都佔用一份記憶體與 stdin/stdout 通道。在本機開發時這不是問題,但若要把 server 部署到容器裡(AG Day 39),請考慮「每個容器只跑一個 server」的設計,避免一個 server 故障影響其他 server。

小結

今天我們把 MCP server 的另外兩種能力補齊,並示範了如何把它們組合起來。重點整理如下:

  • Resources:用 URI 識別、由客戶端或上下文觸發、可被快取的靜態或半靜態資料。今天示範了 SQLite 知識庫的索引與單一文獻讀取。
  • Prompts:可帶參數的對話範本,集中管理「如何跟模型對話」的策略。今天示範了研究報告與摘要改寫兩個範本。
  • 命名空間紀律:工具用動詞、resource 用 URI scheme、prompt 用領域前綴;server name 視為版本的一部分。
  • 權限與隔離:resource 函式可以加上存取邏輯;正式產品請把身分驗證交給外部系統。
  • 模組化 import:所有裝飾器作用在同一個 FastMCP 實例上,子模組用 import 副作用註冊。

今天的 server 已經具備了完整的 MCP 三能力組合。明天我們會從伺服器這一端轉到客戶端這一端:把 LangGraph 流程(AG Day 11 到 AG Day 18)整合進 MCP 客戶端,讓 research-agent 可以自動偵測、連線、呼叫任何遵循 MCP 的外部伺服器。這是從「自己寫工具」到「使用整個生態」的轉折點。

結語

今天我們把 server 從「單一能力的員工」擴張成「員工加圖書館加顧問公司」的三角色組合。Resources 讓客戶端能讀取背景資料,prompts 讓伺服器貢獻對話策略,而 tools 仍然是「做實際工作」的主力。三者搭配得當時,整個 MCP 生態就能形成正向迴圈:越多資源被暴露,越多 prompt 被使用,越多工具被呼叫,價值就越大。

明天,我們會進入「AG Day 28 MCP client:把研究助理接上 MCP 生態」,把視角從伺服器換到客戶端。我們會用官方 mcp.client 介面把多個 MCP server 接進 research-agent,讓代理在執行任務時能動態發現並呼叫外部工具與資源。我們也會把今天的 server 與 LangGraph 流程串起來,讓 research-agent 第一次具備「工具可插拔」的能力。

延伸資源

  • Model Context Protocol 官方規格:https://modelcontextprotocol.io/。resources、prompts、tools 三種能力的最新規範與版本演進。
  • FastMCP 官方說明:https://github.com/modelcontextprotocol/python-sdk。三種能力的裝飾器語法、URI 動態參數與權限設計範例。
  • MCP Inspector 工具:https://github.com/modelcontextprotocol/inspector。用圖形介面對 server 發送 list/read/call 等請求,驗證今天的範例。
  • SQLite 官方說明:https://sqlite.org/lang_select.html。resource 函式所用的查詢語法以此為準。
  • Pydantic v2 官方說明:https://docs.pydantic.dev/latest/。資源與 prompt 的結構化驗證與型別管理;之後 FastMCP 的內部結構也會用到。

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...