一API接入實踐)
1. 先搞清楚 Tool Calling 和 MCP 到底在解決什么問題很多開發(fā)者第一次接觸這兩個詞會下意識覺得它們是競爭關(guān)系——要么用 Tool Calling要么上 MCP。實際做項目時你會發(fā)現(xiàn)它們根本不在一個層面上Tool Calling 解決的是「模型怎么表達我要調(diào)工具」MCP 解決的是「工具從哪來、怎么被統(tǒng)一發(fā)現(xiàn)和調(diào)用」。把這兩件事混在一起談選型必然擰巴。我拿一個真實場景說明。假設你在做一個客服助手用戶問「我的訂單到哪了」。模型本身不知道訂單狀態(tài)它需要調(diào)用一個查物流的函數(shù)。這個「模型決定調(diào)用哪個函數(shù)、傳什么參數(shù)」的過程就是 Tool Calling。而那個查物流的函數(shù)是你寫在 Java 里、還是用 Python 單獨跑一個服務、還是接第三方這就是 MCP 要規(guī)范的事。Tool Calling 的本質(zhì)是一套協(xié)議約定??蛻舳嗽谡埱罄锫暶鳌肝矣心男┕ぞ呖捎谩姑總€工具帶名字、描述、參數(shù)結(jié)構(gòu)模型讀完用戶問題后不直接回答而是返回一個tool_calls結(jié)構(gòu)里面寫明調(diào)用哪個工具、參數(shù)是什么。注意關(guān)鍵點模型不執(zhí)行工具它只輸出調(diào)用意圖。真正執(zhí)行的是你的 Agent 框架或后端代碼。MCPModel Context Protocol則是把「工具」這件事標準化成可插拔的服務。它用 JSON-RPC 通信核心方法就兩個tools/list讓客戶端啟動時自動發(fā)現(xiàn)有哪些工具tools/call讓客戶端轉(zhuǎn)發(fā)調(diào)用請求。MCP Server 可以用任何語言寫獨立部署Agent 啟動時連上就行不用把每個工具都硬編碼進主程序。所以兩者的協(xié)作關(guān)系是Tool Calling 負責模型側(cè)的決策協(xié)議MCP 負責工具側(cè)的供給協(xié)議。一個請求的完整鏈路會經(jīng)過兩段——先是你的后端用 Tool Calling 協(xié)議和模型對話模型返回 tool_calls 后后端判斷這個工具是本地函數(shù)還是 MCP 工具如果是 MCP 工具再用 JSON-RPC 轉(zhuǎn)發(fā)給 MCP Server 執(zhí)行。適合誰如果你只是接一兩個固定工具、團隊就一個后端服務純 Tool Calling 足夠別過度設計。如果你工具數(shù)量多、想跨語言復用、或者希望工具能獨立迭代部署MCP 的價值就出來了。下面我會把兩種方式的配置和請求都寫成可復制的形式并用 TaoToken 的統(tǒng)一 API 通道跑通驗證。2. 用 TaoToken 統(tǒng)一 Key 和 API 通道做前置準備在動手寫 Tool Calling 請求之前得先有一個能穩(wěn)定調(diào)用的模型入口。這里我用 TaoToken 作為統(tǒng)一通道原因是它兼容 OpenAI 的請求格式Tool Calling 的tools字段可以直接透傳不用為不同廠商改協(xié)議。對做選型的開發(fā)者來說先用一個統(tǒng)一入口把邏輯跑通再決定要不要換底層模型成本最低。你需要準備三樣東西Base URL、API Key、Model ID。這三件套在任何 Agent 框架里都是必填項缺一個都跑不起來。Base URL 用https://taotoken.net/api注意這個地址后面不加任何多余路徑OpenAI 兼容的 SDK 會自動拼/v1/chat/completions。API Key 去控制臺生成路徑是 console生成后復制保存頁面上只顯示一次。Model ID 按你實際要用的模型填比如qwen-plus、claude-3.5-sonnet這類具體可用列表在 doc 里能查到。如果你用的是 Claude Code 這類命令行工具配置方式略有不同需要設置環(huán)境變量指向 Anthropic 兼容端點參考 ClaudeCodeAnthropic 的說明。但本文的重點是 Tool Calling 和 MCP所以下面統(tǒng)一用 OpenAI 兼容格式演示這樣 Spring AI、LangChain、OpenClaw 都能直接套用。先驗證 Key 是否可用用一條最簡單的 curlcurl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d { model: qwen-plus, messages: [{role: user, content: 回復ok兩個字}] }如果返回里有choices[0].message.content說明通道正常。這一步別跳過很多后面 Tool Calling 報 401 的問題根源就是 Key 沒生效或者 Base URL 寫錯了。確認能通之后再進入工具調(diào)用的部分。3. 可復制的 Tool Calling 請求與 MCP Server 配置片段這一節(jié)是全文最核心的部分我把 Tool Calling 的完整請求和 MCP Server 的配置都寫成可直接復制的形式。先看 Tool Calling。3.1 Tool Calling 請求示例假設我們要讓模型查天氣客戶端在請求里聲明工具{ model: qwen-plus, messages: [ {role: system, content: 你是一個助手}, {role: user, content: 北京今天天氣怎么樣} ], tools: [ { type: function, function: { name: get_weather, description: 查詢指定城市的天氣, parameters: { type: object, properties: { city: {type: string, description: 城市名} }, required: [city] } } } ] }模型收到后不會直接回答而是返回tool_calls{ choices: [{ message: { role: assistant, content: null, tool_calls: [{ id: call_abc123, type: function, function: { name: get_weather, arguments: {\city\: \北京\} } }] }, finish_reason: tool_calls }] }看到content是 null、finish_reason是tool_calls就說明模型選擇了調(diào)用工具。你的框架執(zhí)行真實函數(shù)后把結(jié)果作為tool消息追加回去{ model: qwen-plus, messages: [ {role: system, content: 你是一個助手}, {role: user, content: 北京今天天氣怎么樣}, {role: assistant, content: null, tool_calls: [{id: call_abc123, type: function, function: {name: get_weather, arguments: {\city\: \北京\}}}]}, {role: tool, tool_call_id: call_abc123, content: {\temp\: 25, \weather\: \晴\}} ], tools: [] }再次發(fā)送后模型生成最終回答「北京今天天氣晴氣溫25℃」。整個循環(huán)的關(guān)鍵原則模型只決定調(diào)用什么工具、生成什么參數(shù)執(zhí)行永遠是框架的事。3.2 MCP Server 配置片段MCP 的配置分兩種傳輸方式stdio 和 HTTP。stdio 適合本地進程配置寫在 Agent 的 settings 里。以常見的 MCP 客戶端配置為例{ mcpServers: { db-server: { command: python3, args: [mcp_db_server.py], env: { DB_HOST: 127.0.0.1, DB_PORT: 3306 } } } }如果是 Spring Boot 項目寫在application.yaml里spring: ai: mcp: client: stdio: servers: db-server: command: python3 args: [mcp_db_server.py]啟動時客戶端會發(fā)tools/list詢問有哪些工具MCP Server 返回工具清單{ result: { tools: [{ name: query_database, description: 查詢MySQL數(shù)據(jù)庫, inputSchema: { type: object, properties: { sql: {type: string, description: SQL語句} }, required: [sql] } }] } }模型調(diào)用時客戶端用tools/call轉(zhuǎn)發(fā){ jsonrpc: 2.0, method: tools/call, params: { name: query_database, arguments: {sql: SELECT COUNT(*) FROM users} }, id: 2 }這里有個容易忽略的點模型看到的工具列表是「內(nèi)置工具 MCP 工具」合并后的結(jié)果它根本不知道哪個來自 MCP。判斷工具來源、決定走本地執(zhí)行還是 JSON-RPC 轉(zhuǎn)發(fā)是 Agent 中間層的職責。這也是為什么 MCP 和內(nèi)置工具的調(diào)用流程完全一致唯一差別就是執(zhí)行階段多了一層轉(zhuǎn)發(fā)。4. 驗證請求與成功結(jié)果把鏈路跑通配置寫完之后必須實際發(fā)一次請求確認鏈路通。我建議分兩步驗證先驗證 Tool Calling 本身再驗證 MCP 轉(zhuǎn)發(fā)。第一步用 curl 直接發(fā)帶 tools 的請求確認模型返回tool_callscurl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d { model: qwen-plus, messages: [{role: user, content: 北京今天天氣怎么樣}], tools: [{ type: function, function: { name: get_weather, description: 查詢指定城市的天氣, parameters: { type: object, properties: {city: {type: string}}, required: [city] } } }] }成功的標志是響應里finish_reason為tool_calls且message.tool_calls[0].function.name是get_weather。如果模型直接回答了天氣說明它沒識別到工具檢查tools字段是否被正確透傳。第二步驗證 MCP 轉(zhuǎn)發(fā)。啟動你的 MCP Server然后在 Agent 里發(fā)一條會觸發(fā) MCP 工具的消息比如「數(shù)據(jù)庫有多少用戶」。觀察日志里是否出現(xiàn)tools/list的調(diào)用以及后續(xù)的tools/call。如果 MCP Server 返回了結(jié)果且模型最終生成了自然語言回答說明整條鏈路通了。實測下來最容易出問題的是 MCP Server 的啟動命令。比如python3 mcp_db_server.py里的路徑是相對路徑Agent 的工作目錄一變就找不到文件。建議用絕對路徑或者確認啟動目錄。另外 stdio 模式下 MCP Server 的日志不能往 stdout 打否則會污染 JSON-RPC 消息日志要重定向到 stderr。驗證通過后你會看到完整的調(diào)用鏈用戶提問 → Agent 合并工具列表 → 模型返回 tool_calls → Agent 判斷來源 → 本地執(zhí)行或 JSON-RPC 轉(zhuǎn)發(fā) → 結(jié)果追加到 messages → 模型生成最終回答。這條鏈路跑通一次后面加工具就是重復勞動。5. 本篇常見錯誤排查401、local proxy failed、reading choices這一節(jié)我把實際踩過的坑列出來對照報錯定位問題。401 Unauthorized。最常見的原因是 API Key 沒生效。檢查三處Key 是否復制完整前后不能有空格、請求頭是否是Authorization: Bearer xxx、Base URL 是否寫成了https://taotoken.net/api而不是帶/v1的完整路徑。如果用 SDK確認base_url參數(shù)設置正確有些 SDK 會自動補/v1有些不會補重復了也會 401。local proxy failed。這個報錯通常出現(xiàn)在本地起了代理層或者 MCP 客戶端連接本地 Server 時。如果是 MCP 場景檢查 MCP Server 進程是否真的起來了command和args拼出來的命令能不能在終端手動跑通。stdio 模式下如果 Server 啟動就崩潰客戶端會報連接失敗。先單獨運行 Server 腳本確認它能正常響應tools/list。reading choices 相關(guān)報錯。這類錯誤一般是響應結(jié)構(gòu)不符合預期代碼里訪問choices[0]時越界或字段不存在。原因可能是模型返回了錯誤信息而不是正常響應比如額度不足、模型名寫錯。先把原始響應打印出來看別直接取字段。如果choices為空檢查model字段是否是有效模型 ID。OAuth 相關(guān)報錯。如果你用的是 Claude Code 或某些需要 OAuth 的工具報 OAuth 失敗通常是認證方式?jīng)]配對。這類工具需要走 Anthropic 兼容端點配置參考 ClaudeCodeAnthropic。確認環(huán)境變量和配置文件里的端點一致別混用 OpenAI 和 Anthropic 兩種格式。工具調(diào)用返回空 arguments。模型返回的arguments是 JSON 字符串需要二次解析。如果直接當對象用會報錯。另外有些模型在參數(shù)不完整時會返回空字符串這時候要在框架層做校驗別把空參數(shù)傳給真實函數(shù)。排查的通用思路先確認模型通道通不帶 tools 發(fā)一條再確認 tools 字段被識別看 finish_reason最后確認工具執(zhí)行層沒問題單獨跑工具函數(shù)。分層定位比盯著一個報錯猜要快得多。6. 選型建議與后續(xù)接入路徑回到最初的問題Tool Calling 和 MCP 怎么選。我的判斷標準很簡單——看你的工具數(shù)量和團隊結(jié)構(gòu)。工具少于五個、就一個后端服務、團隊不跨語言直接用 Tool Calling把工具函數(shù)寫在業(yè)務代碼里注冊到框架夠用且簡單。這時候上 MCP 是給自己加運維負擔多一個進程要管、多一層 JSON-RPC 要調(diào)。工具多、需要跨語言復用、或者希望工具能獨立部署和迭代MCP 的價值就體現(xiàn)出來了。MCP Server 可以用 Python 寫數(shù)據(jù)分析工具、用 Go 寫高性能查詢、用 Node 寫第三方 API 封裝Agent 啟動時自動發(fā)現(xiàn)不用改主程序。這種解耦在工具頻繁變動的場景下收益很明顯。兩者不是替代關(guān)系而是配合關(guān)系。你的 Agent 用 Tool Calling 和模型對話用 MCP 管理工具供給中間層負責把兩者接起來。理解了這一點選型就不會糾結(jié)。如果你要動手接入建議按這個順序先去 API Keys 生成 Key用 模型對話 快速驗證模型可用再照著 接入文檔 把 Tool Calling 請求跑通。如果你要做長期的編碼 Agent 或者多工具編排Coding Plan 會更合適配額和通道都按持續(xù)調(diào)用場景設計。最后提醒一句MCP Server 千萬別直連生產(chǎn)數(shù)據(jù)庫。用只讀賬號、加查詢超時、限制返回行數(shù)這些在寫 Server 的時候就要做進去。工具能力越強越要在執(zhí)行層設邊界模型只負責決策邊界由你的代碼守。