從理論到實踐:我用12要素方法重構了AI 智能體,效果驚人! 原創 精華
本文為 12-Factor Agents[1] 內容的翻譯整理,并結合個人實踐補充了部分筆記和理解。內容涵蓋 LLM 代理開發的 12 項核心原則。
“12 要素代理” 框架受著名的 12 要素應用方法論啟發,為構建可靠、可維護且可擴展的 LLM 應用提供了全面的指南。這些原則解決了將非確定性 AI 組件集成到生產系統的獨特挑戰,強調明確的控制、托管上下文以及無縫的人機協作。
1. 自然語言工具調用

這是Agent架構中最基礎但也最關鍵的轉換層。當用戶說"幫我創建一個5000元的付款鏈接給琳達,用于贊助三月AI技術沙龍"時,系統需要將這句話精確轉換為結構化的API調用。以下是一個真實的轉換示例:
輸入的自然語言:
"幫我創建一個5000元的付款鏈接給琳達,用于贊助三月AI技術沙龍"轉換后的結構化工具調用:
{
"function":{
"name":"create_payment_link",
"parameters":{
"amount":5000,
"customer":"cust_128934ddasf9",
"product":"prod_8675309",
"price":"prc_09874329fds",
"quantity":1,
"memo":"這是三月AI技術沙龍的贊助付款鏈接"
}
}
}隨后,確定性代碼可以獲取有效載荷并進行處理。
# LLM 接收自然語言并返回結構化對象
nextStep = await llm.determineNextStep(
"""
create a payment link for $750 to Jeff
for sponsoring the february AI tinkerers meetup
"""
)
# 根據結構化輸出的 function 字段進行處理
ifnextStep.function == 'create_payment_link':
stripe.paymentlinks.create(nextStep.parameters)
return # 或者你想要的其他處理,見下文
elifnextStep.function == 'something_else':
# ... 其他情況
pass
else: # themodeldidn'tcallatoolweknowabout
# 模型未調用已知工具,執行其他操作
pass必須深刻理解這一轉換過程的每個環節:從自然語言解析到實體識別,再到參數映射和 API 構造。切勿將其視為黑盒,因為任何細節的偏差都可能導致用戶意圖被誤解,進而影響系統的可靠性和用戶體驗。
理解筆記
構建 Agent 過程中,工具方面,需要做的內容是:
- 工具(Tool)說明文檔要結構化、清晰,確保 LLM 能準確理解每個工具的用途、參數和限制,減少歧義。
- 需要為 LLM 返回的結構化調用結果設計健壯的處理流程,包括成功、失敗、異常等分支,保證系統的可預測性和安全性。
- 工具接口和文檔應與代碼保持同步,避免文檔不同步,導致 LLM 理解偏差。
2. 擁有自己的提示詞
提示詞是 LLM 交互的核心,決定了交互的行為和輸出。本原則強調應將提示詞視為關鍵、受版本控制的代碼資產,而非一次性輸入。提示應納入代碼庫統一管理,便于系統性測試、部署和回滾。掌控自己的提示詞有助于保證一致性、可復現性,并能以可控方式持續優化代理行為。

應將你的提示詞視為一等公民的代碼:
function DetermineNextStep(thread: string) -> DoneForNow | ListGitTags | DeployBackend | DeployFrontend | RequestMoreInformation {
prompt #"
{{ _.role("system") }}
你是一個負責前端和后端系統部署的高效助手。
你會遵循最佳實踐,確保部署安全且成功。
并遵循正確的部署流程。
在部署任何系統前,你應檢查:
部署環境(測試/生產)
部署的正確標簽/版本
當前系統狀態
你可以使用 deploy_backend、deploy_frontend、check_deployment_status 等工具
管理部署。對于敏感部署,使用 request_approval 獲取人工確認。
human verification.
始終先思考下一步該做什么,比如:
檢查當前部署狀態
校驗部署標簽是否存在
如有需要,申請人工批準
先部署到測試環境再到生產環境
監控部署進度
{{ _.role("user") }}
{{ thread }}
下一步應該做什么?
"#
}擁有自己的提示詞的主要好處:
- 完全控制:可精確編寫代理所需指令,無需依賴黑盒抽象
- 測試和評估:可像測試其他代碼一樣測試和評估提示
- 快速迭代:可根據實際表現快速修改提示
- 透明度:清楚了解代理正在執行的指令
- 角色技巧:可利用支持非標準用戶/助手角色的 API
請記住:提示詞是你的應用邏輯與 LLM 之間的主要接口。
完全掌控提示詞,為生產級代理提供了必要的靈活性和提示控制。
我無法斷言什么是最優提示,但你一定需要靈活性以便不斷嘗試。
理解筆記
構建 Agent 過程中,提示詞需要自主可控。提示(Prompt)應作為代碼資產進行版本管理和測試,確保每次變更都可追溯和回滾。
- 推薦采用結構化、可維護的提示工程工具,提升提示的可讀性和可復用性。
- 保持提示的靈活性和可控性,有助于快速迭代和適應業務需求變化。
3. 擁有自己的上下文窗口
上下文窗口是 LLM 對過往交互的有限記憶。本原則主張主動且有策略地管理上下文,確保只保留與當前任務直接相關的信息,及時剔除無關內容,防止"上下文漂移"或信息冗余。高效的上下文管理不僅能提升 LLM 的性能,還能減少 token 消耗,讓模型聚焦于關鍵細節。

