Windows下spdlog异步日志库配置与性能调优实战指南
1. 项目概述为什么我们需要一个高效的异步日志库在C后端开发或者高性能桌面应用开发中日志系统是项目的“黑匣子”和“诊断仪”。一个设计糟糕的日志模块比如直接在业务线程里同步写文件往往会在高并发或高频日志输出时成为性能瓶颈导致业务逻辑被I/O操作严重拖慢。我经历过不止一个项目在压力测试下业务响应时间飙升一查性能火焰图罪魁祸首竟然是日志写入操作。这就是为什么我们需要像spdlog这样的专业日志库。它不仅仅是一个格式化输出的工具更提供了一套完整的、生产级别的日志解决方案。其核心优势之一就是异步日志机制。简单来说异步日志就是业务线程生产者不直接操作文件或控制台而是将日志消息快速放入一个内存缓冲区队列然后由一个或多个专用的后台线程消费者来负责实际的I/O写入。这样业务线程的耗时就从毫秒级的磁盘I/O降低到了纳秒级的内存写入性能提升是指数级的。在Windows平台上配置spdlog的异步日志虽然spdlog官方文档提供了基础指引但实际落地时从编译选项、链接库的选择到异步队列的深度、刷新策略等参数的调优再到如何与Windows特有的路径、编码问题和平滑集成到Visual Studio工程中这里面有不少细节和“坑”。网上很多教程要么过于简略要么环境交代不清导致新手照着做也跑不通。这篇教程我将结合自己多次在WindowsVisual Studio 2019/2022环境下集成spdlog异步日志的经验手把手带你完成从零配置到性能调优的全过程让你能快速、稳定地在你的C项目中用上这套高效的日志系统。2. 环境准备与spdlog库的获取2.1 开发环境确认我们假设你正在使用Windows进行C开发最主流的工具链是Visual Studio配合vcpkg包管理器。这是一种高效且推荐的方式。Visual Studio: 请确保已安装推荐2019或2022版本并安装了“使用C的桌面开发”工作负载。vcpkg: 这是一个微软开源的C库管理器。如果你还没有安装可以快速安装打开PowerShell或CMD选择一个合适的目录如C:\src。执行git clone https://github.com/microsoft/vcpkg.git。进入vcpkg目录执行.\bootstrap-vcpkg.bat。为了全局使用建议执行.\vcpkg integrate install这样VS就能自动识别vcpkg安装的库了。2.2 安装spdlog库使用vcpkg安装spdlog非常简单它会自动处理依赖如fmt库和编译配置。打开终端可以是VS自带的开发者命令行也可以是普通的PowerShell在vcpkg所在目录执行以下命令.\vcpkg install spdlog:x64-windows这里的x64-windows是指定编译为64位Windows版本。如果你的项目是32位的则需要安装spdlog:x86-windows。安装成功后vcpkg会输出库的安装路径通常类似于C:\src\vcpkg\installed\x64-windows。注意我强烈建议为你的项目明确指定动态链接DLL还是静态链接。默认情况下x64-windowstriplet 编译的是动态库。如果你希望静态链接以避免运行时依赖可以安装spdlog:x64-windows-static。这个选择会影响你后续的VS项目配置。2.3 创建Visual Studio测试项目打开Visual Studio创建一个新的C控制台应用项目命名为SpdlogDemo。为了测试异步日志我们将项目配置为Release x64模式因为性能测试在Release模式下更有意义。接下来我们需要在项目属性中告诉VS去哪里找spdlog的头文件和库文件。右键项目 - “属性”。在“配置属性” - “VC目录”下包含目录: 添加你的vcpkg安装目录下的installed\x64-windows\include。库目录: 添加你的vcpkg安装目录下的installed\x64-windows\lib。在“配置属性” - “链接器” - “输入” - “附加依赖项”中如果你使用的是动态库通常不需要手动添加.lib文件因为vcpkg的集成已经帮你处理了。但如果遇到链接错误可以尝试在这里添加spdlogd.lib(Debug) 或spdlog.lib(Release)。对于静态库版本则必须添加对应的.lib文件。3. 同步与异步日志的核心概念与配置解析在写代码之前我们必须搞清楚同步和异步在spdlog里到底意味着什么以及如何配置一个异步日志器async_logger。3.1 同步日志器简单但可能阻塞创建一个同步的文件日志器非常简单#include spdlog/spdlog.h #include spdlog/sinks/basic_file_sink.h auto sync_logger spdlog::basic_logger_mt(sync_log, logs/sync_log.txt); sync_logger-info(This is a synchronous log message.);basic_logger_mt创建了一个线程安全的同步日志器。当调用info()时当前线程会阻塞直到日志消息被完整地写入磁盘文件。在日志量不大时这没问题但一旦日志频繁这种阻塞就会直接影响主线程的性能。3.2 异步日志器性能的关键异步日志器的核心思想是解耦。它主要由三部分组成异步日志器 (async_logger) 它本身不执行I/O操作。底层接收器 (sink) 如文件接收器、控制台接收器负责具体的输出。线程池 (thread_pool) 这是大脑。它内部维护一个内存阻塞队列和一组工作线程。日志器将消息推入队列工作线程从队列取出消息再调用对应的接收器进行输出。创建一个异步日志器的标准流程是#include spdlog/async.h // 必须包含异步头文件 #include spdlog/sinks/basic_file_sink.h // 1. 创建线程池并指定队列大小和线程数 auto tp std::make_sharedspdlog::details::thread_pool(8192, 1); // 2. 创建具体的接收器Sink auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(logs/async_log.txt); // 3. 使用线程池和接收器创建异步日志器 auto async_logger std::make_sharedspdlog::async_logger(async_log, std::move(file_sink), std::move(tp), spdlog::async_overflow_policy::block); spdlog::register_logger(async_logger);关键参数解析thread_pool(8192, 1): 第一个参数8192是队列中最多能容纳的日志项数量。当队列满时根据溢出策略处理。第二个参数1是后台工作线程的数量。对于纯文件日志一个线程通常足够如果同时有多个接收器或负载极高可以增加。async_overflow_policy::block: 这是当队列满时的策略。block表示生产者线程调用日志的线程将被阻塞直到队列有空间。这是最安全、不会丢日志的策略。另一种策略是overrun_oldest它会丢弃队列中最老的日志适合对日志完整性要求不极致但绝对不允许阻塞业务线程的场景。实操心得队列大小 (queue_size) 需要权衡。设置太小如1024在高突发日志下容易满导致阻塞设置太大如65536会消耗更多内存。对于大多数应用8192或16384是一个不错的起点。工作线程数通常1个就够了除非你有多个非常耗时的自定义接收器。4. 完整示例一个可复用的异步日志模块封装在实际项目中我们很少直接在main函数里配置日志。更好的做法是封装一个日志初始化模块。下面我展示一个更完整、更健壮的示例包含异步文件日志和同步控制台日志便于调试并处理了Windows路径和编码问题。logger.h#pragma once #include spdlog/spdlog.h #include spdlog/async.h #include spdlog/sinks/basic_file_sink.h #include spdlog/sinks/stdout_color_sinks.h #include memory class Logger { public: static bool Initialize(const std::string log_dir logs, const std::string log_file app.log, spdlog::level::level_enum console_level spdlog::level::info, spdlog::level::level_enum file_level spdlog::level::trace); static std::shared_ptrspdlog::logger Get() { return s_logger; } private: static std::shared_ptrspdlog::logger s_logger; };logger.cpp#include logger.h #include filesystem // C17需要VS2019以上并设置/std:c17 std::shared_ptrspdlog::logger Logger::s_logger nullptr; bool Logger::Initialize(const std::string log_dir, const std::string log_file, spdlog::level::level_enum console_level, spdlog::level::level_enum file_level) { try { namespace fs std::filesystem; // 1. 创建日志目录Windows路径处理 fs::path dir_path(log_dir); if (!fs::exists(dir_path)) { if (!fs::create_directories(dir_path)) { std::cerr Failed to create log directory: log_dir std::endl; return false; } } fs::path file_path dir_path / log_file; // 2. 创建线程池队列大小81921个工作线程 auto tp std::make_sharedspdlog::details::thread_pool(8192, 1); // 3. 创建接收器集合 std::vectorspdlog::sink_ptr sinks; // 控制台接收器同步用于调试 auto console_sink std::make_sharedspdlog::sinks::stdout_color_sink_mt(); console_sink-set_level(console_level); console_sink-set_pattern([%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%s:%#] %v); sinks.push_back(console_sink); // 文件接收器将由异步线程池驱动 auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(file_path.string(), true); file_sink-set_level(file_level); file_sink-set_pattern([%Y-%m-%d %H:%M:%S.%e] [%l] [%s:%#] [thread %t] %v); sinks.push_back(file_sink); // 4. 创建异步日志器 s_logger std::make_sharedspdlog::async_logger(main_logger, sinks.begin(), sinks.end(), std::move(tp), spdlog::async_overflow_policy::block); s_logger-set_level(spdlog::level::trace); // 日志器级别应低于或等于所有sink的级别 // 5. 注册并设置为全局默认日志器可选 spdlog::register_logger(s_logger); spdlog::set_default_logger(s_logger); // 6. 刷新策略每3秒或每条严重错误日志后刷新到磁盘 spdlog::flush_every(std::chrono::seconds(3)); s_logger-flush_on(spdlog::level::err); spdlog::info(Logger initialized successfully. Log file: {}, file_path.string()); return true; } catch (const spdlog::spdlog_ex ex) { std::cerr Spdlog initialization failed: ex.what() std::endl; return false; } catch (const std::exception ex) { std::cerr Initialization failed: ex.what() std::endl; return false; } }main.cpp#include logger.h #include thread #include vector void worker(int id) { for (int i 0; i 1000; i) { // 使用全局默认日志器 spdlog::info(Worker {}: Log message {}, id, i); // 或者使用获取的日志器 Logger::Get()-info(...); } } int main() { // 初始化日志日志目录为“logs”文件名为“myapp.log” if (!Logger::Initialize(logs, myapp.log)) { return -1; } spdlog::info(Application started.); // 模拟多线程高并发写日志 std::vectorstd::thread threads; for (int i 0; i 5; i) { threads.emplace_back(worker, i); } for (auto t : threads) { t.join(); } spdlog::info(All workers finished.); // 程序结束前确保所有缓冲日志被刷新 spdlog::shutdown(); return 0; }关键点解析模式 (set_pattern) 我设置了不同的模式用于控制台和文件。控制台使用带颜色的简洁格式 (%^%l%$表示带颜色的级别)文件则包含更全的信息如线程ID (%t) 和源代码位置 (%s:%#)便于后期分析。级别控制 可以为不同的接收器设置不同的日志级别。例如控制台只显示info及以上而文件记录所有trace级别的细节。这通过sink-set_level()实现。刷新策略spdlog::flush_every(std::chrono::seconds(3))确保即使日志量小每3秒也会强制刷一次盘避免日志长时间停留在内存缓冲区。flush_on(spdlog::level::err)保证任何错误日志都会立即触发刷新这对于捕捉程序崩溃前的最后信息至关重要。优雅关闭spdlog::shutdown()会在程序退出前等待线程池中的所有剩余日志被处理完毕确保没有日志丢失。这是一个好习惯。5. 高级配置与性能调优实战基础配置能跑起来但要用于生产环境我们还需要关注一些高级特性和调优点。5.1 线程池与队列的深度调优线程池的配置直接影响性能和稳定性。队列大小 (queue_size) 这是内存缓冲区。计算公式可以粗略估算预期峰值每秒日志条数 * 消费者处理每条日志最慢时间(秒) * 安全系数(如2)。例如峰值每秒1万条处理一条需0.1ms则10000 * 0.0001 * 2 2。但实际中I/O波动大建议设置一个较大的值如8192或16384。监控队列是否经常满会触发阻塞或丢弃是调整的依据。工作线程数 (n_threads) 对于仅写入单个机械硬盘的场景多个线程可能因磁盘锁导致竞争反而降低性能1个线程通常是最优的。如果是写入SSD或者有多个独立的接收器如同时写文件和网络可以适当增加但不宜超过CPU核心数。溢出策略 再次强调block策略最安全但可能引起业务线程延迟。如果你选择overrun_oldest务必通过spdlog::init_thread_pool的第三个参数设置一个回调来监控日志丢失的情况。5.2 后端缓冲区与刷新策略除了队列每个文件接收器也有自己的内存缓冲区。// 创建文件接收器时可以指定缓冲区大小默认为8192字节 auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(log.txt, true); // 或者通过 rotating_file_sink 来按大小或时间分割文件避免单个文件过大 #include spdlog/sinks/rotating_file_sink.h auto rotating_sink std::make_sharedspdlog::sinks::rotating_file_sink_mt(log.txt, 1024 * 1024 * 10, 5); // 10MB大小保留5个备份刷新策略除了全局的flush_every和flush_on你还可以针对单个日志器或接收器设置。5.3 Windows下的路径与编码问题路径分隔符 使用std::filesystem::path(C17) 可以自动处理/和\它是跨平台的。避免手动拼接字符串。中文路径/文件名 spdlog内部使用窄字符std::string和UTF-8。在Windows上文件系统API通常使用宽字符wchar_t。basic_file_sink_mt内部会进行转换。确保你的源文件保存为UTF-8 with BOM编码在VS中设置或者将字符串字面量显式转换为UTF-8否则中文字符在日志文件中可能是乱码。// 方法一使用u8前缀 (C11) auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(u8logs/中文日志.txt, true); // 方法二在VS项目属性 - 高级 - 字符集设置为“使用多字节字符集”不推荐限制大5.4 集成到大型项目CMake如果你的项目使用CMake集成vcpkg和spdlog会更加优雅。在CMakeLists.txt顶部指定vcpkg工具链cmake_minimum_required(VERSION 3.15) project(MyApp) set(CMAKE_TOOLCHAIN_FILE C:/src/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE STRING Vcpkg toolchain file)使用find_packagefind_package(spdlog CONFIG REQUIRED) add_executable(MyApp main.cpp logger.cpp logger.h) target_link_libraries(MyApp PRIVATE spdlog::spdlog)CMake会自动处理包含目录和链接依赖。6. 常见问题排查与调试技巧实录即使按照教程一步步来也可能会遇到问题。这里记录几个我踩过的坑和解决方法。问题1编译错误 “未找到 spdlog/async.h” 或类似错误。原因 没有包含正确的头文件或者vcpkg的包含目录没有正确设置。排查确认#include spdlog/async.h存在。在VS的项目属性 - C/C - 常规 - 附加包含目录中检查路径是否正确指向了vcpkg\installed\x64-windows\include。可以打开该目录确认下面有spdlog文件夹。清理解决方案并重新生成。问题2链接错误 LNK2019无法解析的外部符号。原因 最常见的是没有链接正确的库。如果你安装的是动态库 (x64-windows)确保项目属性 - 链接器 - 输入 - 附加依赖项中没有旧的或错误的.lib文件名。vcpkg集成通常会自动添加。如果是静态库 (x64-windows-static)则必须手动添加spdlog.lib或spdlogd.lib。排查检查vcpkg安装的输出确认安装的是哪种版本。在项目属性 - C/C - 代码生成 - 运行时库确保与库匹配。通常动态库对应/MD或/MDd静态库对应/MT或/MTd。不匹配会导致严重的链接错误。尝试执行vcpkg integrate remove然后vcpkg integrate install重新集成。问题3程序崩溃错误发生在 spdlog 内部或退出时。原因 多线程环境下日志器的生命周期管理不当。例如在全局或静态变量中使用了日志器而这些变量的析构顺序可能早于某些线程结束。解决确保在所有工作线程结束后再调用spdlog::shutdown()。尽量使用spdlog::default_logger()或通过智能指针管理日志器避免裸指针。如果崩溃发生在析构时尝试在main函数末尾、shutdown之前将所有全局日志器指针重置 (reset())。问题4日志文件没有内容或者内容不完整。原因 刷新策略未生效或程序异常退出未来得及刷新缓冲区。排查确认调用了spdlog::flush_every和设置了flush_on级别。在程序退出前主动调用spdlog::default_logger()-flush()。检查磁盘空间和文件权限。使用调试器或OutputDebugString查看是否有spdlog内部异常被捕获。问题5性能不如预期甚至比同步还慢。原因 配置不合理。例如队列大小设置过小导致生产者线程频繁阻塞或者工作线程数过多引起锁竞争。排查使用性能分析工具如VS的性能探测器查看线程阻塞情况。尝试将队列大小调大如32768。将工作线程数减少为1。对于文件日志单消费者线程往往是最高效的。检查日志格式是否过于复杂或者是否在日志调用中进行了昂贵的计算如spdlog::info(Value: {}, expensiveFunction())。昂贵的计算应在日志调用前完成。调试技巧在Debug模式下可以定义宏SPDLOG_ACTIVE_LEVEL为SPDLOG_LEVEL_TRACE并在代码中使用SPDLOG_LOGGER_TRACE(logger, ...)等宏它们可以在编译时完全移除日志语句避免影响Release性能。启用spdlog的调试信息在包含spdlog头文件之前定义#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG并设置相应的模式可以看到库内部的调试输出到stderr。配置完成后你可以运行示例程序观察logs目录下生成的myapp.log文件。你会看到即使有多个线程同时疯狂写日志主线程也几乎不受影响这就是异步日志带来的巨大优势。通过调整队列大小、刷新间隔和日志格式你可以让它完美适配你的应用场景。

