สัปดาห์ที่เราให้หน่วยความจำระยะยาวจริง ๆ แก่ agent ของเรา การเรียกคืนกลับแย่ลง

ไม่ใช่ทันที วันแรกเหมือนมีเวทมนตร์ — agent จำรายละเอียดการ deploy จากเซสชันวันจันทร์ได้ในวันพุธ โดยไม่ต้องอธิบายซ้ำ พอจบสัปดาห์ที่สอง มันกลับคืนโน้ตที่เกือบเหมือนกันห้ารายการสำหรับ "เราจัดการ rate-limiting อย่างไร" แต่ละอันผิดนิดหน่อย และไม่มีอันไหนเป็นอันที่ผมต้องการจริง ๆ เลย agent เรียก memorize อย่างขยันขันแข็งกับทุกการสังเกต ทุกทางตัน ทุกการคาดเดาที่ยังไม่สุก มันสร้างลิ้นชักขยะให้ตัวเองและตอนนี้กำลังรื้อค้นในนั้นทุกครั้งที่มี query

นี่คือส่วนของ "ให้หน่วยความจำแก่ agent ของคุณ" ที่ไม่มีใครเตือน หน่วยความจำที่มีแต่โตขึ้นไม่ใช่หน่วยความจำ — มันคือ log และ log ที่คุณค้นด้วยความหมายจะ มีสัญญาณรบกวนมากขึ้น เมื่อมันโต เพราะทุกรายการที่เกือบซ้ำซึ่งคุณเก็บไว้แย่งชิงส่วนเดียวกันของการจัดอันดับ ยิ่งมีความทรงจำมาก การเรียกคืนยิ่งแย่ ตรงกันข้ามกับสิ่งที่คุณตกลงไว้พอดี

Octobrain คือทางแก้แบบโอเพนซอร์สของเราสำหรับเรื่องนี้ — เซิร์ฟเวอร์หน่วยความจำ MCP ที่เขียนด้วย Rust ซึ่งให้หน่วยความจำระยะยาวแบบถาวรและค้นได้ด้วยความหมายแก่ agent ใด ๆ เราแนะนำมันไปตั้งแต่เดือนเมษายน และในรีลีส 0.7.0 หน่วยความจำได้เรียนรู้ที่จะลืม บทความนี้คือคู่มือที่ผมอยากจะมีตั้งแต่แรก: วิธีตั้งค่าหน่วยความจำ LLM แบบถาวรที่ยังคมชัด โดยใช้สองแนวคิด — กำหนดขอบเขตต่อโปรเจกต์ และปล่อยให้มันรวมข้อมูลเอง — บวกกับคำถามเชิงปฏิบัติว่าควรเก็บอะไรและควรปล่อยอะไรไว้


ปัญหาที่แท้จริงคือการเรียกคืน ไม่ใช่การจัดเก็บ

การเก็บของนั้นง่าย key-value store ใด ๆ ก็ทำได้ ส่วนที่ยากของหน่วยความจำระยะยาวของ agent คือส่วนที่ยากเดียวกับหน่วยความจำของมนุษย์: ดึงสิ่งที่ ถูกต้อง กลับมาในช่วงเวลาที่ ถูกต้อง จากกองที่ไม่เคยหยุดโต

Octobrain ดึงข้อมูลด้วยความหมาย ไม่ใช่คีย์เวิร์ด เบื้องหลังมันฝัง (embed) ความทรงจำทุกอันลงในเวกเตอร์ด้วยโมเดลภายในเครื่อง (ค่าเริ่มต้นคือ fastembed:nomic-ai/nomic-embed-text-v1.5 ขนาด 768 มิติ ทำงานบน CPU ไม่ต้องมี API key) แล้วเก็บไว้ในฐานข้อมูลเวกเตอร์ LanceDB บนดิสก์ query remember จะถูกฝังด้วยวิธีเดียวกัน แล้วเวกเตอร์ที่ใกล้ที่สุดจะถูกส่งกลับมา เพื่อไม่ให้การค้นแบบความหมายล้วนพลาดสตริงที่ตรงเป๊ะ การค้นจึงเป็นแบบ ไฮบริด: ข้อความเต็ม BM25 และความคล้ายเวกเตอร์ถูกรวมกันด้วย Reciprocal Rank Fusion ด้านบนยังมีการจัดอันดับใหม่ด้วย cross-encoder แบบเลือกได้

