简

從 Google Drive 到 Salesforce 的數據流理解 MCP 代碼執行:工具定義按需發現,中間數據在運行時傳遞與處理,再把必要結果交給模型,同時權衡執行、安全和狀態管理成本。

Code Execution with MCP:工具調用與中間數據怎樣繞開模型中轉?
25 分鐘
4931 字

上一篇討論了每輪推理需要什麼信息。這一篇把問題落到工具調用上:一份資料需要從系統 A 送到系統 B,是否一定要先讓模型讀完整份內容,再由模型把它寫進下一次調用?

Anthropic 的 《Code execution with MCP》給出的方向,是讓模型編寫調用程序,由執行環境組合 MCP 工具。工具仍然被真實調用,但部分數據傳遞和處理不再經過模型上下文。

  • 先看連接: MCP 統一了什麼,應用又負責什麼。
  • 再看數據流: 直接調用與代碼執行,分別讓哪些內容進入模型。
  • 最後看邊界: 怎樣發現工具、處理結果,以及少用 token 後仍要承擔的執行成本。

下面沿用原文 Google Drive → Salesforce 的任務背景,重新設計一個小例子:把指定會議文檔的原文,保存到已經確認的 Salesforce Lead 備註中。這裏討論的是調用結構,不會連接真實賬户;接口、記錄 ID 和代碼都是教學示例。

一、MCP 工具怎樣接入 Agenth2

先明確連接角色,再看工具以什麼方式交給模型,才能區分協議職責與數據流設計。

1. MCP:連接 Host、Client 與 Serverh3

先把三個角色分開。Agent 所在的應用是 Host,它組織模型交互並管理連接;MCP Client 與對應 Server 通信;Server 暴露工具等能力,再連接文檔系統、CRM 或其他資源。一個 Host 可以管理多個 Client,各自連接不同的 Server。 MCP 架構規範

在會議文檔任務裏,Google Drive Server 提供讀取能力,Salesforce Server 提供修改記錄的能力。模型不用直接掌握兩套服務的底層通信細節,應用可以通過 MCP 發現並調用這些能力。

但“通過統一協議接上了工具”和“怎樣把工具呈現給模型”,是兩件事。應用既可以向模型提供逐個工具的定義,也可以在執行環境中提供可調用的代碼接口。MCP 是連接與能力交換的一層,不是代碼執行引擎,也不是模型上下文的強制路由規則。

具體到工具,協議中的 tools/list 用於取得定義,tools/call 用於發起調用。應用如何選擇定義、怎樣包裝結果、哪些內容交給模型,仍然需要設計。不能把“連接了 MCP Server”直接理解為“必須把它的全部定義和結果都塞進模型”。 MCP Tools 規範

這一點也解釋了為什麼代碼執行沒有讓 MCP 失去價值:程序接管了部分調用組織,底下仍然需要統一的能力入口、參數約定和連接管理。

2. Direct Tool Calling:模型參與逐步調用與參數傳遞h3

這裏的 Direct Tool Calling,指應用把業務工具暴露給模型,模型生成參數,應用執行工具,再把結果送回模型的常見交互方式。所謂“直接”,不是模型繞過程序親自訪問 Google Drive。

對於這個例子,如果讀取工具返回全文,而寫入工具要求內聯提供備註文本,過程可以展開成:

模型请求读取指定文档
↓ 应用执行读取工具
文档全文作为 Tool Result 进入模型
↓ 模型生成下一次工具参数
同一份全文被写进更新 Lead 的请求
↓ 应用执行写入工具
写入确认返回模型

用户要求的是複製原文,不是分析原文。但在這條路徑中,模型不僅要決定“讀取後寫入”,還要重新生成已經取得的長文本。假設全文包含會議中的客户編號、報價與換行格式,重新生成時遺漏一行或改變一個數字,都可能讓搬運結果偏離原始資料。

這裏有兩筆不同的上下文開銷:

開銷進入模型的是什麼會議任務中的問題
能力描述工具名稱、説明、參數結構等定義只讀文檔和寫備註,卻可能加載整個業務工具庫
中間數據已取得的資料,以及下一次調用中生成的參數同一篇全文先被讀取,再被重新寫進參數

