AI News HubLIVE
站内改写4 分鐘閱讀

AI代理中的“啞核心,智能邊緣”架構

許多AI代理系統在生產環境中失敗,原因是智能集中在了難以測試、替換和推理的中心。本文提出了一種架構原則:啞核心,智能邊緣,即編排器應僅負責控制流,而領域智能分佈在邊緣的專有節點中。這種設計提高了可測試性、可替換性和成本效益,並降低了耦合風險。

來源Hacker News AI作者: arizen

許多代理系統在生產環境中失敗,它們都有一個共同點:智能集中在中心,這使得系統難以測試、替換和推理。編排器承擔了過多工作——同時處理路由、持有領域知識、管理記憶、選擇工具和塑造輸出。當出現故障時,無法隔離問題;當需求變化時,無法精確更新;整個系統必須一起改動。

這不是模型質量問題。這些團隊並非使用低質量的LLM,而是遇到了一個架構錯誤。這一錯誤如此常見,以至於值得命名,並有清晰的對抗原則。

該原則是:啞核心,智能邊緣。編排器——即序列化工作的中央節點——應幾乎無狀態,僅編碼控制流。智能位於外圍,即擁有自身領域邊界的專有節點,這些節點可以獨立地進行推理、測試和替換。這不僅僅是風格偏好,當系統有多個需要獨立演進的領域、工具或職責時,這是一種有用的拓撲結構。

智能核心為何失敗

集中智能的衝動是可以理解的。你有一個強大的模型,編寫一個系統提示,給它所有工具,讓它自己解決問題。在演示中,這可行。模型足夠強大,可以同時處理多個關注點,成功路徑看起來清晰。

但生產環境會以四種方式打破這種模式:

第一:糾纏。當編排器同時編碼路由邏輯和領域知識時,更改一個就需要觸及另一個。新工具意味着重寫提示;新領域規則意味着重新測試路由。系統產生了沒有架構邊界的耦合——只有一個又長又脆弱的自然語言指令字符串。

第二:不可測試性和不透明性。你無法為同時處理五件事的LLM提示編寫單元測試。你只能運行端到端評估,觀察湧現行為是否穩定。當代理行為異常時,你需要知道失敗是在路由、領域推理、工具選擇還是輸出格式化中。智能核心將所有這些問題混為一談——迴歸問題直到生產環境才顯現,然後你只能用手電筒調試黑箱。

第三:成本放大。智能核心代理會將每個令牌的上下文——完整歷史、所有工具模式、所有領域規則——通過同一路徑發送,每一步都如此。在多步驟工作流中,這會反覆為當前步驟可能不需要的上下文付費。而啞核心路由到專有節點,專有節點只接收它們需要的上下文。在模型路由經濟學規模下——數百萬次調用——成本差異迅速累積。

原則的定義

結構外圍原則:在具有多個領域或工具邊界的代理系統中,自主判斷的能力應儘可能分佈到圖的邊緣,核心僅負責狀態轉換和路由契約。

這並不是新想法,而是老的系統工程在代理圖中的應用。Unix管道之所以有效,是因為每個程序只做一件事,並通過簡單穩定的接口通信。微服務有效——當它們有效時——也是出於同樣的原因。互聯網的核心協議故意設計得簡單,智能存在於端點。啞核心,智能邊緣將同樣的邏輯應用於代理圖。

編排器的工作範圍精確:接收類型化輸入,確定哪個專有節點處理,分發,等待結果,並輸出類型化輸出。它不編碼領域知識,不持有持久記憶,不對內容做出判斷。它是一個狀態機——並且應該能被讀作一個狀態機。

相比之下,專有節點在其領域邊界內是自主的。研究專有節點知道如何查詢來源、評估可信度和綜合發現。代碼審查專有節點知道代碼庫慣例、要檢查的失敗模式以及如何格式化輸出。每個節點都可以獨立地進行提示、微調、替換或評估。編排器永遠不需要知道發生了什麼變化。

“啞”的實際含義

“啞核心”是一個精確術語,而非貶義。編排器仍然可以在CLASSIFY_INTENT步驟中使用LLM——將傳入請求分類為類型化的意圖是語言理解的合理用途。但它絕不能對該意圖的內容進行推理、應用領域啓發式或對領域內的邊緣情況做出判斷。

一個有用的測試:如果你從編排器的系統提示中移除所有領域特定詞彙,並用通用佔位符替換,路由邏輯是否仍然有效?如果是,則核心是適當“啞”的。如果路由依賴於理解“帶有爭議收費的退款請求”的含義,那麼領域知識已泄漏進核心,你有了耦合問題。