相关新闻

LeetCode接雨水问题:双指针解法与优化策略

LeetCode接雨水问题:双指针解法与优化策略

1. 问题背景与核心挑战"接雨水"是LeetCode题库中一道经典的Hard级别算法题(编号42),考察对数组处理、动态规划和双指针等核心编程思想的综合运用能力。题目描述如下:给定n个非负整数表示的高度图,每个柱子的…

2026/8/9 8:17:49 阅读更多 →
Supabase:开源BaaS平台,PostgreSQL驱动的全栈开发利器

Supabase:开源BaaS平台,PostgreSQL驱动的全栈开发利器

1. 项目概述:Supabase到底是什么?最近在Vibe Coding的社群里,Supabase这个名字被反复提及,频率高到让我这个老码农都忍不住侧目。很多刚入行的朋友,甚至一些有经验但主要用传统单体架构的开发者,都在问同一…

2026/8/9 8:17:49 阅读更多 →
滑模控制在车辆稳定性系统中的应用与优化

滑模控制在车辆稳定性系统中的应用与优化

1. 高速行驶中的车辆稳定性挑战当车速超过120km/h时,车辆动力学特性会发生显著变化。前轮转向角度的微小变化可能导致车身姿态的剧烈波动,这种非线性特性在紧急变道或强侧风条件下尤为明显。去年我在测试某款电动SUV时,就曾亲历过80km/h横风下…

