用 TensorRT 加速 PP-OCR:一套 C++ DLL + C# 调用的高性能 OCR 推理方案
目录说明效果项目特点为什么选择 FP16适用场景测试体验部署建议时间不稳定设置C#调用源码下载说明在 OCR 项目落地中很多人都会遇到同一个问题模型效果不错但推理速度、部署便利性、GPU 兼容性、内存稳定性很难同时兼顾。最近我们基于 PP-OCR 系列模型完成了一套新的 TensorRT 推理版本lw.TensorRT.PPOCRSharp它采用 C 实现底层高性能推理 DLLC# 负责界面调用和业务集成适合 Windows 环境下对 OCR 速度有要求的场景。效果NVIDIA GeForce RTX4060 Laptop GPU (8 GB)CUDA 12.4TensorRT-10.16.1.11项目特点TensorRT GPU 推理加速底层使用 NVIDIA TensorRT 直接加载转换后的.engine文件进行推理相比通用推理框架在 NVIDIA GPU 上更容易获得更低延迟。C DLL 封装C# 简单调用核心推理逻辑封装在 C DLL 中C# 端通过 P/Invoke 调用既保证性能也方便 WinForms、WPF、业务系统集成。支持 PP-OCR 多版本模型当前测试程序中已加入多组模型选择PP-OCRv5 mobilePP-OCRv5 serverPP-OCRv6 tinyPP-OCRv6 smallPP-OCRv6 medium可以根据速度、精度、显存占用灵活选择。支持 det / rec / cls 三阶段 OCR完整支持文本检测、文本识别、方向分类模型调用。实际使用时也可以关闭 cls进一步提升速度。自动检测 TensorRT engine 文件程序会直接加载已经转换好的.engine文件。如果缺少 engineC# 程序会自动生成trtexec_convert_commands.txt说明文档提示用户如何使用本机trtexec.exe转换 ONNX 模型。因为不同电脑 TensorRT 安装路径不同文档中使用TRTEXEC占位用户只需要替换成本机路径即可。GPU ID 可配置界面保留use_gpu和gpu_id设置适合多显卡环境。底层 C 已经处理 CUDA device 绑定避免多线程推理时跑错 GPU。多 predictor 并发识别识别模型支持多个 predictor 并行处理适合一张图中存在多行文本的场景。实际部署时可以根据显卡性能调整rec_predictor_num并不是越大越好建议从 1、2、4 逐步测试。为什么选择 FP16TensorRT 支持 FP16 和 INT8但 OCR 模型尤其是 rec 识别模型对量化非常敏感。在实际测试中未经充分校准的 INT8 可能出现识别为空、准确率明显下降等问题。因此当前版本选择 FP16 作为默认和推荐方案速度提升明显精度更稳定转换流程简单更适合通用部署适用场景这套方案适合Windows 桌面 OCR 软件工业视觉字符识别票据、表单、截图 OCR批量图片文字识别C# 项目需要调用高性能 OCR DLLNVIDIA GPU 环境下追求更低延迟的 OCR 推理测试体验在 TensorRT FP16 engine 准备好之后程序启动后即可初始化模型并进行识别。典型流程选择 OCR 模型设置 GPU ID、batch、predictor 数量点击初始化选择图片点击识别程序会输出 det、rec、整体 OCR 耗时方便对不同模型、不同参数进行性能对比。部署建议为了获得更稳定的速度建议使用 NVIDIA 独立显卡设置 NVIDIA 电源管理模式为“最高性能优先”Windows 电源模式设置为高性能初始化后先预热几次再统计速度不建议跨机器复用 TensorRT engine不同显卡、驱动、CUDA、TensorRT 版本建议重新转换 engine时间不稳定设置1、查询GPU最高频率2、锁定GPU频率3、低延时模式设置为超高性4、电源管理模式设置为最高性能优先C#调用源码using Newtonsoft.Json; using OpenCvSharp; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace OCRTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } const string DllName lw.TensorRT.PPOCRSharp.dll; //初始化 [DllImport(DllName, EntryPoint init, CallingConvention CallingConvention.Cdecl)] public extern static int init(ref IntPtr engine , [MarshalAs(UnmanagedType.I1)] bool use_gpu , int gpu_id , string det_model_dir , int limit_side_len , double det_db_thresh , double det_db_box_thresh , double det_db_unclip_ratio , [MarshalAs(UnmanagedType.I1)] bool use_dilation , [MarshalAs(UnmanagedType.I1)] bool cls , [MarshalAs(UnmanagedType.I1)] bool use_angle_cls , string cls_model_dir , double cls_thresh , double cls_batch_num , string rec_model_dir , string rec_char_dict_path , int rec_batch_num , int rec_img_h , int rec_img_w , int predictor_num , StringBuilder msg); //识别 [DllImport(DllName, EntryPoint ocr, CallingConvention CallingConvention.Cdecl)] public extern static int ocr(IntPtr engine, IntPtr image, StringBuilder msg, out IntPtr ocr_result, out int ocr_result_len); //识别按图像内存传入避免托管层依赖 C Mat ABI [DllImport(DllName, EntryPoint ocr2, CallingConvention CallingConvention.Cdecl)] public extern static int ocr2(IntPtr engine, int rows, int cols, int channels, IntPtr data, StringBuilder msg, out IntPtr ocr_result, out int ocr_result_len); //释放 [DllImport(DllName, EntryPoint destroy, CallingConvention CallingConvention.Cdecl)] public extern static int destroy(IntPtr engine, StringBuilder msg); static IntPtr OCREngine; private Bitmap bmp; private String imgPath null; private ListOCRResult ltOCRResult; private string fileFilter *.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tif;*.png; private StringBuilder OCRResultInfo new StringBuilder(); private StringBuilder OCRResultAllInfo new StringBuilder(); Pen pen new Pen(Brushes.Red, 2f); /// summary /// 选择图片 /// /summary /// param namesender/param /// param namee/param private void button1_Click(object sender, EventArgs e) { OpenFileDialog ofd new OpenFileDialog(); ofd.Filter fileFilter; if (ofd.ShowDialog() DialogResult.OK) { imgPath ofd.FileName; bmp?.Dispose(); bmp new Bitmap(imgPath); pictureBox1.Image bmp; richTextBox1.Clear(); button2_Click(null, null); } } /// summary /// 识别 /// /summary /// param namesender/param /// param namee/param private void button2_Click(object sender, EventArgs e) { if (OCREngine IntPtr.Zero) { MessageBox.Show(请先初始化); return; } if (imgPath null) { MessageBox.Show(请先选择图片); return; } button1.Enabled false; button2.Enabled false; richTextBox1.Clear(); OCRResultInfo.Clear(); OCRResultAllInfo.Clear(); StringBuilder msgTemp new StringBuilder(128); Stopwatch stopwatch new Stopwatch(); stopwatch.Start(); IntPtr strPtr IntPtr.Zero; int ocr_result_len 0; string ocr_result string.Empty; int res -1; try { using (Mat img Cv2.ImRead(imgPath, ImreadModes.Color)) { res ocr2(OCREngine, img.Rows, img.Cols, img.Channels(), img.Data, msgTemp, out strPtr, out ocr_result_len); } if (strPtr ! IntPtr.Zero ocr_result_len 0) { byte[] buffer new byte[ocr_result_len]; Marshal.Copy(strPtr, buffer, 0, ocr_result_len); ocr_result Encoding.UTF8.GetString(buffer); } stopwatch.Stop(); double totalTime stopwatch.Elapsed.TotalMilliseconds; OCRResultAllInfo.AppendLine($耗时: {totalTime:F2}ms); OCRResultAllInfo.AppendLine(---------------------------); OCRResultInfo.AppendLine($耗时: {totalTime:F2}ms); OCRResultInfo.AppendLine(---------------------------); if (res 0) { ltOCRResult Newtonsoft.Json.JsonConvert.DeserializeObjectListOCRResult(ocr_result); OCRResultAllInfo.Append(JsonConvert.SerializeObject(ltOCRResult, Newtonsoft.Json.Formatting.Indented)); using (Graphics graphics Graphics.FromImage(bmp)) { foreach (OCRResult item in ltOCRResult) { OCRResultInfo.AppendLine(item.text); System.Drawing.Point[] pt new System.Drawing.Point[] { new System.Drawing.Point(item.x1, item.y1) , new System.Drawing.Point(item.x2, item.y2) , new System.Drawing.Point(item.x3, item.y3) , new System.Drawing.Point(item.x4, item.y4) }; graphics.DrawPolygon(pen, pt); } } if (checkBox1.Checked) { richTextBox1.Text OCRResultAllInfo.ToString(); } else { richTextBox1.Text OCRResultInfo.ToString(); } pictureBox1.Image null; pictureBox1.Image bmp; } else { MessageBox.Show(识别失败 msgTemp.ToString()); } } finally { stopwatch.Stop(); if (strPtr ! IntPtr.Zero) { Marshal.FreeCoTaskMem(strPtr); } button1.Enabled true; button2.Enabled true; } } /// summary /// 初始化 /// /summary /// param namesender/param /// param namee/param private void Form1_Load(object sender, EventArgs e) { rdov6tiny.Checked true; chkcls.Checked false; chkuse_gpu.Checked true; txtgpu_id.Text 0; LoadDefaultImage(); } private void checkBox1_CheckedChanged(object sender, EventArgs e) { richTextBox1.Clear(); if (checkBox1.Checked) { richTextBox1.Text OCRResultAllInfo.ToString(); } else { richTextBox1.Text OCRResultInfo.ToString(); } } private void chkcls_CheckedChanged(object sender, EventArgs e) { if (OCREngine IntPtr.Zero) { return; } richTextBox1.Text ; Console.WriteLine(cls设置已改变正在重新初始化模型...); UnloadModel(); LoadModel(); } private void radioButton1_CheckedChanged(object sender, EventArgs e) { RadioButton rb sender as RadioButton; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { UnloadModel(); } private void btnDestroy_Click(object sender, EventArgs e) { UnloadModel(); } void UnloadModel() { if (OCREngine ! IntPtr.Zero) { StringBuilder msgTemp new StringBuilder(128); destroy(OCREngine, msgTemp); Console.WriteLine(释放成功: msgTemp.ToString()); OCREngine IntPtr.Zero; } } private void btnInit_Click(object sender, EventArgs e) { if (OCREngine ! IntPtr.Zero) { StringBuilder msgTemp new StringBuilder(128); destroy(OCREngine, msgTemp); Console.WriteLine(释放成功: msgTemp.ToString()); OCREngine IntPtr.Zero; LoadModel(); } else { LoadModel(); } } void LoadModel() { StringBuilder msgTemp new StringBuilder(128); bool use_gpu true; int gpu_id 0; string det_model_dir ; int limit_side_len 960; double det_db_thresh 0.3; double det_db_box_thresh 0.6; double det_db_unclip_ratio 1.2; bool use_dilation false; bool cls true; bool use_angle_cls true; string cls_model_dir inference_trt/PP-OCRv5_mobile_cls_onnx.engine; double cls_thresh 0.9; int cls_batch_num 1; string rec_model_dir ; string rec_char_dict_path inference/ppocrv5_dict.txt; int rec_batch_num 8; int rec_img_h 48; int rec_img_w 320; int predictor_num 4; //赋值 if (chkuse_gpu.Checked true) { use_gpu true; } else { use_gpu false; } gpu_id Convert.ToInt32(txtgpu_id.Text.ToString()); det_db_thresh Convert.ToDouble(txtdet_db_thresh.Text.ToString()); det_db_box_thresh Convert.ToDouble(txtdet_db_box_thresh.Text.ToString()); det_db_unclip_ratio Convert.ToDouble(txtdet_db_unclip_ratio.Text.ToString()); if (chkcls.Checked true) { cls true; } else { cls false; } cls_batch_num Convert.ToInt32(txtcls_batch_num.Text.ToString()); rec_batch_num Convert.ToInt32(txtrec_batch_num.Text.ToString()); predictor_num Convert.ToInt32(txtpredictor_num.Text.ToString()); if (rdomobile.Checked) { det_model_dir BuildEnginePath(PP-OCRv5_mobile_det_onnx); rec_model_dir BuildEnginePath(PP-OCRv5_mobile_rec_onnx); cls_model_dir BuildEnginePath(PP-OCRv5_mobile_cls_onnx); } elseif (rdoserver.Checked) { det_model_dir BuildEnginePath(PP-OCRv5_server_det_infer); rec_model_dir BuildEnginePath(PP-OCRv5_server_rec_infer); cls_model_dir BuildEnginePath(PP-OCRv5_server_cls_infer); } elseif (rdov6small.Checked) { det_model_dir BuildEnginePath(PP-OCRv6_small_det); rec_model_dir BuildEnginePath(PP-OCRv6_small_rec); rec_char_dict_path inference/PP-OCRv6_small_rec_dict.txt; } elseif (rdov6medium.Checked) { det_model_dir BuildEnginePath(PP-OCRv6_medium_det); rec_model_dir BuildEnginePath(PP-OCRv6_medium_rec); rec_char_dict_path inference/PP-OCRv6_medium_rec_dict.txt; } else { det_model_dir BuildEnginePath(PP-OCRv6_tiny_det); rec_model_dir BuildEnginePath(PP-OCRv6_tiny_rec); rec_char_dict_path inference/PP-OCRv6_tiny_rec_dict.txt; } if (!EnsureTensorRtEngines(det_model_dir, rec_model_dir, cls ? cls_model_dir : null, rec_batch_num)) { return; } Console.WriteLine(TensorRT precision: FP16); Console.WriteLine(det model: det_model_dir); if (cls !File.Exists(Path.Combine(Application.StartupPath, cls_model_dir.Replace(/, Path.DirectorySeparatorChar)))) { Console.WriteLine(cls model missing, disabled: cls_model_dir); cls false; use_angle_cls false; } Console.WriteLine(cls model: (cls ? cls_model_dir : disabled)); Console.WriteLine(rec model: rec_model_dir); Console.WriteLine(rec dict : rec_char_dict_path); int res init(ref OCREngine , use_gpu , gpu_id , det_model_dir , limit_side_len , det_db_thresh , det_db_box_thresh , det_db_unclip_ratio , use_dilation , cls , use_angle_cls , cls_model_dir , cls_thresh , cls_batch_num , rec_model_dir , rec_char_dict_path , rec_batch_num , rec_img_h , rec_img_w , predictor_num , msgTemp); if (res 0) { Console.WriteLine(模型加载成功); } else { string msg msgTemp.ToString(); Console.WriteLine(模型加载失败 msg); } } private bool EnsureTensorRtEngines(string detEngine, string recEngine, string clsEngine, int recBatchNum) { Liststring missing new Liststring(); foreach (string engine in new[] { detEngine, recEngine, clsEngine }) { if (string.IsNullOrWhiteSpace(engine)) continue; string fullPath Path.Combine(Application.StartupPath, engine.Replace(/, Path.DirectorySeparatorChar)); if (!File.Exists(fullPath)) missing.Add(engine); } if (missing.Count 0) { returntrue; } StringBuilder sb new StringBuilder(); sb.AppendLine(TensorRT FP16 engine 转换说明); sb.AppendLine(); sb.AppendLine(); sb.AppendLine(当前缺少以下 engine 文件请先使用 trtexec.exe 转换。); sb.AppendLine(不同电脑的 trtexec.exe 路径可能不同请把下面命令中的 TRTEXEC 替换为本机 trtexec.exe 的完整路径或把 TensorRT bin 目录加入 PATH 后替换为 trtexec.exe。); sb.AppendLine(); sb.AppendLine(常见位置示例); sb.AppendLine(C:\TensorRT-xx\bin\trtexec.exe); sb.AppendLine(项目目录\TensorRT-10.16.1.11.Windows.amd64.cuda-12.9\TensorRT-10.16.1.11\bin\trtexec.exe); sb.AppendLine(); sb.AppendLine(建议在 exe 所在目录执行以下命令); sb.AppendLine(Application.StartupPath); sb.AppendLine(); foreach (string engine in missing) { string onnx EngineToOnnxPath(engine); string outDir Path.GetDirectoryName(Path.Combine(Application.StartupPath, engine.Replace(/, Path.DirectorySeparatorChar))); Directory.CreateDirectory(outDir); string shape BuildTrtShapeArgs(engine, recBatchNum); sb.AppendLine(缺少 engine); sb.AppendLine(对应 ONNX onnx); sb.AppendLine(转换命令); sb.AppendLine($\TRTEXEC\ --onnx\{onnx.Replace(/, Path.DirectorySeparatorChar)}\ --saveEngine\{engine.Replace(/, Path.DirectorySeparatorChar)}\ --fp16 {shape}); sb.AppendLine(); } sb.AppendLine(转换完成后重新点击初始化。); sb.AppendLine(注意engine 和显卡型号、驱动、CUDA、TensorRT 版本绑定不建议跨机器复用。); string commandFile Path.Combine(Application.StartupPath, trtexec_convert_commands.txt); try { File.WriteAllText(commandFile, sb.ToString(), Encoding.UTF8); sb.AppendLine(); sb.AppendLine(转换命令已写入); sb.AppendLine(commandFile); } catch (Exception ex) { sb.AppendLine(); sb.AppendLine(转换命令写入 txt 失败); sb.AppendLine(ex.Message); } MessageBox.Show(sb.ToString(), 缺少 TensorRT engine, MessageBoxButtons.OK, MessageBoxIcon.Information); Console.WriteLine(sb.ToString()); returnfalse; } private string BuildEnginePath(string modelName) { returninference_trt/ modelName _fp16.engine; } private string EngineToOnnxPath(string engine) { string file Path.GetFileNameWithoutExtension(engine); if (file.EndsWith(_fp16, StringComparison.OrdinalIgnoreCase)) { file file.Substring(0, file.Length - 5); } returninference/ file .onnx; } private string BuildTrtShapeArgs(string engine, int recBatchNum) { string name Path.GetFileNameWithoutExtension(engine).ToLowerInvariant(); if (name.Contains(rec)) { int optBatch Math.Max(1, recBatchNum); int maxBatch Math.Max(optBatch, 16); return $--minShapesx:1x3x48x32 --optShapesx:{optBatch}x3x48x320 --maxShapesx:{maxBatch}x3x48x1280; } if (name.Contains(cls)) { return--minShapesx:1x3x80x160 --optShapesx:8x3x80x160 --maxShapesx:16x3x80x160; } return--minShapesx:1x3x32x32 --optShapesx:1x3x960x960 --maxShapesx:1x3x960x960; } private void LoadDefaultImage() { string defaultImagePath Path.Combine(Application.StartupPath, 3.jpg); if (!File.Exists(defaultImagePath)) { defaultImagePath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, 3.jpg); } if (!File.Exists(defaultImagePath)) { return; } imgPath defaultImagePath; bmp?.Dispose(); bmp new Bitmap(imgPath); pictureBox1.Image bmp; } } }下载通过网盘分享的文件lw.TensorRT.PPOCRSharp_Test 链接: https://pan.baidu.com/s/1bG5n0ZgJ7mW2fQ4dn9sjaQ 提取码: cmvf引入地址

