-
세션이 끝나면 다 잊어버리는 AI — OpenClaw가 memory 도구로 의미 기반 기억을 만든 방법IT 2026. 7. 16. 22:00
오픈소스 개인 AI 어시스턴트 OpenClaw를 며칠 써 보면 누구나 같은 실망을 한 번은 겪는다. 어제 "나는 TypeScript를 선호해"라고 분명히 말했는데, 오늘 새 대화를 열면 에이전트는 그걸 까맣게 모른다. 사람이라면 당연히 기억할 맥락을 매번 처음부터 다시 알려줘야 하는 것이다. 이건 OpenClaw만의 문제가 아니라 거대 언어 모델(LLM)이라는 기술 자체의 본질적 한계다 — 모델은 한 대화(세션) 안에서만 맥락을 들고 있고, 세션이 닫히면 그 안의 모든 것을 잊는다. 이것을 무상태(stateless) — 호출과 호출 사이에 아무 상태도 보존하지 않는 성질 — 라고 부른다. OpenClaw는 이 망각 문제를
memory라는 도구로 푼다. 에이전트가 사실·대화를 디스크에 저장하고, 단어가 아니라 의미로 회상(시맨틱 검색)하게 만드는 도구다. 이 글은 그 도구가 왜 필요했고, 어떤 구조로 풀었으며, 로컬 임베딩으로 프라이버시·비용까지 어떻게 해결하는지를 따라간다.배경 — LLM은 세션이 끝나면 다 잊는다
LLM의 한 번의 호출은 그 순간 프롬프트(prompt — 모델에 넣는 입력 텍스트 전체)에 들어 있는 것만 안다. 대화가 길어지면 OpenClaw는 그 대화 내용을 프롬프트에 계속 쌓아 맥락을 유지하지만, 새 대화를 시작하거나 긴 대화를 압축(compaction — 길어진 대화를 요약해 줄이는 과정)하면 원래 텍스트는 사라진다. OpenClaw 문서는 이 점을 분명히 못 박는다 — "모델은 디스크에 저장된 것만 기억한다. 숨겨진 상태는 없다." 즉 기억하고 싶은 것이 있으면 누군가 파일에 적어야 한다.
다이어그램 설명. 이 그림은 기억 장치가 없을 때 사용자의 선호 정보가 어떻게 증발하는지를 보여준다. 첫 세션에서 사용자가 선호를 말하면 대화가 진행되는 동안엔 프롬프트 안에 들고 있지만, 세션이 닫히거나 긴 대화가 요약으로 압축되는 순간 대화 원문이 사라지고, 새 세션을 열면 모델은 그 선호를 전혀 모르는 백지 상태로 돌아간다. 이 흐름이 핵심인 이유는 망각이 버그가 아니라 무상태라는 설계 그 자체이기 때문이다 — 모델은 호출과 호출 사이에 아무것도 들고 있지 않도록 만들어졌다. 놓치기 쉬운 함정은 "대화가 어딘가에 자동 저장되겠지"라는 직관이다. 디스크에 명시적으로 적지 않으면 아무것도 남지 않는다. 그래서 사람에게 메모장이 필요하듯, 에이전트에게도 기억을 적어 둘 곳과 그걸 다시 찾아오는 방법이 둘 다 필요하다.
핵심 문제 — 저장만으로는 부족하다, "찾아오는 것"이 진짜 문제다
망각 문제의 절반은 "어딘가에 적어 두면" 풀린다. OpenClaw는 에이전트 작업 공간(workspace, 기본
~/.openclaw/workspace)에 평범한 마크다운 파일로 기억을 적는다 — 오래 가는 사실·선호·결정은MEMORY.md에, 그날그날의 관찰과 세션 요약은memory/2026-06-21.md같은 날짜별 노트에. 하지만 진짜 어려운 문제는 그 다음이다. 적어 둔 수백 개의 노트 중에서, 지금 이 질문에 관련된 것을 어떻게 다시 찾아오는가?가장 단순한 방법은 키워드 검색이다. 그런데 키워드는 의외로 자주 빗나간다. 사용자가 예전에 "TypeScript가 좋아"라고 적어 뒀는데 오늘 "타입 안전한 언어 추천해줘"라고 물으면, "TypeScript"라는 단어가 질문에 없으니 키워드 검색은 그 노트를 놓친다. 단어는 다르지만 의미가 같은 경우를 키워드는 잡지 못한다.
다이어그램 설명. 이 그림은 단어 단위 검색이 "의미는 같지만 단어가 다른" 질문에서 어떻게 헛도는지를 보여준다. 질문이 들어오면 가운데 판단 단계에서 저장된 노트에 같은 단어가 들어 있는지를 보는데, 같은 뜻이라도 다른 단어로 물으면(왼쪽 분기) 관련된 선호 메모를 통째로 놓치고, 단어가 정확히 겹칠 때만(오른쪽 분기) 찾아낸다. 이 구조의 한계가 핵심인 이유는, 사람은 같은 생각을 매번 다른 단어로 표현하기 때문이다 — "TypeScript", "타입 안전한 언어", "정적 타입 언어"는 같은 선호를 가리키지만 글자가 다르다. 놓치기 쉬운 함정은 "검색이니까 어련히 찾겠지"라는 기대다. 단어 매칭은 ID·코드 기호처럼 정확히 일치해야 의미 있는 토큰엔 강하지만, 자연어의 동의어·바꿔 말하기엔 약하다. 그래서 기억을 쓸모 있게 만들려면 단어가 아니라 의미로 찾는 방법이 필요해진다.
그래서 무슨 가치인가: 저장은 출발점일 뿐이고, "관련된 것을 의미로 다시 찾아오는 회상(recall)"이 안 되면 적어 둔 기억은 묻혀서 죽은 데이터가 된다.
해결 방법 — 의미로 찾는 시맨틱 검색, 그리고 키워드와의 하이브리드
OpenClaw는 회상 문제를 임베딩 기반 시맨틱 검색(semantic search)으로 푼다. 임베딩(embedding)이란 텍스트를 그 의미를 담은 숫자 벡터(여러 개의 실수로 된 좌표)로 바꾸는 기술이다 — 뜻이 비슷한 문장은 벡터 공간에서 가까운 좌표에 놓인다. "TypeScript가 좋아"와 "타입 안전한 언어 추천해줘"는 글자는 달라도 벡터로 바꾸면 서로 가깝다. 그래서 질문을 벡터로 바꾼 뒤 가장 가까운 노트를 찾으면, 단어가 하나도 안 겹쳐도 의미가 통하는 기억을 회상할 수 있다. 에이전트는 이 회상을
memory_search(의미로 노트를 찾는 도구)와memory_get(특정 파일·줄 범위를 읽는 도구)이라는 두 도구로 사용한다.다이어그램 설명. 이 그림은 의미 기반 회상이 어떻게 단어 매칭의 한계를 넘는지를 두 갈래의 흐름이 만나는 구조로 보여준다. 한 흐름에서는 저장된 노트들이 각각 임베딩(의미를 담은 숫자 벡터)으로 변환되어 SQLite 인덱스에 쌓이고, 다른 흐름에서는 들어온 질문도 똑같은 방식으로 벡터로 바뀐다. 두 흐름이 "벡터 공간에서 가장 가까운 노트 찾기"로 합쳐지고, 단어가 하나도 안 겹쳐도 의미가 가까운 메모를 회상한다. 이 패턴이 핵심인 이유는 검색의 기준이 글자에서 뜻으로 바뀌었기 때문이다 — 노트와 질문을 같은 의미 공간의 좌표로 놓으면 "가깝다 = 뜻이 비슷하다"가 성립한다. 놓치기 쉬운 함정은 "그럼 키워드 검색은 이제 필요 없겠네"라는 결론인데, 다음 절에서 보듯 OpenClaw는 의미 검색과 키워드 검색을 둘 다 쓴다. ID나 코드 기호처럼 정확히 일치해야 하는 것은 여전히 키워드가 더 강하기 때문이다.
하이브리드 검색 — 의미와 단어를 가중치로 섞는다
임베딩 제공자(provider)가 설정돼 있으면
memory_search는 하이브리드 검색(hybrid search)을 쓴다 — 벡터 유사도(의미)와 키워드 매칭(정확한 단어, 예컨대 ID나 코드 기호)을 함께 쓰는 방식이다. 둘은 잘하는 영역이 다르다. 의미 검색은 동의어·바꿔 말하기에 강하고, 키워드 검색(BM25 — 단어 빈도 기반의 고전적 랭킹 알고리즘)은 "버그 #1234",parseConfig같이 글자 그대로 일치해야 의미 있는 토큰에 강하다. OpenClaw는 둘의 점수를 가중치로 섞는데, 기본값은 의미 0.7 : 단어 0.3이다.다이어그램 설명. 이 그림은 하나의 질문이 두 검색 방식으로 동시에 채점된 뒤 가중치로 합쳐지는 흐름을 보여준다. 질문이 두 갈래로 갈라져 의미 유사도 점수와 단어 일치 점수를 각각 매기고, 둘이 0.7 대 0.3의 비율로 합산되어 최종 순위가 정해진다. 이 비율을 쓰는 이유는 회상의 대부분이 자연어 질문이라 의미 쪽에 무게를 더 주는 게 합리적이지만, ID·코드 기호 같은 정확한 토큰을 완전히 버리면 안 되기 때문이다. 이 가중치는 설정에서 바꿀 수 있다.
로컬 임베딩 — 프라이버시와 비용을 한 번에 푼다
여기서 자연스러운 우려가 생긴다. "임베딩을 만들려면 내 개인 메모를 외부 API로 보내야 하나?" 기본값은 OpenAI 임베딩이라 그 경우 메모 텍스트가 OpenAI로 나간다. 개인 일기·재정 기록·가족 메모를 다루는 개인 어시스턴트에서 이건 그냥 넘길 수 없는 문제다. OpenClaw는 제공자를 고를 수 있게 해서 이걸 푼다 — OpenAI 대신 로컬 GGUF 모델(llama.cpp로 내 기기에서 직접 돌리는 임베딩 모델 파일 포맷), Ollama, 또는 OpenAI 호환 엔드포인트를 지정할 수 있다.
다이어그램 설명. 이 그림은 같은 메모 텍스트가 제공자 선택에 따라 어디서 벡터로 변환되는지가 갈리는 흐름을 보여준다. 로컬 모델을 고르면 임베딩이 내 기기 안에서 만들어져 텍스트가 밖으로 나가지 않고, 원격 API를 고르면 메모가 외부로 전송되며 API 키와 호출 비용이 든다. 이 선택지가 핵심인 이유는 개인 어시스턴트가 다루는 데이터의 민감도 때문이다 — 일기나 재정 메모를 외부로 보내지 않고도 의미 검색을 쓸 수 있다는 게 곧 "프라이버시를 지키면서 회상한다"는 뜻이다. 기본 로컬 모델은
embeddinggemma-300m(약 0.6GB)으로 자동 내려받아져 가볍게 돌아간다.저장은 SQLite — 벡터와 전문 검색을 한 파일에
그럼 임베딩으로 만든 벡터와 단어 색인은 어디에 두는가? OpenClaw의 기본(builtin) 백엔드는 SQLite(파일 하나로 동작하는 임베디드 데이터베이스)에 둔다 — 추가 의존성 없이 키워드 검색·벡터 유사도·하이브리드 검색이 한 파일 안에서 다 된다. 인덱스는 기본적으로
~/.openclaw/memory/{agentId}.sqlite에 에이전트별로 저장된다.다이어그램 설명. 이 그림은 메모리 인덱스 하나의 SQLite 파일 안에 세 가지 역할이 함께 들어 있는 구조를 보여준다. 의미 유사도 쿼리를 위한 벡터 저장, 키워드 검색을 위한 전문 색인(FTS5), 임베딩 캐시가 모두 한 파일에서 운영된다. 별도 벡터 DB 서버를 띄우지 않아도 파일 하나로 의미 검색과 키워드 검색이 동시에 돌아가니 개인 기기에서 운영 부담이 거의 없다. 임베딩 캐시 덕분에 노트를 조금 고쳐 재색인해도 안 바뀐 부분은 다시 임베딩하지 않아 비용·시간이 절약된다.
회상의 품질을 다듬는 손잡이 — 다양성과 최신성
의미로 가장 가까운 노트만 뽑으면 한 가지 함정이 있다. 거의 똑같은 내용의 메모가 여러 개 있으면 회상 결과가 그 비슷한 것들로만 채워져, 정작 다른 관점의 정보가 밀려난다. OpenClaw는 이를 두 개의 선택적 손잡이로 다듬는다 — MMR(Maximal Marginal Relevance — 관련성과 다양성을 함께 따지는 재정렬)과 시간 감쇠(temporal decay)다.
다이어그램 설명. 이 그림은 검색 후보가 최종 회상 결과로 정해지기까지 두 단계의 보정을 거치는 흐름을 보여준다. 하이브리드 검색이 뽑은 후보들이 먼저 다양성 재정렬을 거쳐 거의 똑같은 메모가 상위를 독점하지 않게 골고루 섞이고, 이어 시간 감쇠가 오래된 노트의 점수를 낮춰 최신 정보에 가중치를 준다(기본은 30일마다 점수가 절반). 오래 가는 사실을 담는 파일과 날짜 없는 노트는 감쇠에서 제외된다 — "나는 TypeScript를 선호해" 같은 상시 유효한 선호가 시간이 지났다고 잊히면 안 되기 때문이다. 이 손잡이들이 핵심인 이유는 "가장 가까운 것"만으로는 회상 품질이 충분치 않아서다 — 비슷한 것만 쏟아지거나, 1년 전 결정이 어제 결정과 같은 무게로 올라오면 곤란하다.
결과 — 무엇이 좋아졌나
memory도구가 들어오면서, 앞서 본 망각과 회상 실패가 이렇게 정리된다.이전 (기억 없는 무상태 에이전트) 이후 (memory 도구 + 시맨틱 검색) 세션이 끝나면 모든 맥락을 잊음 마크다운 파일에 저장 → 다음 세션이 회상 키워드가 안 겹치면 관련 메모를 놓침 의미로 찾아 동의어·바꿔 말하기도 회상 ID·코드 기호 검색은 의미 검색이 약함 하이브리드 — 의미 0.7 + 단어 0.3로 보완 임베딩하려면 개인 메모를 외부로 전송 로컬 GGUF/Ollama로 기기 안에서 임베딩 비슷한 메모·오래된 정보가 결과를 점령 다양성 재정렬·시간 감쇠로 품질 보정 정리하면, OpenClaw의
memory도구는 에이전트를 "매번 처음부터 다시 설명해야 하는 무상태 챗봇"에서 "어제 한 말을 의미로 기억하는 어시스턴트"로 바꾸는 전환점이다. 기억을 평범한 마크다운 파일에 저장하되, 회상은 단어가 아니라 의미로 하고, 키워드가 강한 영역은 하이브리드로 보완하며, 그 모든 임베딩을 내 기기 안에서 만들어 개인 메모를 밖으로 내보내지 않는다 — 프라이버시와 호출 비용을 동시에 잡으면서. 그래서 봇이 어제 말을 또 잊은 것처럼 보일 때 의심할 것은 "모델이 멍청해서"가 아니라 "그 사실이 파일에 저장됐는가, 그리고 회상 설정(제공자·하이브리드·감쇠)이 제대로 됐는가"다. 결국 이건 "AI가 얼마나 똑똑하냐"만큼이나 "그 똑똑함이 어제의 맥락 위에 쌓이느냐"가 개인 어시스턴트의 쓸모를 결정한다는 설계 판단이다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
AI 도입 후 찾아오는 정체기 — 진짜 벽은 입력과 출력의 마찰이다 (0) 2026.07.18 AI로 10배 더 만드는데, 왜 결과를 아무도 안 믿을까 — 이해부채와 이해의 항복 (0) 2026.07.18 외부 시스템마다 도구를 손으로 만들면 안 끝난다 — OpenClaw가 MCP로 남의 도구를 꽂아 쓰는 법 (0) 2026.07.17 텍스트만 뱉는 에이전트는 그림을 못 그린다 — OpenClaw가 미디어 생성을 프로바이더 추상화로 푼 방법 (1) 2026.07.17 지금 시키는 일만 하던 에이전트가 미래의 자기에게 일을 거는 법 — OpenClaw cron 도구 (1) 2026.07.16 큰 작업을 혼자 떠안지 않는 에이전트 — OpenClaw가 하위 작업을 격리 세션으로 떼어내는 법 (0) 2026.07.16 에이전트가 답만 뱉던 시절은 끝났다 — OpenClaw가 message 도구로 능동 발신과 채널 액션을 연 방법 (0) 2026.07.15 LLM에게 파일을 통째로 다시 쓰게 두면 안 되는 이유 — OpenClaw가 파일 편집을 4개 도구로 쪼갠 방법 (0) 2026.07.15 AI 에이전트에게 셸을 쥐여 주는 순간 — OpenClaw가 exec 실행과 승인 게이트로 위험을 길들인 방법 (0) 2026.07.15 fetch로는 로그인·동적 페이지를 못 읽는다 — OpenClaw가 격리 브라우저로 푼 방법 (0) 2026.07.14