news 2026/8/16 4:24:39

从零到一搭建智能客服系统(LangGraph + FastAPI + 智谱AI 实战)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零到一搭建智能客服系统(LangGraph + FastAPI + 智谱AI 实战)

一、这个项目是做什么的?

「π域」是一个快递行业的 AI 智能客服系统。它的核心价值是:用 AI Agent 替代 80% 的重复性人工客服工作,实现 7×24 小时秒级响应。

具体来说,它能做这几件事:

  • FAQ 问答:用户问“运费怎么算?”、“寄到北京要多久?”——系统基于知识库自动回答
  • 订单查询:用户输入运单号,系统调用快递鸟 API 返回真实物流轨迹
  • 投诉工单:用户说“包裹破损了”,系统提取信息,自动生成工单编号
  • 地址修改:用户说“改地址”,系统引导用户提供新地址
  • 转人工:用户说“转人工”,系统通过 WebSocket 排队,客服接单后实时对话

二、技术栈选型(为什么是这些?)

组件选型选型理由
后端框架FastAPI轻量、异步、自动生成 Swagger 文档,开发效率极高
多 Agent 编排LangGraph支持状态管理和条件路由,比 LangChain 更灵活可控
大模型智谱 GLM-4-Flash性价比极高,响应速度快,中文能力优秀
向量数据库Chroma轻量级、本地持久化、零配置,无需额外部署
实时通信WebSocket双向实时通信,天然适合排队 + 聊天场景
前端原生 HTML + CSS + JS无框架依赖,轻量快速,酷黑主题

三、系统架构(一张图看懂)

用户输入 │ ▼ FastAPI /chat 接口 │ ▼ ───────────────────────────────────────────────────────── │ LangGraph 多 Agent 编排 │ │ │ │ ──────────── ──────────── │ │ │ 意图识别 │ → │ 条件路由 │ │ │ │ (Intent) │ │ (Router) │ │ │ ──────────── ─────────── │ │ │ │ │ ───────────────────────────────── │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ──────── ──────── ──────── │ │ │ FAQ │ │ 订单 │ │ 投诉/转人工│ │ │ │ Agent │ │ Agent │ │ Agent │ │ │ ──────── ──────── ──────── │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ Chroma检索 快递鸟API WebSocket排队 │ ───────────────────────────────────────────────────────── │ ▼ 返回最终回答

四、核心功能详细实现

1. 意图识别(Few-shot + 上下文记忆)

问题

在零样本场景下,模型对“寄到广州要几天”这类边缘问题容易误判为 other。

解决方案

构建 Few-shot 示例库,运行时动态检索最相似的 3 个示例注入 Prompt。

示例库结构(data/intent_examples.json):

[{"question":"怎么算运费","intent":"faq"},{"question":"寄到北京要多久","intent":"faq"},{"question":"查一下我的快递","intent":"order"},{"question":"转人工","intent":"human"},{"question":"改地址","intent":"change_address"}]

核心代码:

defintent_agent(state:AgentState):question=state.get("user_question")examples=load_examples()similar=find_similar_examples(question,examples,top_k=3)few_shot_text="\n".join([f"用户:{ex['question']}\n输出:{{\"intent\": \"{ex['intent']}\"}}"forexinsimilar])prompt=f""" 你是一个快递客服意图识别专家。判断用户问题属于以下哪一类: - faq: 咨询常见问题 - order: 查询订单/物流 - complaint: 投诉或理赔 - human: 转人工 - change_address: 修改地址 - other: 其他 以下是一些参考示例:{few_shot_text}用户问题:{question}"""

多轮上下文记忆

维护 context_summary 字段,将最近 2 轮对话摘要传入意图识别 Prompt,解决指代消解问题:

用户:查一下我的快递 AI:请提供运单号 用户:YT3762892935155 ✅ 系统能理解这是在补充运单号

2. RAG 知识库(FAQ 问答)

技术方案

  • 分块策略:chunk_size=512,重叠 50 字符
  • Embedding 模型:智谱 embedding-2
  • 向量库:Chroma(本地持久化)
  • 检索策略:Top-3 相似片段

FAQ 加载代码:

defload_faq():chunks=split_faq("data/faq_knowledge.md",chunk_size=512,overlap=50)collection=get_chroma_collection()ids=[f"faq_{i}"foriinrange(len(chunks))]collection.add(documents=chunks,ids=ids)