相关新闻

终极终端输入法切换指南:告别手动切换的烦恼![特殊字符]

终极终端输入法切换指南:告别手动切换的烦恼![特殊字符]

终极终端输入法切换指南:告别手动切换的烦恼!🚀 【免费下载链接】im-select 📟 Switch your input method through terminal 项目地址: https://gitcode.com/gh_mirrors/im/im-select 还在为编程时频繁切换中英文输入法而烦…

2026/7/21 16:35:25阅读更多 →
加密不等于安全

加密不等于安全

很多开发者认为,只要对消息内容做了端到端加密,通信就是安全的。但现实远比这复杂。 让我们看一个场景:假设你在使用一个加密聊天软件,每条消息发送时,网络上会出现一个约 1500 字节的数据包,每隔 5 秒准时…

2026/7/21 16:35:26阅读更多 →
Cordova AdMob Pro开发者指南:深入理解AdMob.js的API设计与实现

Cordova AdMob Pro开发者指南:深入理解AdMob.js的API设计与实现

Cordova AdMob Pro开发者指南:深入理解AdMob.js的API设计与实现 【免费下载链接】cordova-admob-pro :fire: Cordova Plugin for Google AdMob, DFP, ADX. Easy monetization using mobile Ad, with single line of JavaScript. Compatible with Cordova CLI, Inoic…

