1. 背景

随着大语言模型(LLM)的快速发展,AI 客服、企业知识库问答、智能助手等应用逐渐落地。

传统客服系统通常依赖:

  • 固定关键词匹配
  • FAQ 页面
  • 人工维护规则

存在以下问题:

  1. 用户表达方式多样,关键词匹配效果差
  2. 知识更新需要修改代码
  3. 无法理解上下文语义
  4. 面对大量业务文档维护成本高

例如用户询问:

“钱怎么还没有退回来?”

传统系统可能无法匹配:

“退款多久到账?”

而基于 RAG 的系统可以通过语义理解找到相关知识。

2. 什么是 RAG?

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合:

  • 文档检索
  • 向量数据库
  • 大语言模型
    的 AI 应用架构。

简单流程:

用户问题
  ↓
问题向量化
  ↓
向量数据库检索
  ↓
获取相关知识
  ↓
拼接 Prompt
  ↓
LLM生成回答

核心思想:

不重新训练模型,而是给模型提供外部知识,让模型根据资料回答。

3. 系统整体架构

本项目实现一个本地运行的 AI 客服系统。

整体架构:


                 用户

                  |
                  |

              RAG应用程序

                  |

        --------------------

        |                  |

    Chroma向量库        Ollama

        |                  |

    知识文档             Qwen模型

        |

   txt / markdown文档

技术组件:

模块 技术
开发语言 Python
AI框架 LangChain
大语言模型 Qwen2
模型运行 Ollama
Embedding模型 nomic-embed-text
向量数据库 Chroma
知识文件 TXT文档

4. RAG工作流程

4.1 文档加载

首先准备客服知识库:

目录:

docs/

└── 电商客服.txt

示例内容:

Q: 如何联系客服?

A:
用户可以通过在线客服、客服电话或提交工单方式联系客服人员。


Q: 如何申请退款?

A:
进入我的订单,选择商品点击申请退款。

程序读取:

DirectoryLoader(
    docs_dir,
    glob="**/*.txt"
)

加载所有 txt 文档。

4.2 文档切割

由于大模型输入长度有限,需要将长文本切分。

例如:

原文:

退款规则:
用户申请退款后,需要审核。
审核通过后1-7天到账。

切割:

chunk1:

退款规则:
用户申请退款后,需要审核。


chunk2:

审核通过后1-7天到账。

代码:

RecursiveCharacterTextSplitter(
    chunk_size=300,
    chunk_overlap=100
)

参数说明:

参数 作用
chunk_size 每个文本块大小
chunk_overlap 文本块之间重叠内容

5. Embedding向量化

计算机无法直接理解:

如何退款?

需要转换成向量:

[0.213,
 0.532,
 0.891,
 ...]

这个过程叫:

Embedding

本项目使用:

nomic-embed-text

代码:

embeddings = OllamaEmbeddings(
    model="nomic-embed-text"
)

6. 构建向量数据库

文本:

退款多久到账?

转换:

向量:
[0.23,0.54,0.88]

保存:

Chroma

----------------------
向量        文本
----------------------

xxx        退款规则

xxx        商品规则

xxx        订单规则

----------------------

代码:

Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

7. 用户问题检索

用户输入:

退货怎么办?

首先:

问题向量化:

退货怎么办?

↓

[0.22,0.55,0.87]

然后 Chroma 搜索相似内容:

返回:

支持七天无理由退货

退货需要提交售后申请

8. Prompt增强

普通模型:

用户:
怎么退款?

RAG:

变成:

你是客服助手。

参考资料:

进入订单选择退款申请。

用户问题:

怎么退款?

请根据资料回答。

这样模型不会依赖自己的记忆,而是参考企业知识库。

9. 模型生成答案

最终交给 Qwen:

参考资料:

进入我的订单,
点击申请退款。


问题:

怎么退款?

生成:

您好,
您可以进入我的订单,
选择对应商品并点击申请退款。

10. 核心代码实现

初始化模型

llm = ChatOllama(
    model="qwen2:1.5b",
    temperature=0
)

创建检索器

retriever = vectorstore.as_retriever(
    search_kwargs={
        "k":3
    }
)

表示:

每次查询返回最相关的 3 个文本块。

构建 RAG Chain

rag_chain = (

{
"context": retriever | format_docs,

"question": RunnablePassthrough()

}

| prompt

| llm

| StrOutputParser()

)

执行流程:

问题

↓

Retriever

↓

Context

↓

Prompt

↓

LLM

↓

Answer

11. 为什么选择 RAG 而不是训练模型?

很多人认为:

企业知识应该重新训练模型。

实际上大多数场景不需要。

原因:

训练模型:

成本高

周期长

需要GPU

更新困难

RAG:

修改文档

↓

重新生成向量

↓

立即生效

例如:

退款规则改变:

以前:

7天到账

修改:

3天到账

重新建立知识库即可。

12. 当前系统存在的问题

目前版本属于基础 RAG:

还有优化空间。

1. 检索优化

目前:

向量搜索

可以增加:

  • BM25关键词搜索
  • 混合检索
  • rerank模型

2. 对话记忆

当前:

问题1

↓

回答


问题2

↓

不知道问题1

可以加入:

