新闻详情

新闻详情

首页 / 资讯中心 / 详情

C#短信猫群发源码实战:串口AT指令与PDU编码全解析

发布时间:2026/9/29 15:49:31来源:尧图网络
C#短信猫群发源码实战:串口AT指令与PDU编码全解析
简介这是一份基于短信猫的C#短信群发系统完整源码面向需要快速搭建短信群发功能的企业开发者和.NET技术学习者。源码可实现批量短信发送通常涵盖短信模板管理、号码列表导入与处理、发送状态跟踪等环节适用于企业营销、通知服务等场景。压缩包内含114个文件主要包含38个C#源文件、17个resx界面资源文件、17个resources数据文件、14个gif图标、7个dll库及3个可执行程序另含数据库mdb、项目解决方案sln等整体仅721KB结构紧凑解压后即可编译运行。系统覆盖串口通信、GSM AT指令、多线程并发发送、数据库操作、界面设计与异常处理等核心模块可作为学习C#硬件通信与企业级应用开发的实战范例。已有120人学习适合具备一定C#基础、希望深入掌握短信猫二次开发及多线程编程的开发者参考借鉴。1. 短信猫不是过时方案C# 短信群发源码到底能做什么提到短信群发大多数人的第一反应是云平台API。但如果你在工厂、医院、学校或政企内网环境里做过消息提醒马上会碰上一道坎业务系统在隔离网段服务器不允许出公网或者数据敏感根本不想走第三方通道。这时候基于短信猫的 C# 短信群发方案反而是最稳的一条路。短信猫本质是一个工业级GSM模块加串口或USB接口的通讯设备C# 通过串口发AT指令就能驱动它不依赖外网一条硬件几十到几百块平均一条短信成本几分钱。它解决的问题不是“谁都能发”而是“在受控环境里、用自己的通道、稳定地把短信发出去”。这套源码方案适合三类人做上位机系统的工控开发、做内部运维告警的系统工程师、以及需要给大批量客户发通知但又不想接云服务的小团队。接下来的内容照着一个可落地的路径走先讲怎么选硬件和接口再给出一套能直接跑的 C# 串口通讯基类然后把 AT 指令交互、中文PDU编码、接收解析逐个拆开最后把最容易翻车的几个坑提前告诉你。新手跟步骤能跑通老手可以直接拿去改造成自己的消息中间件。2. 硬件选型与串口通讯短信猫方案的第一步是搞清设备和接口2.1 短信猫的三种接口选型串口、USB、网络口短信猫从接口上分三类原生RS232串口、USB转串口、以及带网口的IPModem。做 C# 开发时原生串口最简单直接System.IO.Ports.SerialPort就能驱动稳定性最好适合长期挂机的群发场景。USB口短信猫其实内部也是串口插上后会虚拟成一个COM口需要在设备管理器里确认端口号驱动层偶尔会因为休眠或拔插造成端口漂移适合临时用或低频率发送。网口短信猫走TCP/IP协议一般用Socket连它的9000端口优势是可以跨机器部署但价格贵一倍且需要额外的通讯协议封装。对绝大多数 C# 项目来说选USB口或者原生串口都行第一次做建议直接买原生串口或工业级USB猫省去很多兼容性上的血泪折腾。选型时还要看模块型号。市场上常见的是Wavecom Q2358C、SIMCom SIM900A、中兴MG2639等模块C# 代码层面差异不大因为它们都遵循标准AT指令。区别在于模块支持的频段是双频还是四频直接关系到国内的信号覆盖是否支持PDU格式的中文短信老模块只支持Text格式中文发不了是否有硬件流控引脚部分模块需要接RTS/CTS代码里要对应配置我一贯的建议是开发阶段买一个带串口线的原装Wavecom猫因为国内大量现成资料、测试工具都是基于这个型号的遇到问题好排查。上线阶段再换成便宜一些的兼容模块因为软件层你已经跑通了剩下的只是硬件稳定性问题。2.2 串口参数为什么是 9600,8,N,1一种习惯而非标准短信猫串口参数的“默认值”是波特率9600、数据位8、停止位1、无校验但这不是AT指令规定的而是绝大多数短信猫出厂固件的默认串口配置。真正决定参数的是模块手册里的“UART Configuration”一节不同厂商可能默认115200尤其是一些国产4G模块。所以写 C# 代码时第一件事不是抄参数而是拿串口调试工具逐个波特率试一遍直到发送AT\r能收到OK为止。C# 里SerialPort的关键参数设置如下using System.IO.Ports; var sp new SerialPort { PortName COM3, // 设备管理器里看到的端口号 BaudRate 9600, // 先在调试工具里确认再写死到代码 DataBits 8, Parity Parity.None, // 无校验 StopBits StopBits.One, Handshake Handshake.None, // 不用流控让模块自动处理 ReadTimeout 1000, // 读超时避免阻塞 WriteTimeout 1000, Encoding Encoding.ASCII // AT指令用 ASCII中文内容走 PDU }; sp.Open();说明两点Handshake这里设成None是因为大多数短信猫模块出厂默认关闭硬件流控如果你买的二手设备或工业模块需要流控就要改成Handshake.RequestToSend或Handshake.XOnXOff不然会出现发大段指令时数据被截断的现象。Encoding设ASCII是为了保证AT指令按字节发送如果设成UTF8某些中文字符会被错误编码导致指令直接被模块丢弃。打开端口后先做一次握手测试sp.WriteLine(AT\r); // 发送 AT 指令 Thread.Sleep(200); // 等待模块响应 string resp sp.ReadExisting(); // 读取返回内容 if (resp.Contains(OK)) Console.WriteLine(模块在线); else Console.WriteLine(请检查端口和波特率);读响应时不要用ReadLine()因为短信猫很多响应里混合着\r\nReadLine()在部分固件下会丢掉最后一段。ReadExisting()虽然后期做解析时不够严谨但用于连调阶段确认模块在线完全够用。2.3 一套 C# 串口基类发送、接收、事件回调的封装形式连调通过后不要直接在业务代码里到处写sp.Write。短信猫这种设备一次只能处理一条指令群发场景下并发操作会直接把模块状态机搞乱。常见做法是封装一个SmsCatService类内部持有一个串口实例、一个发送队列和一个接收线程。public class SmsCatService : IDisposable { private SerialPort _port; private readonly object _lockObj new object(); private readonly Queuestring _sendQueue new Queuestring(); private bool _isRunning true; public event Actionstring OnSmsReceived; // 来短信事件 public event Actionstring OnSendFailed; // 发送失败事件 public SmsCatService(string portName, int baudRate 9600) { _port new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One); _port.DataReceived Port_DataReceived; } public void Start() { _port.Open(); new Thread(ProcessQueue).Start(); // 后台线程处理发送队列 } public void Enqueue(string atCommand) { lock (_lockObj) { _sendQueue.Enqueue(atCommand); } } private void ProcessQueue() { while (_isRunning) { string cmd null; lock (_lockObj) { if (_sendQueue.Count 0) cmd _sendQueue.Dequeue(); } if (cmd ! null) { _port.WriteLine(cmd); Thread.Sleep(300); // 给模块留出处理时间 } else { Thread.Sleep(50); // 队列空时降低CPU占用 } } } private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { string data _port.ReadExisting(); // 这里先触发事件解析逻辑由上层实现 OnSmsReceived?.Invoke(data); } public void Dispose() { _isRunning false; _port?.Close(); _port?.Dispose(); } }这个封装的三个关键点串口写入全部串行化由队列和单线程保证不重入每次AT指令后固定延时300毫秒给模块留出处理时间不是越快越好的通信机制必须等待响应DataReceived事件在后台线程触发如果要更新WinForm或WPF界面必须通过Invoke或SynchronizationContext切换回UI线程否则会抛出跨线程访问异常。这套基类是后续所有AT指令交互的底座。3. AT指令集交互短信发送从 Text 到 PDU 的完整路径3.1 基础 AT 指令从开机关机到信号查询的必用指令集驱动短信猫的指令集遵循3GPP TS 27.005标准C# 项目中实际高频使用的指令不超过10条。先列一份必用指令参考表把指令意图、响应特征和注意事项写清楚指令作用成功响应特征注意点AT握手测试OK模块在线的基础判断ATCMGF1切换到Text模式OK发中文必须用PDU模式ATCMGF0切换到PDU模式OK默认就是PDU模式但显式设置更稳妥ATCSQ查询信号强度CSQ: 20,0第一个值范围0-31低于10基本发不出去ATCREG?查询网络注册状态CREG: 0,1第二值1或5表示已注册ATCMGS长度发送短信先返回再发内容最后返回CMGS: 编号长度是TPDU长度不是字符数ATCNMI1,1,0,0,0设置新短信的主动通知模块主动推送CMTI: SM,索引C# 里通过事件接收异步通知ATCMGLALL读取SIM卡内全部短信逐条返回CMGL: 索引,状态,...群发后建议清空否则越积越多这些指令里最需要关注的是ATCSQ。我给新接手的同事讲课时一直强调一个场景你代码写得再对信号强度不到10模块表现就是偶尔超时、偶尔成功、偶尔发出去对方收不到而且没有任何报错。这种“发货不稳定”的假象最耗时间排查。所以串口打开后的第一件事跑一次ATCSQ确认信号低于10就别排期上线去换位置或加天线。3.2 Text 模式发英文短信与 PDU 模式的核心区别短信猫支持两种短信格式Text模式适合纯英文短内容代码简单直接把内容写在ATCMGS号码后面以\x1A结束。PDU模式是3GPP定义的二进制封装格式把短信中心号、发送号码、内容编码、时间戳都合一包适合中文和长短信。C# 里要把一条中文短信发出核心就是构造这串PDU。两者的转换公式是短信猫源码里最不能抄错的部分因为每一步都是字节操作错一个半字节整包作废。先看 Text 模式最简单写法sp.Encoding Encoding.ASCII; sp.WriteLine(ATCMGF1); Thread.Sleep(200); sp.WriteLine(ATCMGS\8613800138000\); Thread.Sleep(200); sp.Write(Hello, this is a test message); sp.Write(\x1A); // CtrlZ 表示内容结束Text模式编码简单但只能发GSM 7-bit字符集的字符不支持中文。一旦内容里有中文模块会直接返回ERROR或者发出乱码。这时候就需要切到PDU模式先把中文转成Unicode编码的十六进制序列再按PDU规范的顺序逐字节排布。3.3 中文 PDU 编码计算 TP-Length 的完整流程C# 短信猫源码的核心难点就在PDU编码。以一条中文短信为例PDU可分为三大段短信中心号码、TPDU头、用户数据。中文用UCS2编码两个字节表示一个字符。构造流程按以下步骤public static string BuildPdu(string phoneNumber, string content) { // 第一步短信中心号码通常为空串表示用SIM卡默认中心 string smsc ; // 第二步把手机号转成 PDU 格式 string pduPhone PhoneNumberToPdu(phoneNumber); // 第三步中文内容转十六进制 UCS2 string pduContent ContentToUcs2Hex(content); // 第四步计算用户数据长度UCS2 每字符占2字节 int contentLength content.Length * 2; // 第五步拼出第一段不含中心号码的TPDU string header 11000D pduPhone 0008 contentLength.ToString(X2); // 第六步整包 PDU string fullPdu smsc header pduContent; // 第七步TPDU 长度 完整PDU 减半两个十六进制字符代表一字节 int tpLength (fullPdu.Length - smsc.Length) / 2; return tpLength : fullPdu; } static string PhoneNumberToPdu(string phone) { // 86 开头是国内手机号去掉 号 string national phone.StartsWith(86) ? phone.Substring(3) : phone; if (national.StartsWith(86) national.Length 12) national national.Substring(2); // 奇数长度末尾补 F if (national.Length % 2 1) national F; // 两两一组交换字节顺序 StringBuilder sb new StringBuilder(); for (int i 0; i national.Length; i 2) { sb.Append(national[i 1]); sb.Append(national[i]); } return sb.ToString(); } static string ContentToUcs2Hex(string content) { byte[] bytes Encoding.BigEndianUnicode.GetBytes(content); StringBuilder sb new StringBuilder(); foreach (byte b in bytes) sb.Append(b.ToString(X2)); return sb.ToString(); }这段代码的调用逻辑BuildPdu返回11之类的TP长度加冒号加完整PDU的字串然后发送指令是ATCMGS11模块返回后再把PDU内容发出去以\x1A结束。常出问题的地方有两个contentLength乘以2是因为UCS2下每个中文占2字节如果你内容里混了英文实际字节数可能是Encoding.BigEndianUnicode.GetByteCount(content)用字符数乘以2的方式会漏掉一个半字节的情况ContentToUcs2Hex必须用BigEndianUnicode短信PDU里的UCS2是大端序用系统默认的UnicodeUTF-16 LE编码会导致所有中文字节对调发出的短信全是乱码。3.4 完整发送一条中文短信的最小C#方法把上面所有环节串起来得到实际调用的发送函数public bool SendSms(string phone, string content) { lock (_lockObj) { try { _port.Encoding Encoding.ASCII; // 切换到 PDU 模式 _port.WriteLine(ATCMGF0); Thread.Sleep(200); _port.ReadExisting(); // 清空缓冲区吞掉 OK // 构造 PDU string pdu BuildPdu(phone, content); string[] parts pdu.Split(:); string tpLen parts[0]; string pduBody parts[1]; // 发送指令等待模块返回 _port.Write(ATCMGS tpLen \r); Thread.Sleep(300); // 发送数据并以 CtrlZ 结束 _port.Write(pduBody); _port.Write(\x1A); // 等待响应判断是否成功 DateTime deadline DateTime.Now.AddSeconds(5); string response ; while (DateTime.Now deadline) { response _port.ReadExisting(); if (response.Contains(CMGS)) return true; if (response.Contains(ERROR)) return false; Thread.Sleep(100); } return response.Contains(CMGS); } catch (Exception ex) { // 写日志 Console.WriteLine($发送失败: {ex.Message}); return false; } } }这个方法可以作为源码的核心。给出两个工程参数模块处理一条短信的时间通常在2到8秒之间取决于信号和SIM卡写卡速度所以发送循环中建议按队列间隔等待2秒以上每次发送后调用ATCMGD索引删除已发短信避免SIM卡存储空间满了后自动拒收新指令。方法里返回true只代表模块接受成功不代表对方收到这是GSM短信的天然机制在业务层面要做到发送记录和回执分开管理。4. 接收短信与群发引擎把单发能力扩展成 C# 短信群发源码4.1 短信接收解析从CMTI通知到完整内容的提取链路群发系统中常见一个隐藏需求用户回复退订短信、客户回复确认信息系统需要自动识别并处理。短信猫在默认状态下不会主动通知新短信需要先发送ATCNMI1,1,0,0,0。设置完成后模块收到新短信会主动推送一行CMTI: SM,3含义是短信被存到了SIM卡的第3个存储位置。此时C#代码去执行ATCMGR3读取这条短信内容模块返回的是一整块文本CMGR: 0,,24 0891683108200105F011000B811361837421F60008C50D522B60A8... OK其中0891...开头的是PDU编码的短信内容。解析流程分两步先判断存储介质类型是SMSIM卡还是ME模块内存再判断数据是0已读还是1未读。如果要做自动处理需要在读取后主动发ATCMGD3删除防止SIM卡存满。接收解析的常见问题是ReadExisting()读到的是分段数据尤其短信内容较长时模块的UART缓冲区分两三次才把完整内容推完。C# 里需要等串口短时间静默后再开始解析而不是收到第一次数据就动手。一个实用的做法是等待到ReadTimeout触发异常或连续200毫秒没有新数据再认为当前缓冲是一整条消息。4.2 群发引擎设计待发队列、失败重试与黑名单过滤短信猫单模块发短信是窄带通道一条短信从构造到模块响应通常4到8秒所以理论单猫极限是每分钟10到15条。C# 群发源码要做的是把发送流程做成一个稳定的流水线而不是一味追求并发数。群发引擎三个核心组件是队列管理、任务分片、失败重试。发送端用Channelstring或BlockingCollectionSmsTask做消息队列消费者单线程按FIFO处理后台数据库维护待发表、成功表、失败表三个状态每条消息允许重试2次中间间隔30秒。这三种设置能防止SIM卡被模块频繁写入导致写失败同时保留了对瞬时信号劣化的容忍度。群发前必须过一遍黑名单过滤。这里指的不是业务黑名单而是两类硬性过滤一是连续相同内容超过100条会被运营商风控所以群发任务要按号码段分批同一批次内文本做微调二是号段过滤PHS小灵通号段、虚拟运营商号段、海外号段要根据业务范围过滤掉。这两个过滤写在系统启动时和入队前各执行一次宁可拒绝不可错发。4.3 多猫并发为什么说多猫不等于多线程抢端口群发量超过单猫上限时常见做法是USB HUB接四到八个短信猫。这个方案能行但有个工程上的坑USB短信猫在系统休眠或USB电平波动后会出现端口假死SerialPort.IsOpen仍是true但发指令永远没有响应。C# 代码层面要做的心跳检测是每发完50条短信主动查询一次ATCSQ连续三次无响应就把端口关闭重开并做模块重新初始化。这是多猫方案里非常关键的保活机制否则隔夜群发任务醒来时四台设备已经静默挂掉两台。多猫并发改造后的发送模型是// 每只猫跑一个消费者线程 ListThread sendThreads new ListThread(); foreach (var cat in smsCats) { Thread t new Thread(() CatSendLoop(cat)); t.IsBackground true; t.Start(); sendThreads.Add(t); } void CatSendLoop(SmsCat cat) { while (true) { SmsTask task null; lock (_taskQueue) { if (_taskQueue.Count 0) task _taskQueue.Dequeue(); } if (task null) { Thread.Sleep(200); continue; } bool ok cat.SendSms(task.Phone, task.Content, out string error); if (!ok task.RetryCount 2) { task.RetryCount; lock (_taskQueue) { _taskQueue.Enqueue(task); // 重试任务回队尾 } } Thread.Sleep(task.IntervalMs); // 模块处理时间 } }这段代码按每猫单线程的模型分发清楚避开两个名词所指向的陷阱“线程安全”不只是对队列加锁SerialPort内部缓冲区也不是线程安全的多线程同时调用Write会互相覆盖半句话必须保证一个端口只被一个线程使用“并发”在短信猫方案里增加的是吞吐量而非省时间——4个猫跑2万条短信总耗时约等于单猫处理一条的耗时乘以上限规划容量时按照每猫每小时450条来估算留出重试余量。5. 短信猫 C# 开发避坑指南4个高频问题的现象、原因与解决5.1 串口打开成功但 AT 指令无响应疑似模块“假死”现象sp.Open()不抛异常端口资源也正常但发AT\r等5秒收不到任何回复。重启软件后又正常运行几个小时再次出现。原因大多数USB转串口芯片CH340、CP2102、FTDI在空闲一段时间后会进入休眠模式或者模块PPPSession互相抢占资源。这类问题跟代码逻辑无关是设备层面的掉线。解决思路分三层第一层应用层做心跳每30秒发一次AT\r无响应则执行sp.Close()后重新Open()第二层在设备管理器里把USB端口的电源管理里“允许计算机关闭此设备以节约电源”关掉第三层在硬件上把模块的DTR和RTS引脚固定拉高部分模块在DTR低电平时会自动进入休眠状态。C# 里可以通过sp.DtrEnable true; sp.RtsEnable true;实现引脚控制。5.2 中文短信发出去是乱码最隐蔽的原因是编码方向搞反现象英文短信正常中文短信对方收到显示为“锟斤拷”类型乱码但模块本身没有报错。原因PDU里的UCS2编码应该是大端序但Encoding.BigEndianUnicode和Encoding.Unicode在.NET里是不同的东西。Encoding.Unicode默认是UTF-16LE也就是小端序。如果你用系统默认的Encoding.Unicode做转换“你”字U4F60会从4F 60变成60 4F输出的是完全不同的字符。另一个低级错误是字符串拼接时十六进制字母要保证大写部分模块固件对2a和2A的处理不一致小写在某些固件里会被误判成AT指令结束符。解决方式是ContentToUcs2Hex方法里统一用b.ToString(X2)强制大写编码用Encoding.BigEndianUnicode代码里加注释防止后来人改回去。5.3 SIM卡被写满后群发任务无声失败现象群发跑到第3000条左右发送成功率骤降ATCMGS返回ERROR或直接超时但信号强度正常。原因普通SIM卡的短信存储空间只有50到200条不等。短信猫发出去后已发消息默认留存不手动删除就会把SIM卡存满。模块在存储满后会拒绝新指令而且失败模式是“部分返回ERROR部分无响应”非常容易误导排查方向。解决发送成功后立即发送ATCMGD索引删除。但注意两条命令之间必须间隔500毫秒以上不然模块闪存处于写入状态时响应慢第二条指令会撞上半字节乱码。批量删短信可以用ATCMGD1,1这个扩展语法作用是删除所有已读短信比逐条删除更高效但前提是在读取返回数据时把状态位正确解析出来否则会误删未读短信。5.4 群发后部分号码收不到短信却没有报错日志现象任务显示全部成功但部分真实用户反馈没收到短信中心没有下发失败回执。原因两类情况叠加造成。一是短信猫的信号强度在群发过程中随SIM卡温升而下降初始CSQ是20持续发200条后降到了8低信号区域直接投递失败。二是运营商对同一内容、连续发送、高频号段的风控拦截发生在短信中心侧短信猫收到的CMGS成功响应只表示短信中心接收了这个提交不表示短信中心一定继续投递。解决每50条检查一次ATCSQ发现信号低于12暂停发送60秒等信号回升同批次任务中在内容尾部加随机流水号或不同签名降低风控触发概率上线前选几个已知能收短信的“测试尾巴”号码每500条抽检一次。这类问题的排查思路就很像“玄学”了但按信号、频控、目标号段三个维度查基本能定位到具体原因。6. 短信猫 C# 方案的验证方法与进阶用法6.1 压测脚本用一条 SQL 和 C# 内置 stopwatch 验证单猫极限每次群发任务上线前建议跑一次压测记录模块在不同信号强度下的实际吞吐量。用Stopwatch简单计时往队列里塞100条测试短信记录从启动到最后一个完成的时间然后计算真实速率并跟理论值对比如果误差超过30%先查信号强度和SIM卡写卡速度。var sw new Stopwatch(); sw.Start(); for (int i 0; i 100; i) { smsCat.Enqueue($ATCMGS{BuildPdu(13800138000, $测试短信{i 1}号)}); } while (!queue.IsEmpty) Thread.Sleep(100); sw.Stop(); double rate 100.0 / sw.Elapsed.TotalMinutes; Console.WriteLine($实际速率: {rate:F1} 条/分钟);同时记录每50条的ATCSQ值。如果压测后段信号值比前段掉了3个点以上硬件上建议换外接天线或调整模块摆放位置这个步骤看似多余但能省掉高峰期一大半的异常。6.2 进阶用法一串口短信服务封装成 Windows 服务或 Web API把短信猫能力封装成一个独立服务是这套方案最常用到的进阶形态。三层结构是基础设施层SmsCatService 串口通信、服务层TaskManager 队列管理、接口层Web API 或内部事件。业务系统通过HTTP接口POST /api/sms提交短信请求服务内部统一入队由消费者线程控制发送节奏。这么做的好处是业务代码不再依赖SerialPort的线程模型同一套短信猫硬件可以被多个业务系统复用避免每个系统都挂一只USB猫。在这种架构下短信猫变成了“内网短信网关”与无纸化办公、工单系统、告警平台对接都很方便。6.3 进阶用法二按号码前缀路由到不同短信猫有多个短信猫模块时可以做号码路由。把移动、联通、电信的号段后缀按模块分别绑定比如1号猫只发移动号码、2号猫只发联通号码、3号猫发电信。这种方式在代码里非常轻量入队前把号码前三位判断一下放进对应模块的队列就行。效果是模块工作温度更低、SIM卡被写入的频率减半单模块群发量上限也随之翻倍。C# 里用一个Dictionarystring, SmsCatService做路由表按键是号段前缀值是有对应SIM卡的模块实例。这个方案折腾下来积累的最深感触是短信猫不是最酷的技术但往往是生产环境下最不过时的通道。它需要你接受“异步送达”这件事一个OK响应背后可能还有几秒钟的盲目等待。压测脚本、心跳保活、SIM卡清理这些做事习惯比任何一段源码都更抗风险在关键时候能帮你把损失降到最低。希望这些踩坑经验和代码模板能帮到你让你第一次接短信猫就少走弯路真正把心思放在业务价值上。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