無需總是采用標準消息格式向 LLM 傳遞上下文。
標準消息格式 vs 自定義格式對比:
標準消息格式:
[
{
"role":"system",
"content":"You are a helpful assistant..."
},
{
"role":"user",
"content":"Can you deploy the backend?"
},
{
"role":"assistant",
"content":null,
"tool_calls": [
{
"id":"1",
"name":"list_git_tags",
"arguments":"{}"
}
]
},
{
"role":"tool",
"name":"list_git_tags",
"content":"{\"tags\": [{\"name\": \"v1.2.3\", \"commit\": \"abc123\", \"date\": \"2024-03-15T10:00:00Z\"}, {\"name\": \"v1.2.2\", \"commit\": \"def456\", \"date\": \"2024-03-14T15:30:00Z\"}, {\"name\": \"v1.2.1\", \"commit\": \"abe033d\", \"date\": \"2024-03-13T09:15:00Z\"}]}",
"tool_call_id":"1"
}
]優化的自定義格式(更高效):
[
{
"role":"system",
"content":"You are a helpful assistant..."
},
{
"role":"user",
"content":|
Here's everything that happened so far:
<slack_message>
From:@alex
Channel:#deployments
Text:Canyoudeploythebackend?
</slack_message>
<list_git_tags>
intent:"list_git_tags"
</list_git_tags>
<list_git_tags_result>
tags:
-name:"v1.2.3"
commit:"abc123"
date:"2024-03-15T10:00:00Z"
-name:"v1.2.2"
commit:"def456"
date:"2024-03-14T15:30:00Z"
-name:"v1.2.1"
commit:"ghi789"
date:"2024-03-13T09:15:00Z"
</list_git_tags_result>
what'sthenextstep?
}
]實現上下文構建的Python代碼:
class Thread:
events: List[Event]
classEvent:
type: Literal["list_git_tags", "deploy_backend", "deploy_frontend",
"request_more_information", "done_for_now",
"list_git_tags_result", "deploy_backend_result",
"deploy_frontend_result", "request_more_information_result",
"done_for_now_result", "error"]
data: Union[ListGitTags, DeployBackend, DeployFrontend, RequestMoreInformation,
ListGitTagsResult, DeployBackendResult, DeployFrontendResult,
RequestMoreInformationResult, str]
defevent_to_prompt(event: Event) -> str:
data = event.data ifisinstance(event.data, str) \
else stringifyToYaml(event.data)
returnf"<{event.type}>\n{data}\n</{event.type}>"
defthread_to_prompt(thread: Thread) -> str:
return'\n\n'.join(event_to_prompt(event) for event in thread.events)不同階段的上下文窗口示例:
初始釘釘群請求:
<dingtalk_message>
From: @小張
Channel: #部署群
Text: 可以幫我部署最新的后端到生產環境嗎?
</dingtalk_message>錯誤處理和恢復后:
<slack_message>
From: @alex
Channel: #deployments
Text: Can you deploy the latest backend to production?
</slack_message>
<deploy_backend>
intent: "deploy_backend"
tag: "v1.2.3"
environment: "production"
</deploy_backend>
<e>
error running deploy_backend: Failed to connect to deployment service
</e>
<request_more_information>
intent: "request_more_information_from_human"
question: "I had trouble connecting to the deployment service, can you provide more details and/or check on the status of the service?"
</request_more_information>
<human_response>
data:
response: "I'm not sure what's going on, can you check on the status of the latest workflow?"
</human_response>關鍵好處包括:
- 信息密度:以最大化LLM理解的方式構建信息
- 錯誤處理:以幫助LLM恢復的格式包含錯誤信息
- 安全性:控制傳遞給LLM的信息,過濾敏感數據
- 靈活性:隨著您了解最佳實踐而調整格式
- Token效率:優化上下文格式以提高token效率和LLM理解
在任何時刻,你給代理 LLM 的輸入都是"這是目前為止發生的事情,下一步是什么?"
一切都關乎上下文工程。LLM 是無狀態函數,只負責將輸入轉化為輸出。要獲得最佳輸出,必須為其提供最優輸入。
營造良好上下文環境包括:
- 明確的提示和指令
- 檢索到的文檔或外部數據(如 RAG)
- 過往狀態、工具調用、結果或其他歷史
- 相關但獨立的歷史/對話信息(記憶)
- 輸出結構化數據類型的說明
理解筆記
構建 Agent 過程中,為了使 LLM 擁有更好的效果,從提示詞工程向情景工程轉換,利用工程方法和系統思維,提供 LLM 所需的:
- 當前情況:當前背景、當前進展;
- 目標任務:分解目標、最終目標;
- 已有工具、手段;
- 已有信息:歷史資料、過往記憶、過往案例;
上下文管理不僅僅是拼接歷史消息,更要有選擇性地組織和壓縮信息,確保 LLM 只接收到與當前任務最相關的內容。
建議建立上下文構建的標準流程和模板,便于團隊協作和復用。
4. 工具只是結構化的輸出

