客服工單處理是企業運營中的關鍵環節:需要快速分類、智能路由、實時回應和全程追蹤。傳統方案依賴人工,效率低、成本高。而 LangGraph 作為新一代 Agent 編排框架,使得我們可以構建可預測、可追蹤、可控制的 AI 客服系統。本文詳細介紹如何用 LangGraph 打造生產級的智能工單系統。
系統架構設計
整體架構
用戶提交工單
↓
[工單接收服務]
↓
[LangGraph 工作流引擎]
├→ [分類 Agent] - 識別工單類型(技術問題、賬戶、計費等)
├→ [優先級 Agent] - 評估緊急程度
├→ [路由 Agent] - 決定分配給哪個部門
├→ [回應 Agent] - 生成初始回覆
└→ [品質檢查 Agent] - 驗證回應品質
↓
[存儲和通知]
工單生命週期
工單狀態流:
┌─────────────┐
│ 新建 │ (open)
└──────┬──────┘
│
▼
┌─────────────┐
│ 分類中 │ (classifying)
└──────┬──────┘
│
▼
┌─────────────┐
│ 等待分配 │ (assigned)
└──────┬──────┘
│
▼
┌─────────────┐
│ 処理中 │ (in_progress)
└──────┬──────┘
│
├→ ┌─────────────┐
│ │ 已解決 │ (resolved)
│ └─────────────┘
│
└→ ┌─────────────┐
│ 已關閉 │ (closed)
└─────────────┘
全程可追蹤
LangGraph 核心實現
1. 定義狀態(State)
1from typing import Annotated, Literal
2from dataclasses import dataclass, field
3from datetime import datetime
4
5@dataclass
6class TicketState:
7 """工單狀態模型"""
8 # 基本信息
9 ticket_id: str
10 user_id: str
11 created_at: datetime
12 subject: str
13 description: str
14
15 # 分類結果
16 category: Literal[
17 "technical", "billing", "account",
18 "feature_request", "bug_report", "other"
19 ] = None
20 category_confidence: float = 0.0
21
22 # 優先級
23 priority: Literal["low", "medium", "high", "critical"] = "medium"
24 urgency_score: float = 0.0
25
26 # 路由信息
27 assigned_department: str = None
28 assigned_agent_id: str = None
29
30 # 對話歷史
31 messages: list[dict] = field(default_factory=list)
32
33 # 回應信息
34 response: str = None
35 response_quality_score: float = 0.0
36
37 # 狀態追蹤
38 status: str = "open"
39 current_node: str = None
40 processing_history: list[dict] = field(default_factory=list)
41
42 # 錯誤處理
43 errors: list[str] = field(default_factory=list)
44 retry_count: int = 0
45 max_retries: int = 3
2. 定義 Agent 節點
1from langchain_anthropic import ChatAnthropic
2from langchain_core.prompts import ChatPromptTemplate
3from langgraph.graph import StateGraph, END
4import json
5import os
6
7class TicketAgents:
8 def __init__(self):
9 # 模型 ID 從環境變數讀取:請填目前可用的 Claude 模型 ID(見 Anthropic 模型文件),
10 # 不要寫死已退役的 claude-3-5-sonnet-20241022。
11 self.model = ChatAnthropic(model=os.environ["LLM_MODEL"])
12
13 # Agent 1: 分類 Agent
14 def classify_agent(self, state: TicketState) -> TicketState:
15 """識別工單類型和關鍵信息"""
16
17 prompt = ChatPromptTemplate.from_template("""
18 分析以下客服工單,提取關鍵信息和分類。
19
20 工單主題:{subject}
21 工單描述:{description}
22
23 請以 JSON 格式返回:
24 {{
25 "category": "technical|billing|account|feature_request|bug_report|other",
26 "confidence": 0.0-1.0,
27 "key_issues": ["issue1", "issue2"],
28 "urgency_signals": ["signal1", "signal2"],
29 "extraction": {{
30 "affected_product": "...",
31 "error_message": "...",
32 "account_related": true/false,
33 "payment_related": true/false
34 }}
35 }}
36 """)
37
38 chain = prompt | self.model
39 response = chain.invoke({
40 "subject": state.subject,
41 "description": state.description
42 })
43
44 # 解析回應
45 result = json.loads(response.content)
46 state.category = result["category"]
47 state.category_confidence = result["confidence"]
48 state.current_node = "classify"
49
50 # 記錄処理歷史
51 state.processing_history.append({
52 "timestamp": datetime.now().isoformat(),
53 "node": "classify",
54 "result": result
55 })
56
57 return state
58
59 # Agent 2: 優先級評估 Agent
60 def priority_agent(self, state: TicketState) -> TicketState:
61 """評估工單的優先級"""
62
63 prompt = ChatPromptTemplate.from_template("""
64 基於以下信息評估工單的優先級:
65
66 類別:{category}
67 主題:{subject}
68 描述:{description}
69
70 評估因素:
71 1. 系統中斷?(critical)
72 2. 用戶無法訪問?(high)
73 3. 功能受限?(medium)
74 4. 功能請求/建議?(low)
75
76 返回 JSON:
77 {{
78 "priority": "low|medium|high|critical",
79 "urgency_score": 0.0-1.0,
80 "reasoning": "...",
81 "sla_hours": 24|12|4|1
82 }}
83 """)
84
85 chain = prompt | self.model
86 response = chain.invoke({
87 "category": state.category,
88 "subject": state.subject,
89 "description": state.description
90 })
91
92 result = json.loads(response.content)
93 state.priority = result["priority"]
94 state.urgency_score = result["urgency_score"]
95 state.current_node = "priority"
96
97 state.processing_history.append({
98 "timestamp": datetime.now().isoformat(),
99 "node": "priority",
100 "result": result
101 })
102
103 return state
104
105 # Agent 3: 路由 Agent
106 def routing_agent(self, state: TicketState) -> TicketState:
107 """決定工單應該分配給哪個部門"""
108
109 # 部門配置
110 departments = {
111 "technical": {
112 "name": "技術支持部",
113 "skills": ["api", "integration", "performance"],
114 "avg_response_time": 2,
115 "available_agents": 5
116 },
117 "billing": {
118 "name": "計費部",
119 "skills": ["invoicing", "payment", "refund"],
120 "avg_response_time": 4,
121 "available_agents": 3
122 },
123 "account": {
124 "name": "賬戶管理部",
125 "skills": ["login", "profile", "security"],
126 "avg_response_time": 1,
127 "available_agents": 4
128 }
129 }
130
131 prompt = ChatPromptTemplate.from_template("""
132 根據工單的類別和優先級,決定分配給哪個部門。
133
134 類別:{category}
135 優先級:{priority}
136 部門信息:{departments_info}
137
138 返回 JSON:
139 {{
140 "assigned_department": "technical|billing|account",
141 "reasoning": "...",
142 "estimated_wait_time": "X minutes",
143 "fallback_department": "..."
144 }}
145 """)
146
147 chain = prompt | self.model
148 response = chain.invoke({
149 "category": state.category,
150 "priority": state.priority,
151 "departments_info": json.dumps(departments, ensure_ascii=False)
152 })
153
154 result = json.loads(response.content)
155 state.assigned_department = result["assigned_department"]
156 state.current_node = "routing"
157
158 state.processing_history.append({
159 "timestamp": datetime.now().isoformat(),
160 "node": "routing",
161 "result": result
162 })
163
164 return state
165
166 # Agent 4: 回應生成 Agent
167 def response_agent(self, state: TicketState) -> TicketState:
168 """根據工單類型生成初始回覆"""
169
170 prompt = ChatPromptTemplate.from_template("""
171 根據工單信息生成專業的初始回覆。回覆應該:
172 1. 感謝用戶報告問題
173 2. 確認已收到工單
174 3. 解釋接下來的步驟
175 4. 如果可能,提供初步解決方案
176
177 類別:{category}
178 優先級:{priority}
179 主題:{subject}
180 描述:{description}
181 部門:{department}
182
183 生成專業、友好的客服回覆(中文,150-300 字):
184 """)
185
186 chain = prompt | self.model
187 response = chain.invoke({
188 "category": state.category,
189 "priority": state.priority,
190 "subject": state.subject,
191 "description": state.description,
192 "department": state.assigned_department
193 })
194
195 state.response = response.content
196 state.current_node = "response_generation"
197
198 state.processing_history.append({
199 "timestamp": datetime.now().isoformat(),
200 "node": "response_generation",
201 "response": state.response
202 })
203
204 return state
205
206 # Agent 5: 品質檢查 Agent
207 def quality_check_agent(self, state: TicketState) -> TicketState:
208 """驗證回應品質"""
209
210 prompt = ChatPromptTemplate.from_template("""
211 評估以下客服回覆的品質:
212
213 工單:{subject}
214 回覆:{response}
215
216 評估維度:
217 1. 專業性 (0-1)
218 2. 清晰性 (0-1)
219 3. 完整性 (0-1)
220 4. 友好性 (0-1)
221 5. 相關性 (0-1)
222
223 返回 JSON:
224 {{
225 "overall_score": 0.0-1.0,
226 "scores": {{
227 "professionalism": 0.0-1.0,
228 "clarity": 0.0-1.0,
229 "completeness": 0.0-1.0,
230 "friendliness": 0.0-1.0,
231 "relevance": 0.0-1.0
232 }},
233 "issues": ["issue1", "issue2"],
234 "recommendations": ["fix1", "fix2"],
235 "approved": true/false
236 }}
237 """)
238
239 chain = prompt | self.model
240 response = chain.invoke({
241 "subject": state.subject,
242 "response": state.response
243 })
244
245 result = json.loads(response.content)
246 state.response_quality_score = result["overall_score"]
247 state.current_node = "quality_check"
248
249 # 如果品質不符合要求,生成改進建議
250 if not result["approved"]:
251 state.errors.append(f"品質檢查未通過:{result['issues']}")
252 return state
253
254 state.processing_history.append({
255 "timestamp": datetime.now().isoformat(),
256 "node": "quality_check",
257 "score": state.response_quality_score,
258 "approved": True
259 })
260
261 return state
3. 構建 LangGraph
1from langgraph.graph import StateGraph, START, END
2
3def build_ticket_workflow():
4 """構建工單處理工作流"""
5
6 workflow = StateGraph(TicketState)
7 agents = TicketAgents()
8
9 # 添加節點
10 workflow.add_node("classify", agents.classify_agent)
11 workflow.add_node("priority", agents.priority_agent)
12 workflow.add_node("routing", agents.routing_agent)
13 workflow.add_node("response_generation", agents.response_agent)
14 workflow.add_node("quality_check", agents.quality_check_agent)
15
16 # 添加邊(節點間的轉移)
17 workflow.add_edge(START, "classify")
18 workflow.add_edge("classify", "priority")
19 workflow.add_edge("priority", "routing")
20 workflow.add_edge("routing", "response_generation")
21 workflow.add_edge("response_generation", "quality_check")
22
23 # 品質檢查的條件轉移
24 def check_quality(state: TicketState):
25 if state.response_quality_score >= 0.8:
26 return "end"
27 else:
28 return "response_generation" # 重新生成
29
30 workflow.add_conditional_edges(
31 "quality_check",
32 check_quality,
33 {
34 "end": END,
35 "response_generation": "response_generation"
36 }
37 )
38
39 return workflow.compile()
運行工作流
執行工單處理
1# 初始化工作流
2ticket_processor = build_ticket_workflow()
3
4# 創建新工單
5new_ticket = TicketState(
6 ticket_id="TKT-2024-001",
7 user_id="user_123",
8 created_at=datetime.now(),
9 subject="API 認證失敗導致集成中斷",
10 description="""
11 我們的應用無法連接到您的 API。
12 錯誤信息:401 Unauthorized
13 這發生在上午 10:00 UTC,影響了所有用戶。
14 """
15)
16
17# 執行工作流
18print("開始處理工單...")
19result = ticket_processor.invoke(new_ticket)
20
21# 查看結果
22print(f"工單 ID: {result.ticket_id}")
23print(f"分類: {result.category} (置信度: {result.category_confidence:.2%})")
24print(f"優先級: {result.priority}")
25print(f"分配部門: {result.assigned_department}")
26print(f"回應品質分數: {result.response_quality_score:.2f}")
27print(f"生成的回覆:\n{result.response}")
28print(f"\n処理歷史:")
29for entry in result.processing_history:
30 print(f" - {entry['node']}: {entry['timestamp']}")
高級特性
1. 上下文感知的多輪對話
1def conversation_agent(self, state: TicketState) -> TicketState:
2 """支持多輪對話的 Agent"""
3
4 # 構建對話歷史
5 history = "\n".join([
6 f"{msg['role']}: {msg['content']}"
7 for msg in state.messages[-5:] # 最近 5 條消息
8 ])
9
10 prompt = ChatPromptTemplate.from_template("""
11 你是一個客服代理。基於以下工單歷史和對話,提供幫助。
12
13 工單背景:
14 - 類別:{category}
15 - 優先級:{priority}
16
17 對話歷史:
18 {history}
19
20 用戶最新消息:{user_message}
21
22 生成有幫助的回覆:
23 """)
24
25 chain = prompt | self.model
26 response = chain.invoke({
27 "category": state.category,
28 "priority": state.priority,
29 "history": history,
30 "user_message": state.messages[-1]["content"]
31 })
32
33 # 添加到消息歷史
34 state.messages.append({
35 "role": "assistant",
36 "content": response.content,
37 "timestamp": datetime.now().isoformat()
38 })
39
40 return state
2. 錯誤恢復和重試
1def add_error_handling(workflow):
2 """為工作流添加錯誤處理機制"""
3
4 def handle_error(state: TicketState, error: Exception):
5 state.errors.append(str(error))
6 state.retry_count += 1
7
8 if state.retry_count >= state.max_retries:
9 state.status = "escalated"
10 # 升級給人工客服
11 return "escalate_to_human"
12 else:
13 # 重試
14 return f"retry_{state.current_node}"
15
16 return workflow
3. 實時監控和告警
1def monitor_workflow(state: TicketState):
2 """實時監控工作流狀態"""
3
4 metrics = {
5 "ticket_id": state.ticket_id,
6 "status": state.status,
7 "processing_time": calculate_processing_time(state),
8 "quality_score": state.response_quality_score,
9 "retry_count": state.retry_count,
10 "error_count": len(state.errors)
11 }
12
13 # 發送到監控系統
14 send_to_monitoring_system(metrics)
15
16 # 告警規則
17 if state.retry_count >= 2:
18 alert(f"工單 {state.ticket_id} 重試次數過多")
19
20 if state.response_quality_score < 0.7:
21 alert(f"工單 {state.ticket_id} 回應品質低")
生產部署
Docker 容器化
1FROM python:3.11-slim
2
3WORKDIR /app
4
5COPY requirements.txt .
6RUN pip install -r requirements.txt
7
8COPY . .
9
10EXPOSE 8000
11
12CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
FastAPI 服務包裝
1from fastapi import FastAPI, BackgroundTasks
2from pydantic import BaseModel
3
4app = FastAPI()
5ticket_processor = build_ticket_workflow()
6
7class TicketRequest(BaseModel):
8 user_id: str
9 subject: str
10 description: str
11
12@app.post("/tickets")
13async def create_ticket(request: TicketRequest, background_tasks: BackgroundTasks):
14 """創建新工單"""
15
16 ticket = TicketState(
17 ticket_id=generate_ticket_id(),
18 user_id=request.user_id,
19 created_at=datetime.now(),
20 subject=request.subject,
21 description=request.description
22 )
23
24 # 後台處理工單
25 background_tasks.add_task(process_ticket, ticket)
26
27 return {"ticket_id": ticket.ticket_id, "status": "accepted"}
28
29async def process_ticket(ticket: TicketState):
30 """處理工單"""
31 result = ticket_processor.invoke(ticket)
32 save_to_database(result)
33 notify_user(result)
性能指標
下表是設計目標,不是量測結果;上線後請以實際監控數據(見上方監控章節)回填。
| 指標 | 目標值 | 實現方式 |
|---|---|---|
| 平均響應時間 | <5 秒 | 並行處理,快速模型 |
| 工單分類準確率 | >95% | 微調模型,人工審查 |
| 首次解決率 | >70% | 知識庫集成,持續優化 |
| 品質滿意度 | >4.5/5 | 品質檢查 Agent,人工評審 |
| 成本 / 工單 | <$0.1 | 批量處理,快速模型 |
總結
使用 LangGraph 構建 AI 客服系統的優勢:
- 可預測性:每個步驟可追蹤,結果可解釋
- 可控性:清晰的工作流,易於調試和修改
- 可擴展性:輕鬆添加新的 Agent 或修改邏輯
- 成本效益:自動化 70-80% 的工單,大幅降低成本
- 用戶體驗:快速回應,減少等待時間
LangGraph 讓 AI 驅動的客服系統成為可能,同時保持人類的監督和控制。
