☰
企业级知识库问答系统架构设计与落地实践:LangChain与Chroma实战
2026/10/10 6:32:12 网站建设 项目流程

1. 为什么我不建议你直接上手就写代码

很多人一看到"企业级知识库问答系统"这个标题,第一反应就是打开编辑器,pip install langchain,然后照着某个教程把代码敲一遍。我见过太多这样的案例了——代码跑起来了,Demo 也能回答几个问题,但一旦把公司真实的文档丢进去,效果立刻崩盘:要么检索出来的内容驴唇不对马嘴,要么模型开始一本正经地胡说八道,要么响应慢到用户直接关掉页面。

问题出在哪?出在跳过了架构设计这一步。

企业级知识库问答和你在个人电脑上跑个玩具 Demo,本质上是两回事。玩具 Demo 只需要证明"这条路能走通",而企业级系统要解决的是"这条路能不能稳定地、低成本地、可维护地走一万遍"。这两者之间的差距,就像街边炒饭摊和连锁餐饮中央厨房的差距——都能填饱肚子,但后者要考虑供应链、标准化、食品安全、成本控制、人员培训。

所以这篇文章我不会一上来就给你贴代码。我会先带你把整个系统的骨架搭清楚:数据怎么流转、每个模块承担什么职责、哪些地方容易出问题、为什么选 LangChain 而不是自己手写、为什么用 Chroma 而不是别的向量库、开源 LLM 到底能不能扛住企业场景。把这些想明白了,代码只是水到渠成的事。

这篇文章适合谁看?如果你是有一定 Python 基础、想把这套技术栈落地到实际业务中的开发者,那正好。如果你是完全零基础的小白,也能看懂,因为我会用大量生活化的类比来解释每个技术决策背后的逻辑。但我要提前说一句:企业级系统的复杂度不在于代码量,而在于对边界的把控。哪些事该交给框架做,哪些事必须自己控制,这个判断力才是核心。

接下来,我会按照一个真实项目的推进顺序来展开:先讲清楚整体架构和数据流,再逐个拆解文档处理、向量化存储、检索策略、LLM 集成这几个核心环节,最后聊一聊上线之后才会暴露的那些坑。每一部分我都会告诉你"为什么这么做"以及"不这么做会怎样"。

2. 先把数据流画在纸上:这套系统的骨架长什么样

2.1 从用户提问到答案返回,中间到底发生了什么

很多人对 RAG(检索增强生成)的理解停留在"把文档塞进向量库,然后搜出来给模型"这个层面。这个理解没错,但太粗了。真实系统里,一个用户提问从输入到拿到答案,中间要经过至少七个环节,每个环节都有它的脾气。

我用一个具体的场景来串一遍。假设某公司的内部知识库里有三千份产品文档、技术手册和客服话术,一个客服人员输入"客户反馈设备在低温环境下频繁重启,该怎么处理"。这句话进入系统后,会经历以下流程:

第一步,查询预处理。用户的原始提问往往口语化、有歧义、甚至带错别字。系统需要先做一轮清洗和改写,比如把"低温环境"标准化成"低温工况",把"频繁重启"识别为"反复启动异常"。这一步很多人会忽略,但它直接决定了后面检索的命中率。

第二步,查询向量化。用同一个 Embedding 模型把处理后的查询转成一个高维向量。注意,这里必须和建库时用的是同一个模型,否则就像用中文词典去查英文单词,维度对不上,语义空间也不一致。

第三步,向量检索。拿着查询向量去 Chroma 里做相似度搜索,找出最接近的 Top-K 个文本块。这里的 K 值选择很讲究,太小了可能漏掉关键信息,太大了会引入噪声干扰模型判断。

第四步,重排序。向量检索返回的结果是按向量距离排序的,但向量距离近不代表语义相关度高。所以需要用一个重排序模型(Reranker)对这 K 个结果做二次精排,把真正相关的排到前面。