?工具調用被過度神秘化了,其實質就是LLM輸出的結構化JSON數據,您的代碼解析這些數據并執行相應操作。讓我們看一個具體的例子,假設您有兩個工具??CreateIssue???和??SearchIssues??,讓 LLM "在幾種工具中選擇一種"其實就是讓它輸出 JSON,我們可以將其解析為對應的對象。
class Issue:
title: str
description: str
team_id: str
assignee_id: str
classCreateIssue:
intent: "create_issue"
issue: Issue
classSearchIssues:
intent: "search_issues"
query: str
what_youre_looking_for: str模式很簡單:
- LLM 輸出結構化 JSON
- 確定性代碼執行相應操作(如調用外部 API)
- 捕獲結果并反饋到上下文
這樣就能清晰區分 LLM 的決策和應用操作。LLM 決定做什么,代碼決定如何執行。LLM 所謂"工具"并不意味著每次都要嚴格映射到某個函數。
理解這一本質后,你可以更靈活地設計工具接口:定義清晰數據結構、處理異常、優化性能,甚至支持非原子復雜操作。不要被"function calling"等術語迷惑,工具調用只是 LLM 決策與應用邏輯之間的橋梁,關鍵是保持決策層和執行層的清晰分離。
重要的是,"下一步"未必像"運行純函數并返回結果"那樣原子。當你把"工具調用"視為模型輸出、描述確定性代碼應做什么的 JSON 時,就獲得了極大靈活性。這與原則八(擁有控制流)完美結合。
理解筆記
構建 Agent 過程中,采用關注點分離方式,設計工具使用方式:
- LLM 進行決策,分析當前情景,決定下一步要干什么;
- 工具進行確定性執行;
- 工具調用的本質是 LLM 輸出結構化數據(如 JSON),由后端代碼解析并執行,LLM 不直接操作外部世界。
- 關注點分離有助于系統的可維護性和安全性,LLM 負責"決策",代碼負責"執行"。
5.統一執行狀態和業務狀態
傳統系統往往分離執行狀態(當前步驟、等待狀態、重試次數等)和業務狀態(用戶數據、處理歷史等),這種分離會增加系統復雜度并帶來一致性問題。在AI應用之外的許多基礎設施系統也試圖分離"執行狀態"和"業務狀態",這種分離可能是有價值的,但對您的用例來說可能過于復雜。

