
在人工智能落地的新阶段,大语言模型(LLM)的“幻觉”问题和私有数据无法实时接入的痛点,让RAG(检索增强生成)技术成为了企业智能化转型的最优解。与其让模型凭空“编造”答案,不如先让它去企业的知识库中“查阅”资料,再基于资料进行总结归纳。然而,自研RAG系统往往面临“Demo跑得通,上线就卡顿”的窘境。本文将带你深入RAG系统的完整架构,通过核心代码拆解和实战优化思路,构建一个稳定、高效的企业级智能问答系统。
一个完整的RAG系统包含两个核心阶段。离线索引阶段负责将企业分散的PDF、Word、数据库等文档进行清洗、分块、向量化,并存入向量数据库。在线查询阶段则将用户的问题向量化,在数据库中进行语义检索,召回相关文本片段后,连同原始问题一起组装成Prompt交给大模型生成最终答案。这两者的协同决定了系统的下限。
在初期验证阶段,我们可以利用LangChain和Chroma向量数据库快速搭建原型。以下代码展示了从文档加载、文本切分到向量检索的完整链路:
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
# 1. 文档加载与智能分块(解决上下文断裂问题)
loader = DirectoryLoader('./knowledge_base', glob='**/*.md')
docs = loader.load()
# 推荐使用递归分割器,按段落、句子层级切分,chunk_size建议500-800
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50, # 重叠区域防止语义丢失
separators=["\n\n", "\n", "。", "!", "?", ";"]
)
chunks = text_splitter.split_documents(docs)
# 2. 向量化与存储
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
vectorstore = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")# 3. 构建检索生成链
from langchain.prompts import ChatPromptTemplate
from langchain_community.chat_models import ChatDeepSeek
# 设计“负向约束”Prompt,强制模型基于上下文回答
prompt = ChatPromptTemplate.from_template("""
你是一个严谨的企业知识助手。请严格基于以下【上下文】回答问题。
如果上下文中没有提到相关内容,请直接回复“知识库暂未收录该信息”,严禁编造。
【上下文】
{context}
【问题】
{question}
回答:""")
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
llm = ChatDeepSeek(model="deepseek-chat", temperature=0.1)
# 此处省略LCEL链式调用,实际生产需构建 RunnablePassthrough上述基础代码虽然跑通了流程,但面对海量数据时,召回精度低和响应延迟高是两大痛点。针对这些问题,我们可以从以下三个维度进行优化:
1. 混合检索(Hybrid Search)与重排序(Rerank) 纯向量检索容易丢失关键词精确匹配(如产品型号、合同编号)。生产环境建议采用Elasticsearch + 向量库的混合策略,召回候选集后再利用精排模型(如BAAI/bge-reranker)进行二次打分。
# 伪代码示例:重排序优化
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
reranker = CrossEncoderReranker(model_name="BAAI/bge-reranker-base")
# 先召回Top 20,再重排序截断Top 5,精度可提升约20%
compressed_retriever = ContextualCompressionRetriever(
base_compressor=reranker,
base_retriever=base_retriever
)2. 语义分块与上下文增强 固定字数切分(如500字硬切)极易切断完整论述。优化方案是引入语义分割器,根据文档的Markdown标题、段落结束符进行动态切分,并在分块元数据中保留章节标题。当检索到该块时,将章节标题作为“上下文锚点”一并送入大模型,能显著提升回答的逻辑连贯性。
3. 多级缓存与异步处理 对于高频提问(如公司考勤制度),引入语义缓存(GPTCache),对于完全相同或高度近似的问题直接返回缓存结果,绕过向量检索和LLM生成环节。经实测,该策略可降低约60%的平均响应延迟。
系统上线并非终点。建议引入RAGAS评估框架,对检索结果的“相关性”和生成结果的“忠实性(Faithfulness)”进行自动化打分。通过收集用户的反馈数据(点赞/点踩),持续优化分块策略和Prompt模板,形成数据飞轮。
构建RAG系统绝不仅仅是“调用几个API”那么简单,它是一场涉及数据清洗、检索策略、Prompt工程和系统架构的综合性工程。从基础的向量检索起步,逐步引入混合搜索、重排序和缓存机制,你的自研问答系统才能从“玩具”进化为真正可靠的生产工具。希望本文的架构思路与代码实践,能为你的企业AI落地之路提供清晰的地图。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。