กลไกนี้ดี บนเบนช์มาร์ก SciFact ของ BEIR การดึงข้อมูลแบบไฮบริดของ Octobrain ได้คะแนน 0.742 nDCG@10 เทียบกับ 0.665 ของ BM25 แบบคลาสสิกและ 0.713 ของ embedding เปล่า — การรวมเพิ่มราว +2 nDCG@10 เหนือ embedder เพียงอย่างเดียว คุณภาพการดึงข้อมูลไม่เคยเป็นคอขวดเลย

คอขวดคือ สิ่งที่เราป้อนเข้าไป โน้ตห้าอันที่ทับซ้อนกันเกี่ยวกับบั๊กเดียวกันไม่ได้ทำให้อันใดอันหนึ่งอันดับสูงขึ้น มันแบ่งสัญญาณ การดึงข้อมูลที่ดีบน corpus ที่มีสัญญาณรบกวนก็ยังให้คำตอบที่มีสัญญาณรบกวนอยู่ดี ดังนั้นทางแก้จึงไม่ใช่ embedder ที่ดีกว่า แต่คือการดูแล corpus — แบบอัตโนมัติ เพราะไม่มีมนุษย์คนไหนจะมานั่งตัดแต่งหน่วยความจำของ agent ด้วยมือ


แนวคิดที่หนึ่ง: กำหนดขอบเขตหน่วยความจำต่อโปรเจกต์

แหล่งสัญญาณรบกวนแรกคือการปนเปื้อนข้ามโปรเจกต์ หากไม่มีการแยก ความทรงจำของทุกโปรเจกต์จะอยู่ในแอ่งเดียวกัน และ query เรื่อง "auth flow" ในเว็บแอปของคุณก็จะลากโน้ต auth จากสามบริการที่ไม่เกี่ยวข้องเข้ามาด้วย

Octobrain แยกความทรงจำตาม ขอบเขต (scope) ขอบเขตคือสตริง และโดยค่าเริ่มต้นจะถูกอนุมานจาก git remote ของคุณ เปิด repository ของบล็อกนี้เองแล้วขอบเขตคือ github.com/muvon/muvon-web การอนุมานเป็นอย่างที่คุณคงเดาได้พอดี:

git remote get-url origin  →  host/org/repo

ดังนั้น [email protected]:muvon/octobrain.git จึงกลายเป็น github.com/muvon/octobrain ไม่มี git remote? มันจะถอยไปใช้ขอบเขตแบบอิงพาธ local/<parent>/<dir> เพื่อให้แม้แต่ไดเรกทอรีทดลองก็ยังได้รับการแยก และมีขอบเขตสงวนหนึ่งอัน — สตริงว่าง "" — สำหรับความทรงจำ global ที่ควรมองเห็นได้ทุกที่

การแบ่ง global/project นั้นคือโมเดลความคิดทั้งหมด และมันสอดคล้องกับความแตกต่างที่เป็นจริง:

ขอบเขต เก็บที่นี่ ตัวอย่าง
โปรเจกต์ (github.com/org/repo) ข้อเท็จจริงที่จริง ภายใน repository นี้ "เทสต์รันด้วย pnpm -r test:unit", "staging API ต้องมี header X-Acme-Token", "ที่นี่เราเลือก rate limiting แบบ token-bucket"
Global ("") ข้อเท็จจริงที่จริง เกี่ยวกับคุณ ทุกที่ "ชอบ tab", "ต้องการข้อความคอมมิตแบบ conventional เสมอ", "ใช้ fish ไม่ใช่ bash"

ผลตอบแทน: เมื่อ agent ของคุณรันใน repository ของบล็อก การเรียก remember จะจัดอันดับเฉพาะกับความทรงจำของ repository บล็อกบวกกับค่าที่คุณตั้งไว้แบบ global เท่านั้น โน้ต auth จากบริการอื่นนั้นไม่อยู่ในชุดผู้เข้าชิงเลย ผู้เข้าชิงสะอาดกว่า การเรียกคืนคมชัดกว่า — ก่อนที่การรวมข้อมูลใด ๆ จะทำงานเสียอีก

ขอบเขตถูกกำหนดอย่างไร

