RAG 系统 Embedding 流程分析与自托管 API 适配

RAG 系统 Embedding 流程分析与自托管 API 适配 1. 问题背景在构建一个轻量化 RAG检索增强生成系统时使用了 LangChain 框架结合自托管的 FreeLLMApi兼容 OpenAI 格式进行文本向量化。在开发过程中遇到了运行时类型错误并对 Embedding 模型如何处理文本以及自托管服务与 OpenAI 原生服务的差异产生了疑问。2. 运行时问题分析2.1 错误现象错误日志TypeError: Document.__init__() got an unexpected keyword argument page_content2.2 根本原因该错误发生在load_chunks_from_file函数中。代码尝试通过Document(page_content..., metadata...)实例化对象。原因实例化时传递的参数名page_content与当前环境中安装的Document类定义不匹配。这通常是因为导入了错误的Document类或者使用了版本不兼容的 LangChain 核心库。解决方案确保从langchain_core.documents正确导入Document类并核对该版本类构造函数的参数名。3. 深度技术探讨Embedding 工作机制3.1 文本是如何转换为向量的调用embeddings.embed_documents(batch_texts)时内部执行流程如下原始文本→\rightarrow→Tokenizer分词→\rightarrow→Token IDs (整数序列)→\rightarrow→神经网络→\rightarrow→Embedding向量核心结论神经网络无法直接处理字符串必须经过 Token 化转换为数字 ID 才能进行矩阵运算。3.2_tokenize方法的作用在 LangChain 的OpenAIEmbeddings实现中_tokenize方法的作用不是预处理文本而是计数量长度。目的计算当前文本包含多少个 token以判断是否超过模型最大长度限制例如 8191 tokens。逻辑如果超限→\rightarrow→执行截断或切分→\rightarrow→再次检查如果不超限→\rightarrow→进入_get_len_safe_embeddings阶段。3.3_get_len_safe_embeddings解析该方法名为 “Length Safe”意味着它假设输入文本已经通过了长度校验因此它会跳过所有校验步骤直接将原始字符串batch_texts发送给 API 接口。4. 自托管服务 vs OpenAI 原生 API4.1 推理逻辑对比特性OpenAI 原生 API自托管推理服务 (如 FreeLLMApi)传输内容原始字符串 (str)可能是字符串也可能是Token IDsTokenize 位置服务端完成可能在客户端完成→\rightarrow→传输 IDsAPI 接口https://api.openai.com/v1私有 IP (如172.21.6.101) 自定义端口模型定义明确的模型名 (如text-embedding-3)可能使用auto等路由别名4.2 如何判断是否为自建推理服务IP 地址使用私有 IP 段10.x,172.16-31.x,192.168.x。端口号使用非标准 HTTPS 端口如3001。客户端类型self.client的类型不是标准openai.OpenAI类。输入参数API 调用时传递的是batch_tokens(List[int]) 而非batch_texts(List[str])。5. 适配方案让自托管服务走 OpenAI 逻辑若自托管服务兼容 OpenAI 格式但其 SDK 强制要求传递batch_tokens而你希望传输原始文本可采取以下方案方案 A重写 Embedding 类 (推荐)继承OpenAIEmbeddings并重写embed_documents绕过内部的 Token 转换逻辑强制发送原始字符串。方案 B直接使用 HTTP 请求不使用 LangChain 的封装直接通过requests或httpx调用/v1/embeddings端点确保input字段传递的是字符串列表。# 伪代码示例responserequests.post(urlhttp://172.21.6.101:3001/v1/embeddings,json{model:auto,input:[原始文本1,原始文本2]},headers{Authorization:fBearer{API_KEY}})6. 总结运行时错误→\rightarrow→检查类导入与参数匹配。Embedding 流程→\rightarrow→本地 Tokenize 仅用于长度校验→\rightarrow→传输原始文本→\rightarrow→服务端 Tokenize→\rightarrow→生成向量。自托管识别→\rightarrow→通过私有 IP、非标端口及self.client类型判断。适配关键→\rightarrow→确认 API 接收的是string还是token_ids通过重写方法或直接调用 REST API 解决不兼容问题。