一Key打通Tool與MCP調(diào)用鏈)
1. 從一次“工具調(diào)用失敗”說(shuō)起Skill 機(jī)制到底解決什么問(wèn)題如果你最近在折騰 Agent 工具鏈大概率遇到過(guò)這種場(chǎng)景模型明明“知道”該調(diào)用哪個(gè)工具但一到具體執(zhí)行就翻車——要么參數(shù)格式不對(duì)要么根本不知道某個(gè)庫(kù)該怎么用。我試過(guò)把 PDF 處理、圖片壓縮、音視頻轉(zhuǎn)碼這些能力全塞進(jìn) system prompt結(jié)果上下文直接爆掉模型反而變笨了。這就是 Skill 機(jī)制要解決的核心問(wèn)題。Skill 是什么一句話概括Skill 知識(shí)文檔SKILL.md 加載器skill_loader.py 底層 Tool 執(zhí)行能力。它不是一門新技術(shù)而是把“按需加載領(lǐng)域知識(shí)”這件事工程化了。能做什么讓模型在需要處理 PDF 時(shí)才加載 PDF 的處理指南需要操作數(shù)據(jù)庫(kù)時(shí)才加載 SQL 規(guī)范平時(shí)這些知識(shí)不占用上下文。適合誰(shuí)正在把自建能力接入多模型工具鏈的開發(fā)者尤其是那些已經(jīng)有一堆 Tool 和 MCP Server、但發(fā)現(xiàn) token 消耗失控的團(tuán)隊(duì)。傳統(tǒng)做法是把所有工具定義和領(lǐng)域知識(shí)一次性注入。MCP 官方博客里提到過(guò)兩個(gè)典型問(wèn)題工具定義會(huì)讓上下文窗口過(guò)載中間工具的結(jié)果會(huì)消耗額外 token。Skill 的思路是“漸進(jìn)式加載”——SKILL.md 平時(shí)躺在磁盤上只有觸發(fā)條件匹配時(shí)才被讀進(jìn)上下文。整條鏈路是這樣的用戶提問(wèn) → 關(guān)鍵詞匹配到某個(gè) Skill → skill_loader.py 解析 SKILL.md → 把正文注入 system prompt → 模型根據(jù)知識(shí)決定是否調(diào)用 Tool → ToolExecutor 執(zhí)行 → 結(jié)果返回模型。注意中間那步“決定是否調(diào)用 Tool”是可選的如果用戶只是問(wèn)“PDF 提取表格有幾種方法”模型靠 SKILL.md 的知識(shí)就能回答不需要真的執(zhí)行代碼。理解了這條鏈路你就能明白為什么 Skill 和 Tool、MCP 是互補(bǔ)而非替代關(guān)系。Tool 給模型“手”MCP 給模型“遠(yuǎn)程手”Skill 給模型“大腦的參考資料”。下面我會(huì)從 SKILL.md 的最小模板開始一步步拆到 skill_loader.py 的解析邏輯最后用 TaoToken 統(tǒng)一 Key 驗(yàn)證整條 Tool 與 MCP 調(diào)用鏈?zhǔn)欠襁B通。2. SKILL.md 最小模板與 skill_loader.py 解析邏輯從聲明到注冊(cè)為 Tool2.1 SKILL.md 的兩段式結(jié)構(gòu)每個(gè) Skill 就是一個(gè) Markdown 文件結(jié)構(gòu)分兩部分YAML 元數(shù)據(jù) 正文知識(shí)。元數(shù)據(jù)用---包裹至少包含name和description兩個(gè)字段。description的寫法很關(guān)鍵它決定了模型什么時(shí)候該激活這個(gè) Skill。下面是一個(gè)可以直接復(fù)制使用的最小模板我把它放在skills/pdf/SKILL.md--- name: pdf description: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill. license: Proprietary. LICENSE.txt has complete terms --- # PDF Processing Guide ## Overview 處理 PDF 時(shí)優(yōu)先使用 pdfplumber 提取文本和表格它比 PyPDF2 對(duì)復(fù)雜版式更友好。 ## Extract Tables python import pdfplumber with pdfplumber.open(input.pdf) as pdf: page pdf.pages[0] tables page.extract_tables() for table in tables: for row in table: print(row)Merge PDFs使用 pypdf 的 PdfMergerfrom pypdf import PdfMerger merger PdfMerger() merger.append(a.pdf) merger.append(b.pdf) merger.write(merged.pdf) merger.close()元數(shù)據(jù)里的 description 寫得越具體觸發(fā)匹配越準(zhǔn)。我見過(guò)有人只寫“處理 PDF”結(jié)果模型在用戶提到“文檔”時(shí)就誤激活。把具體動(dòng)作extract、merge、split、OCR都列出來(lái)匹配精度會(huì)高很多。 ### 2.2 skill_loader.py 的 23 行核心邏輯 加載器的職責(zé)很單一讀文件、切分元數(shù)據(jù)和正文、返回結(jié)構(gòu)化結(jié)果。核心就是判斷文件是否以 --- 開頭然后用 split(---, 2) 切成三部分。下面是完整實(shí)現(xiàn) python Skill 加載模塊 import yaml def load(path: str) - tuple[dict, str]: 解析 SKILL.md 文件返回 (metadata, content)。 with open(path, r, encodingutf-8) as f: content f.read() if not content.startswith(---): return {}, content # 只分割成三部分前導(dǎo)空字符串、metadata、剩余內(nèi)容 parts content.split(---, 2) if len(parts) 3: return {}, content metadata yaml.safe_load(parts[1]) body parts[2].strip() return metadata or {}, body if __name__ __main__: import sys from pathlib import Path script_dir Path(__file__).parent test_file script_dir / skills/pdf/SKILL.md if len(sys.argv) 1: test_file Path(sys.argv[1]) print(fLoading: {test_file}) print( * 50) meta, body load(str(test_file)) print(METADATA:) for k, v in meta.items(): display f{v[:60]}... if isinstance(v, str) and len(v) 60 else v print(f {k}: {display}) print(f\nCONTENT (first 300 chars):\n{body[:300]}...)這里有個(gè)容易踩的坑split(---, 2)的第二個(gè)參數(shù)是最大分割次數(shù)不是分割份數(shù)。如果寫成split(---)正文里出現(xiàn)的---分隔線會(huì)把內(nèi)容切碎。用maxsplit2才能保證只切出元數(shù)據(jù)部分。2.3 從解析結(jié)果到注冊(cè)為 Tool加載器返回的metadata用來(lái)做觸發(fā)判斷body才是注入上下文的知識(shí)。但 Skill 本身不包含執(zhí)行邏輯它只是“告訴模型怎么做”。真正執(zhí)行時(shí)模型還是要通過(guò) ToolExecutor 調(diào)用內(nèi)置工具。注冊(cè)流程可以這樣理解啟動(dòng)時(shí)掃描skills/目錄下所有SKILL.md把metadata.name和metadata.description注冊(cè)成一個(gè)輕量級(jí)的“可激活 Skill 列表”。這個(gè)列表本身很小不占多少 token。當(dāng)用戶輸入進(jìn)來(lái)先用關(guān)鍵詞或向量匹配判斷該激活哪個(gè) Skill再調(diào)用load()把對(duì)應(yīng)正文讀進(jìn)來(lái)。如果你用的是支持 MCP 的客戶端可以把 Skill 加載器包裝成一個(gè) MCP Server 暴露出去。這樣模型既能通過(guò) MCP 調(diào)用遠(yuǎn)程服務(wù)又能通過(guò) Skill 獲取領(lǐng)域知識(shí)兩條鏈路共用同一套 Key 管理。3. 可復(fù)制配置用 TaoToken 統(tǒng)一 Key 打通 Tool 與 MCP 調(diào)用鏈3.1 為什么需要統(tǒng)一 Key當(dāng)你的 Agent 同時(shí)要調(diào)用多個(gè)模型、多個(gè) MCP Server、多個(gè)自建 Tool 時(shí)Key 管理會(huì)變成噩夢(mèng)。每個(gè)服務(wù)一套 Key輪換時(shí)到處改配置還容易把 Key 硬編碼進(jìn)代碼提交到倉(cāng)庫(kù)。TaoToken 的做法是提供一個(gè)統(tǒng)一的 API 入口Base URL 指向https://taotoken.net/api所有模型調(diào)用和工具調(diào)用都走這一個(gè) Key。這樣配置的好處是skill_loader.py 里不需要關(guān)心具體用哪個(gè)模型只需要在調(diào)用時(shí)指定 Model IDMCP Server 的連接配置也統(tǒng)一走同一個(gè) Base URL。換模型時(shí)只改一個(gè)字段不用動(dòng)加載器邏輯。3.2 settings.json 配置片段如果你用的是 Claude Code 或類似的客戶端配置文件通常放在~/.claude/settings.json。下面是一個(gè)可復(fù)制的配置片段把 Base URL、Key、Model ID 三件套都寫全{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: sk-your-taotoken-key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 }, skills: { enabled: true, paths: [./skills] }, mcpServers: { filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, ./workspace] } } }注意ANTHROPIC_BASE_URL后面不要加/v1TaoToken 的 API 入口已經(jīng)處理了路徑。Key 從控制臺(tái)的 API Keys 頁(yè)面獲取不要直接寫死在代碼里用環(huán)境變量注入更安全。3.3 skill_loader.py 與 MCP 的橋接配置如果你想讓 Skill 加載器本身也通過(guò) MCP 暴露可以在 MCP Server 配置里加一個(gè)自定義 Server。下面是一個(gè) TOML 格式的配置示例適用于支持 TOML 配置的客戶端[mcp_servers.skill_loader] command python args [-m, skill_loader_server, --skills-dir, ./skills] [mcp_servers.skill_loader.env] TAOTOKEN_BASE_URL https://taotoken.net/api TAOTOKEN_API_KEY sk-your-taotoken-key TAOTOKEN_MODEL claude-sonnet-4-20250514這樣配置后模型可以通過(guò) MCP 協(xié)議調(diào)用skill_loader的list_skills和load_skill兩個(gè)方法動(dòng)態(tài)獲取可用 Skill 列表和具體內(nèi)容。整個(gè)鏈路里Tool 調(diào)用、MCP 調(diào)用、Skill 加載都共用同一個(gè) TaoToken Key。3.4 驗(yàn)證配置是否生效配置寫完后先用一個(gè)最小請(qǐng)求驗(yàn)證 Key 和 Base URL 是否連通??梢杂?curl 直接測(cè)curl -X POST https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H x-api-key: sk-your-taotoken-key \ -H anthropic-version: 2023-06-01 \ -d { model: claude-sonnet-4-20250514, max_tokens: 100, messages: [{role: user, content: 回復(fù) OK 兩個(gè)字母}] }如果返回里包含content字段且文本是OK說(shuō)明 Key 和 Base URL 都正確。這一步過(guò)了再往下測(cè) Skill 加載和 MCP 調(diào)用。4. 驗(yàn)證請(qǐng)求與成功結(jié)果實(shí)測(cè) Skill 加載與 MCP 調(diào)用是否連通4.1 單獨(dú)測(cè)試 skill_loader.py先不接模型直接跑加載器確認(rèn) SKILL.md 能被正確解析python skill_loader.py skills/pdf/SKILL.md預(yù)期輸出類似Loading: skills/pdf/SKILL.md METADATA: name: pdf description: Use this skill whenever the user wants to do anything with PDF files... license: Proprietary. LICENSE.txt has complete terms CONTENT (first 300 chars): # PDF Processing Guide ## Overview 處理 PDF 時(shí)優(yōu)先使用 pdfplumber 提取文本和表格...如果METADATA是空的檢查文件開頭是不是有 BOM 或者空格。content.startswith(---)對(duì)首字符很敏感Windows 下用記事本保存容易帶 BOM用 VS Code 另存為 UTF-8 無(wú) BOM 即可。4.2 測(cè)試模型能否根據(jù) Skill 知識(shí)調(diào)用 Tool寫一個(gè)最小測(cè)試腳本把 SKILL.md 的正文注入 system prompt然后讓模型處理一個(gè) PDF 任務(wù)import anthropic client anthropic.Anthropic( base_urlhttps://taotoken.net/api, api_keysk-your-taotoken-key, ) with open(skills/pdf/SKILL.md, r, encodingutf-8) as f: content f.read() parts content.split(---, 2) body parts[2].strip() response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens500, systemf你是 PDF 處理專家參考以下指南\n\n{body}, messages[{role: user, content: 幫我寫一段提取 PDF 表格的代碼}], ) print(response.content[0].text)成功的話模型會(huì)輸出使用pdfplumber的代碼而不是泛泛而談。這說(shuō)明 Skill 知識(shí)已經(jīng)正確注入模型能根據(jù)知識(shí)決定調(diào)用哪個(gè) Tool。4.3 測(cè)試 MCP 調(diào)用鏈如果你配置了 MCP Server可以用客戶端自帶的 MCP 調(diào)試命令驗(yàn)證。以 filesystem Server 為例npx modelcontextprotocol/inspector npx -y modelcontextprotocol/server-filesystem ./workspace在 Inspector 界面里能看到list_directory、read_file等工具。點(diǎn)擊調(diào)用如果返回文件列表說(shuō)明 MCP 鏈路通了。這時(shí)候再回到模型側(cè)讓模型通過(guò) MCP 讀取一個(gè)文件觀察返回結(jié)果里是否包含文件內(nèi)容。4.4 完整鏈路成功標(biāo)志整條鏈路跑通的標(biāo)志是用戶提問(wèn) → 模型匹配到 pdf Skill → 加載 SKILL.md → 模型決定調(diào)用 bash Tool 執(zhí)行pip install pdfplumber→ ToolExecutor 返回安裝結(jié)果 → 模型輸出最終代碼。整個(gè)過(guò)程里模型調(diào)用走 TaoToken 的 Base URLMCP 調(diào)用走同一個(gè) KeySkill 加載走本地文件系統(tǒng)。三者互不干擾但共用一套認(rèn)證。5. 本篇常見錯(cuò)誤排查401、local proxy failed、reading choices、OAuth5.1 401 Unauthorized最常見的報(bào)錯(cuò)。原因通常是 Key 寫錯(cuò)、Key 過(guò)期、或者 Base URL 配錯(cuò)。先檢查ANTHROPIC_AUTH_TOKEN是不是從控制臺(tái)復(fù)制的完整 Key注意不要有多余空格。然后確認(rèn)ANTHROPIC_BASE_URL是https://taotoken.net/api不要寫成https://taotoken.net/api/v1路徑重復(fù)會(huì)導(dǎo)致 404 或 401。如果用的是 settings.json檢查 JSON 格式是否合法??梢杂胮ython -m json.tool settings.json驗(yàn)證。JSON 里不能有注釋尾逗號(hào)也會(huì)導(dǎo)致解析失敗。5.2 local proxy failed這個(gè)報(bào)錯(cuò)通常出現(xiàn)在客戶端嘗試連接本地代理時(shí)。檢查你的環(huán)境變量里有沒(méi)有HTTP_PROXY或HTTPS_PROXY指向一個(gè)不存在的本地端口。如果有臨時(shí)取消這些環(huán)境變量再試unset HTTP_PROXY unset HTTPS_PROXY另外檢查 settings.json 里有沒(méi)有配置proxy字段指向本地地址。TaoToken 的 API 入口是直連的不需要額外代理配置。5.3 reading choices 相關(guān)報(bào)錯(cuò)這個(gè)報(bào)錯(cuò)一般出現(xiàn)在解析模型返回結(jié)果時(shí)。如果返回體里沒(méi)有choices字段說(shuō)明請(qǐng)求可能發(fā)到了錯(cuò)誤的端點(diǎn)。檢查你用的 SDK 是不是 Anthropic 格式Anthropic 的返回是content數(shù)組不是choices。如果你用的是 OpenAI 格式的 SDK需要把 Base URL 改成對(duì)應(yīng)的兼容端點(diǎn)或者換用 Anthropic SDK。還有一種情況是流式返回被中斷導(dǎo)致 JSON 解析失敗??梢栽谡?qǐng)求里加stream: false先排除流式問(wèn)題。5.4 OAuth 相關(guān)報(bào)錯(cuò)如果你在客戶端里配置了 OAuth 登錄但同時(shí)又配了 API Key兩者可能沖突。OAuth 流程會(huì)嘗試刷新 token如果刷新失敗就會(huì)報(bào)錯(cuò)。解決辦法是明確用哪一種認(rèn)證方式用 API Key 就把 OAuth 相關(guān)配置清掉用 OAuth 就不要在環(huán)境變量里放ANTHROPIC_AUTH_TOKEN。5.5 Skill 加載后模型不調(diào)用 Tool這不是報(bào)錯(cuò)但很常見。模型讀完 SKILL.md 后只是回答了問(wèn)題沒(méi)有調(diào)用 Tool。原因可能是description寫得太模糊模型沒(méi)匹配到或者 system prompt 里沒(méi)有明確告訴模型“你可以調(diào)用工具”。可以在 system prompt 里加一句“如果需要執(zhí)行代碼請(qǐng)調(diào)用 bash 工具”給模型一個(gè)明確的行動(dòng)指令。6. 把 Skill 接入你的工具鏈從驗(yàn)證到長(zhǎng)期使用整條鏈路驗(yàn)證通過(guò)后你可以把 skill_loader.py 包裝成一個(gè)常駐服務(wù)啟動(dòng)時(shí)掃描skills/目錄把每個(gè) SKILL.md 的元數(shù)據(jù)注冊(cè)到內(nèi)存里。用戶輸入進(jìn)來(lái)時(shí)先用輕量級(jí)匹配關(guān)鍵詞或向量判斷該激活哪個(gè) Skill再調(diào)用load()讀取正文。這樣既節(jié)省 token又保證模型在需要時(shí)能拿到準(zhǔn)確的領(lǐng)域知識(shí)。長(zhǎng)期使用時(shí)建議把 Skill 目錄納入版本管理每個(gè) Skill 一個(gè)文件夾SKILL.md 里的description當(dāng)成接口文檔來(lái)維護(hù)。新增 Skill 時(shí)先寫 SKILL.md再用skill_loader.py單獨(dú)測(cè)試解析最后接入模型驗(yàn)證觸發(fā)是否準(zhǔn)確。如果你需要管理多個(gè)模型和多個(gè) MCP Server用 TaoToken 的統(tǒng)一 Key 能省掉大量配置工作。模型對(duì)話可以在控制臺(tái)里直接測(cè)試API Keys 頁(yè)面管理所有 Key接入文檔里有各客戶端的詳細(xì)配置示例。需要長(zhǎng)期跑編碼任務(wù)或 Agent 的話Coding Plan 提供了更穩(wěn)定的配額。整條 Tool 與 MCP 調(diào)用鏈的連通性用上面那套 curl 加 Python 腳本就能驗(yàn)證不需要復(fù)雜的測(cè)試框架。