跳转到内容

需求分析与技术选型

从这一章开始,我们将离开"单个知识点讲解"的模式,进入综合项目实战阶段。前面九章我们学习了模型 I/O、RAG、记忆、多模态、LCEL、Agent、流式/异步/中间件——这些不是孤立的技术点,而是构建一个完整 AI 应用的积木。本章和下一章的目标,就是把所有积木搭成一座真正能用的建筑。

一个真实的智能客服场景

想象你是一家 SaaS 公司的技术负责人,公司产品叫 CloudDesk——一个在线协作平台。每天有几百个客户通过网页聊天窗口、邮件或工单系统提出问题:

  • "你们的免费版支持几个团队成员?"
  • "我想把数据从 Notion 迁移过来,有导入工具吗?"
  • "上个月我付了专业版但被扣了两次钱,怎么退款?"
  • "API 返回 503 错误是什么意思?"

目前这些问题全靠人工客服处理。问题很明显:响应慢(平均等待 5 分钟)、成本高(每个坐席月薪 8000+)、覆盖时间有限(只能覆盖工作时间)。你的老板给你下达了一个任务:用 AI 构建一套智能客服系统,能够自动回答 70% 以上的常见问题,复杂问题再转人工

这就是我们要构建的系统。它不是一个玩具 demo,而是一个需要考虑知识库管理、意图识别、多轮对话、人工接管、日志审计、性能监控等维度的生产级应用。

从业务需求到技术需求

在动手写代码之前,我们需要先把模糊的业务诉求翻译成精确的技术需求。这个过程叫做需求分析,它是任何项目最关键也最容易被跳过的步骤。

核心功能需求

经过与产品团队和客服团队的沟通,我们梳理出以下核心功能:

第一,基于产品知识的自动问答。这是系统的主干能力。用户问产品相关的问题(定价、功能、使用方法),系统能够从公司的产品文档、FAQ、帮助中心文章中检索出准确信息并生成自然语言回复。这对应我们已经学过的 RAG 技术

第二,意图识别与路由分流。不是所有问题都适合 AI 回答。用户可能想查订单状态、申请退款、投诉服务态度——这些需要走不同的处理流程。系统需要在接收到用户消息的第一时间判断"这个问题该由谁来处理",然后分发给对应的处理器。这涉及 分类/路由 能力。

第三,多轮对话上下文保持。用户不会一次就把话说完。典型对话可能是这样的:

用户: 你们免费版有什么限制?
AI:  免费版最多支持 5 个成员,存储空间 2GB...
用户: 那 专业版呢?
AI:  专业版支持无限成员,存储空间 100GB...
用户: 好的,我要升级,怎么操作?

注意第三轮——用户说"那 专业版呢?"和"我要升级",这两句话脱离上下文是无法理解的。系统必须记住前面的对话内容才能正确回应。这对应 记忆(Memory) 组件。

第四,人工接管机制。AI 不是万能的。当遇到以下情况时,系统应该主动将对话转给人工客服:

  • 连续多次无法回答用户的问题
  • 用户明确表示"转人工"/"找真人"
  • 检测到用户情绪激动(投诉类场景)
  • 涉及敏感操作(退款、账号封禁等)

这个机制在行业内被称为 Handoff(交接)

非功能性需求

除了功能本身,一个生产级系统还必须满足这些质量属性:

维度要求对应技术手段
响应速度首个 token 在 2 秒内出现流式输出(stream)
并发能力支持 100+ 用户同时在线异步编程(async/await)
答案准确性产品相关问题准确率 > 85%RAG 检索质量优化
可观测性每次对话可追溯、可审计中间件日志 + 回调
安全性不泄露内部信息、不执行危险操作内容审核中间件

你会发现,右边的"对应技术手段"恰好就是我们前九章学过的全部内容。这不是巧合——LangChain 的设计哲学就是把这些工程关注点以统一的方式组织起来

系统架构总览

基于以上分析,我们的智能客服系统包含以下核心模块:

┌─────────────────────────────────────────────────┐
│                  用户接入层                        │
│         (Web 聊天 / API / 邮件 / 工单)            │
└──────────────┬──────────────────────────┬────────┘
               │                          │
       ┌──────▼──────┐          ┌────────▼────────┐
       │  意图识别器   │          │   内容审核器      │
       │ (Intent      │          │ (Content        │
       │  Classifier) │          │  Auditor)       │
       └──────┬──────┘          └────────┬────────┘
              │                          │
    ┌─────────┼─────────┬───────────────┘
    │         │         │
┌───▼───┐ ┌──▼───┐ ┌──▼──────────┐ ┌──────────────┐
│ RAG   │ │ 记忆  │ │ 人工接管     │ │ 通用闲聊/兜底 │
│ 问答链 │ │ 组件  │ │ Handoff     │ │ Fallback     │
└───┬───┘ └──┬───┘ └──┬──────────┘ └──────────────┘
    │         │         │
    └────┬────┴─────────┘

    ┌────▼────────────┐
    │    LLM 核心      │
    │  (ChatModel)     │
    └─────────────────┘

每个模块都对应一节的内容:

  • 10.2 — 构建 RAG 问答链(加载产品知识库)
  • 10.3 — 实现意图识别与分流路由
  • 10.4 — 集成人工接管(Handoff)机制

