在本地 AI 中实现绝对可复现:一份 12,810 条哈希的硬核工程记录

在本地 AI 中实现绝对可复现:一份 12,810 条哈希的硬核工程记录

一个本地优先的 AI 桌面助手、两次逐字节一致的构建、53 道自动化门禁,以及让这些数字真正成立的那些工程细节。

EchoDesk v0.2.5 · Void Entropia Studio · 2026 年 11 月 仓库: https://github.com/wyx-spark/EchoDesk · 发布: https://github.com/wyx-spark/EchoDesk/releases/tag/v0.2.5


摘要

  • 本地优先 AI 的「信任」,本质上是对一个你下载来的二进制的判断。这篇文章讲的是如何把这件事变成可复核的。
  • 我们暂时没有商业代码签名证书。我们有的是:两次独立完整构建,冷构建合计 1,496.7 秒(约 24.9 分钟),12,810 条 SHA-256 逐字节一致。
  • 同一个版本通过了 53 道自动化门禁,耗时 533.6 秒,其中包括真实安装/卸载、带像素校验的界面探针,以及一次真实浏览器的端到端运行。
  • 后端显式接管原生模型内存(不指望 GC「总会回收」),在分配炸弹发生之前就拒绝它,并用模型自己的 GGUF 头部加一次防御式硬件探测来决定 GPU 卸载层数与上下文窗口。
  • 下面几乎所有内容都能对着公开仓库、v0.2.5 标签与发布产物复核;凡是来自我们自己测量的数字,文中都会说明。

一、信任问题

本地 AI 最难建立的是信任。核心承诺 ------ 你的文档永不离开这台机器 ------ 是关于一个你从陌生人那里下载来的二进制的判断。你没法读完几百 MB 的原生代码,也不应该只凭我们一面之词。

商业代码签名证书能解决其中一部分。我们暂时还没有:一次免费签名申请没有走通 ------ 一段小插曲,不是这篇文章的主题。我们能控制的是另一半问题,于是把构建置于开源世界最严格的标准之下:任何人都能从源码重建发布物,并得到相同的字节;发布门禁真的去执行一次发布,而不是描述它。

这个区分值得说准:签名证明这个二进制是谁发布的 ,不证明这个二进制对应哪份源码。SmartScreen 检查前者;对一个会解析合同和内部文档的本地优先助手来说,后者才是关键。

这就是本文记录的工作:可复现构建、53 道门禁、显式的内存所有权、一个硬件规划器 ------ 也包括那些出过错的环节。不喊口号,只谈工程。


二、六十秒讲清 EchoDesk

EchoDesk 是一个完全跑在本机的桌面 AI 助手。

  • 两个进程。 Python 后端(31 个顶层模块:推理、文件解析、对话、Agent 循环)加 .NET 前端(WPF 面向 Windows,长期支持;Avalonia 面向三平台)。两者通过 stdin/stdout 上的按行 JSON 通信,一行请求、一行响应,第一条是 ready 握手。
  • 没有服务端。 没有 EchoDesk 云、没有账号体系、没有遥测端点。前端不监听任何端口,外部无法连入,自己也从不发起网络请求。
  • 本地推理。 模型是本机的 .gguf 文件,由 llama-cpp-python 加载。你的提示词和文档不会离开进程。
  • 五条由用户显式开启的联网路径,在隐私政策里逐项列明: 模型下载、网页搜索(默认关闭)、技能市场、更新检查、针对你自己输入的 URL 的浏览器自动化。其余代码路径全部本地。没有崩溃上报、没有使用统计、没有设备指纹。

这个架构让可验证性变得格外重要:一个从不回传数据的程序,恰恰是那种「你应该能自己重新编译出同一个二进制」的程序。


三、可复现构建:敌人是熵

「可复现构建」听起来像一个属性,实际上是跟十几个不确定性来源的拉锯战。每一个单独看都情有可原,合起来就是灾难。

我们的规则很简单:SOURCE\\\_DATE\\\_EPOCH 只有一份实现 ,取自 HEAD 的 git log -1 --format=%ct,格式化一律用 UTC。工作区不干净(git status --porcelain 非空)时打包直接终止,所以发布物只能来自一个确切的提交。开发期的豁免开关存在、显式、且从不用于验证。

剩下的,一个一个拆掉:

