# แผนที่กับความทรงจำ: จับคู่การค้นหาโค้ดเชิงความหมายกับหน่วยความจำถาวรสำหรับเอเจนต์ AI

> การค้นหาโค้ดเชิงความหมายช่วยให้เอเจนต์ค้นเจอโค้ดที่ถูกต้อง หน่วยความจำถาวรช่วยให้มันจดจำการตัดสินใจเกี่ยวกับโค้ดนั้น ถ้าใช้แค่อย่างเดียว คุณจะได้เอเจนต์ที่อนุมานบริบทใหม่ทุกเซสชัน หรือจดจำข้อสรุปที่หาตำแหน่งในโค้ดไม่เจอ นี่คือวิธีเชื่อม Octocode กับ Octobrain เข้าด้วยกันให้เอเจนต์ทั้งค้นเจอและจดจำได้

ผมเฝ้าดูเอเจนต์ตัวหนึ่งทำความคุ้นเคยกับบริการชำระเงินที่ไม่รู้จักถึงสี่ครั้งในบ่ายวันเดียว บริการเดียวกัน สี่เซสชันใหม่ สี่ครั้งที่มันไล่ตามตัวจัดการ webhook ตั้งแต่ต้น ค้นพบใหม่ว่าการรีทรายเป็น idempotent เพราะมีคีย์ dedupe และสรุปใหม่ว่าคำนำหน้า `legacy_` บนสามฟังก์ชันหมายถึง "ห้ามแตะ" ทุกเซสชันมันทำงานได้ดี ทุกเซสชันมันโยนงานนั้นทิ้งเมื่อหน้าต่างบริบทปิดลง

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

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

---

## ความล้มเหลวสองแบบ ครึ่งที่ขาดหายไปหนึ่งครึ่ง

ให้ **การค้นหาโดยไม่มีความทรงจำ** แก่เอเจนต์ แล้วคุณจะได้วงวน "สี่ครั้งต่อบ่าย" มันหาตัวจัดการ webhook เจอทันที แต่ _ความหมาย_ ของตัวจัดการนั้น — ทำไมมันถึงถูกออกแบบมาแบบนี้ อะไรปลอดภัยที่จะเปลี่ยน เส้นทางไหนคือเส้นทางเก่า — ไม่ได้อยู่ที่ใดอย่างถาวร ทุกเซสชันอนุมานมันใหม่ เอเจนต์มีความสามารถแต่ความจำเสื่อม

ให้ **ความทรงจำโดยไม่มีการค้นหา** แก่เอเจนต์ แล้วคุณจะได้ความล้มเหลวตรงข้าม ซึ่งเงียบกว่าและแย่กว่า มันจำข้อสรุปได้ — "คีย์ dedupe ในตัวจัดการ webhook ทำให้การรีทรายเป็น idempotent" — แต่หกสัปดาห์ต่อมามันหา _ตำแหน่ง_ ของโค้ดที่ข้อสรุปนั้นพูดถึงไม่เจออีก ตัวจัดการถูกรีแฟกเตอร์ ฟังก์ชันถูกเปลี่ยนชื่อ ไฟล์ถูกแยกเป็นสอง ความทรงจำตอนนี้เป็นประโยคที่มั่นใจซึ่งชี้ไปที่ความว่างเปล่า เอเจนต์เชื่อมันและลงมือบนข้อเท็จจริงที่ไม่จริงอีกต่อไป

เครื่องมือสองอย่างปิดจุดบอดของกันและกัน:

|                          | หาโค้ดเจอ | จำการตัดสินใจ | เมื่อไม่มีอีกตัว            |
| ------------------------ | --------- | ------------- | --------------------------- |
| **การค้นหาเชิงความหมาย** | ใช่       | ไม่           | อนุมานบริบทใหม่ทุกเซสชัน    |
| **หน่วยความจำถาวร**      | ไม่       | ใช่           | จำข้อสรุปที่หาตำแหน่งไม่เจอ |

แผนที่กับความทรงจำ ใช้อย่างเดียว ก็ขาดไปครึ่งหนึ่ง