第五步,上下文组装。把重排序后的文本块按照一定的模板拼装成 Prompt,连同用户的原始问题一起送给 LLM。这个模板的设计直接影响模型输出的质量,后面我会详细讲。

第六步,LLM 生成。开源 LLM 接收 Prompt,基于检索到的上下文生成答案。这里要控制好温度参数,企业场景下通常要调低,保证输出的稳定性和一致性。

第七步,后处理与返回。对模型输出做一轮校验,比如检查是否引用了不存在的文档、是否包含敏感信息、格式是否规范,然后返回给用户。

这七个环节环环相扣,任何一个环节出问题,最终答案的质量都会打折扣。我见过太多项目只关注第三步和第六步,结果上线之后发现效果远不如预期,回头排查才发现是查询预处理没做好,或者上下文组装太粗糙。

2.2 为什么选 LangChain 而不是自己从零写

这个问题我被问过无数次。答案很简单:LangChain 帮你省掉的不是代码量,而是决策成本。

自己从零写不是不行,但你要面对一堆琐碎的问题:文档加载器要支持 PDF、Word、Markdown、HTML 等多种格式,每种格式的解析库都不一样;文本分割要考虑按字符、按 token、按语义还是按段落;向量库的接口要自己封装,还要处理批量插入、增量更新、删除重建;Prompt 模板要自己管理版本;LLM 的调用要处理重试、超时、并发控制。这些事情单拎出来都不难,但加在一起就是巨大的工程量。

LangChain 的价值在于它把这些环节抽象成了统一的接口。你换一个向量库,只需要改一行配置;你换一个 LLM,也只需要改一行配置。这种可替换性在企业场景下极其重要,因为今天用 Chroma,明天可能因为数据量增长要换成 Milvus;今天用这个开源模型,明天可能因为效果不好要换另一个。如果代码和具体实现耦合太深,每次替换都是一次重构。

但 LangChain 也不是银弹。它的抽象层有时候会掩盖底层细节,导致出问题的时候不好排查。我的建议是:用 LangChain 做编排,但核心环节要保留自己控制的入口。比如文本分割策略、检索后的重排序逻辑、Prompt 模板,这些最好自己写,不要完全依赖框架的默认实现。

2.3 Chroma 在企业场景中的真实定位

Chroma 是一个轻量级的向量数据库,主打易用性和嵌入式部署。它的优势很明显:安装简单、API 简洁、和 LangChain 集成度高、支持本地持久化。对于中小规模的知识库(比如几万到几十万个文本块),Chroma 完全够用。

但你要清楚它的边界。Chroma 不是为高并发、大规模分布式场景设计的。如果你的知识库有上千万个文本块,或者需要支持几百个并发查询,Chroma 可能会成为瓶颈。这时候你需要考虑 Milvus、Qdrant 或者 Weaviate 这类更重量级的方案。

不过话说回来,大多数企业的内部知识库根本到不了那个量级。我做过一个统计,一个中等规模公司的全部产品文档、技术手册、会议纪要加在一起,经过合理分割后大概也就几万个文本块。这个规模用 Chroma 绰绰有余,而且省去了维护分布式集群的麻烦。

选型这件事,我的原则是:先用最简单的方案把事做成,等真正遇到瓶颈了再换。过早优化是万恶之源,这句话在向量库选型上同样适用。

3. 文档处理:决定系统上限的关键一步

3.1 文档加载不是简单的读文件

很多人以为文档加载就是open()读文件,顶多再用个 PDF 解析库。但企业场景下的文档来源极其复杂:有扫描版的 PDF、有带复杂表格的 Excel、有嵌套层级的 Word、有从网页导出的 HTML、还有各种格式的会议纪要。每种格式的解析难度都不一样。

扫描版 PDF 是最麻烦的,因为它本质上是图片,需要 OCR 才能提取文字。OCR 的准确率直接影响后续所有环节的效果,如果 OCR 把"重启"识别成"重起",那检索的时候用户搜"重启"就永远搜不到。所以如果你的知识库里有大量扫描件,OCR 环节必须单独优化,不能随便找个库跑一遍就完事。

