RAG系统五层架构设计与LangChain工程实践
2026/9/14 6:44:02 网站建设 项目流程

1. 什么是RAG?它不是“给大模型喂资料”那么简单

RAG,全称Retrieval-Augmented Generation(检索增强生成),最近两年在工程落地场景里被反复提起,但很多人一上来就把它理解成“把PDF扔进系统,让AI回答问题”——这就像说“会拧螺丝就是汽车工程师”一样,表面没错,实则漏掉了整个底盘设计、动力匹配和安全冗余。我带过6个政务知识库项目,从区级政策问答到省级法规智能解读,RAG从来不是技术选型的终点,而是系统稳定性的起点。核心关键词RAG、LangChain、LCEL、python、parser,每一个都不是孤立存在:RAG是目标,LangChain是当前最成熟的工程脚手架,LCEL(LangChain Expression Language)是让链路可读、可测、可维护的语法糖,python是实现载体,parser则是连接非结构化数据与向量世界的“翻译官”。它解决的不是“能不能答”,而是“答得准不准、快不快、稳不稳、查得清”。比如某市12345热线知识库上线后,市民问“新生儿落户需要哪些材料”,旧系统返回三段模糊政策条文,新RAG系统直接定位到《XX市户籍管理实施细则》第十七条第二款,并提取出“出生医学证明原件+父母身份证复印件+户口本原件”三项明确清单,响应时间从8.2秒压到1.7秒,人工复核率下降63%。这不是调用一个API就能做到的,它背后是一整套数据清洗、分块策略、嵌入质量、召回排序、上下文拼接、幻觉抑制的闭环。如果你正打算用Dify或FastGPT搭个知识库页面,先别急着点“部署”,花15分钟搞懂RAG底层逻辑,能帮你避开80%的线上故障。

2. RAG基础架构拆解:为什么必须分五层设计

2.1 数据层:Parser不是“读文件”,而是语义切片的艺术

很多人以为Parser就是用PyPDF2读PDF、用docx2python读Word,然后按固定字数切块——这是RAG项目崩盘的第一张多米诺骨牌。我接手过一个政务项目,原始材料是2000页《XX省营商环境白皮书》,用简单按512字符切块后,embedding模型把“第三章第二节‘政务服务标准化’”和“附录B‘高频事项办理时限表’”强行拉进同一向量空间,导致用户问“企业开办要多久”,系统召回的是章节标题而非具体表格数据。真正的Parser必须做三件事:结构识别→语义锚定→上下文保全

  • 结构识别:用pdfplumber解析PDF时,不只取text,还要抓取font size、bold标记、page number、section header层级;处理Word文档时,用python-docx读取paragraph.style.name,区分“标题1”“正文”“表格文字”;对网页HTML,用BeautifulSoup提取

    标签+ 内容块,而非raw text。

  • 语义锚定:对每个文本块打上元数据标签,例如{"source": "白皮书_2023.pdf", "chapter": "第三章", "section": "3.2", "type": "policy_clause"},这些字段后续会参与rerank加权。
  • 上下文保全:绝不能把“第十二条:……(此处省略500字)……第十三条:申请人应提交以下材料:1. 营业执照副本;2. 法定代表人身份证……”切成两段。我们用正则r'第[零一二三四五六七八九十百千]+条[::]\s*'做段落边界检测,确保条款完整性;对表格,用pandas.read_html()转DataFrame再序列化为markdown table字符串,保留行列关系。
    实操中,我坚持用langchain.document_loaders的子类重写loader,而不是直接调load_and_split()。比如针对政府公文,自定义GovDocLoader,内置对“依据”“现批复如下”“特此通知”等公文特征词的识别逻辑,自动剥离发文机关、文号、日期等非正文信息。parser环节投入2天,能减少后期70%的bad recall问题。

2.2 检索层:Embedding不是“选个模型就行”,而是精度与速度的平衡术

