使用 Knative 的 LLM 代理:概述 ¶
發布日期:2024-07-17
使用 Knative 的 LLM 代理:概述¶
作者:Calum Murray,Red Hat 軟體工程實習生
LLM 是一種變革性技術,能夠實現使用者和軟體系統之間的新型互動形式。但是,我們如何確保 LLM 給予使用者正確的答案?我們是否可以將 LLM 用作不僅僅是問答/摘要工具,還可以讓它們代表我們採取行動?
LLM 代理和工具呼叫是該領域中一些新興的模式,允許 LLM 與其他工具和模型互動,解決了大部分的正確性問題,並使 LLM 能夠為使用者採取行動。有了這些好處,我們一直在 Knative 社群中尋找方法,讓您可以更輕鬆地建立 LLM 代理系統,並以更符合您建置系統其餘部分的方式進行:宣告式和雲端原生。在這篇部落格文章中,我們將首先介紹 LLM 代理究竟是什麼以及 LLM 如何呼叫工具的一些背景知識,然後我們將討論我們設想 Knative 在這種範例中的適用之處。
什麼是代理?¶
在 AI 中,代理被定義為能夠接收有關其環境的資訊,並使用該資訊來做出決策和採取行動以達成目標的系統。在 LLM 的背景下,代理是一個以 LLM 為核心的系統,能夠在回答其收到的提示時,決定採取哪些行動。可以建置 LLM 代理來採取的常見行動包括:向使用者發送文字或其他媒體、呼叫工具以協助回答使用者,以及呼叫另一個代理以協助回答使用者。一般而言,LLM 代理也將具有一個系統提示,說明其角色是什麼,並提供一些關於何時呼叫工具和/或回覆使用者的規則。對於大多數代理,控制流程可以顯示如下
LLM 代理優於其他形式代理的一個關鍵屬性是,是否呼叫更多工具、再次呼叫 LLM、呼叫另一個代理或完成處理的決策由 LLM 做出 - 而不是其他形式的邏輯(手動編碼或基於 AI/ML)。因此,雖然上圖顯示 LLM 和代理是兩個獨立的實體,但它們通常是同一個實體。每當工具或代理呼叫完成時,該資訊就會被傳送到 LLM,然後 LLM 會決定如何處理該資訊。有時,LLM 會決定再次呼叫自己 - 例如,我們觀察到當 LLM 想要在繼續呼叫其他代理或工具之前向使用者發送一些文字時,就會發生這種情況。
LLM 如何呼叫工具?¶
LLM 呼叫工具所需要的一切是 LLM 能夠傳達它想要呼叫哪個工具,以及它想要提供給工具的任何參數(如果有的話)的方法。由於 LLM 輸出只是一連串的 Token,因此需要某種外部系統可以從輸出中剖析此資訊,因此 LLM 需要以一致的方式輸出結構化或半結構化的資料來呼叫工具。關於如何執行此操作有多個不同的 API,而且目前在某種程度上取決於您正在使用的確切模型(因為它們已受過以不同方式處理此問題的訓練)。就本部落格而言,我們將特別關注 OpenAI Chat API 來執行此操作,但是對於其他模型,概念通常是相同的。
在 OpenAI Chat API 中,您需要傳遞 LLM 可以使用的一系列工具。您必須提供的關鍵資訊是工具的 name
,以及工具可能接受的任何 parameters
。對於每個參數,也必須提供有關參數類型、其用途及其名稱的資訊,以便 LLM 能夠盡可能準確地呼叫該工具。例如,以下 JSON 物件是一個有效的工具
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
這個 JSON 物件將包含在任何對 OpenAI Chat API 的呼叫中,其中 LLM 可能想要選擇呼叫 get_current_weather
函式。如果未包含,LLM 將不會知道該工具,並且將無法呼叫它。
當 LLM 被呼叫並帶有一組工具時,它能夠決定是否呼叫任何工具,以及使用哪些參數呼叫哪些工具。檢查模型是否想要進行任何工具呼叫的方式是查看回應訊息的 tool_calls
屬性。例如,在 Python 中,您會執行以下操作
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
從那裡,您將擁有一個要呼叫的工具陣列,以及要傳遞給每個工具的參數。因此,要呼叫該工具,您必須使用 LLM 選擇提供的參數呼叫某個函式或類別方法。
使用 Knative 進行 LLM 工具呼叫¶
在調查 LLM 如何呼叫工具時,我們注意到許多工具都是簡單的 API 包裝器:它們取得 LLM 提供的參數並將它們對應到某種形式的 API 呼叫中。我們也注意到,由於 LLM 只知道工具的名稱及其可以接受的參數,因此任何不是 API 包裝器的工具都可以很容易地變成一個(例如,透過將工具的邏輯放入一個建置為 Linux 容器的 Knative 函式,並將其部署為 Knative 服務)。但是為什麼這很重要?
當所有工具都只是 API 包裝器時,定義系統中任何工具所需要的一切就是
- 工具的名稱
- 工具的描述
- 工具接受的參數
- 如何將參數對應到工具的 API 中
請注意,以上列表中的所有內容都只是關於工具的中繼資料,而且使用這四個中繼資料,我們可以定義任何我們希望 LLM 能夠呼叫的任何工具。這是一個非常重要的結果,因為它允許我們概括工具呼叫,並從呼叫工具的程式碼中提取工具的定義。換句話說,我們可以根據 LLM 訊息編寫一次呼叫工具的程式碼,並使用系統中關於工具的中繼資料來處理每個個別工具的細節。
在 Knative 中,我們已經有一個 CustomResource 來記錄這個中繼資料:EventTypes! EventTypes 最初是為了建模 Knative Eventing 系統中存在的 CloudEvents 類型而建立的,以便開發 Event Consumers 的開發人員可以輕鬆了解可用的內容以及如何使用它。但是,同樣的資訊可以用來描述服務期望接收的內容(在這種情況下,作為來自 LLM 的工具呼叫)。 EventTypes 可以直接使用,無需任何變更,來描述 LLM Agent 可以使用哪些工具,以及如何呼叫它們。
舉例來說,假設我有一個服務可以返回特定地點的目前天氣。我可以用 EventType 表示此服務期望的合約,如下所示:
apiVersion: eventing.knative.dev/v1beta2
kind: EventType
metadata:
name: get.current.weather
spec:
reference:
apiVersion: serving.knative.dev/v1
kind: Service
name: get-current-weather
description: "Get the current weather in a given location."
schemaData: '{"location":{"type":"string","description":"The city and state, e.g. San Francisco, CA"},"unit":{"type":"string","description":"One of [celsius, farenheit]"}}'
type: "get.current.weather"
EventType 的描述可以直接對應到 LLM 期望的工具描述,名稱可以取自 EventType 資源的名稱(但請注意:OpenAI 模型要求工具名稱只能使用 a-z、A-Z、0-9、底線和破折號,且最大長度為 64,因此我們可能需要對名稱進行一些清理)。至於函式的參數,我們可以透過解析 EventType 的 schemaData
來取得。
正如我們在上面看到的,EventType 資源包含所有資訊,以告知 LLM 如何呼叫服務。要使用來自包含工具呼叫的 LLM 訊息呼叫工具,我們需要做的就是使用 schemaData
以及 EventType 中的 type
欄位,來建構具有正確資料的 CloudEvent,該事件將被傳送到正確的服務。要將其傳送到服務,我們可以選擇:
- 從 spec 解析參考到 URI,並直接呼叫該 URI
- 使用 Knative Broker 來處理所有工具呼叫到正確的 Knative Service 的分派
考慮到使用 Brokers 的許多優勢(例如傳遞重試、支援 broker 的持久訊息技術,如 Apache Kafka 等),我們選擇使用 Broker 將所有工具呼叫分派到正確的 Service。為了取得工具呼叫結果的回應(而不僅僅是 broker 確認收到事件),我們新增了一個部署,該部署位於 broker 前面,提供請求-回覆語意。我們計劃透過新的 CustomResource 新增此部署 - 請查看此處的 issue以取得更多資訊,以及其運作方式。
這樣一來,您的 LLM Agent 要學習如何呼叫其中一個服務,您只需:
- 使用篩選器選擇特定類型的事件,從您的 broker 建立到您的服務的觸發器
- 建立一個具有相同
type
的 EventType,該 EventType 使用schemaData
來描述您服務的 API
總結¶
在這篇部落格文章中,我們介紹了什麼是 LLM 代理、LLM 如何呼叫工具,以及如何使用 Knative 透過中繼資料簡化工具呼叫。如果您對如何建立使用 Knative 來簡化工具呼叫和探索的 LLM 代理系統,以及我們對這項技術未來發展的願景感興趣,請持續關注我們即將發布的下一篇關於此主題的部落格文章!如果您對此主題有任何疑問,我們邀請您在 CNCF slack 實例中的 Knative 頻道與我們互動。