2026/7/21 16:35:27阅读更多 →
Vibe编程:AI辅助的自然语言开发新范式

Vibe编程:AI辅助的自然语言开发新范式

1. 什么是Vibe编程?Vibe编程(Vibe Coding)是近年来兴起的一种新型软件开发方式,它彻底改变了传统编程的工作流程。简单来说,这是一种完全依赖AI辅助的编程方法,开发者只需要用自然语言描述需求,…

2026/7/22 6:43:07阅读更多 →
Tilix终端模拟器:Linux开发者的高效分屏利器

Tilix终端模拟器:Linux开发者的高效分屏利器

1. Tilix终端模拟器概述Tilix是一款基于GTK3开发的Linux终端模拟器,最初名为Terminix,后因商标问题更名为Tilix。作为GNOME桌面环境的原生应用,它采用了现代的界面设计风格,同时保留了传统终端工具的高效特性。我在日常开发工作中…

2026/7/22 6:43:07阅读更多 →
全品类对俄出口赋码技术方案:单套 CRPT 诚实标识采集系统的模块化设计解析

全品类对俄出口赋码技术方案:单套 CRPT 诚实标识采集系统的模块化设计解析

多品类货品同步出口俄罗斯时,企业若分品类采购独立赋码设备与管理软件,会增加产线改造、系统对接、人员培训等多重成本。本文从技术架构层面,详解深圳市兴通物联科技有限公司 CRPT 诚实标识采集系统,依靠统一解码硬件、模块化软件…