หากคุณขับ Octobrain ผ่าน MCP client ที่ทำ handshake ของเซสชัน ขอบเขตจะถูกล็อกจากไดเรกทอรีทำงานโดยอัตโนมัติ — agent ไม่ต้องคิดเรื่องนี้เลย และพารามิเตอร์ scope จะถูกถอดออกจากสคีมาของเครื่องมือทั้งหมดเพื่อไม่ให้มันทำพลาดได้ เซิร์ฟเวอร์ยังประกาศขอบเขตที่ใช้ได้ในคำสั่งของ MCP ด้วยซ้ำ:

Available project scopes (pass as the 'scope' parameter):
  github.com/muvon/muvon-web

เมื่อเซสชัน ไม่ได้ ถูกล็อก เครื่องมือจะเปิด scope ออกมาตรง ๆ และ memorize จะรับแฟล็ก global: true เพื่อจงใจวางข้อเท็จจริงลงในขอบเขตที่ใช้ร่วมกันไม่ว่าคุณจะอยู่ที่ไหน แฟล็กนั้นจะปรากฏก็ต่อเมื่อมีขอบเขตโปรเจกต์ที่ถูกล็อกให้ override เท่านั้น มิฉะนั้นคุณก็แค่ส่ง scope: "" เอง คำแนะนำที่ฝังอยู่ในคำอธิบายเครื่องมือนั้นตรงไปตรงมา: ใช้ global สำหรับข้อเท็จจริงข้ามโปรเจกต์อย่างค่าที่ตั้งและธรรมเนียมปฏิบัติ; อย่า ใช้สำหรับความรู้เฉพาะโปรเจกต์ การรั่วของขอบเขตคือสัญญาณรบกวนที่คุณพยายามหลีกเลี่ยง


พื้นผิวเครื่องมือที่คุณเรียกใช้จริง

Octobrain จงใจเปิดพื้นผิว MCP ขนาดเล็ก ทุกเครื่องมือที่คุณเปิดมีค่าใช้จ่ายในแง่ context ของ agent ใน ทุกเทิร์น — มันอ่านสคีมาก่อนทำอะไรก็ตาม — ดังนั้นรีลีส 0.7.0 จึงลดพื้นผิวลง และ 0.8.0 ก็คงความเบาไว้ สี่เครื่องมือ สี่งาน:

memorize    เก็บความทรงจำ (พร้อมความสัมพันธ์แบบ inline ได้)
remember    การเรียกคืนเชิงความหมาย (คืนเพื่อนบ้านในกราฟระยะ 1 hop)
forget      ลบ (ต้องมี confirm=true)
knowledge   ทำดัชนี/ค้น/อ่าน/จับคู่เอกสารและ URL ภายนอก

memorize

คำกริยาสำหรับการเก็บ จำเป็น: title (5–200 ตัวอักษร) และ content (10–10000 ตัวอักษร) ที่เหลือเป็นทางเลือกแต่ควรเข้าใจ:

  • memory_type — หมวดหมู่อย่าง architecture, bug_fix, decision, user_preference, goal ใช้สำหรับกรองในการเรียกคืน
  • importance — 0.0–1.0 คำอธิบายเครื่องมือให้จุดยึดที่เป็นจริง: ข้อเท็จจริงที่ผู้ใช้ระบุ 0.8–1.0, การตัดสินใจ 0.7–0.9, การแก้บั๊ก 0.6–0.8, การอนุมานของ AI 0.3–0.6
  • source — ระดับความเชื่อถือ ได้แก่ user_confirmed (ผู้ใช้พูดอย่างชัดเจน) หรือ agent_inferred (agent สรุปเอง) นี่ไม่ใช่แค่ความสวยงาม: ข้อเท็จจริงที่ยืนยันแล้วจัดอันดับสูงกว่าในการดึงข้อมูล และผลลัพธ์กลับมาพร้อมป้าย [CONFIRMED] / [INFERRED] เพื่อให้ agent รู้ว่าควรเชื่อถือแต่ละอันมากแค่ไหน
  • tags, related_files — สำหรับการกรองและการผูกความทรงจำกับโค้ดที่มันอธิบาย
  • related_to — อันที่น่าสนใจ อาเรย์ของลิงก์แบบมีชนิดไปยังความทรงจำที่ มีอยู่แล้ว สร้างในการเรียกครั้งเดียวกัน นี่คือวิธีสร้างกราฟโดยไม่ต้องไป-กลับรอบที่สอง