技术选型决策

在具体实现之前,我们需要对每个关键组件做技术选型。选型的原则是:优先选择 LangChain 生态内已验证的方案,避免重复造轮子;同时在必要的地方保留定制空间

LLM 选型

对于客服场景,模型的选型需要平衡三个因素:成本、响应速度、中文理解能力

方案成本(每百万 token)响应速度中文能力推荐度
GPT-4o~$2.5(输入)/ $10(输出)优秀⭐⭐⭐⭐ 生产首选
GPT-4o-mini~$0.15 / $0.6很快良好⭐⭐⭐⭐⭐ 性价比最优
Claude 3.5 Sonnet~$3 / $15优秀⭐⭐⭐⭐ 长文本优势
本地部署(Qwen/Llama)免费(需 GPU)取决于硬件良好⭐⭐⭐ 数据敏感场景

推荐策略:开发测试阶段用 GPT-4o-mini 降低成本,生产环境根据实际效果决定是否升级到 GPT-4o。代码层面通过环境变量切换,不做硬编码:

python
import os
from langchain_openai import ChatOpenAI

def get_llm(model_name: str = None):
    model_name = model_name or os.getenv("LLM_MODEL", "gpt-4o-mini")
    return ChatOpenAI(
        model=model_name,
        temperature=0.1,
        streaming=True,
    )

llm = get_llm()

向量数据库选型

客服知识库的规模通常在几千到几万条文档之间,属于中小规模。我们对比几种方案:

方案特点适用场景
Chroma内嵌式、零配置、Python 原生开发和小规模生产 ✅ 推荐
FAISSFacebook 出品、纯内存、极快纯检索、不需要持久化查询
Milvus分布式、支持十亿级向量大规模生产环境

本项目选择 Chroma 作为默认向量存储。原因很简单:它是 LangChain 生态中集成度最高的向量数据库,无需额外安装服务器,一行代码就能启动,非常适合作为教程项目的起点。后续如果需要扩展到更大规模,替换底层存储只需修改 retriever 的创建逻辑,上层链路完全不受影响。

python
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()
vectorstore = Chroma(
    collection_name="cloud_desk_kb",
    embedding_function=embeddings,
    persist_directory="./chroma_db",
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

记忆方案选型

客服场景的记忆需求比较特殊:需要按会话隔离(每个用户的对话互不干扰),同时需要持久化(用户关闭浏览器后再回来,历史记录还在)。我们在第 5 章学过的 RunnableWithMessageHistory 正好满足这两个需求:

python
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory

store = {}

def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

with_memory = RunnableWithMessageHistory(
    runnable=base_chain,
    get_session_history=get_session_history,
    input_messages_key="question",
    history_messages_key="chat_history",
)

开发阶段用内存存储即可,生产环境可以无缝切换到 Redis 或 SQLite 后端。

框架选型总结

组件选择理由
编排框架LangChain v1.0 + LCEL统一的声明式语法
LLMChatOpenAI (GPT-4o-mini)成本低、速度快、中文好
EmbeddingOpenAIEmbeddings质量高、生态兼容性好
向量存储Chroma零配置、开发友好
记忆RunnableWithMessageHistory会话隔离 + 可持久化
Web 框架FastAPI异步原生、流式支持好
流式协议SSE (Server-Sent Events)浏览器原生支持

项目结构规划

在开始编码之前,先确定文件结构。一个好的项目结构能让代码的组织一目了然:

customer-service/
├── knowledge_base/              # 产品知识库原始文档
│   ├── pricing.md               # 定价方案
│   ├── features.md              # 功能介绍
│   ├── faq.md                   # 常见问题
│   └── policies.md              # 政策条款
├── config.py                    # 全局配置(模型、API Key 等)
├── rag_pipeline.py              # RAG 检索增强管线
├── intent_classifier.py         # 意图识别与分流
├── memory_manager.py            # 会话记忆管理
├── handoff.py                   # 人工接管机制
├── content_auditor.py           # 内容审核中间件
├── chatbot.py                   # 主系统:组装所有模块
├── server.py                    # FastAPI 服务端
└── main.py                      # 入口 / CLI 交互

这个结构遵循了单一职责原则:每个文件负责一个明确的模块,模块之间通过清晰的接口交互。接下来三节,我们会逐一实现每个模块,最后在 10.4 节把它们组装成一个完整的系统。

常见误区

误区一:先写代码再想需求。很多开发者拿到项目就急着开始 import 和写 class,结果写到一半发现架构不对,推倒重来。"磨刀不误砍柴工"——花 30 分钟做需求分析和技术选型,能避免后面数小时的返工。

误区二:什么都想一步到位。看到上面的架构图就想着一次性实现所有功能——流式输出、异步、审核、限流、监控……这是不现实的。正确的做法是 MVP 思维:先用最简单的方式跑通主流程(RAG 问答 → 记忆 → 输出),然后再逐层叠加中间件和能力。

误区三:忽略非功能性需求。只关心"能不能答对问题",不关心"响应有多快""并发撑不撑得住""出了问题怎么排查"。在生产环境中,非功能性需求的失败往往比功能 bug 更致命——一个响应超时的客服系统比一个偶尔答错的系统更让用户崩溃。

基于 MIT 许可发布