2026/7/22 6:43:07阅读更多 →
救命!2026年AI写论文工具排行榜,写论文卡壳的学生党直接抄作业

救命!2026年AI写论文工具排行榜,写论文卡壳的学生党直接抄作业

作为熬了 3 年论文、前后踩过十几款 AI 写作工具坑的老学长,今天直接给大家上硬货 ——2026 年 AI 写论文工具排行榜!结合《2025 论文写作工具白皮书》的用户实测数据,还有我从本科毕设到硕士小论文的全程使用体验,精选出 7 款真正…

2026/7/22 6:43:07阅读更多 →
Unity3D手游《最后一战》源码深度解析:从项目导入到核心系统学习

Unity3D手游《最后一战》源码深度解析:从项目导入到核心系统学习

1. 项目概述与价值定位拿到《最后一战》这个Unity3D手游的完整项目源码和资源包,对于任何一个想深入游戏开发,特别是想了解一款完整商业手游内部构造的开发者来说,这无异于拿到了一份珍贵的“工程图纸”。这不仅仅是一堆代码和美术资产的集合…

2026/7/22 6:43:07阅读更多 →
机器学习实战:房价预测系统开发指南

机器学习实战:房价预测系统开发指南

1. 项目概述"基于机器学习的房价预测系统"是一个典型的回归分析应用场景,它利用历史房产交易数据训练模型,从而对新房源的价格进行科学估算。这个项目完美结合了Python的数据处理能力和机器学习算法的预测能力,是数据科学入门者向实…