2026/8/9 8:17:49 阅读更多 →

最新新闻

AI创意协作:从“十二星座恋综”看结构化内容生成工作流

AI创意协作:从“十二星座恋综”看结构化内容生成工作流

最近在尝试用 AI 生成一些创意内容时,我发现一个挺有意思的现象:很多人拿到一个像“十二星座恋综”这样的主题,第一反应往往是直接丢给 AI,让它生成一段描述或脚本。但结果常常是,要么生成的内容过于套路化&#xff0c…

2026/8/9 9:28:18 阅读更多 →
构建高效召回系统:MySQL、ES、Qdrant与Redis四库协同架构实践

构建高效召回系统:MySQL、ES、Qdrant与Redis四库协同架构实践

1. 项目缘起:为什么召回系统需要“四库全书”?做搜索和推荐的朋友,尤其是最近在折腾RAG(检索增强生成)架构的,肯定对“召回”这个词不陌生。简单说,召回就是从海量数据里,快速、准确…

2026/8/9 9:28:18 阅读更多 →
3步开启专业缠论分析:通达信免费插件终极指南

3步开启专业缠论分析:通达信免费插件终极指南

3步开启专业缠论分析:通达信免费插件终极指南 【免费下载链接】Indicator 通达信缠论可视化分析插件 项目地址: https://gitcode.com/gh_mirrors/ind/Indicator 通达信缠论可视化分析插件是一款基于C开发的免费专业工具,专门为技术分析爱好者提供…

