尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Cherry Studio 测试 Mock 体系解析:基于 `tests/__mocks__/` 的统一测试桩设计与实践
Cherry Studio 测试 Mock 体系解析基于tests/__mocks__/的统一测试桩设计与实践【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio本篇技术指南围绕 Cherry Studio 开源仓库中的统一测试 Mock 目录 tests/mocks/README.md 展开系统讲解该项目如何按进程类型Renderer / Main组织 Mock、如何通过 setup 文件全局注入、以及如何利用test-mocks路径别名在测试中完成数据播种、错误模拟与生命周期服务桩替。读完本文你将掌握 Cherry Studio 测试体系的核心约定并能在自己的测试文件中复用这套 Mock API 编写真实、可维护的单元测试。一、为什么需要一套“统一”的测试 MockCherry Studio 是典型的 Electron 桌面应用横跨主进程Main、渲染进程Renderer与共享层Shared。直接对真实服务编写单元测试会遇到三类障碍环境缺失jsdom 中没有 Electron 主进程的ipcMain、BrowserWindow渲染层也拿不到window.electron桥接对象副作用难以控制CacheService、DataApiService、PreferenceService这类横切基础设施牵动数据库、网络与跨窗口通信测试必须能精准控制其状态生命周期复杂主进程服务通过ServiceContainer注册、依赖注入且带onInit/onStart/onStop/onDestroy生命周期直接实例化成本高。因此仓库在 tests/mocks/ 下维护了一套“统一 Mock”按进程类型分目录组织并在测试 setup 文件中全局配置让绝大多数测试无需关心基础设施的桩替细节。可用 Mock 一览进程Mock说明RendererCacheService三层缓存memory/shared/persistRendererDataApiServiceData API 的 HTTP 客户端RendererPreferenceService用户偏好设置RendereruseDataApiData API HooksuseQuery、useMutation 等RendererusePreference偏好 HooksRendereruseCache缓存 HooksMainapplication统一的应用 Mock 工厂提供application.get()MainDbService携带 mock db 的数据库服务MainCacheService内部缓存 跨窗口共享缓存MainDataApiServiceAPI 协调器MainPreferenceService偏好服务文件结构tests/__mocks__/ ├── renderer/ │ ├── CacheService.ts │ ├── DataApiService.ts │ ├── PreferenceService.ts │ ├── useDataApi.ts │ ├── usePreference.ts │ └── useCache.ts ├── main/ │ ├── application.ts │ ├── CacheService.ts │ ├── DataApiService.ts │ ├── DbService.ts │ ├── FileManager.ts # 应用工厂默认实例之一README 树未列出见 application.ts │ └── PreferenceService.ts ├── RendererLoggerService.ts └── MainLoggerService.ts说明实际目录中 main/application.ts 的defaultServiceInstances还注册了FileManager、MainWindowService、WindowManager、IpcApiService、JobManager等最小桩替README 的文件树仅展示了核心基础设施实际可application.get()的服务比表格更广。二、测试 SetupMock 如何全局生效Mock 在两个 setup 文件中完成全局注入分别对应 vitest.config.ts 中main与renderer两个测试项目项目均声明各自的setupFiles。Renderertests/renderer.setup.tsrenderer.setup.ts 通过vi.mock把渲染进程关键模块整体替换data/PreferenceService→MockPreferenceServicedata/DataApiService→MockDataApiServicedata/CacheService→MockCacheServicedata/hooks/useDataApi→MockUseDataApidata/hooks/usePreference→MockUsePreferencedata/hooks/useCache→MockUseCache此外还处理了 jsdom 环境的典型缺口ResizeObserver、electron.ipcRenderer、window.api桥、uuid、axios、cherrystudio/ui组件库以及 toast/popup 通知面beforeEach中统一执行resetToastMocks()/resetPopupMocks()防止共享状态泄漏。同时注意到 setup 对logger做了全局替换RendererLoggerService且对 i18n 采用“懒初始化 容错”策略renderer.setup.ts只有需要真实翻译的组件测试才会初始化renderer/i18n/resolver被 mock 掉 i18n 的文件不会因初始化失败而报错。Maintests/main.setup.tsmain.setup.ts 注入的 Mock 更多涵盖四个基础设施服务main/data/PreferenceService、main/data/DataApiService、main/data/CacheService、main/data/db/DbService每个都同时导出类与单例保持向后兼容类导出被替换为vi.fn()供serviceRegistry使用application整体替换为mockApplicationFactory()产物Electron 主进程模块全集app、ipcMain、BrowserWindow、dialog、shell、session、webContents、nativeTheme等日志依赖winston、winston-daily-rotate-fileelectron-store与node:oshomedir固定为/mock/home。值得注意的设计node:fs、node:path、node:os采用...await vi.importActual(...)透传真实实现main.setup.ts因为drizzle-orm/better-sqlite3/migrator需要真实读取磁盘上的迁移文件需要受控行为的测试再通过vi.spyOn(fs, existsSync)局部覆盖。三、Import 路径别名test-mocks/*Mock 工具函数通过别名test-mocks/*导入别名指向tests/__mocks__定义于 electron.vite.config.ts在 vitest.config.ts 中随mainConfig.resolve.alias/rendererConfig.resolve.alias继承给测试项目。import { MockCacheUtils } from test-mocks/renderer/CacheService import { MockMainCacheServiceUtils } from test-mocks/main/CacheService注意区分两类导入被测模块使用生产别名如data/CacheService、data/hooks/useDataApi——它们已被 setup 全局替换为 MockMock 工具使用test-mocks/*别名——用于在测试体内播种状态、模拟错误、断言调用。四、Renderer 进程 Mock 详解4.1 CacheService三层缓存 MockMock 完整复刻生产CacheService的三层结构对应 src/renderer/data/CacheService.ts并内置 TTL 过期逻辑expireAt检查与订阅者通知。方法签名速查类别方法签名Memory类型安全get/set/has/delete/hasTTLK(key: K) ...set带ttl?Memorycasual 动态 keygetCasual/setCasual/hasCasual/deleteCasual/hasTTLCasualT(key: string) ...Shared类型安全getShared/getSharedSnapshot/setShared/hasShared/deleteShared/hasSharedTTLK(key: K) ...PersistgetPersist/setPersist/hasPersistK(key: K) RendererPersistCacheSchema[K]Hook 管理registerHook/unregisterHook(key: string) voidReady 状态isSharedCacheReady/onSharedCacheReady—生命周期subscribe/cleanup—从源码tests/mocks/renderer/CacheService.ts可以看到若干值得测试利用的“真实感”细节TTL 会真实过期get/has命中已过期条目会删除并通知订阅者再返回undefinedShared 键有 schema 默认值回退getShared对固定 schema 键在未命中时回退到DefaultSharedCache而模板实例在运行时 miss 返回undefinedgetSharedSnapshot则是纯粹的物理读不做 TTL/淘汰/默认值处理属于内部 API生产环境只允许useCache.ts使用测试可自由探测delete会拒绝删除被 Hook 占用的键当activeHookCounts中存在该键时返回false并打印错误模拟生产中的 Hook 引用保护Persist 写操作去重setPersist使用isEqual比较新旧值相同则静默返回保证通知次数与真实服务一致。使用示例import { cacheService } from data/CacheService import { MockCacheUtils } from test-mocks/renderer/CacheService describe(Cache, () { beforeEach(() MockCacheUtils.resetMocks()) it(basic usage, () { cacheService.setCasual(key, { data: value }, 5000) expect(cacheService.getCasual(key)).toEqual({ data: value }) }) it(with test utilities, () { MockCacheUtils.setInitialState({ memory: [[key, value]], shared: [[shared.key, shared]], persist: [[persist.key, persist]] }) }) })MockCacheUtils还提供triggerCacheChange模拟订阅事件、setSharedCacheReady切换 shared 缓存就绪态并触发回调、simulateTTLExpiration把条目过期时间改为过去验证过期分支、getCurrentState检查内部三层状态与 Hook 计数。4.2 DataApiServiceHTTP 客户端 Mock提供与生产一致的get/post/put/patch/delete以及数据变更通知与重试配置方法签名get(path, options?) Promiseanypost(path, options) Promiseanyput(path, options) Promiseanypatch(path, options) Promiseanydelete(path, options?) PromiseanyonDataChanged(endpoints, listener) () void— 函数式扇出生产语义configureRetry(options) voidgetRetryConfig() RetryOptionsimport { dataApiService } from data/DataApiService import { MockDataApiUtils } from test-mocks/renderer/DataApiService describe(API, () { beforeEach(() MockDataApiUtils.resetMocks()) it(basic request, async () { const response await dataApiService.get(/topics) expect(response.topics).toBeDefined() }) it(custom response, async () { MockDataApiUtils.setCustomResponse(/topics, GET, { custom: true }) const response await dataApiService.get(/topics) expect(response.custom).toBe(true) }) it(error simulation, async () { MockDataApiUtils.setErrorResponse(/topics, GET, new Error(Failed)) await expect(dataApiService.get(/topics)).rejects.toThrow(Failed) }) it(data change convergence, () { const listener vi.fn() dataApiService.onDataChanged(/topics, listener) MockDataApiUtils.emitDataChange([{ endpoint: /topics, kind: membership }]) expect(listener).toHaveBeenCalledWith([{ endpoint: /topics, kind: membership }]) }) })对于 Hook 消费者useDataApiMock 暴露同样的配对useDataChange注册监听器MockUseDataApiUtils.emitDataChange(effects)以生产批量语义投递通知。两者都委托给DataApiServiceMock 的扇出——与生产分层一致因此通过任一工具发射通知都能到达任一模块注册的监听器tests/mocks/renderer/useDataApi.ts。4.3 useDataApi HooksReact 数据操作 Hooks 的 Mock 提供与生产一致的签名真实实现在 src/renderer/data/hooks/useDataApi.ts并按 API 路径自动生成默认数据。Hook签名返回useQuery(path, options?){ data, loading, error, refetch, mutate }useMutation(method, path, options?){ mutate, loading, error }usePaginatedQuery(path, options?){ items, total, page, loading, error, hasMore, hasPrev, prevPage, nextPage, refresh, reset }useInvalidateCache()(keys?) PromiseanyuseReadCache()(path, query?) TResponse \| undefineduseWriteCache()async (path, value, query?) void从源码看实际 Mock 模块还导出了 README 表格之外的能力useInfiniteQuery游标分页、useInfiniteFlatItems展平pages[].items、useDataChange、prefetch测试中同样可以直接使用。默认数据生成逻辑tests/mocks/renderer/useDataApi.ts对常见路径返回结构化的假数据/topics返回两条带id/name/createdAt的主题列表/messages返回 user/assistant 两条消息/paintings返回空游标分页结构未知路径回退到{ id: mock_id, data: mock_data }。import { useQuery, useMutation, useReadCache, useWriteCache } from data/hooks/useDataApi import { MockUseDataApiUtils } from test-mocks/renderer/useDataApi describe(Hooks, () { beforeEach(() MockUseDataApiUtils.resetMocks()) it(useQuery, () { const { data, loading } useQuery(/topics) expect(loading).toBe(false) expect(data).toBeDefined() }) it(useMutation, async () { const { mutate } useMutation(POST, /topics) const result await mutate({ body: { name: New } }) expect(result.created).toBe(true) }) it(custom data, () { MockUseDataApiUtils.mockQueryData(/topics, { custom: true }) const { data } useQuery(/topics) expect(data.custom).toBe(true) }) it(useReadCache reads seeded values, () { // 键形状与生产一致省略 query 得到 [path]传入非空 query 得到 [path, query] MockUseDataApiUtils.seedCache(/topics, { topics: [{ id: t1 }], total: 1 }) const read useReadCache() expect(read(/topics)).toEqual({ topics: [{ id: t1 }], total: 1 }) }) it(useWriteCache persists to mock store (assertable via getCachedValue), async () { const write useWriteCache() await write(/topics, { topics: [], total: 0 }) expect(MockUseDataApiUtils.getCachedValue(/topics)).toEqual({ topics: [], total: 0 }) }) })注意useReadCache/useWriteCache底层共享同一个内存Map。resetMocks()会同时清空调用历史与缓存存储如果只想清缓存而保留 Hook Mock请使用clearCache()。MockUseDataApiUtils还提供丰富的场景模拟mockQueryLoading/mockQueryResult/mockQueryError、mockMutationSuccess/mockMutationError/mockMutationLoading/mockMutationWithTrigger允许传入自定义vi.fn()断言调用参数、mockPaginatedData等。4.4 useCache Hooks缓存操作 HooksHook签名返回useCache(key, initValue?)[value, setValue]useSharedCache(key, initValue?)[value, setValue]useSharedCacheValue(key)value \| undefined只读绝不物化默认值useSharedCacheSelector(keys, selector, isEqual?)selector(values)基于当前 mock 的 shared 值只读逐渲染求值、非响应式usePersistCache(key)[value, setValue]setValue接受具体值或函数式更新器(prev) next镜像生产实现。Mock 会基于最新 mock 值解析更新器并带同样的默认值回退因此使用函数式更新的调用点无需改动即可在 Mock 下运行。import { useCache } from data/hooks/useCache const [value, setValue] useCache(key, default) setValue(new value) setValue((prev) prev !) // 函数式更新器4.5 usePreference Hooks偏好设置 Hooks真实实现见 src/renderer/data/hooks/usePreference.tsHook签名返回usePreference(key)[value, setValue]useMultiplePreferences(keyMap)[values, setValues]import { usePreference } from data/hooks/usePreference const [theme, setTheme] usePreference(ui.theme) await setTheme(dark)五、Main 进程 Mock 详解5.1 范围约定只 Mock 横切基础设施tests/mocks/main/ 只承载横切基础设施的 MockPreferenceService、CacheService、DbService、DataApiService外加最小化的MainWindowService/WindowManager桩替全部经 main.setup.ts 全局预置。不要为特性化的生命周期服务如FileProcessingTaskService、KnowledgeRuntimeService在此添加文件。ServiceOverrides类型被刻意锁定为keyof typeof defaultServiceInstancestests/mocks/main/application.ts以强制执行该边界。特性服务应在测试文件内局部桩替见 5.4 节。服务类别如何 Mock基础设施上表所列已全局 Mock通过mockApplicationFactory({ Name: {...} })覆盖特性化生命周期服务测试文件内局部vi.mock(application)MockBaseService直接导入的单例无生命周期直接vi.mock(path/to/module)5.2 Application Mock统一工厂所有主进程测试都通过 main.setup.ts 全局获得application.get()的 Mock。需要自定义服务实例的测试可通过mockApplicationFactory(overrides)覆盖特定服务。API导出说明mockApplicationFactory(overrides?)返回完整 Mock 模块{ application, serviceList }供vi.mock()使用createMockApplication(overrides?)只返回 Mockapplication对象defaultServiceInstances所有已注册服务的默认 Mock 实例从源码可以看到 Mock 容器对生产ServiceContainer语义的精心复刻tests/mocks/main/application.tsget(name)命中返回实例未知名称抛出Unknown servicegetOptional(name)对已注册服务抛出提示“不是条件服务请用 get()”对未知名称返回undefined——这能抓住错误地把普通服务的get()降级成getOptional()的代码Mock 还提供getPath返回/mock/key确定性路径、isQuitting可变标志测试可置true触发退出感知代码路径、quit/relaunch/shutdown等间谍方法。getOptional语义Mock 无法完全证明容器语义——如果get/getOptional的选择对某段代码至关重要应补充真实ServiceContainer的冒烟测试参见 dataApiDataChange.container.test.ts。使用方式全局 setupmain.setup.ts 已配置vi.mock(application, async () { const { mockApplicationFactory } await import(./__mocks__/main/application) return mockApplicationFactory() })在单个测试文件中覆盖基础设施服务const mockDb { select: vi.fn(), insert: vi.fn() } vi.mock(application, async () { const { mockApplicationFactory } await import(test-mocks/main/application) return mockApplicationFactory({ DbService: { getDb: () mockDb } }) })对于非基础设施服务不要在这里覆盖——请使用 Testing Other Lifecycle Services 一节的方式在测试文件内局部桩替。5.3 四个基础设施 MockMain DbService提供对 Mock SQLite 数据库的访问方法签名getDb() MockDbwithWriteTxT(fn: (tx) T) T同步镜像生产isReadybooleangetterimport { MockMainDbServiceUtils } from test-mocks/main/DbService beforeEach(() MockMainDbServiceUtils.resetMocks()) // 使用默认 mock db MockMainDbServiceUtils.getDefaultMockDb() // 替换为自定义 db MockMainDbServiceUtils.setDb(customMockDb)底层默认 dbtests/mocks/main/DbService.ts是链式、同步better-sqlite3 形态的 drizzle 查询构建器select/insert/update/delete返回同一构建器链式方法from/where/set/values/limit/offset/orderBy/groupBy/having/returning/onConflictDoUpdate/leftJoin等均可继续链式调用同步终结器.run()返回{ changes: 0, lastInsertRowid: 0 }.all()返回[].get()返回undefined。withWriteTx的双模式行为一旦真实数据库被挂载setupTestDatabase()→setDb()withWriteTx会委托给db.transaction(fn, { behavior: immediate })以获得真实事务语义抛错回滚等纯 Mock 模式默认 db、未setDb()则退化为fn(this.db)——无互斥锁、无 BUSY 重试。需要自定义行为时用vi.spyOn(dbServiceInstance, withWriteTx)注入。手写 DbService Mock 必须包含此方法否则生产代码会抛TypeError: dbService.withWriteTx is not a function。Main CacheService内部缓存 跨窗口共享缓存类别方法签名生命周期initialize/cleanup() Promisevoid/() void内部缓存get/set/has/deleteT(key: string, ...)共享缓存getShared/setShared/hasShared/deleteSharedK(key: K, ...)订阅subscribeChange/subscribeSharedChangeT(key, callback) () voidimport { MockMainCacheServiceUtils } from test-mocks/main/CacheService beforeEach(() MockMainCacheServiceUtils.resetMocks()) MockMainCacheServiceUtils.setCacheValue(key, value) MockMainCacheServiceUtils.setSharedCacheValue(shared.key, shared)订阅 Mock 的局限subscribeChange/subscribeSharedChange是调用追踪桩不复现真实的触发语义。它们的用途是验证registerDisposable(cacheService.subscribeChange(...))接线与订阅确实发生而不是模拟回调触发。另外setShared/deleteShared会无条件把每次调用记入broadcastCalls不做isEqual短路以保持getBroadcastHistory()消费方的向后兼容。Main DataApiService管理 ApiServer 与 IpcAdapter 的 API 协调器方法签名initialize() Promisevoidshutdown() PromisevoidgetSystemStatus() objectgetApiServer() ApiServerimport { MockMainDataApiServiceUtils } from test-mocks/main/DataApiService beforeEach(() MockMainDataApiServiceUtils.resetMocks()) MockMainDataApiServiceUtils.simulateInitializationError(new Error(Failed))Main PreferenceService带类型化键的偏好存储以DefaultPreferences.default为种子方法签名initialize() PromisevoidgetK(key: K) UnifiedPreferenceType[K]setK(key: K, value) PromisevoidgetMultipleK(keys: K[]) RecordK, UnifiedPreferenceType[K]setMultiple(values) PromisevoidsubscribeForWindow(windowId, keys) voidimport { MockMainPreferenceServiceUtils } from test-mocks/main/PreferenceService beforeEach(() MockMainPreferenceServiceUtils.resetMocks()) // 播种偏好值 MockMainPreferenceServiceUtils.setPreferenceValue(ui.theme, dark) // 模拟外部变更触发主进程订阅者 MockMainPreferenceServiceUtils.simulateExternalPreferenceChange(ui.theme, light)工具函数还包括getPreferenceValue、setMultiplePreferenceValues、getAllPreferenceValues、simulateWindowSubscription、getSubscriptionCounts。5.4 测试其他生命周期服务局部桩替特性化的生命周期服务应当在测试文件内局部桩替。一个典型测试需要三处替换application、BaseService与生命周期装饰器。规范配置import type * as LifecycleModule from main/core/lifecycle import { getDependencies, getPhase } from main/core/lifecycle/decorators import { Phase } from main/core/lifecycle/types import { beforeEach, describe, expect, it, vi } from vitest const { appGetMock, startTaskMock, getTaskMock } vi.hoisted(() ({ appGetMock: vi.fn(), startTaskMock: vi.fn(), getTaskMock: vi.fn() })) vi.mock(application, () ({ application: { get: appGetMock } })) vi.mock(main/core/lifecycle, async (importOriginal) { const actual await importOriginaltypeof LifecycleModule() class MockBaseService { ipcHandle vi.fn() protected readonly _disposables: Array{ dispose: () void } | (() void) [] protected registerDisposableT extends { dispose: () void } | (() void)(d: T): T { this._disposables.push(d) return d } } return { ...actual, BaseService: MockBaseService } }) beforeEach(() { vi.clearAllMocks() appGetMock.mockImplementation((name: string) { if (name FileProcessingTaskService) { return { startTask: startTaskMock, getTask: getTaskMock } } throw new Error(Unexpected application.get(${name})) }) }) // 声明 Mock 之后再导入被测模块SUT const { FileProcessingService } await import(../FileProcessingService)关键点用vi.hoisted提升间谍、在beforeEach中给application.get注入按名称分发的实现未预期的名称直接抛错保证依赖声明完备、并通过importOriginal保留生命周期模块的getPhase/getDependencies等真实装饰器。常用断言技巧测试容器不运行因此要手动驱动onInit/onStart/onStop/onDestroy生命周期钩子目标方式Phaseexpect(getPhase(MyService)).toBe(Phase.WhenReady)依赖expect(getDependencies(MyService)).toEqual([OtherService])注册的 IPC 通道const svc new MyService(); (svc as any).onInit(); (svc as any).ipcHandle.mock.calls.map(c c[0])单个 IPC 处理器ipcHandle.mock.calls.find(c c[0] channel)?.[1]然后调用Disposables驱动生命周期后检查(svc as any)._disposables参考实现KnowledgeService.test.ts —— dispatch 桩 phase/deps 逐通道处理器检查注意 README 写的是src/main/services/knowledge/...当前仓库实际位于src/main/features/knowledge/__tests__/ShortcutService.test.ts —— 更丰富的MockBaseService含registerDisposable no-op 装饰器替换六、Best Practices 与 Troubleshooting实践约定基础设施服务已全局预置 Mock通过mockApplicationFactory({ Name: {...} })覆盖而不是临时手写application.getMock特性化生命周期服务在测试文件内局部桩替——不要把它们加进tests/__mocks__/main/或defaultServiceInstances每个基础设施 Mock 都暴露MockMainNameServiceUtils含resetMocks()及服务专属助手播种值、模拟错误。在beforeEach中调用resetMocks()。常见问题排查问题解决方案Mock 未生效检查测试是否运行在正确的进程项目renderer/main见 vitest.config.ts类型错误确保 Mock 与真实接口匹配必要时使用类型断言状态污染在beforeEach中调用resetMocks()导入问题使用路径别名data/CacheService而非相对路径七、小结Cherry Studio 的 tests/mocks/ 展示了 Electron 应用中“按进程分层 全局 setup 注入 工具函数播种”的 Mock 组织范本渲染进程 Mock 覆盖三层缓存、Data API 客户端与三大 Hook 族并在行为细节上贴近生产TTL 过期、schema 默认值、函数式更新器、批量变更通知主进程 Mock 通过统一的应用工厂复刻ServiceContainer语义严格区分“横切基础设施”与“特性化服务”的桩替边界并提供了可复制的生命周期服务测试模板。这套体系让开发者可以在完全可控、确定性的环境下验证从缓存读写到 IPC 通道注册的每一层行为。【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

