AI Agent 这个词 2026 年听了太多遍,但真正动手写过一个的人并不多。这篇文章不讲概念,带你用 LangChain + Claude 从零搭一个能用的智能客服 Agent——能查订单状态、处理退换货申请、遇到解决不了的问题自动转人工。

完整代码约 200 行,Python 环境即可运行。

准备环境:API Key 与依赖安装

开始前需要两个东西:Claude API Key 和 Python 3.10+。

1
pip install langchain langchain-anthropic python-dotenv

在项目根目录创建 .env 文件:

1
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxx

如果你是第一次接触 Claude API,可以参考之前写的 Ollama 本地部署指南,里面讲了 API Key 获取和本地模型的成本对比,本地模型也能跑 Agent,但 Claude 在工具调用能力上目前最强。

设计 Agent 的工具集

Agent 和普通 Chatbot 的关键区别是——它能调用工具。我们的智能客服需要三个工具:

  1. 查询订单——根据订单号查状态
  2. 申请退换货——创建退换货工单
  3. 转人工——把对话上下文打包给人工客服

先定义工具函数。新建 tools.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from langchain.tools import tool
from typing import Optional

# 模拟订单数据库
ORDERS = {
"ORD001": {"status": "已发货", "item": "机械键盘", "eta": "5月28日"},
"ORD002": {"status": "处理中", "item": "显示器支架", "eta": "待确认"},
"ORD003": {"status": "已签收", "item": "Type-C 拓展坞", "eta": None},
}

@tool
def query_order(order_id: str) -> str:
"""根据订单号查询订单状态。order_id 格式如 ORD001"""
order = ORDERS.get(order_id.upper())
if not order:
return f"未找到订单 {order_id},请核对订单号后重试。"
status_text = f"订单 {order_id}{order['item']},状态:{order['status']}"
if order['eta']:
status_text += f",预计送达:{order['eta']}"
return status_text

@tool
def request_return(order_id: str, reason: Optional[str] = None) -> str:
"""为用户创建退换货申请。需要订单号和退换原因"""
order = ORDERS.get(order_id.upper())
if not order:
return f"未找到订单 {order_id},无法创建退换货申请。"
if order['status'] == '已签收':
reason_text = f"(原因:{reason})" if reason else ""
return f"退换货申请已提交{reason_text}。工单号 RTN-{order_id},客服将在 24 小时内联系您确认退货地址。"
return f"订单 {order_id} 当前状态为「{order['status']}」,暂不支持退换货。请收到商品后再申请。"

@tool
def escalate_to_human(summary: str) -> str:
"""当 AI 无法解决用户问题时,将对话摘要转接给人工客服"""
return f"已为您转接人工客服。工单号 CS-{hash(summary) % 10000:04d},预计等待 2-3 分钟。对话摘要:{summary[:100]}"

三个工具各有分工:查订单只读,退换货会创建工单,转人工是兜底。LangChain 的 @tool 装饰器把普通函数包装成 Agent 可调用的工具,函数的 docstring 会自动成为工具描述——Agent 靠这段文字判断什么时候该用什么工具。

构建 Agent 核心逻辑

新建 agent.py,把工具注册到 Agent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os
from dotenv import load_dotenv
from langchain_anthropic import ChatAnthropic
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from tools import query_order, request_return, escalate_to_human

load_dotenv()

# 初始化 Claude 模型
llm = ChatAnthropic(
model="claude-sonnet-4-6",
temperature=0.3,
max_tokens=1024,
)

tools = [query_order, request_return, escalate_to_human]

# Agent 的系统提示词
system_prompt = """你是一个专业的电商智能客服助手。请遵循以下规则:

1. 用中文回复,语气友好专业
2. 用户询问订单时,先调用 query_order 查询,再回复
3. 用户要求退换货时,先确认订单状态,符合条件再调用 request_return
4. 遇到无法解决的问题(如投诉、退款争议、技术故障),调用 escalate_to_human 转人工
5. 不要编造订单信息,一切以工具返回的数据为准
6. 回复简洁,控制在 150 字以内
"""

prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 调试时可以看到 Agent 的推理过程
handle_parsing_errors=True,
)

这里有几个设计选择值得解释:

  • temperature=0.3——客服场景不能太有创意,要保持回答一致性
  • verbose=True——开发阶段打开,能看到 Agent 每一步的推理和工具调用
  • handle_parsing_errors=True——防止 Claude 返回格式异常导致 Agent 崩溃

这和 Claude Code 自定义规则与自动化工作流 的思路一致——通过 system prompt 约束行为边界,让 AI 在给定框架内发挥,而不是放任自由发挥。

运行与交互

最后写一个简单的命令行交互入口 main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from langchain_core.messages import HumanMessage, AIMessage
from agent import agent_executor

def chat():
print("🤖 智能客服已上线,输入 'quit' 退出\n")
history = []

while True:
user_input = input("👤 您: ")
if user_input.lower() == 'quit':
print("👋 感谢咨询,再见!")
break

result = agent_executor.invoke({
"input": user_input,
"chat_history": history,
})

reply = result["output"]
print(f"🤖 客服: {reply}\n")

history.append(HumanMessage(content=user_input))
history.append(AIMessage(content=reply))

if __name__ == "__main__":
chat()

运行 python main.py,试试这些对话:

1
2
3
4
5
6
7
8
9
👤 您: 帮我查一下 ORD001 的订单状态
🤖 客服: 您的订单 ORD001(机械键盘)目前已发货,预计5月28日送达。

👤 您: 我想退货
🤖 客服: 好的,ORD001 还未签收,暂时无法申请退换货。建议您收到商品后如果不满意再联系我。

👤 您: 我收到的键盘有质量问题,我要投诉
🤖 客服: 非常抱歉给您带来不便!已为您转接人工客服处理投诉。
工单号 CS-3847,预计等待 2-3 分钟。

进阶优化方向

这个 Demo 能跑起来,但离生产环境还有距离。如果要继续完善,几个方向值得考虑:

接入真实数据源。把 ORDERS 字典换成真实的数据库查询——LangChain 支持 SQLDatabaseToolkit,可以直接连 MySQL/PostgreSQL 执行 SQL。Agent 拿到 schema 后会自动生成查询语句,不需要你手写 SQL。

增加多轮记忆持久化。目前对话历史存在内存里,服务重启就丢失。LangChain 内置了多种 Memory 方案——ConversationBufferMemory 适合短对话,ConversationSummaryMemory 会把长对话压缩成摘要,节省 token。生产环境推荐用 Redis 做持久化存储。

接入多渠道。客服 Agent 的核心逻辑写好之后,前面接什么渠道都可以——微信公众号、企业微信、网页聊天窗口。架构上把 Agent 的 invoke() 包一层 API,各渠道统一调用同一个入口。

RAG 知识库增强。如果你的客服需要回答产品规格、退换货政策这类问题,可以把FAQ 文档向量化存入向量数据库。用户提问时先检索相关文档片段,再交给 Agent 回答。这比把全部 FAQ 塞进 system prompt 高效得多——关于 Prompt 工程的具体技巧,可以参考 从入门到进阶的完整指南

如果你对这个 Agent 的进阶版本(接入数据库 + 知识库 + 钉钉/飞书)感兴趣,可以在评论区告诉我,下篇接着写。