目錄
AI Agent 的開發和普通 LLM API 呼叫有本質的差別:普通呼叫是無狀態的單次請求,而 Agent 需要維護跨步驟的狀態、根據工具回傳的結果做決策、並且處理中途失敗的情況。LangGraph 把這個複雜性包裝成有向圖(directed graph),讓開發者用聲明式的方式定義 Agent 的工作流程。
這篇文章是「AI 程式開發實戰」系列的第三課,目標是建構一個影片製作 AI Agent:輸入一個主題,Agent 自動完成主題研究、腳本撰寫、分鏡描述等步驟,輸出完整的影片製作素材。
TL;DR
用 LangGraph 建構影片製作 Agent 的核心是:(1) 定義清楚的 State 結構,(2) 把每個任務寫成獨立的節點函數,(3) 用條件邊處理失敗重試和分支邏輯。不要用 OpenCV + TensorFlow 去「訓練」Agent,那是錯誤的抽象——影片製作 Agent 的核心是 LLM 推理和工具呼叫,不是傳統的機器學習訓練。
前置條件
pip install langgraph langchain-openai langchain-community
需要:
- OpenAI API key(或任何相容的 LLM API)
- Python 3.10+
- 基本的 Python async/await 理解
Agent 的整體設計
影片製作流程可以拆解成幾個明確的步驟,每個步驟有清楚的輸入和輸出:
graph LR
A[用戶輸入主題] --> B[主題研究]
B --> C{研究夠充分?}
C -->|否| B
C -->|是| D[撰寫腳本大綱]
D --> E[展開各段腳本]
E --> F[生成分鏡描述]
F --> G[輸出完整素材包]
步驟一:定義 State
LangGraph 的核心是 State——一個貫穿整個工作流程的資料結構:
from typing import TypedDict, List, Optional
from langgraph.graph import StateGraph, END
class VideoProductionState(TypedDict):
topic: str
research_notes: Optional[str]
outline: Optional[List[str]]
script_sections: Optional[List[str]]
storyboard: Optional[List[str]]
error: Optional[str]
retry_count: int
每個節點接收這個 state,修改它,然後回傳更新後的版本。這讓狀態的流向完全可追蹤。
步驟二:實作各節點
每個節點是一個接收 state 回傳 state 的函數:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
def research_node(state: VideoProductionState) -> VideoProductionState:
topic = state["topic"]
response = llm.invoke([
{"role": "system", "content": "你是一個專業的影片內容研究員。"},
{"role": "user", "content": f"請針對「{topic}」進行深入研究,提供5個關鍵論點和相關事實。"}
])
return {**state, "research_notes": response.content, "retry_count": 0}
def outline_node(state: VideoProductionState) -> VideoProductionState:
notes = state["research_notes"]
response = llm.invoke([
{"role": "system", "content": "你是一個影片腳本策劃師。"},
{"role": "user", "content": f"根據以下研究筆記,規劃一個5分鐘影片的大綱:
{notes}"}
])
# 簡單解析:把每行當成一個大綱項目
outline = [line.strip() for line in response.content.split('
') if line.strip()]
return {**state, "outline": outline}
步驟三:加入條件邊
條件邊讓 graph 可以根據節點的執行結果選擇不同的下一步:
def should_retry_research(state: VideoProductionState) -> str:
notes = state.get("research_notes", "")
retry_count = state.get("retry_count", 0)
# 如果研究筆記太短,且還沒重試超過 2 次,就重試
if len(notes) < 200 and retry_count < 2:
return "retry"
return "continue"
# 建構 graph
builder = StateGraph(VideoProductionState)
builder.add_node("research", research_node)
builder.add_node("outline", outline_node)
# ... 其他節點
builder.set_entry_point("research")
builder.add_conditional_edges(
"research",
should_retry_research,
{
"retry": "research", # 回到自己
"continue": "outline" # 繼續下一步
}
)
步驟四:組裝和執行
graph = builder.compile()
# 執行
initial_state = VideoProductionState(
topic="量子計算的未來",
research_notes=None,
outline=None,
script_sections=None,
storyboard=None,
error=None,
retry_count=0
)
result = graph.invoke(initial_state)
print(result["script_sections"])
常見問題
Q:為什麼不直接用 LangChain 的 AgentExecutor?
AgentExecutor 適合工具呼叫型 Agent(ReAct 模式),但對於有明確步驟順序的工作流程,LangGraph 的可見性更好——你能清楚看到 Agent 走到哪一步、每步的輸入輸出是什麼。
Q:如何處理 LLM 呼叫失敗?
在節點函數裡包 try/except,失敗時把錯誤記錄到 state 的 error 欄位,然後用條件邊決定要重試還是終止:
def research_node(state: VideoProductionState) -> VideoProductionState:
try:
# ... 正常邏輯
return {**state, "research_notes": response.content}
except Exception as e:
return {**state, "error": str(e)}
Q:如何讓 Agent 使用外部工具(如網路搜索)?
用 LangChain 的 tool decorator 定義工具,然後在節點裡直接呼叫,或者使用 ToolNode 把工具包裝成 graph 節點。
參考資料
相關標籤
相關文章
OpenClaw × Playwright CLI:三段式 AI 瀏覽器自動化,執行階段 0 Token
用 OpenClaw 的 Playwright CLI + Skill 三段式流程,讓 AI 學一次瀏覽器操作,之後每次執行零 Token 消耗,比 Playwright MCP 節省約 4 倍 Token。
AI Agent 的工作原理是什麼,Harness Engineering 又是什麼?
AI Agent 是讓模型能持續感知環境、使用工具、自主完成任務的系統;Harness Engineering 則是讓 Agent 可靠運作的工程學科——設計環境、限制、回饋迴圈,讓 AI 從「聰明但不穩定」變成「可部署的工程系統」。
AI 如何重塑人的思考方式:工具之外的認知轉變
AI 工具改變的不只是你做事的速度,而是你思考問題的方式——從「怎麼做」轉向「做什麼」和「判斷對不對」,這個轉變對工程師的長期影響值得認真思考。