如何用 Gyroflow 免费消除视频抖动:完整陀螺仪防抖指南

如何用 Gyroflow 免费消除视频抖动:完整陀螺仪防抖指南

如何用 Gyroflow 免费消除视频抖动:完整陀螺仪防抖指南 【免费下载链接】gyroflow Video stabilization using gyroscope data 项目地址: https://gitcode.com/GitHub_Trending/gy/gyroflow Gyroflow 是一款免费开源的视频稳定软件。它读取相机内置陀螺仪记录…

📅 2026/9/19 5:33:09
gopsutil disk与load包详解:磁盘分区、IO计数器、系统负载一次看全

gopsutil disk与load包详解:磁盘分区、IO计数器、系统负载一次看全

gopsutil disk与load包详解:磁盘分区、IO计数器、系统负载一次看全 【免费下载链接】gopsutil psutil for golang 项目地址: https://gitcode.com/gh_mirrors/go/gopsutil 想在 Go 程序里监控磁盘空间、磁盘IO和系统负载?gopsutil(Go …

📅 2026/9/19 5:33:09
smolagents 构建高质量 Agent 实战指南:工作流简化、信息流优化与系统化调试方法论

smolagents 构建高质量 Agent 实战指南:工作流简化、信息流优化与系统化调试方法论