ที่ Muvon เราออกทั้งสองครึ่งเป็น MCP server แบบโอเพนซอร์ส — [Octocode](https://github.com/Muvon/octocode) สำหรับแผนที่ [Octobrain](https://github.com/Muvon/octobrain) สำหรับความทรงจำ — และโฮสต์ที่รันทั้งคู่ด้วยกันคือ [Octomind](https://github.com/Muvon/octomind) ทั้งคู่เป็น Apache-2.0 โพสต์นี้คือคู่มือเวิร์กโฟลว์สำหรับใช้มันเป็นคู่ ถ้าคุณอยากได้การเจาะลึก [การค้นหาโค้ดเชิงความหมายของ Octocode](/blog/octocode-semantic-code-search) และ [การแนะนำ Octobrain](/blog/introducing-octobrain-mcp-memory-server) ครอบคลุมแต่ละเครื่องมือแยกกัน ผมจะอ้างอิงมากกว่าเล่าซ้ำ

---

## แต่ละฝั่งเปิดเผยอะไรจริง ๆ

พื้นฐานก่อน เพราะการประกอบจะมีเหตุผลก็ต่อเมื่อคุณรู้พื้นผิวเครื่องมือจริง เหล่านี้คือเครื่องมือ MCP ไม่ใช่รายการความฝัน

**Octocode** จัดทำดัชนีรีโพของคุณด้วยการแยกวิเคราะห์ AST ของ tree-sitter — สัญลักษณ์จริง ไม่ใช่ก้อนข้อความแบน — และเปิดเผยสี่เครื่องมือให้เอเจนต์:

| เครื่องมือ          | ทำอะไร                                                                                                                                 |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `semantic_search`   | ค้นหาเน้น recall ตามแนวคิดหรือพฤติกรรม "การยืนยันตัวตนถูกจัดการที่ไหน" "โค้ดที่รีทรายคำขอที่ล้มเหลว" หาโค้ดเจอแม้ชื่อไม่ตรงกับคำของคุณ |
| `structural_search` | การจับคู่รูปแบบ AST และการค้นหาสัญลักษณ์แบบเป๊ะ แม่นยำและถูกเมื่อคุณรู้ชื่อ สตริง หรือจุดเรียกใช้                                      |
| `view_signatures`   | ดึงลายเซ็นฟังก์ชันและนิยามชนิดโดยไม่มีตัวบอดี้ — วิธีถูกที่สุดในการทำแผนที่ไฟล์ก่อนอ่าน                                                |
| `graphrag`          | คิวรีกราฟความรู้บน `imports`, `calls`, `implements`, `extends` "อะไรขึ้นอยู่กับโมดูลการชำระเงิน"                                       |

ดัชนีถูกจำกัดขอบเขตตามโปรเจกต์และเป็นแบบ local-first คุณสร้างมันครั้งเดียวด้วย `octocode index` แล้วมันก็คงความเป็นปัจจุบัน จุดที่ควรจำไว้: Octocode ตอบคำถาม _"สิ่งนี้อยู่ที่ไหนและเชื่อมต่ออย่างไร?"_ — และสะท้อนโค้ดตามที่มีอยู่ ณ ตอนนี้เท่านั้น

**Octobrain** ให้หน่วยความจำระยะยาวแก่เอเจนต์ จำกัดขอบเขตต่อโปรเจกต์ตาม URL รีโมต Git แบบ normalize แล้ว (`host/org/repo`) สี่เครื่องมือ MCP:

| เครื่องมือ  | ทำอะไร                                                                                                                                                                                                                                    |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `memorize`  | จัดเก็บอินไซต์ การตัดสินใจ หรือข้อเท็จจริง รับ `title`, `content`, `memory_type` (`architecture`, `decision`, `bug_fix`, `security`, …), `importance`, `tags`, `related_files` และ `related_to[]` สำหรับลิงก์แบบอินไลน์ไปยังความทรงจำอื่น |
| `remember`  | ค้นหาเชิงความหมายเหนือความทรงจำที่จัดเก็บไว้ คืนเพื่อนบ้านกราฟ 1 ฮ็อปโดยอัตโนมัติ รองรับ `created_after` / `created_before` สำหรับคิวรีเชิงเวลา                                                                                           |
| `forget`    | ลบความทรงจำด้วย `memory_id` หรือคิวรี — ย้อนกลับไม่ได้ ต้องใช้ `confirm=true`                                                                                                                                                             |
| `knowledge` | ฐานความรู้แยกต่างหากสำหรับจัดทำดัชนีและค้นหาเอกสารและ URL ภายนอก (`search`, `store`, `read`, `match`, `delete`)                                                                                                                           |

คำอธิบายของ `memorize` เองบอกเอเจนต์ให้ _เรียก `remember` ก่อนเพื่อหลีกเลี่ยงข้อมูลซ้ำ_ และให้ทำเครื่องหมายข้อเท็จจริงเป็น `user_confirmed` (ความสำคัญสูง) เทียบกับ `agent_inferred` (ต่ำกว่า) Octobrain เชื่อมความทรงจำที่คล้ายกันเชิงความหมายโดยอัตโนมัติแบบ Zettelkasten และรองรับความสัมพันธ์ `supersedes` เพื่อให้ข้อเท็จจริงที่แก้ไขแล้วถูกจัดอันดับเหนือข้อที่ล้าสมัยซึ่งมันแทนที่ — ข้อเก่ายังคงคิวรีได้สำหรับประวัติ จำสิ่งนี้ไว้: Octobrain ตอบคำถาม _"เราตัดสินใจอะไรเกี่ยวกับสิ่งนี้ และเมื่อไหร่?"_ — และเป็นฝั่งเดียวที่คงอยู่ข้ามเซสชัน

สังเกตความสมมาตร Octocode รู้โค้ดปัจจุบันแต่ลืมทุกบทสนทนา Octobrain จำทุกบทสนทนาแต่ไม่รู้โค้ด ไม่มีฟิลด์ใด — `related_files` บนความทรงจำ เส้นทางไฟล์ในผลการค้นหา — ที่มีความหมายโดยไม่มีอีกเครื่องมือมาช่วยแก้

---

## พวกมันประกอบกันอย่างไร: วงวน

เครื่องมือสองอย่างไม่ได้แค่อยู่ร่วมกัน — มันก่อตัวเป็นวงวน และวงวนนั้นคือเทคนิคทั้งหมด สี่จังหวะ:

**1. ค้นหาเพื่อหาตำแหน่ง** เอเจนต์ไม่รู้ว่าตรรกะ idempotency ของ webhook อยู่ที่ไหน มันเรียก `semantic_search("webhook retry idempotency dedupe")` Octocode คืนตัวจัดการและการตรวจสอบคีย์ dedupe ตอนนี้เอเจนต์มี _ตำแหน่ง_ และ _โค้ดปัจจุบัน_

**2. จดจำการตัดสินใจ ไม่ใช่ตำแหน่ง** หลังจากใช้เหตุผลกับโค้ดนั้น — ยืนยันว่าการรีทรายเป็น idempotent ระบุเส้นทางเก่า ตกลงกับคุณเรื่องขอบเขต — เอเจนต์เรียก `memorize` สิ่งสำคัญ: สิ่งที่มันจัดเก็บคือ _ข้อสรุปและการให้เหตุผล_ ติดแท็กด้วย `related_files` ไม่ใช่สำเนาโค้ดและไม่ใช่หมายเลขบรรทัด `memory_type = "architecture"` `importance` สูงถ้าคุณยืนยัน การตัดสินใจตอนนี้คงทน

**3. จดจำในครั้งถัดไป** เซสชันใหม่ หน้าต่างบริบทว่างเปล่า ก่อนแตะอะไร เอเจนต์เรียก `remember("webhook payments idempotency")` Octobrain คืนการตัดสินใจที่จัดเก็บไว้ _พร้อมเพื่อนบ้าน 1 ฮ็อป_ — บันทึกความปลอดภัยที่เกี่ยวข้อง คำเตือนเส้นทางเก่าที่ลิงก์ไว้ เอเจนต์เริ่มเซสชันโดยรู้สิ่งที่เคยใช้เวลาสี่เซสชันกว่าจะหาออก

**4. ค้นหาอีกครั้งเพื่อตรวจสอบ** จังหวะนี้คือจังหวะที่คนข้าม และมันคือสิ่งที่ทำให้ความทรงจำซื่อสัตย์ ความทรงจำบอกว่า "idempotency อยู่ในตัวจัดการ webhook" ก่อนลงมือ เอเจนต์เรียก `semantic_search` หรือ `view_signatures` บน `related_files` เพื่อยืนยันว่าโค้ดยังตรงกับความทรงจำ ถ้าตัวจัดการถูกรีแฟกเตอร์และคีย์ dedupe ย้ายที่ การค้นหาใหม่จะเผยความไม่ตรงกัน เอเจนต์อัปเดตความทรงจำ — `memorize` พร้อมลิงก์ `supersedes` ไปยังของเก่า — แล้วดำเนินต่อบนความจริงปัจจุบัน

```
        ┌─────────────────────────────────────────────┐
        │                                             │
        ▼                                             │
  semantic_search ──► ให้เหตุผล ──► memorize ──► remember
   (หาตำแหน่งโค้ด)    (ตัดสินใจ)   (เก็บการ      (เซสชันถัดไป:
        ▲                          ตัดสินใจ)     โหลดกลับ)
        │                                          │
        └────────── ค้นหาอีกครั้งเพื่อตรวจสอบ ◄────────┘
            (โค้ดยังตรงกับความทรงจำหรือไม่?)
```

แผนที่ทำให้ความทรงจำยึดติดกับโค้ดจริง ความทรงจำกันเอเจนต์ไม่ให้อนุมานสิ่งที่มันรู้อยู่แล้วใหม่ การค้นหาโดยไม่มีขั้นที่ 2 และ 3 คือเอเจนต์ความจำเสื่อม ความทรงจำโดยไม่มีขั้นที่ 1 และ 4 คือเอเจนต์มั่นใจ-แต่-ผิด วงวนคือทั้งสองครึ่งที่ทำหน้าที่ของมัน

เหตุผลที่ขั้นที่ 4 สำคัญมาก: ความทรงจำคือข้อกล่าวอ้างเกี่ยวกับโค้ด ณ จุดเวลาหนึ่ง และโค้ดเคลื่อนที่ Octobrain จัดอันดับข้อเท็จจริงที่แก้ไขด้วย `supersedes` เหนือข้อที่ล้าสมัยได้ แต่ _บางสิ่ง_ ต้องสังเกตความล้าสมัยก่อน Octocode คือ "บางสิ่ง" นั้น การค้นหาใหม่คือการตรวจสอบความเป็นจริงของเอเจนต์เทียบกับความทรงจำของตัวเอง

---

## ลงทะเบียนทั้งสอง server เพื่อให้เอเจนต์มีทั้งคู่ด้วยกัน

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

Octomind ประกาศ MCP server ในคอนฟิกภายใต้ `[[mcp.servers]]` server ในตัว (`core`, `runtime`, `agent`, `orchestration`) อยู่เสมอ คุณเพิ่ม Octocode และ Octobrain เป็น `stdio` server สองตัว:

```toml
[[mcp.servers]]
name = "octocode"
type = "stdio"
command = "octocode"
args = ["mcp", "--path=."]
timeout_seconds = 240
tools = []

[[mcp.servers]]
name = "octobrain"
type = "stdio"
command = "octobrain"
args = ["mcp"]
timeout_seconds = 60
tools = []
```

`tools = []` หมายถึง "เปิดเผยเครื่องมือทั้งหมดของ server นี้" `--path=.` จำกัด Octocode ไว้ที่รีโพปัจจุบัน Octobrain จำกัดตัวเองโดยอัตโนมัติด้วย URL รีโมต Git แบบ normalize แล้ว (`host/org/repo`) ดังนั้นความทรงจำที่เอเจนต์จัดเก็บในโปรเจกต์หนึ่งจึงแยกจากอีกโปรเจกต์ ไทม์เอาต์ของ Octocode ใจกว้างเพราะการค้นหาครั้งแรกหลังจัดทำดัชนีอาจดึงโมเดล embedding ในเครื่องเข้าแคช ของ Octobrain สั้นกว่าเพราะการค้นหาความทรงจำมีต้นทุนต่ำ

ถ้าคุณใช้ Claude Code แทน Octomind ก็เป็น server สองตัวเดิม ลงทะเบียนแบบ CLI:

```bash
claude mcp add octocode  -- octocode mcp --path .
claude mcp add octobrain -- octobrain mcp
```

Claude Desktop, Cursor และ Windsurf รับบล็อก JSON `mcpServers` เดียวกัน — หนึ่งรายการต่อหนึ่ง server กลไกมีบันทึกไว้ต่อเครื่องมือ สิ่งเดียวที่สำคัญตรงนี้คือ _ทั้งคู่ ในเอเจนต์เดียวกัน_ เอเจนต์ที่มี Octocode แต่ไม่มี Octobrain คือแผนที่ที่ไม่มีความทรงจำ เอเจนต์ที่มี Octobrain แต่ไม่มี Octocode คือความทรงจำที่ไม่มีแผนที่ คุณต้องการคู่

ข้อกำหนดเบื้องต้นหนึ่งอย่างก่อนรันครั้งแรก: จัดทำดัชนีรีโพ `octocode index` ที่รากโปรเจกต์ Octobrain ไม่ต้องการอะไร — มันเริ่มว่างเปล่าและเติมเต็มเมื่อเอเจนต์จัดเก็บการตัดสินใจ ถ้ารีโพของคุณใหญ่พอจนการจัดทำดัชนีเป็นงานจริงจัง โพสต์พี่น้องเรื่อง [การจัดทำดัชนีโค้ดเบสขนาดใหญ่สำหรับการค้นหาเชิงความหมายในเครื่อง](/blog/indexing-large-codebase-semantic-search-locally) ครอบคลุมการทำโดยไม่ต้องใช้คีย์ API

---

## ตัวอย่างใช้งานจริง: พาเอเจนต์ทำความคุ้นเคยกับบริการที่ไม่รู้จัก

นี่คือบริการชำระเงินจากต้นโพสต์ คราวนี้ทำอย่างถูกต้อง ดูวงวนทำงานที่สี่เซสชันความจำเสื่อมทำไม่ได้

**เซสชัน 1 — เริ่มแบบเย็น สร้างแผนที่และความทรงจำแรก**

เอเจนต์ไม่เคยเห็นบริการนี้ มันเริ่มด้วยการทำแผนที่ ไม่ใช่การอ่าน:

```
view_signatures("src/payments/**/*.rs")
  → webhook.rs: handle_webhook, verify_signature, dedupe_key
  → charge.rs:  create_charge, capture, legacy_settle, legacy_refund, legacy_void
```

สามฟังก์ชันที่มีคำนำหน้า `legacy_` กระโดดเข้าตา เอเจนต์ถาม คุณยืนยันว่ามันเป็นเส้นทางการชำระบัญชีที่เลิกใช้แล้วซึ่ง cron job ยังเรียกอยู่ และไม่มีใครได้รับอนุญาตให้ "เก็บกวาด" นี่คือการตัดสินใจที่คุ้มค่าจะเก็บไว้ — มันจึงเข้าไปในความทรงจำ ไม่ใช่ในความว่างเปล่า:

```
memorize(
  title: "legacy_ settlement path in charge.rs is load-bearing",
  content: "legacy_settle/refund/void are called by the nightly
            reconciliation cron. Deprecated but NOT dead. Do not remove
            or refactor without checking cron/reconcile.rs.",
  memory_type: "architecture",
  importance: 0.9,
  source: "user_confirmed",
  tags: ["payments", "legacy", "cron"],
  related_files: ["src/payments/charge.rs", "src/cron/reconcile.rs"]
)
```

จากนั้นมันไล่ตาม idempotency ด้วย `semantic_search("webhook retry idempotency")` ลงจอดที่ `dedupe_key` ใช้เหตุผลกับมัน และจัดเก็บความทรงจำที่สอง — `memory_type: "architecture"` ลิงก์กับอันแรกด้วย `related_to` เพื่อให้ทั้งสองโผล่ขึ้นมาด้วยกันภายหลัง เซสชันจบ ความทรงจำสองชิ้นคงอยู่ ดัชนีโค้ดคงอยู่ การให้เหตุผลของบ่ายนั้นไม่ใช่ของใช้แล้วทิ้งอีกต่อไป

**เซสชัน 2 — เริ่มแบบอุ่น สามสัปดาห์ต่อมา**

หน้าต่างบริบทใหม่ แทนที่จะไล่ตามใหม่ เอเจนต์โหลดสิ่งที่มันรู้ก่อน:

```
remember("payments webhook legacy settlement")
  → "legacy_ settlement path is load-bearing" (importance 0.9, CONFIRMED)
  → เพื่อนบ้าน 1 ฮ็อป: "webhook idempotency via dedupe_key"
```

เรียกครั้งเดียว และเอเจนต์เริ่มจากจุดที่เซสชัน 1 จบ — รวมถึงเพื่อนบ้านที่ลิงก์ไว้ซึ่งมันไม่ได้ขอชัด ๆ ตอนนี้ขั้นตอนตรวจสอบ ความทรงจำชี้ไปที่ `src/payments/charge.rs` ดังนั้นก่อนเชื่อมัน เอเจนต์ค้นหาอีกครั้ง:

```
view_signatures("src/payments/charge.rs")
  → create_charge, capture, settle_v2, refund_v2, void_v2
```

ฟังก์ชัน `legacy_` หายไปแล้ว มีคน ship `settle_v2` และลบเส้นทางเก่า ความทรงจำตอนนี้เก่าค้าง — และเพราะเอเจนต์ _ตรวจสอบเทียบกับแผนที่แทนที่จะเชื่อความทรงจำแบบหลับหูหลับตา_ มันจึงจับได้ มันแทนที่การตัดสินใจเก่าแทนที่จะลงมือบนข้อเท็จจริงที่หมดอายุสามสัปดาห์:

```
memorize(
  title: "settlement path migrated to settle_v2",
  content: "legacy_settle/refund/void removed in the v2 migration.
            cron/reconcile.rs now calls settle_v2. Earlier 'do not remove'
            note no longer applies.",
  memory_type: "architecture",
  related_to: [{ target_id: <old_memory_id>, relationship_type: "supersedes" }],
  related_files: ["src/payments/charge.rs", "src/cron/reconcile.rs"]
)
```

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

---

## รูปแบบที่ควรหลีกเลี่ยง

วงวนนั้นเรียบง่าย วิธีทำให้มันพังนั้นเฉพาะเจาะจง หลีกเลี่ยงสิ่งเหล่านี้:

**จดจำหมายเลขบรรทัดที่ไม่เสถียร** "บั๊กอยู่ที่ `charge.rs:142`" ไร้ค่าทันทีที่มีคนเพิ่ม import ด้านบน จัดเก็บ _อะไร_ และ _ทำไม_ ยึดด้วย `related_files` และชื่อสัญลักษณ์ — ให้ขั้นตอนค้นหาใหม่หา _ที่ไหน_ Octocode หา `dedupe_key` เจอไม่ว่ามันจะอยู่บรรทัด 142 หรือ 90 หมายเลขบรรทัดที่จดจำไว้คือคำโกหกที่มีไทม์สแตมป์

**จัดทำดัชนีลงความทรงจำมากเกินไป** คำอธิบายของ `memorize` ใน Octobrain ชัดเจน: ข้ามสถานะชั่วคราวและสิ่งที่อนุมานใหม่ได้ง่าย ถ้า `semantic_search` หามันเจอในการเรียกครั้งเดียว มันไม่ควรอยู่ในความทรงจำ — ความทรงจำมีไว้สำหรับ _ข้อสรุปและการตัดสินใจ_ ไม่ใช่ข้อเท็จจริงที่แผนที่ถืออยู่แล้ว การจดจำว่า "โมดูล auth อยู่ใน src/auth" คือการเปลืองช่องว่างกับสิ่งที่แผนที่ตอบให้ฟรี และเจือจาง recall ของความทรงจำที่สำคัญจริง ความทรงจำเก็บสิ่งที่โค้ด _บอกคุณไม่ได้_: ทำไม ขอบเขต และ "ห้ามแตะอันนี้" ที่คุณรู้เพียงเพราะมีคนบอก

**เชื่อความทรงจำที่เก่าค้างโดยไม่ตรวจสอบใหม่** อันนี้กัดแรงที่สุด และนั่นคือเหตุผลที่ขั้นที่ 4 มีอยู่ ความทรงจำคือข้อกล่าวอ้างเกี่ยวกับโค้ด ณ จุดเวลาหนึ่ง โค้ดเคลื่อนที่ ค้นหา `related_files` ใหม่เสมอก่อนลงมือบนการตัดสินใจเก่า เมื่อโค้ดเคลื่อนไปแล้ว ให้ `supersede` ความทรงจำแทนที่จะยัดข้อสรุปเก่าลงบนโค้ดใหม่ ความทรงจำที่คุณไม่เคยตรวจสอบคือหนี้ทางเทคนิคที่ย้อนเถียงกลับ

**ปล่อยให้ความทรงจำที่ถูกแทนที่เน่าแทนที่จะลิงก์มัน** เมื่อข้อเท็จจริงเปลี่ยน อย่าแค่ `memorize` อันใหม่แล้วทิ้งอันเก่าเป็นเด็กกำพร้า — ลิงก์มันด้วย `supersedes` Octobrain จัดอันดับข้อเท็จจริงปัจจุบันเหนือข้อที่เก่าค้าง _และ_ คงประวัติให้คิวรีได้ การแก้ไขที่กำพร้าทิ้งความทรงจำที่ขัดแย้งกันสองชิ้นที่มั่นใจเท่ากัน และไม่มีทางบอกได้ว่าอันไหนเป็นปัจจุบัน

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

---

## เวอร์ชันสั้น

เอเจนต์ AI ในโค้ดเบสที่ไม่รู้จักต้องการสองสิ่งที่มนุษย์ถือเป็นเรื่องธรรมดา: ความสามารถในการ _ค้นเจอ_ โค้ดที่เกี่ยวข้อง และความสามารถในการ _จดจำ_ ว่าตัดสินใจอะไรเกี่ยวกับมัน การค้นหาเชิงความหมายคืออย่างแรก หน่วยความจำถาวรคืออย่างที่สอง รันมันเป็นคู่ — ค้นหาเพื่อหาตำแหน่ง จดจำการตัดสินใจ จดจำในครั้งถัดไป ค้นหาอีกครั้งเพื่อตรวจสอบ — แล้วเอเจนต์จะเลิกทำความคุ้นเคยกับตัวเองใหม่ทุกเซสชัน และเลิกเชื่อข้อสรุปที่มันวางลงในโค้ดไม่ได้อีกต่อไป

แผนที่บอกคุณว่าสิ่งต่าง ๆ อยู่ที่ไหน ความทรงจำบอกว่าคุณตัดสินใจอะไรเกี่ยวกับมัน ให้เอเจนต์ทั้งคู่และเชื่อมวงวนระหว่างพวกมัน นั่นคือเทคนิคทั้งหมด ถ้าสุขอนามัยของความทรงจำคือส่วนที่คุณอยากได้เพิ่ม โพสต์พี่น้องเรื่อง [หน่วยความจำเอเจนต์โดยปราศจากเสียงรบกวน](/blog/ai-agent-memory-without-the-noise) เจาะลึกว่าอะไรคุ้มค่าจะเก็บไว้

— Don

---

_[Octocode](https://github.com/Muvon/octocode) และ [Octobrain](https://github.com/Muvon/octobrain) เป็นโอเพนซอร์สภายใต้ Apache-2.0 และรันด้วยกันภายใน [Octomind](https://github.com/Muvon/octomind) เจอมุมคมในวงวนไหม? [เปิด issue](https://github.com/Muvon/octobrain/issues) — เวิร์กโฟลว์ดีขึ้นเมื่อผู้คนบอกเราว่ามันพังตรงไหน_