ตัวอย่างการเก็บที่เป็นรูปธรรม อย่างที่ agent จะส่งออกมา:

{
	"title": "Rate limiting uses a token bucket",
	"content": "We rate-limit the public API with a token bucket (100 req/min/key), returning 429 + Retry-After on exhaustion. Chosen over fixed-window to avoid burst-at-boundary.",
	"memory_type": "decision",
	"importance": 0.85,
	"source": "user_confirmed",
	"tags": ["api", "rate-limiting"],
	"related_files": ["src/middleware/ratelimit.rs"]
}

remember

คำกริยาสำหรับการเรียกคืน และเป็นอันที่คุณควรเรียก ก่อน — ก่อน memorize (เพื่อเลี่ยงการเก็บซ้ำ) และตอนเริ่มงาน (เพื่อโหลด context) มันรับ query ที่เป็นได้ทั้งสตริงเดี่ยว หรือดีกว่านั้นคืออาเรย์ของคำที่เกี่ยวข้อง 2–5 คำเพื่อความครอบคลุมเชิงความหมายที่กว้างขึ้น มันคืนผลลัพธ์ที่ตรงที่สุด พร้อมกับ เพื่อนบ้านในกราฟที่อยู่ติดกันโดยอัตโนมัติ ดังนั้นการตรงกับความทรงจำหนึ่งจะดึงความทรงจำที่เชื่อมโยงกับมันขึ้นมาด้วย

มันยังรับตัวกรองที่ใช้งานได้จริงในรีลีสล่าสุด: created_after / created_before (ISO-8601) สำหรับคำถามเชิงเวลาอย่าง "เราตัดสินใจอะไรเมื่อสัปดาห์ก่อน", min_relevance สำหรับเกณฑ์คุณภาพขั้นต่ำ และ memory_types / tags สำหรับการจำกัด การขยาย query ที่ช่วยกู้คำถามคลุมเครือ — pseudo-relevance feedback แบบ HyDE-lite ของ Octobrain — ทำงานอัตโนมัติและเพิ่มการเรียกคืนตามที่อ้างไว้ +10–30% บน query แบบ long-tail โดยไม่ต้องมี LLM และไม่ต้องตั้งค่า

forget

การลบถาวร ต้องมี confirm: true — ไม่มีการลืมโดยบังเอิญ ลบด้วย memory_id สำหรับอันเดียว หรือด้วย query + ตัวกรองสำหรับการกวาดเป็นจำนวนมาก คำอธิบายเครื่องมือมีกฎที่ควรซึมซับไว้: อย่าลืมความทรงจำเพียงเพราะมันเก่า — การเสื่อม (decay) จัดการเรื่องนั้น (อยู่ด้านล่าง) ใช้ forget ก็ต่อเมื่อบางอย่าง ผิด จริง ๆ หรือถูกแทนที่ไปแล้ว

knowledge

อีกครึ่งหนึ่งของหน่วยความจำ: เอกสารภายนอก memorize มีไว้สำหรับข้อคิดที่กลั่นกรองซึ่ง agent ผลิตขึ้น; knowledge มีไว้สำหรับวัสดุต้นทางที่ agent อ่าน ห้าคำสั่ง ส่งผ่านฟิลด์ command:

# ทำดัชนีและค้นในแหล่งเดียว (ทำดัชนีทันที)
knowledge command=search query="how to handle async tasks" source=https://docs.rs/tokio/

# อ่านข้อความเต็มของไฟล์หรือ URL หนึ่ง (ทางเลือกสุดท้ายเมื่อการค้นได้ผลน้อย)
knowledge command=read source=/path/to/design-doc.md

# grep เนื้อหาที่ทำดัชนีแล้วด้วย regex
knowledge command=match pattern="spawn_blocking|block_in_place"

# เก็บและลบข้อความดิบภายใต้คีย์ (ขอบเขตเซสชัน)
knowledge command=store key=meeting-notes content="..."
knowledge command=delete key=meeting-notes

มีกฎเข้มข้นหนึ่งข้อที่สคีมาบังคับและเซิร์ฟเวอร์ย้ำในคำสั่งของมัน: source คือไฟล์หรือ URL เดียวเสมอ ไม่ใช่ไดเรกทอรี หากส่งไดเรกทอรีเข้าไป มันจะถูกปฏิเสธ ชนิดที่รองรับคือ .html, .txt, .md, .pdf, .docx รวมถึง URL แบบ http/https