smolagents 构建高质量 Agent 实战指南:工作流简化、信息流优化与系统化调试方法论 【免费下载链接】smolagents 🤗 smolagents: a barebones library for agents that think in code. 项目地址: https://gitcode.com/gh_mirrors/smo/smolagents 本…

📅 2026/9/19 5:33:09
MORE NEWS

更多资讯

📰

锁屏后程序继续运行?详解系统睡眠与电源设置

先直接说结论:电脑锁屏后程序能不能继续跑,关键在于系统的“睡眠”而不是“锁屏”本身。很多人把锁屏当成程序中断的原因,其实真正让你下载任务停摆、渲染进度清零、远程连接断开的,大多是电脑自动睡过去了,而不是锁屏…

📰

Java开发者的大模型应用开发指南:基于SpringAI的工程化实践

1. 为什么 Java 开发者需要一套自己的大模型应用开发方法论过去一年多,我身边不少做 Java 后端的同事都动过转大模型应用的念头,但真正动手时几乎都卡在同一个地方:Python 生态里的 LangChain、LlamaIndex 教程铺天盖地,而自己每天…

📰

Caffe PReLU 层深度解析:从配置参数到源码实现与反向传播

Caffe PReLU 层深度解析:从配置参数到源码实现与反向传播 【免费下载链接】caffe Caffe: a fast open framework for deep learning. 项目地址: https://gitcode.com/gh_mirrors/ca/caffe PReLU(Parameterized Rectified Linear Unit,…

📰

基于MATLAB的双缝干涉虚拟仿真平台:从建模到测量

简介:基于MATLAB的杨氏双缝干涉实验虚拟仿真平台构建文档,面向物理专业学生、高校教师及仿真实验爱好者,解决传统光学实验依赖实体设备、难以重复观察干涉现象的问题。文档从双缝干涉理论基础出发,围绕实验设计与仿真平台构建展开…

📰

Spring Boot 集成 DeepSeek API:从调通到工程化实战

1. 为什么把“调通 DeepSeek”当成第一站如果你最近在关注 AI 应用开发,大概率会发现一个现象:身边做后端的人,讨论最多的不是某个大模型跑分多高,而是“怎么把大模型接进自己的项目”。我在自己的项目里做这块时,最初…

📰

SpringBoot Actuator未授权访问:从信息泄露到深度利用实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

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

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

📞 💬