尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
C#上位机通过Modbus TCP读写西门子1200 PLC实战与避坑
简介C# 与西门子 S7-1200 PLC 的 ModbusTcp 通信示例工程面向具备一定 C# 基础、希望切入工业自动化数据采集与设备控制的开发者及工控调试人员。内容围绕 ModbusTcp 请求/响应机制展开覆盖读线圈、读离散输入、读保持寄存器、读输入寄存器以及单/多线圈和寄存器写入等常用功能码并结合西门子 PLC 的 I/Q/IR/HR 地址映射说明调用方式示例同时呈现 Socket 直连与通信库两种实现思路便于对比协议细节、连接管理、超时重试与异常处理。压缩包共 46 个文件以 13 个 cs 源码为核心配合 xml 配置、zip 归档、exe 可执行文件及项目资源等整体约 13.02MB目录结构适合按模块查阅。已有 4316 人学习可作为搭建 PLC 通信测试环境、理解报文收发与排错思路的参考。1. 网线一连读回的全是零C# 直连西门子 1200 的起点上位机用 C# 通过 ModbusTcp 读西门子 1200 PLC第一次联调常见的画面是这样的Socket 连上了请求发出去了读回来的保持寄存器全是 0换一段地址再读直接抛出 Illegal Data Address 异常。这大概率不是通讯库的问题更可能是 PLC 侧的交换区和上位机的地址约定没对上——1200 做 Modbus TCP 服务端需要手动挂 MB_SERVER 指令、手动划一块非优化 DB 当寄存器区这两件事 PLC 不会替你自动生成。这份资源提供的是一套分层的最小工程协议层封装连接、重连和批量读设备层用 JSON 点表描述地址和类型宿主层跑采集循环另外附一个现场排查用的小工具。它面向正在做上位机对接、被地址偏移和字节序反复折磨的 C# 开发者哪怕你之前只用 Modbus Poll 点过几下照着把第一条数据读出来也不难。2. 工程骨架与技术选型三层目录 NModbus 的最小可跑结构2.1 为什么是 ModbusTcp而不是 S7 协议或 OPC UA1200 本身是支持 S7 协议的就是 TIA 下载、在线监控用的那套。问题是这套协议不公开C# 侧只能依赖第三方封装库PLC 固件一升级、库一停更上位机就得跟着返工。OPC UA 更规范但需要额外授权、额外组态一个只读几十个点的工位项目用不上这么重的方案。ModbusTcp 的好处很实在公开标准502 端口PLC 侧一条 MB_SERVER 指令就能起一个服务端换别家 PLC 也是同一套代码。代价同样要讲清楚——它没有语义寄存器里是速度还是温度全靠你事先约定没有订阅机制只能靠轮询单次读寄存器数量有上限BOOL 量还得自己打包进字里面。所以选型判断可以很简单点位数在几百以内、采集周期 100500ms、现场可能换品牌选 ModbusTcp点位上千、要毫秒级响应、要语义化变量名和报警模型直接上 OPC UA。这个判断我会写进 README省得后面接手的人反复问“为什么不用那个更高级的”。2.2 三层目录协议层、设备层、宿主层工程结构刻意切成了三层好处是换通讯库不影响业务代码加点位不用改采集逻辑PlcModbusDemo/ ├── PlcModbusDemo.sln ├── src/ │ ├── PlcModbus.Protocol/ # 通讯底座 │ │ ├── ModbusTcpChannel.cs # 连接、重连、串行化读写 │ │ ├── ModbusAddress.cs # 地址合并、分块 │ │ └── RegisterConverter.cs # 寄存器与 C# 类型互转 │ ├── PlcModbus.Device/ # 设备层 │ │ ├── PlcTag.cs # 单个点位模型 │ │ ├── PlcTagTable.cs # 点表加载与分组 │ │ └── PlcTagTable.json # 点位配置 │ └── PlcModbus.Host/ # 宿主层 │ ├── Program.cs # 采集循环 │ └── appsettings.json # PLC 连接参数 └── tools/ └── ModbusProbe/ # 现场排查小工具依赖方向是单向的Host 依赖 DeviceDevice 依赖 ProtocolProtocol 只依赖 NModbus 和 System.Net.Sockets。把通讯库限制在协议层里是这套结构里最值钱的一条约束——哪天 NModbus 不维护了只改 Protocol 那三个文件上层一行不用动。层目录职责依赖协议层PlcModbus.Protocol建链、超时、重连、字节序转换NModbus设备层PlcModbus.Device点位定义、地址分组、量程换算协议层宿主层PlcModbus.Host采集节拍、异常上报、数据落库设备层2.3 环境与依赖.NET 6 NModbus 装哪一版运行环境就是 .NET 6 或 .NET 8 控制台项目加上 NModbus 这一个 NuGet 包没有别的依赖。创建和还原的命令如下dotnet new sln -n PlcModbusDemo dotnet new console -n PlcModbus.Host -o src/PlcModbus.Host dotnet new classlib -n PlcModbus.Protocol -o src/PlcModbus.Protocol dotnet new classlib -n PlcModbus.Device -o src/PlcModbus.Device # 注意包名是 NModbus不是 NModbus4 dotnet add src/PlcModbus.Protocol package NModbus这里踩过的坑必须先说明NuGet 上同时存在NModbus4和NModbus两个包命名空间都是NModbus看起来像同一个东西。NModbus4是很早的版本只支持 .NET Framework装到 .NET 6 项目上要么还原失败要么运行期抛TypeLoadException。选NModbus它支持 netstandard2.0能跑在 .NET 6/8 上。另外采集循环里我不建议一路 async 到底。Modbus TCP 是一问一答的短连接事务同步 API 加一个独立采集线程逻辑反而清楚也不会出现并发请求在同一个 Socket 上互相踩踏的情况。真要上 async也得用信号量把事务串起来本质是一样的。3. PLC 侧配置MB_SERVER 的 CONNECT 参数与保持寄存器映射3.1 MB_SERVER 必须放在 OB1 里循环调用1200 做 Modbus TCP 服务端靠的是MB_SERVER指令。它的调用位置有硬性要求放在主循环 OB1 里每个扫描周期都执行不要塞进循环中断 OB 靠触发去调也不要加边沿触发。指令内部要维护连接状态机你一停它客户端那边就表现为随机超时、连接莫名断开排查起来非常费劲。关键引脚和它们的含义引脚说明REQ使能一般直接给 TRUEDISCONNECT断开当前连接正常运行给 FALSECONNECT指向一个 TCON_IP_v4 结构描述监听参数MB_HOLD_REG保持寄存器交换区指向 DB 里的数组NDR / DR有新请求 / 请求处理中ERROR / STATUS错误标志与状态码现场排查主要看这两个CONNECT 指向的 TCON_IP_v4 结构参数填法如下参数填什么说明interfaceId64以硬件标识符为准在设备组态里查 CPU 的 PROFINET 接口属性id1同一 CPU 内不重复即可connectionType1111 表示 TCPactiveEstablishedFALSEPLC 做服务端被动等客户端连remoteAddress0.0.0.0填 0 表示不限制客户端 IPremotePort0被动连接不用填localPort502Modbus 标准端口改成别的上位机也得跟着改一个MB_SERVER实例对应一条连接。现场要多台上位机同时读就得复制多个实例、给不同的id数量受 CPU 连接资源限制一般几个到十几个具体看型号手册。连接数满了之后新客户端连不上但老连接一切正常这个现象很容易被误判成网络问题。3.2 交换区 DB取消「优化的块访问」是硬前提MB_HOLD_REG指向的 DB 必须取消「优化的块访问」这个勾。优化访问的 DB 里变量没有固定绝对地址TIA 按自己的一套规则排布MB_SERVER拿不到连续的字地址结果就是客户端能连上、能读读回来全是 0。这个坑我在两个项目上各踩过一次现象完全一样没有任何报错。一个可用的布局大概是这样DB 命名为DB_Modbus属性里取消优化访问偏移变量类型对应寄存器0.0SpeedREAL40001400024.0TemperatureREAL40003400048.0StatusWordWORD4000510.0CounterINT40006MB_HOLD_REG填P#DB1.DBX0.0 WORD 100注意最后那个 100 是字的个数不是字节数。填小了会出现“读越界地址抛异常”填大了不影响功能但会让人误以为交换区很宽裕。REAL 是 4 字节占两个保持寄存器这是所有数据类型对不上的源头。另外留意 TIA 编译后的偏移列非优化 DB 里混排类型时可能插入填充字节填充也占地址实际寄存器编号要按偏移列算不能按变量顺序数。还有一种写法是声明Array[0..199] of Word作为纯交换区逻辑侧算完 REAL 再用程序搬进去。两种都行前者省事、后者更可控。以现场 TIA 版本为准编译或运行报错就换另一种别在一个写法上硬顶。3.3 BOOL 和状态字别指望线圈区MB_SERVER只挂了一个MB_HOLD_REG数据区处理的功能码就是读保持寄存器、写单个寄存器、写多个寄存器这几个。你在 C# 侧调ReadCoils去读 0xxxx 线圈区等回来的大概率是非法功能码异常。BOOL 量我一般这么处理在交换区里留一个 WORD 当状态字bit0 是运行、bit1 是报警、bit2 是急停PLC 侧按位赋值上位机侧取值后按位与。这样一次读一个寄存器就能拿到十几个开关量比一个点一个点读省事得多。再留一个 INT 当心跳PLC 每个扫描周期或者每 100ms 加一溢出归零。上位机判断心跳值有没有在变比读一堆数据去猜“PLC 是不是死了”靠谱——数据可能恰好没变化心跳不会。4. C# 通讯核心链路连接、批量读、类型转换、写回的四段实现4.1 连接与重连把 TcpClient 的生命周期收紧采集程序跑几天几夜最怕的不是连不上是连上了但连接已经处于半死状态。我的做法是所有异常一律当成“连接脏了”直接关掉重建不去判断它到底是哪种异常using System; using System.Net.Sockets; using System.Threading; using NModbus; namespace PlcModbus.Protocol { public sealed class ModbusTcpChannel : IDisposable { private readonly string _ip; private readonly int _port; private readonly byte _unitId; // NModbus 的 master 不是线程安全的所有事务必须串起来 private readonly SemaphoreSlim _gate new SemaphoreSlim(1, 1); private TcpClient _tcp; private IModbusMaster _master; public ModbusTcpChannel(string ip, int port 502, byte unitId 1) { _ip ip; _port port; _unitId unitId; } public bool IsOpen _tcp ! null _tcp.Connected _master ! null; public void EnsureOpen() { if (IsOpen) return; Close(); _tcp new TcpClient { ReceiveTimeout 2000, SendTimeout 2000, NoDelay true // 关掉 Nagle这种小报文别攒 }; _tcp.Connect(_ip, _port); var factory new ModbusFactory(); _master factory.CreateMaster(_tcp); _master.Transport.ReadTimeout 1000; _master.Transport.WriteTimeout 1000; _master.Transport.Retries 0; // 重试交给上层不然一次卡三倍时间 } public ushort[] ReadHolding(ushort start, ushort count) { _gate.Wait(); try { EnsureOpen(); return _master.ReadHoldingRegisters(_unitId, start, count); } catch { Close(); // 任何异常都认为连接已脏下次重建 throw; } finally { _gate.Release(); } } public void WriteMultiple(ushort start, ushort[] values) { _gate.Wait(); try { EnsureOpen(); _master.WriteMultipleRegisters(_unitId, start, values); } catch { Close(); throw; } finally { _gate.Release(); } } public void Close() { _master?.Dispose(); _master null; _tcp?.Close(); _tcp null; } public void Dispose() { Close(); _gate.Dispose(); } } }_gate是这段代码的核心。IModbusMaster内部维护请求序号和响应匹配多个线程同时用它响应会串到别人的请求上现象是随机读到别的点的数据或者报 CRC 类异常。加锁之后吞吐会降一点但 Modbus 本来就是一问一答锁的代价可以忽略。_tcp.Connect这个同步方法没有超时参数网线拔了会按系统默认超时卡几十秒。要不卡主采集线程可以换成ConnectAsync加Task.Wait(3000)判断结果或者在独立线程里做首次连接。Retries 0是刻意的。NModbus 自带重试但它在超时场景下会把一次采集拖成两三倍时长采集周期直接失控。重试逻辑放到外层循环里看得见、控得住。4.2 批量读把上百个点压成三次请求点表里几十上百个地址一个个读是灾难。Modbus TCP 每次请求都有固定开销加上 PLC 扫描周期逐点读很容易把 200ms 的采集节拍撑爆。做法是把地址排序、去重把相邻的地址合并成块中间的小空洞顺手读回来using System.Collections.Generic; using System.Linq; namespace PlcModbus.Protocol { public static class ModbusAddress { /// summary /// 把散点地址合并成若干连续块 /// /summary /// param nameaddresses0 基地址集合/param /// param namemaxGap允许吞掉的空洞长度默认 4 个寄存器/param /// param namemaxCount单次请求最大寄存器数Modbus 上限 125留点余量/param public static List(ushort Start, ushort Count) BuildBlocks( IEnumerableushort addresses, ushort maxGap 4, ushort maxCount 120) { var sorted addresses.Distinct().OrderBy(a a).ToList(); var blocks new List(ushort, ushort)(); if (sorted.Count 0) return blocks; ushort start sorted[0]; ushort end sorted[0]; foreach (var addr in sorted.Skip(1)) { // 空洞不大、且不超单次上限就并进当前块 if (addr - end maxGap addr - start 1 maxCount) { end addr; } else { blocks.Add((start, (ushort)(end - start 1))); start end addr; } } blocks.Add((start, (ushort)(end - start 1))); return blocks; } } }maxGap是个经验值。设成 0 就是严格连续才合并块数会多设成 4 到 8能吞掉点表里零散的空位块数明显下降多读回来的几个寄存器反正也不解析。maxCount卡在 120是因为标准上限是 125超了直接异常留 5 个余量给后面加点位。举个实际数字一份 96 个点的表地址从 0 到 210 之间零散分布不合并是 96 次请求合并后通常压到 35 次一个 200ms 周期里绰绰有余。4.3 寄存器到 C# 类型的转换REAL、DWORD、INT 的大端拼装这一段是最容易出事的地方。PLC 侧 REAL 是 IEEE754 单精度、大端字节序、高字在前ReadHoldingRegisters返回的是ushort[]每个元素是一个 16 位字。直接BitConverter.ToSingle去拼在小端机器上必然得到垃圾值using System; namespace PlcModbus.Protocol { public static class RegisterConverter { /// summary两个保持寄存器 - float/summary /// param namehigh高字地址较小的那个/param /// param namelow低字/param /// param namewordSwap高低字是否颠倒部分第三方设备会这样/param public static float ToSingle(ushort high, ushort low, bool wordSwap false) { if (wordSwap) (high, low) (low, high); var bytes new byte[4]; bytes[0] (byte)(high 8); bytes[1] (byte)(high 0xFF); bytes[2] (byte)(low 8); bytes[3] (byte)(low 0xFF); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); return BitConverter.ToSingle(bytes, 0); } /// summaryfloat - 两个保持寄存器写回 PLC 用/summary public static (ushort High, ushort Low) FromSingle(float value, bool wordSwap false) { var bytes BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); ushort high (ushort)((bytes[0] 8) | bytes[1]); ushort low (ushort)((bytes[2] 8) | bytes[3]); return wordSwap ? (low, high) : (high, low); } /// summary两个寄存器 - 32 位有符号整数/summary public static int ToInt32(ushort high, ushort low) (int)(((uint)high 16) | low); /// summary单个寄存器 - 16 位有符号整数/summary public static short ToInt16(ushort register) unchecked((short)register); /// summary取状态字的某一位/summary public static bool GetBit(ushort word, int index) ((word index) 1) 1; } }ToSingle里的关键是两步先把两个字按大端拼成 4 个字节再根据运行平台决定要不要整体反转最后交给BitConverter。这样写不依赖任何库的辅助方法NModbus 换版本也不受影响。wordSwap参数是给那些高低字顺序反过来的设备留的开关西门子的 REAL 保持默认false就行。ToInt16用unchecked强转是为了让 40001 里存的 -1 读出来是 -1 而不是 65535。这个细节在温度、偏移量这类可能为负的点上会暴露正数场景永远发现不了。4.4 采集循环与写回一个线程、一把锁、一条兜底日志宿主层就是很朴素的一个循环异常全部落日志绝不让一次读取失败把整个进程带走using System; using System.Threading; using PlcModbus.Protocol; var channel new ModbusTcpChannel(192.168.0.10, 502, 1); // 0-1: 主轴速度 REAL2-3: 油温 REAL4: 状态字 WORD var blocks ModbusAddress.BuildBlocks(new ushort[] { 0, 1, 2, 3, 4 }); while (true) { var sw System.Diagnostics.Stopwatch.StartNew(); try { foreach (var (start, count) in blocks) { var regs channel.ReadHolding(start, count); if (start 0 count 4) { float speed RegisterConverter.ToSingle(regs[0], regs[1]); float temp RegisterConverter.ToSingle(regs[2], regs[3]); Console.WriteLine($速度 {speed:F1} rpm油温 {temp:F1} ℃); } if (start 4 start count 4) { ushort status regs[4 - start]; Console.WriteLine($运行 {RegisterConverter.GetBit(status, 0)}报警 {RegisterConverter.GetBit(status, 1)}); } } } catch (Exception ex) { // 超时、断线、PLC 停机全落这里下个周期自动重建连接 Console.WriteLine($[{DateTime.Now:HH:mm:ss}] 采集失败{ex.GetType().Name} {ex.Message}); } // 固定节拍扣掉本轮耗时 Thread.Sleep(Math.Max(0, 200 - (int)sw.ElapsedMilliseconds)); }写回用的是同一把锁调WriteMultiple之前先把 float 转成两个寄存器var (hi, lo) RegisterConverter.FromSingle(1250.5f); channel.WriteMultiple(10, new[] { hi, lo }); // 写到 40011 起始的两个寄存器写操作要注意一点上位机写进去的值PLC 逻辑下一轮扫描可能就覆盖了。真正要下发设定值PLC 侧得有一个“接收标志位”配合上位机写值、置位标志、PLC 读走并清标志这套握手不做现场会反复出现“设了参数没生效”的争执。5. 避坑与排查连不上、读全零、数值翻车的五条现场记录5.1 连接与协议层现象一连接被拒绝抛 SocketException 10061或者连接超时。原因通常是三个MB_SERVER没在 OB1 里循环调用PLC 根本没在监听 502CONNECT 里的localPort填错了CPU 有多个网口interfaceId选到了没接线的那个。排查顺序是先ping通再用telnet 192.168.0.10 502看端口开没开端口不通就别在 C# 代码里找问题了。另外电脑上的防火墙和 PLC 所在网段的隔离策略也要确认。现象二连上了但每次都抛 Illegal Data Address异常码 02。这是地址基址搞混了。PLC 手册写的是 40001 这种 4xxxx 表示法NModbus 要的是 0 基偏移40001 对应 040011 对应 10。直接把手册上的编号填进去差一位小地址可能刚好落在数组里读出错值边界地址就抛异常。另一个原因是读取长度超出了MB_HOLD_REG声明范围比如只声明了 100 个字你去读起始 95、长度 10 的这一段。现象三跑几个小时都正常突然开始偶发超时之后彻底连不上。八成是多线程共用了同一个IModbusMaster请求和响应错位或者断线后旧连接没释放PLC 侧的连接资源被占满新连接进不来。解决办法就是第 4 章那套一把SemaphoreSlim串行化异常时Dispose掉 master 和 TcpClient 再重建。血泪经验是——别去区分异常类型做精细恢复直接重建最省心。5.2 数据层现象四能连、能读、不报错所有寄存器全是 0。第一嫌疑是交换区 DB 还勾着「优化的块访问」MB_SERVER拿不到绝对地址读出来就是一片零。第二嫌疑是MB_HOLD_REG指针长度写少了或者指向的偏移不是 DB 起点。第三嫌疑最容易被忽略PLC 逻辑确实没往这块写程序还在调试阶段交换区就是空的。三个都排掉之后再用 TIA 在线监控直接看数组一眼就能分清是通讯问题还是逻辑问题。现象五REAL 读出来是 1.4E-45、2.8E-45、NaN 这类明显不对的值。这个特征太典型了基本可以断定是高低字顺序反了。西门子的 REAL 是高字在前某些第三方设备或网关会反过来。修法就是把ToSingle的wordSwap打开或者手动把regs[0]和regs[1]换个位置再拼。反过来的情况也存在写下去的设定值 PLC 读到的是天文数字同样先查字序再查是不是把 INT 当成了 REAL 解析。6. 二次开发改造把硬编码地址换成点表驱动的采集器第一版代码里地址是写死的加一个点位就要改代码重新发版这在现场是没法接受的。我后来把点位全部外置成 JSON 点表采集器只认“地址 类型 量程”三件事{ Plc: { Ip: 192.168.0.10, Port: 502, UnitId: 1, IntervalMs: 200 }, Tags: [ { Name: 主轴速度, Address: 0, Type: Real, Unit: rpm, Scale: 1.0 }, { Name: 油温, Address: 2, Type: Real, Unit: ℃, Scale: 1.0 }, { Name: 状态字, Address: 4, Type: Word }, { Name: 产量计数, Address: 5, Type: Int32, Scale: 1 } ] }加载点表后先用BuildBlocks把Address分块读回来再按每个点的类型调对应的转换方法最后乘Scale做量程换算。整个过程不碰协议层加点位就是改配置文件。改造后的验证方法我一般走三步先看日志里的请求次数是不是只跟块数有关而不是跟点数有关再把点表里的地址故意改错一位确认能抛异常而不是静默读错值最后拿 Modbus Poll 或者自己写的 ModbusProbe 同时读同一段地址两边数值对上了才算过。再往下做值得加的通常就三件事变化上送值没变就不往数据库写省掉大量无效记录、断线缓存异常期间的数据暂存本地恢复后补传、写值握手用标志位确认 PLC 真的接收了。本文还有配套的精品资源点击获取
RELATED

