代理與應用之間的缺失環節
大多數AI代理工具運行在服務器上,限制了瀏覽器API、設備功能和前端狀態的訪問。瞭解LangChain的無頭工具如何為現代代理應用啓用安全的客户端工具執行。
開源
代理與應用之間的缺失鏈接
2026年6月10日
6
分鐘
返回博客
創建代理
關鍵要點
大多數代理工具只看到後端。瀏覽器、應用和設備包含服務器端工具無法直接訪問的有價值狀態和能力。
無頭工具將客户端能力引入代理循環。代理可以調用瀏覽器API、本地內存和應用特定操作作為第一類工具,同時保留結構化輸入和輸出。
在客户端執行既改善用户體驗又提升隱私。代理可以直接與用户環境交互,減少往返,並允許敏感數據默認保留在本地。
TL;DR:大多數代理工具在服務器上運行,這意味着代理可以調用API,但無法與用户實際工作的瀏覽器、應用狀態或設備能力交互。通過LangChain中的無頭工具,我們通過讓代理調用客户端能力(如地理位置、剪貼板訪問、本地內存和應用內操作)作為第一類工具來彌補這一差距。這使代理更有用、更私密,並更好地與實際應用行為對齊。
如今的代理能力越來越強,但用户關心的許多能力存在於客户端運行時而非服務器上。瀏覽器和應用擁有本地狀態、用户選擇、設備API和應用特定操作,這些通常無法通過後端系統訪問。結果,代理可以推理下一步該做什麼,但難以在用户實際工作的環境中行動。
造成這一差距的一個原因是大多數代理工具在服務器上執行。當模型決定使用工具時,代理在進程中運行它或將其委託給外部服務(如MCP服務器),然後將結果反饋給推理循環。這對API、數據庫和後端系統有效,但存在明顯限制:
無法直接訪問僅瀏覽器或僅設備的API。
無法對從未同步到服務器的前端狀態採取行動。
通常迫使隱私敏感數據離開設備。
為本質上是本地的操作引入不必要的往返。
瀏覽器是許多高價值代理操作實際發生的地方:讀取本地應用狀態、對當前UI採取行動、使用設備能力而不將數據發送到後端。桌面應用通過本地文件、原生集成和會話特定狀態展現相同模式。如果您的代理無法訪問該運行時,它仍然擅長後端工作流,但弱於用户實際體驗的交互。
想象您正在為Figma、Google Slides或富文本編輯器構建副駕駛代理。代理可以在服務器上推理用户的請求,但文檔模型、選擇狀態和編輯命令都在客户端。服務器端工具無法在光標處插入文本、重新格式化選定對象或跳轉到活動幻燈片,因為這些操作屬於應用運行時,而非後端API。如今,團隊通常通過臨時UI橋接來彌合這一差距:將一些客户端狀態序列化到服務器,獲取響應,然後命令式地修補客户端。這可行,但脆弱、難以組合,且對模型的推理循環不可見。
讓您的代理直接從用户瀏覽器訪問內存或地理位置API。
這就是LangChain中無頭工具解決的問題。
無頭工具改變了什麼
對模型而言,無頭工具看起來與其他工具無異:它有名稱、描述和一組預期輸入。模型決定何時調用它,就像其他工具一樣。不同之處在於接下來發生的事情。
服務器不是自己運行工具,而是將工具調用發送到客户端:用户的瀏覽器、桌面應用或實際擁有該能力的任何環境。客户端在本地運行工具並將結果發送回來,代理從中斷處繼續。
雖然這初聽起來像一個小實現細節,但它實際上改變了代理可以可靠控制的系統類型。
模型從不需要知道工具在哪裏運行。它看到一個工具,決定使用它,並獲得結果。但在幕後,服務器和客户端正在協調:服務器知道代理想做什麼,客户端知道如何做。這種分離是核心思想。
您可以手動連接,從React應用調用navigator.geolocation.getCurrentPosition()並將結果發送給代理。但這樣一來,模型無法發現或決定何時調用該能力。它作為臨時側通道存在於推理循環之外。無頭工具將客户端操作置於代理的推理循環之內,而非旁邊。
為什麼這很重要
好處不僅僅是“瀏覽器訪問”。想象一個幫助您處理幻燈片堆的代理:它應該能夠跳轉到活動幻燈片、讀取本地上下文並原地更新演示文稿,而無需將會話發送到後端。無頭工具通過將客户端能力作為代理循環中的真實工具暴露出來,使這種交互成為可能。
某些操作無法在後端正確模擬。地理位置是明顯的例子——瀏覽器擁有權限提示和設備信號。剪貼板訪問、畫布渲染、文件選擇器和實時UI導航都依賴於活動客户端環境。標準工具可以通過後端服務近似這些操作。無頭工具可以調用真實事物。
但無頭工具不僅限於瀏覽器API。它們是給代理安全訪問應用原生操作的通用機制。例如,slidev-agent(Popular Slidev演示框架的插件)使用無頭工具在用户活動演示中導航到特定幻燈片。這不是數據檢索問題或服務器自動化問題。
這種模式也改變了隱私權衡。代理內存並不總屬於集中式後端。通過由瀏覽器存儲(如IndexedDB)支持的無頭工具,內存可以默認保留在本地——持久、低延遲、自然限定於該用户和瀏覽器——而無需將回憶轉化為服務器端數據管理問題。
它在代碼中如何工作
在TypeScript中,定義和實現之間的分離特別清晰。您定義一次工具,使用.implement(...)附加實現,並將實現傳遞給前端流式鈎子。服務器和客户端共享相同的模式,但只有客户端加載特定於瀏覽器的執行邏輯。
// tools.ts import { tool } from "langchain";
export const geolocationGet = tool({ name: "geolocation_get", description: "從瀏覽器獲取用户的當前位置。", schema: z.object({}), }); // App.tsx import { useStream } from '@langchain/react';
// 共享工具定義 import { geolocationGet as geolocationGetDefinition } from './tools';
export function App() { const stream = useStream({ // ... tools: [ // 客户端側的實際工具實現 geolocationGetDefinition.implement(async () => { const position = await new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject), );
return { latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy, }; }), ], });
return
...
; }
在我們的LangChain文檔中查看實時演示,結合瀏覽器本地內存、地理位置和可選的人工審批。
總結
標準工具讓代理訪問後端系統。無頭工具讓它們訪問用户實際工作的地方。
用户並不生活在您的後端。他們生活在瀏覽器、應用和設備中,許多最有價值的代理交互都在那裏發生。無頭工具使這些交互可用,同時保留類型化模式、顯式能力、結構化輸出和可審查性,允許代理使用對用户原生、而非僅對服務器方便的工具。
開始使用LangChain Python或LangChain JS中的無頭工具。
感謝@huntlovell、@colifran_和@sydneyrunkle的 thoughtful 審閲和反饋。
查看您的代理真正在做什麼
LangSmith,我們的代理工程平台,幫助開發者調試每個代理決策、評估更改並一鍵部署。
嘗試LangSmith
獲取演示