몇 달 전 MemKraft의 LongMemEval 98.0%를 알린 뒤로 토끼굴에 공지를 못 했다. MemKraft를 개인 에이전트에 붙여 매일 쓰면서 문제를 하나씩 고치다 보니 어느새 v3가 되어 있었다. 많이 기억하고 잘 찾으면 된다고 생각했는데, 기억이 늘어날수록 더 어려운 질문들이 나타났다.
v1.0.2에서는 먼저 성능을 재현할 수 있게 했다. LongMemEval의 데이터 준비, 검색, 답변, 채점을 다시 돌릴 수 있는 평가 도구를 패키지에 넣었다. 검색도 정확한 표현, 의미 확장, 시간 단서, 통합 순위로 나눴다. v1.0.3에서는 긴 회의록을 겹치는 조각으로 저장했다. 필요한 한 문장이 수천 자 안에 묻히지 않게 하고, 정확한 검색이 실패할 때만 느슨한 검색을 쓰게 했다.
곧 저장량 자체가 문제가 됐다. 내 MEMORY.md가 153KB까지 커진 적이 있다. v1.1.0은 기억을 가져오고, 오래된 항목을 보관층으로 옮기고, 정해진 크기로 요약하고, 전체 상태를 진단하게 했다. v1.1.1은 파일 변경을 감시하고 정리 작업을 예약했다. 중요한 점은 오래된 기억을 버리지 않았다는 것이다. 많이 기억하는 기반을 유지하면서, 지금 자주 필요한 것과 오래 보관할 것을 나눴다.
v2.0에서 문제의 모양이 바뀌었다. 메모를 각각 찾는 것만으로는 관계를 설명할 수 없었다. A가 B와 일하고 B가 C를 맡는다는 사실을 모두 저장해도, 셋을 연결한 질문에는 자주 틀렸다. 그래서 로컬 SQLite 지식 그래프를 붙였다. 사람, 조직, 프로젝트를 선으로 잇고 여러 단계를 따라가게 했다.
v2.1은 한국어 조사와 어순에서도 이 관계를 뽑도록 고쳤다. v2.2는 담당자가 CEO에서 CTO로 바뀌면 예전 역할의 유효 기간을 닫았고, 질문 유형에 따라 정확 검색, 관계 확장, 시간 순서를 여러 번 훑었다. v2.3은 여기서 더 나아갔다. BM25로 문서 길이와 희귀 단어를 반영하고, RRF로 서로 단위가 다른 검색 순위를 안전하게 합쳤다. 원인과 결과의 사슬, 중복 기억과 만료된 사실을 정리하는 consolidation, 시간 질문과 개수 질문을 위한 별도 경로도 이 시기에 들어갔다.
이 과정에서 한 가지를 배웠다. 잘 찾는 시스템은 틀린 것도 잘 찾는다. 담당자가 바뀌었는데 석 달 전 메모가 검색 1위로 올라오면, 못 찾는 것보다 더 위험하다. 관계와 시간은 검색을 꾸미는 부가기능이 아니었다. 어떤 사실이 누구와 연결되고 언제까지 참이었는지 알아야 현재의 답이 된다.
v2.6에서는 기억을 일화, 일반 지식, 절차로 구분하고, 활동량과 중요도에 따라 보관 등급을 추천했다. 같은 대상에 서로 다른 값이 동시에 유효하면 충돌로 표시했다. 기억이 많아진 뒤에는 저장 여부보다 어떤 종류의 기억인지, 서로 양립할 수 있는지가 중요해졌기 때문이다.
실패도 있었다. v2.7.3에서 문장을 숫자 벡터로 바꾸는 로컬 embedding 검색을 실험했다. 표현이 달라도 의미가 비슷한 문장을 찾으려는 시도였다. 그러나 검증에서는 검색 시간이 약 13배 늘었고 유의미한 정확도 향상은 없었다. v2.7.4에서 기본 경로에서 빼고 선택 기능으로 돌렸다.
그 뒤 v2.8과 v2.9는 더 화려한 검색법보다 기존 검색을 제대로 빠르게 만드는 데 집중했다. 문서를 매번 다시 읽지 않도록 인덱스와 읽기 캐시를 만들고, 역색인으로 관련 후보만 훑었다. 빠르다는 이유로 기억을 누락하지 않도록 기존 결과와 동일한지도 함께 검사했다.
v2.7.1에서 들어간 ReasoningBank는 또 다른 문제에서 시작했다. 에이전트가 지난달 실패한 방식으로 같은 작업을 다시 시도했다. 결과만 저장하고 그 결과에 이른 과정은 버렸기 때문이다. ReasoningBank는 생각, 행동, 결과, 교훈을 하나의 궤적으로 남겼다.
v2.9.2에서는 이를 한 번의 호출로 기록하고 유사한 과거 작업을 찾게 했다. v2.10과 v2.11에서는 작업 시작 전에 관련 실패와 성공을 짧은 분량으로 불러오되, 그 내용을 신뢰할 수 없는 인용문으로 취급했다. 기억 속 문장이 다음 에이전트에 명령을 내리면 안 되기 때문이다.
v2.12부터 v3의 기반 공사가 시작됐다. Memory Gym은 관계, 시간, 충돌, 희귀 단서가 섞인 시험으로 검색 변경을 평가하고, 기준을 넘지 못하면 릴리스를 막는다. provenance는 기억이 어느 문서와 구간에서 나왔는지 기록하고
why()로 근거를 되짚게 했다.v2.13의 candidate는 검토 전 정보를 곧바로 사실로 승격하지 않고 임시 보관한다. session overlay는 같은 대화에서는 방금 들은 내용을 바로 쓰되 다른 대화와 장기 기억에는 새지 않게 한다. resolver dry-run은 저장하기 전에 중복, 수정, 충돌 여부를 미리 보여준다.
v3.0은 이 조각들을 기억의 생애주기로 묶었다. 정보가 들어오고, 검증되고, 현재 사실이 되고, 낡고, 정리되고, 다시 쓰이는 전 과정이다.
v3.0.1은 현재 사실의 갱신 상태와 후보 기억의 폐기를 감사할 수 있게 했고, 숫자의 합계나 기간도 근거가 분명할 때만 계산하게 했다. v3.0.2는 제한된 컨텍스트 안에서도 본문보다 날짜가 먼저 잘려 시간 계산이 틀리는 문제를 고쳤다. 날짜, 시간, 숫자의 표기 차이도 실제 오답과 채점 방식의 오차를 구분해 측정하게 했다.
v3.0.3에서는 ReasoningBank의 자연어 힌트가 모델 호출을 안정적으로 줄이는지 28개 과제와 9개 자료로 총 1,260회 실험했다. 결과는 gate FAIL이었다. 자연어 교훈은 다시 해석해야 했고, 정확도와 지연이 안정적이지 않았다. 여기서 기억과 실행 사이에는 권한 경계가 필요하다는 결론에 도달했다.
그래서 만든 deterministic execution은 기억 속 문장을 실행하는 기능이 아니다. 출처와 파일 무결성을 확인하고, 미리 허용한 여섯 개의 정확한 절차 문법과 일치할 때만 로컬에서 처리한다. 임의 코드와 셸 명령은 실행하지 않는다. 모호하면 닫힌 상태로 실패하고 기존 모델 경로를 정확히 한 번만 호출한다.
고정된 28개 사례에서 24개를 로컬로 처리하고 4개만 모델로 넘겼다. 정확도는 28/28을 유지했고 호출은 28회에서 4회로 85.714% 줄었다. 실제 provider 순차 실험에서는 305.406초가 12.894초가 됐지만, 긴 지연이 포함된 단 한 번의 관측이므로 일반적인 성능으로 주장하지 않는다.
전체 검증은 2,240 passed, 3 skipped였고 독립 리뷰의 Critical과 Important 지적은 0건이었다. 기존 Markdown, schema v1, 공개 API도 그대로 호환된다.
에이전트의 기억이 다음 행동의 근거가 되는 순간, 기억 시스템은 권한 시스템이기도 하다. 많이 기억하는 능력 위에 연결과 시간, 출처와 검증, 실패 학습과 안전한 실행이 차례로 쌓여야 한다.
내가 만들고 싶은 것은 많이 기억하고, 정확히 연결하고, 근거를 설명하며, 기억한 것을 다음 행동에 제대로 쓰는 에이전트다.
MemKraft는 MIT 라이선스로 공개되어 있다. 스타, 포크, PR 모두 환영한다.
https://github.com/seojoonkim/memkraft