แนวคิดที่สอง: ปล่อยให้หน่วยความจำรวมข้อมูลด้วยตัวเอง

การกำหนดขอบเขตตัดสัญญาณรบกวนข้ามโปรเจกต์ แต่ไม่ได้ทำอะไรกับปัญหาโน้ตเกือบซ้ำห้าอันในโปรเจกต์เดียว นั่นคือสิ่งที่การรวมข้อมูลมีไว้ และทางเลือกการออกแบบสำคัญใน 0.7.0 คือการทำให้มัน เป็นอิสระอัตโนมัติ — เพราะสิ่งหนึ่งที่คุณพึ่งพาไม่ได้คือการที่ agent (หรือมนุษย์) จะจำได้ว่าต้องเก็บกวาด

การรวมข้อมูลแบบหลับ (sleep consolidation)

เมื่อเริ่มทำงาน หากผ่านไปหนึ่งวันนับจากรอบก่อน Octobrain จะรันรอบ "หลับ": มันหากลุ่มของความทรงจำที่คล้ายกัน เพิ่งสร้าง และยังอยู่สถานะ Working แล้วพับแต่ละกลุ่มเป็นข้อคิดที่รวมแล้วหนึ่งอัน ต้นฉบับไม่ได้ถูกลบ — มันเปลี่ยนไปสู่สถานะ Consolidated ด้วยความสำคัญที่ถูกลดทอน เชื่อมไว้ใต้ parent ใหม่ในฐานะที่มา โน้ตคลุมเครือห้าอันเรื่อง rate-limiting กลายเป็นความทรงจำเดียวที่สะอาดและมั่นใจสูงขึ้น และร่องรอยย้อนกลับไปยังโน้ตดิบยังคงอยู่เพื่อการตรวจสอบ

มันถูกควบคุมด้วยไฟล์ marker จึงเป็นแบบ lazy ไม่ใช่ cron หรือ scheduler เบื้องหลัง และรอบที่ช้าหรือล้มเหลวไม่เคยขวางอะไร ค่าเริ่มต้นเป็นแบบระมัดระวัง:

[memory]
sleep_consolidation_enabled          = true   # opt-out, not opt-in
sleep_consolidation_interval_hours   = 24     # at most once a day
sleep_consolidation_threshold        = 0.85   # cosine similarity to cluster
sleep_consolidation_min_cluster_size = 3      # need 3+ to bother
sleep_consolidation_max_age_days     = 7      # only recent Working memories

คุณสามารถบังคับรอบจาก CLI เพื่อทดสอบได้ — octobrain memory sleep-consolidate --threshold 0.85 --min-size 3 — แต่ประเด็นคือคุณไม่ต้องทำเลย

การรวมข้อมูลที่ยึดเป้าหมาย (goal-anchored)

การรวมข้อมูลแบบหลับจับกลุ่มตาม ความคล้าย เวอร์ชันที่คมกว่าจับกลุ่มตาม เจตนา Octobrain มีชนิดความทรงจำ goal และวงจรชีวิตจริง — Working → Consolidated → Archived ขั้นตอนทำงาน ซึ่งทั้งหมดแสดงผ่านลิงก์ related_to ของ memorize คือ:

  1. memorize ความทรงจำชนิด goal ที่จับสิ่งที่คุณพยายามจะทำ
  2. สำหรับทุกการค้นพบระหว่างทาง memorize ด้วย related_to: [{ target_id: <goal_id>, relationship_type: "achieves" }]
  3. เมื่องานปิดลง memorize โน้ตบทเรียนที่ได้เรียนรู้ด้วย relationship_type: "closes"

ลิงก์ closes นั้นจะ trigger การรวมข้อมูลโดยอัตโนมัติ — ไม่ต้องเรียกเครื่องมือแยก โน้ตปิดท้ายจะกลายเป็น parent ที่รวมแล้ว (ความสำคัญถูกดันขึ้นเป็น max(sources) * 1.1) และทุกแหล่ง achieves จะเปลี่ยนไปสู่สถานะ Consolidated ด้วยความสำคัญที่ถูกลดทอน ยังคงค้นได้เพื่อร่องรอยการตรวจสอบ การค้นพบที่กระจัดกระจายห้าอันยุบรวมเป็นความทรงจำเดียวที่มีความหมาย ยึดกับเจตนาที่สร้างมันขึ้นมา

