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