带表格的文档也很棘手。表格里的信息是有结构关系的,简单的文本提取会把表格拍扁成一行一行的文字,丢失行列对应关系。比如一个设备参数表,原本是"型号 | 工作温度 | 功耗"三列,拍扁之后变成"型号A 工作温度-20到60 功耗5W 型号B 工作温度-10到50 功耗8W",模型读到这种文本很难正确理解。

我的处理策略是:对不同类型的文档用不同的加载器,并且在加载阶段就做好元数据标注。比如每份文档都记录来源、类型、创建时间、所属部门这些信息,后面检索的时候可以结合元数据做过滤,提高精准度。

3.2 文本分割:切得好不好,直接决定检索准不准

文本分割是 RAG 系统里最容易被低估的环节。很多人直接用 LangChain 的RecursiveCharacterTextSplitter,设个chunk_size=1000、chunk_overlap=200就完事了。这样做不是不行,但效果往往不够好。

为什么分割这么重要?因为向量检索的基本单位是文本块。如果一个文本块太大,里面混杂了多个主题,那它的向量表示就是这些主题的"平均值",检索的时候哪个主题都匹配不精准。如果一个文本块太小,信息不完整,模型拿到之后无法理解上下文,生成的答案就会断章取义。

我通常会把chunk_size设在 500 到 800 个字符之间,chunk_overlap设在 100 到 150 之间。这个范围是经过多次实测得出的:太小了信息碎片化,太大了噪声多。但这不是固定值,要根据文档类型调整。技术手册这种信息密度高的文档,块可以小一点;会议纪要这种上下文依赖强的文档,块要大一点。

更重要的是分割策略。我强烈建议按语义边界分割,而不是按固定字符数硬切。具体做法是先用段落分隔符切,如果某个段落还是太长,再按句子切,最后才按字符切。LangChain 的RecursiveCharacterTextSplitter支持自定义分隔符列表,你可以把中文的句号、问号、感叹号、分号都加进去,让它优先在这些位置断开。

还有一个技巧是给每个文本块加上标题和来源信息。比如在文本块前面拼接上"本文档来自《XX设备维护手册》第三章第二节",这样检索的时候,即使文本块本身的内容不够明确,标题信息也能帮助模型理解上下文。

3.3 元数据设计:让检索多一个维度

纯向量检索有一个天然缺陷:它只考虑语义相似度,不考虑其他维度的信息。但企业场景下,很多查询是带条件的。比如"最近三个月关于XX产品的技术公告",这里"最近三个月"和"XX产品"就是元数据条件,光靠向量相似度是筛不出来的。

所以我在建库的时候,会给每个文本块附加丰富的元数据:文档来源、文档类型、创建时间、最后更新时间、所属产品线、密级、作者等等。检索的时候,先用元数据做一轮过滤,再在过滤后的子集里做向量检索。这样既提高了精准度,又减少了计算量。

Chroma 支持在添加文档时附带 metadata 字典,查询时可以用where参数做过滤。这个功能一定要用起来,它是区分玩具 Demo 和企业级系统的关键标志之一。

4. 向量化与 Chroma 建库:那些文档不会告诉你的细节

4.1 Embedding 模型怎么选

Embedding 模型的选择直接决定了检索质量的上限。选错了模型,后面再怎么优化都是事倍功半。

目前主流的选择分两类:一类是闭源 API,比如某些商业服务提供的 Embedding 接口;另一类是开源模型,可以本地部署。企业场景下,如果数据敏感度高,通常倾向于本地部署开源模型;如果追求效果和省事,闭源 API 也是合理选择。

开源 Embedding 模型里,我比较推荐的是那些在多语言检索任务上表现稳定的模型。选型的时候重点看几个指标:检索准确率(通常看 MTEB 榜单)、推理速度、模型大小、支持的最大输入长度。对于中文场景,还要特别关注中文语义理解能力,有些模型在英文上表现很好,但中文就拉胯了。