检索 + 生成代码:

deffaq_agent(state:AgentState):query=state.get("user_question")collection=get_chroma_collection()results=collection.query(query_texts=[query],n_results=3)context="\n\n".join(results['documents'][0])prompt=f"基于以下知识回答用户问题:\n{context}\n问题:{query}"return{"final_answer":call_llm(prompt)}

3. 真实订单查询(快递鸟 API)

对接步骤

  1. 注册快递鸟账号,获取 EBusinessID 和 APIKey
  2. 封装签名算法(MD5 + Base64)
  3. 实现智能识别快递公司编码(根据运单号前缀)

核心代码:

defquery_order(order_id:str):# 1. 智能识别快递公司shipper_code=recognize_express(order_id)# SF/YTO/ZTO...ifnotshipper_code:return{"code":-1,"msg":"无法识别该运单号所属快递公司"}# 2. 构造请求request_data=f'{{"LogisticCode":"{order_id}","ShipperCode":"{shipper_code}"}}'params={"EBusinessID":CUSTOMER_CODE,"RequestType":"8002","RequestData":request_data,"DataSign":encrypt(request_data,APP_KEY),"DataType":2}# 3. 发送请求并解析resp=requests.post("https://api.kdniao.com/api/dist",data=params)result=resp.json()ifresult.get("Success"):return{"code":0,"data":{"traces":result.get("Traces",[])}}return{"code":-1,"msg":result.get("Reason","查询失败")}

4. 转人工闭环(WebSocket)

架构设计

用户端 ws──→ WebSocket 服务器 ←──ws── 客服端 │ ├── 排队队列 ├── 活跃会话管理 ─ 消息路由

消息类型

类型方向说明
join_queue用户 → 服务器加入排队
agent_ready客服 → 服务器客服上线
agent_take客服 → 服务器接单
chat双方 → 服务器聊天消息转发
agent_offline客服 → 服务器客服下线
end_session客服 → 服务器结束会话

WebSocket 消息路由核心代码:

asyncdefhandle_message(ws,message):data=json.loads(message)msg_type=data.get("type")client_id=data.get("client_id")ifmsg_type=="join_queue":waiting_queue.append({"user_id":client_id,"ws":ws})awaitws.send(json.dumps({"type":"queue_status","position":len(waiting_queue)}))elifmsg_type=="agent_take":user_info=waiting_queue.pop(0)active_sessions[user_info["user_id"]]={"user_ws":user_info["ws"],"agent_ws":ws}awaituser_info["ws"].send(json.dumps({"type":"assigned"}))awaitws.send(json.dumps({"type":"assigned"}))elifmsg_type=="chat":target=data.get("target")content=data.get("content")iftarget=="agent":awaitactive_sessions[client_id]["agent_ws"].send(...)eliftarget=="user":foruid,sessioninactive_sessions.items():ifsession["agent_ws"]==ws:awaitsession["user_ws"].send(...)

五、踩坑记录(真实经验)

问题原因解决方案
KeyError: ‘“intent”’Prompt 中 JSON 示例的花括号被 str.format() 误解析将 {“intent”: “faq”} 改为 {{“intent”: “faq”}}
LLM 返回 ```json {…} ```模型有时会输出 Markdown 代码块用正则 r’```json\s*({.?})\s```’ 提取纯 JSON
KeyError: ‘user_question’LangGraph 状态传递丢失字段使用 state.get(“user_question”, “”) 安全取值
快递鸟返回"没有可用套餐"账号未开通服务或套餐未生效切换沙箱环境测试,或联系客服开通免费套餐
WebSocket 客服消息用户收不到路由逻辑错误,未正确映射 agent_ws 到 user_id在 active_sessions 中双向存储
排队列表不刷新renderQueue 动态修改 h3 导致 DOM 引用丢失预置 refreshSpinner,只更新内容不重建 DOM

六、项目成果

功能完成度

功能状态
FAQ 问答
订单查询(真实 API)
投诉工单生成
地址修改
转人工闭环(WebSocket)
用户退出人工
客服结束会话
前端酷黑主题

代码结构