Embedding模型选型常被简化为“用bge-large还是m3e”,但实际影响远不止准确率。去年某税务知识库项目,初期用bge-reranker-base做rerank,QPS仅12,而业务要求峰值QPS≥80。我们最终切换为bge-m3(支持multilingual+dense+sparse混合检索),配合Faiss的IVF_PQ索引,QPS提升至113,同时MRR@10从0.68升到0.79。关键不在模型本身,而在向量化管道的设计

  • 分块策略决定embedding质量上限。我们测试过三种方式:
    • 固定长度(512字符):MRR@10=0.52,大量条款被截断;
    • 语义分块(使用langchain.text_splitter.RecursiveCharacterTextSplitter,设置chunk_size=256, chunk_overlap=64):MRR@10=0.61,但小条款(如“第十五条:本办法自发布之日起施行”)被淹没;
    • 规则驱动分块:对政策文件,按“条款”切分;对操作指南,按“步骤”切分;对FAQ,按“Q&A对”切分。用正则预处理后,MRR@10达0.74,且chunk平均长度更均衡(180±42字符)。
  • 向量维度影响存储与检索效率。bge-large输出1024维,Faiss索引体积约1.2GB/百万向量;bge-m3输出1024维dense+256维sparse,但通过Faiss的IndexHNSWFlat+IndexIDMap组合,实际内存占用降低37%,且支持hybrid search。
  • Embedding服务部署必须考虑冷启动。我们用ONNX Runtime量化bge-m3模型,推理延迟从320ms降至89ms(RTX 4090),并用Redis缓存高频query的embedding结果,缓存命中率68%,进一步摊薄均值延迟。

提示:不要迷信SOTA模型。政务场景中,bge-zh-v1.5在中文法律术语上比bge-m3更稳,但m3的hybrid能力对跨文档关联(如“社保缴纳”链接到“医保报销”“个税抵扣”)有不可替代性。选型前务必用真实业务query集跑A/B测试,指标看MRR@10+P95延迟+内存占用三维度。

2.3 召回层:单路召回是陷阱,多路召回才是生产标配

“rag多路召回”成为热搜词绝非偶然。单一向量召回在复杂查询下必然失效。典型案例如用户问:“2024年小微企业所得税优惠,跟2023年比有什么变化?”——这需要同时召回:

  • 语义召回:匹配“小微企业 所得税 优惠 变化”向量相似度;
  • 关键词召回:用Elasticsearch匹配“2024”“2023”“所得税”“优惠”布尔组合;
  • 图谱召回:从政策知识图谱中找出“小微企业所得税优惠”节点的版本变更边;
  • 时效召回:过滤发布日期在2023-01-01之后的文档。
    我们采用LangChain的RunnableParallel构建多路召回器:
from langchain_core.runnables import RunnableParallel retriever = RunnableParallel( semantic=retriever_vector, keyword=retriever_es, graph=retriever_neo4j, time=retriever_time_filter )

但关键在融合策略:不是简单去重合并,而是按业务权重加权。例如对“政策咨询”类query,semantic权重0.4、keyword权重0.3、graph权重0.2、time权重0.1;对“办事指南”类,keyword权重提至0.5(用户常输入“怎么办理”“流程”“步骤”等短词)。融合后用Cross-Encoder(如bge-reranker-base)做最终重排,MRR@10提升22%。

注意:多路召回不是堆砌组件。ES关键词召回必须配置同义词库(如“个税”→“个人所得税”“所得税”),否则“个税减免”查不到“个人所得税优惠政策”;图谱召回需预置实体关系,不能依赖LLM实时抽取——线上延迟扛不住。我们用spaCy训练NER模型识别“政策名称”“条款编号”“生效日期”,离线构建图谱,召回延迟<50ms。

2.4 生成层:LCEL不是语法糖,而是可观测性的生命线

LCEL(LangChain Expression Language)常被当作“写链式调用的快捷写法”,但它真正的价值在于让LLM调用变成可调试、可监控、可灰度的函数。没有LCEL的RAG链路像黑盒:query进去,response出来,中间任何环节出错都只能靠日志猜。用LCEL重构后,每个组件都是独立runnable,支持:

  • 逐节点调试chain.invoke({"input": "新生儿落户材料"})→ 查看retriever.invoke()返回的chunks、prompt.format()生成的完整prompt、llm.invoke()的原始response;
  • 性能监控:用chain.with_config(configurable={"model": "qwen2-7b"})动态切换模型,配合Prometheus埋点,统计各节点P95延迟;
  • 灰度发布chain.with_config(configurable={"rerank_enabled": True})控制rerank开关,AB测试效果。
    我们政务项目的核心chain定义如下:
from langchain_core.runnables import RunnablePassthrough, RunnablePick from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 构建可调试链路 retrieval_chain = ( {"context": retriever | RunnablePick("documents"), "question": RunnablePassthrough()} | prompt | llm | StrOutputParser() ) # 关键:每个|操作符都是独立runnable,可单独测试 # retriever | RunnablePick("documents") → 验证召回质量 # prompt → 打印format后的prompt,检查上下文拼接逻辑 # llm → 替换为mock_llm验证超时/错误处理

实操心得:LCEL链路必须配合结构化输出解析。政务场景严禁LLM自由发挥,我们强制用pydantic BaseModel定义response schema:

class Answer(BaseModel): answer: str = Field(description="直接、简洁的答案,不超过100字") sources: List[str] = Field(description="引用的政策文件名及条款号,如['XX市户籍条例 第12条']") confidence: float = Field(description="0-1置信度,基于上下文支持度计算") parser = JsonOutputParser(pydantic_object=Answer) prompt = ChatPromptTemplate.from_messages([ ("system", "你是一名政务助手,请严格按JSON格式输出,字段必须完整"), ("user", "{question}\n\n参考信息:{context}") ])

这样LLM输出必为JSON,parser.parse()失败即触发fallback机制(返回“暂未找到相关信息”),避免幻觉答案流出。

2.5 评估层:不用人工评测,RAG系统永远在裸奔

90%的RAG项目缺评估层,结果就是上线后靠用户投诉发现问题。我们建立三级评估体系:

  • 离线评估:用历史工单构建test set(2000条真实query),指标包括:
    • 召回率(Recall@5):top5结果中含正确答案的比例;
    • 相关性(Relevance@3):人工标注top3结果的相关性(0-3分),计算平均分;
    • 答案准确性(Accuracy):LLM生成答案与标准答案的BLEU-4+ROUGE-L综合得分。
  • 在线评估:在prod链路中注入evaluator节点,对10%流量采样:
    • 记录retriever返回的chunks与llm最终引用的sources是否一致(检测幻觉);
    • 计算prompt中context token占比,>30%说明chunk过大,需优化分块;
    • 监控llmresponse中“根据XX文件”“依据第X条”等溯源表述出现频率,<50%即预警。
  • 业务评估:对接客服系统,统计“用户追问率”(首次回答后用户继续问“还有吗?”“具体怎么操作?”的比例),该指标下降15%才视为有效改进。
    去年某项目上线后,离线评估Accuracy达0.82,但在线发现23%的query中LLM引用了未召回的文档片段——根源是prompt模板中{context}变量被意外截断。没有在线评估,这个问题会持续数月。

3. LangChain实战:从零搭建可交付的RAG服务

3.1 环境准备:Python安装不是“下载exe点下一步”

“python安装教程”“linux系统安装python”是高频搜索词,但生产环境Python安装远不止版本选择。政务项目要求:

  • Python版本锁定:必须3.10.x(3.11+的asyncio变更影响LangChain 0.1.x稳定性);
  • 包管理隔离:禁用全局pip,强制用venv+requirements.in(pip-compile生成);
  • 二进制依赖预编译:Faiss、onnxruntime在CentOS 7上需预编译wheel,否则pip install耗时18分钟且常失败。
    我们的标准流程:
  1. 下载python-3.10.12-amd64.tar.xz(非官网源码,用pyenv提供的预编译包);
  2. pyenv install 3.10.12 && pyenv global 3.10.12
  3. python -m venv .venv && source .venv/bin/activate
  4. pip install pip-tools && pip-compile requirements.in
  5. pip install -r requirements.txt --find-links https://xxx.com/wheels/ --trusted-host xxx.com(私有wheel仓库)。

实操坑:CentOS 7默认glibc 2.17,而onnxruntime-1.18要求glibc 2.28。解决方案是下载onnxruntime-1.16.3-cp310-cp310-manylinux_2_17_x86_64.whl(兼容glibc 2.17),并用patchelf --set-rpath '$ORIGIN/../lib' onnxruntime.cpython-310-x86_64-linux-gnu.so修复路径。这个细节不处理,服务启动必报GLIBC_2.28 not found

3.2 核心代码:LangChain入门不是抄demo,而是理解组件契约

LangChain入门教程常教from langchain import OpenAI,但生产环境必须理解每个组件的输入/输出契约。以retriever为例,其invoke()方法必须返回List[Document],而Document必须含page_contentmetadata。我们封装的retriever基类:

