USearch 向量相似度搜索引擎在 Unity RAG 中的集成:HNSW 原理与 LLMUnity 本地化改造实战
桌面应用数字人AI 应用【免费下载链接】Mate-EngineA free Desktop Mate alternative with a lightweight interface and custom VRM support, though with more features.项目地址https://gitcode.com/gh_mirrors/ma/Mate-Engine点击查看免费下载导读本文以 Mate-Engine 仓库中 Assets/LLMUnity/Runtime/RAG/usearch/README.md 为主体系统讲解 USearch——一个基于 HNSW 算法的单文件向量相似度搜索引擎——及其在 LLMUnity RAG检索增强生成模块中的落地方式。你将了解到 USearch 与 FAISS 的对比结论、索引的序列化与磁盘服务、精确与近似检索、量化与内存优化等核心机制并通过 NativeMethods.cs、USearchIndex.cs、DBSearch.cs 等仓库源码掌握这套引擎在 Unity 中如何被本地化改造并以DBSearch组件的形式驱动 RAG 语义检索。一、USearch 是什么定位与许可证USearch 是一个相似度搜索引擎Similarity Search Engine其核心卖点是更小、更快的单文件实现基于 HNSWHierarchical Navigable Small World近邻图算法提供比 FAISS 更快的向量检索实现以单个 C11 头文件为核心实现简单且可扩展开箱即用地支持十余种编程语言C、Python、JavaScript、Java、Rust、C99、Objective-C、Swift、C#、GoLang、Wolfram 等覆盖 Linux、macOS、Windows、iOS、WebAssembly 等平台支持 SIMD 优化与用户自定义距离度量可 JIT 编译支持f16、i8等半精度/四分之一精度存储支持从磁盘直接 view 大索引而不必加载进 RAM支持异构查询、键重命名与运行时删除内置 Binary Tanimoto 与 Sorensen 系数适用于基因组学与化学分子检索提供uint40_t紧凑邻居编号可支撑 40 亿以上规模的点集兼容 OpenMP 与自定义 executor可精细控制 CPU 利用率支持近实时聚类与子聚类、语义搜索与 fuzzy/语义 Join。许可证方面USearch 以Apache-2.0协议分发仓库内保留了完整的许可文本LICENSE。二、仓库内的本地化改造从 NuGet 到 Unity 的移植这是关联文档的重点章节记录了本仓库对 USearch C# 绑定所做的全部改动。原文列出的修改项如下NativeMethods.cs新增导入usearch_view_buffer与usearch_load_buffer两个原生函数USearchIndex.cssave与load函数被修改改为在一个ZipArchive中同时保存/加载IndexOptions与索引本身.meta文件由 Unity 自动生成新增 Cloud.Unum.USearch.asmdef用于声明程序集名称arm64 目录下的 dll 由 USearch 官方代码库为 arm64 macOS 单独编译。结合源码逐一核实可看到这些改动的具体落地2.1 原生互操作层 NativeMethods.csNativeMethods.cs 是整个绑定层的底层通过DllImport(libusearch_c, CallingConvention CallingConvention.Cdecl)对接 C 原生库并用别名声明了句柄类型usearch_index_t IntPtr、usearch_key_t UInt64、usearch_error_t IntPtr、usearch_distance_t Single。其中暴露的核心函数包括函数作用usearch_init按IndexOptions创建索引usearch_free释放索引usearch_save/usearch_load/usearch_view文件级保存、加载、只读视图usearch_size/usearch_capacity/usearch_dimensions/usearch_connectivity查询索引元信息usearch_reserve预扩容usearch_add添加向量float[]/double[]两个重载usearch_contains/usearch_count/usearch_get查询键是否存在、键下向量数量、取回向量usearch_remove/usearch_rename删除与重命名键usearch_search近似最近邻搜索含指针版、float[]、double[]三个重载文档中提到被额外导入的两个 buffer 函数也确在其中[DllImport(LibraryName, CharSet CharSet.Ansi, CallingConvention CallingConvention.Cdecl)] public static extern void usearch_load_buffer(usearch_index_t index, void_ptr_t buffer, size_t length, out usearch_error_t error); [DllImport(LibraryName, CharSet CharSet.Ansi, CallingConvention CallingConvention.Cdecl)] public static extern void usearch_view_buffer(usearch_index_t index, void_ptr_t buffer, size_t length, out usearch_error_t error);此外LLMUnity 还额外追加了一个usearch_filtered_search带过滤回调的搜索以及FilterCallback委托声明为分组检索提供了底层支撑。2.2 托管包装类 USearchIndexUSearchIndex.cs 是IDisposable的托管包装类内部持有IntPtr _index句柄。构造函数接受MetricKind、ScalarKind量化类型、dimensions、connectivity、expansionAdd、expansionSearch、multi等参数组装成IndexOptions后调用usearch_init创建索引另有从IndexOptions直接构造、以及(path, view)两种加载构造。它实现了元信息查询Size()、Capacity()、Dimensions()、Connectivity()增删改查Add(key, vector)含float[]/double[]单条与批量重载、Get单条与多条、Remove、Rename、Contains、Count自动扩容Add前通过CheckIncreaseCapacity判断容量不足时调用usearch_reserve预扩容错误处理每次原生调用后经HandleError检查错误指针非空则抛出 USearchException资源释放Dispose 析构函数双保险确保原生索引被usearch_free释放。文档提到的 ZipArchive 持久化也在此落实public void Save(ZipArchive zipArchive) { string indexPath Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Save(indexPath); try { zipArchive.CreateEntryFromFile(indexPath, GetIndexFilename()); } catch (Exception ex) { Debug.LogError(...); } File.Delete(indexPath); } public void Load(ZipArchive zipArchive) { ... ZipArchiveEntry entry zipArchive.GetEntry(GetIndexFilename()); // 读出到 managedBuffer用 GCHandle 钉住后交给 usearch_load_buffer usearch_load_buffer(_index, unmanagedBuffer, (UIntPtr)managedBuffer.Length, out error); ... }即Save先把索引临时落盘再把文件写入 Zip 归档的usearch/index条目Load则从归档中读出字节流经 GCHandle 固定托管缓冲后直接调用usearch_load_buffer从内存重建索引。2.3 新增的搜索扩展LLMUnity 附加部分在文件末尾// Additional methods from LLMUnity //标记之下USearchIndex还提供了带过滤条件的搜索能力FilterFunction静态委托与filterLock锁对象使用[MonoPInvokeCallback]标记的StaticFilter静态回调——这是为了在AndroidIL2CPP平台下把托管回调安全地传给原生代码其他平台则直接使用 C# lambda 闭包SearchT(queryVector, count, out keys, out distances, scalarKind, filter)核心实现用 GCHandle 钉住查询向量无过滤时调用usearch_search有过滤时调用usearch_filtered_search最后按实际匹配数收缩结果数组。2.4 类型定义与程序集USearchTypes.cs 定义了MetricKind枚举Cos、Ip内积、L2sq、Haversine、Pearson、Jaccard、Hamming、Tanimoto、SorensenScalarKind枚举Float32、Float64、Float16、Int8、Byte1可序列化的IndexOptions结构体StructLayout.Sequential字段与原生侧一一对应metric_kind、metric、quantization、dimensions、connectivity、expansion_add、expansion_search、multi。文件内还留有自定义度量委托的 TODO 注释说明该能力在 C# 绑定中尚未启用。Cloud.Unum.USearch.asmdef 则将上述 C# 代码声明为Cloud.Unum.USearch程序集使其可被 LLMUnity 的 RAG 模块直接引用。2.5 各平台原生库README 提到runtime dlls 由 NuGet 包导出并加入 x86_64 文件夹。在本仓库中各平台的原生库被集中放置在 Assets/LLMUnity/Resources/usearchwindows/libusearch_c.dlllinux/libusearch_c.somacos/libusearch_c.dylibAndroid/libusearch_c.soiOS/libusearch_static_c.a静态库。这也解释了为什么NativeMethods.cs中的LibraryName统一为libusearch_c——Unity 会在运行时按平台自动选择对应后缀的原生库。三、核心参数体系IndexOptions 与构造示例上游 README 给出了 Python 端的灵活构造示例本仓库的 C# 端与之对应index Index( ndim3, # 输入向量的维度 metriccos, # 可选 l2sq、haversine 等默认 ip dtypef32, # 可按需量化为 f16 或 i8默认 f32 connectivity16, # 可选限制每个图节点的邻居数 expansion_add128, # 可选控制建索引时的召回率 expansion_search64, # 可选控制搜索质量 multiFalse, # 可选是否允许一个键对应多个向量默认 False )C# 侧的USearchIndex构造函数参数与之一一对应USearchIndex( MetricKind metricKind, // 距离度量如 MetricKind.Cos ScalarKind quantization, // 量化类型如 ScalarKind.Float16 ulong dimensions, // 向量维度 ulong connectivity 0, // 图节点邻居数上限 ulong expansionAdd 0, // 建索引时的扩展系数 ulong expansionSearch 0,// 搜索时的扩展系数 bool multi false // 是否允许一键多向量 )参数对效果的影响依据 USearchIndex.cs 与 DBSearch.cs 的实现注释connectivity限制近邻图中每个节点的连接数expansionAdd控制添加向量时的检索范围越大召回越高、建索引越慢expansionSearch控制查询时的扩展范围越大搜索结果越接近精确、延迟越高multi允许同一键下挂多个向量。四、与 FAISS 的对比设计哲学与实测差异上游 README 中有一张详细的对比表双方都采用 HNSW 算法但设计取向截然不同——USearch 在保持性能的同时更紧凑、更易移植主打用户自定义度量和零依赖维度FAISSUSearch改进幅度1 亿个 96df32/f16/i8向量索引耗时2.6 / 2.6 / 2.6 h0.3 / 0.2 / 0.2 h9.6 / 10.4 / 10.7 x1 亿个 1536df32/f16/i8向量索引耗时5.0 / 4.1 / 3.8 h2.1 / 1.1 / 0.8 h2.3 / 3.6 / 4.4 x代码库规模84 K SLOC3 K SLOC更易维护支持的度量9 种固定度量任意度量可扩展支持的语言C、Python10 种语言可移植支持的 ID 类型32 位、64 位32 位、40 位、64 位更省空间必需依赖BLAS、OpenMP无更轻量绑定方式SWIG原生绑定更低延迟Python 绑定体积~10 MB1 MB更易部署上述索引耗时数据来自上游在 Intel Sapphire Rapids 上以最简单的内积距离测试的结果同等召回率与内存消耗同时搜索速度也大幅领先。基础用法两者几乎一致这就是熟悉 ANN 的人上手零成本的原因$ pip install numpy usearch import numpy as np from usearch.index import Index index Index(ndim3) vector np.array([0.2, 0.6, 0.4]) index.add(42, vector) matches index.search(vector, 10) assert matches[0].key 42 assert matches[0].distance 0.001 assert np.allclose(index[42], vector)五、序列化与从磁盘服务索引USearch 支持三种序列化形式写入文件以路径定义写入流用回调增量序列化或重建写入定长缓冲区 / 支持随机访问的内存映射文件。最后一种方式允许直接以只读view方式从外部内存服务索引从而把建索引与在线服务的机器成本分开优化README 中提到这在 AWS 等公有云上可带来约20 倍的成本削减。index.save(index.usearch) loaded_copy index.load(index.usearch) view Index.restore(index.usearch, viewTrue) other_view Index(ndim..., metric...) other_view.view(index.usearch)在 C# 端USearchIndex的(string path, bool view)构造函数正是对应这一能力viewtrue时走usearch_view内存映射、不载入 RAM否则走usearch_load完整载入。而在 LLMUnity RAG 场景中索引进一步被封装进 ZipArchive见 2.2 节随RAG.Save/Load一起持久化到.zip文件。六、精确搜索 vs 近似搜索近似搜索如 HNSW主要用于精确暴力搜索代价过高的场景——典型是集合内有数百万条记录时。对于小集合可直接用search方法做精确搜索from usearch.index import search, MetricKind, Matches, BatchMatches import numpy as np # 生成 10000 个 1024 维随机向量 vectors np.random.rand(10_000, 1024).astype(np.float32) vector np.random.rand(1024).astype(np.float32) one_in_many: Matches search(vectors, vector, 50, MetricKind.L2sq, exactTrue) many_in_many: BatchMatches search(vectors, vectors, 50, MetricKind.L2sq, exactTrue)传入exactTrue时系统完全跳过索引直接用 SimSIMD 优化的相似度度量对全量数据暴力搜索。README 引用的对比测试中FAISSIndexFlatL2耗时 55.3 ms而usearch.index.search仅 2.54 ms。需要说明的是这是上游文档给出的单一场景数据实际提升幅度取决于硬件与数据分布。七、多索引组合、聚类与 Join7.1 多索引并行查询面对十亿乃至万亿级向量时与其构建一个巨型索引不如构建多个小索引再统一查看from usearch.index import Indexes multi_index Indexes( indexes: Iterable[usearch.index.Index] [...], paths: Iterable[os.PathLike] [...], view: bool False, threads: int 0, ) multi_index.search(...)7.2 聚类与子聚类索引构建完成后USearch 本身就可以被看作一种聚类结构支持比 SciPy、UMap、tSNE 等独立聚类库更快的 KNN 聚类也支持迭代加深的子聚类clustering index.cluster( min_count10, # 可选 max_count15, # 可选 threads..., # 可选 ) # 获取聚类中心及规模 centroid_keys, sizes clustering.centroids_popularity # 用 Matplotlib 画直方图 clustering.plot_centroids_popularity() # 导出 NetworkX 图 g clustering.network # 获取某个簇的成员 first_members clustering.members_of(centroid_keys[0]) # 对簇继续细分支持同样的参数 sub_clustering clustering.subcluster(min_count..., max_count...)这种聚类与 K-Means 等传统方法结果并不完全相同但用途一致。README 提到在 5 万个聚类的规模上USearch 与传统聚类方法的性能差距可达 100 倍量级作为对比Scikit-Learn 处理 100 万点数据集的聚类查询可能需要数分钟到数小时。7.3 Join一对一、一对多、多对多映射与对每条记录逐一搜索不同join要求在一对一映射下禁止不同搜索结果之间的冲突是模糊匹配场景的基础。USearch 可实现次二次复杂度的近似、模糊与语义 Joinmen Index(...) women Index(...) pairs: dict men.join(women, max_proposals0, exactFalse)八、用户自定义度量大多数向量检索库只提供内积与欧氏距离USearch 则允许任何用户自定义度量从而覆盖从地理坐标的 Haversine 距离到由多个 AI 模型拼接出的复合 embedding 度量等场景。HNSW 不需要向量等长只要求可比较因此甚至可以拿 GZip 压缩比作为距离函数做模糊文本匹配。需要如实说明在本仓库的 C# 绑定中USearchTypes.cs的IndexOptions.metric字段默认置空自定义度量委托仍处于 TODO 状态该能力目前主要在 Python 等绑定中可用。九、内存效率、降精度与量化训练量化模型 降维是加速向量搜索的常见手段但这种方式并不总是可靠可能改变数据统计特性且分布漂移时需要频繁调整。USearch 的做法是对降精度后的向量做高精度算术。同一个索引的add与search操作会在f64、f32、f16、i8与单比特表示之间自动降/升精度。可用如下命令检查硬件加速是否启用$ python -c from usearch.index import Index; print(Index(ndim768, metriccos, dtypef16).hardware_acceleration) avx512f16 $ python -c from usearch.index import Index; print(Index(ndim166, metrictanimoto).hardware_acceleration) avx512popcnt使用更小的数值类型能省下存储向量的 RAM还可以压缩构成近邻图的邻居列表。默认用 32 位uint32_t枚举邻居无法支撑超过 40 亿条数据此时可用自定义uint40_t类型它仍比常见的 8 字节整数省 37.5% 空间且可扩展到 1 万亿条记录。十、跨语言功能矩阵上游 README 给出的功能覆盖情况核心功能在所有绑定中均已支持更宽泛的功能按需移植功能C 11Python 3C 99JavaJavaScriptRustGoLangSwift添加、搜索、删除✅✅✅✅✅✅✅✅保存、加载、查看✅✅✅✅✅✅✅✅用户自定义度量✅✅❌❌❌❌❌❌批量操作❌✅❌❌✅❌❌❌Join✅✅❌❌❌❌❌❌变长向量✅❌❌❌❌❌❌❌40 亿以上容量✅❌❌❌❌❌❌❌值得一提的是README 特别说明某些场景下功能对等没有意义——例如批量操作宿主语言本身具备完整的多线程能力而 USearch 索引结构天生并发安全因此用户完全可以在自己语言里实现最优的批处理/调度/负载均衡。十一、典型应用示例11.1 AI 多模态语义搜索用多模态编码器如 UForm Web 框架如 UCall USearch约 20 行 Python 即可搭出文搜图平台import ucall import uform import usearch import numpy as np import PIL as pil server ucall.Server() model uform.get_model(unum-cloud/uform-vl-multilingual) index usearch.index.Index(ndim256) server def add(key: int, photo: pil.Image.Image): image model.preprocess_image(photo) vector model.encode_image(image).detach().numpy() index.add(key, vector.flatten(), copyTrue) server def search(query: str) - np.ndarray: tokens model.preprocess_text(query) vector model.encode_text(tokens).detach().numpy() matches index.search(vector.flatten(), 3) return matches.keys server.run()11.2 RDKit 分子检索化学中常见的做法是把 SMILES 结构编码为二进制指纹再用 Tanimoto 等二值相似度度量检索from usearch.index import Index, MetricKind from rdkit import Chem from rdkit.Chem import AllChem import numpy as np molecules [Chem.MolFromSmiles(CCOC), Chem.MolFromSmiles(CCO)] encoder AllChem.GetRDKitFPGenerator() fingerprints np.vstack([encoder.GetFingerprint(x) for x in molecules]) fingerprints np.packbits(fingerprints, axis1) index Index(ndim2048, metricMetricKind.Tanimoto) keys np.arange(len(molecules)) index.add(keys, fingerprints) matches index.search(fingerprints, 10)11.3 GIS 地理检索iOS借助 Objective-C 与 Swift 绑定USearch 可轻松用于移动应用——把经纬度编码为二维向量用 Haversine 距离在移动地图上实时查找最近的兴趣点POI且易于扩展至高维向量。十二、在 Mate-Engine 的 LLMUnity RAG 中的实际集成这是本仓库最值得关注的部分上述引擎被封装为DBSearch与暴力检索的SimpleSearch并列为 LLMUnity RAG 的两种搜索方法。参见 RAG.cs 中的SearchMethods枚举定义public enum SearchMethods { DBSearch, // 基于 USearch 的 ANN 检索推荐 SimpleSearch, // 简单暴力检索 }12.1 DBSearch 如何驱动 USearchDBSearch.cs 继承自SearchMethod在Awake中通过InitIndex()创建索引其参数与 USearch 的IndexOptions一一对应[ModelAdvanced] public ScalarKind quantization ScalarKind.Float16; // 量化类型半精度 [ModelAdvanced] public MetricKind metricKind MetricKind.Cos; // 度量余弦相似度 [ModelAdvanced] public ulong connectivity 32; // 图节点邻居数上限 [ModelAdvanced] public ulong expansionAdd 40; // 建索引扩展系数 [ModelAdvanced] public ulong expansionSearch 16; // 搜索扩展系数 public void InitIndex() { index new USearchIndex(metricKind, quantization, (ulong)llmEmbedder.llm.embeddingLength, connectivity, expansionAdd, expansionSearch, false); }也就是说embedding 的维度直接取自 LLM embedder 的embeddingLength向量以Float16量化存储用余弦距离度量语义相似度——这些都是可在 Unity Inspector 中调节的模型高级选项。DBSearch通过以下抽象方法把SearchMethod的生命周期桥接到USearchIndexAddInternal(key, embedding)→index.Add((ulong)key, embedding)RemoveInternal(key)→index.Remove((ulong)key)SaveInternal(ZipArchive)/LoadInternal(ZipArchive)→index.Save/Load(archive)即 2.2 节的 ZipArchive 持久化ClearInternal()→index.Dispose()后重建索引。12.2 分组检索的底层实现DBSearch.IncrementalFetchKeys展示了带过滤的增量检索流程它先构造一个过滤委托把不属于目标 group 或已见过的键排除掉再调用带 filter 的搜索Funcint, int filter (int key) !dataSplit.Contains(key) || seenKeys.Contains(key) ? 0 : 1; index.Search(embedding, k, out ulong[] keys, out float[] distances, filter);这个委托最终会进入USearchIndex.Search在 AndroidIL2CPP上通过[MonoPInvokeCallback]的StaticFilter 锁转发到原生usearch_filtered_search其他平台则直接用 lambda。这与SimpleSearchSimpleSearch.cs先对组内所有 embedding 计算InverseDotProduct再排序的暴力方式形成鲜明对比数据量大时DBSearch的 ANN 检索显著更快。12.3 RAG 的完整链路从 RAG.cs 看RAG 组件由搜索方法 可选分块方法组成rag.Init(SearchMethods.DBSearch, ChunkingMethods.TokenSplitter, llm); rag.Add(phrase); // 文本 - embedding - 入库 (string[] similarPhrases, float[] distances) await rag.Search(query, k); rag.Save(ragPath); // 全部内容打包进 zip await rag.Load(ragPath);结合 Chunking.cs 可以看到启用分块时长文本先被Split成多个 chunk每个 chunk 作为独立条目加入DBSearch并通过sentenceToPhrase/phraseToSentences映射回原始短语ReturnChunks(true/false)决定搜索结果返回 chunk 还是整段原文。12.4 测试佐证仓库的 TestSearch.cs 对两套搜索方法做了完全对称的行为验证可从中观察 USearch 检索的预期行为TestDBSearch与TestSimpleSearch共用同一套用例TestSearchMethodT验证了Add/Remove/Clear、按 group 计数、Top-k 搜索结果与距离、增量检索的分批取回、以及Save/Load往返一致性测试使用固定的语义相近句子how is the weather today? 与 is it raining?并断言固定距离差weatherRainingDiff 0.2073563f说明Cos度量下的语义距离是可复现的TestRAG_DBSearch_*系列把 DBSearch 分别与NoChunking、TokenSplitter、SentenceSplitter组合验证了分块模式下返回 chunk 与返回原文两种行为的正确性。例如TestDBSearch会验证添加weather、raining、sometext三条后用weather查询 Top-2 时第一个结果必须是weather本身距离约 0第二个是raining距离 0.2073Save 后 Clear 再 Load计数与检索结果均保持一致。十三、已知边界与使用建议综合文档与源码有几个值得注意的边界需要如实说明自定义度量尚未在 C# 绑定中启用USearchTypes.cs留有实现自定义度量委托的 TODOIndexOptions.metric字段当前固定为默认值。若需要 Haversine、Tanimoto 等度量请使用已枚举的MetricKind批量添加在 C# 侧是循环实现USearchIndex.Add(keys[], vectors[][])逐条调用usearch_add并非原生批量接口大规模灌库时性能上不如 Python 绑定原生库按平台分发只有 Resources/usearch 下列出的 Windows、Linux、macOS、Android、iOS 五个平台有对应二进制其他平台需要自行编译libusearch_c过滤器在 Android 上串行化为绕开 IL2CPP 回调限制Android 平台的带过滤搜索使用了filterLock全局锁多线程并发搜索场景下会有锁竞争。十四、许可证与引用本模块以Apache-2.0协议分发完整文本见 Assets/LLMUnity/Runtime/RAG/usearch/LICENSE。若在论文或产品中引用 USearch可参考上游 README 提供的 BibTeX 条目其版本号为 2.8.16DOI 为 10.5281/zenodo.7949416software{Vardanian_USearch_2023, doi {10.5281/zenodo.7949416}, author {Vardanian, Ash}, title {{USearch by Unum Cloud}}, url {https://github.com/unum-cloud/usearch}, version {2.8.16}, year {2023}, month oct, }总结USearch 以单文件 HNSW 无依赖 多语言绑定的轻量设计成为向量相似度检索领域 FAISS 之外的高性价比选择。在 Mate-Engine 仓库中它经由 NativeMethods.cs 的原生互操作层、USearchIndex.cs 的托管包装含 ZipArchive 持久化与过滤搜索扩展被完整移植进 Unity并通过 DBSearch.cs 接入 LLMUnity RAG为桌面伴侣应用提供先向量检索、再生成回答的语义问答能力。理解这套引擎的参数体系度量、量化、connectivity、expansion与序列化机制是在本项目里打造高效、可持久化语义搜索系统的关键。赞分享桌面应用数字人AI 应用【免费下载链接】Mate-EngineA free Desktop Mate alternative with a lightweight interface and custom VRM support, though with more features.项目地址https://gitcode.com/gh_mirrors/ma/Mate-Engine点击查看免费下载相关推荐NetHack环境互动指南喷泉、祭坛与其他特殊地形NetHack环境互动指南喷泉、祭坛与其他特殊地形 NetHack作为一款经典的 Roguelike 游戏其丰富的地形互动系统是游戏深度的重要体现。玩家在探游戏开发Dokploy 安全政策与漏洞披露指南从负责任报告流程到源码级安全实践Dokploy 安全政策与漏洞披露指南从负责任报告流程到源码级安全实践 Dokploy 是一个免费、可自托管的开源 PaaS 平台Open Source A后端前端云原生DevOps容器编排运维终极指南Weaviate向量数据库核心索引算法HNSW原理与优化策略终极指南Weaviate向量数据库核心索引算法HNSW原理与优化策略 Weaviate是一款开源向量数据库它既能存储对象数据也能存储向量数据通过将向量搜索向量数据库数据库后端RAG人工智能语义搜索上一篇New API 大模型网关部署与多协议转换实战Docker 快速上手、环境变量与网关架构解析下一篇First Contributions 项目实战Git 用户身份与配置作用域完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考