2026/7/22 6:41:07阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 0:53:59阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 0:53:59阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/22 0:53:59阅读更多 →
中小企业小程序开发公司怎么选:预算、上手和售后避坑指南

中小企业小程序开发公司怎么选:预算、上手和售后避坑指南

中小企业做小程序,最常见的矛盾是预算有限,但又不希望功能太单薄;没有技术团队,但又希望后续能自己运营;想快速上线,又担心隐性收费和售后失联。选型时如果只看“低价套餐”或“案例数量”,很容…

2026/7/22 0:01:17阅读更多 →
GEO优化如何沉淀长期内容资产?广拓时代谈AI搜索时代的内容ROI

GEO优化如何沉淀长期内容资产?广拓时代谈AI搜索时代的内容ROI

企业做营销,最怕钱花完了,资产没有留下。 效果广告能带来一段时间的曝光,但预算停止后,流量往往也随之停止。短视频内容可能在几天内冲高,也可能很快沉下去。AI搜索时代,企业需要重新思考一个问题&#xff…

2026/7/22 0:01:17阅读更多 →
Agent 终态判定:何时该停止思考、给出最终回复

Agent 终态判定:何时该停止思考、给出最终回复

Agent 终态判定:何时该停止思考、给出最终回复 一、你的 Agent 在"再想想"的循环里绕了 12 轮,用户已经关窗口了 Agent 与人最大的区别是:人知道什么时候该停下来给答案,Agent 会一直"想"下去。你给 Agent 接…

2026/7/22 0:01:17阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/21 22:53:50阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/21 18:53:30阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/21 18:53:30阅读更多 →