这里有一个容易被忽略的点:Embedding 模型的输入长度限制。大多数模型的上下文窗口是 512 个 token,超过这个长度的文本会被截断。如果你的文本块设成了 800 个字符,很可能超出限制,导致后半部分信息丢失。所以要么把块调小,要么选支持更长输入的模型。

还有一个实操经验:建库和查询必须用同一个 Embedding 模型。这个听起来是废话,但我真的见过有人建库用了一个模型,查询的时候换了另一个,结果检索出来的东西完全不相干。原因是不同模型把文本映射到了不同的向量空间,两个空间之间没有可比性。

4.2 Chroma 的持久化与增量更新

Chroma 默认是把数据存在内存里的,进程一关数据就没了。生产环境必须开启持久化,指定一个本地目录或者远程服务地址。

import chromadb from chromadb.config import Settings client = chromadb.PersistentClient( path="./chroma_db", settings=Settings(anonymized_telemetry=False) )

anonymized_telemetry=False这行建议加上,否则 Chroma 会发送匿名使用数据,企业内网环境可能不允许。

增量更新是另一个必须考虑的问题。企业的知识库不是一成不变的,每天都有新文档加入,旧文档更新或废弃。如果每次更新都全量重建索引,成本太高。Chroma 支持按 ID 更新和删除,你可以给每个文本块分配一个稳定的 ID(比如文档路径加块序号),更新的时候直接 upsert,删除的时候按 ID 删。

但这里有个坑:Chroma 的删除是软删除还是硬删除,取决于版本。有些版本删除后空间不会立即释放,需要手动调用压缩操作。如果你的知识库更新频繁,要定期检查数据库文件大小,必要时做一次全量重建来回收空间。

4.3 批量插入的性能优化

往 Chroma 里插入数据的时候,如果一条一条插,速度会非常慢。正确的做法是批量插入,每批 100 到 500 条。但批量也不能太大,太大会导致内存暴涨或者请求超时。

我的经验是:先算好 Embedding,再批量写入。Embedding 计算是 CPU 或 GPU 密集型的,写入是 IO 密集型的,两者分开做可以更好地利用资源。具体流程是:先把所有文本块收集起来,分批调用 Embedding 模型算出向量,存到一个临时列表里,然后再分批写入 Chroma。

还有一个细节:写入的时候要处理失败重试。网络抖动、服务重启、磁盘满了,这些情况都可能导致写入失败。如果不做重试,数据就丢了,而且很难发现。建议给写入操作包一层重试逻辑,记录失败批次,事后可以补写。

5. 检索策略:从"能搜到"到"搜得准"

5.1 向量检索的局限性

向量检索的核心假设是:语义相似的文本,在向量空间里的距离也近。这个假设在大多数情况下成立,但有几种情况会失效。

第一种是关键词精确匹配的场景。比如用户搜一个产品型号"XYZ-2000",向量检索可能会返回"XYZ-1000"、"XYZ-3000"这些语义相近但型号不同的文档。这种时候,关键词匹配反而更准。

第二种是否定查询。用户问"哪些设备不支持低温启动",向量检索会倾向于返回提到"低温启动"的文档,但不管文档说的是"支持"还是"不支持"。这种语义上的细微差别,向量模型往往捕捉不到。

第三种是多条件组合查询。用户同时限定产品线、时间范围、文档类型,纯向量检索无法处理这种结构化条件。

所以企业级系统不能只靠向量检索,必须结合其他检索方式。

5.2 混合检索:向量加关键词的正确打开方式

混合检索的思路是:同时做向量检索和关键词检索,然后把两路结果融合。融合的算法有几种,最简单的是加权求和,给两路结果各分配一个权重,按加权分数排序。更复杂一点的用 RRF(Reciprocal Rank Fusion),它不依赖分数,只看排名,对不同检索方式的分数尺度差异更鲁棒。

