1. 问题背景:客服工单积压,地址解析成了瓶颈
我们负责某头部跨境电商平台的智能客服系统,日均订单 200 万,其中约 15% 的咨询与订单售后相关。售后场景里最典型的一类问题是"我的包裹寄到哪了"“地址填错了怎么改”——这类问题看似简单,却高度依赖对用户自然语言中地址信息的准确抽取与结构化。
改造前,系统走的是传统规则引擎 + 关键词匹配:用户说"帮我改一下收货地址",规则引擎匹配到"改地址"意图后,弹出一个固定表单让用户手动重填。结果有两个痛点:
- 地址解析失败率高:用户口语化表达(“寄到公司吧”“放丰巢就行”)无法被规则覆盖,地址解析失败率高达 12%,大量工单转人工。
- 多轮任务无法编排:改地址需要"核验身份 → 校验新地址 → 确认生效时间"三步,规则引擎写死流程,一旦用户中途岔开话题(“顺便问下运费险”),整个会话状态就丢了。
日均转人工工单约 1.2 万,客服团队 40 人,人均日处理 300 单,高峰期排队时长超过 20 分钟。业务方给的目标很明确:把地址解析失败率从 12% 压到 3% 以内,转人工率降一半。
我最初接触大模型 Agent,并不是为了追热点,而是被这个具体的业务问题倒逼的:规则引擎在地址解析和多轮编排上已经到顶,再堆正则和状态机,边际收益越来越低。我需要一个能"理解口语、自主走流程"的方案,于是开始调研 LangChain 的 Agent 能力。
2. 根因分析:为什么规则引擎撑不住
我们复盘了线上日志,发现三个根因:
第一,意图识别是"扁平"的,没有任务状态机。 规则引擎只做单轮匹配,无法表达"改地址"这个任务内部的身份核验、地址校验、生效确认三个子步骤,更无法在用户岔开话题后恢复上下文。
第二,地址抽取依赖正则,覆盖不了口语化表达。 线上正则库维护了 300 多条规则,但"寄到公司"“放前台”"老地址旁边那个小区"这类指代和省略,正则完全无能为力。
第三,会话状态存 Redis 但无超时恢复机制。 用户隔 10 分钟回来继续改地址,Redis 里的 session 已过期,只能从头再来,体验极差。
根因清楚了:我们需要一个能自主编排多步任务、能理解口语化地址、能跨轮次保持状态的方案。这正是大模型 Agent 的用武之地。
3. 方案对比与选型
我们评估了三个方案:
| A. 纯 Prompt 驱动 Agent | 用 LangChain 0.3 + GPT-4o,把任务编排逻辑全写进 System Prompt | 开发快,3 天出原型 | 流程不可控,模型自由发挥,关键步骤可能跳过 |
| B. 规则引擎 + 大模型辅助抽取 | 保留原规则引擎,仅用大模型替换地址抽取模块 | 改动小,风险低 | 任务编排仍是硬编码,多轮岔题问题没解决 |
| C. 大模型 Agent + 显式工具调用(ReAct) | 用 LangChain 0.3 的 AgentExecutor,把"身份核验"“地址校验”"订单查询"封装成 Tool,由模型自主决定调用顺序 | 编排灵活,关键步骤可用 Tool 约束 | 需要设计好 Tool 边界和 Prompt,调试成本高 |
选型依据:方案 A 太不可控,客服场景出错代价高(改错地址 = 寄丢包裹);方案 B 治标不治本。最终选了 C:用 Agent 做编排,但把"身份核验""地址校验"这类强约束步骤做成 Tool,模型只能调用 Tool 拿结果,不能自己编造。这样既保留自主性,又守住安全底线。
调参细节:temperature 从默认的 0.7 降到 0.2,减少模型在工具选择上的随机性;max_iterations 设为 6,防止模型在复杂会话里无限循环调用工具。这两个参数是灰度期调出来的,后面踩坑部分会细说。
技术栈:Python 3.11 + LangChain 0.3.7 + OpenAI GPT-4o + Redis 7.2(会话状态)+ PostgreSQL 16 + PostGIS 3.4(地址库)。
4. 实操步骤:Agent 编排的核心实现
4.1 定义工具集
# tools.py
from langchain.tools import BaseTool
from pydantic import BaseModel, Field
class VerifyIdentityInput(BaseModel):
user_id: str = Field(description="用户ID")
order_id: str = Field(description="订单号")
class VerifyIdentityTool(BaseTool):
name = "verify_identity"
description = "核验用户身份与订单归属,返回是否匹配"
args_schema = VerifyIdentityInput
def _run(self, user_id: str, order_id: str) –> str:
# 调用内部用户服务,返回 "verified" 或 "mismatch"
return check_user_order(user_id, order_id)
关键点:每个 Tool 的 description 要写清楚"什么时候该调用、参数是什么含义",这直接决定模型编排的准确率。我们第一版 description 写得太简略,模型经常把参数传错。
4.2 组装 Agent
# agent.py
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o", temperature=0.2)
prompt = ChatPromptTemplate.from_messages([
("system", """你是电商客服助手。处理改地址任务时,必须按顺序调用工具:
1. verify_identity 核验身份
2. validate_address 校验新地址
3. confirm_change 确认生效
用户岔开话题时,先回答用户问题,再回到未完成的任务。"""),
("placeholder", "{chat_history}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
4.3 会话状态管理
# session.py
import redis, json
r = redis.Redis(host="localhost", port=6379, db=0)
def save_session(session_id: str, state: dict):
# 用 Redis Hash 存任务状态,TTL 30 分钟
r.hset(f"agent:{session_id}", mapping=state)
r.expire(f"agent:{session_id}", 1800)
def load_session(session_id: str) –> dict:
data = r.hgetall(f"agent:{session_id}")
return {k.decode(): json.loads(v) for k, v in data.items()}
预期运行结果:用户输入"我要改地址,订单 20260918001",Agent 自动调用 verify_identity → 返回 verified → 继续问新地址 → 调用 validate_address → 确认后调用 confirm_change,全程无需人工介入。
5. 踩坑与排错
5.1 坑一:Agent 跳过身份核验
报错/现象:线上日志发现,约 8% 的会话里,用户说"帮我改地址"后,Agent 直接问新地址,跳过了 verify_identity。
排查:打开 verbose 日志,发现模型认为"用户已登录,身份可信",所以跳过了核验。这是典型的模型过度信任上下文。
解决:在 System Prompt 里加硬约束:"无论用户是否已登录,改地址前必须调用 verify_identity,否则拒绝执行。“同时把 verify_identity 的 description 改为"改地址任务的强制前置步骤,不可跳过”。修复后跳过率降到 0.3%。
5.2 坑二:地址校验 Tool 返回格式不兼容
报错:
ValueError: Invalid tool response: expected string, got dict
排查:validate_address 内部返回了 Python dict(结构化地址),但 LangChain 的 Tool 要求返回字符串。模型拿到 dict 后无法解析,直接报错。
解决:所有 Tool 统一返回 JSON 字符串:
def _run(self, address: str) –> str:
result = geocode_address(address) # 返回 dict
return json.dumps(result, ensure_ascii=False)
5.3 坑三:Redis 会话状态丢失
现象:用户隔 15 分钟回来,Agent 忘了之前核验过身份,重新问一遍。
排查:发现 save_session 里 json.loads(v) 在读取时对非 JSON 字符串(如普通字符串状态)会抛异常,导致整个 session 读取失败,回退到空状态。
解决:读取时做类型兼容:
def load_session(session_id: str) –> dict:
data = r.hgetall(f"agent:{session_id}")
result = {}
for k, v in data.items():
try:
result[k.decode()] = json.loads(v)
except (json.JSONDecodeError, TypeError):
result[k.decode()] = v.decode()
return result
5.4 坑四:temperature 调太高导致工具乱选
现象:灰度首日,约 5% 的会话里 Agent 把 validate_address 和 confirm_change 的调用顺序搞反,先确认生效再校验地址,导致用户收到"地址已更新"但实际没改。
排查:对比日志发现,这些会话的 temperature 都是默认的 0.7。模型在工具选择上随机性太大,把"校验"和"确认"两个步骤的顺序颠倒了。
解决:把 temperature 从 0.7 压到 0.2,同时给 confirm_change 的 description 加上"必须在 validate_address 通过后调用"的约束。修复后顺序颠倒率降到 0.1% 以下。
6. 验证数据与效果
上线后压测与灰度两周,数据如下:
| 地址解析失败率 | 12% | 2.1% | 下降 82.5% |
| 转人工率 | 30% | 14% | 下降 53% |
| 平均处理时长 | 4.2 分钟 | 1.8 分钟 | 下降 57% |
| 单 Agent 并发 | 50 QPS | 200 QPS | 提升 4 倍 |
压测环境:8 核 16G 单机,GPT-4o 接口延迟平均 800ms,Agent 单轮完整任务(3 次工具调用)端到端耗时约 3.2 秒,满足客服场景的实时性要求。
7. 复盘:什么场景该用,什么场景不该用
适用场景:
- 任务有明确子步骤、但步骤顺序允许一定灵活性(如售后处理、订单修改)。
- 用户表达口语化、多样化,规则难以穷举(如地址、商品描述)。
- 需要跨多轮保持上下文,且能接受 2-4 秒的响应延迟。
不适用场景:
- 强合规、零容错场景(如支付、资金操作):模型编排的不确定性不可接受,应坚持硬编码状态机。
- 超低延迟场景(<500ms):Agent 多轮工具调用叠加 LLM 推理,延迟难压下来。
- 工具数量超过 15 个:模型选择工具的准确率会明显下降,此时应拆分多个专用 Agent。
代价与边界:这套方案不是免费的。GPT-4o 的 token 成本比规则引擎高一个数量级,单次改地址任务平均消耗约 2.8k token,按当前价格折算约 0.02 元/单,日均 200 万订单里约 15% 走 Agent,仅推理成本一天就是 6000 元左右。另外,Agent 的响应延迟(3.2 秒)比规则引擎(0.5 秒)高不少,高峰期需要给 Agent 单独扩 2 台 8 核 16G 的机器扛并发。
边界提醒:Agent 的"自主"是有限度的。我们最终把身份核验、地址校验做成强约束 Tool,模型只能在约束内编排。自主性要给在"怎么走流程"上,而不是"要不要走流程"上——这是本次落地最大的经验。如果你的业务是支付、资金操作这类零容错场景,或者对延迟敏感到 500ms 以内,不要照搬这套方案,硬编码状态机更稳。


