news 2026/10/13 16:01:05

C# 实战 Tesseract-OCR:中英日韩多语言识别与性能调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C# 实战 Tesseract-OCR:中英日韩多语言识别与性能调优

简介:这份资源面向需要在C#项目中集成OCR能力的开发者,重点解决中、英、日、韩等多语言文字的图像识别需求。内容围绕Tesseract-OCR这一开源引擎展开,涵盖.NET封装库的引入方式、语言数据包配置、识别引擎实例化与文本提取等关键环节,并涉及图像预处理、字符集白名单、多语言混合识别等提升准确率的实用思路,适合具备一定C#基础、希望快速落地票据、证件、扫描件等文本抽取场景的中级开发者。资源包共50个文件,以cs源码、dll动态库、traineddata语言数据包、config配置及resx资源文件为主,另含exe可执行程序与pdb调试符号,压缩包约44.3MB,x86与x64目录结构清晰,便于直接运行与二次开发。目前已有4142人学习下载,可作为C#调用Tesseract-OCR的完整参考工程,帮助读者省去环境搭建与语言包配置的摸索成本。

1. 从一张糊掉的扫描件说起:C# 里把 Tesseract-OCR 跑通到底要几步

上周同事甩过来一个文件夹,里面是三百多张扫描的合同页,要求把中英日韩四种语言的文字全部抽出来做成可检索的文本。他试过几个在线 OCR 接口,要么按量收费,要么日韩文识别率惨不忍睹,要么干脆不支持批量。我接手后的第一反应就是 Tesseract-OCR——这个从惠普实验室走出来、后来由 Google 维护的开源引擎,在 C# 里通过 Tesseract 包装库就能直接调用,离线跑、不花钱、支持一百多种语言,中英日韩全在射程内。

但真动手你会发现,从 NuGet 装包到跑出第一行正确的中文,中间隔着一堆坑:语言包放哪、tessdata 路径怎么配、图片预处理做到什么程度、PageSegMode 选哪个模式。这篇就把我在 C# 项目里用 Tesseract-OCR 的完整链路拆开,从环境搭建到多语言识别再到参数调优,每一步都给出可复现的代码和参数说明。如果你手头正好有批量识别中英日韩文档的需求,或者之前试过 Tesseract 但被识别率劝退,这篇应该能帮你省下几个小时的试错时间。

2. 环境搭建与语言包配置:别让 tessdata 成为第一个翻车点

2.1 NuGet 包选型:Tesseract 还是 Emgu.CV 封装

在 C# 里调 Tesseract,主流路线有两条。一条是直接用Tesseract这个 NuGet 包(GitHub 上 charlesw 维护的 tesseract 分支),它把 Tesseract 的 C++ API 用 P/Invoke 包了一层,接口干净,依赖少。另一条是走 Emgu.CV 的 OCR 模块,Emgu.CV 本身是 OpenCV 的 .NET 封装,它内部也集成了 Tesseract,但版本往往滞后,而且你为了 OCR 还得把整个 OpenCV 运行时拖进来,包体积直接翻几倍。

我一般选第一条路。安装命令就一行:

dotnet add package Tesseract

装完之后项目里会多出x64和x86两个原生 DLL 目录,这是 Tesseract 引擎的 C++ 编译产物,运行时必须保证它们被复制到输出目录。如果你用的是 .NET Framework 项目,通过 NuGet 安装后这些原生 DLL 会自动进bin;.NET Core / .NET 5+ 项目里,需要确认.csproj里有类似这样的配置,否则发布时会漏掉:

<ItemGroup> <None Update="x64\*.dll"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> <None Update="x86\*.dll"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>

这里有个容易忽略的点:Tesseract 包默认只带英文语言数据。你要识别中文、日文、韩文,必须单独下载对应的traineddata文件。这些文件在 tesseract-ocr 的 GitHub 仓库里有,文件名分别是chi_sim.traineddata(简体中文)、chi_tra.traineddata(繁体中文)、jpn.traineddata(日文)、kor.traineddata(韩文)。下载后统一放到一个叫tessdata的文件夹里。

2.2 tessdata 路径的三种配法及各自适用场景

tessdata放哪、代码里怎么指,是新手最容易卡住的地方。我见过有人把 traineddata 直接丢在bin\Debug根目录下,然后抱怨TesseractEngine初始化报 “Failed to find data file”。Tesseract 引擎找语言文件有一套自己的搜索逻辑,你得按它的规矩来。

