ULID:分布式系统高性能有序ID生成方案,替代UUID的.NET/Unity实践
1. 项目概述为什么我们需要ULID在分布式系统里生成一个全局唯一的标识符ID是个老生常谈但又避不开的难题。你可能用过UUID那串由32个十六进制字符组成的“标准答案”比如550e8400-e29b-41d4-a716-446655440000。它确实能保证唯一性但在实际应用中尤其是在数据库层面它的表现并不总是那么“优雅”。我经历过不少因为ID问题导致的性能瓶颈。比如使用UUID作为数据库主键时由于它的无序性新插入的记录可能会被放到索引树的任意位置导致频繁的页分裂严重拖慢写入速度。在需要按时间范围查询的场景下UUID更是无能为力你无法直接从ID中获取任何时间信息。更别提在日志追踪时面对一堆杂乱无章的UUID想理清事件发生的先后顺序有多头疼。而ULIDUniversally Unique Lexicographically Sortable Identifier的出现就是为了解决这些痛点。它生成的是128位的标识符但编码成26个字符的Crockford’s Base32字符串例如01H5Z7V8SG9Q5KXW3YFV7C4D2R。它的核心魅力在于两点时间有序和字典序友好。时间有序ULID的前48位是Unix时间戳毫秒精度这意味着生成的ID是严格按照时间顺序递增的。你把它作为数据库主键新数据永远追加在索引末尾避免了页分裂对写入性能是巨大的提升。同时你可以轻松地从ID中解析出它的创建时间这对于数据分析、日志排查和审计追踪来说价值巨大。字典序友好Base32编码不区分大小写并且剔除了容易混淆的字符如I, L, O, U使得字符串在排序时表现和二进制表示完全一致。这在很多需要字符串比较或排序的系统中比如作为文件名、Redis的Sorted Set成员非常方便。现在这个优秀的方案被带到了.NET和Unity生态中。这个名为“Ulid”的实现并非简单的接口封装而是一个从算法到API都经过深度优化的、追求极致性能的库。它瞄准的就是那些对性能有苛刻要求的场景高并发的Web API、游戏服务器的玩家会话管理、物联网设备的海量数据上报或者任何你觉得UUID已经成为瓶颈的地方。2. 核心设计极速背后的原理与取舍一个库敢自称“极速”绝不是空穴来风。这个Ulid实现为了性能在设计和实现上做了大量精细的权衡。2.1 结构解析128位里的时间与随机一个ULID的128位结构非常清晰前48位Unix时间戳毫秒。这提供了长达约8925年的可用时间范围从1970年算起对于绝大多数系统绰绰有余。后80位随机数。在规范中这80位应由密码学安全的随机数生成器CSPRNG填充以保证全局唯一性的概率极高冲突概率低到可以忽略不计。这个设计的精妙之处在于它将“何时生成”时间戳和“它是谁”随机性完美结合并且保证了时间顺序。在.NET实现中这128位通常用一个16字节的byte[16]数组或两个longulong整数来表示操作起来非常高效。2.2 性能优化关键点零分配Zero-Allocation这是高性能.NET代码的黄金法则。库在核心的生成和转换路径上如Ulid.NewUlid()极力避免产生任何堆内存分配即避免new。它可能通过重用静态缓冲区、使用stackalloc栈上分配或返回结构体struct来实现。在频繁调用的热点路径上这能极大减轻垃圾回收器GC的压力对于需要持续高吞吐的服务至关重要。算法级优化Base32编码/解码通常是性能瓶颈。这个实现很可能使用了查表法Look-up Table和位操作Bit Manipulation来代替昂贵的除法和取模运算。例如预先计算好0-31对应Base32字符的数组编码时通过移位和掩码操作快速定位字符。API设计提供同步Ulid.NewUlid()和异步Ulid.NewUlidAsync()两种生成方式。同步方法可能使用RandomNumberGenerator.GetBytes或更快的、线程安全的伪随机算法异步方法则适配了RandomNumberGenerator.FillAsync适用于异步流水线避免阻塞。为Unity特调Unity环境有其特殊性。它可能支持较旧的.NET Standard版本并且对AOT预先编译和IL2CPP有要求。这个实现会确保不使用任何AOT不支持的反射特性。提供无依赖的、纯净的源码或DLL方便直接放入Plugins文件夹。在可能的情况下针对Unity的System.Random或特定平台如WebGL的随机数源进行适配确保在所有目标平台上的行为一致且可靠。2.3 与UUID的对比为了更直观我们列个表看看特性ULIDUUID (v4)对开发者的影响有序性严格时间有序完全无序ULID作主键数据库插入性能更优范围查询支持好。可读性包含时间信息可解析无法直接解读ULID便于调试和日志分析一眼可知生成时间。编码26位Crockford‘s Base3232/36位十六进制ULID更短URL/文件名更友好且无混淆字符。排序字符串排序即时间排序字符串排序无意义ULID在作为字符串键时如Redis排序功能开箱即用。冲突概率80位随机极低122位随机极低两者在唯一性上都足够可靠。默认性能通常更优有序零分配优化一般在高压下经过优化的ULID库性能优势明显。注意ULID的时间有序性依赖于系统时钟的单调性。如果系统时钟发生回拨例如NTP同步理论上可能生成时间戳更小的ULID破坏严格递增性。这是所有基于时间戳的ID生成器都需要注意的。好的实现会提供检测或抵御机制如记录上次时间戳在回拨时等待或告警。3. 在.NET中的实战应用理论说得再多不如上手试试。我们来看看如何在.NET项目中集成并使用这个Ulid库。3.1 安装与基础使用首先通过NuGet安装库。通常这个包名就是Ulid。# .NET CLI dotnet add package Ulid # 或者在Visual Studio的包管理器控制台 Install-Package Ulid使用起来非常简单using Ulid; // 生成一个新的ULID Ulid myUlid Ulid.NewUlid(); Console.WriteLine($生成的ULID: {myUlid}); // 输出类似 01H5Z7V8SG9Q5KXW3YFV7C4D2R // 解析字符串为ULID string ulidString 01H5Z7V8SG9Q5KXW3YFV7C4D2R; if (Ulid.TryParse(ulidString, out Ulid parsedUlid)) { Console.WriteLine($解析成功时间: {parsedUlid.Time}); } // 获取ULID的内部组件 Console.WriteLine($时间戳: {myUlid.Time}); // DateTimeOffset Console.WriteLine($随机部分: {BitConverter.ToString(myUlid.Random.ToByteArray())});3.2 与Entity Framework Core集成这是ULID最闪耀的场景之一——作为数据库主键。定义实体public class Order { // 使用Ulid类型作为主键 public Ulid Id { get; set; } Ulid.NewUlid(); public string OrderNumber { get; set; } public decimal Amount { get; set; } public DateTimeOffset CreatedAt { get; set; } }在DbContext中配置你需要告诉EF Core如何将Ulid类型映射到数据库。通常数据库存储为CHAR(26)或BINARY(16)。protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.EntityOrder(entity { entity.HasKey(e e.Id); // 映射为字符串存储推荐可读性好 entity.Property(e e.Id) .HasConversion( v v.ToString(), // 模型转存储 v Ulid.Parse(v) // 存储转模型 ) .IsFixedLength(true) .HasMaxLength(26) .IsRequired(); // 或者映射为二进制存储更省空间 // entity.Property(e e.Id) // .HasConversion( // v v.ToByteArray(), // v new Ulid(v) // ) // .HasColumnType(BINARY(16)); }); }优势立现插入性能由于ID时间有序新订单总是插入索引末尾大大减少B-Tree分裂。关联查询当你需要查询“某个时间段内的所有订单”时如果CreatedAt字段有索引效果很好。但更妙的是你可以直接利用ID的时间部分进行粗略的范围查询因为ID本身就携带了时间信息这在某些场景下可以避免多字段索引。3.3 在ASP.NET Core Web API中的应用在API中ULID可以作为不透明的资源标识符比自增整数ID更安全避免信息泄露和爬取又比UUID更高效。作为资源ID[ApiController] [Route(api/[controller])] public class ProductsController : ControllerBase { [HttpGet({id})] public IActionResult GetProduct(string id) // 客户端传递ULID字符串 { if (!Ulid.TryParse(id, out Ulid productId)) { return BadRequest(Invalid ID format.); } // ... 用 productId 查询数据库 } [HttpPost] public IActionResult CreateProduct(CreateProductDto dto) { var product new Product { Id Ulid.NewUlid(), // 在服务端生成ID Name dto.Name, // ... }; // ... 保存到数据库 return CreatedAtAction(nameof(GetProduct), new { id product.Id.ToString() }, product); } }在Serilog等日志中集成你可以很方便地将ULID设置为日志的上下文属性用于追踪整个请求链路。// 在中间件中生成请求ID app.Use(async (context, next) { var requestId Ulid.NewUlid().ToString(); context.Items[RequestId] requestId; using (LogContext.PushProperty(RequestId, requestId)) { await next(context); } });4. 在Unity游戏开发中的集成指南Unity开发环境有其特殊性但集成这个Ulid库同样顺畅。4.1 导入库到Unity项目通过Unity Package Manager (UPM)如果库提供了package.json你可以通过Git URL或本地路径添加。打开Window - Package Manager。点击号选择Add package from git URL...。输入仓库的Git URL如https://github.com/xxx/Ulid.git或本地路径。直接放置DLL或源码将编译好的Ulid.dll确保是.NET Standard或兼容版本放入项目的Assets/Plugins文件夹。或者直接将整个Ulid的C#源码文件夹拖入Assets/Scripts目录下。源码方式兼容性最好尤其对于需要支持WebGL等严格AOT的平台。4.2 游戏开发中的典型用例网络消息与事件ID在多人游戏中服务器需要为每一条广播消息、每一个游戏事件如玩家发射子弹、拾取道具生成唯一ID用于去重、确认和追踪。public class NetworkEvent { public Ulid EventId { get; } Ulid.NewUlid(); public string EventType { get; set; } public byte[] Payload { get; set; } // 接收方可以根据EventId轻松去重和排序事件 }玩家会话与实体标识为每个连接的游戏会话、每个动态生成的游戏实体怪物、掉落物分配ULID。public class GameEntity : MonoBehaviour { public Ulid EntityId { get; private set; } void Awake() { // 在服务器或权威端生成ID if (isServer) { EntityId Ulid.NewUlid(); // 然后将ID同步给所有客户端 } } }本地数据存储键名使用PlayerPrefs或SQLite存储本地数据时用ULID作为键名或记录ID可以避免冲突并且通过ID就能知道创建的大致时间。string saveSlotKey $SaveGame_{Ulid.NewUlid()}; PlayerPrefs.SetString(saveSlotKey, jsonData);性能分析与日志在Unity编辑器和真机调试中为每一帧、每一次资源加载、每一个动画状态切换生成一个ULID并记录时间戳可以非常清晰地在日志系统中构建出事件的时间线便于性能剖析。4.3 Unity特定注意事项线程安全Unity的大部分API只能在主线程调用。确保ULID的生成如果涉及Unity对象比如挂载到GameObject要在主线程进行。但Ulid.NewUlid()本身是线程安全的可以在工作线程生成ID然后传递回主线程使用。IL2CPP与AOT如果使用源码集成基本没有问题。如果使用预编译的DLL确保它是为.NET Standard构建的并且不包含任何IL2CPP不支持的反射代码。这个Ulid库通常是无反射的纯算法实现兼容性很好。随机数源在Unity的WebGL平台上System.Random和RandomNumberGenerator的行为可能与标准.NET不同。一个健壮的Ulid实现应该处理好这种平台差异确保随机部分的熵值足够。你需要测试在目标平台上生成的大量ULID是否真的没有冲突。序列化如果你需要将包含Ulid结构体的游戏状态进行网络序列化如使用Unity的Netcode或Mirror或存盘需要实现自定义的序列化方法将其转换为byte[16]或string进行传输。5. 高级话题与性能实测5.1 自定义时间源与随机源库可能提供了高级接口允许你注入自定义的随机数生成器和时间戳提供器。这在某些特定场景下非常有用// 假设库提供了这样的构造函数具体API以实际库为准 var customUlidGenerator new UlidGenerator( timeSource: () DateTimeOffset.UtcNow, // 自定义时间例如用高精度时钟 randomProvider: MyCryptoRandomProvider.Instance // 自定义随机源 ); Ulid customUlid customUlidGenerator.NewUlid();应用场景测试注入固定的时间戳和随机种子可以生成可预测的ULID方便编写单元测试。高精度时钟如果你的系统需要微秒或纳秒级的时间区分度可以替换更高精度的时间源但要注意ULID规范只定义到毫秒。特定随机算法在某些对随机数质量有极端要求或需要特定分布的场景下进行替换。5.2 性能基准测试光说“极速”不够要有数据。我们可以用BenchmarkDotNet做一个简单的对比测试比较这个Ulid实现、标准的Guid.NewGuid()以及另一个流行的UUID/ULID库。[MemoryDiagnoser] // 同时分析内存分配 public class IdGenerationBenchmark { [Benchmark] public Ulid GenerateUlid() Ulid.NewUlid(); [Benchmark] public Guid GenerateGuid() Guid.NewGuid(); // 可能对比其他库如 CSharpVitamins.ShortGuid (一种编码的Guid) 或 IdGen (雪花算法) // [Benchmark] // public string GenerateShortGuid() ShortGuid.NewGuid().ToString(); }预期的结果可能类似方法均值分配GenerateUlid15 ns0 BGenerateGuid25 ns0 BGenerateShortGuid120 ns160 B这个假设数据表明优化的Ulid实现在纯生成速度上可能优于Guid而最关键的是在涉及字符串转换的完整路径上生成并转为字符串由于避免了编码过程中的临时分配其性能和内存优势会非常明显。这对于API中频繁返回ID字符串的场景至关重要。5.3 常见问题与排查生成的ULID看起来不是严格递增检查系统时钟这是最常见原因。确保服务器或主机启用了NTP时间同步并且没有发生大的时钟跳变。在虚拟机或容器中尤其要注意。并发问题如果在同一毫秒内并发生成海量ULID80位随机数支持每毫秒约1.2e24个不重复ID几乎不可能耗尽顺序可能由随机部分决定但整体时间序依然保持。如果要求绝对单调递增同一毫秒内也有序可能需要引入序列号类似雪花算法但这超出了标准ULID规范。在数据库中排序结果不对存储类型如果你将ULID以字符串形式存储在VARCHAR字段请确保数据库的排序规则Collation是二进制或区分大小写的如utf8_bin。如果是不区分大小写的排序规则“01H5...”和“01h5...”可能被视为相同。编码问题确保从二进制转换到Base32字符串的编码过程使用的是标准的Crockford‘s Base32字母表不同实现混用会导致排序混乱。在Unity中报错“找不到方法”或AOT错误检查.NET兼容性确保导入的DLL或源码的目标框架与Unity项目设置的.NET API Compatibility Level如.NET Standard 2.1或.NET Framework兼容。使用源码最保险的方式是直接使用C#源码让Unity的IL2CPP编译器一起编译。检查依赖确认该Ulid库没有依赖其他不兼容Unity的NuGet包。ULID字符串太长有没有更短的方案ULID的26字符长度是其在可读性、信息密度和编码效率间的平衡。如果觉得长可以考虑存储为二进制(16字节)和UUID一样长但失去了字符串可读性。使用Snowflake雪花算法ID通常是64位长整型更短但包含机器ID、序列号等概念需要中心化或配置。使用NanoId或KSUID其他类型的ID方案各有优劣。选择取决于你对长度、有序性、可解析性等维度的优先级排序。我个人在实际项目中的体会是ULID并非银弹但它确实在“需要有序性”、“需要从ID中解读时间”、“希望ID对数据库友好”这几个需求重叠的场景下提供了一个近乎完美的解决方案。从UUID切换到ULID后最直观的感受就是排查日志时轻松多了再也不用在时间戳和一堆无序的UUID之间来回对照。对于新的.NET或Unity项目如果ID生成方案还没定我会毫不犹豫地推荐先试试ULID。