熵源 处理方式
归档里的墙钟时间 所有条目 mtime = SOURCE\\\_DATE\\\_EPOCH;zip 的 date\\\_time 取该 epoch 的 UTC 元组
程序集里的构建机路径 两个 .csproj 均启用 Deterministic、ContinuousIntegrationBuild、DeterministicSourcePaths,并写入显式 PathMap
属主/属组元数据 tar 条目强制 uid=0、gid=0,uname/gname 置空
文件顺序 目录遍历排序,条目按稳定键排序,zip 与 tar 都按该顺序写入
权限位 固定模式(文件 0644、目录 0755),符号链接按链接存储而不是解引用
gzip 头 filename="" 与 mtime=epoch ------ 两者都是必需项,两者都容易被忘
依赖漂移 requirements.lock 与 requirements-build.lock,分平台,sys\\\_platform 标记按目标 RID 求值,绝不按构建机;python-build-standalone 固定到日期,不用 latest
PE 时间戳 Setup.exe 与打包后的入口 exe 在构建后就地规范化 PE 时间戳
安装器压缩 TimeStampRounding=1,\\\[Files] 加 notimestamp
PyInstaller 内部 base\\\_library.zip 在收集后重写:固定条目时间、属性,并排序 条目名。PyInstaller 6.22.3 从 Python 的 set 派生基础模块集合,两次构建会以不同顺序写入相同条目。只修时间戳不够。

gzip 头是我最喜欢的例子,因为它只是两个关键字参数:

python 复制代码
# tools/reproducible.py ------ 两个参数都是逐字节一致的必需项
with gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=epoch, compresslevel=9) as gz:
    with tarfile.open(fileobj=gz, mode="w", format=tarfile.GNU\\\_FORMAT) as archive:
        ...
        info.mtime = epoch
        info.uid = 0
        info.gid = 0
        info.uname = ""
        info.gname = ""

漏了 filename="",归档会悄悄带上构建机上的文件名;漏了 mtime,每次重建都不一样。这两种失败都要等到有人真的去 diff 两次构建才会暴露 ------ 而这正是 tools/verify\\\_reproducible\\\_build.ps1 干的事。

验证脚本是刻意做狠的。它把整条 流水线跑两遍:Windows 发布树与安装程序、三平台 standalone 后端、三平台归档。两遍之间删除 bin/、obj/、\\\_\\\_pycache\\\_\\\_/、dist/ 与发布输出。然后逐项比对安装程序、三个归档、它们的清单,以及发布树里的每一个文件。v0.2.5 的两次冷构建合计 1,496.7 秒(约 24.9 分钟)。

v0.2.5 的结果:

  • 每份清单 12,810 条 SHA-256,两次构建完全一致,逐字节。
  • 两份清单文件本身的哈希也相同: 5F94655D8F04A914A278B54490A0CF917A986295568B5FCA543B23E618057913
  • 最终安装程序 EchoDesk-v0.2.5-Setup.exe = 590b19b366191f6d612791f4c043d578931f1c5d17e8e9202d49077d6747f61b

如果你在干净机器上从 v0.2.5 标签重建,得到的哈希不同,那就是一个真实的缺陷,我们想要那个 Issue。这句话就是可复现构建的全部价值主张,任何证书都替代不了。


四、五十三道门禁,以及门禁说谎的那一天

可复现构建只是其中一道门禁。守护 v0.2.5 的发布流水线有 53 项检查 ,耗时约 9 分钟(533.6 秒)。它不是单元测试套件,而是把「发布」本身执行一遍:

  • 构建发布树与安装程序,然后真装、真卸,断言哪些东西必须留下:用户配置、会话、注册表、模型、插件、界面偏好。
  • 打开三个平台的归档,检查顶层结构、文件数与清单。
  • 双向校验所有语言包,检查双语文档、换行符、依赖锁,并确认没有任何开发者目录(tools/、tests/、records/、prompts/)漏进发布树。
  • 无头驱动 Avalonia 界面,断言布局不变量,并比对渲染像素。
  • 用真实的 Microsoft Edge 跑一次端到端自动化。

53 项门禁是一台生产信心的机器。它同时也是一台生产虚假信心的机器,而我们有伤疤为证。

那些验证了错误产物的门禁

有两个发布周期里,五个界面探针脚本的默认被测程序是硬编码的:publish\\\\EchoDesk-v0.2.2。而我们发布的是 v0.2.3。探针一直通过 ------ 通过的是旧二进制 。等我们把脚本改成从 backend/version.py 派生发布树,v0.2.3 的 LTS 提示条和新的「关于」页立刻被报告为缺失,因为它们从来就不在被探测的那棵树里。

