人工智能大模型Agent 记忆AI AgentRAG知识图谱dsh-plugin【免费下载链接】MemOSSelf-evolving memory OS for LLM AI Agents: ultra-persistent memory, hybrid-retrieval, and cross-task skill reuse, with 35.24% token savings and DeepSeek Harness support.项目地址https://gitcode.com/gh_mirrors/memos/MemOS点击查看免费下载导读apps/memos-local-plugin/core/embedding/是 MemOS 本地插件memos-local-plugin中唯一与 Embedding Provider 打交道的模块它把「local / OpenAI 兼容 / Gemini / Cohere / Voyage / Mistral」六类向量服务统一收敛为一个Embedder门面屏蔽了角色语义、批量请求、重试退避、维度规整与归一化等全部细节为上层检索提供「把文本变成可用于余弦相似度的向量」的唯一入口。读完本文你将掌握该层的完整数据流、六类 Provider 的接入方式与参数差异、缓存与错误处理的设计取舍以及如何用配置文件把 MemOS 指向任一家向量服务。1. 模块定位为什么需要一层 Embedding 门面core/embedding的设计目标可以用一句话概括README 原文Give me a vector for this text, in a way that makes cosine similarity reflect semantic similarity.答案是「取决于 Provider」——不同供应商的接口、鉴权方式、维度、角色语义各不相同。因此该模块做了两条硬性约束单点出口core/中任何需要向量的地方都必须经过Embedder门面Provider 实现不导出到本目录之外见 types.ts 顶部注释。门面的公共入口集中在 index.ts导出createEmbedder、createEmbedderWithProvider、makeProviderFor及全部类型与工具函数。Provider 只做一件事每个 Provider 实现同一个EmbeddingProvider接口nameembed(texts, role, ctx)只管发起 HTTP / 本地推理调用并返回原始number[][]批处理、缓存、重试、维度校验与 L2 归一化全部由门面统一完成见 embedder.ts 中EmbeddingProvider接口注释。这样上层retrieval / capture永远只面对一个稳定的门面换模型、换厂商都不需要改业务代码。1.1 最小使用示例import { createEmbedder, type EmbeddingConfig } from ./core/embedding; const embedder createEmbedder(cfg.embedding); const vec await embedder.embedOne(hello world); const vecs await embedder.embedMany([ { text: user asked X, role: document }, { text: user asked X, role: query }, ]);embedOne接收字符串或{ text, role }返回一个Float32ArrayembedMany返回按输入顺序排列的Float32Array[]内部自动去重同一文本重复 N 次只产生一次 Provider 往返返回向量的长度严格等于config.embedding.dimensions配置为 0 时按 Provider 原生维度自动推断见 normalize.ts 的postProcess。embedOne在实现上就是对embedMany的薄封装embedder.ts 第 105-111 行所以下文以embedMany的数据流为准。2. 六类 Provider 一览Provider 名称底层服务维度 / 模型默认值角色语义localhuggingface/transformers运行Xenova/all-MiniLM-L6-v2384 维首次调用下载约 23 MB 模型int8 量化 CPU 推理不区分角色openai_compatiblePOST endpoint/embeddings兼容 OpenAI 原生、Azure、智谱、硅基流动、百炼、Groq 等默认模型text-embedding-3-small默认端点https://api.openai.com/v1/embeddings不区分角色geminigenerativelanguage.googleapis.com/v1beta/models/model:batchEmbedContents默认模型text-embedding-004768 维区分RETRIEVAL_DOCUMENT/RETRIEVAL_QUERYcohereapi.cohere.ai/v1/embed默认模型embed-english-v3.0通过input_type区分search_document/search_queryvoyageapi.voyageai.com/v1/embeddings—区分 document / query 角色mistralapi.mistral.ai/v1/embeddingsOpenAI 兼容的请求/响应形状不区分角色openai_compatible的请求体为{ input: string[], model }响应为{ data: [{ embedding: number[] }] }endpoint未指定时默认指向 OpenAI 官方地址也可通过endpoint指向 Azure 等任何兼容实现openai.ts。gemini默认在 URL 上以?keyAPI_KEY携带密钥gemini.ts这一点在「注意事项」一节还会强调日志脱敏问题。所有云端 Provider 都要求配置apiKey缺失时直接抛出MemosError(codeembedding_unavailable)不会静默回退。3. 核心数据流从输入到可存库的向量README 给出了门面内部的完整流水线结合 embedder.ts 的实现可还原为inputs ─▶ normalize(input list → role-tagged {text}) │ ▼ sha256(provider|model|role|text) → cache lookup (LRU) │ ├── hit ──────────────────────────┐ ▼ └── miss → batched by role │ batch k texts ──▶ provider.embed() │ │ │ │ ▼ ▼ ▼ dim-enforce L2-normalize (Float32Array) ──────▶ interleave in input order │ └── cache.set(key, vec)具体步骤拆解输入规整每个入参统一为{ text, role }纯字符串默认role: documenttoInput函数embedder.ts 第 79-82 行。缓存查找以sha256(provider|model|role|text)的 64 位十六进制串为键查 LRU 缓存。批处理未命中的输入先按role分组再以batchSize默认 32切块逐块调用provider.embed()。后处理postProcess完成维度规整、Float32Array化、L2 归一化默认开启。回填按原输入下标回填结果并写入缓存保证embedMany的输出顺序与输入顺序严格一致。3.1 批处理BatchingbatchSize默认 32决定每次 HTTP 调用携带的文本条数。关键点在于先按 role 分组、再切批一个混合了query与document的列表会产出两组各自角色正确的往返请求而不是一次角色模糊的请求README 2.1 节。对 Cohere / Gemini / Voyage 这类「查询与文档使用不同input_type/taskType」的服务这一步直接决定了向量质量。3.2 维度规整与归一化NormalizationProvider 返回的是其原生维度的浮点数组门面会强制对齐配置声明的dimensionsnormalize.ts 的enforceDim维度相等 → 直接通过维度更大 →截断。这是把 1536 维模型接入 384 维存量库的旋钮无需重塑 SQLite 表维度更小 →直接抛错EMBEDDING_UNAVAILABLE。静默零填充会污染下游余弦相似度因此宁可失败也不伪装。随后向量被转为Float32Array并做 L2 归一化除非config.normalizefalse。「归一化一次」的设计收益在于查询时无需重复归一化余弦相似度在已存 blob 上退化为点积配合 vector.ts 中预存的平方 L2 范数norm2每次检索能省一次 sqrt 与一次全向量扫描。补充说明localProvider 在推理时已通过{ pooling: mean, normalize: true }完成均值池化与归一化local.ts 第 115-116 行不会再叠加归一化。3.3 角色语义Role部分服务对「被检索的内容」与「检索词」分别建模。门面用EmbedRole统一暴露这一语义rolelocalopenaigeminicoherevoyagemistraldocumentn/an/aRETRIEVAL_DOCUMENTsearch_documentdocumentn/aqueryn/an/aRETRIEVAL_QUERYsearch_queryqueryn/a调用约定嵌入用户的搜索文本时传role: query嵌入入库内容时传role: document或省略默认为 document。4. 配置项全解EmbeddingConfig的完整字段定义在 types.ts以下是全部可配置项及其默认值字段类型默认值说明providerlocal \| openai_compatible \| gemini \| cohere \| voyage \| mistral—必填选择 Providerendpointstring各 Provider 官方地址自定义端点如 Azure、自建反向代理modelstring各 Provider 默认模型模型标识如bge-m3dimensionsnumber—期望输出维度 0表示按 Provider 原生维度自动推断apiKeystring—云端 Provider 必填providerIgnorestring[]—OpenRouter 路由跳过指定 ProviderproviderOrderstring[]—OpenRouter 路由首选顺序openRouterbooleanfalse是否为 OpenRouter 反向代理 / CNAME 显式启用路由字段cache.enabledbooleantrue是否启用内存 LRU 缓存cache.maxItemsnumber20000缓存条目上限timeoutMsnumber30000单次 HTTP 调用超时maxRetriesnumber2瞬时错误5xx / 429 / 网络最大重试次数batchSizenumber32每次 HTTP 往返的最大文本数headersRecordstring, string—追加到出站 HTTP 请求的额外头normalizebooleantrue是否对所有输出向量做 L2 归一化onError函数—终端失败时的错误回调用于写入system_error日志行onStatus函数—成功/失败的状态回调供 Overview 模型卡片消费实际部署时provider与apiKey两项已在插件模板配置中暴露config.openclaw.yaml 第 20-22 行embedding: provider: local # local | openai_compatible | gemini | cohere | voyage | mistral apiKey: # required for cloud providers切换到云端服务只需把provider改为目标厂商并填入apiKey其余高级字段model、batchSize、timeoutMs、normalize等按需在配置中追加。更完整的进阶参数说明见 CONFIG-ADVANCED.md。4.1 两个容易被忽略的配置回调onError仅在 Provider终端失败重试耗尽时触发一次用于把system_error写入api_logs让 Logs 查看器能展示基础设施故障回调内部异常会被吞掉绝不会掩盖原始错误embedder.ts 第 229-243 行。onStatus成功与失败都会调用是 Overview 模型卡片的机器可读数据源EmbedStatusDetail携带durationMs、retryDecision、retryReason等诊断字段types.ts 第 77-87 行。5. 缓存设计为什么只用内存 LRU默认缓存为进程内 LRUmaxItems 20000。按 384 维 ×Float32Array估算约 20 MB 内存代价极低README 第 3 节。实现位于 cache.ts缓存键由node:crypto的sha256对provider|model|role|text取 64 位十六进制摘要makeCacheKeyLruEmbedCache用Map插入有序 命中即「删除再重插」实现 LRU 提升set时超出maxItems逐出最旧条目并计数evictions关闭缓存cache.enabled: false时自动换入NullEmbedCache调用方代码零改动——门面内部只依赖EmbedCache接口。README 明确解释了「不落盘」的三点理由重启后重新嵌入对local免费、对云端只是几分钱把文本 blob无论是否哈希持久化到磁盘会模糊「机密文本只存在于 SQLite blob」的安全边界core/storage/repos/*中的仓库在向量入库后已自行缓存向量——检索期命中由 SQLite 本身服务比在嵌入层再做第二层缓存更优。另外两个与缓存相关的实现细节值得一提请求内去重同一次embedMany里重复出现的文本只有第一次会真正 miss后续出现都复用同一趟往返的结果embedder.ts 第 148-158 行。关闭缓存同时关闭去重cache.enabled: false时每个输入会拿到独立 key追加#i后缀这是为了保留「关闭缓存做基准测试」的场景第 122-134 行。6. 容错与错误处理6.1 重试与退避所有 HTTP 调用统一走 fetcher.ts 的httpPostJson它负责超时单次调用AbortSignal.timeout(timeoutMs)默认 30s并与调用方传入的AbortSignal合并瞬时错误重试HTTP 5xx / 429 / 网络错误timeout、ETIMEDOUT、ECONNRESET、EAI_AGAIN、socket hang up 等按指数退避重试最多maxRetries默认 2次Retry-After 尊重429 / 503 响应头携带Retry-After时会解析并记录冷却recordRetryCooldown冷却期内对同一 provider/url/模型的作用域直接跳过调用绝对截止时间deadlineAt是跨重试共用的端到端 deadline退避计划若无法在截止前完成则放弃retryDecision: defer4xx 不重试非瞬时错误如 400直接抛出不浪费重试预算。上述行为在 fetcher.test.ts 中有系统覆盖包括「按 HTTP-date 格式的 Retry-After 等待后重试 429」「冷却期命中」「deadline 不足则 defer」「400 不重试」等用例。6.2 错误语义不自动回退所有不可恢复的失败统一冒泡为MemosError(codeembedding_unavailable)details携带{ provider, url, … }门面不会在云端 Provider 失败时自动回退到localembedder.ts 顶部注释明确说明——这是有意为之上层retrieval / capture可以自行决定用本地嵌入器重试但本层保持错误语义清晰便于测试与排障失败后lastError记录时间戳与消息且不会被随后的成功清除——Viewer 通过比较lastError.at与lastOkAt决定 Overview 卡片显示绿色还是红色避免「一次缓存友好的成功」掩盖仍真实存在的 Provider 故障types.ts 第 156-163 行。6.3 失败重试队列除了同步重试模块还提供createEmbeddingRetryWorkerretry-worker.ts基于embedding_retry_queue仓库的异步重试机制失败任务落库后由 worker 领取claim、续租touchClaimHeld、重放单元测试 retry-queue.test.ts 与 retry-worker.test.ts 覆盖了领取、失败重试与系统错误事件上报systemErrorEvent等场景。这为「同步退避耗尽但值得稍后重试」的批量嵌入任务提供了兜底通道。7. 日志通道门面按通道名细分日志方便按 provider 维度过滤embedding— 门面初始化与统计init时打印 provider / model / dimensions / cacheEnabled / batchSizeembedding.cache— 缓存写入 / 清除 / 命中embedding.local— HF pipeline 加载与逐调用 traceembedding.openai_compatible/embedding.gemini/embedding.cohere/embedding.voyage/embedding.mistral— 各自 HTTP 尝试 / 时长 / 状态。每行日志都会携带{ traceId, sessionId, ... }等上下文字段由 core/logger/context.ts 的上下文传播器注入可与链路追踪对接。8. 测试体系单元测试集中在tests/unit/embedding/与 README 第 6 节一一对应normalize.test.ts — 维度规整、L2、Float32 转换cache.test.ts — LRU 逐出、命中/未命中计数、Null 缓存行为对齐fetcher.test.ts — 5xx/429 重试、超时、错误映射providers.test.ts — 每个 Provider 用 fakefetch挂载一次往返覆盖鉴权、角色翻译、响应解析与错误面local.test.ts 与 local-abort.test.ts — 惰性加载单例不变量、请求中止时的响应行为不真实下载模型embedder.test.ts — 门面端到端缓存命中路径、混合角色、batchSize 分块、重复去重、统计计数、维度规整retry-queue.test.ts / retry-worker.test.ts — 异步重试队列与 worker。providers.test.ts用「每个测试挂载一个 fakefetch」的方式把各 Provider 的鉴权头、请求体、角色翻译与响应解析都固化成了可回归的行为契约。9. 注意事项与已知边界local首次调用会下载模型到 huggingface 缓存目录约 23 MB。真正触发local推理的测试必须显式开启env-gated且不占用单元测试预算LocalEmbeddingProvider通过模块级extractorPromise惰性加载、进程内共享单例local.ts。gemini的?keyAPI_KEY把密钥放进 URL。fetcher.ts依赖 logger 的脱敏管道在日志中抹掉查询串不要在别处打印原始 URL。voyage与cohere按 token 计费。调大batchSize虽能摊薄 HTTP 开销但会快速逼近 TPM 上限需权衡。更改dimensions会破坏存量余弦比较。向量已写入 SQLite 后再改配置中的dimensions新老行之间无法做余弦比对。README 的建议是优先整体升级模型并在下一轮通过resetCache() recomputeOnDemand重新嵌入——该重算路径属于 Phase 9当前尚未实现属于已知边界。查询侧预归一化由于写入侧已做 L2 归一化检索侧直接以点积代替余弦即可见 vector.ts 的dot/cosine/norm2实现这也是「归一化一次」设计的直接收益点。10. 小结core/embedding是一个教科书式的「门面 策略」分层六个 Provider 各自只负责协议翻译而批处理、缓存、重试、维度规整、归一化、统计与错误语义全部收敛到Embedder统一实现。对使用者而言切换嵌入服务只需改embedding.provider与embedding.apiKey两个配置项对二次开发者而言EmbeddingProvider接口types.ts就是扩展新厂商的唯一契约——实现embed()并把它注册进makeProviderForembedder.ts 第 349-370 行即可。想要进一步了解向量如何落库与检索可直接阅读 vector.ts 与 core/storage 目录。赞分享人工智能大模型Agent 记忆AI AgentRAG知识图谱dsh-plugin【免费下载链接】MemOSSelf-evolving memory OS for LLM AI Agents: ultra-persistent memory, hybrid-retrieval, and cross-task skill reuse, with 35.24% token savings and DeepSeek Harness support.项目地址https://gitcode.com/gh_mirrors/memos/MemOS点击查看免费下载相关推荐MemOS 本地插件 LLM 层深度解析LlmClient 门面、多 Provider 路由与容错设计MemOS 本地插件 LLM 层深度解析LlmClient 门面、多 Provider 路由与容错设计 导读 core/llm/ 是 MemOS 本地插件人工智能大模型Agent 记忆AI AgentRAG知识图谱dsh-pluginMemOS 本地插件 core/pipeline 深度解析算法编排器与 MemoryCore 门面层的架构设计MemOS 本地插件 core/pipeline 深度解析算法编排器与 MemoryCore 门面层的架构设计 导读 apps/memos local plu人工智能大模型Agent 记忆AI AgentRAG知识图谱dsh-pluginMemOS 本地插件 JSON-RPC Bridge 深度解析非 TypeScript 适配器的统一接入层MemOS 本地插件 JSON RPC Bridge 深度解析非 TypeScript 适配器的统一接入层 导读 MemOS 本地插件 apps/memos人工智能大模型Agent 记忆AI AgentRAG知识图谱dsh-plugin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?