นี่ยังอธิบายว่าทำไมเครื่องมือ consolidate แบบแยกจึงไม่อยู่ในพื้นผิว MCP อีกต่อไป: การปิดเป้าหมายตอนนี้เป็นแค่ memorize ที่มีลิงก์ closes และการรวมข้อมูลแบบหลับก็รันเอง เครื่องมือน้อยลง พลังเท่าเดิม (คำสั่ง CLI octobrain memory consolidate <goal-id> ยังอยู่สำหรับการใช้งานแบบ manual และการดูแลระบบ)

การเสื่อมแบบครึ่งชีวิต: การลืมในฐานะสัญญาณจัดอันดับ

กลไกที่สามทำงานต่อเนื่อง ความสำคัญของทุกความทรงจำเสื่อมลงตามตารางครึ่งชีวิตแบบ Ebbinghaus — และทุกครั้งที่คุณเข้าถึงความทรงจำ มันจะได้รับการเสริมแรง ความทรงจำที่ถูกเรียกคืนบ่อยจะยังคงแข็งแรง ส่วนอันที่ไม่มีอะไรไปแตะจะค่อย ๆ จางในการจัดอันดับ

[memory]
decay_enabled            = true
decay_half_life_days     = 90    # higher = memories stay relevant longer
access_boost_factor      = 1.2   # reinforcement multiplier per access
min_importance_threshold = 0.05  # floor — decay never deletes

มีตัวกันสองอย่างที่ทำให้สิ่งนี้ปลอดภัย มี พื้น ของความสำคัญ — ความทรงจำที่เก่าจะจมไปด้านหลังแต่ไม่เคยหายไป เพราะการเสื่อมเป็นสัญญาณการจัดอันดับใหม่ ไม่ใช่การลบ และตัวนับการเข้าถึงคงอยู่ข้ามการรีสตาร์ต ดังนั้นความรู้สึกของหน่วยความจำว่า "อะไรกำลังมาแรง" จึงไม่รีเซ็ตทุกเซสชัน ผลสุทธิคือความทรงจำที่คุณใช้จริงลอยขึ้น ส่วนอันที่คุณเก็บครั้งเดียวแล้วไม่เคยต้องใช้จะจมลง โดยคุณไม่ต้องดูแลเลย นี่แหละคือเหตุผลที่เครื่องมือ forget บอก agent ว่า อย่า ลบสิ่งของเพียงเพราะมันเก่า — การเสื่อมจัดการเรื่องนั้นอยู่แล้ว อย่างนุ่มนวล โดยไม่สูญเสียประวัติ


ควรเก็บอะไร และควรปล่อยอะไรไว้

กลไกพาคุณไปได้แค่ระดับหนึ่ง วินัยที่แก้การเรียกคืนของเราคือการตัดสินว่าอะไร สมควร ได้รับความทรงจำ สัญชาตญาณของ agent คือเก็บทุกอย่าง นโยบายที่ถูกต้องใกล้เคียงกับสิ่งตรงข้าม

เก็บ:

  • การตัดสินใจและเหตุผลของมัน "เราเลือก token-bucket แทน fixed-window เพราะ burst-at-boundary" ทำไม คือส่วนที่แพงในการสร้างขึ้นใหม่
  • ข้อเท็จจริงที่ได้มายากเกี่ยวกับ repository นี้ คำสั่งเทสต์ที่ไม่ชัดเจน, header ของ staging, migration ที่ต้องรันก่อน สิ่งที่ agent มิฉะนั้นจะค้นพบใหม่ (หรือเดาใหม่) ทุกเซสชัน
  • ค่าที่ผู้ใช้ตั้ง — ในขอบเขต global พูดครั้งเดียว จริงทุกที่
  • การแก้บั๊กพร้อมสาเหตุที่แท้จริง ไม่ใช่ "แก้ webhook แล้ว" แต่ "การ retry ของ webhook ต้องมี idempotency key; หากไม่มี การ retry จะคิดเงินซ้ำ"

