
에이전트의 메모리는 수정과 반복을 구분하지 못한다
요약
LLM 에이전트의 메모리 효율성을 높이기 위해 '놀라움(surprise)' 점수를 활용한 드리프트 적응형 메모리 시스템을 구축한 사례를 다룹니다. 코사인 유사도 사전 필터링 오류와 놀라움 점수가 수정과 반복을 구분하지 못하는 문제 등 실제 디버깅 과정을 통해 에이전트 메모리 설계의 난관을 설명합니다.
핵심 포인트
- LLM 호출 없이 신경망을 이용해 메모리 저장 여부를 결정하는 효율적 방식 제안
- 코사인 유사도 사전 필터가 모순된 정보를 걸러내는 데 방해가 될 수 있음
- 놀라움 점수 기반 방식은 정보의 수정과 단순 반복을 구분하기 어려움
- 에이전트 메모리 설계 시 정보의 드리프트(drift)와 망각 로직의 중요성
Qwen 에이전트를 위한 드리프트 적응형 (drift-adaptive) 메모리를 구축하며, 무승부를 승리로 바꾼 단 한 번의 디버깅 세션에 대하여.
저는 LLM 에이전트를 위한 메모리 사이드카 (memory sidecar)를 구축했습니다. 제 아이디어는 간단하면서도, 제가 생각하기에는 약간 영리했습니다. LLM 호출을 전혀 사용하지 않고 무엇을 기억할지 결정하는 것이었습니다. 작은 신경망 메모리 (Titans 스타일, 추론 시 학습)가 들어오는 모든 사실에 대해 "놀라움 (surprise)" 점수를 생성합니다. 새로운 것은 놀랍기 때문에 저장합니다. 반복되는 것은 놀랍지 않으므로 건너뜁니다. Mem0나 Zep 같은 시스템들이 매 턴마다 LLM 호출 비용을 지불하는 반면, 이 방식은 쓰기 경로 (write path)에서 토큰 소모가 제로입니다.
데모는 훌륭해 보였습니다. 하지만 이것이 실제로 작동하는지 증명하려 했을 때, 제 시스템은 무너졌고 그 과정에서 진짜 문제가 무엇인지 배울 수 있었습니다.
무승부
적응형 망각 (adaptive forgetting)이 도움이 되는지 테스트하기 위해, 저는 벤치마크를 작성했습니다. 사용자의 사실 관계가 시간이 지남에 따라 드리프트 (drift)되는 멀티 세션 대화를 절차적으로 생성하는 방식입니다. 사용자는 Ames에서 Chicago를 거쳐 Seattle로 이동합니다. 차(tea)에서 커피(coffee)를 거쳐 말차(matcha)로 바꿉니다. 각 정책 (policy)은 동일한 스트림과 동일한 검색 (retrieval)을 보게 되므로, 유일한 변수는 쓰기 및 망각 (write-and-forget) 로직입니다. 그런 다음 두 가지를 측정합니다. 현재의 사실을 여전히 기억하는가, 그리고 오래된 사실을 검색 결과로 다시 끌어들이는가?
저는 제 영리한 신경망 게이트 (neural gate)가 승리할 것이라 기대하며 실행했습니다. 하지만 결과는 다섯 줄짜리 코사인 유사도 (cosine-similarity) 베이스라인과 무승부를 기록했습니다. 몇 번의 실행에서는 오히려 패배하기도 했습니다.
이 순간이 프로젝트의 실체를 결정합니다. 숫자를 변명하며 넘기거나, 아니면 왜 그런지 찾아내거나 둘 중 하나입니다. 저는 왜 그런지 찾아 나섰고, 그 답은 서로 겹쳐져 있는 두 개의 별개 버그였습니다.
버그 1: 프리필터 (pre-filter)가 증거를 숨기고 있었다
망각 로직은 다음과 같이 작동했습니다: 새로운 사실이 도착하면, 그것과 모순될 수 있는 오래된 사실을 찾고 (1차적으로 저렴한 코사인 유사도 사용), 그 후 아주 작은 로컬 NLI 모델을 실행하여 그것이 정말로 모순되는지 결정합니다. 만약 모순된다면, 오래된 사실을 감쇠 (decay)시킵니다.
실제 NLI 점수를 출력해 보았습니다. 점수는 거의 완벽했습니다. "Ames에서 Chicago로 이사했다"는 "Ames에 산다"와 0.99의 신뢰도로 모순됩니다. "내 강아지는 이 아파트를 좋아한다"는 아무것과도 모순되지 않으며, 0.00입니다. 모델이 문제는 아니었습니다.
문제는 코사인 사전 필터 (cosine pre-filter)였습니다. 저는 같은 주제의 사실들은 매우 유사할 것이라고 생각하여 이를 0.75로 설정했습니다. 하지만 실제 업데이트는 그렇지 않습니다. "커피로 바꿨다"와 "요즘은 말차만 마신다"의 코사인 유사도는 0.63입니다. 사전 필터가 NLI 모델이 확인하기도 전에 이들을 걸러내 버렸고, 그 결과 오래된 커피 관련 사실이 영원히 살아남게 된 것입니다. 해결책은 사전 필터를 완화하여 판별 신호 (discriminative signal)가 제 역할을 할 수 있도록 하는 것이었습니다. 그러자 오래된 정보의 오염 (stale contamination)이 한꺼번에 거의 모두 사라졌습니다.
그리고 나서, 현재 재현율 (current recall)이 무너졌습니다.
두 번째 버그: 놀라움 (surprise)은 반복과 수정을 구분하지 못한다
여기가 제가 예상치 못했던 부분이며, 이 프로젝트 전체의 핵심 아이디어입니다.
망각 문제를 해결하자, 이제 메모리는 필요한 사실들을 버리기 시작했습니다. 원인을 추적해 보니 범인은 제가 가장 자랑스러워했던 요소인 승인 게이트 (admission gate)였습니다. 지식 업데이트에 어떤 일이 일어나는지 살펴보십시오:
SKIP surprise=0.38 threshold=0.40 "Ames에서 Chicago로 이사했다."
놀라움 게이트 (surprise gate)가 이를 거부했습니다. 당연한 결과였습니다. "Chicago로 이사했다"는 위치에 관한 것이고, 메모리는 이미 위치에 대해 많은 것을 알고 있습니다. 이는 익숙한 주제이므로 놀라움 점수가 낮게 나오고, 게이트는 이를 중복된 반복으로 읽어 버려버립니다.
이것이 문제의 전부를 한 줄로 요약한 것입니다. 놀라움은 새로움 (novelty)을 측정하며, 수정은 새롭지 않습니다. 그것은 중복된 정보와 정확히 똑같이 보입니다. 고정된 임계값 (fixed threshold)은 이를 버립니다. 적응형 임계값 (adaptive threshold) 역시 이를 버립니다. 왜냐하면 놀라움의 크기만으로는 "Ames에 산다"라고 두 번 말한 것과, "Ames에 산다"라고 한 뒤 "Chicago로 이사했다"라고 말한 것을 구분할 수 없기 때문입니다. 둘 다 놀라움 수치는 낮습니다. 하나는 노이즈이고, 다른 하나는 사용자가 일주일 동안 당신에게 말한 가장 중요한 사실입니다.
그렇다면 무엇이 이 둘을 구분할까요? 제가 망각 (forgetting)을 위해 이미 사용하고 있던 것과 동일한 모순 신호 (contradiction signal)입니다. 중복 (duplicate)은 놀라움 수치가 낮고 일관적입니다. 수정 (correction)은 놀라움 수치가 낮으면서도 모순적입니다. 저는 수용 (admission) 단계가 두 신호를 모두 읽도록 만들었습니다. 즉, 정보가 새롭거나(novel), 혹은 당신이 이미 믿고 있는 무언가와 모순될 경우에 사실을 저장하도록 한 것입니다. 이 단 한 번의 변경으로 인해 모순 신호는 이중 역할을 수행하게 됩니다. 단 한 번의 쓰기 (write) 작업으로 수정을 수용하는 동시에, 그 수정이 바로잡는 오래된 사실을 망각하게 됩니다.
또한 이는 기존 문헌의 모든 정적 밀도 게이트 (static density gate)가 왜 업데이트 상황에서 실패하는지를 깔끔하게 설명해 줍니다. 그들은 수정을 거의 중복된 정보로 간주하여 버립니다. 그들은 메모리가 존재해야 하는 바로 그 사례를 구조적으로 인지하지 못하고 있습니다.
결과
400개 이상의 홀드아웃 드리프팅 스트림 (held-out drifting streams, 단일 임계값을 튜닝할 때 사용한 것과는 다른 랜덤 시드 범위를 사용하여 스스로 채점하지 않도록 함)을 대상으로 테스트한 결과, 완성된 컨트롤러는 기존에 발표된 최첨단 (state-of-the-art) 쓰기 게이트보다 깨끗한 회상 (clean recall) 측면에서 0.35 높게 나타났으며, 쓰기당 LLM 토큰을 전혀 사용하지 않고도 오래된 오염 (stale contamination)을 약 9배 줄였습니다. 격차에 대한 모든 신뢰 구간 (confidence interval)은 0을 포함하지 않습니다.

