M004_基于LangchainRAG的银行智能客服系统设计与开发做银行智能客服这个项目前后折腾了三个多月。刚接到需求那会儿团队里不少人第一反应是“这不就是接个大模型API嘛套个Prompt不就完事了”。真做起来才发现银行场景和互联网To C客服完全是两码事——知识库更新频率、答案准确性要求、合规审计约束、私有化部署限制每一项都在逼着你放弃“裸奔大模型”的偷懒路线。最终落地选型是LangChain RAG检索增强生成用向量检索把银行内部的业务制度、产品说明、操作手册先捞出来再让大模型基于检索结果组织回答。这套方案解决的核心痛点就是让模型在不额外微调的前提下尽量少“编答案”把答案来源钉在内部知识库上。适合正在做企业级客服、知识问答类项目或者刚接触RAG但想了解生产环境落地细节的开发者参考。1. 整体设计与方案选型拆解1.1 为什么是RAG而不是微调项目启动前我们内部做了一轮技术选型讨论争论最集中的就是RAG和微调两条技术路线到底怎么选。当时团队里有人认为银行场景专业术语多、问答格式要求严格微调才能让模型真正“懂行”。但仔细分析后发现银行的业务知识有一个关键特点更新极其频繁。存款利率可能按月调整理财产品说明书隔一阵就换一批信用卡积分规则说改就改这些内容如果用微调方式跟进意味着每次业务变更都要重新走一遍数据准备、训练、评估、上线的全流程一个版本没跑完下一波变更又来了根本追不动。RAG的优势恰恰在于把“知识”和“推理”解耦。知识放在向量数据库里随增随改模型只需要负责理解问题和组织语言。业务侧改一份文档索引更新一下客服的回答立刻就能跟上不需要重新训练模型。从项目排期看微调一条路走通至少需要GPU资源、训练工程师、数据标注人力而RAG的工程重点在数据处理和检索链路团队现有的后端开发能力就能覆盖。成本上RAG因为不需要为每个业务场景单独训练模型长期维护成本也更可控。当然RAG也不是银弹。如果你的场景对格式模板要求极其死板比如必须按固定字段输出报表或者领域知识极度封闭、公开语料完全覆盖不到微调仍然是必要的补充。我们最终选了个折中路线底层基座模型不做微调但对检索出的知识片段做了大量后处理规则用工程手段把“格式合规”这件事兜住。这个思路后面在回答策略章节会详细展开。1.2 系统整体架构与技术栈整个系统按模块划分大致可以拆成五层接入层对接银行的在线客服渠道统一接收用户问题同时做渠道适配和会话管理问答编排层基于LangChain的Agent和Chain机制负责任意路由、检索触发、回答生成的组织知识处理层涵盖离线文档解析、清洗、切片、向量化、入库的全流程检索增强层向量检索 关键词检索的双路召回配合重排模型做精排服务与审计层负责接口封装、权限校验、日志留存和回答溯源技术选型上LangChain作为编排框架承担了Chain组织、Prompt管理、文档加载器和向量存储对接的职责。向量数据库选的FastAPI Faiss的组合——起初我们评估过Milvus和Elasticsearch但考虑到项目初期数据量在几十万片级别Faiss单机部署完全够用而且不需要额外维护分布式集群。后来数据量增长后迁移到了Milvus接口层面因为LangChain做过封装迁移成本并不高。Embedding模型用的是国产的开源embedding模型具体地说是从 HuggingFace 下载的中文向量模型选择它主要是因为它对中文金融术语的支持效果好并且支持私有化部署不依赖外部API调用。检索链路分两条路并行一条是向量检索用Embedding模型把用户问题转成向量后在Faiss里做相似度搜索另一条是BM25关键词检索用来兜底一些专业术语和精确匹配场景。两路结果汇合后进入重排阶段——这也是我们在实践里发现对最终回答质量影响最大的一个环节具体做法后文会详细写。1.3 为什么用LangChain做编排市面上有不少RAG框架比如LlamaIndex也做得不错但结合银行项目的实际情况LangChain有两个不可替代的点。第一是它的抽象层次刚好合适从文档加载器、文本分割器、向量存储到Chain每个环节都留了接口让你替换自己的实现而不是把整套方案焊死。比如官方默认的文本分割器对中文支持一般我们直接自己写了一个针对银行文档结构的分割逻辑通过LangChain的TextSplitter基类接入其他链路代码一行没改。第二是它的工具生态在检索问答这个场景上最成熟。像RetrievalQA、ConversationalRetrievalChain这些高层封装配合ChatPromptTemplate做Prompt管理开发效率确实高。当然LangChain的版本迭代很快API经常变动我们在项目里做了一个策略核心业务逻辑自己包一层Service不直接散落调用LangChain的API这样后续升级LangChain版本时改动可控。2. 银行知识库建设与语料处理2.1 数据来源与特征分析知识库建设是RAG项目里最脏最累但又最决定上限的环节。数据不行后面检索、Prompt整得再花哨都白搭。银行客服涉及的知识来源比一般企业复杂得多我们第一期整理下来主要有这几类产品制度类文档存款、贷款、理财、信用卡等产品的业务制度和操作规程多为Word和PDF格式经常有大段法律条文式表述操作手册类内容网银、手机银行、自助设备的操作指引往往带有步骤编号和界面截图说明高频问答对客服团队过往积累的标准问答库结构相对规整但字段格式不统一公告与通知利率调整、系统升级、产品停售等时效性强的信息对新鲜度要求高这些数据有一个共同的问题格式混乱。同一个产品在不同文档里可能表述不一致有的文档扫描件夹杂在Word里有的PDF翻录后文字带大量空格和错位。如果原样入库检索效果会非常差。我们统计过第一版直接入库后部分问题的检索召回准确率不到六成根因就是源头数据噪声太大。2.2 文档清洗与切片策略清洗阶段我们沉淀了一套固定流程。首先是格式统一所有Word和PDF转成纯文本扫描件走OCR服务识别识别结果里常见的“囗”“口”混用、断行错乱用规则批量修一遍。然后做内容去重同一份制度文件可能存在多个版本按发布时间保留最新同时把附件、落款、历史修订记录这些页面噪声剔除。切片是知识库质量的关键一步也是很多人容易忽视的地方。我们踩过的坑是直接用固定字符数切分比如每500字一刀切结果一个完整的产品规则被掰成两三截检索时经常只召回其中一部分回答就残缺不全。后来我们改用“结构感知切分”大致逻辑是先识别文档的段落结构针对银行制度文件里常见的“第X章”“第X条”“一、二、三”层级做标记切分时优先保持章节和条目的完整性一个条目内容过长时才按段落二次切分相邻切片增加少量重叠overlap避免语义边界被切断语义完整性保住了检索的命中率明显改善。另外切完的每一片都保留元数据包括来源文档名、章节路径、更新时间这些信息在回答溯源和权限过滤时都要用到。2.3 Embedding模型选型与向量化Embedding是整个检索链路的地基选型时对比了市面上几款主流中文Embedding模型。测试集是从银行客服真实对话里抽样出的两百条问题按“能否检索到正确答案所在的文档片段”这个指标卡出来的结果效果排名前列的分别是BGE-M3、BGE-large-zh-v1.5和M3E。最终选了BGE系列模型理由是它在中文长文本上的表现稳定而且对金融术语的语义理解明显比其他通用模型强。向量化过程中还有几个工程细节值得说。第一是查询侧和文档侧可以使用不同的向量化策略文档入库时用完整的描述性语句生成向量而用户查询往往很短直接用原句向量化就行不需要额外做Query扩展。第二是向量维度与检索性能的权衡BGE-large-zh-v1.5是1024维在Faiss里索引两百万条向量毫无压力但当数据量再上一个量级降维或者换用M3E这类768维模型可以作为备选方案。第三是增量更新每天凌晨定时扫描新增和变更的文档增量向量化后更新索引保证知识库新鲜度。3. 基于LangChain的问答链路实现3.1 会话管理与问题理解银行客服场景的对话和单轮问答最大的区别在于上下文依赖。用户经常先问“信用卡怎么申请”接着问“需要什么材料”这个问题单独看是不完整的必须结合上一轮才能理解。我们基于LangChain的ConversationalRetrievalChain做扩展实现了一个轻量级的会话管理模块。具体做法是把历史对话压缩成两部分的记忆一部分是原始对话记录用于大模型理解指代关系另一部分是系统抽取出的“当前任务摘要”防止多轮之后上下文太长把关键信息冲掉。两个部分拼接后作为问题理解的上下文输入再做检索。这里有一个经验不要把全部历史对话都塞进Prompt一方面浪费Token另一方面检索时的噪声也更大通常保留最近三到五轮就够了更早的内容通过摘要保留核心意图。遇到需要个人化回答的问题比如查积分、查账单系统会抽取用户ID拿到会话上下文中存储的账户信息和权限范围再决定回答策略。涉及具体账户金额的问题我们不会让大模型直接回答而是触发后端接口实时查询后把结果按模板组装成答案——这也是银行场景里对准确率要求最严格的一类问题。3.2 Prompt设计与LLM调用封装Prompt设计在RAG链路里的重要性怎么强调都不过分。我们第一版Prompt非常简单大概就是“基于以下资料回答用户问题”结果模型经常把检索出来的无关信息也揉进答案甚至自己发挥补充一些知识库没有的内容。后来经过多轮迭代沉淀出一套相对稳定的Prompt结构system_template 你是银行智能客服助手请严格按照以下规则回答用户问题 1. 只能依据“参考资料”中的内容回答问题严禁编造参考资料中不存在的信息。 2. 如果参考资料不足以回答用户问题请直接回复“抱歉这个问题我暂时无法回答”不要尝试猜测。 3. 如果用户问题涉及账户、额度、利率等个人化信息提示用户通过人工客服或自助渠道查询。 4. 回答时保持简洁、专业避免使用模型自身经验补充无关内容。 参考资料 {context} 这套Prompt看起来简单但背后的设计是有讲究的。第一点“严禁编造”实际上是给模型划了边界配合“无法回答就直接说”能有效把回答的幻觉率压下来这点后面评测章节有数据支撑。第二点是针对银行合规要求的个人化查询必须转人工防止模型基于模糊数据给出错误账户信息。Prompt里的{context}就是检索重排后选出的最相关文档片段通常取三到四段每段限制在三百字左右太长会让模型抓不住重点太短则信息可能不够。LLM调用层我们做了统一封装通过LangChain的llm接口代理底层可以切换不同的基座模型。第一期用的开源模型参数量级别大概在7B到14B之间部署在内网GPU服务器上。对延迟的要求是单次回答控制在3秒以内因此Prompt的Token数做了严格控制检索结果过多时先做一遍截断和去重再进入模型。3.3 检索增强的完整编排整个问答编排的核心代码结构大致是这样的# 向量检索 vector_retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 10} ) # 关键词检索 keyword_retriever BM25Retriever.from_documents(documents) # 双路召回合并 ensemble_retriever EnsembleRetriever( retrievers[vector_retriever, keyword_retriever], weights[0.7, 0.3] ) # 重排 compressor CrossEncoderReranker( model_namebge-reranker-large, top_n4 ) # 组装问答链 qa_chain RetrievalQA.from_chain_type( llmllm, retrievercompress_retriever, chain_typestuff, return_source_documentsTrue )EnsembleRetriever做双路召回合并权重配比上向量检索占七成、关键词检索占三成这个比例是在两百多条测试问题上逐步调出来的。纯向量检索对近义表达和口语化问题更友好比如用户说“我卡里钱少了”靠语义能关联到“账户余额变动”相关文档但遇到“U盾”这种专业名词向量召回反而不如关键词精确匹配。合并后的结果再用交叉编码器重排这里用的模型专门针对“文档片段与问题的相关性”做打分效果比向量相似度再排序要准不少。chain_type我们选的stuff意思是把检索结果都塞进Prompt一起让模型回答。这个模式在小规模检索结果下效果最好因为模型能看到全部上下文不会因为遗漏某一篇而产生偏差。如果检索片段数量太多可以改用map_reduce或者refine模式但回答质量和延迟都会有所牺牲。项目一期检索结果控制在四段以内stuff完全够用。4. 检索质量优化与效果调优实践4.1 双路召回与重排的实战效果检索质量是RAG系统回答准确率的前置条件检索都找不到正确内容模型再聪明也无济于事。我们在调优过程中记录了一组数据第一版单独用向量检索时两百道测试题中有大约七成能正确命中答案所在的文档片段加上BM25关键词召回做合并后命中率提升到八成左右再加上重排模型精选Top结果最终“答案准确率”稳定在九成以上。这个提升链条说明一个道理每一层优化都是在补上一层漏掉的东西。向量检索解决语义相似问题但有专业术语时不灵关键词检索解决精确匹配问题但口语化表达不灵两者合并覆盖的面更全但多路召回会引入噪声把不相关但字符相似的内容混进来。重排模型就是干这个活的把两路结果合并后统一做相关性打分低质量的片段在最后一步被过滤掉。重排模型的选择上我们用了交叉编码器架构的专用重排模型。它的特点是把问题和文档片段拼接在一起输入模型可以捕捉更细粒度的语义匹配比向量相似度这种“先各自编码再算距离”的方式更准。代价是推理速度慢所以只对双路召回后的少量候选十到二十条做重排而不是在全量索引上做这样精度和性能都能兼顾。4.2 问题改写与查询扩展银行客服场景里用户提问的口语化程度比我们预想的要高得多。比如用户说“我那个贷款为啥没批下来”系统如果直接拿这句话去检索向量机虽能匹配到一些相关文档但准确率不太稳定。我们的解决方案是在检索前加一个“问题改写”步骤让大模型把口语化问题转成更正式的检索式表达。rewrite_prompt 请将用户的问句改写为适合知识库检索的正式查询语句。 要求保留核心意图去掉口语化表达补充必要的业务术语。 例如 用户问我那个贷款为啥没批下来 改写为个人贷款审批未通过原因 用户问信用卡怎么提额快 改写为信用卡额度提升方法 用户问{question} 改写为 这一招对检索质量提升非常明显。主要原因是Embedding模型训练的语料偏向正式文本口语化表达在向量空间里的分布和正式术语不在一个区域改写后再检索更容易命中知识库里那些“一本正经”的制度文档。当然问题改写会引入额外一拍延迟我们只在检索前做一次实测增加的时间大约几百毫秒在可接受范围内。4.3 针对银行专业场景的检索调优通用RAG教程教的是标准做法真落到银行场景有几处要单独调。一是同义词和简称的问题“对公账户”和“单位银行结算账户”指的是同一件事知识库里可能两种表述都有但检索时不一定都能召回。我们的办法是在索引写入时额外扩展一组同义词字段把文档涉及的核心业务实体别称一起存进去检索时多一个匹配通道。二是时效性加权。银行文档里“现行利率”“最新优惠”这类信息知识库里旧文档和新文档可能同时存在纯相似度检索可能会召回旧版本。我们的做法是给切片元数据里增加发布时间字段重排打分时做轻微的时间衰减加权让新文档排名略靠前避免回答“已经过期的存款利率”这种低级错误。三是安全过滤前置。部分文档属于内部制度只有特定角色权限的客服人员才能查看在检索阶段就要根据当前用户的权限范围对候选文档做过滤而不是等回答生成后才发现越权。这个操作要在检索之前做因为一旦包含敏感内容的片段被塞进了Prompt即使模型不直接输出也存在数据泄露的风险。5. 评测体系与闭环迭代5.1 分类评测指标设计RAG系统上线前如果只靠人工点几条问题看看效果基本等于没测。我们基于银行客服的实际场景搭建了一套分类评测体系主要分三个维度答案准确性、拒答合理性和格式合规性。答案准确性模型回答的核心信息是否和知识库原文一致是否出现事实错误或编造拒答合理性当知识库信息不足时模型是否正确拒答而不是强行给答案格式合规性涉及金额、日期、利率等数字时格式是否正确是否存在“大概”“左右”等模糊表达评测集是从真实客服日志里抽样出的三百条问题覆盖高频咨询、边缘案例和易错场景每轮迭代后在这个固定集上跑一遍记录三个维度的通过率变化。这样每次改动Prompt还是重排逻辑都能看到明确的量化反馈而不是凭感觉说“好像效果好了点”。5.2 评测结果与调优过程第一版系统跑完评测答案是“惨不忍睹”。答案准确率不到七成拒答率又过高——有一半以上的问题模型都回复“无法回答”里面相当一部分其实是知识库里有答案但检索没找出来。当时对照bad case一个个分析归纳出了几类主要问题第一类是切分不合理导致的召回失败产品规则被切碎后检索命中的只是一个残缺片段模型看了半天形不成完整答复只好拒答。这直接推动了章节2里结构感知切分策略的落地。第二类是Prompt边界不清晰模型对“哪些能答、哪些不能答”的判断摇摆造成拒答率偏高。我们把Prompt里“无法回答”的触发条件写得更具体比如“仅在参考资料完全未提及的情况下拒答”通过率明显改善。第三类是重排把正确答案挤掉了有时候重排模型偏好语义更流畅的段落反而把包含明确答案的段落排到后面后来通过调整Top N数量和重排权重缓解了这个问题。三轮迭代后答案准确率从六成多提到了九成左右拒答合理率也恢复了正常区间。这个过程让我深刻体会到一件事RAG项目的调优重心大部分时间不在模型上而在数据和检索链路上模型本身反而不用怎么动。_5.3 线上监控与人工反馈闭环系统上线后评测不能停但要换个形式。线上运行会不断产生新的提问类型知识库也可能出现新的盲区。我们设计了一个“bad case回流”机制:客服系统里增加了一个反馈按钮当用户对回答不满意或转人工时这条会话自动打标进入待分析队列。每周抽取一批bad case人工标注出问题原因是检索漏召回、重排排错还是知识库缺内容汇总后进入优化清单。这个闭环是系统持续变好的关键。比如上线第二周就发现用户经常问“营业网点在哪里”这类问题和知识库里的文档内容关联度低检索效果很差。后来我们在知识库里补建了一个网点和营业时间的数据源对应问题从bad case里慢慢消失。没有这个反馈闭环很多问题你根本不知道用户在问什么系统迭代就成了闭门造车。6. 部署实践与避坑总结6.1 私有化部署与资源规划银行场景的信息安全要求决定了系统必须私有化部署所有模型和数据都在内网环境不能调用外部API。整个系统包含四大块资源GPU服务器跑Embedding模型和LLM推理、CPU服务器跑检索服务和后端接口、向量数据库存储、对象存储保存原始文档和处理后的文本切片。GPU服务器的显存规划要提前算好。Embedding模型参数量不大CPU也能跑但我们实测GPU推理速度快三四倍高峰期检索并发上来后CPU方案会明显拖慢响应所以还是给Embedding模型单独分了一块GPU。LLM推理选择的基座模型参数量约14B用FP16量化部署时大约需要30GB显存单张48GB显卡可以承载。这里给个计算经验推理显存大约等于模型参数量乘以2倍FP16再留出KV Cache的余量不用卡得太死。向量数据库初期用Faiss单机部署完全够用索引加载到内存后检索是毫秒级。但要注意增量更新的策略我们遇到的问题是频繁更新索引会导致内存碎片化检索偶尔卡顿后来改成“夜间全量重建 日内增量缓存”的模式才稳定下来。6.2 内容安全与合规审计银行对客服回答的合规性要求极其严格该系统架构中专门设计了内容安全过滤和合规审计两层机制。第一层是回答内容过滤模型生成答案后增加规则引擎检测敏感信息和不合规表达比如不承诺“保本保息”不使用“绝对没问题”这类话术涉及投诉建议会自动转给人工处理。第二层是全链路审计日志从用户问题、检索命中的文档切片、模型生成的原始回复到最终发送给用户的答案全程记录下来留待后续合规审查和溯源。在合规审计方案之外还有一项独立的事实一致性校验环节。对涉及金额、时间、利率等关键数字的答案系统增加了一个可用API层调用的校验服务将模型回复中的关键数字和检索到的原文做比对不一致时触发告警并转人工。这一层校验对降低风险帮助很大也是RAG系统在银行场景里能走通的关键因素。6.3 踩坑清单与实操建议把项目里印象比较深的几个坑列出来希望对后来者有帮助。坑一Tokenizer差异导致的切片计数失真。我们最初用字符数控制切片长度后来发现大模型Tokenize中文时不同模型的Token化比例不一致导致“看起来长度合适”的切片输入模型后Token数超限。后来所有切片长度统一改用Token数计算按模型实际Tokenizer的容量定上限这类问题就再没出现过。坑二文档去重不彻底导致的回答漂移。同一份产品制度被多个部门上传过内容略有差异检索时多个版本一起命中模型有时综合出前后不一致的回答。现在入库前会用SimHash对切片做一轮去重相似度超过阈值的只保留最新版。坑三LangChain版本升级带来的接口变更。项目期间LangChain从旧版本升到新版本不少API都变了。我们的应对是前面提过的Service隔离策略业务代码不直接调LangChain接口统一收口封装升级时只改封装层。坑四高峰期检索超时。并发量上去后检索链路偶尔出现超时原因是向量检索做了全量扫描内存索引查询时间不稳定。后来加了缓存层把高频问题直接缓存答案实测大部分重复问题的响应时间降到几百毫秒压力显著缓解。坑五Embedding模型更新后向量空间不一致。中期换过一次Embedding模型版本结果新旧向量在同一个索引里语义空间断裂检索效果时好时坏。教训是Embedding模型版本一旦确定就尽量保持稳定如果必须升级需要全量重新向量化再重建索引。我个人在整个项目里最大的体会是RAG系统真正难的并不是LangChain怎么用、向量库怎么配而是数据质量和评测闭环这两件“笨功夫”。第一版系统从搭建到跑通只花了两周但后续六周时间几乎都花在清洗数据、调检索、看bad case、改Prompt的循环里。效果的自然语言真实提升正是这些看似不起眼的重复劳动一点一点堆出来的。如果你正准备做类似的项目我的建议是先把知识库的数据治理做好先把评测集建起来再去追求更花哨的模型和框架。地基打牢了上面盖什么都稳。
阅读完成 · 觉得有帮助?