· 6 phút · Kỹ thuật

Bộ nhớ lâu dài cho Claude Code: Ngữ cảnh xuyên phiên thực sự hoạt động thế nào

Bộ nhớ lâu dài cho Claude Code: Ngữ cảnh xuyên phiên thực sự hoạt động thế nào

Bạn đóng máy tính xách tay vào thứ Sáu sau một phiên kéo dài ba giờ, trong đó Claude Code đã tái cấu trúc mô-đun xác thực của bạn, biết rằng nhóm bạn sử dụng một Result<T> trình bao tùy chỉnh thay vì ném ngoại lệ, và cuối cùng đã hiểu tại sao UserService không thể nhập từ billing/. Đến thứ Hai, bạn mở một phiên mới và Claude tự tin bọc một hàm mới trong try/catch rồi nhập mô-đun bị cấm. Mọi điều nó đã học đều biến mất.

Đây là vấn đề cốt lõi về trải nghiệm sử dụng của các công cụ lập trình tác tử: mô hình không có bộ nhớ về các sự kiện đã trải qua. Mỗi phiên đều bắt đầu từ con số không, cộng với những gì bạn đã ghi lại thủ công. Hãy tìm lời giải bằng kỹ thuật — một cách trung thực, bao gồm cả những phần không hiệu quả.

Vấn đề cốt lõi: các phiên không lưu trạng thái theo thiết kế

Một phiên Claude Code là một cuộc hội thoại. Khi phiên kết thúc, bản ghi được lưu trữ và ngữ cảnh làm việc — sự hiểu biết tích lũy qua hàng chục lần gọi công cụ — biến mất. Phiên tiếp theo tái tạo ngữ cảnh từ ba nguồn:

  • Của bạn CLAUDE.md files (project and user scope)
  • Bất kỳ tệp nào Claude đọc trong phiên
  • Những gì bạn nhập

Không nguồn nào trong số này ghi lại được suy ra kiến thức: những ngõ cụt bạn đã khám phá, lý do tồn tại của một giải pháp tình thế kỳ lạ, việc bạn đã thử phương án A và nó làm hỏng CI. Việc suy ra lại kiến thức đó tiêu tốn token và thời gian thực trong từng phiên.

Phản ứng tự nhiên là xây dựng một lớp bộ nhớ — ghi lại những gì đã xảy ra, nén chúng, rồi đưa phần liên quan trở lại khi khởi động. Dự án mã nguồn mở claude-mem là một triển khai tham chiếu rõ ràng của chính mẫu này, và đáng để nghiên cứu dù bạn có áp dụng nó hay không.

Mẫu kiến trúc đằng sau bộ nhớ lâu dài của Claude Code

Mọi cách tiếp cận nghiêm túc đối với bộ nhớ lâu dài của Claude Code đều tuân theo cùng một chu trình gồm ba giai đoạn. Hiểu riêng từng giai đoạn giúp bạn tự xây dựng, mua giải pháp hoặc bỏ qua từng phần.

Giai đoạn 1: Thu thập

Bạn cần theo dõi những gì đã xảy ra trong một phiên. Claude Code cung cấp các hook trong vòng đời — các lệnh shell được kích hoạt khi có sự kiện. Những hook liên quan gồm:

HookKích hoạt khiDùng để
SessionStartMột phiên bắt đầuNạp bộ nhớ
SessionEndMột phiên kết thúcKích hoạt thu thập
PostToolUseSau mỗi lần gọi công cụTruyền liên tục hoạt động ở mức chi tiết
StopTác tử hoàn tất phản hồiTạo điểm kiểm tra

Một hook thu thập tối giản trong .claude/settings.json:

{
  "hooks": {
    "SessionEnd": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/mem/capture.sh"
          }
        ]
      }
    ]
  }
}

Hook nhận JSON qua stdin để mô tả sự kiện. Với SessionEnd bạn nhận được ID phiên và đường dẫn bản ghi hội thoại, nên capture.sh có thể đọc toàn bộ nhật ký hội thoại:

#!/usr/bin/env bash
INPUT=$(cat)
TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path')
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id')

# Hand the raw transcript to the compression stage
python3 "$CLAUDE_PROJECT_DIR/.claude/mem/compress.py" \
  --transcript "$TRANSCRIPT" \
  --session "$SESSION_ID"

Một điều dễ mắc phải: hook chạy với thời gian chờ giới hạn, và việc gửi đồng bộ một bản ghi hội thoại lớn tới LLM sẽ vượt quá giới hạn đó. Trong thực tế, bạn nên để việc thu thập được khởi chạy mà không cần chờ hoàn tất — ghi đường dẫn bản ghi hội thoại vào hàng đợi rồi xử lý bằng một tiến trình nền, thay vì xử lý trực tiếp trong hook.

Giai đoạn 2: Nén