相关推荐

单片机轻量级AES128纯C实现:ECB/CBC与PKCS7填充

单片机轻量级AES128纯C实现:ECB/CBC与PKCS7填充

简介:面向单片机与嵌入式开发者的AES128加解密C语言实现包,聚焦资源受限平台上的对称加密落地问题,涵盖ECB与CBC两种工作模式及PKCS7Padding补齐与去填充逻辑,适合具备一定C基础、需要在固件中集成数据加密功能的初中级嵌入式工程…

📅 2026/10/26 11:06:09
Markdown编辑器:技术文档写作的高效解决方案

Markdown编辑器:技术文档写作的高效解决方案

1. Markdown编辑器:轻量化写作的终极解决方案 作为一名长期与技术文档打交道的开发者,我深刻理解高效写作工具的重要性。Markdown编辑器正是解决这个痛点的完美方案——它用简单的纯文本语法实现了复杂的格式排版,让我们能够专注于内容创作而…

📅 2026/10/26 11:06:09
MCP协议SDK开发实战:物联网通信与性能优化

MCP协议SDK开发实战:物联网通信与性能优化

1. MCP协议与SDK开发概述 在当今分布式系统架构中,协议与SDK的开发能力已成为工程师的核心竞争力。MCP(Model Context Protocol)作为一种轻量级通信协议,近年来在物联网设备控制、跨平台服务调用等场景展现出独特优势。其核心设计理念是通过标准化的上下…

