LangChain 学习笔记 10:接入很多模型,不等于系统真的可替换
LangChain 的一大特点是集成丰富:聊天模型、Embedding、向量库、Loader、Retriever 和工具都能找到不同实现。刚开始看会觉得,只要接口统一,底层服务就可以随时替换。
真正做迁移时才会发现,“代码能跑”只代表第一关通过。不同服务在能力、数据和运维上的差异,并不会因为套了一层框架就消失。
统一接口解决了什么
框架可以把常见操作整理成相近形状,例如模型调用、批处理、流式输出、添加文档和相似度检索。上层流程因此可以围绕“聊天模型”或“Retriever”编程,而不是到处写供应商 SDK。
这对原型开发很有帮助,也能减少重复适配代码。但统一接口更像插座标准,并不能保证接上的每台设备性能相同。
模型替换要检查能力差异
从模型 A 换到模型 B 时,至少要重新确认:
- 是否支持工具调用、结构化输出和图片输入;
- 消息角色与流式事件是否一致;
- 上下文长度、限流和超时策略;
- 同一 Prompt 的输出质量与稳定性;
- token 计算、价格和延迟。
如果业务依赖工具并行调用,就不能只定义一个“所有模型都有 generate 方法”的最低公分母接口。适配层还应暴露所需能力,并在启动或调用前检查。
向量库迁移更像数据迁移
向量库的差异不仅是查询函数名。索引算法、距离度量、过滤语法、多租户方式、备份恢复和一致性都可能不同。
更换 Embedding 模型时,还涉及向量维度和空间变化,通常需要重建索引。即使 Embedding 不变,迁移向量库也要验证元数据、文档 ID、删除语义和 top-k 排序是否一致。
我会把这些版本一起写进索引清单:
{
"embedding_model": "example-embedding-v2",
"dimension": 1536,
"distance": "cosine",
"chunking_version": "manual-v3",
"created_at": "2026-07-30"
}
没有这些信息,几个月后很难解释某批向量是怎样生成的。
薄适配层仍然值得保留
即使已经使用 LangChain,我也倾向在业务项目中保留很薄的一层,例如 ChatService、EmbeddingService 和 KnowledgeRetriever。
这层接口只暴露业务真正需要的能力:生成客服草稿、生成文档向量、按权限检索知识。框架升级或供应商变化时,修改集中在基础设施层,业务代码不必直接感知每个类名变化。
适配层不要追求覆盖供应商全部功能。共性能力走统一接口,确实需要的特殊能力通过明确扩展点提供,并用测试说明它不能被任意实现替换。
“可替换”必须通过测试证明
我会准备一套契约测试:相同输入能否返回约定结构,超时和错误能否映射到统一类型,过滤条件是否生效,流式结果是否完整。
在契约测试之外,还需要业务评测。模型换了以后分类准确率是否下降?向量库迁移后标准问题的召回率是否变化?这些才决定替换是否真正成功。
这章给我的启发
集成的价值不是把所有供应商伪装成完全相同,而是把差异集中到可管理的位置。
统一契约让上层代码稳定,能力声明提醒我们差异仍然存在,版本记录和回归测试则保证迁移不是一次碰运气。类名会过时,供应商也会变化;这些工程习惯才是更长期的资产。

浙公网安备 33010602011771号