概念梳理:
- 執行狀態:當前步驟、下一步、等待狀態、重試次數等。
- 業務狀態:代理工作流程中到目前為止發生的事情(例如 OpenAI 消息列表、工具調用和結果列表等)
如果可能的話,簡化——盡可能統一這些狀態。實際上,您可以設計應用程序,使得所有執行狀態都可以從上下文窗口推斷出來。在許多情況下,執行狀態(當前步驟、等待狀態等)只是關于到目前為止發生了什么的元數據。
這種方法有幾個好處:
- 簡單:所有狀態的真相來源
- 序列化:線程可以輕松序列化/反序列化
- 調試:整個歷史記錄在一個地方可見
- 靈活性:只需添加新的事件類型即可輕松添加新狀態
- 恢復:只需加載線程即可從任何點恢復
- 分叉:可以通過將線程的某些子集復制到新的上下文/狀態 ID 中來隨時分叉線程
- 人機界面和可觀察性:將線程轉換為人類可讀的 Markdown 或豐富的 Web 應用程序 UI
理解筆記
構建 Agent 過程中,構建上下文過程中,將執行狀態和業務狀態進行統一,一定程度上想起來規則引擎和狀態機,構建規則,然后交給事件或者數據。
- 明確區分并統一 LLM 的"執行狀態"與應用的"業務狀態",避免信息不一致導致的誤判。
- 為每個狀態變更建立可追溯日志,提升系統可觀測性和可維護性。
6. 使用簡單的 API 啟動/暫停/恢復
LLM 代理應設計為擁有清晰、簡潔的編程接口,便于生命周期管理。這意味著應提供簡單的 API 來啟動新的代理實例、暫停執行,以及從特定狀態恢復。這對于調試、測試和管理長期運行或復雜代理流程至關重要,使開發者能夠隨時介入和檢查代理行為。

用戶、應用、管道或其他代理都應能便捷地通過 API 啟動代理。
當遇到長時間運行的操作時,代理及其協調的確定性代碼應能優雅地暫停。
像 webhook 這樣的外部觸發器應允許代理從中斷點恢復,無需與代理編排器深度集成。
核心要求:
- 簡單啟動:用戶、應用、管道和其他 Agent 應能通過簡單 API 啟動 Agent
- 優雅暫停:Agent 及其編排代碼應能在需要時暫停
- 外部恢復:如 webhook 等外部觸發器應能讓 Agent 從中斷點恢復,無需深度集成
這種設計對生產環境尤為重要,為 AI 系統提供必要的安全網和控制機制,使其能處理更高價值任務。最關鍵的能力是:我們需要能中斷正在工作的 Agent 并稍后恢復,尤其是在工具選擇和調用之間。
理解筆記
構建 Agent 過程中,采用簡單原則,觸發后尋找上下文,開始執行后通過狀態 ID 進行跟進。
- 設計簡單、清晰的 API,支持 Agent 的啟動、暫停和恢復,便于生命周期管理。
- 為每個 Agent 實例分配唯一狀態 ID,方便追蹤和恢復。
- 為長流程任務設計中斷點和恢復機制,提升系統健壯性和用戶體驗。
7. 使用工具呼叫聯系人類
雖然 LLM 功能強大,但總有需要人類判斷、專業知識或干預的場景。本原則主張通過工具調用,將"人機交互"明確納入代理功能。當 LLM 遇到模糊、不確定或需外部批準的情況時,應能觸發結構化通知或上報給人類操作員,確保關鍵決策在需要時獲得人工監督。