2026/8/9 9:28:18 阅读更多 →
FPGA ISP之CISP-Lite IP软件栈

FPGA ISP之CISP-Lite IP软件栈

CISP-Lite Linux CISP-Lite 在 Kria KV260 上的 Linux 相机软件栈 ISP V4L2 libcamera 树莓派 GStreamer 目录 项目简介特性系统架构CISP-Lite IP仓库结构快速上手License 项目简介 CISP-Lite 是一套基于 C/HLS 实现的轻量级图像信号处理器(ISP)&…

2026/8/9 9:28:18 阅读更多 →
PUBG罗技鼠标宏压枪脚本终极指南:5分钟快速上手提升射击精度

PUBG罗技鼠标宏压枪脚本终极指南:5分钟快速上手提升射击精度

PUBG罗技鼠标宏压枪脚本终极指南:5分钟快速上手提升射击精度 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 还在为PUBG中难以控制的…

2026/8/9 9:28:18 阅读更多 →
Django全栈开发:从零构建博客系统实战指南

Django全栈开发:从零构建博客系统实战指南

1. Django全栈开发入门:为什么选择博客系统作为练手项目?十年前我刚接触Django时,导师扔给我一个任务:"用Django做个博客系统"。当时觉得这太基础了,直到真正动手才发现,一个完整的博客系统几乎涵…

2026/8/9 9:27:17 阅读更多 →

日新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

月新闻

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

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

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

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

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

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

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

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

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

2026/8/8 17:02:44 阅读更多 →