Bản ghi hội thoại thô không có ích khi dùng làm bộ nhớ — chúng quá lớn và chứa đầy nhiễu (nội dung tệp được xuất ra, hàng loạt đầu ra công cụ, lỗi gõ của bạn). Giai đoạn nén dùng LLM để chắt lọc phiên thành những thông tin có giá trị lâu dài. Đây là lúc bạn dùng một lần gọi Haiku 4.5, thay vì Opus — tóm tắt chính là loại tác vụ khối lượng lớn, ít rủi ro mà mức giá của Haiku hướng tới.

import anthropic

client = anthropic.Anthropic()

PROMPT = """You are a memory compressor. From this coding session
transcript, extract ONLY durable facts worth remembering next session:
- Architectural decisions and their rationale
- Conventions discovered (naming, error handling, imports)
- Dead ends already explored (so we don't repeat them)
- Unresolved TODOs

Output JSON: a list of {fact, category, files[], confidence}.
Omit anything transient. If nothing durable happened, output []."""

resp = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=1500,
    system=PROMPT,
    messages=[{"role": "user", "content": transcript_text}],
)
memories = resp.content[0].text

Hãy chú ý đến trường confidence và chỉ dẫn rõ ràng yêu cầu xuất []. Cả hai đều nhằm hạn chế thiệt hại từ kiểu lỗi mà chúng ta sẽ đề cập sau. Lưu đầu ra ở nơi có thể truy vấn — SQLite với một cột embedding, hoặc một kho lưu trữ vector dùng dự án và đường dẫn tệp làm khóa.

Giai đoạn 3: Nạp

Khi phiên bắt đầu, bạn truy xuất các thông tin ghi nhớ liên quan và nạp chúng vào ngữ cảnh. Hook SessionStart có thể in ra stdout, và đầu ra đó được thêm vào ngữ cảnh của Claude:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/mem/inject.sh" }
        ]
      }
    ]
  }
}

Quyết định kỹ thuật then chốt là lọc theo mức độ liên quan. Nạp toàn bộ bộ nhớ là cách làm đơn giản nhưng sai — nó khiến ngữ cảnh phình to và làm chìm các thông tin hữu ích. Cách tốt hơn: truy xuất dựa trên nội dung mà phiên có khả năng sẽ xử lý. Nếu chưa xác định được, chỉ nạp những thông tin có độ tin cậy cao, áp dụng cho toàn dự án, và cung cấp phần còn lại qua một máy chủ MCP để Claude có thể truy vấn bộ nhớ khi cần:

# A tiny MCP tool the agent calls when it wants history
@mcp.tool()
def recall(query: str, files: list[str] = []) -> list[dict]:
    """Retrieve relevant memories about this codebase."""
    return memory_store.search(query, files=files, min_confidence=0.6)

Trong thực tế, mô hình chủ động truy xuất này hiệu quả hơn mô hình đẩy sẵn. Thay vì đoán thông tin nào liên quan ngay khi khởi động, bạn để tác tử hỏi “chúng ta đã từng chỉnh sửa đoạn mã thanh toán này chưa?” đúng lúc cần đến. Hook cung cấp một bản tóm tắt nhỏ luôn có trong ngữ cảnh; máy chủ MCP xử lý việc truy xuất có mục tiêu.

Những điểm dễ gặp lỗi — và thực sự có lỗi

Tôi đã vận hành các lớp bộ nhớ đủ lâu để hoài nghi về chúng. Những kiểu lỗi này có thật và tác động của chúng tích lũy theo thời gian.

Bộ nhớ được AI nén có thể chứa thông tin bịa đặt. Bản thân bộ phận nén cũng là một mô hình ngôn ngữ. Đôi khi nó sẽ ghi lại một “quyết định” vốn chỉ là ý tưởng đã bị loại bỏ, hoặc đảo ngược lý do cho một lựa chọn. Lúc đó, bạn có thông tin ghi nhớ sai nhưng nghe rất đáng tin được nạp ngay khi khởi động, và tác tử tin nó quá mức. Điều này còn tệ hơn việc không có bộ nhớ, vì thông tin sai lại được trình bày đầy tự tin. Trường confidence và việc con người rà soát kho bộ nhớ là những biện pháp giảm thiểu thực sự duy nhất.

Ngữ cảnh lỗi thời là mối nguy âm thầm. Bạn tái cấu trúc UserService vào thứ Ba. Bộ nhớ từ thứ Hai vẫn ghi “phần xác thực nằm trong UserService.” Không có gì đánh dấu thông tin đó là không còn hợp lệ. Độ chính xác của thông tin ghi nhớ giảm ngay khi mã thay đổi, và không có tín hiệu rõ ràng để xác định khi nào chúng hết hiệu lực. Hãy gắn thông tin ghi nhớ với giá trị băm của tệp hoặc SHA của commit, và coi chúng là đáng ngờ khi tệp liên quan được di chuyển.

Chi phí token tăng trong mỗi phiên. Bộ nhớ được nạp là phần ngữ cảnh bạn phải trả phí ở mỗi lượt, dù có dùng đến hay không. Một lớp bộ nhớ nạp 4K token khi khởi động sẽ cộng lượng đó vào chi phí đầu vào trong suốt phiên. Mô hình MCP chủ động truy xuất giúp giảm chi phí, nhưng việc thu thập và nén cũng tạo ra chi phí định kỳ riêng.