没有人撒谎。门禁是绿的,因为它测的是一台博物馆藏品。

修好之后立刻抓到真问题的门禁

对比度检查患的是同一种病:它拿错了色板去断言悬停/按下的对比度。当它改为检查 Avalonia 中真正定义这些令牌的主题字典后,抓到了一个真实的无障碍缺陷 ------ 浅色主题 AccentHoverBrush 的 #0095A8 实测只有 3.58:1 ,低于 4.5:1 阈值。现在它是 #00808F,4.68:1。

修好后的流水线第一次全量运行

第一次「打算全绿」的全量运行失败了四次,每一次都是真实原因:

  1. 硬件探测里有一个未声明的可选 psutil 导入。开发机上碰巧装了 psutil,所以能跑;在干净的构建机上会直接失败。删除它,改用三平台标准库路径。
  2. 两个测试仍然硬编码 publish/EchoDesk-v0.2.2。
  3. 三张 emoji ASCII 降级表缺 📐(U+1F4D0),而新的界面警告标签用到了它。
  4. 发布门禁从未执行 Avalonia 的 chat 探针,所以它新加的断言只是装饰。

我们写进项目规则的教训很直白:门禁失败时先怀疑门禁 ------ 但只修根因,绝不为了让灯变绿而放宽它。 而且,一条断言必须被证明「有能力失败」。当初修 Config.save() 把配置写到当前工作目录而不是程序目录的缺陷时,我们临时恢复了旧实现,确认新断言会变红,然后才接受修复。一条你从未见它失败过的断言,只是一句注释。


五、内存:泄漏通常是生命周期缺陷

我们不声称「零内存泄漏」。我们声称的是一句更窄、也更有用的话:每一类我们能证明的泄漏都已经消除;剩下的大块分配,全部是有预算的,而不是靠运气。

5.1 那个没人关闭的句柄

后端的崩溃处理器原本在模块导入时 就安装,并以追加模式打开 backend\\\_crash.log、一直持有句柄。而 main.py 几乎被每一个测试脚本导入。后果有两层:

  • 每个测试进程在生命周期内都泄漏一个打开的文件句柄;
  • 测试里每一个未捕获异常都被追加进真正的 后端崩溃日志,于是真实崩溃被测试噪声淹没(test\\\_reasoning.py ValueError、test\\\_retrieval.py ValueError、test\\\_search.py TypeError)。

修法很小:安装逻辑移进 install\\\_crash\\\_handlers(),只由 if \\\_\\\_name\\\_\\\_ == "\\\_\\\_main\\\_\\\_": 调用,导入模块因此没有任何副作用。现在有一条回归断言检查 import main 之后崩溃日志句柄仍为 None。

这就是最典型的泄漏。不是对象图里什么聪明的循环引用 ------ 只是一个在导入作用域获取、然后永远不释放的资源。

5.2 原生内存不认你的 GC

一个加载好的 GGUF 模型是几百 MB 由 llama.cpp 持有的原生内存,不是 Python 的。CPython 会在最后一个引用消失时回收 Llama 包装对象,但原生析构的时机不属于 API 契约 ------ 而「迟早会回收」在你准备加载第二个模型、或用户连点四十次「测试加载」的时候,一点都不够。

所以所有权是显式的:

python 复制代码
def close(self) -> None:
    llm = getattr(self, "llm", None)
    self.llm = None
    if llm is None:
        return
    close = getattr(llm, "close", None)
    if callable(close):
        try:
            close()          # 触发 llama\\\_model\\\_free / llama\\\_free
        except Exception:
            log.debug("释放 llama.cpp 模型失败(忽略)", exc\\\_info=True)

LLMEngine 是上下文管理器,\\\_\\\_exit\\\_\\\_ 必定调用 close()。「测试加载」更进一步:它跑在子进程 里,带 60 秒超时 ------ 因为线程杀不掉,超时的线程会让模型永远驻留。子进程在 finally 里关闭引擎、del 掉、再 gc.collect();父进程在超时后直接结束进程,由操作系统回收一切。

这是一个「内存泄漏修复」,本质却是进程生命周期修复。如果你需要内存的硬上限,你就需要一个由操作系统执行的边界。

5.3 在分配炸弹发生前拒绝它

最危险的「泄漏」根本不是泄漏 ------ 是一次本就不该发生的成功分配。