第一种,显式传路径。在new TesseractEngine()的第二个参数里写死 tessdata 的绝对或相对路径:

using Tesseract; // path 指向包含 traineddata 文件的目录 var engine = new TesseractEngine(@"D:\ocr\tessdata", "chi_sim", EngineMode.Default);

这种方式最直接,适合 tessdata 放在项目外部、多个项目共享一份语言包的场景。缺点是路径硬编码,换台机器就得改。

第二种,用环境变量。Tesseract 会读TESSDATA_PREFIX这个环境变量,你可以在程序启动时设置:

Environment.SetEnvironmentVariable("TESSDATA_PREFIX", @"D:\ocr\tessdata"); var engine = new TesseractEngine(@"./", "chi_sim+eng", EngineMode.Default);

注意第二个参数传"./"时,引擎会去TESSDATA_PREFIX指向的目录找语言文件。这种方式适合部署环境统一、可以通过配置文件注入路径的情况。

第三种,把 tessdata 作为项目内容文件,随程序一起发布。在.csproj里把 tessdata 目录标记为Content并设置CopyToOutputDirectory,运行时用相对路径@"./tessdata"访问。这是最省心的做法,尤其适合桌面应用打包分发。

提示:多个语言同时识别时,语言代码用+连接,比如"chi_sim+eng+jpn+kor"。但要注意,加载的语言越多,初始化越慢,内存占用也越大。如果一次只需要识别一种语言,别图省事全加载。

2.3 初始化引擎与第一个可运行示例

环境配好之后,先跑一个最小可运行示例,确认整条链路是通的。下面这段代码读取一张图片,用中英混合模式识别,输出文本和置信度:

using Tesseract; using System; class Program { static void Main() { // tessdata 目录放在程序运行目录下 string tessDataPath = @"./tessdata"; // 中英混合识别,语言代码用 + 连接 using (var engine = new TesseractEngine(tessDataPath, "chi_sim+eng", EngineMode.Default)) { // 加载待识别图片 using (var img = Pix.LoadFromFile(@"test_contract.png")) { // 执行识别 using (var page = engine.Process(img)) { string text = page.GetText(); float confidence = page.GetMeanConfidence(); Console.WriteLine($"识别置信度: {confidence:F2}"); Console.WriteLine("识别结果:"); Console.WriteLine(text); } } } } }

这段代码里几个关键点:Pix.LoadFromFile支持 PNG、JPEG、TIFF、BMP 等常见格式,底层走的是 Leptonica 图像处理库。EngineMode.Default表示使用标准的 LSTM 引擎,如果你用的是旧版 traineddata(非 LSTM),可能需要改成EngineMode.TesseractOnly。page.GetMeanConfidence()返回的是整页的平均置信度,范围 0 到 1,低于 0.6 基本说明识别质量有问题,得回头查图片质量或参数配置。

跑通这一步之后,你至少能确认三件事:原生 DLL 加载正常、tessdata 路径正确、语言包版本和引擎版本匹配。这三件事任何一件出问题,都会在new TesseractEngine或engine.Process时抛异常。

3. 多语言识别实战:中英日韩混排文档的处理策略

3.1 语言代码组合与加载顺序对识别率的影响

Tesseract 支持一次加载多个语言,语法是"lang1+lang2+lang3"。但这里有个很多人不知道的细节:语言加载顺序会影响识别结果的倾向性。Tesseract 在识别时会综合多个语言的字符集和语言模型来打分,排在前面的语言在模糊字符的判定上会有微弱优势。

举个例子,中日文里都有大量汉字,但日文汉字和简体中文汉字的字形有差异。如果你识别的是日文文档,语言代码写成"chi_sim+jpn",引擎可能会把某些日文汉字往简体中文方向靠,导致输出里混入不该有的简体字形。正确的做法是把目标语言放在前面:"jpn+chi_sim"。

对于中英日韩四语混排的文档,我一般会根据文档主体语言来决定顺序。如果主要是中文合同里夹杂英文术语和少量日韩文,用"chi_sim+eng+jpn+kor";如果是一份多语言对照的说明书,每种语言段落分明,更好的做法是先按段落切分,再对每个段落用对应的单语言模式识别,而不是一股脑全丢给多语言引擎。

// 根据文档主体语言选择语言组合 string lang = "chi_sim+eng"; // 中文为主,英文为辅 // string lang = "jpn+eng"; // 日文为主 // string lang = "kor+eng"; // 韩文为主 using (var engine = new TesseractEngine(@"./tessdata", lang, EngineMode.Default)) { // 设置页面分割模式为自动 engine.DefaultPageSegMode = PageSegMode.Auto; using (var img = Pix.LoadFromFile(@"mixed_doc.png")) using (var page = engine.Process(img)) { Console.WriteLine(page.GetText()); } }

PageSegMode.Auto会让引擎自动分析页面布局,适合大多数场景。但如果你的图片是单栏纯文本,用PageSegMode.SingleBlock或PageSegMode.SingleLine往往能拿到更高的识别率,因为引擎不需要花精力去猜版面结构。

3.2 图片预处理:灰度化、二值化与去噪的代码实现

Tesseract 对图片质量的要求比很多人想象的要高。直接拿手机拍的文档照片去识别,背景阴影、倾斜角度、光照不均都会让识别率断崖式下跌。我的一般做法是在送入 Tesseract 之前,先用 OpenCV 或 System.Drawing 做一轮预处理。

核心步骤就三个:灰度化、二值化、去噪。灰度化把彩色图转成单通道,减少干扰;二值化把灰度图转成黑白两色,让文字和背景彻底分离;去噪去掉孤立的像素点,避免被误识别成标点。

用 OpenCVSharp 实现的预处理代码如下:

using OpenCvSharp; // 读取原图 Mat src = Cv2.ImRead(@"raw_photo.jpg"); // 转灰度 Mat gray = new Mat(); Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); // 自适应二值化,对光照不均的图片效果更好 Mat binary = new Mat(); Cv2.AdaptiveThreshold(gray, binary, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 15, 10); // 中值滤波去噪 Mat denoised = new Mat(); Cv2.MedianBlur(binary, denoised, 3); // 保存预处理结果,送入 Tesseract Cv2.ImWrite(@"preprocessed.png", denoised);

AdaptiveThreshold的两个关键参数:blockSize设为 15 表示每个像素参考周围 15×15 的区域来计算阈值,图片分辨率越高这个值应该越大;C设为 10 是从计算出的阈值里减去的常数,用来微调二值化的激进程度。MedianBlur的核大小 3 表示 3×3 邻域取中值,对椒盐噪声特别有效,但核太大会把细笔画文字也模糊掉。

预处理不是越复杂越好。我试过对一张本身就很干净的扫描件做全套预处理,结果反而因为二值化把一些浅色文字直接抹掉了。判断标准很简单:预处理后的图片用肉眼看看,文字是否清晰、背景是否干净。如果原图已经足够好,跳过预处理直接识别。

3.3 识别结果的后处理与置信度过滤

Tesseract 返回的原始文本里经常夹杂一些低置信度的垃圾字符,尤其是图片边缘的噪点被误识别成标点的情况。page.GetText()拿到的是纯文本,但如果你需要更细粒度的控制,可以用page.GetIterator()遍历每个识别块,拿到每个词的置信度和边界框。

using (var iter = page.GetIterator()) { iter.Begin(); do { // 获取当前词的文本和置信度 string word = iter.GetText(PageIteratorLevel.Word); float conf = iter.GetConfidence(PageIteratorLevel.Word); // 置信度低于 60 的词丢弃或标记 if (conf > 60) { Console.Write(word + " "); } else { Console.Write($"[?{word}?] "); } } while (iter.Next(PageIteratorLevel.Word)); }

这段代码把置信度低于 60 的词用[? ?]标记出来,方便后续人工校对。实际项目里,我一般会把低置信度词连同它的坐标一起输出到日志,然后针对这些区域回头调整预处理参数或换用单语言模式重新识别。

后处理还包括一些规则化的清洗:中文文本里常见的全角空格、日文里的特殊引号、韩文里的组合字符,这些在不同语言混排时容易出现编码层面的小问题。用正则做一轮统一替换,能省掉不少下游处理的麻烦。

4. 参数调优与性能优化:让识别率从 70% 到 90%

4.1 PageSegMode 的七种模式与选择依据

PageSegMode是 Tesseract 里对识别结果影响最大的参数之一,它告诉引擎如何理解页面布局。很多人一直用默认的Auto,但在特定场景下换一个模式,识别率可能直接提升一截。

模式适用场景注意事项
Auto未知布局,通用最慢,但适应性最强
SingleBlock单栏纯文本比 Auto 快,适合文档扫描件
SingleLine单行文本适合验证码、标签识别
SingleWord单个词适合关键词提取
SingleChar单个字符适合字符级识别任务
SparseText稀疏文本,无固定布局适合街景文字、海报
SparseTextOsd稀疏文本+方向检测适合任意角度拍摄的文字

我处理合同扫描件时一般用SingleBlock,因为合同基本都是单栏排版,用Auto反而会让引擎在页眉页脚和正文之间反复切换分析策略,拖慢速度。处理发票或表格时,SparseText更合适,因为表格线会把版面切碎,Auto模式容易把单元格内容当成独立块处理导致顺序错乱。

设置方式很简单,在engine.Process之前指定:

engine.DefaultPageSegMode = PageSegMode.SingleBlock;

或者在Process方法里临时指定:

using (var page = engine.Process(img, PageSegMode.SingleBlock)) { // ... }

4.2 多线程批量识别的资源管理

Tesseract 的TesseractEngine实例不是线程安全的,多个线程同时调用同一个引擎实例的Process方法会导致崩溃或结果错乱。批量处理大量图片时,正确的做法是每个线程持有独立的引擎实例,或者用对象池管理一组引擎实例轮流使用。

using System.Collections.Concurrent; using System.Threading.Tasks; // 用 ConcurrentBag 管理引擎实例池 var enginePool = new ConcurrentBag<TesseractEngine>(); int poolSize = Environment.ProcessorCount; // 按 CPU 核心数设置池大小 // 初始化引擎池 for (int i = 0; i < poolSize; i++) { enginePool.Add(new TesseractEngine(@"./tessdata", "chi_sim+eng", EngineMode.Default)); } // 并行处理图片列表 var imageFiles = System.IO.Directory.GetFiles(@"D:\scans", "*.png"); Parallel.ForEach(imageFiles, new ParallelOptions { MaxDegreeOfParallelism = poolSize }, file => { if (enginePool.TryTake(out var engine)) { try { using (var img = Pix.LoadFromFile(file)) using (var page = engine.Process(img)) { string text = page.GetText(); // 保存识别结果 System.IO.File.WriteAllText(file + ".txt", text); } } finally { enginePool.Add(engine); // 用完归还池中 } } });

这里有几个参数值得注意:MaxDegreeOfParallelism控制并发度,设成 CPU 核心数比较合理,设太大反而会因为内存竞争拖慢整体速度。每个TesseractEngine实例初始化时会加载语言模型到内存,中英日韩四语全加载大概占 200MB 到 300MB 内存,所以池大小也要考虑机器内存上限。如果内存紧张,可以减小池大小,或者按语言分组,不同语言用不同的池。

4.3 识别速度与内存占用的平衡

Tesseract 的识别速度受图片分辨率影响很大。一张 300 DPI 的 A4 扫描件大概 2500×3500 像素,识别一页需要 2 到 5 秒。如果把分辨率降到 150 DPI,速度能快一倍,但小字号的识别率会下降。我的经验是:正文不小于 10pt 的文档,200 DPI 足够;有脚注或小字的,保持 300 DPI。

内存方面,除了引擎本身占用的模型内存,Pix对象在处理大图时也会占用可观的内存。Pix.LoadFromFile加载的图片会以未压缩的位图形式存在内存里,一张 300 DPI 的彩色 A4 图大概占 25MB。批量处理时一定要用using确保Pix和Page对象及时释放,否则内存会持续增长直到 OOM。

如果识别速度是瓶颈,还有一个技巧:先用低分辨率快速识别一遍,拿到每个文本块的边界框,然后只对置信度低的区域用高分辨率重新识别。这种两阶段策略在文档质量参差不齐的场景下特别有效,整体速度能提升 30% 到 50%。

5. 避坑与排查:那些让我加班到凌晨的 Tesseract 问题

5.1 初始化报 “Failed to find data file” 或 “Error opening data file”

现象:new TesseractEngine(tessDataPath, "chi_sim", ...)直接抛异常,提示找不到数据文件。

原因:tessdata 路径不对,或者 traineddata 文件名不对。Tesseract 对文件名大小写敏感,chi_sim.traineddata写成chi_sim.TrainedData在某些平台上会失败。另外,如果你下载的是.traineddata.gz压缩包,必须先解压,引擎不认压缩格式。

解决:确认 tessdata 目录下确实有chi_sim.traineddata文件,文件名全小写,扩展名是.traineddata。用绝对路径先测试,排除相对路径的干扰。如果用的是TESSDATA_PREFIX环境变量,注意路径末尾不要多加斜杠。

5.2 中文识别结果全是乱码或问号

现象:识别出来的文本里中文部分显示为???或乱码。

原因:最常见的是 traineddata 版本和 Tesseract 引擎版本不匹配。旧版引擎加载新版 LSTM 模型,或者反过来,都会导致字符映射失败。另一个原因是输出编码问题,page.GetText()返回的是 UTF-8 字符串,如果你把它写到文件时用了错误的编码(比如 GBK),中文就会乱码。

解决:确认 Tesseract NuGet 包的版本和 traineddata 的版本对应。一般来说,Tesseract 4.x 的包配 tessdata 仓库里4.0.0分支的 traineddata。写文件时显式指定 UTF-8 编码:File.WriteAllText(path, text, Encoding.UTF8)。

5.3 日韩文识别率极低,几乎不可用

现象:英文和中文识别正常,但日文或韩文部分错误率超过 50%。

原因:日文和韩文的字符集比中文更复杂。日文有平假名、片假名、汉字三套字符系统,韩文有谚文音节组合。如果图片分辨率不够,假名和谚文的细小笔画会糊在一起,引擎无法区分。另外,如果语言代码只写了"jpn"但图片里混有英文,英文部分也会被当成日文乱猜。

解决:日韩文文档的扫描分辨率建议不低于 300 DPI。语言代码加上英文:"jpn+eng"或"kor+eng"。如果文档里日文汉字和中文汉字混排,考虑分段处理,不要用"chi_sim+jpn"这种组合去硬扛。

5.4 批量处理时程序崩溃或内存溢出

现象:处理几十张图片后程序无响应,或者抛OutOfMemoryException。

原因:Pix和Page对象没有及时释放,或者引擎实例创建过多。TesseractEngine实现了IDisposable,但很多人忘了在批量循环里释放它。

解决:每个Pix、Page、TesseractEngine都用using包裹。批量处理用引擎池而不是每次新建。如果图片特别大,考虑先缩放到合理分辨率再送入识别。

5.5 识别结果里混入大量无关符号或空白

现象:输出文本里出现大量~、|、©等无关字符,或者段落之间空白行过多。

原因:图片边缘的噪点、扫描件的黑边、或者 PDF 转图片时留下的页眉页脚线条被误识别成字符。PageSegMode.Auto在处理这类图片时容易把非文字区域也纳入识别范围。

解决:预处理时用Cv2.CopyMakeBorder给图片加一圈白色边框,或者用轮廓检测裁掉黑边。识别时改用PageSegMode.SingleBlock限制识别区域。后处理阶段用正则过滤掉连续的非文字字符。

6. 进阶技巧:用 Tesseract 做结构化数据提取

跑通基础识别之后,真正的价值在于把 OCR 结果变成结构化数据。比如从一批格式固定的发票里提取金额、日期、发票号,或者从合同里提取甲乙方名称和签署日期。Tesseract 本身只负责把图片转成文本,结构化提取需要你在文本之上再做一层解析。

我的做法是结合PageIterator的坐标信息和正则表达式。PageIterator可以拿到每个词或每行的边界框,这样你就能根据位置关系来判断哪些文本属于同一个字段。比如发票上的金额通常在右下角区域,你可以先按坐标筛选出右下角区域的文本块,再用正则匹配数字和货币符号。

using (var iter = page.GetIterator()) { iter.Begin(); do { // 获取当前行的文本和边界框 string lineText = iter.GetText(PageIteratorLevel.TextLine); if (iter.TryGetBoundingBox(PageIteratorLevel.TextLine, out Rect rect)) { // 筛选右下角区域(假设图片宽度 2000,高度 3000) if (rect.X1 > 1200 && rect.Y1 > 2000) { // 在右下角区域里用正则找金额 var match = System.Text.RegularExpressions.Regex.Match( lineText, @"[\d,]+\.\d{2}"); if (match.Success) { Console.WriteLine($"金额: {match.Value}"); } } } } while (iter.Next(PageIteratorLevel.TextLine)); }

这段代码的核心思路是“空间过滤 + 正则匹配”。TryGetBoundingBox返回的Rect包含X1、Y1、X2、Y2四个坐标,你可以根据业务场景定义任意区域。正则部分根据实际字段格式调整,金额、日期、编号各有各的模式。

另一个进阶用法是训练自定义语言模型。Tesseract 支持用tesstrain工具基于你的特定字体和排版训练专属模型。如果你的文档用的是某种特殊字体,或者包含大量专业术语,通用模型识别率不理想,花半天时间训练一个小型专用模型,识别率往往能有明显提升。训练流程大致是:准备文本和对应图片、生成 box 文件、校正 box、执行训练、合并模型。具体命令这里不展开,但思路是值得了解的——当通用方案触顶时,定制化是最后一道防线。

从那以后我每次接手 OCR 项目,都会先拿十张典型图片跑一轮基线测试,记录每种语言、每种模式的识别率和耗时,再决定预处理策略和参数组合。这个习惯帮我避免了很多次“上线后才发现识别率不达标”的尴尬。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 15:58:21

hygen 参数预填充与 index.js 钩子:让 CLI 参数绕过提示直达模板

开发工具CLI 【免费下载链接】hygen The simple, fast, and scalable code generator that lives in your project. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/hy/hygen 点击查看 免费下载 本篇文章围绕 hygen 测试夹具 index-js-existing-params 揭示的核心能力展…

作者头像 李华
网站建设 2026/10/13 15:56:09

TypeScript类型编程入门:从Pick实现看keyof、泛型约束与映射类型

type-challenges 这个项目&#xff0c;我陆陆续续刷过好几轮。说实话&#xff0c;前面十几道基础题里&#xff0c;第 4 题“实现 Pick”是最值得停下来认真琢磨的一道。它表面上只让你做一个MyPick<T, K>&#xff0c;实际上把 TypeScript 类型系统里最常用的四块积木全串…

作者头像 李华
网站建设 2026/10/13 15:55:04

C语言数组与指针核心解析:从内存模型到工程实践

数组这堂课&#xff0c;几乎每个学C语言的人都逃不掉。可我发现一个有意思的现象&#xff1a;很多人学到指针之前&#xff0c;觉得数组简单得不行&#xff0c;不就是“一堆同类型数据排排坐”嘛&#xff1b;但一学到指针&#xff0c;再回头碰数组&#xff0c;突然又觉得哪哪都对…

作者头像 李华
网站建设 2026/10/13 15:51:11

OpenClaw高危漏洞预警:云主机Agent网关的安全加固实战指南

最近安全圈子里陆续在传一个消息&#xff1a;OpenClaw出现高危漏洞预警。如果你正好把OpenClaw这类Agent网关部署在优刻得云主机上&#xff0c;我建议先别急着翻补丁文档&#xff0c;当务之急是把资产暴露面收住&#xff0c;再做系统加固。这篇文章就从OpenClaw为什么容易被盯上…

作者头像 李华
网站建设 2026/10/13 15:51:08

litellm:统一多模型API的LLM网关实践与部署指南

做后端一年多了&#xff0c;从最早接各种大模型 API 一个个写 SDK 封装&#xff0c;到后来维护一套又一套接口代理&#xff0c;我算是被这类“重复造轮子”的活折磨过不少次。如果你最近也在折腾 LLM 应用&#xff0c;大概率听过一个叫litellm的名字。这东西最早是作为“把所有…

作者头像 李华
网站建设 2026/10/13 15:50:28

中国1km土地利用数据1980-2015:长时序分析实战与避坑指南

简介&#xff1a;这份资源是中国1km土地利用遥感监测数据集&#xff0c;覆盖1980至2015年间共45个年份&#xff0c;面向地理学、环境科学、城乡规划及经济学等领域的研究者与政策分析人员&#xff0c;用于探究近四十年土地利用变迁、城市扩张、生态保护与农业动态等议题。压缩包…

作者头像 李华