這不是説每種直接調用都必然重複全文。如果系統支持文件引用、句柄或服務端複製接口,應用也能避免內聯搬運。需要診斷的是實際數據路徑,而不是看到 Direct Tool Calling 就斷言它低效。

同樣,定義和數據也不能混為一談:只做工具搜索,可以減少無關定義;但如果後續仍把全文交給模型,再讓它原樣輸出,數據中轉的開銷依然存在。

二、代碼執行怎樣改變工具調用與數據流h2

連接到相同的外部服務,也可以採用不同的調用組織方式。下面分別看代碼接口、工具發現和執行狀態。

3. Code Execution:用程序組合 MCP 工具h3

代碼適配接口與調用鏈

代碼執行模式增加了一層適配:把可用 MCP 工具包裝成程序能夠調用的函數。模型讀懂接口後編寫代碼,Runtime 執行代碼;函數再通過應用管理的 MCP Client,調用對應 Server。

Cloudflare 的 Code Mode也採用了類似分層:工具被轉換成代碼接口,執行環境通過受控調用與外部系統通信。代碼接口不必意味着腳本持有服務憑證,或者可以任意訪問網絡;實際能力由應用授予。

對這個例子,可以用下面的簡化類型表達運行時提供的兩個適配器:

type Bindings = {
drive: {
readDocument(input: { id: string }): Promise<{ text: string }>;
};
crm: {
replaceLeadNotes(input: {
leadId: string;
notes: string;
}): Promise<{ updated: boolean }>;
};
};
async function copyMeetingNotes(bindings: Bindings) {
const document = await bindings.drive.readDocument({
id: "meeting-demo-08",
});
const result = await bindings.crm.replaceLeadNotes({
leadId: "lead-demo-08",
notes: document.text,
});
if (!result.updated) {
throw new Error("Lead notes update was not confirmed");
}
return { leadId: "lead-demo-08", updated: true };
}

這裏的 Bindings 不是 Google Drive 或 Salesforce SDK 的真實簽名,而是為解釋數據流定義的適配接口。假設用户已確認目標記錄並授權替換備註;“替換”不是追加,也不能在真實系統裏默默覆蓋已有內容。

適配器還要負責把實際 MCP 返回值解析成約定結構,檢查協議錯誤、工具執行錯誤及字段有效性。TypeScript 的類型標註不會自動驗證遠端響應,updated: true 也必須有真實服務結果作依據,而不能由包裝層無條件填入。

運行時中的數據傳遞

這行賦值發生在執行環境裏。文檔內容從讀取結果進入變量,再作為參數傳給 CRM,模型不必重新生成其中的每個字符。最後返回的只是足以説明執行狀態的對象。

圖 1 · 同一份文檔,區別在於中間內容由誰傳遞
直接調用與 MCP 代碼執行的數據流對比 直接調用路徑中,讀取的全文進入模型,再生成寫入參數。代碼執行路徑中,模型先生成程序,Runtime 通過 MCP 讀取和寫入全文,只將必要執行結果交回模型。圖中省略具體 Client 和 Server。 直接調用 · 全文經過模型中轉代碼執行 · 全文在 Runtime 中傳遞 讀取全文生成全文參數讀取結果變量傳遞經 Runtime 彙總狀態 Google DriveModelSalesforceGoogle DriveSalesforceModel指定會議文檔讀全文,再輸出全文接收備註內容指定會議文檔接收備註內容取得必要執行結果 Code Runtime執行模型生成的程序 工具調用均經 MCP;僅展示資料路徑,模型請求與具體連接層已省略。

減少的是模型輸入、輸出和往返,不是業務調用本身。 讀取一次、寫入一次,仍然是兩個真實操作;網絡耗時、服務限流與失敗處理都不會消失。

這裏的“繞開模型”也有條件:運行時不能同時把每次底層響應全文自動回顯給模型,腳本也不能順手 console.log(document)。否則雖然用了代碼,中間數據還是回到了上下文。