Đây là bảng so sánh thẳng thắn:

Cách tiếp cậnChi phí thiết lậpToken phát sinh định kỳRủi ro lỗi thờiPhù hợp nhất với
CLAUDE.md chỉ dùngVài phútThấp, có thể xác định trướcBạn kiểm soátHầu hết dự án
Công cụ MCP có phạm vi giới hạnVài giờChỉ khi có nhu cầuThấpTrạng thái hệ thống hiện tại
Lớp bộ nhớ đầy đủVài ngàyCao hơn, theo từng phiênCaoCông việc kéo dài, mang tính khám phá

Sự thật khó chấp nhận: có lẽ bạn không cần đến nó

Trước khi xây dựng bất kỳ phần nào trong số này, hãy viết một CLAUDE.mdthật tốt. Một tệp được biên soạn thủ công, ghi rõ “chúng ta dùng Result<T>, tuyệt đối không ném ngoại lệ; UserService không được nhập billing/; phần xác thực đã được chuyển sang auth/ trong quý hai” giải quyết 80% vấn đề bộ nhớ mà không có rủi ro bịa đặt và với chi phí có thể xác định trước. Tệp do con người viết nên độ tin cậy đến từ chính cách tạo ra nó.

Phạm vi mà các lớp bộ nhớ thực sự đáng dùng hẹp hơn những lời quảng bá: công việc khám phá kéo dài, trong đó kiến thức được suy ra (những hướng đi bế tắc, các cuộc điều tra còn dang dở) thực sự không thể được viết sẵn vì bạn chưa biết đến nó. Với công việc phát triển tính năng thường xuyên, CLAUDE.md cùng một vài máy chủ MCP có phạm vi giới hạn đáp ứng được nhiều nhu cầu hơn một quy trình bộ nhớ tự động, và không bao giờ cung cấp thông tin sai cho bạn.

Nếu bạn xây dựng quy trình này, giai đoạn nén là nơi cần quan tâm nhất đến chi phí — việc thường xuyên chạy Haiku để tóm tắt khá rẻ, nhưng chỉ khi giá mỗi token vốn đã hợp lý. Đây là một lý do khiến các nhóm định tuyến loại tác vụ nền khối lượng lớn này qua những nhà cung cấp như AI Prime Tech.

Những điểm cần áp dụng trong thực tế

  • Các phiên không lưu trạng thái. Kiến thức rút ra — những hướng đi bế tắc, lý do lựa chọn, quy ước — mới là thứ thực sự bị mất, và việc suy ra lại chúng rất tốn kém.
  • Mô hình là thu thập → nén → nạp. Kết nối việc thu thập và nạp bằng các hook SessionEnd/SessionStart ; thực hiện thu thập bất đồng bộ để tránh vượt thời gian chờ của hook.
  • Ưu tiên chủ động truy xuất thay vì đẩy sẵn. Nạp một bản tóm tắt thật nhỏ khi khởi động, rồi cung cấp một công cụ MCP recall để tác tử chỉ lấy thông tin ghi nhớ khi có liên quan.
  • Nén bằng Haiku 4.5, gắn độ tin cậy và giá trị băm của tệp nguồn cho từng thông tin ghi nhớ, đồng thời coi chúng là đáng ngờ khi tệp thay đổi.
  • Bộ nhớ tự động có thể cung cấp thông tin sai. Ngữ cảnh bịa đặt và lỗi thời còn tệ hơn việc không có ngữ cảnh vì nó được xem là đáng tin cậy. Hãy để con người tham gia giám sát kho bộ nhớ.
  • Hãy thử CLAUDE.md trước. Với hầu hết dự án, một tệp ngữ cảnh viết tay cùng các công cụ có phạm vi giới hạn vượt trội hơn một lớp bộ nhớ đầy đủ về chi phí, độ tin cậy và công sức bảo trì — chỉ dùng khả năng lưu giữ lâu dài khi công việc của bạn thực sự kéo dài và mang tính khám phá.
A

AI Prime Tech xuất bản blog này. Các bài viết được soạn với sự hỗ trợ của AI; hãy đối chiếu những chi tiết phụ thuộc vào phiên bản như ID mô hình, giá và giới hạn với tài liệu chính thức trước khi dựa vào chúng.

Truy cập Claude API với chi phí thấp hơn

Một khóa API cho Claude Opus 5.5, Sonnet 5, Haiku 4.5 và Fable 5.1, cùng GPT-6 mô hình. Thanh toán theo mức sử dụng, không cần đăng ký thuê bao.

Nhận khóa API của bạn →
AI Prime Tech là cổng API bên thứ ba độc lập. Claude™ và Anthropic® là các nhãn hiệu của Anthropic, PBC. Không hàm ý có sự liên kết hay chứng thực.