默認情況下,LLM API 依賴于關鍵的"高風險"令牌選擇:我們是返回純文本,還是結構化數據?
你對第一個標記的選擇非常重視,在這種 ??the weather in tokyo?? 情況下,它是:
這
但在 ??fetch_weather?? 情況下,它是一些特殊標記,表示 JSON 對象的開始:
JSON>
讓 LLM 始終輸出 json,并用自然語言標記(如 ??request_human_input??? 或 ??done_for_now???,而不是像 ??check_weather_in_city?? 這樣的具體工具)聲明意圖,往往能獲得更好效果。
不會直接提升性能,但你應大膽實驗,確保有自由嘗試各種方式以獲得最佳結果。
class Options:
urgency: Literal["low", "medium", "high"]
format: Literal["free_text", "yes_no", "multiple_choice"]
choices: List[str]
# 人機交互工具定義
classRequestHumanInput:
intent: "request_human_input"
question: str
context: str
options: Options
# 代理循環中的用法示例
ifnextStep.intent == 'request_human_input':
thread.events.append({
type: 'human_input_requested',
data: nextStep
})
thread_id = await save_state(thread)
await notify_human(nextStep, thread_id)
return
# 跳出循環,等待帶 thread ID 的響應返回
else:
# ... 其他情況稍后,你可能會從處理 slack、郵件、短信等事件的系統收到 webhook:
@app.post('/webhook')
def webhook(req: Request):
thread_id = req.body.threadId
thread = await load_state(thread_id)
thread.events.push({
type: 'response_from_human',
data: req.body
})
# ... 簡化處理,實際不建議阻塞 web worker
next_step = await determine_next_step(thread_to_prompt(thread))
thread.events.append(next_step)
result = await handle_next_step(thread, next_step)
# todo - 循環、跳出或其他自定義邏輯
return {"status": "ok"}以上包括因素 5(統一執行狀態和業務狀態)、因素 8(擁有自己的控制流)、因素 3(擁有自己的上下文窗口)和因素 4(工具只是結構化輸出)的模式,以及其他幾個。
如果我們使用因素 3 - 用自定義格式化的上下文窗口,幾輪后上下文可能如下:
(snipped for brevity)
<slack_message>
From: @alex
Channel: #deployments
Text: Can you deploy backend v1.2.3 to production?
Thread: []
</slack_message>
<request_human_input>
intent: "request_human_input"
question: "Would you like to proceed with deploying v1.2.3 to production?"
context: "This is a production deployment that will affect live users."
options: {
urgency: "high"
format: "yes_no"
}
</request_human_input>
<human_response>
response: "yes please proceed"
approved: true
timestamp: "2024-03-15T10:30:00Z"
user: "alex@company.com"
</human_response>
<deploy_backend>
intent: "deploy_backend"
tag: "v1.2.3"
environment: "production"
</deploy_backend>
<deploy_backend_result>
status: "success"
message: "Deployment v1.2.3 to production completed successfully."
timestamp: "2024-03-15T10:30:00Z"
</deploy_backend_result>這樣做的好處:
- 明確指示:針對不同類型人機交互的工具讓 LLM 輸出更具體
- 內外循環:支持在傳統 ChatGPT 風格界面之外的代理流程,控制流和上下文初始化不必總是 Agent->Human
- 多人協作:結構化事件便于跟蹤和協調多方輸入
- 多代理:簡單抽象可擴展為 Agent->Agent 請求與響應
- 持久性:結合簡單 API 啟動/暫停/恢復,打造持久、可靠、可自省的多方工作流

理解筆記
構建 Agent 過程中,將"人機交互"標簽,明確地加入到代理的功能。
- 明確將"請求人工輸入"作為一種標準工具調用,便于 LLM 在不確定或高風險場景下主動尋求人類協助。
- 為人機交互設計結構化事件和回調機制,支持多渠道通知和響應。
- 為人工干預流程建立審計和追蹤,提升系統安全性和合規性。
8. 擁有自己的控制流
盡管 LLM 具備"推理"能力,但應用的整體控制流應由確定性代碼明確管理。LLM 只應引導控制流的路徑,而不應成為控制流本身。這樣才能保證可預測性、強健的錯誤處理,并讓開發者為 LLM 的自主性設定清晰邊界,防止意外或不良行為。

如果你擁有自己的控制流,就能做很多有趣的事情。
可以為特定用例構建專屬控制結構。例如,某些工具調用可能需要跳出循環,等待人工或其他長時間任務(如訓練管道)響應。你還可以實現:
- 工具調用結果的匯總或緩存
- LLM 結構化輸出
- 上下文窗口壓縮或其他內存管理
- 日志、追蹤和指標
- 客戶端速率限制
- 持久睡眠/暫停/“等待事件”
這種模式允許你根據需要中斷和恢復代理流程,打造更自然的對話和工作流。
例如:我對每個 AI 框架的首要訴求是,必須能在"選擇工具"與"調用工具"之間中斷代理并稍后恢復。
如果沒有這種粒度的可恢復性,就無法在工具調用前進行人工審核或批準,這會導致:
- 長任務只能暫停在內存中,進程中斷就得重頭再來
- 只能讓代理處理低風險任務,如研究和總結
- 讓代理做更大更有用的事,但只能祈禱它不會出錯
理解筆記
構建 Agent 過程中,使用上下文或者 code 控制流程,LLM 引導控制流的路徑,而不是成為控制流本身。
- 控制流應由確定性代碼主導,LLM 只負責決策建議,避免"黑盒"自動化帶來的不可控風險。
- 為關鍵節點(如工具調用前)設計人工審核或中斷機制,提升安全性。
- 將控制流邏輯與 LLM 推理解耦,便于測試和維護。
9. 將錯誤壓縮到上下文窗口中
當 LLM 驅動的應用發生錯誤時,應向 LLM 提供簡明、相關的故障信息。本原則建議將錯誤詳情以結構化方式壓縮進上下文窗口,讓 LLM 更好地理解問題,并可能建議恢復策略或替代方案。這樣可避免直接傳遞冗長原始日志,防止模型困惑。