編排器的系統提示應該像交通管制員手冊——關於流程、優先級和失敗處理的規則,對貨物沒有意見。專有節點的提示應該像專家簡報——深入、有主見且狹窄。

這也支配了記憶架構。共享的、全局的、可被編排器訪問的記憶是一個壞味道。每個專有節點應在任務期間擁有自己的工作記憶。持久記憶——用户偏好、先前對話摘要、學習到的事實——應由專有節點按需檢索,而不是預加載到編排器的上下文中。編排器傳遞會話標識符,而不是記憶轉儲。

可替換性測試

啞核心、智能邊緣的實際證明是我所稱的可替換性測試:你應該能夠替換任何專有節點——用確定性算法、更小的模型或不同的專有節點實現替換基於提示的實現——而無需修改編排器或任何相鄰專有節點。爆炸半徑應保持在該專有節點邊界內。

如果替換需要更改被替換節點之外的東西,則系統存在隱藏耦合。最常見的來源:編排器解析或依賴專有節點輸出的內部結構,而不是消費類型化契約。修復方法始終相同——在邊緣定義Pydantic模式,在輸出時驗證,並讓編排器消費類型,而不是原始文本。

這就是因果工程進入的地方。當你能夠替換一個節點並觀察對系統行為的孤立影響時,你就有了對系統的因果控制。你可以運行受控實驗:相同的編排器,相同的相鄰專有節點,不同的專有節點B。輸出質量的差異可單獨歸因於專有節點B。這是科學地改進代理系統的方法,而不是靠直覺和祈禱。

實際應用

在LangGraph中的實現模式是直接的。將編排器定義為具有類型化狀態的圖——一個只攜帶路由元數據、會話標識符和結果槽的TypedDict或Pydantic模型。圖中的每個節點都是一個專有函數,接收窄範圍輸入並返回類型化輸出。邊編碼控制流。節點編碼智能。

以下是LangGraph v0.4中的一個最小啞核心編排器示例:

from typing import Literal
from pydantic import BaseModel
from langgraph.graph import StateGraph, END

class OrchestratorState(BaseModel):
    user_input: str
    intent: str = ""
    specialist_result: str = ""
    session_id: str = ""

async def classify_intent(state: OrchestratorState) -> dict:
    intent = await llm_classify(state.user_input)
    return {"intent": intent}

def route_by_intent(state: OrchestratorState) -> Literal["research", "code_review", "fallback"]:
    mapping = {"research": "research", "code_review": "code_review"}
    return mapping.get(state.intent, "fallback")

async def research_specialist(state: OrchestratorState) -> dict:
    result = await run_research_agent(state.user_input, state.session_id)
    return {"specialist_result": result.model_dump_json()}

async def code_review_specialist(state: OrchestratorState) -> dict:
    result = await run_code_review_agent(state.user_input, state.session_id)
    return {"specialist_result": result.model_dump_json()}

graph = StateGraph(OrchestratorState)
graph.add_node("classify", classify_intent)
graph.add_node("research", research_specialist)
graph.add_node("code_review", code_review_specialist)
graph.add_node("fallback", lambda s: {"specialist_result": "I can't help with that."})
graph.set_entry_point("classify")
graph.add_conditional_edges("classify", route_by_intent)
graph.add_edge("research", END)
graph.add_edge("code_review", END)
graph.add_edge("fallback", END)
app = graph.compile()

注意編排器中不包含什麼:沒有領域詞彙,沒有工具模式,沒有記憶檢索,沒有輸出格式化邏輯。route_by_intent函數是一個純映射。如果明天添加一個新專有節點——比如,法律審查——你只需添加一個節點和映射中的一個條目。現有專有節點不變。

每個專有節點通過類型化輸出模式強制執行其契約:

from pydantic import BaseModel, Field

class SpecialistResult(BaseModel):
    """Contract between any specialist and the orchestrator."""
    result: str = Field(..., description="The specialist's output")
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)

這種模式確保編排器永遠不需要解析原始文本。它消費類型化對象,這允許靜態分析、驗證和清晰的責任邊界。

啞核心、智能邊緣模式並不是一刀切的解決方案。對於只有一個工具且步驟很少的簡單代理,智能核心可能更簡單且足夠。但當系統增長到多個領域、工具或需要獨立發展的責任時,該模式提供了可測試性、可替換性和成本效益,這些遠超過了增加的複雜性。