AutoLabelImg实战:自动预标注到YOLO训练,效率提升指南 2026/9/29 16:52:08

AutoLabelImg实战:自动预标注到YOLO训练,效率提升指南

简介:这是一款面向深度学习图像识别场景的自动标注工具 AutoLabelImg,支持 YOLOv8/YOLOv9/YOLOv10 与 RT-DETR 等主流检测模型,适合需要快速构建训练数据集的算法工程师与科研人员。资源包共 532 个文件,压缩后约 83MB&#xff0c…

阅读更多 →
WX1860AL4千兆网卡iperf3性能不达标?五大根因排查实战 2026/9/29 16:51:55

WX1860AL4千兆网卡iperf3性能不达标?五大根因排查实战

上周刚把一张网讯WX1860AL4四口千兆网卡装进服务器,兴冲冲地拿iperf3打流,结果傻眼了:服务端到客户端怎么跑都只有480Mbps左右,离千兆Line Rate差了整整一半。第一反应是网卡有问题,退换货申请都写到一半了。但在折腾了…

阅读更多 →
从零构建AI工程能力:模型部署、推理优化与监控实战 2026/9/29 16:51:55

从零构建AI工程能力:模型部署、推理优化与监控实战

从零构建AI工程能力这件事,我前前后后折腾了差不多两年。最开始的时候,我和大多数人一样,觉得搞AI就是调包、跑模型、看准确率,直到真正要把一个模型塞进生产环境,才发现自己连最基本的工程化思维都没有。模型在notebo…

