当前位置: 首页 > article >正文

从报错到解决:深入剖析LangChain中ollama与OpenAIEmbeddings的兼容性改造

1. 问题背景当ollama遇上OpenAIEmbeddings最近在折腾LangChain项目时遇到一个挺有意思的问题。我想用本地部署的ollama服务替代OpenAIEmbeddings结果刚跑起来就报了个400错误。错误信息显示invalid input type这让我有点懵——明明参数都配置对了啊。先说说为什么会有这个需求。很多开发者现在都喜欢用ollama本地部署大模型毕竟数据隐私和调用成本都是实打实的优势。而LangChain的OpenAIEmbeddings又是处理文本嵌入的利器如果能把这俩结合起来那真是既省钱又安全。但现实往往比理想骨感直接替换就会遇到这个经典的兼容性问题。我当时的测试代码很简单from langchain_openai import OpenAIEmbeddings embeddings OpenAIEmbeddings( modelbge-large-zh-v1.5, openai_api_basehttp://127.0.0.1:11434/v1/, api_keyollama ) output embeddings.embed_query(你好)看起来人畜无害的几行代码却抛出了openai.BadRequestError。这个错误表面上是说输入类型无效但实际暗藏玄机。接下来就带大家一步步拆解这个问题看看怎么让ollama和OpenAIEmbeddings愉快地玩耍。2. 错误排查从表象到本质2.1 第一反应参数检查遇到报错的第一反应当然是检查参数。我反复核对了ollama的API文档和OpenAIEmbeddings的接口要求openai_api_base确实指向了ollama的/v1/端点api_key按ollama要求设置了任意字符串model参数也正确指定了ollama支持的模型甚至用curl直接测试了API连通性curl http://127.0.0.1:11434/v1/embeddings \ -H Content-Type: application/json \ -d { input: [测试文本], model: bge-large-zh-v1.5 }结果这个请求是能正常返回的说明ollama服务本身没问题。那么问题很可能出在LangChain的封装逻辑上。2.2 深入调试Tokenization的锅用调试器跟踪代码执行发现关键问题出在_get_len_safe_embeddings方法里。OpenAIEmbeddings默认会对输入文本进行Tokenization处理而ollama的API并不需要这个步骤。具体来说原始文本传入后OpenAIEmbeddings会先进行分块和Tokenize处理后的数据结构与ollama API的预期不符ollama收到变形的数据后直接拒绝返回400错误这就解释了为什么curl能通但Python代码不行——数据预处理环节出了问题。要解决这个问题我们需要绕过OpenAIEmbeddings的默认Tokenization逻辑。3. 解决方案定制兼容层3.1 继承与重写最优雅的解决方案是创建OpenAIEmbeddings的子类重写关键方法from typing import List, Optional from langchain_community.embeddings import OpenAIEmbeddings class OllamaCompatibleEmbeddings(OpenAIEmbeddings): def _tokenize(self, texts: List[str], chunk_size: int) - tuple: 禁用Tokenization直接返回原始文本 indices list(range(len(texts))) return (range(0, len(texts), chunk_size), texts, indices)这个_tokenize方法的重写是关键它让后续处理直接使用原始文本跳过了可能导致问题的Tokenization步骤。3.2 同步与异步处理为了完整支持LangChain的各种使用场景我们需要同时处理同步和异步调用def _get_len_safe_embeddings( self, texts: List[str], *, engine: str, chunk_size: Optional[int] None ) - List[List[float]]: 同步版本的嵌入获取 _chunk_size chunk_size or self.chunk_size batched_embeddings: List[List[float]] [] for i in range(0, len(texts), _chunk_size): chunk texts[i: i _chunk_size] response self.client.create( inputchunk, modelself.model, **{k: v for k, v in self._invocation_params.items() if k ! model} ) if not isinstance(response, dict): response response.model_dump() batched_embeddings.extend(r[embedding] for r in response[data]) return batched_embeddings async def _aget_len_safe_embeddings( self, texts: List[str], *, engine: str, chunk_size: Optional[int] None ) - List[List[float]]: 异步版本的嵌入获取 _chunk_size chunk_size or self.chunk_size batched_embeddings: List[List[float]] [] for i in range(0, len(texts), _chunk_size): chunk texts[i: i _chunk_size] response await self.async_client.create( inputchunk, modelself.model, **{k: v for k, v in self._invocation_params.items() if k ! model} ) if not isinstance(response, dict): response response.model_dump() batched_embeddings.extend(r[embedding] for r in response[data]) return batched_embeddings这两个方法的核心修改点是直接使用原始文本列表作为input显式传递model参数保持其他调用参数不变4. 实际应用与效果验证4.1 使用方法改造后的调用方式与原版几乎一致embeddings OllamaCompatibleEmbeddings( modelbge-large-zh-v1.5, openai_api_basehttp://127.0.0.1:11434/v1/, api_keyollama, chunk_size512 ) output embeddings.embed_query(你好)唯一的区别就是把OpenAIEmbeddings换成了我们自定义的OllamaCompatibleEmbeddings类。4.2 性能考量在实际测试中发现几个值得注意的点分块大小ollama对长文本的处理能力有限建议chunk_size不要超过512批处理适当增大batch_size可以提高吞吐量但要注意内存消耗错误处理ollama的错误响应格式与OpenAI略有不同必要时可以重写错误处理逻辑下面是一个更完整的示例展示了如何批量处理文档documents [文档1内容, 文档2内容, ...] embeddings OllamaCompatibleEmbeddings( modelbge-large-zh-v1.5, openai_api_basehttp://127.0.0.1:11434/v1/, api_keyollama ) # 批量获取嵌入 doc_embeddings embeddings.embed_documents(documents) # 查询相似度 query 搜索词 query_embedding embeddings.embed_query(query)5. 深入原理为什么需要这样改5.1 ollama与OpenAI API的差异虽然ollama兼容OpenAI API格式但在一些细节处理上仍有差异特性OpenAI APIollamaTokenization必需可选输入格式Token IDs原始文本模型参数必须指定可选错误响应结构化简化版这些差异正是导致兼容性问题的根源。我们的改造方案本质上是在LangChain这一层做了适配让ollama能够接受OpenAIEmbeddings生成的数据格式。5.2 LangChain的设计哲学LangChain的Embeddings类设计遵循了几个原则安全性默认进行长度检查和Tokenization通用性适配不同后端服务可扩展性允许通过继承进行定制我们的解决方案正是利用了这种可扩展性。通过重写关键方法既保留了LangChain的核心功能又适配了ollama的特殊需求。6. 进阶话题更多可能性6.1 支持其他本地模型这套方案不仅适用于ollama稍作修改就能适配其他兼容OpenAI API的本地服务比如FastChat开源的OpenAI兼容服务LocalAI支持多种开源模型的API服务自定义服务自行实现的兼容端点只需要调整model参数和可能的少量请求参数同样的代码就能跑起来。6.2 性能优化技巧在实际使用中我还发现几个提升效率的小技巧连接池调整httpx的连接池大小减少连接建立开销超时设置根据网络状况适当调整timeout缓存机制对频繁查询的文本可以添加缓存层例如可以这样优化初始化参数embeddings OllamaCompatibleEmbeddings( modelbge-large-zh-v1.5, openai_api_basehttp://127.0.0.1:11434/v1/, api_keyollama, timeout30.0, # 适当延长超时 chunk_size256 # 根据硬件调整 )7. 避坑指南你可能遇到的问题在实际部署过程中我踩过几个坑值得分享版本兼容性不同版本的LangChain可能修改了Embeddings的内部实现需要检查方法签名是否变化模型支持不是所有ollama支持的模型都能完美兼容建议先用小数据量测试内存管理批量处理大量文本时注意监控内存使用必要时手动分批次处理比如有一次我遇到了内存泄漏问题最后发现是异步客户端没有正确关闭。解决方案是在使用完毕后显式调用await embeddings.async_client.close()8. 完整代码示例为了方便大家直接使用这里提供完整的实现代码from typing import List, Optional from langchain_community.embeddings import OpenAIEmbeddings class OllamaCompatibleEmbeddings(OpenAIEmbeddings): 兼容ollama的OpenAIEmbeddings实现 def _tokenize(self, texts: List[str], chunk_size: int) - tuple: indices list(range(len(texts))) return (range(0, len(texts), chunk_size), texts, indices) def _get_len_safe_embeddings( self, texts: List[str], *, engine: str, chunk_size: Optional[int] None ) - List[List[float]]: _chunk_size chunk_size or self.chunk_size batched_embeddings: List[List[float]] [] for i in range(0, len(texts), _chunk_size): chunk texts[i: i _chunk_size] response self.client.create( inputchunk, modelself.model, **{k: v for k, v in self._invocation_params.items() if k ! model} ) if not isinstance(response, dict): response response.model_dump() batched_embeddings.extend(r[embedding] for r in response[data]) return batched_embeddings async def _aget_len_safe_embeddings( self, texts: List[str], *, engine: str, chunk_size: Optional[int] None ) - List[List[float]]: _chunk_size chunk_size or self.chunk_size batched_embeddings: List[List[float]] [] for i in range(0, len(texts), _chunk_size): chunk texts[i: i _chunk_size] response await self.async_client.create( inputchunk, modelself.model, **{k: v for k, v in self._invocation_params.items() if k ! model} ) if not isinstance(response, dict): response response.model_dump() batched_embeddings.extend(r[embedding] for r in response[data]) return batched_embeddings使用这个方案后我的LangChain应用成功切换到了本地ollama服务既保证了数据隐私又大幅降低了API调用成本。整个过程虽然遇到些波折但最终的解决方案既干净又可靠。如果你也面临类似的需求不妨试试这个方案相信能帮你省下不少调试时间。

相关文章:

从报错到解决:深入剖析LangChain中ollama与OpenAIEmbeddings的兼容性改造

1. 问题背景:当ollama遇上OpenAIEmbeddings 最近在折腾LangChain项目时,遇到一个挺有意思的问题。我想用本地部署的ollama服务替代OpenAIEmbeddings,结果刚跑起来就报了个400错误。错误信息显示"invalid input type",这…...

3个实用技巧:用PCL2-CE社区版打造你的专属Minecraft启动器

3个实用技巧:用PCL2-CE社区版打造你的专属Minecraft启动器 【免费下载链接】PCL-CE PCL2 社区版,可体验上游暂未合并的功能 项目地址: https://gitcode.com/gh_mirrors/pc/PCL-CE 你是否厌倦了千篇一律的Minecraft启动器界面?是否曾因…...

Qwen3.5-4B-Claude-Opus-GGUF入门:Qwen3.5-4B与Claude-4.6能力对齐评估方法

Qwen3.5-4B-Claude-Opus-GGUF入门:Qwen3.5-4B与Claude-4.6能力对齐评估方法 1. 模型概述 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF是一个基于Qwen3.5-4B的推理蒸馏模型,重点强化了结构化分析、分步骤回答、代码与逻辑类问题的处理能力。该…...

**InfluxDB + Python 实战:从时序数据采集到可视化监控的完整流水线构

InfluxDB Python 实战:从时序数据采集到可视化监控的完整流水线构建 在现代微服务架构和物联网(IoT)场景中,高效、稳定地存储与分析时间序列数据已成为系统可观测性的核心。作为专为时序数据优化的数据库,InfluxDB 凭…...

WebSocket避坑指南:用ws库时你可能会遇到的5个典型问题

WebSocket实战避坑指南:5个高频问题与深度解决方案 1. 连接稳定性:从握手失败到心跳检测 WebSocket连接建立阶段最常见的错误是HTTP 101 Switching Protocols响应失败。某电商平台的监控数据显示,约23%的连接异常发生在握手阶段。以下是典型错…...

Qt 数据QByteArray与QString高效转换实战技巧

1. QByteArray与QString的本质区别 在Qt开发中,QByteArray和QString这两个类经常让新手开发者感到困惑。我第一次接触Qt时,也曾经把两者混为一谈,结果在中文显示时出现了乱码问题。后来才发现,它们的根本区别在于:QByt…...

Android网络请求库终极对决:xUtils3 vs Retrofit 完整指南

Android网络请求库终极对决:xUtils3 vs Retrofit 完整指南 【免费下载链接】xUtils3 Android orm, bitmap, http, view inject... 项目地址: https://gitcode.com/gh_mirrors/xu/xUtils3 在Android开发的世界中,网络请求是每个应用的核心功能之一…...

2026研究生必备|10款主流文献阅读工具深度测评:从入门到精通的选择指南

研一刚入学就被导师扔来50篇英文文献?研二开题前一周还在为文献整理焦头烂额?研三写大论文时发现之前做的笔记全都找不到了?这些惨状的根源往往不是你不够努力,而是工具选错了。本文深度测评10款2026年主流文献阅读工具&#xff0…...

ETS2游戏数据可视化:革新卡车模拟2远程监控体验

ETS2游戏数据可视化:革新卡车模拟2远程监控体验 【免费下载链接】ets2-telemetry-server ETS2/ATS Telemetry Web Server Mobile Dashboard 项目地址: https://gitcode.com/gh_mirrors/et/ets2-telemetry-server 你是否曾在长途驾驶欧洲卡车模拟2时&#xf…...

VCR监控与告警:快速检测Cassette过期和配置问题的完整指南

VCR监控与告警:快速检测Cassette过期和配置问题的完整指南 【免费下载链接】vcr Record your test suites HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests. 项目地址: https://gitcode.com/gh_mirrors/vc/v…...

Hilo游戏跨端适配终极指南:10个技巧让游戏在不同设备上完美显示

Hilo游戏跨端适配终极指南:10个技巧让游戏在不同设备上完美显示 【免费下载链接】Hilo A Cross-end HTML5 Game development solution developed by Alibaba Group 项目地址: https://gitcode.com/gh_mirrors/hi/Hilo Hilo是阿里巴巴集团开发的跨端HTML5游戏…...

文档转换自动化:Word to Markdown全流程实战指南

文档转换自动化:Word to Markdown全流程实战指南 【免费下载链接】word-to-markdown A ruby gem to liberate content from Microsoft Word documents 项目地址: https://gitcode.com/gh_mirrors/wo/word-to-markdown 在数字化内容管理中,文档转换…...

RMBG-2.0实战教程:结合FFmpeg实现‘原图→去背→合成视频’流水线

RMBG-2.0实战教程:结合FFmpeg实现‘原图→去背→合成视频’流水线 1. 引言:从单张抠图到批量视频合成 如果你用过RMBG-2.0,一定会被它精准的抠图效果惊艳到。它能轻松地把照片里的人或物“抠”出来,背景变得干干净净。但你想过没…...

信息学奥赛必备:用C++手把手教你实现圆的计算(附OpenJudge/洛谷真题解析)

信息学奥赛必备:用C手把手教你实现圆的计算(附OpenJudge/洛谷真题解析) 在信息学竞赛的入门阶段,几何计算往往是选手们遇到的第一个"拦路虎"。其中,圆的相关计算因其数学公式的简洁性和编程实现的多样性&…...

F5-TTS语音克隆:5分钟打造专业级多语言语音合成系统

F5-TTS语音克隆:5分钟打造专业级多语言语音合成系统 【免费下载链接】F5-TTS Official code for "F5-TTS: A Fairytaler that Fakes Fluent and Faithful Speech with Flow Matching" 项目地址: https://gitcode.com/gh_mirrors/f5/F5-TTS F5-TTS是…...

Nacos 服务注册为什么默认是临时实例?

做 Spring Cloud 开发的同学,对 Nacos 肯定不陌生。大家平常写代码,配置文件里只要配好 Nacos 地址,程序一启动,服务就自动注册上去了。但不知道大家有没有留意过一个细节:当你把服务停掉,或者直接 Kill 进…...

汽车零件分装报警系统(1)

这个项目是对汽车零件(机油滤芯)分装的时候编码进行警报,机器识别楚错误编码的时候会报警,编码使用正则表达式设置一个正确编码范围,摄像头连接警报器,使用paddleOCR和opencv相关技术,pyqt5设计…...

如何用3个智能体协作,让你的工作效率提升10倍?

如何用3个智能体协作,让你的工作效率提升10倍? 【免费下载链接】eigent Eigent: The Worlds First Multi-agent Workforce to Unlock Your Exceptional Productivity. 项目地址: https://gitcode.com/GitHub_Trending/ei/eigent 你是否曾经有过这…...

IP6163光伏降压DC-DC芯片:MPPT硬件算法如何提升太阳能转换效率

1. IP6163光伏降压芯片:太阳能转换的智能引擎 第一次接触太阳能充电系统时,我遇到一个头疼的问题:明明阳光充足,充电效率却忽高忽低。后来发现是传统方案无法实时追踪太阳能板的最大功率点,导致能量白白浪费。这正是IP…...

面试官:MySQL 唯一索引和主键索引的区别?(修订版)

在线 Java 面试刷题(持续更新):https://www.quanxiaoha.com/java-interview面试考察点索引类型理解:面试官不仅仅是想知道 "有什么区别",更是想考察你是否理解主键索引(聚簇索引)和唯…...

3步实现多平台同步直播:obs-multi-rtmp高效推流指南

3步实现多平台同步直播:obs-multi-rtmp高效推流指南 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp obs-multi-rtmp是一款专为OBS Studio设计的多平台推流插件,能…...

AI专著撰写高效之道:优质工具推荐,专著写作快又好

学术专著的主要价值在于其系统性和逻辑的完整性,但这却是写作过程中最难以攻克的难题。与专注于单一议题的期刊文章不同,AI 写专著需要构建一个包含绪论、理论基础、核心研究、应用拓展和结论的整体框架。各个章节之间要相互关联,层层递进&am…...

OnmyojiAutoScript副本效率提升指南:从异常排查到性能优化

OnmyojiAutoScript副本效率提升指南:从异常排查到性能优化 【免费下载链接】OnmyojiAutoScript Onmyoji Auto Script | 阴阳师脚本 项目地址: https://gitcode.com/gh_mirrors/on/OnmyojiAutoScript 阴阳师自动脚本(OnmyojiAutoScript)作为一款为玩家提供自动…...

突破设备壁垒:用swyh-rs构建零成本家庭音频网络的新方案

突破设备壁垒:用swyh-rs构建零成本家庭音频网络的新方案 【免费下载链接】swyh-rs Stream What You Hear written in rust, inspired by SWYH. 项目地址: https://gitcode.com/gh_mirrors/sw/swyh-rs 在智能家居普及的今天,音频设备却常常陷入&qu…...

5大核心优势揭秘:TradingAgents-CN如何用AI重构金融智能决策?

5大核心优势揭秘:TradingAgents-CN如何用AI重构金融智能决策? 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 当个人投资…...

SSA-KELM多输出回归算法的MATLAB实现与应用:基于麻雀搜索算法优化核极限学习机的代码...

SSA-KELM多输入多输出回归 基于麻雀搜索算法(SSA)优化核极限学习机(KELM)的数据多输出回归预测,Matlab代码,可直接运行,适合小白新手(多输入多输出回归预测) 程序已经调试好,仅需根据需要修改outdim值(输出个数)替换数据集即可运行…...

Step3-VL-10B-Base赋能产业分析:解读“一线产区和二线产区”视觉差异

Step3-VL-10B-Base赋能产业分析:解读“一线产区和二线产区”视觉差异 你有没有想过,那些摆在货架上、标着不同产区的商品,比如茶叶、葡萄酒,它们看起来到底有什么不一样?是包装更精美,还是颜色更深邃&…...

5大场景全面解析SWE-bench:语言模型软件工程能力实战指南

5大场景全面解析SWE-bench:语言模型软件工程能力实战指南 【免费下载链接】SWE-bench SWE-Bench: Can Language Models Resolve Real-world Github Issues? 项目地址: https://gitcode.com/GitHub_Trending/sw/SWE-bench 核心价值:为什么SWE-ben…...

电子电路耦合技术详解与应用指南

1. 电子电路中的耦合技术解析1.1 耦合的基本概念在电子电路设计中,耦合是指将前级电路(信号源)的能量传递至后级电路(负载)的技术过程。这一基础概念在各类电子系统中具有普遍应用价值,特别是在多级放大电路…...

ESP设备精准控制终极指南:esptool的量子级实时响应技术

ESP设备精准控制终极指南:esptool的量子级实时响应技术 【免费下载链接】esptool Espressif SoC serial bootloader utility 项目地址: https://gitcode.com/gh_mirrors/es/esptool esptool是一款由Espressif Systems开发的专业串行引导程序工具,…...