关键词检索可以用 BM25 算法,这是信息检索领域的经典算法,对精确匹配非常有效。LangChain 社区有一些 BM25 的封装,也可以自己用rank_bm25库实现。

实操中,我的做法是:向量检索取 Top 20,关键词检索取 Top 20,融合后取 Top 10 送给重排序。这个比例可以根据实际效果调整。如果发现精确匹配的需求多,就提高关键词检索的权重;如果语义理解的需求多,就提高向量检索的权重。

5.3 重排序:把真正相关的推到前面

重排序是提升检索质量最有效的手段之一,但很多项目都忽略了它。

向量检索用的是双塔模型,查询和文档分别编码,然后算相似度。这种架构速度快,但精度有限,因为它没有建模查询和文档之间的交互。重排序用的是交叉编码器,把查询和文档拼在一起送进模型,能捕捉更细粒度的语义关系,精度更高,但速度慢,所以只适合对少量候选做精排。

具体流程是:向量检索召回 Top 50,重排序模型对这 50 个逐一打分,取分数最高的 5 到 10 个送给 LLM。这样既保证了召回率,又保证了精准度。

重排序模型也有开源方案,选型逻辑和 Embedding 模型类似。要注意的是,重排序模型通常比 Embedding 模型大,推理更慢,如果候选集太大,延迟会很明显。所以召回数量要控制好,50 到 100 是比较合理的范围。

5.4 查询改写:让用户的提问更容易被搜到

用户的提问往往是口语化的、模糊的、甚至是有歧义的。直接拿原始提问去检索,效果往往不好。查询改写就是先把用户的问题"翻译"成更适合检索的形式。

常见的改写策略有几种。一是同义词扩展,把"重启"扩展成"重启 重新启动 反复启动"。二是问题拆解,把"设备在低温和高温下的表现有什么区别"拆成"设备低温表现"和"设备高温表现"两个子查询,分别检索后再合并。三是假设性文档生成,让 LLM 先根据问题生成一个假设的答案,然后用这个答案去检索,因为答案和文档的语义空间更接近。

这几种策略各有适用场景。同义词扩展适合术语多的领域,问题拆解适合对比类查询,假设性文档生成适合开放性问题。实际项目中可以组合使用,但要注意每增加一步都会增加延迟,要在效果和速度之间找平衡。

6. 开源 LLM 的集成与调优

6.1 开源模型能不能扛住企业场景

这是被问得最多的问题。我的回答是:看场景,看模型,看硬件。

如果是内部知识库问答这种场景,对回答的创造性要求不高,更看重准确性和稳定性,那么经过良好微调的开源模型完全可以胜任。但如果是面向客户的场景,对回答的流畅度、语气、安全性要求很高,开源模型可能需要更多的后处理和对齐工作。

模型大小方面,7B 到 13B 的模型在消费级显卡上就能跑,适合中小规模部署。如果追求更好的效果,可以考虑 30B 以上的模型,但硬件成本会显著上升。我的建议是:先用小模型跑通流程,验证效果,如果确实不够再换大模型。不要一上来就追求最大最好的模型,那样既浪费资源,又拖慢迭代速度。

硬件方面,推理主要吃显存。7B 模型用 4-bit 量化后大概需要 6 到 8GB 显存,13B 模型需要 10 到 12GB,30B 模型需要 20GB 以上。如果显存不够,可以用 CPU 推理,但速度会慢很多,不适合生产环境。

6.2 Prompt 模板的设计要点

Prompt 模板是连接检索和生成的桥梁,设计得好不好直接影响最终答案的质量。

一个典型的 RAG Prompt 模板长这样:

你是一个企业知识库助手,请根据以下参考资料回答用户的问题。 参考资料: {context} 用户问题:{question} 回答要求: 1. 只根据参考资料回答,不要编造信息 2. 如果参考资料中没有相关信息,直接说"根据现有资料无法回答" 3. 回答要简洁准确,引用具体的文档来源