更重要的是任務語義。如果要求變成“判斷會議裏哪些承諾需要跟進”,模型就需要看到相關內容,或獲得保留足夠證據的摘錄。複製資料與理解資料不是同一種任務,不能為了減少 token 把判斷必需的信息一起藏掉。

4. Tool Discovery 與數據處理:按需讀定義,在運行時處理結果h3

工具目錄、接口説明與按需加載

一種代碼接口組織方式,是按服務保存工具文件:

tool-api/
├── drive/
│ ├── readDocument.ts
│ └── searchDocuments.ts
└── crm/
├── findLead.ts
└── replaceLeadNotes.ts

模型先看目錄,確定涉及文檔與 CRM,再讀取需要的函數説明。工具多時,也可以增加搜索入口,先返回候選名稱或簡短説明,再取得完整參數定義。這是把第七篇的漸進加載應用到工具目錄。

但把定義寫成文件,不等於完成了按需加載。如果應用隨後把整個目錄下的所有文件拼進提示詞,開銷只是換了表示形式。反過來,運行時導入模塊不等於模型讀懂接口:模型在寫調用代碼前,仍需取得足以理解參數、返回值和副作用的信息。

因此需要分別確認兩個時刻:接口何時對模型可見,代碼何時在運行時可調用。發現成功也不等於有執行權限,目錄中出現一個函數並不能代替調用檢查。

中間數據篩選與結果返回

當任務變成“找出這批會議記錄裏尚未同步到 CRM 的條目”,處理對象就可能是大量結構化記錄。若“尚未同步”已有可靠字段,不必讓模型逐行篩選,可以在代碼中處理:

type MeetingRow = { documentId: string; synced: boolean };
function summarizePending(rows: MeetingRow[]) {
const pending = rows.filter(row => !row.synced);
return {
total: rows.length,
pendingCount: pending.length,
sampleDocumentIds: pending.slice(0, 3).map(row => row.documentId),
};
}

這裏返回的是總數、待同步數量與少量樣本,不是整批記錄。樣本只是幫助檢查結果形態,不能代表完整清單;如果任務要求逐條跟進,就應保存完整清單並提供可讀取的入口。

同理,結構化字段的篩選、連接與統計適合程序處理;“客户是否已經明確接受報價”如果只存在自然語言討論中,就不能隨意用一個關鍵詞匹配替代語義判斷。

我更關注的是過濾規則的責任:模型決定了錯誤的規則,代碼只會更穩定地執行這個錯誤。 所以需要核對字段含義、數據範圍和異常記錄,不能把“程序算出來的”當作業務結論天然正確。

5. Control Flow 與 State:組織循環、錯誤處理和恢復h3

代碼還可以組織翻頁、循環、條件和錯誤處理。如果下一頁游標已經給出,就可以按約定繼續取頁;不需要讓模型在每頁之後重新決定一次“現在取下一頁”。

但模型往返減少,並不保證每個任務都更快。串行服務請求仍然是串行等待;執行環境啓動、代碼生成和修復也需要時間。只有被省下的模型往返與數據處理成本,大於新增開銷,整體才可能獲益。

對於寫入操作,控制流尤其不能只追求緊湊。假設更新 Lead 的請求超時,服務端可能已經完成寫入,也可能尚未處理。程序不能僅憑超時就無條件重跑整段任務,特別是後續接口改成“追加備註”時,重試可能產生重複內容。

一個更清楚的結果約定,是區分已確認成功、明確失敗和狀態未知,再由應用核對或請求進一步判斷。循環有邊界、請求有超時、失敗可追蹤,才能避免“一次執行”變成無法解釋的長任務。

外部文件則承接另一個問題:運行過程中的結果放在哪裏。批量同步可以保存待處理記錄與完成清單,供後續操作讀取,不必每輪把它們全文放回模型。這與第七篇的外部狀態是一致的。

不過,文件持久性取決於存儲是否保留;保存了進度也不等於業務操作與進度寫入具有原子性。如果 CRM 寫入成功,但保存完成清單失敗,恢復時仍需核對真實狀態。外部文件是恢復依據之一,不是“恰好執行一次”的自動保證。

