摘要
LLM 应用接入 Embedding 时,最常见的风险不是模型调用失败,而是文本切分、向量维度和检索结果在不同组件之间悄悄漂移。本文从榜单中的 LangChain 与 Embedding 主题出发,给出一条可审计的接入路径:把原文、切片、向量、过滤条件和引用证据分别建模,再为每个环节设置契约和回归样本。示例只用于说明接口边界,不代表已在任何线上服务中运行。
原文不能直接等于上下文
文档进入链路前,应保存来源标识、版本、语言和更新时间。切片器只负责把文档变成有序片段,不应在这个阶段修改事实内容。每个片段附带文档版本、起止位置和标题路径,后续回答才能给出精确引用。若切片跨越表格或代码块,要额外记录结构类型,避免把一行配置拆成两段后失去含义。
切片长度应通过样本评估,而不是套用一个固定数字。短片段容易丢失上下文,长片段又会降低召回精度。可以选取问答集,对不同长度、重叠比例分别记录召回率、重复片段数和上下文总 token。重叠窗口只补足语义边界,不应成为掩盖标题层级缺失的手段。
向量契约需要显式版本
Embedding 端至少要固定模型名称、维度、归一化方式和批量接口。向量库中的字段应写入 embedding_version,不能只依赖当前配置文件。模型替换或维度改变时,旧向量和新向量不得混用;迁移阶段可以双写,但检索器必须知道当前读取哪个版本。
输入为空、超长、包含不可解码字符时,要在调用模型前返回可分类的错误。批量请求失败也不能简单重试整个批次,否则容易产生重复写入。更稳妥的做法是给每个片段分配幂等键,记录成功和失败的子项,并对重试次数设上限。向量生成耗时、请求大小和拒绝原因都应进入指标。
检索器不应吞掉过滤条件
相似度召回和业务过滤是两件事。检索器可以先召回候选,再执行租户、权限和文档状态过滤,但过滤过程必须在结果对象中保留原因。若过滤后没有结果,应区分"没有相似内容"和"相似内容不可见",这会直接影响回答策略。
重排器也需要稳定契约。输入应包括片段文本、相似度、来源和过滤结果;输出除了排序后的列表,还要返回置信度和被舍弃候选的数量。对同一查询重复执行时,前几名顺序应稳定,或者明确标注随机策略。不要让模型自行补齐缺失的来源字段,引用证据必须来自检索结果。
用回归集发现语义漂移
回归集应覆盖事实问答、跨段落问答、权限过滤和无答案问题。每个问题保存期望的来源文档集合,而不是只保存一段自然语言答案。评估时同时看召回、引用准确率和拒答质量。若模型升级后答案更流畅但来源覆盖率下降,仍应判定为回归。
调试时按链路查看事件:切片数量、向量版本、候选数量、过滤原因和最终上下文。LangChain 的编排能力适合把这些事件串起来,但事件名称和字段需要由应用自己固定。将链路追踪 ID 写入每次检索记录,才能把一个用户问题还原到具体片段。
还应给上下文设置预算。召回器先按来源去重,再按照文档版本和字段权重截取片段,避免同一段话占满整个窗口。预算耗尽时保留标题、来源和命中词项,把被截断的片段数记录为指标。模型回答前可以执行一次证据覆盖检查:如果回答中的实体没有对应片段,就改为请求澄清或明确拒答。
缓存要绑定完整的检索契约。缓存键至少包括规范化问题、租户、过滤条件、embedding 版本和提示模板版本;权限变化或文档删除时主动失效相关键。缓存命中仍需记录来源版本,不能因为命中缓存就跳过权限判断。对相似问题使用近似缓存时,先通过阈值和敏感字段检查,宁可少命中,也不要复用错误的上下文。
上线评估可以采用离线集加小流量观察。离线集关注召回和引用覆盖,小流量关注延迟、拒答率和用户纠错。每次更换切片器或模型都生成一份差异报告,列出新增、消失和顺序变化的来源。报告与配置提交关联,后续才能解释一次回答为何不同。
故障降级也应提前设计。向量服务不可用时,可以退回标题关键词检索,但界面和日志必须标注降级状态;重排器超时时,使用原始相似度并降低回答置信度;来源服务不可用时,不允许模型根据缓存外的常识补答。降级路径同样运行权限过滤,并设置最大持续时间,防止临时方案长期存在。
隐私数据进入向量化前先做字段分类。身份证号、联系方式、密钥和内部账号等内容原则上不进入通用向量库;确需检索时使用独立空间、短保留期和严格审计。删除请求不仅删除原文,还要删除切片、向量、缓存和评估样本中的引用,并保存可证明完成的任务记录。
运行手册还要列出每个组件的负责人、健康检查和切换开关。告警发生时先判断问题位于文档、向量、检索还是生成阶段,再执行对应降级。
恢复后补跑回归集,并确认缓存没有继续返回旧版本结果。
结语
Embedding 接入的核心是契约,而不是某个框架的默认参数。先固定文本边界和向量版本,再把检索过滤、重排和引用拆开验证,LangChain 才能成为可替换的编排层。这样即使模型、向量库或切片策略发生变化,也能通过回归集判断变化究竟改善了召回,还是只是改变了表达。