如果用户在旧版设置里填了 n\\\_ctx = 999999,后端会向 llama.cpp 申请约 100+ GiB 的 KV Cache。在 32 GiB 内存的机器上,宿主会疯狂换页将近一分钟然后失败,整个桌面卡死。现在有预检 :从模型头部估算每 token 的 KV 字节数,乘以请求的上下文,与当前可用内存比较,在进入原生代码之前就返回结构化错误:

请求的上下文 999999 tokens 无法分配(硬件预算 32768),通常意味着超出可用内存。原始错误:Failed to create llama\\\_context

开发机上实测:约 44 秒返回,没有换页风暴,旧模型仍然加载着、仍然可用。一次失败的实验,代价应该是一个错误对话框,而不是用户的一个下午。

5.4 预算是算出来的,不是盼出来的

内存账本的其余部分是会计工作:

  • KV Cache 是算出来的,不是猜的。 GGUF 头部给出层数、注意力头数、KV 头数、键/值维度,每 token 字节数就是算术 ------ 而且是在不加载模型 的情况下从文件里读出来的,按 (路径, 大小, 修改时间) 记忆化,上限 16 条。
  • 上下文从小开始。 初始 2,048,不再是写死的 8,192。上限取四者最小值:配置上限、请求值、模型原生训练窗口,以及预留 20% 余量加 256 MiB 计算缓冲后的内存预算。生成前按需翻倍,扩展失败只告警并沿用旧窗口。
  • GPU 卸载预留 20% 空闲显存,再加 KV Cache 和 512 MiB 计算缓冲。显存缓冲刻意比内存缓冲大,因为它们是不同的分配器、不同的失败模式。
  • 无界结构一律封顶。 模型市场内存中最多保留 20,000 条;流式输出走有界队列(快模型不能把渲染队列变成内存黑洞);长文档分段受上下文大小约束。
  • 升级不积累垃圾。 安装器在升级时只删 bin/ 和缓存目录,精确排除模型、配置、会话、插件;卸载时把小体积用户数据备份到 %LOCALAPPDATA%\\\\EchoDesk\\\\uninstall-backup\\\\,模型原地保留。

5.5 我们还不知道什么

我们还没有跑过一次 72 小时的浸泡测试,在数千次文档循环中采样 RSS 与句柄数。它在待办列表上。在它存在之前,「无泄漏」不是我们的主张 ------ 但「我们知道每一块大分配从哪来、由谁释放」是。


六、硬件自适应:读文件头,不要猜

大多数桌面 AI 工具默认 n\\\_gpu\\\_layers=99,然后让用户自己去发现后果。我们反着来:程序探测宿主、读取模型、算出方案 ------ 然后解释它。

6.1 探测整体包在异常边界里

hardware\\\_profiler.py 探测物理/逻辑核心数与 AVX2/AVX-512,NVIDIA 走 nvidia-smi,AMD 走 amdgpu sysfs,Apple Metal 可用性,以及通过 GlobalMemoryStatusEx、/proc/meminfo 或 sysctl + vm\\\_stat 读取的总/可用内存。然后它会问当前这个 llama\\\_cpp 构建是否支持 GPU 卸载 ------ 有 CUDA 显卡但装的是纯 CPU wheel,绝不能触发卸载。

这些调用在古怪或恶劣的机器上都可能失败。整段探测被包住,任何未预期异常都会静默降级为最保守的纯 CPU 档案。硬件探测永远不能成为助手启动不了的原因。

多显卡主机取空闲显存最大的那一块,绝不相加 ------ 把显存加起来,就是在承诺一个不存在的卸载额度。

6.2 卸载决策就是四行算术

python 复制代码
# 简化节选 ------ 实际实现还会钳制负值
usable = int(gpu.free\\\_vram\\\_bytes \\\* (1.0 - VRAM\\\_SAFETY\\\_RATIO))   # 20% 安全水位线
overhead = kv\\\_cache\\\_bytes + compute\\\_buffer                      # GPU 侧 512 MiB
if model\\\_bytes + overhead <= usable:
    return -1, "full\\\_offload\\\_fits\\\_safety\\\_watermark"             # -1 = 全量卸载