pisphere/ ── main.py # FastAPI 入口 ── state.py # AgentState 定义 ── graph.py # LangGraph 图构建 ── websocket_server.py # WebSocket 服务器 ── agents/ │ ├── intent.py # 意图识别 │ ├── faq.py # FAQ 检索 │ ├── order.py # 订单查询 │ ├── complaint.py # 投诉工单 │ ├── change_address.py # 地址修改 │ ├── handoff.py # 转人工 │ ─ fallback.py # 兜底 ── rag/ │ ├── chroma_client.py # Chroma 客户端 │ ─ faq_loader.py # FAQ 加载器 ── web/ │ ├── index.html # 用户端 │ ─ customer_service.html # 客服端 ── data/ ─ intent_examples.json # Few-shot 示例库

七、后续优化方向

优先级优化项说明
环境变量配置API Key 等敏感信息移入 .env
Docker 容器化便于部署和迁移
工单存储升级JSON → SQLite/PostgreSQL
日志结构化print → logging 模块
Embedding 模型对比测试 bge-large-zh 等模型对检索效果的影响

八、总结

从零到一,我用 3 周时间 完成了「π域」智能客服系统的开发。这个项目让我深入理解了:

  • RAG 完整流程:分块 → 向量化 → 存储 → 检索 → 生成
  • LangGraph 多 Agent 编排:状态管理、条件路由、节点协作
  • WebSocket 实时通信:排队、接单、消息转发
  • Prompt Engineering 实战:Few-shot、上下文注入、置信度阈值

更重要的是,这个项目验证了 “Java 后端开发者可以快速转型 AI Agent 开发” ——你不需要成为算法专家,也能构建出可用的 AI 产品。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/16 4:23:04

OpenClaw实战:基于多智能体框架的水产养殖自动化系统部署指南

1. 项目概述:从“瞎”养到“智”养的蜕变养小龙虾,或者说搞水产养殖,听起来是个挺接地气的活儿,但真干起来,里面的门道可深了。过去很多养殖户,包括我自己刚开始摸索的时候,基本都处在“瞎”养状…

作者头像 李华
网站建设 2026/8/16 4:20:26

Obsidian配置同步终极指南:Settings Sync与Git方案详解

1. 项目概述:为什么你的 Obsidian 需要一套“配置同步”方案? 如果你已经开始用 Obsidian 管理笔记,大概率已经体会过那种“甜蜜的烦恼”:在一台电脑上精心配置了主题、安装了十几个插件、调整了无数快捷键和核心设置&#xff0c…

作者头像 李华
网站建设 2026/8/16 4:13:23

从OpenClaw实战看云服务CLI工具:自动化运维与DevOps效率提升

1. 从“玩虾”到“玩转”:一场开发者与云服务的深度对话最近在开发者圈子里,腾讯云OpenClaw的“玩虾大赛”成了一个不大不小的热点。看到这个标题,你可能会有点懵:“玩虾”?这跟写代码、搞云计算有什么关系&#xff1f…

作者头像 李华
网站建设 2026/8/16 4:05:58

AI Agent技能开发实战:从零构建智能体工具链与自动化应用

这次我们来看一个关于 Agent Skills 的实战教程资源。这个标题指向的是一套号称“最全最细”的 Agent Skills 实战教程,目标是帮助学习者快速入门并掌握相关技能。对于想进入 AI Agent 开发领域的人来说,最关心的不是概念有多复杂,而是有没有…

作者头像 李华
网站建设 2026/8/16 4:05:31

带哨兵位的双向链表

一、简介上一篇我们实现了顺序表和单链表,但是我们发现了一个问题,链表的增、删、改都需要二级指针来操作,为了解决这个麻烦,今天引入一个叫哨兵位的家伙。为什么需要哨兵位?双向链表是数据结构中的基础,但…

作者头像 李华
网站建设 2026/8/16 3:54:25

Qwen Prompt 调优反降分?我的黄金测试集构建血泪史

Qwen Prompt 调优反降分?我的黄金测试集构建血泪史 灰度上线的第3天:从指标迷信到业务落地的Prompt评估实战 当我看到线上客服满意度从92%跌到84%时,后背瞬间渗出一层冷汗。明明根据Qwen的自动评估报告,新版Prompt的BLEU值提升了0.15,为什么真实用户反馈反而更差了?这个问题…

作者头像 李华