* feat(docs): mirror every docs/ page in all 65 locales Extends the documentation mirrors from the 22-page core set (#13940) to every Markdown page under docs/: 152 sources x 65 locales = 9,880 mirrors (6,208 new), language bars rewritten for the full locale list, state adopted so the blocking drift gate now covers all 152 pages. run-translation.mjs: an oversized block made only of table rows or list items (PROVIDER_REFERENCE.md 244-row table, FREE_TIERS.md 71-item list) is cut at item boundaries and rejoined without a blank line — the single 16-40 KB request outlived the backend socket for verbose scripts. 48 older mirrors whose tables had lost rows were retranslated with --force. * docs(i18n): refresh mirrors for the sources the base changed since the branch cut Section-level retranslation of the 29 docs (and README.md) whose source or mirrors moved on release/v3.8.51 during the run, then state adoption; the drift gate is green again on the merged tree.
72 KiB
Memory System (Čeština)
🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW
Zdroj pravdy:
src/lib/memory/asrc/app/api/memory/Naposledy aktualizováno: 2026-06-28 — v3.8.40 (ve výchozím nastavení vypnuto + doplnění kvantizace int8)
OmniRoute poskytuje trvalou konverzační paměť vázanou na klíč API (a volitelně na ID relace). Vzpomínky se automaticky extrahují z odpovědí LLM pomocí jednoduchého porovnávání regulárních výrazů a znovu se vkládají do následujících požadavků jako úvodní systémová zpráva (nebo první uživatelská zpráva u poskytovatelů, kteří odmítají systémovou roli).
Paměť je ve výchozím nastavení VYPNUTÁ (v3.8.30+).
DEFAULT_MEMORY_SETTINGS.enabledmá nyní hodnotufalse(src/lib/memory/settings.ts). Povolení paměti vloží do každého chatovacího požadavku ažmaxTokens(~2k) načteného kontextu, který je zpoplatněn — což může být neočekávaný náklad pro nové instalace a klienty, kteří spravují vlastní kontext. Výslovně ji zapněte v části Nastavení → Paměť (když je paměť povolena,MemorySkillsTabzobrazuje upozornění na náklady za tokeny). Klient může paměť pro jednotlivý požadavek vypnout pomocí hlavičky požadavkux-omniroute-no-memory(true/1/yes) — viz tabulka hlaviček požadavků v API_REFERENCE.md. Požadavek bez paměti nastavímemoryOwnerId = null, čímž se pro daný požadavek zakáže jak vkládání paměti, tak dovedností (open-sse/handlers/chatCore/headers.ts::isNoMemoryRequested).
Paměť je omezena na jednotlivé klíče API, nikoli na jednotlivé uživatele —
každý požadavek ověřený stejným klíčem API sdílí stejný fond paměti s možností
dalšího omezení pomocí sessionId.
Architektura
Klient → /v1/chat/completions (apiKeyInfo vyřešeno dříve)
→ handleChatCore() [open-sse/handlers/chatCore.ts]
→ resolveMemoryOwnerId(apiKeyInfo) # extrahuje ID
→ getMemorySettings() # nastavení uložené v mezipaměti
→ shouldInjectMemory(body, {enabled}) # kontrolní brána
→ retrieveMemories(apiKeyId, config) # SQL + FTS5 + volitelně vektor
→ injectMemory(body, memories, provider) # systémová nebo uživatelská zpráva
→ volání externího poskytovatele
→ při odpovědi: extractFacts(text, apiKeyId, sessionId) # neblokující
→ setImmediate → createMemory(fact) pro každou shodu
→ embed(content) + upsertVector(id, vec)
Místa volání pro vkládání a extrakci jsou zapojena v
open-sse/handlers/chatCore.ts (hledejte retrieveMemories, injectMemory
a extractFacts).
Architektura enginu (tříúrovňové rozlišení)
Memory Engine určuje cestu načítání za běhu na základě dostupné infrastruktury a nastavení. Existují tři úrovně, které se používají v pořadí podle priority:
┌─────────────────────────────────────────────────────────────┐
│ ÚROVEŇ 0 — Klíčová slova (FTS5) │
│ Dostupnost určená testem: FTS5, pokud ji sestavení SQLite │
│ podporuje (better-sqlite3 / node:sqlite / bun:sqlite); │
│ nedostupné v sestaveních bez FTS5 (např. sql.js/WASM — │
│ "no such module: fts5"). Používá se, když strategy = │
│ "exact", nebo jako záložní řešení; položka keyword ve │
│ stavu enginu odráží výsledek testu. │
└──────────────────────────────────┬──────────────────────────┘
│ strategy = semantic|hybrid?
▼
┌─────────────────────────────────────────────────────────────┐
│ ÚROVEŇ 1 — Vestavěné vektory (sqlite-vec) │
│ sqlite-vec v0.1.9 načtené přes db.loadExtension(). │
│ KNN hrubou silou nad vektory Float32. Aktivní, když: │
│ • načtení sqlite-vec přes loadExtension proběhne úspěšně │
│ • Je dostupný zdroj embeddingů (remote | static | │
│ transformers), který dokáže vytvořit Float32Array │
│ • existuje tabulka vec_memories (vytvořená při prvním │
│ volání ready()) │
└──────────────────────────────────┬──────────────────────────┘
│ qdrant.enabled?
▼
┌─────────────────────────────────────────────────────────────┐
│ ÚROVEŇ 2 — Qdrant (volitelná externí vektorová databáze) │
│ Je-li povolena, nahrazuje sqlite-vec pro semantic/hybrid. │
│ Vyžaduje běžící instanci Qdrant + nakonfigurovaný host/port.│
└─────────────────────────────────────────────────────────────┘
Degradace probíhá automaticky a transparentně:
- Pokud se sqlite-vec nepodaří načíst, úroveň 1 není dostupná → použije se úroveň 0.
- Pokud zdroj embeddingů vrátí chybu, úroveň 1 přejde na úroveň 0.
- Pokud Qdrant není v pořádku, úroveň 2 přejde na úroveň 1 (nebo na úroveň 0, pokud není dostupná ani úroveň 1).
Zdroje embeddingů
Vrstva embeddingů (src/lib/memory/embedding/) určuje, který zdroj použít,
na základě MemorySettingsExtended.embeddingSource:
| Zdroj | Popis | Vyžaduje klíč | Studený start |
|---|---|---|---|
remote |
Používá embeddingové API nakonfigurovaného poskytovatele (OpenAI, Cohere atd.) | Ano | Žádný |
static |
Lokální embedding pomocí vyhledávací tabulky potion-base-8M (WordPiece + průměrování) |
Ne | ~200ms |
transformers |
Lokální inference ONNX prostřednictvím @huggingface/transformers v4, all-MiniLM-L6-v2 |
Ne | ~3s + ~400MB RAM |
auto |
Určení za běhu: remote (pokud existuje klíč) → static → transformers → null | Závisí | Závisí |
Pořadí vyhodnocování pro auto:
- Najde prvního poskytovatele v
listEmbeddingProviders()shasKey === true→remote. - Pokud
settings.staticEnabled === true→static. - Pokud
settings.transformersEnabled === true→transformers. - Jinak →
null(degraduje na vyhledávání klíčových slov pomocí FTS5).
Mezipaměť embeddingů (src/lib/memory/embedding/cache.ts) používá mapu LRU v paměti
s klíčem ${source}:${model}:${dim}:${sha256(text)}, omezenou na
MEMORY_EMBEDDING_CACHE_MAX položek (výchozí hodnota 1000) s dobou platnosti
MEMORY_EMBEDDING_CACHE_TTL_MS (výchozí hodnota 5 min). Je sdílena všemi volajícími
po dobu životního cyklu procesu.
Hybridní RRF (k=60)
Když platí strategy = "hybrid" a vektorové úložiště je dostupné, načítání používá
Reciprocal Rank Fusion ke sloučení výsledků FTS5 a vektorového vyhledávání:
RRF(d) = Σ 1 / (k + rank_i(d)) kde k = 60 (lze konfigurovat pomocí MEMORY_RRF_K)
i
Konkrétně:
- Spustí vyhledávání FTS5 → seřazený seznam
R_fts(pozice 1..N). - Spustí vektorové vyhledávání KNN → seřazený seznam
R_vec(pozice 1..M). - Pro každé jedinečné
memoryId:
rrf_score = 1/(60 + fts_rank)+1/(60 + vec_rank)(0, pokud v seznamu není). - Seřadí podle
rrf_scoresestupně a provede průchod s tokenovým rozpočtem.
Je obecně známo, že RRF funguje efektivně bez nutnosti normalizace skóre napříč
heterogenními vyhledávacími systémy. Výchozí hodnota k=60 pochází z původního
článku Cormacka a kol. a funguje dobře pro malé korpusy (<10k paměťových záznamů).
Zpětné doplnění (líné + reindexace)
Když se změní model embeddingů (detekováno prostřednictvím embedding_signature),
vektorové úložiště se znovu sestaví a všechny existující paměťové záznamy se v tabulce
memories označí pomocí needs_reindex = 1.
Líné zpětné doplnění: Při následujícím načítání se pro každý paměťový záznam,
kterému chybí vektorová položka, vytvoří embedding a vloží se do vec_memories
ještě před spuštěním vyhledávání. Tím se náklady na zpětné doplnění rozloží mezi
skutečné požadavky, aniž by se blokovalo spuštění.
Explicitní reindexace: Karta Engine v /dashboard/memory nabízí tlačítko
„Reindexovat nyní“, které volá POST /api/memory/reindex. Obslužná rutina volá
runReindexBatch() ze souboru src/lib/memory/reindex.ts, který při každém požadavku
zpracuje až limit čekajících položek. Průběh lze pravidelně zjišťovat prostřednictvím
GET /api/memory/engine-status (vectorStore.needsReindex).
Tabulka memory_vec_meta (migrace 083_memory_vec.sql) ukládá:
active_dim— aktuální rozměr vektoru (null = dosud nezkalibrováno).embedding_signature—${source}:${model}:${dim}používaný k detekci změn.last_reset_at— časové razítko posledního úplného resetování.vec_loaded— příznak 0/1 určující, zda se sqlite-vec úspěšně načetl.
Rozšíření nastavení
V MemorySettingsExtended v souboru src/shared/schemas/memory.ts je k dispozici devět polí pro embeddingy a vektory, která jsou ukládána prostřednictvím src/lib/db/settings.ts:
| Pole | Typ | Výchozí | Popis |
|---|---|---|---|
embeddingSource |
"remote" | "static" | "transformers" | "auto" |
"auto" |
Který zdroj embeddingů se má použít |
embeddingProviderModel |
string | null |
null |
Poskytovatel/model ve formátu provider/model |
customBaseUrl |
string | null |
null |
Základní URL endpointu kompatibilního s OpenAI pouze pro Memory |
customModelId |
string | null |
null |
ID modelu odesílané vlastnímu endpointu |
transformersEnabled |
boolean |
false |
Výslovné povolení Transformers.js (MiniLM, ~400MB) |
staticEnabled |
boolean |
false |
Výslovné povolení lokálního statického modelu potion-base-8M |
rerankEnabled |
boolean |
false |
Povolení kroku přerazení (přidá +200–500 ms/požadavek) |
rerankProviderModel |
string | null |
null |
Poskytovatel/model přerazení ve formátu provider/model |
vectorStore |
"sqlite-vec" | "qdrant" | "auto" |
"auto" |
Které vektorové úložiště se má použít |
Tato pole jsou dostupná prostřednictvím GET /PUT /api/settings/memory (schéma MemorySettingsExtendedSchema).
Pro zdroj remote přijímá Memory také volitelná nastavení customBaseUrl a
customModelId. Společně vybírají endpoint /embeddings kompatibilní s OpenAI
a model, aniž by měnily globální registr embeddingů. Endpoint je před použitím
normalizován a kontrolován zásadami poskytovatele pro odchozí URL: je vyžadován
protokol HTTP(S), vložené přihlašovací údaje a řetězce dotazu jsou odmítnuty
a adresy cloudových metadat zůstávají blokované. Prázdné hodnoty zachovají
vybraného poskytovatele z registru. Chyby vrácené do řídicího panelu jsou
sanitizovány a přihlašovací údaje endpointu se nikdy nezaznamenávají do protokolu.
TODO (D20): Rozsah
global(sdílení pamětí napříč všemi klíči API) není v této verzi implementován. Vyžaduje změny schématu a globální cestu načítání. Sledujte jej samostatně.
Vrstvy úložiště
Primární: SQLite (tabulka memories)
Vytvořeno migrací 015_create_memories.sql:
| Sloupec | Typ | Poznámky |
|---|---|---|
id |
TEXT PRIMARY KEY |
UUID generované prostřednictvím crypto.randomUUID() |
api_key_id |
TEXT NOT NULL |
Vlastnický klíč API |
session_id |
TEXT |
Volitelný rozsah pro jednotlivé konverzace |
type |
TEXT NOT NULL |
Jedna z hodnot factual, episodic, procedural, semantic |
key |
TEXT |
Stabilní klíč pro upsert, např. preference:i_prefer_python |
content |
TEXT NOT NULL |
Vlastní text skutečnosti |
metadata |
TEXT |
Datový blok JSON (category, extractedAt, source, ...) |
created_at / updated_at |
TEXT |
Řetězce ISO 8601 |
expires_at |
TEXT |
Volitelné vypršení platnosti; NULL znamená trvalou platnost |
memory_id |
INTEGER UNIQUE |
Přidáno migrací 023_fix_memory_fts_uuid.sql pro propojení UUID ↔ rowid FTS5 |
Indexy: api_key_id, session_id, type, expires_at a jedinečný index
memory_id.
Sémantika upsertu: createMemory() vyhledá existující řádek se stejnou
dvojicí (api_key_id, key) a v případě nalezení jej aktualizuje na místě
(sloučí metadata pomocí mělkého spreadu). Tím se zabrání neomezenému růstu
tabulky při opakovaných vyjádřeních preferencí.
Fulltextové vyhledávání (virtuální tabulka memory_fts)
Migrace 022_add_memory_fts5.sql vytvoří virtuální tabulku FTS5 nad poli content
a key. Migrace 023_fix_memory_fts_uuid.sql opravuje chybu z reálného provozu,
kdy primární klíč UUID nebylo možné propojit s celočíselným rowid systému FTS5 —
migrace přidá sloupec memory_id, znovu vytvoří tabulku FTS a nastaví triggery
(memory_fts_ai, memory_fts_ad, memory_fts_au), které udržují FTS
synchronizované při operacích INSERT, DELETE a UPDATE.
Používáno souborem retrieval.ts pro strategie semantic a hybrid (viz níže).
Kód načítání provádí kontrolu pomocí hasTable("memory_fts") a přejde na
chronologické řazení, pokud tabulka FTS chybí nebo dotaz FTS vyvolá chybu.
Volitelné: Qdrant (vektorové úložiště 2. úrovně)
Soubor src/lib/memory/qdrant.ts implementuje volitelnou integraci Qdrant jako
vektorové úložiště 2. úrovně. Načítání je směrováno do Qdrant pouze tehdy, když
má selektor enginu memoryVectorStore hodnotu "qdrant" — výchozí hodnota
"auto" (ani "sqlite-vec") Qdrant nikdy nevybere. Přepínač na kartě
Engine nastavuje současně obě hodnoty qdrantEnabled a memoryVectorStore:
povolení nastaví Qdrant jako primární úložiště, zakázání obnoví hodnotu "auto"
(#5597 — před touto opravou nemělo povolení žádný účinek, protože selektor
enginu nebyl nikde nastavován). Pokud Qdrant není dostupný nebo nic nevrátí,
načítání přejde na sqlite-vec → FTS5.
upsertSemanticMemoryPoint()— vytvoří embedding prokey + contentpomocí nakonfigurovaného embeddingového modelu, zajistí existenci kolekce (při prvním použití vytvoří vektory s kosinovou vzdáleností) a vloží nebo aktualizuje bod s payloadem{memoryId, apiKeyId, sessionId, key, content, metadata, createdAtUnix, expiresAtUnix}.searchSemanticMemory(query, topK, scope)— vytvoří embedding dotazu a prohledá kolekci filtrovanou podlekind = "omniroute_memory"a volitelně podleapiKeyId/sessionId. OmezujetopKna rozsah[1, 20].deleteSemanticMemoryPoint(id)— odstraní jeden bod. Volá se zdeleteMemory()po odstranění řádku SQLite (D15).cleanupSemanticMemoryPoints({retentionDays})— hromadně odstraní body, jejichžexpiresAtUnixje v minulosti nebo jejichžcreatedAtUnixje starší než mez doby uchovávání. Nejprve je spočítá, aby řídicí panel mohl zobrazit skutečné počty.checkQdrantHealth()— kontrola stavu pomocíGET /readyzvčetně latence.
Uživatelské rozhraní nastavení zpřístupňuje konfiguraci Qdrantu, kontrolu stavu, test
sémantického vyhledávání a čištění na kartě Engine stránky /dashboard/memory.
Od verze v3.8.6 jsou zapojeny všechny odpovídající trasy v src/app/api/settings/qdrant/:
| Trasa | Metoda | Popis |
|---|---|---|
/api/settings/qdrant |
GET / PUT |
Načtení / aktualizace nastavení Qdrantu |
/api/settings/qdrant/health |
GET |
Kontrola dostupnosti + latence |
/api/settings/qdrant/search |
POST |
Test sémantického vyhledávání |
/api/settings/qdrant/cleanup |
POST |
Odstranění expirovaných / starých bodů |
/api/settings/qdrant/embedding-models |
GET |
Seznam dostupných embeddingových modelů |
Poznámky k chování (co očekávat):
- Výběr enginu — povolením Qdrantu na kartě Engine se Qdrant stane primárním
úložištěm (nastaví
memoryVectorStore="qdrant"); zakázáním se hodnota obnoví na"auto"(#5597). - Bez zpětného doplnění — do Qdrantu se zapisují pouze paměti vytvořené/aktualizované po jeho povolení (duální zápis typu fire-and-forget). Již existující paměti SQLite se nemigrují; „Reindex Now“ znovu sestaví pouze index sqlite-vec, nikoli Qdrant.
- Rozměr vektorů se zjišťuje automaticky ze skutečného embeddingu při prvním použití — není nutné vyplňovat žádné pole rozměru. Změna embeddingového modelu po vytvoření kolekce se nezpracovává automaticky: existující kolekce zůstane beze změny, zápisy/vyhledávání s neodpovídajícím rozměrem selžou a použije se záložní sqlite-vec. Chcete-li změnit embedder, vytvořte kolekci znovu (pod novým názvem nebo ji v Qdrantu odstraňte).
- Metrika vzdálenosti — vždy Cosine (pevně zakódováno při vytváření kolekce; nelze konfigurovat).
- Ověřování — pouze klíč API (odesílá se v hlavičce
api-key; u neověřovaného lokálního Dockeru je volitelný). JWT/RBAC se nepoužívají. - Konfigurační pole — uživatelské rozhraní zpřístupňuje
host,port,collection,embeddingModel,apiKey.vectorSize/hnswEfConstructjsou dostupné pouze prostřednictvím prostředí/DB avectorSizese k vytvoření kolekce nepoužívá (rozměr se získá z embeddingu).
Kvantizace vektorů (int8 — volitelná, oba backendy)
Oba vektorové backendy podporují volitelnou kvantizaci int8, která snižuje paměťovou náročnost uložených vektorů (přibližně 4× menší než Float32) za cenu mírného snížení úspěšnosti vyhledávání. U obou je ve výchozím nastavení vypnutá — vektory si zachovávají plnou přesnost, pokud není výslovně povolena.
| Backend | Nastavení | Typ | Výchozí hodnota | Kde se načítá |
|---|---|---|---|---|
| Qdrant | qdrantQuantization (klíč DB) |
"none" | "int8" | "binary" |
"none" |
src/lib/memory/qdrant.ts::normalizeQdrantConfig() |
| sqlite-vec | MEMORY_VEC_QUANTIZATION (prostředí) |
"none" | "int8" |
"none" |
src/lib/memory/vectorStore.ts::requestedVecQuantization() |
- Qdrant se konfiguruje pro každou instanci pomocí klíče nastavení
qdrantQuantization(zpřístupněného jako polequantizationvPUT /api/settings/qdrant). Při hodnotě"int8"požádábuildQuantizationConfig()o skalární kvantizaci (always_ram, kvantil0.99) a vyhledávání povolírescore: true, aby vektory s plnou přesností zpřesnily sadu kandidátů int8. - Kvantizace sqlite-vec se nastavuje pouze prostřednictvím prostředí (nejde
o nastavení DB): nastavením
MEMORY_VEC_QUANTIZATION=int8se lokální vektory uloží jako sloupecint8[dim]prostřednictvímvec_quantize_int8(?, 'unit'). Zvolený režim je zahrnut doembedding_signature(přípona:int8), takže přepnutí režimu vyvolá úplnou reindexaci tabulkyvec_memories— stejnou cestou líného zpětného doplnění, která se používá při změně embeddingového modelu.
Typy paměti
MemoryType (src/lib/memory/types.ts):
| Typ | Použití |
|---|---|
factual |
Preference, stabilní fakta o uživateli, vzorce chování |
episodic |
Rozhodnutí spojená s konkrétním okamžikem („Zvolil jsem Postgres“) |
procedural |
Paměť pracovních postupů / návodů (rezervováno; aktuálně bez automatického extraktoru) |
semantic |
Rezervováno pro položky ve vektorovém úložišti |
Strategie načítání MemoryConfig je jedna z hodnot exact, semantic nebo hybrid
a rozsah je jeden z session, apiKey nebo global. Výchozí rozsah z
getMemorySettings() je apiKey.
Extrakce faktů (extraction.ts)
Extrakce je založená na regulárních výrazech, nikoli na LLM — probíhá v rámci procesu pomocí
setImmediate(), takže nikdy neblokuje proud odpovědi:
- Vzory preferencí →
MemoryType.FACTUAL(např.I prefer …,I really like …,my favorite is …,I hate …) - Vzory rozhodnutí →
MemoryType.EPISODIC(např.I'll use …,I chose …,I went with …,I'm going to adopt …) - Vzory chování →
MemoryType.FACTUAL(např.I usually …,I always …,I tend to …)
Každá shoda je sanitizována (trim, sloučení bílých znaků, omezení na 500 znaků),
v rámci dávky deduplikována prostřednictvím stabilního factKey(category, content) a
uložena pomocí createMemory() s metadaty
{category, extractedAt, source: "llm_response"}. Vstupní text je omezen na
64 KiB (MAX_EXTRACTION_TEXT_LENGTH) — pokud je delší, použije se konec textu,
aby byl vždy zahrnut nejnovější obsah asistenta.
extractFactsFromText(text) je exportována pro testy a vrací strukturovaná
fakta bez jejich uložení.
Načítání (retrieval.ts)
retrieveMemories(apiKeyId, config) je hlavní vstupní bod. Provádí následující:
- Normalizuje a validuje konfiguraci pomocí
MemoryConfigSchema. - Okamžitě vrátí
[], pokud jeenablednastaveno na false nebomaxTokens <= 0. - Omezí
maxTokensna rozsah[1, 8000]. - Zjistí, zda existuje moderní tabulka
memories(oproti zastaralé tabulcememory), aby nadále fungovaly i starší databáze. - Sestaví základní dotaz s kontrolou expirace
(
expires_at IS NULL OR datetime(expires_at) > datetime('now')), volitelným rozsahem relace a volitelným omezením podleretentionDays. - Větví se podle strategie:
exact(výchozí): chronologickéORDER BY created_at DESC LIMIT 100.semantic: pokud existujeconfig.queryamemory_fts, použije JOINmemory_fts MATCH ?a řazení podle hodnocení FTS; pokud FTS vrátí 0 řádků, přejde zpět na chronologické řazení.hybrid: sjednocení výsledků FTS (s vyšší relevancí) a chronologické množiny, deduplikované podle id.
- Pokud je zadán dotaz, vypočítá skóre relevance klíčových slov (
getRelevanceScore) nadcontent,keya JSON vmetadata. Řádky s nulovým skóre jsou odfiltrovány. - Seřadí výsledky sestupně podle skóre a poté sestupně podle
createdAt. - Prochází seřazený seznam a přijímá položky, dokud průběžný součet
estimateTokens(content)(≈length / 4) zůstává v rámci rozpočtu. Pokud existuje alespoň jedna shoda, vždy vrátí nejméně jednu položku.
estimateTokens je exportována a používá se při načítání, sumarizaci a v nástroji MCP
omniroute_memory_search.
Vkládání (injection.ts)
injectMemory(request, memories, provider):
- Spojí obsah všech pamětí do jediného řetězce
Memory context: …. - Vybere strategii podle názvu poskytovatele:
- Systémová zpráva (výchozí pro OpenAI, Anthropic, Gemini, …) — vloží
{role: "system", content: memoryText}před všechny existující systémové zprávy, takže systémové výzvy uživatele mají stále přednost. - Uživatelská zpráva (záložní možnost) — pro poskytovatele v
PROVIDERS_WITHOUT_SYSTEM_MESSAGE:o1,o1-mini,o1-preview,glm,glmt,glm-cn,zai,qianfan. Ti systémovou roli odmítají a jinak by vrátili chybu 400 (viz problém #1701 pro GLM/Zhipu).
- Systémová zpráva (výchozí pro OpenAI, Anthropic, Gemini, …) — vloží
- Zaznamená počet, strategii a model pod
memory.injection.injected.
providerSupportsSystemMessage(provider) je exportována pro volající, kteří
potřebují provádět vlastní rozhodování o směrování. U neznámých poskytovatelů je
z bezpečnostních důvodů výchozí hodnota true (systémová role je povolena).
Nastavení (settings.ts)
Konfigurace paměti je uložena v tabulce nastavení databáze, nikoli v proměnných prostředí.
getMemorySettings() načítá data z getSettings() a ukládá výsledek
do mezipaměti v rámci procesu; invalidateMemorySettingsCache() je volána trasou
PUT pro nastavení po provedení zápisů.
Starší pole (všechny verze)
| Klíč DB | Typ | Výchozí hodnota | Ovládací prvek uživatelského rozhraní |
|---|---|---|---|
memoryEnabled |
boolean | false (od v3.8.30 ve výchozím nastavení vypnuto) |
Zapnutí/vypnutí paměti |
memoryMaxTokens |
integer | 2000 (rozsah 0–16000) |
Rozpočet tokenů pro vkládání |
memoryRetentionDays |
integer | 30 (rozsah 1–365) |
Doba uchovávání |
memoryStrategy |
enum | "hybrid" (jedna z recent, semantic, hybrid) |
Strategie vyhledávání |
skillsEnabled |
boolean | false |
Přepíná vkládání dovedností pro jednotlivé klíče (viz SKILLS.md) |
Poznámka: strategie uživatelského rozhraní "recent" se prostřednictvím
toMemoryRetrievalConfig() mapuje na interní strategii vyhledávání "exact"
(chronologické pořadí).
Nová pole (v3.8.6, plán 21 D9)
Popisy polí naleznete také výše v části „Rozšíření nastavení“.
| Klíč DB | Pole API | Výchozí hodnota |
|---|---|---|
memoryEmbeddingSource |
embeddingSource |
"auto" |
memoryEmbeddingModel |
embeddingProviderModel |
null |
memoryTransformersEnabled |
transformersEnabled |
false |
memoryStaticEnabled |
staticEnabled |
false |
memoryRerankEnabled |
rerankEnabled |
false |
memoryRerankModel |
rerankProviderModel |
null |
memoryVectorStore |
vectorStore |
"auto" |
Klíče DB související s Qdrantem (qdrantEnabled, qdrantHost, qdrantPort,
qdrantApiKey, qdrantCollection s výchozí hodnotou "omniroute_memory",
qdrantEmbeddingModel s výchozí hodnotou "openai/text-embedding-3-small") načítá
normalizeQdrantConfig() v qdrant.ts.
Proměnné prostředí (v3.8.6)
Šest volitelných proměnných prostředí upravuje chování enginu za běhu (zdokumentováno v .env.example):
| Proměnná | Výchozí hodnota | Popis |
|---|---|---|
MEMORY_EMBEDDING_CACHE_TTL_MS |
300000 |
TTL mezipaměti embeddingů (5 min) |
MEMORY_EMBEDDING_CACHE_MAX |
1000 |
Maximální počet položek v LRU mezipaměti embeddingů |
MEMORY_TRANSFORMERS_MODEL |
Xenova/all-MiniLM-L6-v2 |
Repo HF pro model Transformers.js |
MEMORY_STATIC_MODEL |
minishlab/potion-base-8M |
Repo HF pro statický model potion |
MEMORY_STATIC_CACHE_DIR |
<DATA_DIR>/embeddings |
Umístění pro ukládání stažených modelů |
MEMORY_VEC_TOP_K |
20 |
Výchozí top-K pro vektorové vyhledávání |
MEMORY_RRF_K |
60 |
Konstanta k RRF pro hybridní vyhledávání |
MEMORY_VEC_QUANTIZATION |
none |
Nastavte na int8, aby se lokální vektory sqlite-vec ukládaly kvantizovaně (přibližně 4× menší; volitelné). Změna režimu vynutí nové indexování. |
Sumarizace (summarization.ts)
summarizeMemories(apiKeyId, sessionId?, maxTokens = 4000) zkomprimuje starší
obsah, když průběžný celkový počet tokenů v pamětech daného klíče překročí
limit. Prochází řádky sestupně podle created_at, ponechá řádky, které se vejdou,
a ve zbývajících nahradí content přímo na místě prvními třemi větami
původního obsahu. tokensSaved je rozdíl hodnot estimateTokens mezi starým a
novým obsahem.
Tato rutina je dostupná, ale v současném chatovacím řetězci se nevolá automaticky
— pokud potřebujete průběžnou komprimaci, volejte ji z úlohy cron, akce správce
nebo propojovacího kódu MemoryConfig.autoSummarize. Ztráta dat je nevratná:
původní text se přepíše.
REST API
Všechny koncové body vyžadují ověření správy (requireManagementAuth).
Základní koncové body paměti (stávající + aktualizované)
| Metoda | Cesta | Popis |
|---|---|---|
GET |
/api/memory |
Stránkovaný seznam s filtry: apiKeyId, type, sessionId, q, limit, page, offset. Odpověď obsahuje stats.total, stats.tokensUsed, stats.hitRate, cacheStats |
POST |
/api/memory |
Vytvoří záznam (ověřeno pomocí Zod: content, key, volitelně type, sessionId, apiKeyId, metadata, expiresAt). Volá createMemory(), která provede upsert podle (apiKeyId, key) |
GET |
/api/memory/[id] |
Načte jeden záznam podle UUID |
PUT |
/api/memory/[id] |
Aktualizuje pole záznamu (type, key, content, metadata). Tělo: MemoryUpdatePutSchema. Také synchronizuje vektor, pokud je dostupný zdroj embeddingu. |
DELETE |
/api/memory/[id] |
Odstraní záznam; odstraní jej také z vec_memories (D15) a v režimu best-effort z Qdrantu. Pokud neexistuje, vrátí 404. |
GET |
/api/memory/health |
Spustí verifyExtractionPipeline("health-check") — cyklus vytvoření→výpis→odstranění. Vrací {working, latencyMs, error?} |
Nové koncové body paměťového enginu (plán 21)
| Metoda | Cesta | Popis |
|---|---|---|
POST |
/api/memory/retrieve-preview |
Zkušební běh retrieveMemories — vrací seřazené výsledky se skóre, úrovní a tokeny. Tělo: RetrievePreviewSchema. Paměti NEVKLÁDÁ ani neupravuje. |
GET |
/api/memory/embedding-providers |
Uvádí poskytovatele s embeddingovými modely a označuje, kteří mají nakonfigurovaný API klíč. |
GET |
/api/memory/engine-status |
Vrací úplný stav enginu: úroveň klíčových slov, rozlišení embeddingu, statistiky vektorového úložiště, stav Qdrantu a konfiguraci opětovného řazení. Schéma: MemoryEngineStatusSchema. |
POST |
/api/memory/summarize |
Ručně spustí komprimaci paměti. Tělo: MemorySummarizeSchema (olderThanDays, apiKeyId?, dryRun). Vrací {candidates, tokensSaved}. |
POST |
/api/memory/reindex |
Spustí přeindexování vektorů pro paměti s needs_reindex=1. Tělo: MemoryReindexSchema (force). Vrací {started, pending}. |
Koncové body nastavení
| Metoda | Cesta | Popis |
|---|---|---|
GET |
/api/settings/memory |
Aktuální normalizované nastavení MemorySettingsExtended (7 nových polí + starší pole) |
PUT |
/api/settings/memory |
Aktualizuje libovolné pole z MemorySettingsExtendedSchema (celkem 12 polí) |
GET |
/api/settings/qdrant |
Aktuální nastavení Qdrantu (QdrantSettingsSchema) |
PUT |
/api/settings/qdrant |
Aktualizuje nastavení Qdrantu. Tělo: QdrantSettingsUpdateSchema. apiKey = prázdný řetězec odstraní klíč. |
GET |
/api/settings/qdrant/health |
Kontrola dostupnosti nakonfigurované instance Qdrantu. Vrací QdrantHealthResultSchema. |
POST |
/api/settings/qdrant/search |
Test sémantického vyhledávání v Qdrantu. Tělo: QdrantSearchSchema (query, topK). |
POST |
/api/settings/qdrant/cleanup |
Odstraní z Qdrantu body odpovídající pamětem s prošlou platností nebo starým pamětem. |
GET |
/api/settings/qdrant/embedding-models |
Vypíše embeddingové modely dostupné pro Qdrant. |
Dotaz pro výpis /api/memory podporuje buď stránkování založené na page
(parsePaginationParams), nebo přímo zadaný offset — pokud je přítomen
offset, má přednost a pro strukturu odpovědi se vypočítá odvozená hodnota
page.
Nástroje MCP (open-sse/mcp-server/tools/memoryTools.ts)
Když je server MCP povolen, zaregistrují se tři paměťové nástroje:
omniroute_memory_search—{apiKeyId, query?, type?, maxTokens?, limit?}→ obalujeretrieveMemories(). Od verze v3.8.6 (D16) sestrategynačítá zgetMemorySettings(), místo aby byla pevně nastavena na"exact". Pokud je zadánoqueryastrategyjesemanticnebohybrid, použije se vektorové úložiště, je-li dostupné.omniroute_memory_add—{apiKeyId, sessionId?, type, key, content, metadata?}→ obalujecreateMemory(). Přijímá pouze 4 kanonické typy:factual,episodic,procedural,semantic(D17).omniroute_memory_clear—{apiKeyId, type?, olderThan?}→ vypíše odpovídající položky, volitelně je filtruje podle časového razítka vytvoření před zadaným datem a poté každou odstraní pomocídeleteMemory()(což také odstraní vektory ze sqlite-vec + Qdrant).
Podrobnosti o transportu a rozsahu naleznete v dokumentu MCP-SERVER.md.
Řídicí panel (Memory Studio)
src/app/(dashboard)/dashboard/memory/page.tsx je nyní Studio se 3 kartami:
Karta: Vzpomínky
- Karta s popisem konceptu (sbalitelné vysvětlení „Jak to funguje“).
- Seznam, vyhledávání a stránkování v reálném čase (prodleva 300 ms).
- Filtr typu (
factual/episodic/procedural/semantic/ všechny). - Modální okno pro přidání vzpomínky (klíč, obsah, typ).
- Úprava přímo v řádku (tlačítko s tužkou →
PUT /api/memory/[id]). - Odstranění jednotlivých řádků (s potvrzovacím dialogem).
- Export aktuální stránky do JSON; import JSON pomocí výběru souboru.
- Karty statistik:
totalEntries,tokensUsed,hitRate. - Tlačítko „Kompaktovat staré“ →
POST /api/memory/summarize(nejprve zkušební běh zobrazí počet kandidátů, poté požádá o potvrzení). - Zelený/červený indikátor stavu řízený pomocí
GET /api/memory/health.
Karta: Pískoviště
- Vstup pro dotaz + výběr strategie (Přesná / Sémantická / Hybridní) + rozpočet tokenů.
- „Simulovat“ →
POST /api/memory/retrieve-preview— zobrazí seřazené výsledky sscore,tier,tokens,vecScore,ftsScore. - Panel vyhodnocení zobrazující, který zdroj vnoření / které vektorové úložiště bylo použito a zda došlo k použití náhradního řešení.
Karta: Engine
- Panel stavu enginu (štítek klíčových slov FTS5, štítek vnoření, štítek vektorového úložiště, štítek stavu Qdrant, štítek opětovného řazení).
- Tlačítko „Reindexovat nyní“ →
POST /api/memory/reindex. - Výběr zdroje vnoření (automatický / vzdálený / statický / transformery + přepínače).
- Karta konfigurace Qdrant (přepínač aktivace, hostitel/port/kolekce/klíč, test připojení, test sémantického vyhledávání, vyčištění).
- Karta konfigurace opětovného řazení (přepínač aktivace, výběr poskytovatele/modelu).
Nastavení paměti a Qdrant jsou také dostupná v
/dashboard/settings → Memory & Skills (MemorySkillsTab.tsx) jako
starší/globální rozhraní nastavení.
Ukládání do mezipaměti
src/lib/memory/store.ts udržuje mezipaměť podobnou LRU v rámci procesu
(MEMORY_CACHE_TTL = 1 min, MEMORY_MAX_CACHE_SIZE = 500, s vyřazením 20 %
nejstarších položek) pro čtení getMemory(id) a také obecnou vrstvu mezipaměti
klíč/hodnota memoryCache (src/lib/memory/cache.ts) s metodami get/set/invalidate,
kterou používají volající vyžadující vlastní mezipaměť s vymezeným rozsahem (LRU s 1 000 položkami,
výchozí TTL 5 min).
Soukromí a životní cyklus
- Vlastníkem paměti je ID klíče API (
resolveMemoryOwnerIdvchatCore.ts). BezapiKeyInfo.idse nespustí načítání, vkládání ani extrakce. - Záznamy s budoucí hodnotou
expires_atjsou z načítání odfiltrovány; staré záznamy překračujícíretentionDaysjsou vyloučeny pomocí podmínkycreated_at >= cutoffve funkciretrieveMemories. - Pro trvalé odstranění použijte
DELETE /api/memory/[id]neboomniroute_memory_clear. - Extrakce probíhá asynchronně bez čekání na výsledek prostřednictvím
setImmediate; selhání jsou protokolována podmemory.extraction.background.faileda volajícímu se nikdy neprojeví. - Ověřovací průchody (
verifyExtractionPipeline) odstraní své vlastní testovací záznamy v blokufinally.
Viz také
- SKILLS.md — nastavení
skillsEnabledvkládá definice nástrojů společně s pamětí. - MCP-SERVER.md — přenos MCP / rozsahy oprávnění.
- API_REFERENCE.md — širší rozhraní API.
- Zdrojové moduly:
src/lib/memory/types.ts,schemas.tssrc/lib/memory/store.ts,retrieval.ts,injection.ts,reindex.tssrc/lib/memory/extraction.ts,summarization.ts,verify.tssrc/lib/memory/settings.ts,qdrant.ts,cache.tssrc/lib/memory/vectorStore.ts— sqlite-vec + hybridní RRFsrc/lib/memory/embedding/index.ts— vrstva vkládání z více zdrojůsrc/lib/memory/embedding/types.ts,remote.ts,staticPotion.ts,transformersLocal.ts,cache.tssrc/shared/schemas/memory.ts— schémata Zod pro všechna těla požadavků paměťového APIsrc/shared/schemas/qdrant.ts— schémata Zod pro nastavení/operace Qdrantsrc/lib/db/memoryVec.ts— operace CRUD promemory_vec_metasrc/lib/db/migrations/015_create_memories.sql,022_add_memory_fts5.sql,023_fix_memory_fts_uuid.sql,083_memory_vec.sqlsrc/app/api/memory/route.ts,[id]/route.ts,health/route.tssrc/app/api/memory/retrieve-preview/route.tssrc/app/api/memory/engine-status/route.tssrc/app/api/memory/embedding-providers/route.tssrc/app/api/memory/summarize/route.tssrc/app/api/memory/reindex/route.tssrc/app/api/settings/memory/route.tssrc/app/api/settings/qdrant/route.ts+ dílčí trasysrc/app/(dashboard)/dashboard/memory/— uživatelské rozhraní Studia (stránka + komponenty + karty + hooky)open-sse/handlers/chatCore.ts(propojení vkládání / extrakce)open-sse/mcp-server/tools/memoryTools.ts
Výběr poskytovatele vkládání (v3.8.16+)
Paměťový modul OmniRoute podporuje čtyři zdroje vkládání (src/lib/memory/embedding/). Každý z nich nabízí jiné kompromisy z hlediska latence, nákladů, kvality modelu a složitosti nastavení.
Zdroje vkládání
| Poskytovatel | Zdroj | Latence | Náklady | Kvalita | Nastavení |
|---|---|---|---|---|---|
transformers |
Místní model ONNX (Xenova/all-MiniLM-L6-v2) | ~50-150ms (CPU) | Zdarma | Dobrá | Pouze npm install |
static |
Předpočítané vektory (v mezipaměti) | <1ms | Zdarma | N/A (závisí na zásahu mezipaměti) | Žádné |
remote |
API OpenAI / Cohere / Voyage | ~100-300ms | $0.02-0.10/1M tokenů | Vynikající | Klíč API |
auto |
Za běhu vybere nejlepší dostupný zdroj | Stejná jako u zvoleného zdroje | Zdarma | Stejná jako u zvoleného zdroje | Žádné |
| (cache) | Vrstva LRU v paměti nad libovolným zdrojem | <1ms (zásah), plná latence (nezásah) | Zdarma | Stejná jako u podkladového zdroje | Vždy zapnuto (nelze vybrat jako zdroj) |
Rozhodovací strom
Jaký je kontext vašeho nasazení?
│
┌───────────┼───────────┬──────────────┐
│ │ │ │
VÝVOJ/TEST MALÁ PROD. VELKÁ PROD. EDGE / OFFLINE
│ │ │ │
▼ ▼ ▼ ▼
transformers transformers remote (Qdrant) transformers
(zdarma, bez API) (nejlepší kvalita) (bez internetu)
│ │ │ │
└────────┬──┴───────────┴──────────────┘
│
▼
VŽDY přidejte navrch vrstvu `cache`
(LruCache obaluje libovolného poskytovatele)
Konfigurace databáze a API
Možnosti vkládání paměti se konfigurují prostřednictvím API / uživatelského rozhraní Nastavení, nikoli pomocí proměnných prostředí. Příslušné databázové klíče nastavení v části Nastavení (normalizeMemorySettings v src/lib/memory/settings.ts) jsou:
memoryEmbeddingSource:"transformers"(místní),"remote"(založený na API, např. OpenAI),"static"(externí úložiště) nebo"auto"memoryEmbeddingProviderModel: Identifikátor modelu pro vzdálené/statické zdroje (např."text-embedding-3-small")memoryTransformersEnabled:true|falsememoryStaticEnabled:true|falsememoryVectorStore:"sqlite-vec","qdrant"nebo"auto"
Místní model (transformers)
Interně používá transformers.js ke spouštění místních modelů:
# Proměnné prostředí načítané v kódu (src/lib/memory/embedding/index.ts):
MEMORY_TRANSFORMERS_MODEL=Xenova/all-MiniLM-L6-v2 # Repozitář modelu HF
MEMORY_STATIC_MODEL=minishlab/potion-base-8M # Statický model potion z HF
MEMORY_STATIC_CACHE_DIR=<DATA_DIR>/embeddings # Adresář mezipaměti
Mezipaměť vkládání LRU
Mezipaměť je ve výchozím nastavení vždy zapnutá a konfiguruje se pomocí proměnných prostředí:
MEMORY_EMBEDDING_CACHE_MAX=1000 # Maximální počet položek v mezipaměti
MEMORY_EMBEDDING_CACHE_TTL_MS=300000 # TTL (5 min)
Údaje o výkonu
Benchmark na typickém 4jádrovém serveru x86 (texty po ~100 tokenech):
| Poskytovatel | p50 | p95 | p99 | Cena / 1 mil. embeddingů |
|---|---|---|---|---|
transformers (CPU) |
80ms | 180ms | 350ms | Zdarma |
remote (OpenAI) |
120ms | 220ms | 400ms | ~$0.02 (ada-002) / $0.13 (3-large) |
static (Qdrant) |
15ms | 30ms | 60ms | Závisí na hostingu Qdrant |
cache (zásah) |
<1ms | <1ms | 2ms | Zdarma |
Vzory extrakce faktů (v3.8.16+)
Modul extraction.ts (src/lib/memory/extraction.ts) používá porovnávání pomocí regulárních výrazů k extrakci strukturovaných faktů ze zpráv konverzace. Porozumění těmto vzorům vám pomůže vyladit kvalitu extrakce pro váš případ použití.
Výchozí kategorie vzorů
| Kategorie | Příklad vzoru | Zachycuje |
|---|---|---|
| PREFERENCE_PATTERNS | "Preferuji <X>", "Mám rád/a <X>", "Nesnáším <X>" |
Uživatelské preference |
| DECISION_PATTERNS | "Použiji <X>", "Rozhodl/a jsem se <X>", "Zvolil/a jsem <X>" |
Rozhodnutí uživatele (epizodická) |
| PATTERN_PATTERNS | "Obvykle <X>", "Vždy <X>", "Nikdy <X>" |
Trvalé vzorce chování |
Příklady vzorů (zjednodušené)
// Ze souboru src/lib/memory/extraction.ts
const PREFERENCE_PATTERNS = [
/\bI\s+(?:really\s+)?prefer\s+([^.,\n]+)/gi,
/\bI\s+(?:really\s+)?like\s+([^.,\n]+)/gi,
/\bI\s+(?:hate|dislike|avoid)\s+([^.,\n]+)/gi,
];
const DECISION_PATTERNS = [
/\bI'?(?:ll|will)\s+use\s+([^.,\n]+)/gi,
/\bI\s+(?:have\s+)?decided\s+(?:to\s+)?([^.,\n]+)/gi,
];
const PATTERN_PATTERNS = [/\bI\s+usually\s+([^.,\n]+)/gi, /\bI\s+always\s+([^.,\n]+)/gi];
Co se extrahuje
Když uživatel řekne:
"Preferuji TypeScript. Pro tento projekt použiji Postgres. Vždy před odesláním změn vytvořím commit. Nemám rád/a Python." Extrakce vytvoří 4 vzpomínky:
Klíč Kategorie Typ Obsah preference:typescriptpreference factual "TypeScript" decision:postgres_for_this_projectdecision episodic "Postgres pro tento projekt" pattern:commit_before_pushingpattern factual "vytvořit commit před odesláním změn" preference:pythonpreference factual "Python"
Limity extrakce
Aby se zabránilo nekontrolované extrakci, platí následující limity:
| Minimální délka obsahu | 3 znaky | | Maximální délka obsahu | 500 znaků |
Kdy extrakci vypnout
Extrakce se spouští automaticky vždy, když je povolena paměť; neexistuje žádný samostatný
přepínač pouze pro extrakci. Chcete-li ji vypnout, zakažte paměť úplně (enabled: false
prostřednictvím PUT /api/settings/memory). Zvažte to v následujících případech:
- Máte velký objem zpráv a náklady na extrakci nejsou zanedbatelné
- Vaše konverzace jsou převážně dočasné (chat, ladění) a nemají dlouhodobou hodnotu
- Kontext již zachycujete prostřednictvím vlastních pluginů
Ladění hybridního RRF (v3.8.16+)
Algoritmus Reciprocal Rank Fusion (RRF) kombinuje výsledky FTS5 (klíčová slova) a vektorového vyhledávání (sémantika). Parametr k určuje, jakou váhu dostanou výsledky na nižších pozicích.
Vzorec
Pro každou kandidátní vzpomínku je skóre RRF následující:
RRF(d) = Σ 1 / (k + rank_i(d))
Kde:
kje konstanta (výchozí hodnota 60)rank_i(d)je pořadí dokumentudv i-tém vyhledávacím systému (FTS, vektor)- Součet se provádí přes všechny vyhledávací systémy
Jak k ovlivňuje výsledky
Hodnota k |
Účinek | Nejvhodnější pro |
|---|---|---|
k=0 |
Čistá fúze pořadí (bez vyhlazování) | Teoretická výchozí úroveň |
k=10-30 |
Výrazně zvýhodňuje nejlepší výsledky, nízké pořadí přispívá jen minimálně | Když jsou první 3 výsledky obvykle správné |
k=60 (výchozí) |
Vyvážené — všech 10 nejlepších výsledků smysluplně přispívá | Univerzální vyhledávání |
k=100+ |
Plošší — i výsledky na nízkých pozicích mohou převážit, pokud se objeví ve více systémech | Když je úplnost > přesnost kritická |
Ladění k v praxi
# Výchozí hodnota
MEMORY_RRF_K=60
# Agresivní přesnost (malá paměť, málo dokumentů)
MEMORY_RRF_K=20
# Maximální úplnost (velká paměť, různorodé dotazy)
MEMORY_RRF_K=120
Příklad s k=20:
- FTS pořadí 1 → příspěvek
1/21 = 0.048 - FTS pořadí 10 → příspěvek
1/30 = 0.033 - Vektorové pořadí 1 → příspěvek
0.048 - Kombinované maximum:
0.096
Příklad s k=60:
- FTS pořadí 1 → příspěvek
1/61 = 0.016 - FTS pořadí 10 → příspěvek
1/70 = 0.014 - Vektorové pořadí 1 → příspěvek
0.016 - Kombinované maximum:
0.033
Při vyšším k je relativní rozdíl mezi 1. a 10. pořadím menší, takže algoritmus více spoléhá na shodu napříč vyhledávacími systémy než na jistotu nejvyššího pořadí.
Kdy změnit k
| Příznak | Co vyzkoušet |
|---|---|
| Nejlepší výsledek vždy vyhraje, ale je chybný | Nižší k (např. 20) — jistota nejvyššího pořadí má větší význam |
| Správná odpověď je mezi prvními 5, ale není první | Vyšší k (např. 100) — plošší bodování odměňuje shodu |
| Úplnost je vysoká, ale přesnost nízká | Nižší k — zostřete řazení |
| Úplnost je nízká (relevantní dokumenty chybí) | Vyšší k — dejte šanci dokumentům na nižších pozicích |
Váhování RRF
Fúze reciprokého pořadí používá stejné váhy pro sémantické vektorové pořadí a pořadí fulltextového vyhledávání:
RRF(d) = 1/(k + rank_vector) + 1/(k + rank_fts)
Pro úpravu jednotlivých vah neexistují žádné proměnné prostředí (MEMORY_RRF_VECTOR_WEIGHT/MEMORY_RRF_FTS_WEIGHT neexistují).
Strategie sumarizace (v3.8.16+)
Modul summarization.ts (src/lib/memory/summarization.ts) komprimuje starší vzpomínky, aby aktivní sada zůstala malá a zároveň byla zachována možnost jejich vyhledání.
Kdy se sumarizace spouští
| Spouštěč | Prahová hodnota (výchozí) |
|---|---|
| Ruční spuštění prostřednictvím API | není k dispozici |
Co se sumarizuje
Z summarization.ts jsou exportovány dva vstupní body:
summarizeMemories(apiKeyId, sessionId?, maxTokens = 4000)— sloučí vzpomínky relace do jediného souhrnného textu omezeného tokenovým rozpočtem.summarizeMemoriesOlderThan(apiKeyId, days, dryRun)— komprimace podle stáří používaná rozhraním API: vybere každou vzpomínku starší neždays, vytvoří z nich jednu zhuštěnou souhrnnou vzpomínku a (pokud jedryRunnastaveno nafalse) odstraní originály. PředánímdryRun: truezobrazíte náhled sady kandidátů a celkového počtu tokenů, aniž by se cokoli změnilo.
Neprobíhá žádné seskupování podle značek/klíčů ani hodnocení jednotlivých vzpomínek jako „základní vs. sumarizovatelné“ — výběr je založen čistě na hranici stáří a souhrnný text obsahuje pro každého kandidáta jeden zhuštěný řádek s prefixem typu.
Spuštění sumarizace
Sumarizace je ruční / volitelná — nastavení autoSummarize má ve výchozím
stavu hodnotu false, takže se nic nekomprimuje automaticky. Spusťte ji prostřednictvím API:
curl -X POST http://localhost:20128/api/memory/summarize \
-H "Authorization: Bearer $OMNIROUTE_KEY"
Chcete-li ji ponechat vypnutou, jednoduše zachovejte výchozí hodnotu autoSummarize
(false).
Tipy pro kvalitní sumarizaci
- Nejprve zobrazte náhled pomocí
dryRun—summarizeMemoriesOlderThan(..., true)vrátí seznam kandidátů a celkový počet tokenů, takže před odstraněním originálů můžete ověřit, co bude sloučeno. - Spouštějte sumarizaci v době nízkého provozu, pokud máte rozsáhlý korpus vzpomínek — volání LLM je nejpomalejší část
# Ve stylu Cronu: sumarizace každý den ve 3:00
0 3 * * * curl -X POST http://localhost:20128/api/memory/summarize \
-H "Authorization: Bearer $OMNIROUTE_KEY"
Vzor poskytovatele MemoryBackend
Zdroj pravdy:
src/lib/memory/backend.ts,src/lib/memory/genericBackend.ts,src/lib/memory/manager.tsTesty:src/lib/memory/__tests__/generic-backend.test.ts
Vzor poskytovatele MemoryBackend zavádí nad stávajícím paměťovým enginem připojitelnou abstrakční vrstvu backendu. Namísto vazby na jedinou implementaci úložiště nyní paměťový systém podporuje více backendů (SQLite, Obsidian, Notion, vlastní HTTP backendy) s konfigurovatelným směrováním na primární a záložní backendy.
Architektura
┌──────────────────────────────────────────────────────────┐
│ Trasy API │
│ (src/app/api/memory/route.ts) │
└──────────────────────┬───────────────────────────────────┘
│
┌──────────────────────▼───────────────────────────────────┐
│ MemoryManager │
│ Singletonový orchestrátor (manager.ts) │
│ │
│ Primární ──► Backend A (např. SQLite) │
│ Záložní ──► Backend B (např. Obsidian) │
│ Backend C (např. Notion přes GenericBackend)│
└──────────────────────┬───────────────────────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌──────────────────┐
│ SQLite │ │ Obsidian │ │ GenericMemory │
│ Backend │ │ Backend │ │ Backend (HTTP) │
└────────────┘ └────────────┘ └──────────────────┘
Základní rozhraní (backend.ts)
Každý backend musí implementovat rozhraní MemoryBackend:
interface MemoryBackend {
readonly id: string;
readonly displayName: string;
// CRUD
create(input: CreateMemoryInput): Promise<Memory>;
get(id: string): Promise<Memory | null>;
update(id: string, updates: Partial<...>): Promise<boolean>;
delete(id: string): Promise<boolean>;
list(filter: MemoryFilter): Promise<{ data: Memory[]; total: number; byType: Record<string, number> }>;
// Vyhledávání
search(config: SearchConfig): Promise<Memory[]>;
// Stav
health(): Promise<HealthCheckResult>;
// Životní cyklus (volitelné)
initialize?(): Promise<void>;
shutdown?(): Promise<void>;
}
MemoryManager (manager.ts)
Singletonový orchestrátor, který:
- Registruje backendy prostřednictvím
register(backend)— voláno při spuštění zindex.ts - Konfiguruje primární a záložní backendy prostřednictvím
configure(primary, fallbacks) - Směruje operace CRUD a vyhledávání na primární backend, při selhání použije řetězec záložních backendů
- Pravidelně provádí kontroly stavu všech backendů
Chování záložních backendů:
| Operace | Primární backend | Záložní backendy |
|---|---|---|
create |
✅ Pouze primární | ❌ |
get |
✅ Nejprve zkusí primární | ✅ Záložní, pokud vrátí null |
update |
✅ Pouze primární | ✅ Asynchronní synchronizace bez čekání |
delete |
✅ Pouze primární | ✅ Asynchronní synchronizace bez čekání |
list |
✅ Pouze primární | ❌ |
search |
✅ Nejprve primární | ✅ Záložní při chybě |
GenericMemoryBackend (genericBackend.ts)
Obecný HTTP konektor, který přizpůsobí libovolné REST API rozhraní MemoryBackend. Je užitečný pro:
- Notion — připojení prostřednictvím Notion API
- Obsidian — připojení prostřednictvím Obsidian Local REST API
- Vlastní backendy — jakákoli služba, která poskytuje RESTful paměťové API
Konfigurace:
interface GenericBackendConfig {
baseUrl: string; // Základní URL backendového API
apiKey?: string; // Bearer token pro autentizaci
headers?: Record<string, string>; // Vlastní HTTP hlavičky
timeout?: number; // Časový limit požadavku (výchozí: 30000ms)
backendType?: string; // Pro protokolování
// Přepsání koncových bodů (výchozí hodnoty používají konvence REST)
endpoints?: {
search?: string; // výchozí: "/memories/search"
create?: string; // výchozí: "/memories"
list?: string; // výchozí: "/memories"
get?: string; // výchozí: "/memories/{id}"
update?: string; // výchozí: "/memories/{id}"
delete?: string; // výchozí: "/memories/{id}"
health?: string; // výchozí: "/health"
};
// Mapování názvů parametrů dotazu
queryParams?: {
query?/apiKeyId?/limit?/offset?/strategy?/maxTokens?/type?/sessionId?/orderBy?/orderDir?/options?
};
// Mapování názvů parametrů cesty
pathParams?: {
id?/memoryId?
};
}
Známé backendy jsou předem nakonfigurovány v KNOWN_BACKENDS:
createKnownBackend("obsidian"); // → GenericMemoryBackend směrující na localhost:27123
createKnownBackend("notion"); // → GenericMemoryBackend směrující na api.notion.com/v1
Vestavěné backendy
SQLiteBackend (sqliteBackend.ts)
Výchozí primární backend. Zapouzdřuje existující úložiště paměti založené na SQLite pomocí src/lib/memory/store.ts. Automaticky se registruje při spuštění.
import { sqliteBackend } from "./sqliteBackend";
memoryManager.register(sqliteBackend);
ObsidianBackend (obsidianBackend.ts)
Zapouzdřuje existující integraci s Obsidianem (src/lib/memory/obsidianBackend.ts). Připojuje se k trezoru Obsidianu prostřednictvím Obsidian Local REST API.
Nastavení
Nastavení backendu paměti jsou uložena v tabulce nastavení aplikace a spravována prostřednictvím src/lib/memory/settings.ts:
| Nastavení | Klíč prostředí/konfigurace | Výchozí | Popis |
|---|---|---|---|
| Primární backend | memoryPrimaryBackend |
"sqlite" |
ID primárního backendu |
| Záložní backendy | memoryFallbackBackends |
[] |
Seřazená ID záložních backendů |
| Konfigurace backendů | memoryBackendConfigs |
{} |
Přepsání konfigurace pro jednotlivé backendy |
Nastavení jsou normalizována pomocí normalizeMemorySettings() a ukládána do mezipaměti v getMemorySettings().
Průběh inicializace
Spuštění aplikace
→ importy v index.ts (vedlejší efekt): registrují SQLiteBackend
→ initMemoryBackends() voláno z životního cyklu aplikace:
1. Načtení nastavení (getMemorySettings)
2. Konfigurace primárního a záložních backendů
3. Inicializace všech backendů (kontrola stavu)
4. Připraveno pro požadavky
Přidání nového backendu
- Implementujte rozhraní
MemoryBackendvsrc/lib/memory/<name>Backend.ts - Exportujte z
src/lib/memory/index.ts - Zaregistrujte pomocí
memoryManager.register(yourBackend)při spuštění - Nakonfigurujte prostřednictvím nastavení: nastavte
memoryPrimaryBackendna ID svého backendu - Otestujte s využitím
src/lib/memory/__tests__/generic-backend.test.tsjako reference
Příklad: Backend Brain
import { createGenericMemoryBackend } from "./genericBackend";
const brainBackend = createGenericMemoryBackend("brain", "BK-Brain", {
baseUrl: process.env.BRAIN_API_URL || "http://localhost:9099",
apiKey: process.env.BRAIN_API_KEY,
endpoints: {
search: "/api/memory/search",
create: "/api/memory",
health: "/api/health",
},
});
memoryManager.register(brainBackend);
Ověření
Jednotkové testy
npx vitest run src/lib/memory/__tests__/generic-backend.test.ts --reporter=verbose
Očekávaný výstup: 35 testů, všechny úspěšné, které pokrývají:
- Konstruktor (2)
- Kontrola stavu (4) — úspěch, selhání 500, síťová chyba, latence
- Inicializace (2) — úspěch, selhání
- Vytvoření (2) — výchozí koncový bod, vlastní koncový bod
- Získání (4) — úspěch, 404 → null, jiná chyba než 404, vlastní parametry cesty
- Aktualizace (2) — úspěch, 404 → false
- Odstranění (2) — úspěch, 404 → false
- Výpis (2) — parametry dotazu, vlastní názvy parametrů
- Vyhledávání (3) — parametry dotazu, vlastní koncový bod, serializace možností
- Autorizační hlavičky (2) — Bearer token, vlastní hlavičky
- Tovární funkce (1)
Kontrola typů
npm run typecheck:core
Očekáváno: 0 chyb.