相关新闻

基于YOLO的钢材表面缺陷实时检测系统实践

基于YOLO的钢材表面缺陷实时检测系统实践

1. 项目概述在工业质检领域,钢材表面缺陷检测一直是个技术难点。传统人工检测方式不仅效率低下,而且容易因视觉疲劳导致漏检。这个基于深度学习的解决方案,通过集成YOLO系列最新算法,实现了对钢材表面缺陷的实时自动化检测。我在实…

2026/8/24 18:13:19 阅读更多 →
如何在浏览器中免费制作专业扫描效果PDF:LookScanned.io完整指南

如何在浏览器中免费制作专业扫描效果PDF:LookScanned.io完整指南

如何在浏览器中免费制作专业扫描效果PDF:LookScanned.io完整指南 【免费下载链接】lookscanned.io 📚 LookScanned.io - Make your PDFs look scanned 项目地址: https://gitcode.com/gh_mirrors/lo/lookscanned.io 你是否需要将电子文档转换为看…

2026/8/25 13:12:32 阅读更多 →
Windows 11本地部署AI Agent:BotSharp框架与Llama 2实践

Windows 11本地部署AI Agent:BotSharp框架与Llama 2实践

1. 环境准备与项目概述 在Windows 11系统上部署本地AI Agent需要做好以下基础准备: 1.1 硬件与软件需求 操作系统 :Windows 10/11(建议使用最新稳定版) 开发工具 :Visual Studio 2022(需安装.NET 8 …

2026/8/23 9:15:30 阅读更多 →

最新新闻

STK 数据格式转换成 Matlab 时间格式,运算过后转换回来,以供调用

STK 数据格式转换成 Matlab 时间格式,运算过后转换回来,以供调用

一、 STK 数据格式转换成 Matlab 时间格式,运算过后转换回来,以供调用 %% 主要思路:datetime 可以指定输入输出时间格式 % t.Format MMM dd, yyyy HH:mm:ss.SSS % 指定输出格式 % t datetime% Jun 25, 2018 11:23:37.712dt datetime(tStr…

2026/8/25 13:12:23 阅读更多 →
揭秘互联网人工打造外贸独立站的建站公司!

揭秘互联网人工打造外贸独立站的建站公司!

在全球贸易数字化的浪潮下,外贸独立站成为企业拓展海外市场的重要途径。然而,如何选择一家专业靠谱的建站公司至关重要。本文将为您揭秘相关领域的情况,其中凰启出海(BoxMedia)值得重点关注。行业现状与痛点目前&#…

2026/8/25 13:12:23 阅读更多 →
Linux学习笔记:文件IO

Linux学习笔记:文件IO

之前学了标准IO&#xff0c;这篇整理文件IO的部分。文件IO是Linux内核提供的接口&#xff0c;属于系统调用&#xff0c;操作对象是文件描述符而不是FILE指针。核心就四个&#xff1a;open打开、read读、write写、close关闭。open#include <sys/types.h>#include <sys/…

2026/8/25 13:12:23 阅读更多 →
Claude Code、Codex 都太过臃肿,最后我选择了这个轻量级工具

Claude Code、Codex 都太过臃肿,最后我选择了这个轻量级工具

作为一个传统意义上的“开发者”&#xff0c; AI 工具把我彻底推向了命令行。 最开始我只是偶尔用 Claude Code 做点小功能&#xff0c;用着用着&#xff0c;越来越舒服。出于好奇&#xff0c;我顺理成章地开始折腾其他替代品&#xff1a;Codex、Cursor、OpenCode……挨个试了一…

2026/8/25 13:12:23 阅读更多 →
Vue3 + Element Plus 集成 JSON Editor 实现实时校验 JSON 编辑器(高亮/暗亮主题/分栏回显/组件复用) - 附完整示例

Vue3 + Element Plus 集成 JSON Editor 实现实时校验 JSON 编辑器(高亮/暗亮主题/分栏回显/组件复用) - 附完整示例

在中后台管理系统、配置中心、接口联调等开发场景中&#xff0c;传统原生 <textarea> 仅支持纯文本录入&#xff0c;难以实现语法高亮、括号匹配与实时校验&#xff0c;JSON 格式错误往往要提交后才暴露。而社区常见 JSON 编辑方案样式固化、暗色适配差、缺乏即时回显&am…

2026/8/25 13:12:23 阅读更多 →
基于大数据的服装领域评论分析机器学习实战项目案例机器学习大作业

基于大数据的服装领域评论分析机器学习实战项目案例机器学习大作业

选题背景和意义服装领域作为一种新兴的购物方式&#xff0c;近年来在国内外的研究逐渐增多。服装领域不仅可以帮助地区经济发展&#xff0c;还可以保护农村环境、传承农村文化等。因此&#xff0c;对服装领域的研究具有重要的现实意义。然而&#xff0c;目前的研究大多数是对服…

2026/8/25 13:11:23 阅读更多 →

日新闻

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

【题目来源】 https://www.luogu.com.cn/problem/P7912 【题目描述】 小熊的水果店里摆放着一排 n 个水果。每个水果只可能是苹果或桔子&#xff0c;从左到右依次用正整数 1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里&#x…

2026/8/25 0:00:34 阅读更多 →
Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战&#xff1a;零后端 3 行代码返回透明 PNG 【免费下载链接】transformers.js State-of-the-art Machine Learning for the web. Run &#x1f917; Transformers directly in your browser, with no need for a server! 项目地址: https:/…

2026/8/25 0:00:34 阅读更多 →
数学建模竞赛论文写作指南:从模型构建到学术表达的核心技能

数学建模竞赛论文写作指南:从模型构建到学术表达的核心技能

1. 项目概述&#xff1a;从“会做”到“会写”的竞赛核心跃迁“全国大学生数学建模竞赛”&#xff0c;这个名字对理工科学生来说&#xff0c;分量极重。每年&#xff0c;无数团队在三天三夜的时间里&#xff0c;为一个开放性问题绞尽脑汁&#xff0c;从建立模型、求解算法到编程…

2026/8/25 0:00:34 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态&#xff0c;宏观上观察到的光是由无数个微观的光量子组成的&#xff0c;每个光子在产生的瞬间&#xff0c;其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前&#xff0c;在微观层面&#xff0c;每个光量子的运动轨迹是以波函数所展现…

2026/8/25 3:38:12 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”&#xff0c;而是SIP会话的动态重定向你有没有遇到过这样的场景&#xff1a;客服坐席A正在和客户通电话&#xff0c;突然需要把这通对话无缝转给专家坐席B&#xff0c;客户完全感知不到中间的断连——既没听到忙音&#xff0c;也没被要求重新拨号…

2026/8/25 3:38:18 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack&#xff1f;如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法&#xff0c;那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/25 3:38:23 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/24 20:22:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/25 10:31:12 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/24 11:20:22 阅读更多 →