这个模板有几个关键点。第一,明确角色和任务,让模型知道自己在做什么。第二,强调基于资料回答,减少幻觉。第三,给出兜底策略,当资料不足时不要硬编。第四,要求引用来源,方便用户核实。

但模板不是越详细越好。太长的模板会占用宝贵的上下文窗口,而且可能让模型抓不住重点。我通常会把模板控制在 200 字以内,把最重要的约束放在前面。

还有一个技巧是动态模板。根据检索结果的质量调整模板内容。如果检索到的资料很相关,就正常回答;如果检索结果分数普遍偏低,就在模板里加一句"参考资料可能不完整,请谨慎回答"。这种动态调整能显著降低错误回答的概率。

6.3 温度参数与输出稳定性

企业场景下,我通常把温度设在 0.1 到 0.3 之间。温度越低,输出越确定、越保守;温度越高,输出越多样、越有创造性。知识库问答不需要创造性,需要的是准确和稳定,所以温度要调低。

但温度调到 0 也不一定好。有些模型在温度为 0 的时候会陷入重复循环,反复输出同一句话。所以 0.1 左右是一个比较安全的区间。

除了温度,还有几个参数值得关注。top_p控制采样的候选范围,通常设 0.9 左右。max_tokens控制输出的最大长度,要根据业务需求设置,太短了答案不完整,太长了浪费资源。repetition_penalty用来抑制重复,如果发现模型爱重复,可以适当调高。

6.4 流式输出与用户体验

LLM 生成一个完整答案可能需要几秒钟甚至十几秒钟。如果等全部生成完再返回,用户会觉得系统很慢。流式输出可以让用户看到答案一个字一个字地蹦出来,感知上的等待时间大大缩短。

LangChain 支持流式输出,通过streaming=True参数开启。但流式输出对前端有要求,需要用 SSE(Server-Sent Events)或者 WebSocket 来推送。如果你的系统是前后端分离的,后端要提供一个流式接口,前端要相应地处理流式数据。

流式输出还有一个好处是可以提前中断。如果用户发现答案不对,可以立即停止生成,节省计算资源。这个功能在交互式场景下很实用。

7. 上线之后才会暴露的那些坑

7.1 检索到了但模型不用

这是最让人抓狂的问题之一:明明检索到了正确的文档,但模型就是不用,非要自己编一个答案。

原因通常有几个。一是上下文太长,模型在长文本中迷失了重点。解决办法是控制上下文长度,只放最相关的几个文本块,并且在每个块前面加上明确的标记。二是Prompt 指令不够强,模型没有意识到必须基于资料回答。解决办法是在 Prompt 里反复强调,甚至用 few-shot 示例来引导。三是模型本身的能力不足,小模型对指令的遵循能力有限。这种情况只能换更大的模型,或者对模型做微调。

我的经验是:在 Prompt 里加一句"如果你不确定,就说不知道",比任何复杂的约束都有效。模型在不确定的时候倾向于编造,给它一个安全的出口,它反而更愿意承认不知道。

7.2 相似问题返回不一致的答案

同一个问题问两遍,得到的答案不一样,这在企业场景下是致命的。用户会质疑系统的可靠性。

造成不一致的原因主要有两个。一是温度参数太高,每次采样结果不同。解决办法是把温度调低。二是检索结果不稳定,每次召回的文本块略有差异。解决办法是固定随机种子,并且在检索环节增加确定性,比如用固定的排序规则。

还有一个隐藏原因是并发导致的资源竞争。如果多个请求同时打到同一个模型实例,显存不够的时候可能会触发换页,导致输出异常。解决办法是限制并发数,或者部署多个模型实例做负载均衡。

7.3 知识库更新后的"缓存不一致"

知识库更新了,但用户查到的还是旧答案。这个问题在系统刚上线的时候不明显,运行一段时间后就会暴露。