from langchain_core.documents import Document from typing import List, Dict, Any class BaseRetriever: def __init__(self, vectorstore, k=5): self.vectorstore = vectorstore self.k = k def invoke(self, input: str, config: Dict[str, Any] = None) -> List[Document]: # 必须保证返回Document列表,且metadata含source/chapter等字段 docs = self.vectorstore.similarity_search(input, k=self.k) for doc in docs: # 强制补充业务元数据 if "source" not in doc.metadata: doc.metadata["source"] = "unknown" if "chapter" not in doc.metadata: doc.metadata["chapter"] = "unknown" return docs

同样,LLM组件必须满足invoke()返回strAIMessage,且支持stream=True。我们用vLLM部署qwen2-7b,封装为LangChain LLM:

from langchain.llms import BaseLLM from vllm import LLM, SamplingParams class VLLM_LLM(BaseLLM): def __init__(self, model_name: str): self.llm = LLM(model=model_name, tensor_parallel_size=2) self.sampling_params = SamplingParams(temperature=0.01, max_tokens=512) def _call(self, prompt: str, stop: List[str] = None) -> str: outputs = self.llm.generate(prompt, self.sampling_params) return outputs[0].outputs[0].text @property def _llm_type(self) -> str: return "vllm"

注意:LangChain的Runnable协议要求组件必须可序列化。vLLM实例含GPU tensor,不能直接pickle,因此_call方法中不保存llm实例,而是在每次调用时从全局变量获取——这是LangChain生产部署的隐藏规则。

3.3 LCEL链路:LangChain架构不是“链式调用”,而是状态流编排

LangChain架构常被误解为“把组件连起来”,但LCEL本质是状态流(State Flow)编排语言。每个|操作符传递的不仅是数据,还有执行上下文。我们政务项目的完整链路:

from langchain_core.runnables import RunnableBranch, RunnableLambda # 多路召回分支 retriever = RunnableBranch( (lambda x: "政策" in x["input"], policy_retriever), (lambda x: "办事" in x["input"], guide_retriever), default_retriever ) # 带fallback的生成链 generation_chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | llm | parser | RunnableLambda(lambda x: { "answer": x.answer, "sources": x.sources, "confidence": x.confidence }) ) # 最终链:支持流式响应 app = generation_chain.with_types(input_type=Dict[str, str])

关键点:

  • RunnableBranch根据query关键词路由到不同retriever,避免所有query都走重型向量检索;
  • RunnableLambda用于后处理,将pydantic对象转dict,适配前端JSON Schema;
  • with_types()声明input_type,FastAPI自动生成功能文档。
    实测对比:用传统SequentialChain写法,修改prompt需改3处代码;用LCEL,只需改prompt变量,其他组件完全解耦。

3.4 部署与监控:VSCode Python环境配置只是开发起点

“vscode python环境配置”是新手痛点,但生产部署需更深层控制:

  • 进程管理:用gunicorn+uvicorn部署FastAPI,worker数=CPU核心数×2,超时设为120s(应对长尾query);
  • 内存隔离:每个worker限制RSS内存≤2GB,OOM时自动重启;
  • 监控埋点:用langchain.callbacks.tracer启用LangSmith,追踪每个query的retriever耗时、llm token数、parser成功率;
  • 日志规范:结构化日志含request_idquery_hashretriever_kllm_model字段,便于ELK聚合分析。
    我们用Prometheus exporter暴露指标:
from prometheus_client import Counter, Histogram QUERY_COUNTER = Counter('rag_query_total', 'Total RAG queries') RETRIEVER_LATENCY = Histogram('rag_retriever_latency_seconds', 'Retriever latency') LLM_TOKENS = Counter('rag_llm_tokens_total', 'LLM output tokens') # 在retriever.invoke中 RETRIEVER_LATENCY.observe(time.time() - start_time) # 在llm._call中 LLM_TOKENS.inc(len(response.split()))

实操心得:LangSmith免费版仅保留7天trace,生产环境必须自建PostgreSQL存储。我们用langsmith-clientClient类重写persist_run方法,将trace存入本地PG,成本降低90%,且支持SQL关联分析(如“召回率低的query是否集中在某类政策”)。

4. RAG项目避坑指南:那些没人告诉你的硬核经验

4.1 Embedding陷阱:模型越大,不一定越好