Redis保存历史消息:

conversation_id

message list

实现多轮对话。

3. Agent能力

未来可以让 AI 调用业务接口:

例如:

用户:

查询我的订单

Agent:

调用:

订单服务API

返回:

订单正在运输中

13. 后续架构升级方向

最终企业级 AI 客服:

                 用户

                  |

              API Gateway

                  |

              AI Agent

                  |

        --------------------

        |                  |

       RAG              Tools

        |                  |

    知识库              订单API

                       支付API

                       商品API


                  |

                LLM

能力:

  • 知识问答
  • 查询订单
  • 自动退款
  • 商品推荐
  • 多轮聊天

14. 总结

本文实现了一个基于:

LangChain

+

Ollama

+

Chroma

+

Qwen

+

Embedding模型

的本地 RAG 智能客服系统。

核心流程:

文档

↓

文本切割

↓

Embedding

↓

向量数据库

↓

语义检索

↓

Prompt增强

↓

LLM生成

RAG 并不是训练一个新的模型,而是通过外部知识增强大模型能力。

未来可以继续扩展:

RAG评估

↓

Agent

↓

Tool Calling

↓

Memory

↓

生产部署

最终构建企业级 AI 应用。

15.RAG.PY(DEMO)

本地需先安装 Ollama

ollama pull qwen2:1.5b        # 对话模型(轻量,适合本地)
ollama pull nomic-embed-text  # 嵌入模型(用于向量化)
pip install langchain langchain-ollama langchain-community chromadb # python依赖
#rag.py
import os
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

# ==================== 配置 ====================
# 这里配置文档目录、向量数据库目录、对话模型和嵌入模型
DOCS_DIR = "./docs"                    # 你的文档目录
CHROMA_DIR = "./chroma_db"             # 向量数据库存储路径
MODEL_NAME = "qwen2:1.5b"             # 对话模型
EMBED_MODEL = "nomic-embed-text"       # 嵌入模型

# ==================== 第一步:加载并分割文档 ====================
def load_and_split_docs(docs_dir):
    """从目录加载所有 .txt 文件并切分为小块。"""
    loader = DirectoryLoader(
        docs_dir,
        glob="**/*.txt",
        loader_cls=TextLoader,
        loader_kwargs={"encoding": "utf-8"},
    )
    documents = loader.load()
    print(f"📄 加载了 {len(documents)} 个文档")

    # 使用递归分割器将文档切成小块,提升检索质量
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=300,        # 每块最多 300 字符
        chunk_overlap=100,      # 相邻块重叠 100 字符,保证语义连续
        separators=["\n\n", "\n", "。", "!", "?", " "],
    )
    chunks = splitter.split_documents(documents)
    print(f"✂️ 分割成 {len(chunks)} 个文本块")
    return chunks

# ==================== 第二步:向量化并存入 Chroma ====================
def build_vectorstore(chunks):
    """使用嵌入模型将文本块向量化,并创建 Chroma 向量数据库。"""
    embeddings = OllamaEmbeddings(
        model=EMBED_MODEL
    )

    vectorstore = Chroma.from_documents(
        documents=chunks,
        embedding=embeddings,
        persist_directory=CHROMA_DIR,
    )

    print("✅ 重新创建向量数据库")

    return vectorstore

# ==================== 第三步:构建 RAG 问答链 ====================
def build_rag_chain(vectorstore):
    """构建检索增强生成(RAG)问答链。"""
    llm = ChatOllama(
        model=MODEL_NAME,
        temperature=0
    )

    retriever = vectorstore.as_retriever(
        search_kwargs={
            "k": 3
        }
    )


    # 定义对话模板,回答须基于检索到的知识库内容
    prompt = ChatPromptTemplate.from_template("""
你是一个电商客服助手。

必须严格根据下面知识库回答。

如果知识库没有答案,回复:
根据现有资料,我无法回答这个问题。


知识库:
{context}


用户问题:
{question}


回答:
""")

    # 辅助函数:将检索到的文档拼接为字符串
    def format_docs(docs):
        return "\n\n".join(doc.page_content for doc in docs)

    # 使用 LCEL(LangChain 表达式语言)组装链路
    # context 从检索器获取后由 format_docs 拼接成字符串,question 直接传入 prompt
    rag_chain = (
        {
            "context": retriever | format_docs,
            "question": RunnablePassthrough(),
        }
        | prompt
        | llm
        | StrOutputParser()
    )
    return rag_chain

# ==================== 第四步:运行交互式问答 ====================
if __name__ == "__main__":
    # 1. 加载文档
    chunks = load_and_split_docs(DOCS_DIR)
    # 2. 构建向量库
    vectorstore = build_vectorstore(chunks)
    # 3. 构建 RAG 链
    rag_chain = build_rag_chain(vectorstore)

    # 4. 交互式问答
    print("\n" + "=" * 50)
    print("🤖 RAG 知识库问答系统已启动(输入 exit 退出)")
    print("=" * 50)

    while True:
        query = input("\n你:").strip()
        if query.lower() in ["exit", "quit", "q"]:
            print("再见!")
            break
        if not query:
            continue

        response = rag_chain.invoke(query)
        print(f"\nAI:{response}")

示例展示:

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