2025年,擁抱AI Agent!
嘿,大家好!這里是一個專注于AI智能體的頻道~
在a16z預測2025年的發(fā)展中,Agent占據了很重要的一個環(huán)節(jié)。昨天中金也發(fā)研報,表示看好Agent的發(fā)展趨勢。包括langchain發(fā)布的24年總結報告,Agent是持續(xù)保持增長的。
所以25年,Agent或許值得期待?今天給家人們完全梳理一下Agent 智能體的系統(tǒng),作為Agent入門指南(超長超長)!
這篇文章會幫你理清頭緒,明確地告訴你智能體到底是什么,以及它們是怎么工作的。我們會拆解智能體的關鍵組成部分,包括“工具”這個重要角色。
同時,也會分享一些實用的經驗,教你如何構建和部署智能體,從簡單的單次交互,到復雜的多智能體系統(tǒng)。
我們還會探討如何在企業(yè)環(huán)境中應用多智能體架構,并將其與微服務進行對比。在后續(xù)的文章中,我們會更深入地研究智能體和運營(AgentOps),以及如何搭建一個企業(yè)級多智能體系統(tǒng)的平臺。
什么是Agent智能體?
簡單來說,“智能體就是一個prompt,它指示基礎模型去和特定的工具互動。”
生成式 AI 智能體通過一個設計好的prompt,協(xié)調基礎模型(大模型)與外部工具之間的互動。這個prompt告訴 LLM 何時以及如何使用這些工具。
每一個“工具”本質上都包含了一組函數(shù)規(guī)范(或者我們叫它“聲明”)。這些聲明包括:
- 函數(shù)名稱:工具的唯一標識符。
- 描述:詳細解釋工具的用途、能解決什么問題,以及在什么情況下可以使用它。
- 參數(shù):列出工具需要的輸入參數(shù),并解釋每個參數(shù)的含義、類型和期望值。
- 輸出(可選):描述工具返回結果的格式和內容。
為了讓這些聲明標準化,市面上通常使用基于 JSON 的 OpenAPI 格式。這種標準化格式可以清晰、機器可讀地描述 API,方便與生成式 AI 模型無縫集成。舉個例子,下面是用 OpenAPI 格式聲明一個可以獲取股票價格的工具:
{
"tools": [
{
"functionDeclarations": [
{
"name": "get_stock_price",
"description": "獲取指定公司的當前股票價格。",
"parameters": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "股票代碼(如,AAPL, MSFT)。"
}
},
"required": ["ticker"]
},
"returns": {
"type": "number",
"description": "當前股票價格。"
}
}
]
}
]
}
我們也可以用 Python SDK 以編程方式創(chuàng)建相同的函數(shù)聲明,比如 Vertex AI 提供的 SDK。這樣做可以更靈活地創(chuàng)建和管理工具規(guī)范:
from vertexai.generative_models import (
FunctionDeclaration,
GenerationConfig,
GenerativeModel,
Part,
Tool,
)
# 創(chuàng)建函數(shù)聲明
get_stock_price = FunctionDeclaration(
name="get_stock_price",
descriptinotallow="獲取指定公司的當前股票價格",
parameters={
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "公司的股票代碼",
}
},
"required": ["ticker"]
},
returns={ # 添加 returns 字段!
"type": "number",
"description": "當前股票價格。"
}
)
# ... 可以添加更多的函數(shù)聲明
# 定義一個工具,包含可以被 FM 使用的函數(shù)列表
company_insights_tool = Tool(
function_declaratinotallow=[
get_stock_price,
# ... 其他函數(shù)聲明
],
)
為了更直觀地展示這些概念,我們將在下面的例子中使用 Vertex AI SDK 和 Gemini 的函數(shù)調用功能。這些例子基于這個代碼倉庫,推薦去看看(https://github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/function-calling/use_case_company_news_and_insights.ipynb)。這種方法能讓你從更底層的角度理解智能體的工作原理。一旦你掌握了這些基礎知識,就可以更輕松地使用 LangChain 等更高級的智能體框架了。
到目前為止,我們主要關注如何用 JSON 定義工具結構,以及如何用 Vertex AI SDK 以編程方式創(chuàng)建這些定義。這些工具定義最終會被轉換成文本,并附加到指令提示中。這讓模型可以判斷,為了滿足用戶的請求,是否需要使用工具,如果要用,該用哪個,以及應該使用哪些參數(shù)。
下面這個例子演示了工具、模型和指令是如何一起工作的:
# 選擇 LLM,配置參數(shù),并提供可用的工具
gemini_model = GenerativeModel(
"gemini-2.0-flash-exp",
generation_cnotallow=GenerationConfig(temperature=0),
tools=[company_insights_tool],
)
# 為 LLM 準備指令
instruction = """
給出一個簡潔、高層次的總結。只使用你從 API 響應中獲取的信息。
"""
agent = gemini_model.start_chat()
接下來,就可以開始向模型發(fā)送新的輸入了:
# 為 LLM 準備你的查詢/問題
query = "Google當前股票價格是多少?"
# 將指令和查詢一起發(fā)送給 LLM
prompt = instruction + query
response = agent.send_message(prompt)
你覺得模型會怎么回應?它會調用真實的函數(shù)嗎?
如果 ??company_insights_tool?
?? 定義正確(包括帶有 ??ticker?
?? 參數(shù)和 ??returns?
?? 字段的 ??get_stock_price?
?? 函數(shù),就像前面的例子那樣),Gemini 應該能識別出它有一個可以回答這個問題的工具。它很可能會生成一個結構化的請求,調用 ??get_stock_price?
?? 函數(shù),并將 ??ticker?
? 參數(shù)設為 "GOOG" (或者 "GOOGL",取決于你如何處理谷歌的兩類股票)。
這里要注意的是,Gemini 本身不會直接執(zhí)行外部代碼或者實時調用股票價格 API。相反,它會生成一個結構化的請求,讓你(開發(fā)者)來執(zhí)行。運行下面的代碼:
# LLM 檢查可用的工具聲明
# LLM 返回最適用的函數(shù)和參數(shù)
function_call = response.candidates[0].content.parts[0].function_call
響應大概會像這樣(簡化版):
name: "get_stock_price"
args {
fields
{ key: "ticker"
value {string_value: "Google"}
}
}
那么,你該如何真正獲取股票價格呢?這就輪到你的代碼出場了:
也就是說,用戶(更常見的情況是你的代碼)需要負責根據模型的響應觸發(fā)正確的代碼。為了做到這一點,我們需要為每一個工具聲明都實現(xiàn)一個單獨的 Python 函數(shù)。下面是 ??get_stock_price?
? 函數(shù)的例子:
# 為每個聲明實現(xiàn)一個 Python 函數(shù)
def get_stock_price_from_api(content):
url = f"https://www.alphavantage.co/query?functinotallow=GLOBAL_QUOTE"
f"&symbol={content['ticker']}&apikey={API_KEY}"
api_request = requests.get(url)
return api_request.text
# ... 其他函數(shù)實現(xiàn)
為了簡化函數(shù)調用的觸發(fā)過程,我們建議創(chuàng)建一個函數(shù)處理器(也就是一個 Python 字典),把函數(shù)聲明中的函數(shù)名稱和實際的代碼函數(shù)對應起來:
# 將函數(shù)聲明和對應的 Python 函數(shù)連接起來
function_handler = {
"get_stock_price": get_stock_price_from_api,
# ...,
}
現(xiàn)在,有了 Python 函數(shù),并且能夠從模型的響應中拿到函數(shù)名稱和參數(shù),下一步就是執(zhí)行相應的函數(shù):
# LLM 檢查可用的工具聲明
# LLM 返回最適用的函數(shù)和參數(shù)
function_call = response.candidates[0].content.parts[0].function_call
function_name = function_call.name
params = {key: value for key, value in function_call.args.items()}
# 調用對應的 Python 函數(shù) (或者 API)
function_api_response = function_handler[function_name](params)[:20000]
API 調用的輸出大概是這樣:
{
"Global Quote": {
"01. symbol": "GOOG",
"02. open": "179.7500",
"03. high": "180.4450",
"04. low": "176.0300",
"05. price": "177.3500",
"06. volume": "17925763",
"07. latest trading day": "2024-11-14",
"08. previous close": "180.4900",
"09. change": "-3.1400",
"10. change percent": "-1.7397%"
}
}
接下來,就可以把結果發(fā)送回模型進行最終處理和響應生成了:
# 將函數(shù)的返回值發(fā)送給 LLM,生成最終答案
final_response = agent.send_message(
Part.from_function_response(
name=function_name,
respnotallow={"content": function_api_response},
),
)
把函數(shù)的響應傳遞給 LLM 后,我們就能得到最終的答案:
谷歌 (GOOG) 的股價目前為 177.35 美元,相比昨天的 180.49 美元收盤價下跌了 1.74%。
這才是最終用戶期望得到的答案。
簡單總結一下,這個過程包含五個步驟:
- 用戶提問:用戶向模型提問(“谷歌的當前股票價格是多少?”)。
- 模型請求函數(shù)調用:模型生成一個請求,指出應該調用哪個函數(shù)(“get_stock_price”),以及應該使用哪個參數(shù)值(“谷歌”)。
- 開發(fā)者執(zhí)行函數(shù):你的代碼從響應中提取函數(shù)調用信息,并用對應的參數(shù)值運行相應的 Python 函數(shù)(“get_stock_price_from_api”)。這個函數(shù)會從外部 API 獲取真實的股票價格數(shù)據。
- 將函數(shù)結果發(fā)回模型:從外部 API 得到的結果(股票價格數(shù)據)被發(fā)送回 LLM。
- 模型生成最終響應:模型使用得到的數(shù)據,生成最終的、人類可以理解的響應。
我們剛才描述的流程是智能體的基礎。具體來說,我們展示的流程是單輪智能體的核心邏輯:一個輸入觸發(fā)一個函數(shù)調用,并產生一個響應。這種模塊化設計非常適合云部署和擴展。你可以把這個邏輯容器化,然后部署在 Google Cloud Run 等服務上。這樣,你就可以創(chuàng)建一個穩(wěn)定、無服務器的智能體,它可以通過 API 訪問,并且可以在你的 VPC 內或者更廣闊的網絡中使用。
邁向多輪智能體
雖然單輪模型奠定了基礎,但大多數(shù)現(xiàn)實世界的生成式 AI 應用需要更復雜的交互。用戶往往不能通過一次問答就得到所有需要的信息。所以接下來,我們來探索多輪智能體。這種智能體可以記住上下文,處理后續(xù)問題,并且協(xié)調多個函數(shù)調用來實現(xiàn)更復雜的目標。
為了說明這個概念,我們用一個受這個代碼倉庫啟發(fā)的例子(https://github.com/google-gemini/cookbook/blob/main/quickstarts/Function_calling.ipynb)。我們的目標是創(chuàng)建一個可以回答特定區(qū)域電影和影院相關問題的生成式 AI 智能體。和單輪智能體一樣,我們首先需要定義智能體可以使用的函數(shù)。為了簡單起見,我們直接在代碼中提供函數(shù)簽名和描述:
def find_movies(description: str, location: str = ""):
"""根據任何描述(類型、標題詞等)查找當前正在影院上映的電影。參數(shù):description:任何類型的描述,包括類別或類型、標題詞、屬性等。location:城市和州,例如舊金山,CA,或者郵政編碼,例如 95616"""
...
return ["Barbie", "Oppenheimer"]
def find_theaters(location: str, movie: str = ""):
"""查找特定地點,以及可選的正在上映的電影的影院。參數(shù):location:城市和州,例如舊金山,CA,或者郵政編碼,例如 95616。movie:任何電影標題"""
...
return ["Googleplex 16", "Android Theatre"]
def get_showtimes(location: str, movie: str, theater: str, date: str):
"""查找特定影院上映電影的開始時間。參數(shù):location:城市和州,例如舊金山,CA,或者郵政編碼,例如 95616。movie:任何電影標題。theater:影院名稱。date:請求放映時間的日期"""
...
return ["10:00", "11:00"]
下一步是在循環(huán)中運行函數(shù)識別、執(zhí)行(使用函數(shù)處理器)和響應生成,直到模型擁有足夠的信息來完全響應用戶的請求。為了實現(xiàn)多輪交互,Gemini 支持自動函數(shù)調用,我們可以使用以下代碼自動完成:
chat = model.start_chat(enable_automatic_function_calling=True)
response = chat.send_message(
"今晚在山景城上映哪些喜劇電影?什么時間?")
for content in chat.history:
print(content.role, "->", [type(part).to_dict(part) for part in content.parts])
print("-" * 80)
下面的交互展示了,當代碼使用用戶查詢“今晚在山景城上映哪些喜劇電影?什么時間?”執(zhí)行時,模型的行為:
user -> [{'text': '今晚在山景城上映哪些喜劇電影?什么時間?'}]
--------------------------------------------------------------------------------
model -> [{'function_call': {'name': 'find_movies', 'args': {'location': '山景城, CA', 'description': '喜劇'}}}]
--------------------------------------------------------------------------------
user -> [{'function_response': {'name': 'find_movies', 'response': {'result': ['Barbie', 'Oppenheimer']}}}]
--------------------------------------------------------------------------------
model -> [{'function_call': {'name': 'find_theaters', 'args': {'movie': 'Barbie', 'location': '山景城, CA'}}}]
--------------------------------------------------------------------------------
user -> [{'function_response': {'name': 'find_theaters', 'response': {'result': ['Googleplex 16', 'Android Theatre']}}}]
--------------------------------------------------------------------------------
model -> [{'function_call': {'name': 'get_showtimes', 'args': {'date': '今晚', 'location': '山景城, CA', 'theater': 'Googleplex 16', 'movie': 'Barbie'}}}]
--------------------------------------------------------------------------------
user -> [{'function_response': {'name': 'get_showtimes', 'response': {'result': ['10:00', '11:00']}}}]
--------------------------------------------------------------------------------
model -> [{'text': '喜劇電影《Barbie》今晚在 Googleplex 16 的放映時間是 10:00 和 11:00。'}]
--------------------------------------------------------------------------------
這個交互表明,模型在每一輪中都會使用完整的對話歷史,以此來判斷還需要哪些信息,應該使用哪個工具,以及如何組織自己的響應。這種記錄過去的交互信息的方式,對多輪對話來說至關重要,我們稱之為短期記憶。此外,除了對話歷史記錄,存儲一些操作指標也很重要,例如每個模型交互的執(zhí)行時間、延遲和內存等,方便我們進一步實驗和優(yōu)化。
下面是圖中描述的多輪智能體執(zhí)行過程的 7 步驟摘要:
- 新查詢:用戶發(fā)起新的交互,提出新的查詢或問題。
- 函數(shù)識別:基礎模型 (FM) 會分析查詢,結合可用的工具和指令,判斷是否需要進行函數(shù)調用。如果需要,它會識別出合適的函數(shù)名稱和需要的參數(shù)。
- 準備函數(shù)調用:FM 會生成一個結構化的函數(shù)調用請求,指定函數(shù)名稱和要傳遞的參數(shù)。
- 執(zhí)行函數(shù)調用:這一步由開發(fā)者的代碼執(zhí)行,而不是 FM 本身(但是 Gemini 支持自動函數(shù)調用,方便實現(xiàn))。代碼會接收函數(shù)調用請求,執(zhí)行對應的函數(shù)(例如,調用 API),并獲取結果。
- 中間響應:函數(shù)執(zhí)行的結果(函數(shù)獲取的數(shù)據)會被發(fā)送回 FM,作為中間響應。
- 更新上下文(對話歷史):FM 會使用中間響應更新其對話歷史(在圖中被稱為“短期記憶”)。然后,F(xiàn)M 會使用更新后的上下文,來決定是否需要進一步的函數(shù)調用,或者是否已經收集到足夠的信息來生成最終響應。如果需要更多信息,過程會循環(huán)回到步驟 2。
- 最終響應:一旦 FM 認為它已經掌握所有必要的信息(或者達到了為避免無限循環(huán)而設定的最大步驟數(shù)),它會生成最終的響應,發(fā)送給用戶。這個響應會整合從所有函數(shù)調用中獲取的信息。
這個多輪交互比較真實地展示了,生成式 AI 智能體是如何處理單個用戶請求的。然而,在現(xiàn)實世界中,我們經常會多次重復使用智能體。想象一下,用戶這周用智能體查找電影放映時間,下周又回來提出類似的要求。如果智能體能夠記住過去交互的長期記憶,它就可以提供更有針對性的推薦,比如推薦用戶之前感興趣的電影或者影院。這種長期記憶會存儲每次交互的短期對話歷史的摘要或完整記錄。
短期和長期記憶都在實現(xiàn)有效的多輪智能體交互中起著至關重要的作用。下面是它們各自的說明和實現(xiàn)方式:
短期記憶(對話歷史):存儲在單個用戶會話中正在進行的對話。這包括用戶的查詢、模型的函數(shù)調用以及來自這些函數(shù)調用的響應。這種上下文對于模型理解后續(xù)問題,以及在整個交互中保持連貫性至關重要。實現(xiàn)選項:
- 日志(小文本日志):對于對話比較短的簡單應用,可以將交互歷史記錄存儲為純文本日志。這種方式實現(xiàn)簡單,但是對于長對話或高流量,效率可能會降低。
- 云存儲/數(shù)據庫(大型非文本日志):對于更復雜的應用(例如,利用多模態(tài)模型處理圖像或者音頻輸入),云存儲服務或者數(shù)據庫會是更好的選擇。這種方式能更結構化地存儲,并高效地檢索對話歷史。
- API 會話(客戶端存儲):對話歷史也可以在客戶端(例如,網頁瀏覽器或者手機應用)使用 API 會話管理。這種方式能減少服務器端的存儲壓力,但存儲的數(shù)據量可能會有限制。
- 以上所有方式的組合:可以混合使用不同的存儲方式,根據應用的特定需求來選擇合適的方案。
長期記憶:存儲用戶在多個會話中的歷史交互信息。這使得智能體能夠學習用戶的偏好,提供個性化的推薦,并在長期使用中提供更高效的服務。實現(xiàn)選項:
- 向量數(shù)據庫(用于 RAG - 檢索增強生成):向量數(shù)據庫特別適合在智能體應用中進行長期記憶存儲。它們將數(shù)據存儲為向量嵌入,從而捕捉數(shù)據的語義含義。這使得智能體可以高效地進行相似性搜索,從而根據當前用戶查詢,從過去的交互中檢索相關信息。這通常用于檢索增強生成(RAG)流程中。
- 元數(shù)據存儲/圖(會話 ID、其他元數(shù)據):元數(shù)據存儲(如圖形數(shù)據庫或鍵值存儲)可以用來存儲關于用戶會話的信息,例如會話 ID、時間戳和其他相關元數(shù)據。這可以用來組織和檢索過去的對話歷史和交互關系。
- 云存儲/數(shù)據庫(實際日志):過去的對話完整日志可以存儲在云存儲或數(shù)據庫中。這種方式提供了所有交互的完整記錄,但可能需要更多的存儲空間和更復雜的檢索機制。
- 以上所有方式的組合:和短期記憶類似,可以使用多種存儲機制的組合來優(yōu)化性能和存儲效率。例如,摘要信息可以存儲在向量數(shù)據庫中以便快速檢索,而完整日志可以存儲在成本更低的云存儲中,用于審計或者更詳細的分析。
智能體調用智能體:多智能體系統(tǒng)的力量
雖然單個智能體可以處理復雜的任務,但有些問題需要協(xié)同努力才能解決。多智能體系統(tǒng)通過讓多個智能體一起工作來解決這個問題,每個智能體負責一個特定的子任務。這種協(xié)作方法允許將復雜問題分解為更小的、更易于管理的部分,從而實現(xiàn)更高效、更強大的解決方案。
多智能體系統(tǒng)的一個關鍵概念是把智能體當作工具:就像一個智能體可以使用外部 API 或者函數(shù)一樣,它也可以使用其他的智能體來執(zhí)行特定的子任務。這種“智能體即工具”的模式允許我們創(chuàng)建分層系統(tǒng),由一個智能體來協(xié)調其他智能體的工作。
下面是一些最常見的多智能體模式:
- 路由智能體(逐一):在這種模式中,一個中央的“路由器”智能體接收初始請求,然后把它逐一委派給其他的智能體。路由器充當協(xié)調者的角色,決定哪個智能體最適合處理任務的哪個部分。當一個智能體完成它的子任務后,結果會返回給路由器,然后路由器會決定下一步的操作。這種模式適用于那些可以分解成順序步驟的任務,其中一個步驟的輸出會影響到下一個步驟。
- 并行(一對多):在這種模式中,一個智能體會把子任務同時分發(fā)給多個智能體。當子任務彼此獨立并且可以并行執(zhí)行時,這種模式很有效,可以顯著減少整體處理時間。一旦所有的智能體都完成了它們的工作,它們的結果會被匯總起來,通常由分發(fā)任務的初始智能體來完成。
- 順序(預定義順序):這種模式涉及到智能體之間預定義的信息流。一個智能體的輸出會直接作為輸入,傳遞給固定序列中的下一個智能體。這種模式適用于那些有明確線性工作流程的任務。
- 循環(huán)流(預定義順序):和順序模式類似,但信息流形成一個循環(huán)。序列中最后一個智能體的輸出會被傳遞回第一個智能體,形成一個循環(huán)。這對于迭代過程來說很有用,在這種過程中,智能體會根據循環(huán)中其他智能體的反饋來改進自己的輸出。
- 動態(tài)(全對全):在這種更復雜的模式中,任何智能體都可以與其他任何智能體通信。沒有中央協(xié)調器或者預定義的信息流。智能體可以動態(tài)地交換信息,并且相互協(xié)商以實現(xiàn)共同的目標。這種模式更靈活,但管理起來也更復雜,需要復雜的通信和協(xié)調機制。
總結一下,你可以這樣理解:
- 在路由器模式中,路由器智能體把其他的智能體當作專門的工具來使用,根據需要逐一調用它們。
- 在并行模式中,初始智能體同時使用多個智能體作為工具,來加速整個過程。
- 在順序和循環(huán)流模式中,智能體在一個預定義的流程或循環(huán)中使用,像工具一樣。
- 在動態(tài)模式中,智能體的互動更像是一個團隊,每個智能體都同時充當其他智能體的用戶和工具,具體情況而定。
這些模式提供了不同的方式來構建多智能體交互,開發(fā)者可以根據應用的特定需求,選擇最合適的方式。
在了解了多智能體協(xié)作的概念后,下一個問題自然是如何在企業(yè)環(huán)境中實踐。上圖展示了一個基于微服務方法的企業(yè)級架構。這種方法把每個智能體都視為一個獨立的微服務,就像微服務把大型應用分解成可以獨立部署的組件一樣。這個類比非常有用,因為它允許我們利用現(xiàn)有的微服務最佳實踐:每個業(yè)務部門可以獨立開發(fā)和部署自己的智能體,作為獨立的微服務,并根據自己的特定需求進行定制。這種分散式的方法可以提高靈活性,并加快開發(fā)周期,因為團隊可以獨立工作,而不會影響系統(tǒng)的其他部分。就像微服務通過 API 進行通信一樣,多智能體系統(tǒng)中的智能體也通過交換消息進行通信,消息通常使用 JSON 等結構化格式。為了確?;ゲ僮餍圆⒈苊庵貜烷_發(fā),一個中央工具注冊表會提供對共享工具的訪問,而一個智能體模板目錄會提供可重用的代碼和最佳實踐。這種方法可以促進協(xié)作,加快開發(fā)速度,并提高整個組織的一致性。我們會在后續(xù)的文章中,更深入地探討這個架構。
結論
這篇文章的關鍵要點包括:
- 生成式 AI 模型依賴智能體通過定義良好的函數(shù)聲明,與外部工具進行交互。
- 智能體本質上是一個提示,它指示基礎模型與特定工具進行交互。
- 多輪智能體通過動態(tài)調用各種函數(shù),并在整個交互過程中維護上下文,來處理復雜的用戶請求。
- 多智能體系統(tǒng)使智能體能夠通過委派子任務和協(xié)調彼此的工作,來協(xié)作解決復雜的問題。
本文轉載自 ??探索AGI??,作者: 獼猴桃