“rag框架”“python安装”搜索背后,是大量开发者卡在embedding环节。常见误区:

  • 盲目追求large模型:bge-large在MTEB榜单SOTA,但在政务短句(如“退休人员医保如何续缴”)上,bge-base召回更准——因为large模型过拟合通用语料,对领域术语泛化弱。我们测试发现,bge-base在政策query上Recall@5比large高3.2%,且推理快2.1倍。
  • 忽略tokenizer一致性:retriever用bge-m3,但llm用qwen2,两者tokenizer不同。若直接用bge-m3的tokenize结果喂qwen2,会产生padding mismatch。解决方案:retriever输出text,llm自行tokenize,绝不传递token ids。
  • 向量归一化缺失:Faiss默认不做L2归一化,而cosine相似度要求向量单位化。必须在插入向量前vector = vector / np.linalg.norm(vector),否则相似度计算失真。这个bug导致某项目上线后,相同query的召回结果每天波动±15%,排查3天才定位。

4.2 Parser雷区:PDF不是文本,而是排版艺术品

“parser”作为核心关键词,其复杂度常被低估。政务PDF的典型问题:

  • 扫描件OCR噪声:某市政策文件是扫描PDF,Tesseract OCR识别出“第十二奈”(应为“第十二条”)、“营亚执照”(应为“营业执照”)。解决方案:用PaddleOCR替换Tesseract,其中文模型对印刷体识别准确率98.7%,且支持版面分析(区分文字/表格/图片)。
  • 页眉页脚污染:PDF每页含“XX市人民政府文件”页眉,简单去重会删掉正文中的相同短语。我们用pdfplumber的page.crop(...)裁剪可视区域,再用正则r'^第[零一二].*条[::]'检测条款起始,跳过页眉区域。
  • 表格跨页断裂:一页末尾的表格在下一页续表,parser若按页切分,表格被撕裂。用pdfplumber的page.extract_table()提取整表,再用pandas.DataFrame.to_markdown()转为结构化文本,保留行列关系。

4.3 LangChain vs LangGraph:不是替代关系,而是阶段演进

“langchain和langgraph的区别”是高频疑问,真相是:LangChain解决“怎么连”,LangGraph解决“怎么控”

  • LangChain适用场景:确定性流程(检索→拼接→生成),如政务问答、知识库查询;
  • LangGraph适用场景:状态机流程(需循环/条件跳转/人工干预),如“政策咨询Agent”:用户问“失业金怎么领”,Agent先召回政策,若用户追问“需要什么材料”,则触发材料检索子流程,再追问“在哪办”,则调用地理位置API。
    我们政务项目初期用LangChain,当接入“12345工单自动分派”需求时,因需根据回答置信度动态决定“直答”“转人工”“补充检索”,才升级为LangGraph:
from langgraph.graph import StateGraph, END from typing import TypedDict, List class GraphState(TypedDict): question: str context: List[Document] answer: str confidence: float next_action: str def retrieve_node(state: GraphState): docs = retriever.invoke(state["question"]) return {"context": docs} def generate_node(state: GraphState): result = generation_chain.invoke({"input": state["question"]}) return { "answer": result["answer"], "confidence": result["confidence"] } def decide_route(state: GraphState) -> str: if state["confidence"] > 0.8: return "answer" elif state["confidence"] > 0.5: return "supplement_retrieve" else: return "human_handoff" workflow = StateGraph(GraphState) workflow.add_node("retrieve", retrieve_node) workflow.add_node("generate", generate_node) workflow.add_conditional_edges( "generate", decide_route, { "answer": END, "supplement_retrieve": "retrieve", "human_handoff": END } )

经验:LangGraph不是LangChain的升级版,而是不同抽象层级。80%的RAG项目用LangChain足够,只有涉及多跳推理、人工协同、状态持久化的场景才需LangGraph。过早引入LangGraph会增加3倍调试成本。

4.4 性能瓶颈真相:90%的慢,不在LLM,而在IO

