ailearn

AI项目实战 - 智能客服系统

从零构建智能客服系统,实现多轮对话与知识库检索

访问-- -- --

前置知识:需要先掌握 RAG基础

本文重点:完整项目实现与部署


一、项目架构

智能客服系统架构:
┌─────────────────────────────────────┐
│            前端界面                   │
│         (Vue/React)                  │
└─────────────────┬───────────────────┘
                  │ HTTP/WebSocket

┌─────────────────────────────────────┐
│            后端服务                   │
│  ┌─────────────────────────────────┐│
│  │  API层 (FastAPI)                ││
│  ├─────────────────────────────────┤│
│  │  对话管理                        ││
│  │  意图识别                        ││
│  ├─────────────────────────────────┤│
│  │  RAG引擎                         ││
│  │  - 知识库检索                    ││
│  │  - 上下文理解                    ││
│  │  - 答案生成                      ││
│  └─────────────────────────────────┘│
└─────────────────┬───────────────────┘

    ┌─────────────┼─────────────┐
    ▼             ▼             ▼
┌───────┐   ┌───────┐   ┌───────┐
│ 向量库 │   │ 数据库 │   │ LLM  │
│Chroma │   │SQLite │   │ API  │
└───────┘   └───────┘   └───────┘

二、后端实现

2.1 核心服务

# services/chat_service.py
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.memory import ConversationBufferMemory
from langchain.prompts import PromptTemplate
class CustomerServiceBot:
    """智能客服机器人"""
    
    def __init__(self, config):
        self.llm = ChatOpenAI(model=config["llm_model"], temperature=0.7)
        self.embeddings = OpenAIEmbeddings(model=config["embedding_model"])
        
        self.vectorstore = Chroma(
            persist_directory=config["persist_dir"],
            embedding_function=self.embeddings
        )
        
        self.sessions = {}
        
        self.system_prompt = """你是一个专业的客服助手。
        
请根据以下规则回答问题:
1. 如果问题在知识库中有答案,基于知识库回答
2. 如果知识库没有答案,礼貌告知用户并建议转人工
3. 保持友好、专业的态度
知识库内容:
{context}
用户问题:{question}
请回答:"""
    
    def get_session(self, session_id):
        if session_id not in self.sessions:
            self.sessions[session_id] = {
                "memory": ConversationBufferMemory(
                    memory_key="chat_history",
                    return_messages=True
                ),
                "history": []
            }
        return self.sessions[session_id]
    
    def chat(self, session_id, question):
        session = self.get_session(session_id)
        
        docs = self.vectorstore.similarity_search(question, k=3)
        context = "\n\n".join([doc.page_content for doc in docs])
        
        prompt = PromptTemplate.from_template(self.system_prompt)
        chain = prompt | self.llm
        
        response = chain.invoke({"context": context, "question": question})
        
        session["history"].append({"role": "user", "content": question})
        session["history"].append({"role": "assistant", "content": response.content})
        
        return {
            "answer": response.content,
            "sources": [{"content": doc.page_content[:100]} for doc in docs]
        }

2.2 API路由

# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
import uuid
app = FastAPI(title="智能客服系统")
bot = CustomerServiceBot({
    "llm_model": "gpt-3.5-turbo",
    "embedding_model": "text-embedding-ada-002",
    "persist_dir": "./chroma_db"
})
class ChatRequest(BaseModel):
    session_id: Optional[str] = None
    message: str
class ChatResponse(BaseModel):
    session_id: str
    answer: str
    sources: list
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    session_id = request.session_id or str(uuid.uuid4())
    result = bot.chat(session_id, request.message)
    return ChatResponse(session_id=session_id, **result)
@app.get("/health")
async def health():
    return {"status": "healthy"}

三、前端实现

<!-- Chat.vue -->
<template>
  <div class="chat-container">
    <div class="messages" ref="messagesContainer">
      <div v-for="msg in messages" :key="msg.id"
           :class="['message', msg.role]">
        <div class="content">{{ msg.content }}</div>
      </div>
    </div>
    
    <div class="input-area">
      <input v-model="inputText" 
             @keyup.enter="sendMessage"
             placeholder="输入您的问题..." />
      <button @click="sendMessage">发送</button>
    </div>
  </div>
</template>
<script setup>
import { ref, nextTick } from 'vue'
import axios from 'axios'
const messages = ref([])
const inputText = ref('')
const sessionId = ref(null)
const sendMessage = async () => {
  if (!inputText.value.trim()) return
  
  const userMessage = inputText.value
  inputText.value = ''
  
  messages.value.push({ id: Date.now(), role: 'user', content: userMessage })
  
  try {
    const response = await axios.post('/api/chat', {
      session_id: sessionId.value,
      message: userMessage
    })
    
    sessionId.value = response.data.session_id
    messages.value.push({ id: Date.now() + 1, role: 'assistant', content: response.data.answer })
  } catch (error) {
    console.error('Error:', error)
  }
}
</script>

四、部署配置

# docker-compose.yml
version: '3.8'
services:
  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    volumes:
      - ./chroma_db:/app/chroma_db
  
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

参考资源


返回AI项目实战 最后更新: 2026年4月20日

访问 --

讨论与反馈