อย่าเก็บ:

  • สถานะชั่วคราว branch ปัจจุบัน, อะไรอยู่ใน working tree, เทสต์ไหนล้มเหลววันนี้ มันเก่าก่อนเซสชันถัดไปและเป็นสัญญาณรบกวนล้วน ๆ ตลอดไปหลังจากนั้น
  • อะไรก็ตามที่สร้างขึ้นใหม่ได้ง่าย ๆ หากคำสั่ง shell บรรทัดเดียวสร้างมันขึ้นมาใหม่ได้ คำสั่งนั้นแหละคือความทรงจำ — ไม่ใช่ผลลัพธ์ของมัน
  • การคาดเดาที่ยังไม่ตรวจสอบ ราวกับเป็นข้อเท็จจริง หาก agent ต้อง บันทึกลางสังหรณ์ นั่นคือสิ่งที่ source: agent_inferred และความสำคัญต่ำมีไว้ ติดป้ายความไม่แน่นอนไว้เพื่อให้การดึงข้อมูลจัดมันต่ำกว่าความรู้ที่ยืนยันแล้ว
  • ข้อคิดเดียวกันห้าครั้ง เรียก remember ก่อน memorize หากมีอันที่เกือบตรงกันกลับมา ให้อัปเดตหรือแทนที่มันแทนการกองอันที่เกือบซ้ำเพิ่มอีก

ประเด็นสุดท้ายนั้นมีเครื่องมือรองรับ เมื่อข้อเท็จจริงใหม่แทนที่อันเก่า — ค่าหนึ่งเปลี่ยนไป การตัดสินใจถูกกลับ — ให้ memorize ข้อเท็จจริงใหม่ด้วย related_to: [{ target_id: <old_id>, relationship_type: "supersedes" }] การดึงข้อมูลจะจัดข้อเท็จจริงปัจจุบันเหนืออันที่ล้าสมัย ซึ่งยังคงค้นได้เพื่อประวัติ คุณแก้บันทึกโดยไม่สูญเสียมันไป


การตั้งค่า

ติดตั้งแล้วชี้ MCP client มาที่มัน

# crates.io
cargo install octobrain

# หรือบน macOS ผ่าน Homebrew
brew install muvon/tap/octobrain

ลองวงรอบเต็มจาก CLI ก่อน:

octobrain memory memorize --title "API Design Pattern" \
  --content "Use REST for CRUD, GraphQL for complex queries" \
  --memory-type architecture --tags "api,design"

octobrain memory remember "how should I design APIs"

จากนั้นเชื่อมเข้ากับ MCP client สำหรับ Claude Desktop ให้เพิ่มลงใน claude_desktop_config.json:

{
	"mcpServers": {
		"octobrain": {
			"command": "/path/to/octobrain",
			"args": ["mcp"]
		}
	}
}

รัน octobrain mcp สำหรับ stdio หรือ octobrain mcp --bind 0.0.0.0:12345 สำหรับ HTTP ที่จัดเก็บอยู่ใน ~/.local/share/octobrain/ (macOS/Linux) หรือ %APPDATA%\octobrain\ (Windows) และความทรงจำของโปรเจกต์ถูกแยกตามขอบเขตตามที่อธิบายไว้ข้างต้น ทุกอย่างมีค่าเริ่มต้นที่สมเหตุสมผล — การรวมข้อมูลแบบหลับ, การเสื่อม, การค้นแบบไฮบริด และ HyDE เปิดอยู่ตั้งแต่แกะกล่อง ชุดปุ่มปรับทั้งหมดมีเอกสารใน config-templates/default.toml ใน repository

การตัดสินใจด้านการตั้งค่าหนึ่งเดียวที่คุ้มค่าจะทำอย่างจงใจคือ decay_half_life_days ค่าเริ่มต้น 90 วันเหมาะกับ codebase ที่ค่อย ๆ พัฒนาอย่างสม่ำเสมอ ตั้งให้สูงขึ้นสำหรับโปรเจกต์ที่เสถียรซึ่งการตัดสินใจยังใช้ได้ยาวนาน; ลดลงสำหรับ prototype ที่เปลี่ยนเร็วซึ่งความจริงของเดือนที่แล้วคือเรื่องโกหกของเดือนนี้


คำถามที่พบบ่อย

การลืมทำให้สูญเสียข้อมูลไหม?