保存經過驗證的處理函數,也能減少重複編寫。代碼複用和任務知識組織有關,但不是同一層設計:一個函數提供可執行邏輯,何時使用它、需要什麼前提,仍需額外説明,不能只靠文件存在。

三、代碼執行的收益與代價怎樣判斷h2

把中間數據留在代碼環境中,可以減少模型接觸資料的範圍,但不是“用了代碼就自動保密”。日誌、異常堆棧、調試輸出和文件回讀,都是數據重新進入模型的入口。

在會議文檔例子裏,即使模型不見原文,原文仍被送往 Salesforce。不進入模型,不等於沒有對外傳輸,也不等於目標系統獲得數據的行為已經被授權。 必須同時檢查目標記錄、寫入字段和允許的數據流向。

若使用佔位符替代敏感字段,還需要應用維護映射,並在允許的調用邊界還原;不能假定 MCP 自帶透明脱敏。隱藏值也不會消除風險:模型如果可以把整份資料送到任意目的地,仍然可能觸發不合適的數據流。

執行模型生成的程序,還增加了直接業務工具調用未必需要承擔的運行時管理工作:代碼能夠使用哪些能力,最長運行多久,最多佔用多少資源,輸出是否被檢查,失敗後怎樣清理和診斷。服務本身的權限與輸入檢查也仍然要保留。

所以我會用任務特徵判斷是否值得引入代碼執行,而不是把它當作默認升級:

任務特徵更值得關注的設計
工具少、結果小,每一步都需要語義判斷直接調用通常更清楚,未必值得增加運行時
大量無關定義佔據輸入,但調用鏈很短優先考慮工具發現與選擇性加載
大塊數據需要搬運,或有固定的多步處理代碼執行更可能減少模型中轉
每次取得結果都會改變業務判斷保留必要的模型反饋點,不強行塞進一段程序
涉及敏感寫入或狀態不明的重試先明確授權、結果檢查與恢復邊界

第六篇講的是工具發現與程序化調用等機制;這一篇進一步追蹤它們落在 MCP 系統中的位置。讀完後,我更傾向於沿數據路徑檢查系統:哪些信息幫助模型判斷,哪些只是被模型搬運,哪些應該留在外部執行與存儲層。

模型需要對下一步有足夠理解,但不必成為所有數據的必經通道。 代碼執行的價值,在於把明確的數據操作交回程序,同時保留需要判斷的反饋點;它優化的是分工,而不只是上下文長度。

幾個關鍵問題,串起連接、數據流與執行邊界h2

已經用代碼調用接口,為什麼還需要 MCP?

代碼負責組織執行,MCP 提供統一的能力發現與調用連接。否則程序可能需要分別適配每個系統的接口與通信方式。兩者可以配合,也不是所有代碼執行都必須依賴 MCP。

代碼執行為什麼能減少中間數據進入 Context?

因為讀取結果可以留在運行時變量裏,再直接傳給下一工具,模型只接收必要輸出。收益來自數據路由的變化,不是函數改了名字;如果全文仍被自動回顯或打印,開銷仍會回來。

工具定義按需加載,能否同時解決大結果問題?

不能。前者減少模型瞭解能力的成本,後者涉及執行結果流向。一個工具的定義很短,也可能返回巨量數據;需要分別檢查定義加載和結果處理。

不把原始資料給模型,會不會影響判斷?

會,取決於任務是否需要理解原始內容。機械複製通常不需要模型重寫全文;語義分析則需要相關證據。不能用不透明摘要替代必要資料,更不能把被過濾掉的信息當作模型已經檢查過。

代碼環境裏的數據是否天然更安全、更持久?

不是。安全取決於能力、輸出和流向限制,持久性取決於實際存儲生命週期。代碼環境可以幫助隔離中間數據,但日誌泄露、錯誤目標、臨時磁盤丟失等問題仍需處理。

一段程序完成多個工具調用,是否只剩一次調用成本?

只可能減少模型交互,不會把多次業務調用變成一次。各服務的網絡、限流和錯誤仍然存在;程序還增加執行與診斷成本。衡量收益應看端到端任務是否可靠完成,而不只看模型請求次數。

參考資料h2