0 前言
Agent是一個使用大語言模型決定應用程式控制流的系統。隨著這些系統的開發,它們隨時間推移變得複雜,使管理和擴充套件更困難。如你可能會遇到:
- Agent擁有太多的工具可供使用,對接下來應該呼叫哪個工具做出糟糕決策
- 上下文過於複雜,以至於單個Agent無法跟蹤
- 系統中需要多個專業領域(例如規劃者、研究員、數學專家等)。
為解決這些問題,你可能考慮將應用程式拆分成多個更小、獨立的代理,並將它們組合成一個多Agent系統。這些獨立的Agent可以簡單到一個提示和一個LLM呼叫,或者複雜到像一個ReActAgent(甚至更多!)。
1 多Agent系統的好處
- 模組化:獨立的Agent使得開發、測試和維護Agent系統更加容易。
- 專業化:你可以建立專注於特定領域的專家Agent,這有助於提高整個系統的效能。
- 控制:你可以明確控制Agent之間的通訊(而不是依賴於函式呼叫)。
2 多Agent架構
多Agent系統中有幾種方式連線Agent:
- 網路:每個Agent都可與其他Agent通訊。任何Agent都可以決定接下來呼叫哪個其他Agent
- 監督者:每個Agent與一個監督者Agent通訊。監督者Agent決定接下來應該呼叫哪個Agent。
- 監督者(工具呼叫):這是監督者架構的一個特殊情況。個別Agent可以被表示為工具。在這種情況下,監督者Agent使用一個工具呼叫LLM來決定呼叫哪個Agent工具,以及傳遞哪些引數給這些Agent。
- 層次結構:你可以定義一個有監督者的多Agent系統。這是監督者架構的概括,並允許更復雜的控制流。
- 自定義多Agent工作流:每個Agent只與Agent子集中的其他Agent通訊。流程的部分是確定性的,只有一些Agent可以決定接下來呼叫哪個其他Agent。
網路
這種架構中,Agent被定義為圖節點。每個Agent都可以與每個其他Agent通訊(多對多連線),並且可以決定接下來呼叫哪個Agent。雖然非常靈活,但隨著Agent數量的增加,這種架構擴充套件性並不好:
- 很難強制執行接下來應該呼叫哪個Agent
- 很難確定應該在Agent之間傳遞多少資訊
建議生產避免使用這架構,而是使用以下架構之一。
監督者
這種架構中,定義Agent為節點,並新增一個監督者節點(LLM),它決定接下來應該呼叫哪個Agent節點。使用條件邊根據監督者的決策將執行路由到適當的Agent節點。這種架構也適用於並行執行多個Agent或使用map-reduce模式。
from typing import Literal
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, MessagesState, START
model = ChatOpenAI()
class AgentState(MessagesState):
next: Literal["agent_1", "agent_2"]
def supervisor(state: AgentState):
response = model.invoke(...)
return {"next": response["next_agent"]}
def agent_1(state: AgentState):
response = model.invoke(...)
return {"messages": [response]}
def agent_2(state: AgentState):
response = model.invoke(...)
return {"messages": [response]}
builder = StateGraph(AgentState)
builder.add_node(supervisor)
builder.add_node(agent_1)
builder.add_node(agent_2)
builder.add_edge(START, "supervisor")
# 根據監督者的決策路由到Agent之一或退出
builder.add_conditional_edges("supervisor", lambda state: state["next"])
builder.add_edge("agent_1", "supervisor")
builder.add_edge("agent_2", "supervisor")
supervisor = builder.compile()
教程以獲取有關監督者多Agent架構的示例。
監督者(工具呼叫)
在這種監督者架構的變體中,我們定義個別Agent為工具,並在監督者節點中使用一個工具呼叫LLM。這可以作為一個ReAct風格的Agent實現,有兩個節點——一個LLM節點(監督者)和一個執行工具(在這種情況下是Agent)的工具呼叫節點。
from typing import Annotated
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import InjectedState, create_react_agent
model = ChatOpenAI()
def agent_1(state: Annotated[dict, InjectedState]):
tool_message = ...
return {"messages": [tool_message]}
def agent_2(state: Annotated[dict, InjectedState]):
tool_message = ...
return {"messages": [tool_message]}
tools = [agent_1, agent_2]
supervisor = create_react_agent(model, tools)
自定義多Agent工作流
在這種架構中,我們新增個別Agent作為圖節點,並提前定義Agent被呼叫的順序,以自定義工作流。在LangGraph中,工作流可以以兩種方式定義:
- 顯式控制流(普通邊):LangGraph允許你透過普通圖邊顯式定義應用程式的控制流(即Agent通訊的順序)。這是上述架構中最確定性的變體——我們總是提前知道接下來將呼叫哪個Agent。
- 動態控制流(條件邊):在LangGraph中,你可以允許LLM決定應用程式控制流的部分。這可以透過使用條件邊實現。一個特殊情況是監督者工具呼叫架構。在這種情況下,驅動監督者Agent的工具呼叫LLM將決定工具(Agent)被呼叫的順序。
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, MessagesState, START
model = ChatOpenAI()
def agent_1(state: MessagesState):
response = model.invoke(...)
return {"messages": [response]}
def agent_2(state: MessagesState):
response = model.invoke(...)
return {"messages": [response]}
builder = StateGraph(MessagesState)
builder.add_node(agent_1)
builder.add_node(agent_2)
# 明確定義流程
builder.add_edge(START, "agent_1")
builder.add_edge("agent_1", "agent_2")
3 Agent之間通訊
構建多Agent系統時最重要的事情是弄清楚Agent如何通訊。有幾個不同的考慮因素:
- Agent是透過圖狀態或工具呼叫進行通訊的嗎?
- 如果兩個Agent有不同的狀態模式怎麼辦?
- 如何透過共享訊息列表進行通訊?
3.1 圖狀態與工具呼叫
Agent之間傳遞的“有效載荷”是什麼?在上述討論的大多數架構中,Agent透過圖狀態進行通訊。在監督者帶工具呼叫的情況下,有效載荷是工具呼叫引數。
圖狀態
要透過圖狀態進行通訊,各個Agent需要被定義為圖節點。這些可以作為函式或整個子圖新增。在圖執行的每一步中,Agent節點接收當前的圖狀態,執行Agent程式碼,然後將更新的狀態傳遞給下一個節點。
通常,Agent節點共享一個單一的狀態模式。然而,你可能想要設計具有不同狀態模式的Agent節點。
3.2 不同的狀態模式
一個Agent可能需要與其餘Agent有不同的狀態模式。例如,搜尋Agent可能只需要跟蹤查詢和檢索到的文件。在LangGraph中有兩種方法可以實現這一點:
- 定義具有單獨狀態模式的子圖Agent。如果子圖和父圖之間沒有共享狀態鍵(通道),則需要新增輸入/輸出轉換,以便父圖知道如何與子圖通訊。
- 定義具有私有輸入狀態模式的Agent節點函式,該模式與整個圖的狀態模式不同。這允許傳遞僅需要用於執行該特定Agent的資訊。
3.3 共享訊息列表
Agent之間通訊的最常見方式是透過共享狀態通道,通常是訊息列表。這假設狀態中至少有一個通道(鍵)由Agent共享。當透過共享訊息列表通訊時,還有一個額外的考慮因素:Agent是共享完整的歷史記錄還是僅共享最終結果?
共享完整歷史記錄
Agent可以共享他們的思維過程的完整歷史記錄(即“草稿墊”)與其他所有Agent。這種“草稿墊”通常看起來像一個訊息列表。共享完整思維過程的好處是,它可能有助於其他Agent做出更好的決策,提高整個系統的整體推理能力。缺點是,隨著Agent數量和複雜性的增長,“草稿墊”將迅速增長,可能需要額外的策略進行記憶體管理。
共享最終結果
Agent可以擁有自己的私有“草稿墊”,並且只與其餘Agent共享最終結果。這種方法可能更適合擁有許多Agent或更復雜的Agent的系統。在這種情況下,你需要定義具有不同狀態模式的Agent。
對於作為工具呼叫的Agent,監督者根據工具模式確定輸入。此外,LangGraph允許在執行時傳遞狀態給單個工具,以便從屬Agent在需要時可以訪問父狀態。
關注我,緊跟本系列專欄文章,咱們下篇再續!
作者簡介:魔都架構師,多家大廠後端一線研發經驗,在分散式系統設計、資料平臺架構和AI應用開發等領域都有豐富實踐經驗。
各大技術社群頭部專家博主。具有豐富的引領團隊經驗,深厚業務架構和解決方案的積累。
負責:
- 中央/分銷預訂系統效能最佳化
- 活動&券等營銷中臺建設
- 交易平臺及資料中臺等架構和開發設計
- 車聯網核心平臺-物聯網連線平臺、大資料平臺架構設計及最佳化
- LLM Agent應用開發
- 區塊鏈應用開發
- 大資料開發挖掘經驗
- 推薦系統專案
目前主攻市級軟體專案設計、構建服務全社會的應用系統。
參考:
- 程式設計嚴選網
本文由部落格一文多發平臺 OpenWrite 釋出!