ไม่ การเสื่อมเป็นสัญญาณจัดอันดับที่มีพื้น — ความทรงจำที่เข้าถึงน้อยจะจมแต่ไม่เคยถูกลบ การรวมข้อมูลย้ายแหล่งไปสู่สถานะ Consolidated ถูกลดทอนแต่ยังค้นได้ เชื่อมไว้ใต้ parent ในฐานะที่มา สิ่งเดียวที่ลบจริง ๆ คือ forget ที่ชัดแจ้งด้วย confirm: true คุณย้อนรอยกลับได้เสมอ

memorize ต่างจาก knowledge อย่างไร?

memorize เก็บข้อคิดที่ agent ผลิต — การตัดสินใจ, การแก้ไข, ข้อสรุป knowledge ทำดัชนีเอกสารที่ agent อ่าน — เอกสาร, ไฟล์ออกแบบ, URL — เพื่อให้มันค้นและอ้างอิงได้ ปัญญาที่กลั่นกรองแล้วกับวัสดุต้นทาง วงจรชีวิตต่างกัน เครื่องมือต่างกัน

ฉันต้องจัดการขอบเขตด้วยมือไหม?

โดยปกติไม่ต้อง ด้วย MCP client ที่ทำ handshake ของเซสชัน ขอบเขตจะถูกล็อกจาก git remote ของไดเรกทอรีทำงานของคุณ และพารามิเตอร์ scope จะถูกถอดออกจากสคีมา คุณแตะขอบเขตอย่างชัดแจ้งเฉพาะเพื่อเก็บค่าที่ตั้งแบบ global (global: true หรือ scope: "") เท่านั้น

ทำไมมีแค่สี่เครื่องมือ MCP? เซิร์ฟเวอร์หน่วยความจำอื่นเปิดเป็นโหล

เพราะทุกเครื่องมือที่คุณเปิดคือสคีมาที่โมเดลอ่านซ้ำในทุกเทิร์น และความแม่นยำในการเลือกเครื่องมือเสื่อมลงเมื่อแคตตาล็อกโต การรวมข้อมูลกลายเป็นอิสระอัตโนมัติ และ relate/consolidate ถูกพับเข้าไปในลิงก์ความสัมพันธ์ของ memorize ดังนั้นงานที่เคยต้องมีเครื่องมือของตัวเองตอนนี้จึงไม่ต้องแล้ว CLI ยังมีชุดเต็มสำหรับงานดูแลระบบ

ฉันต้องมี API key หรือ GPU ไหม?

ไม่ โมเดล embedding เริ่มต้นรันภายในเครื่องบน CPU ผ่าน fastembed — ไม่มีคีย์ ไม่มีเครือข่าย embedder บนคลาวด์ (Voyage, OpenAI, Google, Jina) รองรับหากคุณต้องการคุณภาพสูงขึ้น แต่เป็นทางเลือกเสริม


สิ่งที่แก้การเรียกคืนของเราไม่ใช่อัลกอริทึมการค้นที่ดีกว่า — การดึงข้อมูลของ Octobrain เอาชนะ BM25 บนเบนช์มาร์กอยู่แล้วในขณะที่เรากำลังจมน้ำ มันคือการยอมรับว่าหน่วยความจำต้องลืมเพื่อจะยังมีประโยชน์ กำหนดขอบเขตให้สิ่งที่ถูกต้องได้เป็น ผู้เข้าชิง ตั้งแต่แรก; ปล่อยให้มันรวมข้อมูลเพื่อให้รายการซ้ำยุบรวม; ปล่อยให้มันเสื่อมเพื่อให้น้ำหนักที่ตายแล้วจมลง แล้ว agent จะหยุดรื้อค้นในลิ้นชักขยะและเริ่มตอบจากหน่วยความจำ

เก็บการตัดสินใจและข้อเท็จจริงที่ได้มายาก ข้ามสัญญาณรบกวนชั่วคราว เรียก remember ก่อน memorize ที่เหลือปล่อยให้มันรันเอง

— Don


Octobrain เป็นโอเพนซอร์สภายใต้ Apache-2.0 กลไกการรวมข้อมูลและการเสื่อมที่อธิบายไว้ที่นี่มาในเวอร์ชัน 0.7.0; ระบบขอบเขตและพื้นผิวเครื่องมือที่เบาขึ้นต่อเนื่องมาถึง 0.8.0 หากรายละเอียดการตั้งค่าใดทำให้คุณสะดุด หรือคุณอยากให้เปลี่ยนค่าเริ่มต้นของขอบเขต/การเสื่อม เปิด issue — เราอ่านมัน