📅 2026/10/26 11:01:09
MORE NEWS

更多资讯

📰

ADHD式大脑自我管理指南:从注意力调节到任务启动的实操系统

1. 从“i-have-adhd”这个标题说起:一个被严重低估的自我管理切口第一次看到“i-have-adhd”这个标题,我脑子里蹦出来的不是医学名词,而是一类非常具体的人:他们能在半小时内把一个复杂方案想得天花乱坠,却常常在“把袜…

📰

SaaS点餐平台高并发架构设计与实战优化

1. SaaS点餐平台行业现状与核心挑战中午12点,某连锁餐厅的前台又排起了长队。服务员小王手忙脚乱地记录着顾客点单,后厨的订单打印机不断吐出小票,厨师老李对着堆积如山的订单直摇头。这样的场景正在倒逼餐饮行业进行数字化转型,而…

📰

机器人自主完成胆囊切除术的技术突破与应用前景

1. 项目背景与核心突破在微创外科手术领域,胆囊切除术(cholecystectomy)是最常见的腹腔镜手术之一。传统手术中,医生需要通过小切口插入器械,在视频引导下完成胆囊管和胆囊动脉的夹闭、切割操作。这个被称为"clip…

📰

AI对话记忆管理实战:从claude-mem看记忆提取、检索与遗忘机制

1. 从"claude-mem"这个名字说起:它到底想解决什么第一次看到"claude-mem"这个命名,我的直觉是:这是一个围绕对话记忆做文章的项目。拆开来看,"claude"指向的是对话式AI助手的交互场景,&…

📰

HyperFrames:面向AI代理的确定性视频渲染框架核心原理与实战

做了几年多模态系统和AI代理落地,我越来越确定一件事:AI代理要真正“干实事”,光会写文字、调接口远远不够。画面、视频、时序反馈这些“看得见的世界”,才是连接真实操作的关键。也正因为如此,很多人第一次接触HyperF…

📰

从rea循环到实时响应:Read-Evaluate-Act工程实践与优化

1. 从“rea”这个标题说起:一个被低估的缩写背后藏着什么 第一次看到“rea”这个标题的时候,我盯着屏幕愣了几秒。三个字母,没有正文,没有关键词,没有摘要,连一个标点符号都没有。这种极简到近乎空白的输入…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