per\\\_layer = model\\\_bytes / (model\\\_layers + 1)                    # +1 留给词嵌入与输出头
layers = int((usable - overhead - per\\\_layer) // per\\\_layer)

那个 +1 很关键:llama.cpp 的部分卸载模式下,词嵌入与输出头留在宿主侧,预留一个单层等效额度,才能避免经典的「32 层全卸载,最后一个张量 OOM」。

因为开发机没有独显,这条路径用合成显存档案验证,而且断言是精确值,不是约等于:

合成档案 模型 期望
8 GiB 空闲显存 7B Q4 -1(扣掉 20% 水位线后全量卸载放得下)
12 GiB 空闲显存 13B Q4 -1
4 GiB 空闲显存 13B Q4 部分卸载,恰好 18 层
2 GiB 空闲显存 13B Q4 0(回到 CPU,不做徒劳的卸载)
无加速器 任意 恒为 0

6.3 上下文:从 2K 起步,长到上限

旧代码到处写死 8,192 token,并在一开始就为它分配 KV Cache。32 GiB 内存的机器扛得住,笔记本扛不住。现在引擎以 2,048 加载,在某次提示词要溢出之前按翻倍扩展,收敛到硬件上限。扩展意味着重新加载模型 ------ 真实成本 ------ 但只有真正需要长上下文的用户才会付,而且扩展失败只告警、保留旧窗口,而不是掐断对话。

上限本身取四项约束的最小值:配置上限、请求值、模型的 n\\\_ctx\\\_train、以及内存预算。结果会连同原因一起上报(native / hardware / config / preset / override),因为只告诉用户「你的上下文是 24,064」而不说「谁限制了它」,等于没说。

6.4 三档预设,以及一个「警告而不是撒谎」的覆盖机制

fast / balanced / quality 分别对应批大小、初始上下文、线程数与 KV 精度。在一台 10 物理核 / 16 逻辑核的 CPU 上,用真实的 0.6B 模型实测:

档位 上下文 批大小 线程
fast 1,024 / 16,384 1,024 16(全部逻辑核)
balanced 2,048 / 32,768 512 10(物理核)
quality 4,096 / 32,768 512 10

线程默认跟随物理核心数;对计算密集型负载,超线程带来的是调度开销而不是吞吐。这台机器上是 10 线程,不是 16。

而当用户坚持一个不安全的值 ------ 在纯 CPU 主机上 n\\\_gpu\\\_layers=99,或超过模型原生窗口的上下文 ------ 程序不会偷偷钳制。它照单采纳,重建失败就保留旧引擎,并返回结构化警告与推荐值。原则是:规划器是顾问,不是保姆。但它拒绝静默失败,也拒绝让用户失去一个可用的模型。

「测试加载」存在的理由也是这个:在一个可丢弃的子进程里试配置,拿到耗时和真实错误,同时完全不碰正在工作的模型。


七、隐私是架构,不是承诺

隐私政策是一份文档,隐私是进程边界的属性。

EchoDesk 最强的隐私特性是结构性的:没有服务端可以发送任何东西。 前端不监听端口、不发起请求;后端的五条联网路径各自可关,政策逐项列明每条路径发出什么字段、连哪些域名、怎么关。没有遥测、没有崩溃上传、没有安装 ID、没有设备指纹。唯一与「机器」沾边的外发数据,是更新检查 User-Agent 里的版本号。

几个真正花了工程功夫的细节:

  • 加密文档 通过 COM 借用本机已安装、已授权的 WPS 打开,SaveChanges=False。解密在内存中完成,不写出解密副本。用户打不开的文档程序也打不开 ------ 不做密码破解,这是设计选择。
  • 日志从构造上就是脱敏的。 崩溃日志只含堆栈。自动化审计日志记录时间、事件、文件名、结果与被截断的错误 ------ 从不包含文件内容、模型输出、Token、Cookie、密码或表单值。
  • 用户数据比安装程序活得久。 升级绝不覆盖 config.json、会话、注册表、模型、插件与界面偏好;卸载保留用户数据,并备份其中的小体积部分。
  • 主张要对着代码审计。 当文档承诺得比实现多时,我们要么修代码,要么收窄措辞 ------ 包括那次不舒服的发现:长文档缓存可能把解析后的正文写到磁盘,于是我们被迫把边界说清楚,而不是宣传「任何东西都不落盘」。

最后一点才是信任的关键。一条没和自己的代码核对过的隐私主张,是负债,不是功能。


八、签名能证明什么,不能证明什么

EchoDesk 的 Windows 构建当前未签名。首次运行时 Windows 可能显示「未知发布者」;部分企业策略会直接阻止未签名安装包;macOS Gatekeeper 需要用户手动放行。这些是真实成本,证书是对症的解决办法。

证书做不到的是证明「对应关系」。签名说的是这个二进制由那个发布者发布 ;而被攻陷的构建机同样能产出一个签名完美的恶意二进制。可复现构建回答的是另一个问题:这个二进制是不是所有人都能读的那份源码? 两个答案都需要,而其中一个可以凌晨两点独自完成,不需要任何人批准。

在证书签发之前,可验证的路径是:

  • 公布每个产物的 SHA-256,包括哈希清单自身的摘要;
  • 公布确切的 SOURCE\\\_DATE\\\_EPOCH 与工具链锁定,让重建成为可能;
  • 发布物里的 SIGNING.txt 写清什么已签名、什么没有,而不是暗示缺口已经补上;
  • README 与 CODE\\\_SIGNING.md 标注 Windows 构建未签名,不让人去猜。

这些都不能替代签名。它们是我们今天能证明的那部分。


九、我们做错了什么,还缺什么

一篇只列战绩的文章毫无价值。以下是项目自己记录的已知缺口:

  • GPU 卸载只用合成显存档案验证过。 没有任何真实 CUDA / ROCm / Metal 设备跑过长上下文压力测试。算术被断言了,硬件没有被断言。
  • AMD 探测只覆盖 Linux sysfs ,没有 rocm-smi 路径。
  • 没有 72 小时的 RSS/句柄浸泡测试。 我们移除了可证明的泄漏类别,但没有在负载下证明它们不存在。
  • 量化 KV Cache 未启用。 三档统一 F16,因为 Q8_0 需要我们尚未验证的 flash-attention 支持。切换预设会完整重建模型,没有热切换。
  • macOS 未签名、未公证;Linux 交付 .tar.gz,不是 AppImage。
  • tools/、.github/ 与 docs/ 中的内部措辞仍未清理。 v0.2.5 已完成后端与两个前端的注释双语化;工具脚本与文档是下一批。
  • 动效没有接入系统「减少动态效果」偏好。 它在待办上,还没做。
  • 单显卡路径在开发机上根本无法执行 ------ 这本身就是合成档案方案存在的原因。

这些没有一条藏在非公开的 issue 列表里。它们和代码在同一个仓库。


十、结语:哈希能证明什么

签名与可复现构建回答不同的问题,谁也替代不了谁。但它们的前提不同:签名需要有人愿意为你背书;可复现构建只需要一个编译器。

这种不对称很有用。它意味着一个小项目不必先被信任,才能被检查。任何人都可以挑一个标签,把构建跑两遍,比对 12,810 条摘要 ------ 约二十五分钟,不需要任何人批准。

如果你想自己核对:

text 复制代码
tag:      v0.2.5
setup:    590b19b366191f6d612791f4c043d578931f1c5d17e8e9202d49077d6747f61b
manifest: 5F94655D8F04A914A278B54490A0CF917A986295568B5FCA543B23E618057913
entries:  12,810
gates:    53/53, 533.6 s

如果对上了,你验证到的是一件签名告诉不了你的事:这个二进制就是你能读到的那份源码。如果对不上,你发现了一个可复现性缺陷 ------ 这正是我们想要的 Issue。

名气是流动的,但数学和哈希是永恒的。


EchoDesk 由 Void Entropia Studio 开发。仓库、发布与完整审计记录均公开。欢迎在 Issues 与 Discussions 里讨论,或提交你的可复现构建结果。

相关推荐
简创AIGC陶先生23 分钟前
【直播切片工作台】第31章:任务接口与任务服务
github
用户2991422196806 小时前
GitHub 热榜项目:日榜(2026-11-10)
人工智能·开源·github
miofly6 小时前
Meta发布小模型Muse Ember,智能体基准多项超GPT-6与Claude Haiku 5.5
开源·github
wflynn7 小时前
GitHub 日榜趋势速报 | 2026-11-09
开源·github
miofly9 小时前
GitHub 日榜趋势速报 | 2026-11-10
开源·github
Yingyingyingyyy9 小时前
GitHub 开源热榜项目-周榜(2026-11-09)
开源·github
孟郎郎20 小时前
打造一切(Craft Anything)——克隆构造世间万物
人工智能·ai·github·软件构建·开源软件
海洋之恒21 小时前
GitHub Actions 自动化:5 个真实运维提效案例
运维·自动化·github
小Z先生1 天前
我用 Go + 系统 WebView 写了个纯本地 Postman:不装 Electron、不连云端
后端·github