หน่วยความจำ¶
OpenClaw memory is plain Markdown in the agent workspace. หน่วยความจำของOpenClawคือMarkdownธรรมดาในเวิร์กสเปซของเอเจนต์ไฟล์เหล่านี้คือแหล่งอ้างอิงความจริงเพียงหนึ่งเดียวโมเดลจะ“จำ”ได้เฉพาะสิ่งที่ถูกเขียนลงดิสก์เท่านั้น
เครื่องมือค้นหาหน่วยความจำถูกจัดเตรียมโดยปลั๊กอินหน่วยความจำที่เปิดใช้งานอยู่(ค่าเริ่มต้น: memory-core)ปิดใช้งานปลั๊กอินหน่วยความจำได้ด้วยplugins.slots.memory = "none". Disable memory plugins with plugins.slots.memory = "none".
ไฟล์หน่วยความจำ(Markdown)¶
เลย์เอาต์เวิร์กสเปซค่าเริ่มต้นใช้หน่วยความจำสองชั้น:
memory/YYYY-MM-DD.md- บันทึกรายวัน(เพิ่มต่อท้ายเท่านั้น)
- อ่านของวันนี้+เมื่อวานตอนเริ่มเซสชัน
MEMORY.md(ไม่บังคับ)- หน่วยความจำระยะยาวที่คัดสรรแล้ว
- โหลดเฉพาะในเซสชันหลักแบบส่วนตัวเท่านั้น(ไม่โหลดในบริบทกลุ่ม)
ไฟล์เหล่านี้อยู่ใต้เวิร์กสเปซ(agents.defaults.workspace, ค่าเริ่มต้น~/.openclaw/workspace)ดูAgent workspaceสำหรับโครงร่างทั้งหมด See Agent workspace for the full layout.
ควรเขียนหน่วยความจำเมื่อใด¶
- การตัดสินใจ ความชอบ และข้อเท็จจริงที่คงทนให้เขียนลง
MEMORY.md. - บันทึกประจำวันและบริบทที่กำลังดำเนินอยู่ให้เขียนลง
memory/YYYY-MM-DD.md. - หากมีคนพูดว่า“จำสิ่งนี้ไว้”ให้เขียนลงไป(อย่าเก็บไว้ในRAM)
- This area is still evolving. ส่วนนี้ยังพัฒนาอยู่การเตือนโมเดลให้จัดเก็บหน่วยความจำจะช่วยได้มันจะรู้ว่าควรทำอย่างไร
- หากต้องการให้สิ่งใดคงอยู่ขอให้บอตเขียนลงหน่วยความจำ
การล้างหน่วยความจำอัตโนมัติ(pre-compaction ping)¶
เมื่อเซสชันใกล้ถึงการคอมแพ็กชันอัตโนมัติOpenClawจะทริกเกอร์รอบการทำงานเงียบแบบเอเจนต์เพื่อเตือนโมเดลให้เขียนหน่วยความจำที่คงทนก่อนที่บริบทจะถูกคอมแพ็กต์พรอมป์ต์ค่าเริ่มต้นระบุชัดว่าโมเดล_อาจตอบกลับ_แต่โดยทั่วไปNO_REPLYคือคำตอบที่ถูกต้องเพื่อไม่ให้ผู้ใช้เห็นรอบนี้ The default prompts explicitly say the model may reply,
but usually NO_REPLY is the correct response so the user never sees this turn.
การควบคุมทำผ่านagents.defaults.compaction.memoryFlush:
{
agents: {
defaults: {
compaction: {
reserveTokensFloor: 20000,
memoryFlush: {
enabled: true,
softThresholdTokens: 4000,
systemPrompt: "Session nearing compaction. Store durable memories now.",
prompt: "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store.",
},
},
},
},
}
รายละเอียด:
- เกณฑ์อ่อน: การล้างจะทริกเกอร์เมื่อการประมาณโทเคนของเซสชันข้าม
contextWindow - reserveTokensFloor - softThresholdTokens. - เงียบเป็นค่าเริ่มต้น: พรอมป์ต์มี
NO_REPLYจึงไม่มีการส่งถึงผู้ใช้ - สองพรอมป์ต์: พรอมป์ต์ผู้ใช้และพรอมป์ต์ระบบจะต่อท้ายการเตือน
- หนึ่งการล้างต่อรอบคอมแพ็กชัน(ติดตามใน
sessions.json) - เวิร์กสเปซต้องเขียนได้: หากเซสชันรันแบบsandboxด้วย
workspaceAccess: "ro"หรือ"none"การล้างจะถูกข้าม
ดูวงจรคอมแพ็กชันทั้งหมดได้ที่ Session management + compaction.
การค้นหาหน่วยความจำแบบเวกเตอร์¶
OpenClawสามารถสร้างดัชนีเวกเตอร์ขนาดเล็กเหนือMEMORY.mdและmemory/*.mdเพื่อให้การค้นหาเชิงความหมายพบโน้ตที่เกี่ยวข้องแม้ถ้อยคำต่างกัน
ค่าเริ่มต้น:
- เปิดใช้งานเป็นค่าเริ่มต้น
- เฝ้าดูไฟล์หน่วยความจำเพื่อการเปลี่ยนแปลง(debounced)
- Uses remote embeddings by default. ใช้การฝังแบบรีโมตเป็นค่าเริ่มต้นหากไม่ตั้งค่า
memorySearch.providerOpenClawจะเลือกอัตโนมัติ: 1.localหากมีการตั้งค่าmemorySearch.local.modelPathและไฟล์มีอยู่ 2.openaiหากสามารถแก้ไขคีย์OpenAIได้ 3.geminiหากสามารถแก้ไขคีย์Geminiได้ 4.voyageหากสามารถแก้ไขคีย์Voyageได้ 5. มิฉะนั้นการค้นหาหน่วยความจำจะยังคงปิดจนกว่าจะตั้งค่า - โหมดโลคัลใช้node-llama-cppและอาจต้องการ
pnpm approve-builds. - ใช้sqlite-vec(เมื่อมี)เพื่อเร่งการค้นหาเวกเตอร์ภายในSQLite
Remote embeddings require an API key for the embedding provider. OpenClaw
resolves keys from auth profiles, models.providers.*.apiKey, or environment
variables. Codex OAuth only covers chat/completions and does not satisfy
embeddings for memory search. For Gemini, use GEMINI_API_KEY or
models.providers.google.apiKey. For Voyage, use VOYAGE_API_KEY or
models.providers.voyage.apiKey. When using a custom OpenAI-compatible endpoint,
set memorySearch.remote.apiKey (and optional memorySearch.remote.headers).
แบ็กเอนด์QMD(ทดลอง)¶
ตั้งค่าmemory.backend = "qmd"เพื่อสลับตัวทำดัชนีSQLiteในตัวเป็น
QMD:ไซด์คาร์ค้นหาแบบโลคัลเฟิร์สต์ที่ผสานBM25+เวกเตอร์+การจัดอันดับซ้ำMarkdownยังคงเป็นแหล่งอ้างอิงความจริงOpenClawจะเรียกใช้QMDเพื่อการดึงข้อมูลประเด็นสำคัญ: Markdown stays the source of truth; OpenClaw shells
out to QMD for retrieval. Key points:
ข้อกำหนดก่อนเริ่มต้น
- Disabled by default. ปิดใช้งานเป็นค่าเริ่มต้นเลือกใช้ต่อคอนฟิก(
memory.backend = "qmd") - ติดตั้งQMD CLIแยกต่างหาก(
bun install -g https://github.com/tobi/qmdหรือดาวน์โหลดรีลีส)และตรวจสอบว่าไบนารีqmdอยู่ในPATHของเกตเวย์ - QMDต้องการบิลด์SQLiteที่อนุญาตส่วนขยาย(
brew install sqliteบนmacOS) - QMDรันแบบโลคัลทั้งหมดผ่านBun+
node-llama-cppและดาวน์โหลดโมเดลGGUFจากHuggingFaceอัตโนมัติเมื่อใช้งานครั้งแรก(ไม่ต้องมีดีมอนOllamaแยก) - เกตเวย์รันQMDในXDG homeแบบแยกส่วนภายใต้
~/.openclaw/agents/<agentId>/qmd/โดยตั้งค่าXDG_CONFIG_HOMEและXDG_CACHE_HOME. - รองรับระบบปฏิบัติการ: macOSและLinuxใช้งานได้ทันทีเมื่อมีBun+SQLiteติดตั้งWindowsแนะนำผ่านWSL2 Windows is best supported via WSL2.
วิธีการรันไซด์คาร์
- เกตเวย์เขียนQMD homeแบบแยกส่วนภายใต้
~/.openclaw/agents/<agentId>/qmd/(คอนฟิก+แคช+sqlite DB) - คอลเลกชันถูกสร้างผ่าน
qmd collection addจากmemory.qmd.paths(รวมไฟล์หน่วยความจำเวิร์กสเปซค่าเริ่มต้น)จากนั้นqmd update+qmd embedจะรันตอนบูตและตามช่วงเวลาที่กำหนดได้(memory.qmd.update.interval, ค่าเริ่มต้น5 นาที) - การรีเฟรชตอนบูตจะรันเบื้องหลังเป็นค่าเริ่มต้นเพื่อไม่ให้การเริ่มแชตถูกบล็อกตั้งค่า
memory.qmd.update.waitForBootSync = trueเพื่อคงพฤติกรรมบล็อกเดิม - Searches run via
qmd query --json. การค้นหารันผ่านqmd query --jsonหากQMDล้มเหลวหรือไม่มีไบนารีOpenClawจะถอยกลับไปใช้ตัวจัดการSQLiteในตัวโดยอัตโนมัติเพื่อให้เครื่องมือหน่วยความจำยังทำงาน - OpenClawยังไม่เปิดเผยการปรับbatch-sizeของการฝังQMDวันนี้พฤติกรรมแบตช์ถูกควบคุมโดยQMDเอง
- การค้นหาครั้งแรกอาจช้า:QMDอาจดาวน์โหลดโมเดลGGUFแบบโลคัล(การจัดอันดับซ้ำ/การขยายคำค้น)ในการรัน
qmd queryครั้งแรก - OpenClawตั้งค่า
XDG_CONFIG_HOME/XDG_CACHE_HOMEอัตโนมัติเมื่อรันQMD -
หากต้องการพรีดาวน์โหลดโมเดลด้วยตนเอง(และอุ่นดัชนีเดียวกับที่OpenClawใช้)ให้รันคิวรีครั้งเดียวด้วยไดเรกทอรีXDGของเอเจนต์
OpenClaw’s QMD state lives under your state dir (defaults to
~/.openclaw). สถานะQMDของOpenClawอยู่ใต้ไดเรกทอรีสถานะของคุณ(ค่าเริ่มต้น~/.openclaw)คุณสามารถชี้qmdไปยังดัชนีเดียวกันได้โดยเอ็กซ์พอร์ตตัวแปรXDGเดียวกับที่OpenClawใช้:```bash
Pick the same state dir OpenClaw uses¶
STATE_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}" if [ -d "$HOME/.moltbot" ] && [ ! -d "$HOME/.openclaw" ] \ && [ -z "${OPENCLAW_STATE_DIR:-}" ]; then STATE_DIR="$HOME/.moltbot" fi
export XDG_CONFIG_HOME="$STATE_DIR/agents/main/qmd/xdg-config" export XDG_CACHE_HOME="$STATE_DIR/agents/main/qmd/xdg-cache"
(Optional) force an index refresh + embeddings¶
qmd update qmd embed
Warm up / trigger first-time model downloads¶
qmd query "test" -c memory-root --json >/dev/null 2>&1 ```
พื้นผิวคอนฟิก(memory.qmd.*)
command(ค่าเริ่มต้นqmd):แทนที่พาธไฟล์ปฏิบัติการincludeDefaultMemory(ค่าเริ่มต้นtrue):ทำดัชนีอัตโนมัติMEMORY.md+memory/**/*.mdpaths[]:เพิ่มไดเรกทอรี/ไฟล์เพิ่มเติม(path, ไม่บังคับpattern, ไม่บังคับ stablename)sessions:เลือกใช้การทำดัชนีJSONLของเซสชัน(enabled,retentionDays,exportDir)update:ควบคุมรอบการรีเฟรชและการรันบำรุงรักษา: (interval,debounceMs,onBoot,waitForBootSync,embedInterval,commandTimeoutMs,updateTimeoutMs,embedTimeoutMs)limits:จำกัดเพย์โหลดการเรียกคืน(maxResults,maxSnippetChars,maxInjectedChars,timeoutMs)scope: same schema assession.sendPolicy.scope:สคีมาเดียวกับsession.sendPolicyค่าเริ่มต้นคือDMเท่านั้น(denyทั้งหมด,allowแชตตรง)ผ่อนคลายเพื่อแสดงผลQMDในกลุ่ม/ช่องทาง- เมื่อ
scopeปฏิเสธการค้นหา OpenClaw จะบันทึกคำเตือนพร้อมค่าchannel/chatTypeที่คำนวณได้ เพื่อให้การดีบักผลลัพธ์ว่างทำได้ง่ายขึ้น - สแนิปเพ็ตที่มาจากนอกเวิร์กสเปซจะแสดงเป็น
qmd/<collection>/<relative-path>ในผลลัพธ์memory_search;memory_getเข้าใจพรีฟิกซ์นั้นและอ่านจากรูทคอลเลกชันQMDที่ตั้งค่าไว้ - เมื่อ
memory.qmd.sessions.enabled = true,OpenClawจะส่งออกทรานสคริปต์เซสชันที่ผ่านการทำความสะอาด(รอบผู้ใช้/ผู้ช่วย)ไปยังคอลเลกชันQMDเฉพาะภายใต้~/.openclaw/agents/<id>/qmd/sessions/,เพื่อให้memory_searchสามารถเรียกคืนบทสนทนาล่าสุดได้โดยไม่แตะดัชนีSQLiteในตัว - สแนิปเพ็ต
memory_searchจะมีฟุตเตอร์Source: <path#line>เมื่อmemory.citationsเป็นauto/on;ตั้งค่าmemory.citations = "off"เพื่อเก็บเมทาดาทาพาธไว้ภายใน(เอเจนต์ยังคงได้รับพาธสำหรับmemory_getแต่ข้อความสแนิปเพ็ตจะละฟุตเตอร์และพรอมป์ต์ระบบจะเตือนเอเจนต์ไม่ให้อ้างอิง)
ตัวอย่าง
memory: {
backend: "qmd",
citations: "auto",
qmd: {
includeDefaultMemory: true,
update: { interval: "5m", debounceMs: 15000 },
limits: { maxResults: 6, timeoutMs: 4000 },
scope: {
default: "deny",
rules: [{ action: "allow", match: { chatType: "direct" } }]
},
paths: [
{ name: "docs", path: "~/notes", pattern: "**/*.md" }
]
}
}
การอ้างอิงและการถอยกลับ
memory.citationsมีผลไม่ว่าจะแบ็กเอนด์ใด(auto/on/off)- When
qmdruns, we tagstatus().backend = "qmd"so diagnostics show which engine served the results. เมื่อqmdรันเราจะติดแท็กstatus().backend = "qmd"เพื่อให้ไดแอกนอสติกแสดงว่าเอนจินใดให้ผลลัพธ์หากซับโปรเซสQMDออกหรือเอาต์พุตJSONแยกวิเคราะห์ไม่ได้ตัวจัดการการค้นหาจะบันทึกคำเตือนและคืนผู้ให้บริการในตัว(การฝังMarkdownที่มีอยู่)จนกว่าQMDจะกู้คืน
พาธหน่วยความจำเพิ่มเติม¶
หากต้องการทำดัชนีไฟล์Markdownนอกเลย์เอาต์เวิร์กสเปซค่าเริ่มต้นให้เพิ่มพาธแบบชัดเจน:
agents: {
defaults: {
memorySearch: {
extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
}
}
}
หมายเหตุ:
- พาธอาจเป็นแบบสัมบูรณ์หรือสัมพันธ์กับเวิร์กสเปซ
- ไดเรกทอรีจะถูกสแกนแบบรีเคอร์ซีฟสำหรับไฟล์
.md - ทำดัชนีเฉพาะไฟล์Markdownเท่านั้น
- ไม่สนใจซิมลิงก์(ไฟล์หรือไดเรกทอรี)
การฝังGemini(เนทีฟ)¶
ตั้งค่าผู้ให้บริการเป็นgeminiเพื่อใช้Gemini embeddings APIโดยตรง:
agents: {
defaults: {
memorySearch: {
provider: "gemini",
model: "gemini-embedding-001",
remote: {
apiKey: "YOUR_GEMINI_API_KEY"
}
}
}
}
หมายเหตุ:
remote.baseUrlไม่บังคับ(ค่าเริ่มต้นคือฐานURLของGemini API)remote.headersช่วยให้เพิ่มเฮดเดอร์เพิ่มเติมได้หากจำเป็น- โมเดลค่าเริ่มต้น:
gemini-embedding-001
หากต้องการใช้เอนด์พอยต์ที่เข้ากันได้กับOpenAIแบบกำหนดเอง(OpenRouter, vLLMหรือพร็อกซี)
สามารถใช้คอนฟิกremoteกับผู้ให้บริการOpenAIได้:
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://api.example.com/v1/",
apiKey: "YOUR_OPENAI_COMPAT_API_KEY",
headers: { "X-Custom-Header": "value" }
}
}
}
}
หากไม่ต้องการตั้งค่าคีย์APIให้ใช้memorySearch.provider = "local"หรือกำหนดmemorySearch.fallback = "none".
การถอยกลับ:
memorySearch.fallbackสามารถเป็นopenai,gemini,localหรือnone.- ผู้ให้บริการถอยกลับจะถูกใช้เฉพาะเมื่อผู้ให้บริการการฝังหลักล้มเหลว
การทำดัชนีแบบแบตช์(OpenAI+Gemini):
- Enabled by default for OpenAI and Gemini embeddings. เปิดใช้งานเป็นค่าเริ่มต้นสำหรับการฝังOpenAIและGeminiตั้งค่า
agents.defaults.memorySearch.remote.batch.enabled = falseเพื่อปิด - พฤติกรรมค่าเริ่มต้นจะรอให้แบตช์เสร็จสิ้นปรับ
remote.batch.wait,remote.batch.pollIntervalMsและremote.batch.timeoutMinutesหากจำเป็น - ตั้งค่า
remote.batch.concurrencyเพื่อควบคุมจำนวนงานแบตช์ที่ส่งพร้อมกัน(ค่าเริ่มต้น:2) - โหมดแบตช์ใช้เมื่อ
memorySearch.provider = "openai"หรือ"gemini"และใช้คีย์APIที่สอดคล้องกัน - งานแบตช์Geminiใช้เอนด์พอยต์แบตช์การฝังแบบอะซิงก์และต้องมีความพร้อมของGemini Batch API
เหตุใดแบตช์OpenAIจึงเร็วและถูก:
- สำหรับการเติมข้อมูลย้อนกลับขนาดใหญ่OpenAIมักเป็นตัวเลือกที่เร็วที่สุดที่เรารองรับเพราะสามารถส่งคำขอการฝังจำนวนมากในงานแบตช์เดียวและปล่อยให้OpenAIประมวลผลแบบอะซิงก์
- OpenAIมีราคาลดสำหรับงานBatch APIดังนั้นการทำดัชนีขนาดใหญ่จึงมักถูกกว่าส่งคำขอเดียวกันแบบซิงก์
- ดูเอกสารและราคาOpenAI Batch API:
- https://platform.openai.com/docs/api-reference/batch
- https://platform.openai.com/pricing
ตัวอย่างคอนฟิก:
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
fallback: "openai",
remote: {
batch: { enabled: true, concurrency: 2 }
},
sync: { watch: true }
}
}
}
เครื่องมือ:
memory_search— คืนสแนิปเพ็ตพร้อมไฟล์+ช่วงบรรทัดmemory_get— อ่านเนื้อหาไฟล์หน่วยความจำตามพาธ
โหมดโลคัล:
- ตั้งค่า
agents.defaults.memorySearch.provider = "local" - ระบุ
agents.defaults.memorySearch.local.modelPath(GGUFหรือhf:URI) - ไม่บังคับ:ตั้งค่า
agents.defaults.memorySearch.fallback = "none"เพื่อหลีกเลี่ยงการถอยกลับไปรีโมต
เครื่องมือหน่วยความจำทำงานอย่างไร¶
memory_searchsemantically searches Markdown chunks (~400 token target, 80-token overlap) fromMEMORY.md+memory/**/*.md. It returns snippet text (capped ~700 chars), file path, line range, score, provider/model, and whether we fell back from local → remote embeddings. No full file payload is returned.memory_getอ่านไฟล์Markdownหน่วยความจำเฉพาะ(สัมพันธ์กับเวิร์กสเปซ)เลือกได้จากบรรทัดเริ่มต้นและจำนวนบรรทัดNพาธนอกMEMORY.md/memory/จะถูกปฏิเสธ Paths outsideMEMORY.md/memory/are rejected.- เครื่องมือทั้งสองเปิดใช้งานเฉพาะเมื่อ
memorySearch.enabledประเมินเป็นจริงสำหรับเอเจนต์
สิ่งที่ถูกทำดัชนี(และเมื่อใด)¶
- ประเภทไฟล์:เฉพาะMarkdown(
MEMORY.md,memory/**/*.md) - ที่เก็บดัชนี:SQLiteต่อเอเจนต์ที่
~/.openclaw/memory/<agentId>.sqlite(ตั้งค่าได้ผ่านagents.defaults.memorySearch.store.path,รองรับโทเคน{agentId}) - Freshness: watcher on
MEMORY.md+memory/marks the index dirty (debounce 1.5s). Sync is scheduled on session start, on search, or on an interval and runs asynchronously. Session transcripts use delta thresholds to trigger background sync. - ทริกเกอร์การทำดัชนีใหม่:ดัชนีเก็บลายนิ้วมือของผู้ให้บริการ/โมเดลการฝัง+เอนด์พอยต์+พารามิเตอร์การตัดชิ้นหากสิ่งใดเปลี่ยนOpenClawจะรีเซ็ตและทำดัชนีใหม่ทั้งหมดโดยอัตโนมัติ If any of those change, OpenClaw automatically resets and reindexes the entire store.
การค้นหาไฮบริด(BM25+เวกเตอร์)¶
เมื่อเปิดใช้งานOpenClawจะผสาน:
- ความคล้ายคลึงของเวกเตอร์(จับคู่เชิงความหมายถ้อยคำอาจต่างกัน)
- ความเกี่ยวข้องของคีย์เวิร์ดBM25(โทเคนตรงเช่นIDตัวแปรสภาพแวดล้อมสัญลักษณ์โค้ด)
หากการค้นหาแบบข้อความเต็มไม่พร้อมใช้งานบนแพลตฟอร์มของคุณOpenClawจะถอยกลับเป็นการค้นหาเวกเตอร์อย่างเดียว
ทำไมต้องไฮบริด?¶
การค้นหาเวกเตอร์เก่งด้าน“ความหมายเดียวกัน”:
- “Mac Studio gateway host”เทียบกับ“เครื่องที่รันเกตเวย์”
- “debounce file updates”เทียบกับ“หลีกเลี่ยงการทำดัชนีทุกครั้งที่เขียน”
แต่จะอ่อนกับโทเคนที่ตรงและมีสัญญาณสูง:
- ID(
a828e60,b3b9895a…) - สัญลักษณ์โค้ด(
memorySearch.query.hybrid) - สตริงข้อผิดพลาด(“sqlite-vec unavailable”)
BM25 (full-text) is the opposite: strong at exact tokens, weaker at paraphrases. BM25(ข้อความเต็ม)ตรงข้าม:เก่งโทเคนตรงอ่อนกับการถอดความ การค้นหาไฮบริดคือจุดกึ่งกลางเชิงปฏิบัติ: ใช้สัญญาณการดึงข้อมูลทั้งสองเพื่อให้ได้ผลลัพธ์ที่ดีทั้งคิวรีภาษาธรรมชาติและคิวรีแบบ“เข็มในกองฟาง”
วิธีรวมผลลัพธ์(ดีไซน์ปัจจุบัน)¶
Implementation sketch:
- ดึงพูลผู้สมัครจากทั้งสองฝั่ง:
- เวกเตอร์:อันดับบน
maxResults * candidateMultiplierตามcosine similarity - BM25:อันดับบน
maxResults * candidateMultiplierตามอันดับFTS5 BM25(ยิ่งต่ำยิ่งดี)
- แปลงอันดับBM25เป็นคะแนนประมาณ0..1:
textScore = 1 / (1 + max(0, bm25Rank))
- รวมผู้สมัครตามchunk idและคำนวณคะแนนถ่วงน้ำหนัก:
finalScore = vectorWeight * vectorScore + textWeight * textScore
หมายเหตุ:
vectorWeight+textWeightถูกทำให้เป็น1.0ในการแก้ไขคอนฟิกดังนั้นน้ำหนักจึงทำงานเหมือนเปอร์เซ็นต์- หากการฝังไม่พร้อมใช้งาน(หรือผู้ให้บริการคืนเวกเตอร์ศูนย์)เรายังคงรันBM25และคืนผลลัพธ์คีย์เวิร์ด
- หากไม่สามารถสร้างFTS5ได้เราจะคงการค้นหาเวกเตอร์อย่างเดียว(ไม่ล้มเหลวแบบฮาร์ด)
This isn’t “IR-theory perfect”, but it’s simple, fast, and tends to improve recall/precision on real notes. นี่ไม่ใช่“สมบูรณ์แบบตามทฤษฎีIR”แต่เรียบง่ายเร็วและมักปรับปรุงrecall/precisionกับโน้ตจริง หากต้องการซับซ้อนขึ้นในอนาคตขั้นถัดไปทั่วไปคือReciprocal Rank Fusion(RRF)หรือการทำ normalizationของคะแนน (min/maxหรือz-score)ก่อนผสม
คอนฟิก:
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
enabled: true,
vectorWeight: 0.7,
textWeight: 0.3,
candidateMultiplier: 4
}
}
}
}
}
แคชการฝัง¶
OpenClawสามารถแคชการฝังของชิ้นส่วนในSQLiteเพื่อให้การทำดัชนีใหม่และการอัปเดตบ่อย(โดยเฉพาะทรานสคริปต์เซสชัน)ไม่ต้องฝังข้อความที่ไม่เปลี่ยนซ้ำ
คอนฟิก:
agents: {
defaults: {
memorySearch: {
cache: {
enabled: true,
maxEntries: 50000
}
}
}
}
การค้นหาหน่วยความจำเซสชัน(ทดลอง)¶
คุณสามารถเลือกทำดัชนีทรานสคริปต์เซสชันและแสดงผ่านmemory_searchได้
ฟีเจอร์นี้ถูกกั้นด้วยแฟล็กทดลอง
This is gated behind an experimental flag.
agents: {
defaults: {
memorySearch: {
experimental: { sessionMemory: true },
sources: ["memory", "sessions"]
}
}
}
หมายเหตุ:
- การทำดัชนีเซสชันเป็นแบบเลือกใช้(ปิดเป็นค่าเริ่มต้น)
- การอัปเดตเซสชันถูกdebounceและทำดัชนีแบบอะซิงก์เมื่อข้ามเกณฑ์เดลต้า(พยายามอย่างดีที่สุด)
memory_searchไม่บล็อกการทำดัชนีผลลัพธ์อาจล้าหลังเล็กน้อยจนกว่าการซิงก์เบื้องหลังจะเสร็จ- ผลลัพธ์ยังคงเป็นสแนิปเพ็ตเท่านั้น;
memory_getยังคงจำกัดที่ไฟล์หน่วยความจำ - การทำดัชนีเซสชันแยกต่อเอเจนต์(ทำดัชนีเฉพาะบันทึกเซสชันของเอเจนต์นั้น)
- Session logs live on disk (
~/.openclaw/agents/<agentId>/sessions/*.jsonl). บันทึกเซสชันอยู่บนดิสก์(~/.openclaw/agents/<agentId>/sessions/*.jsonl)กระบวนการ/ผู้ใช้ใดที่เข้าถึงไฟล์ระบบได้สามารถอ่านได้ดังนั้นให้ถือว่าการเข้าถึงดิสก์คือขอบเขตความเชื่อถือเพื่อการแยกที่เข้มงวดขึ้นให้รันเอเจนต์ภายใต้ผู้ใช้OSหรือโฮสต์แยกกัน For stricter isolation, run agents under separate OS users or hosts.
เกณฑ์เดลต้า(ค่าเริ่มต้นแสดง):
agents: {
defaults: {
memorySearch: {
sync: {
sessions: {
deltaBytes: 100000, // ~100 KB
deltaMessages: 50 // JSONL lines
}
}
}
}
}
การเร่งเวกเตอร์SQLite(sqlite-vec)¶
เมื่อมีส่วนขยายsqlite-vecOpenClawจะเก็บการฝังในตารางเสมือนSQLite(vec0)และทำคิวรีระยะเวกเตอร์ในฐานข้อมูลช่วยให้การค้นหาเร็วโดยไม่ต้องโหลดการฝังทั้งหมดเข้าJS This keeps search fast without loading every embedding into JS.
การกำหนดค่า(ไม่บังคับ):
agents: {
defaults: {
memorySearch: {
store: {
vector: {
enabled: true,
extensionPath: "/path/to/sqlite-vec"
}
}
}
}
}
หมายเหตุ:
enabledค่าเริ่มต้นเป็นtrue;เมื่อปิดการค้นหาจะถอยกลับไปใช้cosine similarityในโปรเซสเหนือการฝังที่เก็บไว้- หากส่วนขยายsqlite-vecหายไปหรือโหลดไม่สำเร็จOpenClawจะบันทึกข้อผิดพลาดและทำงานต่อด้วยทางเลือกJS(ไม่มีตารางเวกเตอร์)
extensionPathแทนที่พาธsqlite-vecที่มาพร้อม(มีประโยชน์สำหรับบิลด์กำหนดเองหรือที่ติดตั้งไม่มาตรฐาน)
การดาวน์โหลดการฝังโลคัลอัตโนมัติ¶
- โมเดลการฝังโลคัลค่าเริ่มต้น:
hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(~0.6GB) - เมื่อ
memorySearch.provider = "local",node-llama-cppแก้ไขเป็นmodelPath;หากไม่มีGGUFจะดาวน์โหลดอัตโนมัติไปยังแคช(หรือlocal.modelCacheDirหากตั้งค่า)จากนั้นโหลดการดาวน์โหลดจะต่อเมื่อพยายามใหม่ Downloads resume on retry. - ข้อกำหนดบิลด์เนทีฟ:รัน
pnpm approve-builds,เลือกnode-llama-cpp,จากนั้นpnpm rebuild node-llama-cpp - การถอยกลับ:หากการตั้งค่าโลคัลล้มเหลวและ
memorySearch.fallback = "openai"เราจะสลับไปใช้การฝังแบบรีโมตโดยอัตโนมัติ(openai/text-embedding-3-smallเว้นแต่มีการแทนที่)และบันทึกเหตุผล
ตัวอย่างเอนด์พอยต์ที่เข้ากันได้กับOpenAIแบบกำหนดเอง¶
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
baseUrl: "https://api.example.com/v1/",
apiKey: "YOUR_REMOTE_API_KEY",
headers: {
"X-Organization": "org-id",
"X-Project": "project-id"
}
}
}
}
}
หมายเหตุ:
remote.*มีลำดับความสำคัญเหนือmodels.providers.openai.*remote.headersผสานกับเฮดเดอร์OpenAI;ฝั่งรีโมตชนะเมื่อคีย์ชนกันละremote.headersออกเพื่อใช้ค่าเริ่มต้นของOpenAI Omitremote.headersto use the OpenAI defaults.