“rag技术”“python下载”搜索背后,是开发者对性能的焦虑。实测数据显示:

  • LLM推理耗时占比仅35%(qwen2-7b on A10),其余65%为:
    • 向量检索(Faiss IVF_PQ):28%;
    • 文档加载与解析(PDF→text):22%;
    • Prompt拼接与tokenize:10%;
    • 网络传输(client→server→LLM):5%。
      优化重点应是IO:
  • 文档预加载:将PDF解析结果存入Redis Hash,key为doc:{md5},field为text/chunks/metadata,ttl设为7天。解析耗时从1.2s降至8ms;
  • 向量缓存:对高频query(如“社保缴纳比例”“公积金提取条件”)的embedding结果缓存2小时,缓存命中率41%,整体P95延迟降33%;
  • 异步IO:用asyncio.gather并发执行retriever+ES+graph召回,而非串行,QPS从22提升至68。

最后提醒:不要用LangChain的AsyncRetriever,它只是包装了async/await,底层仍是同步阻塞IO。真正优化要深入Faiss的index.search_async()和Redis的aioredis客户端。

5. RAG项目落地 checklist:从代码到上线的21个关键动作

序号动作为什么重要我们的实践
1定义业务query集(≥200条真实工单)避免用合成数据评估,导致线上效果偏差从12345热线导出近3个月工单,去重后人工标注答案
2parser输出必须含source/chapter/section元数据rerank和溯源依赖元数据,缺失则无法加权自定义loader强制校验metadata字段,缺失则抛异常
3embedding模型必须用业务query微调通用模型对政策术语理解弱用LoRA在bge-base上微调,epochs=3,learning_rate=2e-5
4向量数据库必须开启L2归一化cosine相似度计算前提Faiss中index = faiss.IndexFlatIP(d)→ 改为faiss.IndexFlatL2(d)
5retriever返回Document列表长度必须≤kLangChain内部有len()判断,超长触发异常在retriever.invoke后return docs[:k]
6prompt中context必须用{context}占位符避免字符串拼接导致token溢出用ChatPromptTemplate,自动处理truncate
7LLM输出必须用JsonOutputParser约束防止幻觉,保障结构化定义pydantic schema,parser.parse()失败则fallback
8部署必须用gunicorn+uvicorn组合单uvicorn无法利用多核gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
9每个API端点必须带request_id全链路追踪基础FastAPI middleware注入uuid4
10Redis缓存key必须含version前缀模型更新后缓存自动失效cache.get(f"emb:v1:{query_hash}")
11日志必须结构化(JSON格式)ELK聚合分析必需用structlog,字段含service/level/request_id/duration_ms
12Prometheus指标必须暴露retriever/llm/prompt三类延迟定位瓶颈环节RETRIEVER_LATENCY/LLM_LATENCY/PROMPT_LATENCY
13测试必须覆盖fallback路径网络超时、模型OOM等异常场景pytest mock requests.post,返回503
14Docker镜像必须multi-stage构建减少攻击面build stage装编译依赖,final stage只含runtime
15环境变量必须加密存储API Key等敏感信息用AWS Secrets Manager,启动时注入
16CI/CD必须包含离线评估代码合并前拦截效果退化GitHub Action跑test_set,Accuracy<0.75则拒绝合并
17上线必须灰度10%流量避免全量故障Nginx按cookie hash分流
18监控必须设P95延迟告警用户感知延迟阈值>3s触发PagerDuty
19每周必须人工抽检100条query发现LLM幻觉模式抽样检查“根据XX文件”是否真实存在
20每月必须更新embedding模型政策文件持续新增微调数据集加入新发布文件
21每季度必须重跑全量评估验证长期稳定性用相同test_set,对比MRR@10趋势

这个checklist来自我们6个政务RAG项目的血泪总结。第7条(JsonOutputParser)曾让我们避免一次重大事故:某次模型更新后,LLM开始自由发挥,生成“根据《XX条例》第100条”,而实际该条例只有85条。Parser强制校验schema后,此类问题归零。第19条(人工抽检)发现一个隐蔽问题:LLM在回答“如何办理”时,常虚构“前往XX窗口”,而实际该业务已全程网办。这推动我们增加“办事渠道”元数据字段,并在prompt中强调“仅回答现有渠道”。

我在政务RAG项目里踩过的最大坑,不是模型选错,也不是代码写错,而是把RAG当成一个功能模块,而不是一个需要持续运营的系统。上线第一天,我们盯着QPS和延迟,第二天开始看“用户追问率”,第三天分析“未召回query聚类”,第一周结束时,团队已形成每日晨会:看LangSmith trace、调优retriever、更新parser规则。RAG不是写完代码就结束,而是刚刚开始。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询