솔직하게 말씀드려야 할 부분
저는 실제 발표된 벤치마크인 LongMemEval의 지식 업데이트 (knowledge-update) 질문 세트에서도 테스트를 진행했습니다. 오라클 (oracle) 설정 환경에서는 망각이 손해로 작용합니다. 모든 것을 저장하는 방식 (store-everything)의 점수는 0.69인 반면, 저의 망각 방식의 점수는 0.33입니다.
그 결과는 실제이며 저는 이를 숨기지 않을 것입니다. 하지만 그 이유를 알게 되면 결과가 납득될 것입니다. 오라클 (oracle) 설정은 정답 모델에게 관련된 모든 이력의 턴 (turn)을 제공합니다. 모델이 "나의 이전 최고 기록은 27:00이었다"와 "새로운 최고 기록은 25:50이다"를 모두 읽을 수 있을 때, 모델은 단순히 더 최신 것을 선택합니다. 이전 값을 잊어버리는 것은 모델이 사용할 수 있었던 문맥 (context)을 제거할 뿐입니다. 망각이 제 역할을 하는 경우는 방해 요소 (distractors)가 있을 때, 즉 오래된 사실이 검색 (retrieval)을 오염시킬 수 있을 때입니다. 이는 드리프트 벤치마크 (drift benchmark)가 분리해내는 지점이며, 오라클 설정이 제거해버리는 지점이기도 합니다. 작은 위안거리는, 그런 상황에서도 저의 정밀한 망각 방식은 단순한 코사인 (cosine) 망각 방식보다 거의 두 배의 성능을 보였으며, 기권 (abstention) 질문에서는 모든 것을 저장하는 방식과 일치했다는 점입니다.
Qwen Cloud 기반 구축
이 시스템은 Qwen Cloud를 위해 구축되었으므로, 실제로 Qwen이 어디에 쓰이는지에 대해 언급하겠습니다. Qwen은 읽기 (read) 측면에서 네 가지 역할을 수행합니다. 첫째, 사용자의 질문에 답합니다. 둘째, 네이티브 함수 호출 (native function-calling)을 통해 회상 (recall)을 주도합니다. 따라서 제가 검색 단계를 하드코딩하는 대신, 에이전트 스스로가 언제 recall_memory 도구를 호출할지 결정하고 쿼리 (query)를 작성합니다. 셋째, 저의 게이트 (gate)가 대체하는 LLM 추출 베이스라인 (LLM-extract baseline) 역할을 수행하며, 이를 통해 동일한 모델에서 정직한 zero-versus-N 토큰 비교를 수행할 수 있습니다. 마지막으로, 더 강력한 Qwen 모델이 벤치마크 정답을 판정합니다. 쓰기 (write) 결정은 이들 중 어떤 것도 호출하지 않으며, 이것이 바로 핵심입니다.
백엔드는 Alibaba ECS 인스턴스에서 실행되며 메모리를 오브젝트 스토리지 (Object Storage)에 스냅샷으로 저장하므로, 세션이 종료되었다가 다시 열려도 에이전트는 여전히 기억합니다. 공유할 만한 유일한 배포 시의 상처는, Alibaba의 싱가포르 리전에서 HuggingFace에 접속할 수 없다는 점입니다. 그래서 첫 번째 모델 다운로드 시 에러 없이 요청이 영원히 멈춰버렸습니다. 저는 모델을 로컬에 미리 캐싱하여 서버로 옮긴 뒤 완전히 오프라인 상태로 실행했습니다. 지나고 보니 당연한 일이었지만, 당시에는 한 시간 동안 조용히 혼란을 겪었습니다.
내가 간직할 교훈
이 프로젝트의 영리한 점은 신경망 메모리 (neural memory) 그 자체가 아니었습니다. 그것은 제가 하나의 신호에 요청했던 작업을 두 개의 신호가 수행하고 있다는 사실을 알아차린 것, 그리고 그 실패가 제 데모를 망가뜨릴 만큼 충분히 정직한 벤치마크 (benchmark)를 구축했을 때에만 나타났다는 점이었습니다. 그 결합 (tie)이 제가 얻은 가장 유용한 결과였습니다. 그것이 최종 결과물이 작동하는 이유입니다.
Flashbulb은 답변을 위해 Qwen을 사용하며, 호스팅 및 지속성 (persistence)을 위해 Alibaba Cloud에서 실행됩니다. MIT 라이선스 하에 오픈 소스로 제공됩니다. 10초 요약을 원하신다면: 몇 가지 사실을 가르치고, 메모리를 클라우드에 저장한 뒤, 세션을 종료하고 다시 열면, 모델은 여전히 그것을 기억합니다. 그리고 당신이 이사를 갔다고 말하면, 모델은 실제로 당신의 말을 믿습니다.
코드 (MIT): https://github.com/somtri/flashbulb-qwen
라이브 데모: http://47.84.205.239/
데모 영상:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기