메모리 도구 (Memory Tool)¶
메모리 도구(memory tool)를 쓰면 Claude가 대화를 넘나들며 정보를 저장하고 다시 꺼내 쓸 수 있어요. 동작 방식은 간단해요. Claude가 세션 사이에도 유지되는 파일을 만들고, 읽고, 고치고, 지우는 거예요. 모든 것을 컨텍스트 윈도우(context window)에 억지로 담아두지 않아도 시간이 지나면서 지식이 쌓이게 하려는 목적이에요.
핵심은 적시(just-in-time) 컨텍스트 검색이에요. 관련 정보를 처음부터 전부 불러오는 대신, 에이전트는 배운 내용을 메모리 파일에 기록해 두고 필요할 때 다시 읽어요. 덕분에 활성 컨텍스트가 지금 하는 일에 집중된 채로 유지돼요. 특히 오래 실행되는 세션에서는 이게 중요해요. 컨텍스트 윈도우를 가득 채울 수 있는 상황이잖아요. 더 넓은 패턴은 효과적인 컨텍스트 엔지니어링을 참고하세요.
메모리 도구는 클라이언트 측에서 동작해요. Claude가 파일 작업을 요청하면 그걸 실제로 실행하는 건 우리 애플리케이션이에요. 데이터를 어디에 어떻게 저장할지는 자기 인프라로 직접 통제하는 구조예요.
이 기능에 대한 피드백(버그 리포트 등)은 피드백 양식으로 보내주세요.
이 기능에 ZDR(제로 데이터 보존, zero data retention)이 어떻게 적용되는지는 API 및 데이터 보존 문서를 확인하세요.
사용 사례¶
- 여러 에이전트 세션에 걸쳐 프로젝트 컨텍스트 유지
- 과거 상호작용·결정·피드백에서 얻은 교훈을 새 작업에 적용
- 시간이 지나면서 지식 베이스 구축
작동 방식¶
메모리 도구가 켜져 있으면 Claude는 작업을 시작하기 전에 자동으로 메모리 디렉터리를 확인해요. 작업하는 동안 배운 내용을 /memories 아래 파일에 저장하고, 이후 대화에서는 그걸 다시 읽어 이전 작업을 이어가요.
메모리 도구는 클라이언트 측이므로 Claude는 메모리 작업을 요청만 해요. 애플리케이션이 각 요청을 자기가 직접 통제하는 스토리지에 대해 실행하고, 그 결과를 tool_result 블록으로 돌려줘요(도구 호출 처리 참조). 여기서 /memories 경로는 일종의 접두사예요. 핸들러가 이 접두사를 사용자별 디렉터리나 데이터베이스의 키 같은 실제 스토리지에 매핑한다고 보면 돼요. 메모리는 완전히 애플리케이션 안에만 존재해요. 이후 대화가 같은 tools 항목을 보내고 핸들러가 같은 저장소를 제공하면, 같은 메모리에서 이어지게 돼요. 보안을 위해 모든 메모리 작업은 /memories 디렉터리 안으로 제한하세요(경로 탐색 보호 참조).
예시: 메모리 도구 호출이 작동하는 방식¶
전형적인 상호작용은 이렇게 흘러가요.
1. 사용자 요청:
"Help me respond to this customer service ticket."
2. Claude가 메모리 디렉터리를 확인해요:
"I'll help you respond to the customer service ticket. Let me check my memory for any previous context."
Claude가 메모리 도구를 호출해요:
{
"type": "tool_use",
"id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
"name": "memory",
"input": {
"command": "view",
"path": "/memories"
}
}
3. 애플리케이션이 디렉터리 내용을 반환해요:
{
"type": "tool_result",
"tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
"content": "Here're the files and directories up to 2 levels deep in /memories, excluding hidden items and node_modules:\n4.0K\t/memories\n1.5K\t/memories/customer_service_guidelines.xml\n2.0K\t/memories/refund_policies.xml"
}
4. Claude가 관련 파일을 읽어요:
{
"type": "tool_use",
"id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",
"name": "memory",
"input": {
"command": "view",
"path": "/memories/customer_service_guidelines.xml"
}
}
5. 애플리케이션이 파일 내용을 반환해요:
{
"type": "tool_result",
"tool_use_id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",
"content": "Here's the content of /memories/customer_service_guidelines.xml with line numbers:\n 1\t<guidelines>\n 2\t<addressing_customers>\n 3\t- Always address customers by their first name\n 4\t- Use empathetic language\n..."
}
6. Claude가 메모리를 활용해 도움을 줘요:
"Based on your customer service guidelines, I can help you craft a response. Please share the ticket details..."
메모리 도구는 모든 Claude 4 이상 모델에서 사용할 수 있어요. Anthropic이 제공하는 도구 전체 목록은 도구 레퍼런스를 확인하세요.
시작하기¶
메모리 도구를 쓰는 건 두 단계로 나눠져요:
- 요청에 메모리 도구를 추가해요.
tools항목{"type": "memory_20250818", "name": "memory"}가 전부예요. 여기서name은 반드시memory여야 하고, Anthropic 제공 도구에는 입력 스키마를 따로 정의하지 않아요. - 각 메모리 명령에 대한 클라이언트 측 핸들러를 구현해요. 핸들러는
/memories밖의 경로를 거부해야 하므로, 코드를 쓰기 전에 경로 탐색 보호부터 읽어두세요.
기본 사용법¶
Claude가 메모리 도구를 사용하도록 요청하려면 tools 배열에 메모리 도구만 추가하면 돼요. 인메모리 예시는 다음과 같아요:
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-opus-5",
max_tokens=2048,
messages=[
{
"role": "user",
"content": "Help me respond to this customer service ticket.",
}
],
tools=[{"type": "memory_20250818", "name": "memory"}],
)
print(message)
cURL, CLI, TypeScript, C#, Go, Java, PHP, Ruby 등 다른 언어 예시는 공식 문서의 코드 그룹을 참고하세요.
메모리 핸들러 구현¶
위 예시에 대한 Claude의 응답은 view /memories 같은 메모리 작업을 요청하는 tool_use 블록으로 끝나요. 애플리케이션은 그 작업을 실제로 실행하고, 결과를 tool_result 블록으로 반환한 다음, Claude가 계속 이어갈 수 있도록 대화를 다시 보내요. 이게 표준 도구 사용 루프(tool-use loop)예요.
네 개 SDK는 도구 인터페이스와 루프를 처리해 주는 메모리 도구 헬퍼를 제공해요. BetaAbstractMemoryTool을 서브클래싱하거나(Python, C#), betaMemoryTool을 쓰거나(TypeScript), BetaMemoryToolHandler를 구현해서(Java) 디스크의 파일·데이터베이스·클라우드 스토리지·암호화된 파일 등 자체 스토리지로 메모리를 지원할 수 있어요. Python과 TypeScript는 바로 쓸 수 있는 로컬 파일시스템 구현인 BetaLocalFilesystemMemoryTool도 제공해요. 메모리 도구 자체에는 베타 헤더가 필요 없지만, 헬퍼와 도구 러너 인터페이스는 각 SDK의 베타 네임스페이스에 있어요. Go와 Ruby SDK에는 메모리 헬퍼가 없어서 해당 예시는 도구 사용 루프를 직접 실행하고, PHP는 핸들러 클로저를 범용 BetaRunnableTool로 감싸요. 세 경우 모두 자기 스토리지로 바꿀 수 있는 인메모리 저장소를 사용해요.
import anthropic
from anthropic.tools import BetaLocalFilesystemMemoryTool
client = anthropic.Anthropic()
memory = BetaLocalFilesystemMemoryTool(base_path="./memory")
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Remember that customer Acme Corp prefers email follow-ups.",
}
],
tools=[memory],
)
final_message = runner.until_done()
print(final_message.content)
TypeScript, C#, Go, Java, PHP, Ruby 예시를 포함한 전체 코드는 공식 문서를 참고하세요. Go·PHP·Ruby 예시의 인메모리 저장소는 tool_use 블록의 input에 있는 command 필드에 따라 분기하고, 도구 명령에 설명된 문자열을 반환해요. 프로덕션 핸들러에는 이런 데모 저장소가 생략한 경로 검증도 필요하다는 점 잊지 마세요.
도구 명령¶
클라이언트 측 구현은 다음 명령들을 처리해야 해요. 이 사양은 권장 동작과 반환 문자열을 설명해요. Claude는 도구 결과에 포함된 텍스트를 그대로 읽으므로, 애플리케이션에 필요한 경우 다른 문자열을 반환해도 괜찮아요.
view¶
디렉터리 내용, 또는 선택적 줄 범위와 함께 파일 내용을 표시해요:
view_range는 선택 사항이며 텍스트 파일 보기에 적용돼요. [start_line, end_line]은 해당 줄들을 반환하고, [start_line, -1]은 start_line부터 파일 끝까지 전부 반환해요.
반환 값 — 디렉터리의 경우: 파일과 디렉터리를 크기와 함께 보여주는 목록을 반환해요:
Here're the files and directories up to 2 levels deep in {path}, excluding hidden items and node_modules:
{size}\t{path}
{size}\t{path}/{filename1}
{size}\t{path}/{filename2}
- 최대 2단계 깊이까지 파일을 나열해요.
- 사람이 읽기 쉬운 크기를 표시해요(예:
5.5K,1.2M). - 숨김 항목(
.로 시작하는 파일)과node_modules는 제외해요. - 크기와 경로 사이에 탭 문자를 사용해요.
빈 저장소에서 /memories를 처음 view하는 것은 오류가 아니에요. SDK의 로컬 파일시스템 메모리 도구(BetaLocalFilesystemMemoryTool)는 Claude의 첫 호출 전에 메모리 루트를 만들고, 목록 헤더에 이어 빈 디렉터리 자체에 대한 크기-경로 한 줄을 반환해요.
반환 값 — 파일의 경우: 헤더와 줄 번호와 함께 파일 내용을 반환해요:
줄 번호 형식:
- 너비: 6자, 공백 패딩으로 오른쪽 정렬
- 구분자: 줄 번호와 내용 사이에 탭 문자
- 인덱싱: 1부터 시작(첫 번째 줄이 1번 줄)
- 줄 제한: 999,999줄을 초과하는 파일은 오류를 반환해야 해요 — "File {path} exceeds maximum line limit of 999,999 lines."
출력 예시:
Here's the content of /memories/notes.txt with line numbers:
1 Hello World
2 This is line two
10 Line ten
100 Line one hundred
Claude의 도구 설명에는 view가 이미지 파일(.jpg, .jpeg, .png)도 표시하고, 16,000자보다 긴 파일의 텍스트 보기는 잘라낸다고도 명시돼 있어요. 그래서 이미지 경로에 대한 view 호출과, 긴 파일에 대한 후속 범위 지정 보기(view_range)가 온다고 예상하면 돼요.
오류 처리: 파일 또는 디렉터리가 존재하지 않음 — "The path {path} does not exist. Please provide a valid path."
create¶
새 파일을 생성해요:
{
"command": "create",
"path": "/memories/notes.txt",
"file_text": "Meeting notes:\n- Discussed project timeline\n- Next steps defined\n"
}
반환 값: 성공 시 "File created successfully at: {path}"
오류 처리: 파일이 이미 존재함 — "Error: File {path} already exists"
Claude의 도구 설명에는 create가 파일을 "생성하거나 덮어쓴다"고 되어 있어요. 그러니 이미 존재하는 경로에 대한 create 호출이 올 수 있어요. 오류를 반환하는 것이 참조 동작이고, 대신 덮어쓰는 것도 유효한 구현 선택이에요.
str_replace¶
파일의 텍스트를 교체해요:
{
"command": "str_replace",
"path": "/memories/preferences.txt",
"old_str": "Favorite color: blue",
"new_str": "Favorite color: green"
}
str_replace에서 new_str은 선택 사항이에요. 생략하면 old_str이 대체 없이 그냥 삭제돼요.
반환 값: 성공 시 "The memory file has been edited."에 이어 줄 번호가 포함된 편집된 파일 스니펫
오류 처리:
- 파일이 존재하지 않음: "Error: The path {path} does not exist. Please provide a valid path."
- 텍스트를 찾을 수 없음: "No replacement was performed, old_str{old_str}did not appear verbatim in {path}."
- 중복 텍스트(old_str이 여러 번 나타남): "No replacement was performed. Multiple occurrences of old_str{old_str}in lines: {line_numbers}. Please ensure it is unique"
- 디렉터리 처리: 경로가 디렉터리인 경우 "파일이 존재하지 않음" 오류를 반환해요.
insert¶
특정 줄에 텍스트를 삽입해요:
{
"command": "insert",
"path": "/memories/todo.txt",
"insert_line": 2,
"insert_text": "- Review memory tool documentation\n"
}
insert_text는 insert_line 줄 뒤에 삽입되고, 0은 파일의 시작 부분에 삽입해요.
반환 값: 성공 시 "The file {path} has been edited."
오류 처리:
- 파일이 존재하지 않음: "Error: The path {path} does not exist"
- 잘못된 줄 번호: "Error: Invalidinsert_lineparameter: {insert_line}. It should be within the range of lines of the file: [0, {n_lines}]"
- 디렉터리 처리: 경로가 디렉터리인 경우 "파일이 존재하지 않음" 오류를 반환해요.
delete¶
파일 또는 디렉터리를 삭제해요:
반환 값: 성공 시 "Successfully deleted {path}"
오류 처리: 파일 또는 디렉터리가 존재하지 않음 — "Error: The path {path} does not exist"
디렉터리 처리: 디렉터리와 그 모든 내용을 재귀적으로 삭제해요. 도구 설명은 Claude에게 /memories 디렉터리 자체는 삭제할 수 없다고 알려주므로, 경로가 메모리 루트인 delete는 거부하세요.
rename¶
파일 또는 디렉터리의 이름을 변경하거나 이동해요:
반환 값: 성공 시 "Successfully renamed {old_path} to {new_path}"
오류 처리:
- 원본이 존재하지 않음: "Error: The path {old_path} does not exist"
- 대상이 이미 존재함(덮어쓰지 않음): "Error: The destination {new_path} already exists"
디렉터리 처리: 디렉터리의 이름을 변경해요. 도구 설명은 Claude에게 /memories 디렉터리 자체의 이름은 변경할 수 없다고 알려주므로, old_path가 메모리 루트인 rename은 거부하세요.
프롬프트 가이드¶
요청의 tools에 메모리 도구가 있으면 API가 자동으로 아래 지침을 시스템 프롬프트(system prompt)에 추가해요. 직접 보낼 필요는 없어요:
IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE.
MEMORY PROTOCOL:
1. Use the `view` command of your `memory` tool to check for earlier progress.
2. ... (work on the task) ...
- As you make progress, record status / progress / thoughts etc in your memory.
ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory.
Claude의 도구 설명이 이미 메모리 디렉터리를 정리된 상태로 유지하라고 지시하므로, 그 지침을 반복할 필요는 없어요. 그래도 Claude가 어수선한 메모리 파일을 만든다면 프롬프트에서 이를 더 강화할 수 있어요:
Note: when editing your memory folder, always try to keep its content up-to-date, coherent and organized. You can rename or delete files that are no longer relevant. Do not create new files unless necessary.
Claude가 메모리에 무엇을 기록할지 안내할 수도 있어요. 예: "Only write down information relevant to
보안 고려 사항¶
애플리케이션이 Claude가 요청하는 모든 파일 작업을 실행하므로, 아래 안전 장치는 전부 사용자 책임이에요.
민감한 정보¶
Claude는 일반적으로 민감한 정보를 메모리 파일에 기록하는 것을 거부해요. 더 강력한 보장을 원한다면, 핸들러가 파일을 쓰기 전에 민감한 데이터를 제거하는 검증을 추가하세요.
파일 저장 크기¶
메모리 파일 크기를 추적하고 파일이 커질 수 있는 한도를 설정하세요. view 명령이 반환하는 문자 수에 한도를 두고, Claude가 view_range로 나머지를 페이지 단위로 훑어가도록 하는 것도 고려하세요.
메모리 만료¶
오랫동안 접근되지 않은 메모리 파일은 주기적으로 삭제하세요.
경로 탐색 보호¶
/memories/../../secrets.env 같은 악의적인 경로는 /memories 디렉터리 밖의 파일에 닿을 수 있어요. 구현은 디렉터리 탐색 공격(directory traversal)을 막기 위해 모든 명령의 모든 경로를 검증해야 해요. 다음 안전 장치를 고려해 보세요:
- 모든 경로가
/memories로 시작하는지 검증 - 경로를 정규 형식으로 해석하고 메모리 디렉터리 내에 있는지 확인
../,..\또는 기타 탐색 패턴 같은 시퀀스를 포함하는 경로 거부- URL 인코딩된 탐색 시퀀스(
%2e%2e%2f) 주의 - 언어의 내장 경로 보안 유틸리티 사용(예: Python의
pathlib.Path.resolve()와relative_to())
오류 처리¶
메모리 도구는 텍스트 편집기 도구와 유사한 오류 처리 패턴을 사용해요. 각 명령의 오류 메시지는 도구 명령 섹션에 나열돼 있어요. Claude에게 오류를 알리려면 도구 결과에서 is_error를 true로 설정하고 메시지를 content에 넣으면 돼요:
{
"type": "tool_result",
"tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
"content": "Error: The path /memories/notes.txt does not exist",
"is_error": true
}
컨텍스트 편집 통합¶
메모리 도구는 컨텍스트 편집(context editing)과 함께 사용해 장기 실행 대화를 관리할 수 있어요. 자세한 내용은 컨텍스트 편집을 참고하세요.
컴팩션과 함께 사용¶
메모리 도구는 컴팩션(compaction)과도 함께 쓸 수 있어요. 컴팩션은 서버 측에서 오래된 대화 컨텍스트를 요약하는 기능이에요. 컨텍스트 편집은 클라이언트에서 특정 도구 결과를 지우는 반면, 컴팩션은 대화가 컨텍스트 윈도우 한도에 가까워지면 서버에서 전체 대화를 자동으로 요약해요. 장기 실행 에이전트라면 둘 다 쓰는 걸 고려해 보세요. 컴팩션은 클라이언트 측 관리 작업 없이 활성 컨텍스트를 작게 유지해 주고, 메모리는 요약 뒤에도 남아야 하는 정보를 보존해 줘요.
다중 세션 소프트웨어 개발 패턴¶
여러 에이전트 세션에 걸친 소프트웨어 프로젝트라면, 작업이 진행되면서 임시로 메모리 파일을 써 내려가는 대신 의도적으로 메모리를 설정하세요. 아래 패턴은 메모리를 일종의 복구 메커니즘으로 바꿔 줘요. 각 새 세션은 마지막 세션이 기록해 둔 상태에서 재개돼요.
패턴이 작동하는 방식¶
- 초기화 세션: 첫 번째 세션이 실질적인 작업이 시작되기 전에 메모리 파일을 설정해요. 여기에는 진행 로그(완료된 작업과 다음 작업 추적), 기능 체크리스트(작업 범위 정의), 그리고 프로젝트에 필요한 시작/초기화 스크립트 참조가 포함돼요.
- 후속 세션: 각 새 세션은 해당 메모리 파일을 읽는 것으로 시작해요. 이를 통해 코드베이스를 다시 탐색하거나 이전 결정을 되짚지 않아도 프로젝트 상태를 복원해요.
- 세션 종료 시 업데이트: 세션이 끝나기 전에 완료된 작업과 남은 작업으로 진행 로그를 업데이트해요. 이렇게 해야 다음 세션이 정확한 시작점을 갖게 돼요.
핵심 원칙¶
한 번에 하나의 기능만 작업하세요. 코드가 작성됐을 때가 아니라 엔드투엔드 검증으로 작동이 확인된 후에만 기능을 완료로 표시하세요. 그래야 세션 사이에 진행 로그가 정확하게 유지돼요.
초기화 스크립트, 진행 파일 구조, git 기반 복구를 포함해 이 패턴을 실제로 적용한 사례 연구는 효과적인 하네스: 장기 실행 에이전트를 참고하세요.
다음 단계¶
- Bash 도구: 지속적인 bash 세션에서 셸 명령을 실행해요.
- 컨텍스트 편집: 컨텍스트 편집으로 대화 컨텍스트가 커짐에 따라 자동으로 관리해요.
- 컴팩션: 컨텍스트 윈도우 한도에 가까워지는 긴 대화를 관리하기 위한 서버 측 컨텍스트 컴팩션이에요.
- 도구 레퍼런스: Anthropic 제공 도구 디렉터리 및 선택적 도구 정의 속성에 대한 레퍼런스예요.