阅读更多 →
模块化的思想内核:超越文件拆分的边界思维 2026/9/29 16:51:55

模块化的思想内核:超越文件拆分的边界思维

先讲一件真事儿。前两年我参与过一个中后台项目,接手时正好赶上团队做“模块化重构”,把原来几个动辄上千行的巨型JS文件按功能拆分成了50多个小文件,每个文件平均不到100行,目录层级也从两层直接拉到了五层。重构完成那天大家挺高…

阅读更多 →
Agent记忆管理实战:从hindsight机制到MCP与Docker落地 2026/9/29 16:51:54

Agent记忆管理实战:从hindsight机制到MCP与Docker落地

1. 从“hindsight”这个词说起:为什么它值得单独拿出来聊 第一次看到“hindsight”作为项目名,我脑子里蹦出来的不是词典释义,而是一个很具体的开发场景:Agent 在跑完一轮任务之后,回头翻自己的记忆,发现“…

阅读更多 →
基于Docker与MCP构建LLM Agent记忆系统:hindsight架构实战 2026/9/29 16:51:54

基于Docker与MCP构建LLM Agent记忆系统:hindsight架构实战

1. 从“hindsight”说起:为什么我们需要给Agent装上“后视镜”第一次看到“hindsight”这个词,我脑子里蹦出来的不是词典释义,而是自己踩过的一个坑。去年做一套基于LLM的客服工单自动分类系统,模型在单轮对话里表现堪称完美&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