這一點雖短,但很重要。代理的優勢之一是"自我修復"——對于短任務,LLM 可能會調用失敗的工具。優秀的 LLM 能很好地讀取錯誤消息或堆棧跟蹤,并判斷后續工具調用需要如何調整。
class ErrorHandler:
def__init__(self):
self.error_counts = defaultdict(int)
self.max_retries = 3
def handle_error(self, error: Exception, context: str) -> str:
error_type = type(error).__name__
self.error_counts[error_type] += 1
if self.error_counts[error_type] > self.max_retries:
returnf"<critical_error>Too many {error_type} errors. Human intervention required.</critical_error>"
# 壓縮錯誤信息
compressed_error = self.compress_error(error, context)
returnf"<e>{compressed_error}</e>"
def compress_error(self, error: Exception, context: str) -> str:
# 提取關鍵信息,過濾掉冗余的堆棧跟蹤
if isinstance(error, ConnectionError):
returnf"Connection failed to {context}: {str(error)[:100]}"
elif isinstance(error, ValidationError):
return f"Validation error in {context}: {error.args[0] if error.args else 'Unknown validation issue'}"
else:
return f"{type(error).__name__} in {context}: {str(error)[:100]}"上下文窗口中的錯誤表示:
<deploy_backend>
intent: "deploy_backend"
tag: "v1.2.3"
environment: "production"
</deploy_backend>
<e>部署服務連接失敗: 無法連接到 https://deploy.company.com</e>
<request_more_information>
intent: "request_more_information_from_human"
question: "部署服務似乎不可用,我應該嘗試其他方案還是等待?"
context: "由于連接問題,v1.2.3部署失敗。"
</request_more_information>在有限的上下文窗口中表示錯誤信息是一門藝術:既要保留足夠的診斷信息讓AI理解問題所在,又不能占用過多寶貴的上下文空間。您需要實現智能的錯誤分類、壓縮和優先級排序機制,甚至可以在錯誤解決后將其從上下文中移除以節省空間。同時,建立錯誤計數器和閾值機制防止AI陷入重復錯誤的循環,當達到閾值時及時升級給人類處理。
** 錯誤恢復策略:**
def smart_error_recovery(thread: Thread, error: Exception):
if isinstance(error, RateLimitError):
# 對于速率限制,等待并重試
thread.events.append({
'type': 'rate_limit_hit',
'data': {'wait_time': error.retry_after}
})
return'wait_and_retry'
elif isinstance(error, AuthenticationError):
# 對于認證錯誤,請求人類干預
thread.events.append({
'type': 'auth_error',
'data': {'service': error.service}
})
return'request_human_help'
else:
# 對于其他錯誤,讓LLM決定下一步
compressed_error = compress_error(error)
thread.events.append({
'type': 'error',
'data': compressed_error
})
return 'let_llm_decide'理解筆記
構建 Agent 過程中,智能錯誤處理機制是構建可靠AI系統的關鍵組成部分。
- 錯誤信息應結構化、簡明地反饋給 LLM,避免冗長日志導致模型困惑。
- 為常見錯誤類型設計標準化摘要模板,便于 LLM 理解和自我修復。
- 記錄每次錯誤及其處理過程,持續優化錯誤處理策略。
10.小型、專注的 Agent
本原則主張將復雜 LLM 應用拆分為更小、更專業的代理,每個代理專注于不同任務或領域。模塊化方法能減輕單個 LLM 的認知負擔,通過縮小關注范圍提升準確性,也讓系統更易開發、測試和維護。小型代理也更易于微調和優化。