根源在于向量库的更新和 LLM 的上下文之间存在时间差。你更新了向量库,但用户之前的查询可能被缓存了,或者 LLM 的上下文里还残留着旧信息。解决办法是:更新知识库后,主动清理相关缓存;对于关键更新,可以给用户一个提示,告诉他们知识库已更新,建议重新提问。

另外,删除文档的时候要彻底。不仅要删向量库里的记录,还要清理相关的缓存、日志、以及任何可能残留的副本。我见过一个案例,某文档被删除了,但因为缓存没清,用户还是能搜到内容,造成了信息泄露。

7.4 成本失控:Token 消耗比想象中快

开源 LLM 虽然不用付 API 费用,但硬件成本、电力成本、运维成本都是实打实的。而且 RAG 系统的 Token 消耗比普通对话大得多,因为每次都要把检索到的上下文塞进 Prompt。

控制成本的手段有几个。一是优化检索,减少不必要的上下文。二是压缩上下文,用摘要或者关键句提取来替代全文。三是缓存常见问题的答案,避免重复计算。四是设置 Token 上限,超过就截断或者拒绝。

我建议在系统里加一个监控面板,实时显示 Token 消耗、响应延迟、检索命中率这些指标。没有监控的系统就像没有仪表盘的汽车,出了问题都不知道在哪。

7.5 安全与权限:不是所有人都能看所有文档

企业知识库往往涉及不同密级的信息。技术文档可能全员可见,但财务数据、人事信息、战略规划这些只有特定人员能看。如果系统不做权限控制,那就是一个巨大的安全隐患。

权限控制的实现方式有两种。一是在检索阶段过滤,根据用户身份在向量检索时加上元数据条件,只检索用户有权限的文档。二是在生成阶段过滤,先检索再根据权限筛选,但这样效率低,而且有泄露风险。

推荐第一种方式。具体做法是给每个文本块的元数据里加一个"访问权限"字段,检索的时候用where条件过滤。用户身份从登录系统获取,和权限字段做匹配。

这里有一个容易忽略的点:权限变更后的同步。如果某个用户的权限被收回了,但他之前的查询缓存里还有敏感信息,那就麻烦了。所以权限变更时要主动清理相关缓存,确保下次查询用的是新权限。

8. 一些让我少走弯路的实操习惯

做了几个知识库项目之后,我养成了几个习惯,分享出来供参考。

第一个习惯是先建一个小规模的测试集。不要一上来就把所有文档都灌进去,先挑几十份有代表性的文档,跑通全流程,验证效果。测试集里要包含各种边界情况:超长文档、表格文档、扫描件、多语言混合文档。小规模验证通过之后,再逐步扩大。

第二个习惯是记录每次查询的完整链路。从用户输入、查询改写、检索结果、重排序分数、最终 Prompt、模型输出,全部记下来。出问题的时候,这些日志就是排查的依据。没有日志的系统,排查问题全靠猜。

第三个习惯是定期做人工评估。自动指标(比如检索命中率、答案准确率)只能反映一部分情况,很多问题要靠人眼才能发现。我通常每周抽 50 个真实查询,人工判断答案质量,记录 bad case,然后针对性优化。

第四个习惯是给系统留后门。所谓后门,就是当自动流程出问题时,人工可以介入。比如提供一个"重新检索"按钮,让用户换一批资料重新生成;或者提供一个"反馈"入口,让用户标记错误答案,这些反馈数据可以用来优化系统。

第五个习惯是版本化管理。Embedding 模型、LLM、Prompt 模板、检索策略,这些都要版本化。每次变更都记录版本号和变更内容,出问题可以快速回滚。我见过太多项目因为改了一个 Prompt 导致效果全面下降,又找不到旧版本,只能从头调。

这套系统从零搭起来,快的话一两周能跑通 Demo,但要达到企业级可用,至少需要一两个月的迭代。难点不在代码,在于对业务的理解、对数据的处理、对边界的把控。希望这篇文章能帮你少踩一些坑,把精力花在真正重要的地方。

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

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

立即咨询