與其構建包攬一切的單體代理,不如構建小型、專注、專業的代理。代理只是更大、更確定性系統的一個構件。
關鍵洞察在于 LLM 的局限性:任務越大越復雜,步驟越多,上下文窗口越長,LLM 越容易迷失或分心。讓代理專注于特定領域,并將流程控制在 3-10 步、最多 20 步內,有助于保持上下文可控,提升 LLM 性能。
隨著上下文擴大,LLM 更容易迷失或分心
小型、專注代理的優勢:
- 可控上下文:窗口越小,性能越好
- 職責明確:每個代理有清晰范圍和目標
- 更高可靠性:減少復雜流程中迷失的風險
- 易于測試:便于驗證特定功能
- 調試友好:更易定位和修復問題
理解筆記
構建 Agent 過程中,設計專注于特定領域的小型 Agent。
- 將復雜任務拆分為多個小型、專注的 Agent,每個 Agent 只負責單一領域或流程。
- 為每個 Agent 明確職責邊界,便于獨立開發、測試和優化。
- 通過組合多個 Agent 實現復雜業務,提升系統靈活性和可維護性。
11. 隨時隨地觸發,隨時隨地與用戶見面
可靠的 LLM 應用應能從多種入口和界面訪問和觸發。無論網頁聊天、API、移動端還是內部儀表盤,代理都應能無縫接收輸入并響應。這種靈活性確保代理能集成進現有流程,并在用戶偏好的平臺上互動,提升可用性和采納率。

允許用戶通過 Slack、郵件、短信等任意渠道觸發客服,客服也可通過同樣渠道響應。
這樣做的好處:
- 在用戶所在的地方與其見面:有助于打造"像真人或數字同事"的 AI 應用
- 外環代理:支持代理被事件、定時任務等非人類觸發,關鍵節點可尋求人類協助
- 高風險工具:快速整合多方人員,讓代理能安全執行高風險操作(如發外部郵件、更新生產數據),提升可審計性和信心
理解筆記
構建 Agent 過程中,使用多渠道接入用戶,似乎對國內的封閉系統存在一定的沖擊。
- 支持多種入口和渠道(如 Web、API、IM、定時任務等)觸發和交互,提升系統可用性。
- 為每個渠道設計統一的接入和認證機制,確保安全和一致體驗。
- 關注國內外不同生態的集成方式,提升系統兼容性。
12. 讓你的 Agent 成為無狀態 Reducer
本原則鼓勵將 LLM 代理設計為無狀態處理器,每次只依賴輸入和外部狀態生成輸出,無需在交互間維護內部長期記憶。所有持久狀態應交由外部存儲(如數據庫、消息隊列)管理。這種模式提升了可擴展性、彈性和水平擴展能力,任何代理實例都能處理任意請求,單實例故障也不會丟失數據。

理解筆記
構建 Agent 過程中,采用無狀態的純函數的轉換器方式,更能滿足擴展、測試等需求。
- Agent 應設計為無狀態的"Reducer",每次只依賴輸入和外部狀態,輸出結果。
- 將所有持久化狀態交由外部存儲系統管理,提升系統彈性和可擴展性。
- 無狀態設計有助于水平擴展和故障恢復,是生產級 Agent 的基礎。
這些原則如何落地
電商平臺的智能客服
假設您在構建一個電商平臺的智能客服系統。按照12-Factor原則,您不會直接使用某個Agent框架,而是:首先設計清晰的工具調用接口(查詢訂單、處理退款等),然后精心設計提示詞來處理常見的客服場景,接下來實現狀態管理來跟蹤每個對話的進展,最后設計簡單的API來讓人工客服能夠隨時介入。這樣構建的系統不僅更可靠,也更容易維護和擴展。
內容創作助手的設計思路
如果您在開發內容創作助手,可以這樣應用這些原則:將不同的創作任務(標題生成、大綱規劃、段落寫作)設計為獨立的小Agent,每個Agent專注于自己的領域。用戶可以從任何平臺(Web、移動App、瀏覽器插件)觸發這些Agent,系統會根據用戶的創作進度智能地組織上下文信息。這種設計既提高了創作效率,又保持了用戶的創作控制權。
參考資料
[1] 12-Factor Agents: ???https://github.com/humanlayer/12-factor-agents??
本文轉載自??AI 博物院?? 作者:longyunfeigu

















