떠올린 뒤에는——AI Agent는 쓸수록 어떻게 나를 더 잘 이해하게 될까
기억을 금고에서 어떻게 꺼낼까요? 일곱 개의 구성 요소와 하나의 파이프라인으로 이루어진, session을 넘나드는 회상의 전체 경로입니다.
저장하는 건 어렵지 않습니다. 어려운 건 제가 필요할 때 딱 맞는 기억이 스스로 떠오르게 하는 것입니다.
—— Write Track을 완성한 그날 오후, 터미널 앞에서 적은 출발점
Write Track과 Background Track을 다룬 두 글에서는 기억을 어떻게 저장하고 잊는지 이야기했습니다. 두 경로를 연결하면 금고가 스스로 정리되지만, 마지막 한 걸음이 남습니다. 어떻게 다시 꺼낼 것인가 하는 문제입니다.
기억을 어떻게 꺼낼 것인가는 사실 가장 먼저 마주친 문제였습니다. Write Track을 완성한 다음 날 새 대화를 열고 AI에게 “지난주 그 OCR 프로젝트는 어디까지 진행됐어?”라고 물었는데 답하지 못했습니다. 데이터는 분명 있는데 찾지 못한 것입니다. 그때 저장만 해서는 부족하다는 걸 알았습니다.
사실 memvault를 처음 떠올린 건 @AI超元域 에게서였습니다. 그가 openclaw 강의에서 “agent가 쓸수록 나를 더 잘 이해하게 만들자”라는 말을 했는데, 정말 깊이 공감해서 계속 보조 도구를 만들고 싶었습니다. 나중에 openclaw에서 claude code로 돌아오면서, 우선 claude code에서 시작해 memvault의 원형을 만들어 보자고 생각했습니다. 이후 그가 소개한 LanceDB Pro에서도 정교한 설계를 많이 참고하며 memvault를 조금씩 완성해 왔습니다. 진심으로 감사드립니다.
“다시 꺼낼 수 있는” 경로가 기억 시스템 전체의 핵심입니다. 이 글에서는 일곱 구성 요소의 역할 분담, 그 뒤에 있는 설계 철학, 아직 다듬고 있는 몇 가지 경계를 풀어보겠습니다. 이 경로는 지금 매일 작동합니다. Write Track을 완성한 날에는 답하지 못했던 OCR 진행 상황도 이제는 session과 몇 주의 간격을 넘어 물으면 이어서 답합니다.
먼저 처음 구상부터 이야기하겠습니다
처음에는 아주 단순하게 생각했습니다. 받아서 인덱스를 만들고, 조회할 때 가장 비슷한 몇 건을 찾으면 된다고요. 하지만 일주일간 만들어 보니 부족했습니다. “내 그 작업은 어디까지 했지?”, “최근에 무슨 얘기를 했지?”, “다음에 어떻게 하면 좋을까?”라는 세 질문을 같은 경로로 조회하면 모두 빗나갔습니다. 서로 다른 세 가지 조회 방식이 필요했습니다.
첫째, 먼저 어떤 질문인지 추정합니다
“지난주 그 OCR은 어디까지 했어?”, “최근에 무슨 얘기를 했지?”, “X를 해볼까 생각 중인데 어떻게 생각해?”라는 세 가지 질문은 서로 다른 경로를 거쳐야 합니다. 첫 단계는 진행 상황, 회상, 조언 중 무엇을 묻는지 가려내는 것입니다. 그래야 뒤따르는 정렬 가중치와 깊이가 맞아집니다. 처음에는 이 단계를 나누지 않아 “작업”이라는 단어가 3주 전의 무관한 대화와 match되곤 했습니다.
분류는 두 겹의 깔때기를 거칩니다. 먼저 키워드를 훑는데 비용이 들지 않습니다. 다음으로 의미 벡터를 계산하는데 몇 밀리초면 됩니다. 둘 다 확신하지 못할 때에만 LLM에게 한 번 판단을 맡깁니다. 이 단계는 비용이 훨씬 큽니다. 대부분의 질문은 앞의 두 단계에서 분류되고, LLM은 정말 모호할 때만 동원됩니다.
정확히 분류하고 나면 뒤따르는 각 단계의 가중치가 자동으로 바뀝니다. 진행 상황을 물으면 시간 순위의 비중이 커지고, 정의를 물으면 의미 유사도의 비중이 커지며, 조언을 물으면 확장 사고를 위한 갈림길이 열립니다. 같은 agent라도 질문 방식에 따라 받는 기억이 달라집니다. 새 session에서 “지난주 그 OCR은 어디까지 했어?”라고 물어도 agent가 대화를 이어갈 수 있는 이유는 기억력이 좋아서가 아니라, 무엇을 묻는지 먼저 제대로 판단했기 때문입니다.
하지만 “무엇을 묻는가”는 한층 더 세분할 수 있습니다. 같은 “최근 어떻게 지내?”라도 바쁠 때는 진행 상황을 묻고, 휴가 때는 지난 시간을 돌아보려는 뜻일 수 있습니다. 문장만 봐서는 구분할 수 없습니다. 그래서 분류 위에 개인화된 선호도를 한 겹 더 얹었습니다. 시스템은 최근 7일, 30일, 90일 동안 어떤 유형의 질문을 자주 했는지 보고 그 선호도를 판단에 섞습니다. 과거를 자주 돌아보는 사람의 “최근 어떻게 지내?”는 회고 쪽으로, 진행 상황을 자주 확인하는 사람의 질문은 진행 상황 쪽으로 기웁니다. 같은 말도 사람에 따라 다른 경로를 탑니다.
개인화 선호도 층은 Background Track의 관심사 프로필과 출처가 같습니다. 무엇을 봤고, 얼마나 머물렀고, 몇 번 다시 돌아왔는지가 서서히 취향의 윤곽을 그립니다. 의도 분류는 “말 그대로 무엇을 묻는가”를 맡고, 이 층은 “가장 자주 알고 싶어 하는 것이 무엇인가”를 맡습니다. 둘을 합쳐야 진짜 원하는 답에 가까워집니다.
둘째, 두 가지 방식으로 동시에 찾습니다: 의미와 키워드
의미 검색과 키워드 검색에는 각각 놓치는 부분이 있어서 이 단계에서는 둘을 동시에 실행합니다. 한쪽은 의미가 얼마나 비슷한지, 다른 쪽은 키워드가 얼마나 일치하는지 계산합니다. 두 순위 목록이 나오면 RRF(역순위 융합)로 합칩니다.
- 의미만 검색할 때: “MLX”라고 물었는데 기억에는 “Apple Silicon 추론 프레임워크”라고 적혀 있다면 의미는 맞지만 키워드는 다릅니다. 다만 약어, 인명, 프로젝트 코드명 앞에서는 놓칠 수 있습니다
- 키워드만 검색할 때: 정확한 문구 일치에는 강하지만 표현을 바꾸면 찾지 못합니다
RRF는 각 ranker의 순위를 점수로 바꿉니다. 해당 기억을 더 앞에 놓은 ranker가 점수를 더 많이 기여합니다. 점수가 아닌 순위로 투표하는 이유는 두 점수의 척도가 달라 그대로 더하면 한쪽으로 치우치기 때문입니다.
이 단계는 순전히 후보를 건지는 단계입니다. 찾은 것이 100건일 수도 있고, 고르는 것은 다음 단계에서 합니다.
셋째, 가장 알맞은 몇 건을 고릅니다: 열한 겹의 순위 매기기
정렬은 100건의 후보를 상위 15건으로 좁힙니다. 겹겹이 쌓인 열한 가지 신호를 이용하며, 각 층은 각 후보에 승수를 더합니다.
- 시간——새로울수록 가점이 붙습니다. 감쇠 곡선은 직선으로 떨어지지 않고 Weibull 형태입니다. 저장 직후 하루 이틀은 천천히 감쇠하고, 한 달 뒤에는 더 빠르게 떨어지다가, 오래 지나면 낮고 안정적인 꼬리 구간에 들어갑니다
- 신뢰도——직접 작성한 기억이 AI가 자동 생성한 기억보다 가점을 받습니다
- 사용 횟수——자주 꺼낸 기억은 가점을, 드물게 쓰인 기억은 감점을 받습니다. 자주 불러와 보는 기억은 더 천천히 감쇠합니다. 가끔 2~3년 전의 기억이 살아남는 것도 이 원리입니다
- 그래프 중심성——지식 네트워크에서 많이 참조될수록 가점을 받습니다
- 의미적 근접도——질문과 비슷할수록 가점을 받습니다
- 점수 하한——너무 낮으면 바로 탈락시킵니다
- 중복 제거——두 건이 너무 비슷하면 점수를 낮춘 뒤 다시 비교합니다
이 11개 층을 아무렇게나 쌓은 것은 아닙니다. 각 층은 검색이나 기억 연구의 검증된 개념과 대응합니다. 시간 감쇠, 신뢰, 그래프 중심성, 망각 곡선, 의미, 노이즈, 중복 제거입니다. 새 방법을 발명한 게 아니라 십여 편의 논문에서 신호를 골라개인 기억이라는 상황에 맞는 정렬 방식을 조합한 것입니다. 그 바탕에는 두 가지 핵심 설계 원칙이 있습니다.
첫째, 의도에 따라 가중치를 다르게 둡니다.사실을 찾을 때는 신뢰, 탐색할 때는 시간, 개체를 찾을 때는 의미에 무게를 둡니다. 같은 후보라도 질문 방식에 따라 순위가 완전히 뒤집힐 수 있습니다. 그래서 첫 단계에서 의도를 분류해야 합니다. 의도가 틀리면 가중치도 틀리고, 이후 아무리 정교하게 정렬해도 소용없습니다.
둘째, 쓰기와 읽기는 서로 이어지는 고리이지 독립된 두 파이프라인이 아닙니다.Write Track은 기억을 쓸 때마다 출처의 신뢰도를 매깁니다. Read Track은 정렬할 때 그 점수를 가중치로 읽습니다. 더 중요한 것은 반대 방향입니다. 어떤 기억을 읽을 때마다 시스템은 “읽혔다”는 사실을 해당 기억에 다시 기록합니다. 그러면 다음번에는 그 기억이 더 오래 살아남습니다. 쓸 때 조금 더 작업하고 읽을 때 계산을 덜 하며, 읽는 행동이 다시 기억의 수명을 늘립니다. 일반적인 RAG에는 이 연결이 없습니다. 벡터 저장소가 정적이어서 한 번 쓰면 그대로입니다.
아직 다듬는 중: 순위의 안정성
이 다층 정렬의 어려움은 각 층의 가중치가 서로 잡아당긴다는 점입니다. 하나를 바꾸면 다른 몇 가지 지표도 연쇄적으로 흔들릴 수 있습니다. 지금은 정답을 아는 질문 수십 개로 구성한 golden query 세트로 지킵니다. 가중치를 조정할 때마다 먼저 실행해서 성능이 퇴보하지 않았는지 봅니다. 대부분의 상황에서는 안정적이지만 모든 의도와 시간 범위에서 한결같이 작동하도록 계속 조정하고 있습니다.
넷째, 신중하게 고르는 관문: 주의력 게이트
주의력 게이트는 불필요한 정밀 재정렬 대부분을 생략합니다. 후보가 너무 적거나(두세 건), 앞쪽 몇 건의 점수 차이가 이미 크거나, 모든 후보의 점수가 좁은 범위에 몰린 경우에는 건너뜁니다. 모든 질문에 전체 과정을 적용할 필요는 없습니다.
정렬을 마친 뒤 마지막 정밀 재정렬도 있습니다. 더 비싼 모델에 질문과 후보 기억을 함께 넣어 공동으로 점수를 매깁니다. 단순 비교보다 훨씬 정확하지만 후보마다 모델을 한 번씩 실행해야 해서 느리고 비쌉니다.
정밀 재정렬 모델이 연속 세 번 실패하면 10분 동안 자동으로 순수 정렬 방식으로 돌아갑니다. 억지로 버티지 않는 퓨즈 같은 장치입니다.
다섯째, 깊은 질문에만 택하는 갈림길: 빠른 사고와 느린 사고를 빌려옵니다
진행 상황이나 과거를 묻는 확실성이 높은 질문에는 앞의 네 단계면 충분합니다. 하지만 “X를 해볼까 생각 중인데 어떻게 생각해?” 같은 질문에는 Read Track이 더 느린 갈림길을 탑니다. 적중한 개념에서 출발해 지식 그래프를 따라 몇 단계 이동하고 주변 기억까지 가져옵니다. 이 경로는 비용이 더 들어 가벼운 질문에는 사용하지 않으며, 확장 사고가 필요한 질문으로 판단될 때만 시작합니다.
“가장 비슷한 문단”만 찾아서는 이런 질문에 쓸모 있는 답을 줄 수 없습니다. agent는 인터넷 글 같은 일반적인 조언만 하게 됩니다. 정말 유용한 답은당신의 맥락에서 자라나야 합니다. 과거에 무엇을 했고 최근 무엇에 관심을 두었으며 어떤 개념이 X와 이어지는지가 필요합니다.
이 “빠름 / 느림” 구분은 제가 생각해 낸 게 아니라 Kahneman의 《빠른 생각, 느린 생각》에서 빌려왔습니다. 사람의 뇌에는 원래 두 체계가 있습니다. 하나는 빠르고 직관적이며 힘이 적게 들고, 다른 하나는 느리고 추론하며 수고가 듭니다. 기억 시스템이 모든 질문을 어려운 문제처럼 다뤄서도, 모두 직관적인 문제처럼 다뤄서도 안 됩니다. 그래서 Read Track은 두 경로를 나란히 놓고 질문 자체가 어느 쪽으로 갈지 결정하게 합니다. 사용자가 직접 선택할 필요는 없습니다.
“X를 해볼까 생각 중인데 어떻게 생각해?”라고 물으면 정형화된 조언이 아니라 지난달에 Y를 했고 올해 Z를 언급한 맥락을 담은 답을 받습니다. 그게 이 경로의 종착점입니다.
헷갈리기 쉬운 부분
Read Track에는 두 가지 “느림”이 있는데, 같은 것이 아닙니다.
첫 번째 느림——앞에서 말한 “깊은 질문은 느린 경로를 탄다”는 뜻입니다. 확장 사고가 필요한 질문을 하면 시스템이 그 자리에서 갈림길을 하나 더 택해 그래프에서 이웃을 찾습니다. Kahneman의 이중 체계를 구현한 것으로, 빠른 질문에는 빠르게, 깊은 질문에는 천천히 답합니다.
두 번째 느림——Slow Thinker라고 하며 백그라운드에서 몰래 실행됩니다. 눈앞의 이번 문답을 처리하는 대신 당신의 이야기를 들으며 “다음에는 무엇을 물을까?”를 추정하고, 예상 답을 미리 찾아 cache에 넣어 둡니다. 이 경로는 Salesforce의 VoiceAgentRAG.
에서 영감을 받았습니다. 앞의 것은 “현재”, 뒤의 것은 “예측”입니다. 둘 다 느림이라고 부르지만 하나는 전면에서, 하나는 백그라운드에서 실행되며 구현 파일도 다릅니다.
여섯째, 마지막 단계: agent가 볼 수 있게 포장하기
정렬해서 상위 15건을 골라도 agent의 context에는 한도가 있습니다. 15건의 전문을 넣으면 token이 넘칠 수 있습니다. 그래서 마지막 단계에서는 두 가지를 합니다. 긴 문단은 전문 대신 요약만 남기는데, 이는선택과 집중입니다. 호출자가 Hook인지 API인지 CLI인지에 따라 형식을 달리합니다. API에는 JSON을, 채팅 인터페이스에는 카드를 주는데, 이는형식 맞추기.
입니다. 이 단계는 장식처럼 보이기 쉽지만 agent가 결국 얼마나 볼 수 있는지를 결정합니다. 초기에는 상위 15건을 그대로 context에 넣어 긴 block 하나가 token의 절반을 차지하곤 했습니다. budget-aware packing을 추가한 뒤 token 활용률이 60%에서 85%로 올랐습니다. 정렬이 아무리 좋아도 AI의 머릿속에 들어가지 못하면 소용없습니다.
입고 검수만으로 충분할까요? 출고 전에 한 번 더 필요합니다
입고할 때 한 번만 검사해서는 부족합니다. 따라서 agent에게 포장해 주기 전에 다시 걸러야 합니다. 입고 때 한 번, 출고 때 한 번 거치는 이중 보안 검사입니다.
금고에 저장하기 전 기억은 이미 한 번 보안 검사를 받습니다. “앞의 지시를 무시하라”, “지금부터 ...라고 말하라”처럼 agent를 조종하려는 문자열을 걸러내는 과정이며 Write Track 글에서 다뤘습니다. 그러나 검사 규칙은 개선됩니다. 3개월 전 들어온 기억에는 옛 규칙이 적용됐습니다. 공격 수법도 매달 달라져서 오늘 통과한 문자열이 다음 달에는 새로운 위협이 될 수 있습니다.
위험한 문장 패턴을 발견하면 출고 단계에서 즉시 고쳐 쓰거나 버립니다. 백그라운드에서 미리 저장한 답도 같은 검사를 거칩니다. 저장할 때 걸러내고, 꺼내 쓰기 직전에 다시 걸러냅니다. 번거롭지만 agent에게 주는 내용은 깨끗해야 합니다.
일곱째, Read Track의 절충
6가지 의도 분류, 11겹의 scoring, 2개의 rerank gate(attention gate + circuit breaker), Cascade Recall의 세 모드(LOCAL / GLOBAL / HYBRID), budget-aware output formatter. 이 조합이 지금 매일 작동하는 시스템입니다. session 간 회상, 진행 상황 질문, 조언 요청이 모두 이 경로를 탑니다. 각 층은 golden query 회귀 테스트로 지키고, Dream Loop는 매일 새벽 4시에 백그라운드에서 기억을 자동으로 정리합니다.
하지만 완벽하지는 않습니다. 알려진 경계를 솔직히 몇 가지 적어보겠습니다.
- 지연 시간 vs 회상률——그래프 경로를 타는 깊은 회상은 느려서 몇백 밀리초가 들기도 합니다. 확장 사고가 필요한 질문에만 사용하는 것은 절충입니다
- 정밀 선택 단계의 계산 비용이 큽니다——주의력 게이트로 일부를 아끼지만 실행해야 할 때는 여전히 실행합니다. 퓨즈가 작동해 대체 경로로 돌아가면 결과 품질의 차이가 보입니다
- 동결 층까지 압축된 기억은 전문을 다시 꺼낼 수 없습니다——요약만 남습니다. 법적 추적에는 괜찮지만 당시의 맥락을 재구성하기에는 부족합니다
- 의도 분류가 틀리면 파이프라인 전체가 잘못된 방향으로 갑니다——현재는 동적 신뢰도 임계값으로 빈도를 줄이고 있으며, 사후 복귀 장치는 더 안정적인 방법을 찾는 중입니다
- 자체 평가 층으로 모든 환각을 막을 수는 없습니다——slow 모드에서는 CRAG 자체 평가를 실행하지만 fast 모드에서는 이 층을 생략합니다. 그 대가로 fast 경로에서는 환각이 빠져나갈 수 있습니다
각 항목은 비용과 효과를 맞바꾼 결과입니다. 시스템은 작동하고 있고 실제로 매일 사용합니다. 위 항목은 알려진 경계일 뿐 당장 터질 함정은 아닙니다. 이를 공개하는 이유는 모든 “찾았다”의 비용을 숨기지 않고 적어 두기 위해서입니다.
여덟째, 전체를 관통하는 설계 원칙 몇 가지
이 시스템을 떠받치는 것은 장치 자체보다 반복해서 등장하는 다섯 가지 설계 원칙입니다. 빠른 사고와 느린 사고(질문이 탐색 깊이를 결정), 쓸 때 조금 더 작업해 읽을 때 계산을 줄이기, 읽는 행동 자체가 기억의 수명을 늘리기, intent가 모든 것을 결정하기, trade-off를 숨기지 않고 공개하기입니다.
- 빠른 사고와 느린 사고——모든 질문에 전력을 다할 필요는 없습니다. 질문의 깊이는 질문 자체가 정하며 사용자가 단계를 직접 선택하지 않습니다
- 쓸 때 조금 더 작업하면 조회할 때 계산하지 않아도 됩니다——
trust_score,access_count와 트리플의 이중 투영처럼 쓰기 단계의 “번거로운 추가 작업”은 조회할 때 한 단계를 줄이기 위한 것입니다 - 읽는 행동은 기억의 수명을 다시 기록합니다——질문할 때마다 적중한 기억의 유효 기간이 늘어납니다. 쓰지 않으면 자연히 희미해지고, 자주 찾으면 남습니다. 자주 다니는 길에 풀이 자라지 않는 것과 같습니다
- intent가 모든 것을 결정합니다——질문 방식에 따라 검색 전략, 정렬 가중치, 깊이가 달라집니다. 같은 agent도 질문에 따라 사실상 다른 검색기가 됩니다
- trade-off는 공개해야 합니다——대가가 없는 척할 수 없습니다. 적어 두면 지금의 저도, 나중의 저도 볼 수 있습니다
아홉째, 떠올리는 것만으로는 부족합니다 — 질문하기 전에 준비해 둡니다
좋은 종업원은 주문에 답하기만 하지 않습니다. 잔이 빈 것을 보고 먼저 물을 따라줍니다. Read Track에는 백그라운드에서 몰래 이런 일을 하는 녀석이 있습니다. 당신이 입을 열기 전에 먼저 추정하고, 찾고, 답을 준비합니다.
지금까지는 모두 “당신이 물으면 시스템이 찾는다”는 이야기였습니다. 이 녀석은 다섯 가지 일을 합니다.
- 지금 무슨 이야기를 하는지 듣습니다——현재 대화를 지켜보며 최근 몇 마디로 다음에 무엇을 물을지 추정합니다
- 논리적인 흐름을 따라갑니다——예상한 몇 가지 질문을 사람이 자연스럽게 이어서 물을 순서로 정렬합니다
- 몰래 먼저 답을 찾습니다——가능성이 가장 높은 질문 몇 개에 대해 백그라운드에서 전체 검색을 실행하고 찾은 기억을 가까이 둡니다
- 절제해서 움직입니다——매 문장마다 작동하지는 않습니다. 대화가 너무 짧거나 최근 화제가 확연히 바뀌었거나 방금 예측했다면 다시 움직이지 않습니다. 쓸데없는 비용을 피하려는 것입니다
- 당신이 실제로 물을 때까지 기다립니다——질문하는 순간 먼저 준비해 둔 결과에 맞는 것이 있는지 봅니다. 맞으면 바로 사용해 전체 검색 한 번을 아끼고, 맞지 않으면 정상 경로로 가니 잃는 것이 없습니다
다음 요리를 미리 준비하는 주방장과 같은 원리입니다. 손님이 아직 주문하지 않았지만 전채를 먹은 다음에는 대개 메인 요리를 주문합니다. 가능성 있는 두세 가지 요리의 재료를 미리 손질해 둡니다. 실제로 주문하면 몇 초 만에 내놓을 수 있고, 다른 요리를 주문하면 그 재료를 다음 테이블에 쓸 수도 있습니다. 최악의 경우 버리면 됩니다.
앞서 말한 “빠른 사고와 느린 사고의 갈림길”과 혼동하기 쉽습니다. 그쪽은 질문을 받은 뒤 그 자리에서 깊은 경로를 더 탈지 결정하고, 이쪽은 질문하기 전부터 몰래 움직입니다. 하나는 전면에서, 하나는 백그라운드에서 실행됩니다. 둘 다 “느림”이라고 부르지만 하는 일은 완전히 다릅니다.
준비한 결과가 맞으면 질문부터 답까지 거의 지연이 없습니다. 재료가 이미 손질돼 있기 때문입니다. 맞지 않으면 그 재료는 낭비입니다. 그래서 “절제해서 움직이기”가 중요합니다. 대화가 너무 짧거나, 화제가 벗어났거나, 방금 움직였다면 멈춥니다. 무리하게 추측하느니 적게 추측하는 편이 낫습니다.
백그라운드에서 찾은 재료도 저장실에 들어가기 전에 한 번 소독하고, 저장실에서 꺼내 agent에게 보여주기 전에 다시 소독합니다. 앞서 말한 이중 보안 검사를 이 준비 경로에도 똑같이 적용해야 합니다. “내부에서” 준비했다는 이유로 방심할 수는 없습니다.
여기까지가 지금 Read Track의 전체 모습입니다. 이해하고, 찾고, 정렬하고, 고르고, 넣고, 제때 건넵니다. 각 부분을 여전히 다듬고 있지만 뼈대는 이미 세워졌고 매일 작동합니다.
여기까지 Read Track을 살펴봤습니다. 의도 파악, 검색, 정렬, 선택, 포장, 소독, 사전 검색이라는 일곱 구성 요소와 하나의 파이프라인입니다.
이 시스템은 제가 “기억해야 할 것을 기억하도록” 돕지 않습니다. 그건 Write Track과 Background Track의 책임입니다. Read Track이 맡는 일은 하나입니다. 제가 그 기억이 필요할 때 알맞은 기억이 스스로 떠오르게 하는 것입니다.
첫머리에 쓴 “저장하는 건 어렵지 않다. 어려운 건 알맞은 기억이 스스로 떠오르게 하는 것이다”라는 말대로, 이제는 실제로 떠오릅니다.
아키텍처 개요
Read Track의 진입점은 recall(query, context)이고, 파이프라인의 뼈대는 다음과 같습니다.QueryClassify(의도 분류)→ Fast Search(빠른 회상)→ (Cascade Recall(연쇄 회상), slow only) → Output Formatter입니다. 호출자가 Hook(후크), MCP(Model Context Protocol), CLI(명령줄), API(애플리케이션 인터페이스) 중 무엇이든 같은 파이프라인을 거칩니다. 차이는 마지막 Output Formatter(출력 형식 변환기)가 직렬화하는 형식뿐입니다. Scoring(점수 매기기)과 Reranking(재정렬)은 독립된 stage(단계)가 아니라 qdrant_search() 안에 들어 있습니다(services.py).
이 pipeline은 10편 이상의 연구에서 아이디어를 빌렸습니다.HippoRAG 의 PPR,LightRAG 의 이중 모드 검색,GraphRAG 의 세 겹 KG, HyDE의 이중 task 설계,CRAG 의 자체 평가 게이트,Kahneman 의 fast / slow 역할 분담,VoiceAgentRAG 의 사전 검색, Weibull 감쇠 곡선,RRF 융합,Attention-Residual 의 intent-dependent 가중치입니다. 아래에서 각 구성 요소의 출처를 짚어보겠습니다.
첫째, Query Router 의도 분류
Query Router는 먼저 각 query를 여섯 가지 intent(의도) 중 하나로 분류합니다.entity_lookup,factual,conceptual,exploratory,cross_domain,unknown(query_archetypes.py), 분류 결과는 뒤따르는 세 가지를 결정합니다.LayerPlan(층별 계획: 어느 층을 조회할지),ScoringConfig(점수 설정: 11 stages의 가중치 벡터),RetrievalMode(검색 모드: LOCAL 로컬 / GLOBAL 전역 / HYBRID 혼합)입니다.
판정은 두 경로를 거칩니다.
- 키워드 매칭:
~0ms, 순수 정규식 / 단어 목록 적중 - 의미 벡터:
~5ms, query를 embedding(임베딩 벡터)으로 계산해 archetype(원형) 벡터와 비교
두 쪽의 신뢰도 점수를 합친 뒤에도 동적 임계값보다 낮을 때에만 LLM을 호출합니다(~500ms).query_router.py 안의 QueryClassifyOp 는 이 전체 융합을 하나의 Operator(연산자)로 만듭니다. Slow Thinker(느린 사고)의 사전 검색 결과도 이 층에서 주입합니다.
Personalized Router: 의도 위에 얹는 개인 선호도 층
memvault.query.personalized_router 에서 QueryClassifyOp 뒤에 re-weight 층을 추가해 순수 archetype 분류의 사각지대를 메웁니다. 같은 query “최근 어떻게 지내?”라도 attention profile이 factual 쪽으로 기운 사용자와 exploratory 쪽으로 기운 사용자의 정답 intent는 다릅니다.
- 에서
attention_profile7 / 30 / 90일의 intent 분포를 가져옵니다(BG Track의 Interest Profile과 출처가 같고,attention_tracker.py에서 기록합니다) - 여섯 intent의 archetype 신뢰도 점수에 prior 가중치를 적용합니다.
p_final = p_classify × (1 + α × intent_freq_norm), α의 기본값은 0.25입니다 - 표본이 적을 때의 보호 장치:
profile.sample_count < 50면 바로 bypass합니다(콜드 스타트 편향 방지) - 출력은
PersonalizedIntent이며, 뒤따르는ScoringConfig/RetrievalMode는 원래 archetype 결과가 아니라 이 값을 사용합니다
이 경로는 Background Track의 Interest Profile과 같은 attention_profile 를 읽습니다. BG가 기록하고 Read가 조회할 때 소비하므로, 또 하나의 Write-Read 순환 고리가 됩니다.
둘째, Fast Search: Qdrant Hybrid(혼합 인덱스)+ RRF
qdrant_search()(services.py 근처에서)dense(밀집 벡터, Qwen3 0.6B MLX, 1024d)와 sparse(희소 벡터, BM25 per-service avgdl)를 동시에 조회합니다. 이는 Fast Search가 반드시 실행하는핵심이며, 둘은 다시 Reciprocal Rank Fusion(역순위 융합, RRF)으로 합칩니다.
score_rrf(doc) = Σ_ranker 1 / (k + rank_in_that_ranker)
k의 기본값은 60입니다. 점수가 아니라 순위로 투표하는 이유는 dense와 sparse의 점수 척도가 완전히 달라 그대로 더하면 점수가 큰 ranker(정렬기)에 압도되기 때문입니다.
Scoring과 Reranking은 모두 qdrant_search() 안에 들어 있습니다. 독립 stage가 아닌 것은 의도적인 설계입니다. Scoring에 필요한 access_count,provenance,attention_profile 이 모두 qdrant_search 의 작용 범위(scope) 안에 있으므로 별도의 stage로 빼면 state(상태)를 많이 옮겨야 합니다.
셋째, 11-Stage Scoring Pipeline
11개 stage(scoring_pipeline.py)는 intent에 따라 서로 다른 가중치를 적용합니다.entity_lookup 는 SemanticBoost를 0.5로 올리고,exploratory 는 Recency를 높이며,factual 는 Trust에 더 무게를 둡니다. 초기에는 모든 intent가 같은 가중치를 공유해 factual과 exploratory의 top-10이 8건이나 겹쳤습니다. intent별로 나눈 뒤에야 구분됐습니다. 각 stage는 ScoringOp(점수 연산자, Operator 프로토콜을 따름)입니다.
<code> 1. RecencyBoost (시의성 가중치) × (1 + 0.15 × e^(-age/14)) 2. ImportanceWeight (신뢰도 가중치) × (0.7 + 0.3 × confidence) 3. TrustBoost (신뢰 가중치) × (1 - 0.3 × (1 - trust)) 4. FeedbackBoost (피드백 가중치) × (1 + 0.15 × tanh(net/3)) 5. LengthNorm (길이 정규화) ÷ (1 + 0.3 × |log2(len/500)|) 6. WeibullDecay (Weibull 감쇠) 4-tier: Core 180d · Hot 60d · Warm 30d · Cold 14d 7. PPRBoost (그래프 중심성 가중치) × (1 + 0.3 × ppr_score) # HippoRAG-inspired 8. SemanticBoost (의미 가중치) × (1 + 0.3 × cosine_sim) 9. MinScoreGate (최저 점수 게이트) hard filter < 0.10 10. NoiseFilter (노이즈 필터) 7종 quarantine tag 11. PairwiseDedup (쌍별 중복 제거) cosine > 0.85 → ×0.5 then min_score </code>
Weibull(Weibull 분포) 4-tier는 confidence(신뢰도)가 결정합니다. confidence가 높으면 Core tier(핵심 층)에 들어가 천천히 감쇠하고, 낮으면 Cold tier(차가운 층)에 들어가 14일 만에 절반으로 줄어듭니다.
access_count(접근 횟수)는 effective half-life(유효 반감기, 최대 10x)를 늘립니다. 이는 Read와 Write의 순환 고리 중 하나로, 읽는 행동이 access_count에 다시 기록되어 수명을 늘립니다(이 내용은 Write Track 의 Provenance 단락에서 언급했습니다).
넷째, Jina v3 Reranker + Attention Gate
Attention Gate(주의력 게이트)는 세 가지 skip 규칙으로 불필요한 rerank를 막습니다.
- 후보 ≤ 2건: 바로 return(반환)하고 rerank(재정렬)하지 않습니다
- 상위 점수의 우세: 앞의 두 건 점수 차이 > threshold(임계값)이면 결과가 이미 명확하므로 rerank하지 않습니다
- 밀집 집단: 모든 후보의 점수가 좁은 구간에 몰리면 rerank로도 구분하기 어려워 건너뜁니다
아이디어는 TurboQuant+ 의 early return(조기 반환) 전략에서 얻었습니다.reranker.py 실행하는 모델은 Cross-encoder(교차 인코더) 0.6B MLX(rerank_bridge.py)입니다. query(질문)와 doc(문서)에 함께 점수를 매겨 단순한 dual-encoder(이중 인코더)보다 훨씬 정확하지만, 각 건마다 모델을 한 번씩 실행해야 해서 비쌉니다.
Circuit Breaker(차단기): 연속 3회 실패하면 600s recovery에 들어가 그동안 reranker(재정렬 모델)를 우회하고 순수 scoring을 사용합니다.
Score Blending(점수 융합): 기본값은 0.3 × scoring + 0.7 × rerank이지만 intent에 따라 달라집니다.entity_lookup 의 0.2/0.8 에는 rerank의 비중을 높이고,exploratory 의 0.5/0.5 에서는 scoring의 비중을 절반으로 돌립니다. exploratory 질문에는 절대적인 정답이 없어서 원래 점수가 더 중요하기 때문입니다.
다섯째, Cascade Recall(slow intent only)
Fast path(빠른 경로)는 항상 실행되고, Cascade는 slow intent(느린 의도)에서만 시작됩니다. 둘 중 하나를 고르는 방식은 아닙니다.kg_services.py 안의 cascade_recall()(연쇄 회상)은 Fast Search의 주요 결과(schema 필드 cards)와 Cascade Recall이 확산시킨 보충 결과(cascade_cards)를 하나의 response(응답)로 합칩니다.
이 “fast / slow 이분법”의 뼈대는 Kahneman의 이중 체계(System 1 빠른 사고 / System 2 느린 사고)에서 왔습니다. 초기 버전에서는 사용자가 fast 또는 slow를 직접 골랐지만, 이후 intent가 결정하도록 refactor했습니다(choose_thinking_mode()). 그래도 “빠른 길과 느린 길”의 역할 분담 자체는 바뀌지 않았습니다.
내부에서는 두 경로로 나뉩니다.
- GLOBAL(전역): L2 Summary(LLM이 미리 생성한 커뮤니티 요약)+ L1 Community(Leiden 군집화 알고리즘 결과)입니다. 두 층은 scoring pipeline을 거치지 않습니다. 미리 압축해 둔 view(뷰)라서 바로 가져오면 됩니다
- LOCAL(로컬): L0 Triple + PPR(Personalized PageRank) Walk(그래프 탐색)입니다. 적중한 개체에서 시작해 감쇠 계수 0.85로 그래프를 몇 단계 걸으며 인접 triple을 가져옵니다
Mode는 intent가 결정합니다.entity_lookup/factual 는 LOCAL(정확성이 필요),conceptual/exploratory 는 GLOBAL(전체 조망이 필요),cross_domain 는 HYBRID(혼합, 전체 검색)를 택합니다.
L0/L1/L2 자체는 scoring을 거치지 않습니다. Blocks(기억 블록) 층만 전체 qdrant_search() 의 scoring + reranking을 거칩니다. 이는 cascade_cards 안의 Blocks 부분과 cards 가 같은 정렬 논리를 쓰게 해서 같은 기억이 fast와 cascade에서 서로 다른 점수를 받지 않도록 하기 위함입니다.
헷갈리기 쉬운 점——“Cascade Recall의 slow”와 다음 panel-end에서 말할 “Slow Thinker”는 다른 것입니다. 전자는 Kahneman 계열로,조회하는 바로 그때깊이 파고들지를 결정합니다. 후자는 VoiceAgentRAG 계열로,백그라운드에서 다음 질문을 예측하고미리 찾아 cache에 넣습니다. 둘 다 우연히 slow라고 부르지만 서로 다른 파일에 구현돼 있습니다(kg_services.py vs slow_thinker.py).
Pipeline 순서의 취약성
11개 stage의 순서에는 의존 관계가 있습니다. RecencyBoost가 TrustBoost 앞에 있는 이유는 dream loop가 합친 뒤의 trust가 새 기억과 옛 기억의 시간 순서에 의해 덮일 수 있어 먼저 시간으로 보정해야 하기 때문입니다.
순서에 의존하는 pipeline은 태생적으로 취약합니다. stage 두 개의 위치만 바꿔도 top-k(상위 k건)가 전부 달라질 수 있습니다. 현재는 예상 순위가 정해진 golden query(기준 질문) 수십 개의 회귀 테스트로 지킵니다. 가중치를 바꾸기 전에 실행해 top-k 차이가 임계값을 넘으면 막습니다. 지금은 쓸 만하지만 더 robust(견고)하게 만들기 위해 계속 조정하고 있습니다.
여섯째, Output Formatter와 token 예산
Output Formatter는 파이프라인의 마지막 단계입니다. token 예산 때문에 세 가지를 하게 됐습니다.cards 와 cascade_cards 의 몫을 6:4로 나누고, 너무 긴 block은 요약만 남겨 agent가 전문을 펼칠지 고르게 하며, 중복 문단은 점수가 가장 높은 것만 남깁니다.
- 주요 결과
cards와 확산 결과cascade_cards의 budget(token 예산) 분할(보통 60/40) - 너무 긴 block(기억 블록)에는 먼저 요약을 attach(첨부)하고 원문은
expand(펼치기) 필드에 넣어 agent가 더 볼지 결정하게 합니다 - 중복 문단(cosine > 0.9)은 점수가 가장 높은 것만 남깁니다
모든 진입점(Hook, API, MCP, CLI)은 같은 pipeline(파이프라인)을 거칩니다. 차이는 여기뿐입니다.format(형식)은 직렬화 매개변수이며(text / json / cards), 상위 검색 전략과 전혀 관계가 없습니다. 이전에는 이 층을 과소평가했습니다. top-15(상위 15건)를 그대로 context(문맥)에 넣었더니 긴 block 하나가 token의 절반을 차지해 뒤의 기억이 들어갈 자리가 없었습니다. budget-aware packing(예산 인식 포장)을 추가하니 평균 활용률이 60%에서 85%로 올랐습니다.
Read-Time Sanitize: Write Injection Guard와 대칭
Read 쪽에서 대칭적으로 한 번 더 실행하는 memvault.security.read_sanitize는 Write Track이 구현되기 전에 injection_guard.is_unsafe() 가 쓰기 당시의 규칙 버전만 적용했던 허점을 메웁니다. 3개월 전에 들어온 block에는 옛 규칙이 적용됐고 공격 사례도 진화하고 있습니다.
- 모든
cards/cascade_cards을 Output Formatter 전에 스캔합니다is_unsafe_for_injection()(Write 쪽 ruleset을 공유하며 배포할 때마다 동기화합니다) - 규칙에 적중한 block은
sanitize_for_injection()을 거칩니다. 위험한 token sequence는[REDACTED]로 대체해 의미 문맥을 보존합니다. top-k가 희석되지 않도록 블록 전체를 버리지는 않습니다 - Slow Thinker의 prefetch cache에도 똑같이 적용합니다. cache에 넣기 전에 한 번(write-time), cache에서 꺼내 agent에게 주기 전에 다시 한 번(read-time) 걸러 cache가 read sanitize를 우회하는 뒷문이 되지 않게 합니다
- 적중 이벤트를
audit_log에 기록해 옛 block 중 어떤 것이 새 규칙을 건드렸는지 추적하고, 이를 Write 쪽 ruleset 개선에 되먹입니다
비대칭적인 보안 검사에는 구멍이 있습니다. 쓰기 쪽만 지키는 것은 규칙이 영원히 개선되지 않고 공격도 진화하지 않는다고 가정하는 셈입니다. Write와 Read 양쪽에서 각각 한 번씩 실행해야 오래된 block에도 새 규칙을 적용할 수 있습니다.
일곱째, Trade-off 목록
Read Track은 빠르고 정확하고 완전할 수 없습니다. 각 항목은 비용과 효과를 맞바꾸는 선택이며 세 가지 중 두 가지만 고를 수 있습니다. 아직 완전히 해결하지 못한 것은 대략 다음과 같습니다.
| 문제 | 현재 상태 |
|---|---|
| 지연 시간 vs 회상률 | slow path(느린 경로)는 p95(95백분위 지연 시간)에 큰 영향을 줍니다. 현재는 intent 게이트를 두어 정말 확장 사고가 필요한 질문에만 사용합니다 |
| Reranker의 계산 비용이 큽니다 | Attention Gate가 rerank 요청의 약 30%를 막고, Circuit Breaker가 실패를 600s 동안 격리합니다 |
| Cold / Frozen tier에는 summary만 남습니다 | 전문을 압축하면 다시 꺼낼 수 없습니다. 계획 중인 tier upgrade를 통해 자주 호출되는 cold block(차가운 기억 블록)을 warm(따뜻한 층)으로 올릴 수 있습니다 |
| 의도 오분류 | pipeline 전체가 잘못된 길로 갑니다. 현재는 동적 신뢰도 임계값으로 오분류를 줄이지만 좋은 사후 복귀 방법은 없습니다 |
| CRAG 자체 평가에서 놓침 | deep 모드(깊은 모드)에서만 CRAG를 실행합니다. fast 모드(빠른 모드)에서는 이 층을 생략하므로 fast 경로에서 환각을 놓칠 수 있습니다 |
여덟째, 전체를 관통하는 설계 결정
앞의 일곱 절에서 설명한 장치 아래에는 반복해서 등장하는 다섯 가지 설계 원칙이 있습니다. intent를 모든 하위 단계에 전달하기(intent-driven everywhere),trust_score 와 access_count 가 만드는 write-read 순환 고리, Kahneman의 fast / slow를 thinking_mode로 구현하기, write와 read 양쪽에 defense in depth를 적용하기, 대가가 없는 척하지 않고 모든 trade-off를 공개하기입니다.
- Intent-driven everywhere:
QueryClassifyOp의 intent는 scoring weights, retrieval mode, score blending ratio, cascade layer routing까지 전달됩니다. 같은 query도 intent에 따라 완전히 다른 경로를 탑니다 - Write-Read 순환 고리:
trust_score쓸 때source_tracker가 점수를 매기고 읽을 때TrustBoostOp가 사용합니다.access_count는 읽을 때 다시 기록되어 다음 읽기에서WeibullDecay의 effective half-life에 영향을 줍니다. 이 순환 고리는 Write / Read Track을 가로지르며 단방향 pipeline이 아닙니다 - Kahneman fast / slow:
thinking_mode = fast / slowKahneman의 이중 체계를 구현합니다. slow는 fast보다 Cascade Recall + CRAG 자체 평가를 더 실행합니다. 양자택일이 아니라 slow = fast + extras입니다 - Defense in depth: Write Track의 세 gate와 injection guard가 가로막고, Read Track의 attention gate가 무의미한 rerank를 건너뛰며 circuit breaker가 재정렬 실패를 격리합니다. 각 층은 다음 층이 fail해도 전체가 무너지지 않게 합니다
- Trade-off on paper: 지연 시간 vs 회상률, 계산 비용 vs 품질, 차가운 저장소 vs 전문 복원 등 모든 trade-off를 일곱째 절에 명시하며 대가가 없는 척하지 않습니다
아홉째, Slow Thinker: Predictive Prefetch
Slow Thinker는 독립적인 백그라운드 pipeline(memvault.slow_thinker)으로, 주 recall()을 막지 않습니다. 이벤트 소스는 conversation.utterance.appended이고, Salesforce AI Research의 VoiceAgentRAG(이중 에이전트: 백그라운드 Slow Thinker + 전면 Fast Talker + FAISS speculative cache)에서 영감을 받았습니다. “주방장이 다음 요리를 준비한다”는 이 구성 요소의 기술적 이름에서 빌려온 비유입니다.
다섯 가지 구성 요소
- NextQuestionPredictor: 최근 N=8개의 utterance를 사용하고 작은 LLM을 호출해 예측 query 상위 3개를 만듭니다. Prompt는 “그다음은?” 같은 빈 query를 허용하지 않고 구체적으로 조회할 수 있게 제한합니다
- PredictionPipeline: 5개의 Op를 잇습니다.
ContextSampler→QuestionGenerator→QuestionRanker(대화가 자연스럽게 이어질 가능성 순으로 정렬)→QuestionDeduplicator(최근 5분 안에 예측한 것과 중복 제거)→QuestionEmitter. 각 단계의 구현은 따로 교체할 수 있습니다 - SpeculativeFetcher: 예측 query 중 top-1 / top-2로 전체
recall()를 실행합니다(intent에 따라 11-stage scoring + reranker + cascade 포함). 결과는 Redismemvault:prefetch:{user_id}:{query_hash}에 쓰고 TTL은 300s입니다. Fire-and-forget 방식이라 실패해도 재시도하지 않습니다(다음 utterance에서 새 예측을 만듭니다) - Admission Control: 다섯 가지 필터 규칙을 모두 통과해야 prefetch를 허용합니다
conversation.length < 3 turns→ skip(표본이 너무 적음)topic_drift_score > 0.7→ skip(방금 화제가 바뀌어 옛 context가 쓸모없음)last_predict_age < 30s→ skip(방금 실행했으므로 반복 fetch 방지)predicted_query.confidence < 0.4→ skip(작은 LLM도 확신하지 못해 실행해 봐야 token 낭비)min_sample_threshold: 사용자conversation_count < 10는 Slow Thinker 전체를 bypass합니다(콜드 스타트 기간에는 켜지 않음)
- 주입 지점:
QueryClassifyOp안입니다. 실제recall()이 들어오면 먼저memvault:prefetch:{user_id}:{query_hash}를 확인합니다. hit이면 미리 가져온 결과를 곧장 Output Formatter로 보내 중간 pipeline 전체를 아낍니다. miss이면 원래 흐름으로 돌아가므로 대가 없는 성능 저하입니다
Read-Time Sanitize와의 관계
Prefetch cache는 Sanitize를 두 겹으로 적용하는 곳입니다. cache에 넣기 전에 sanitize_for_injection()(write-time)를 실행하고, cache에서 꺼내 agent에게 주기 전에 Output Formatter가 다시 sanitize합니다(read-time). Cache가 Read 쪽 sanitize를 우회하는 뒷문이 되지 못하게 하는 것은 설계에서 고정한 불변식(invariant)입니다.
이렇게 설계한 이유
VoiceAgentRAG의 핵심 관찰은 음성 agent에서 inter-utterance 간격(사람이 말을 시작해 마칠 때까지)이면 전체 RAG를 한 번 실행하기에 충분하다는 것입니다. 이 “사람이 말하는 시간”에 speculatively fetch를 해두면 hit일 때 latency가 ~800ms에서 < 100ms로 줄어듭니다(Redis 적중 + format). memvault의 대화 인터페이스도 같은 시간대를 활용합니다.
miss rate 관측값은 약 55–65%(top-3 예측 중 하나 적중)입니다. 이는 prefetch의 35–45%가 완전한 낭비라는 뜻입니다. “유휴 token을 써서 적중 시 지연 시간을 없애겠다”는 명확한 선택이므로 Admission Control의 다섯 규칙은 이 구성 요소의 생명선이지 있으면 좋은 부가 기능이 아닙니다.
Read Track 삼부작은 여기서 끝납니다. 의도 → 회상 → 정렬 → 재정렬 → 그래프 → 포장 → 양쪽 sanitize → 예측형 사전 검색입니다. 각 층에는 fallback과 trade-off가 있으며 golden query로 지키고, 매일 작동합니다.
Read Track을 모두 살펴봤습니다.QueryClassify → fast/slow split → 11-stage scoring → reranker → OutputFormatter → read_sanitize → SlowThinker prefetch loop. 일곱 구성 요소와 하나의 entry-agnostic pipeline입니다.
이 시스템은 “memvault가 기억해야 할 것을 기억했는가”를 책임지지 않습니다. 그건 Write Track과 Dream Loop의 몫입니다. Read Track이 맡는 것은 단 하나, 주어진 query에 맞는 session 간 기억을 surface하는 일입니다.
실제로 오래 조정한 것은 새 구성 요소보다 scoring 가중치, prefetch 적중률, cascade의 경계 판단 같은 장기 매개변수였습니다. 삼부작은 여기까지입니다.
당신이 타이핑하는 속도에 맞춰 준비할 수 있을까요
백그라운드 사전 검색은 다음 문장을 생각하는 사이에 자료를 준비해야 하므로 타이핑 속도와 직접 관련이 있습니다.스스로 아는 숫자 네 가지를 입력하면 이 글의 규칙에 따라 하루에 사전 검색을 몇 번 허용하고 그중 몇 번쯤 헛수고가 되는지 계산합니다. 네 항목 모두 별도로 측정할 필요가 없고 브라우저 안에서만 계산하며 데이터는 전송하지 않습니다.
상수는 이 글에서 가져왔습니다. 3차례 미만이면 실행하지 않음, 30s 쿨다운, TTL 5분, 적중 시 대기 시간이 “~800ms에서 <100ms로” 줄어듦입니다.계산된 허용 횟수는 상한이지 실제 횟수가 아닙니다——이 글의 다섯 가지 허용 규칙 중 다른 두 가지(topic drift, 예측 신뢰도)는 실제로 무엇을 말하는지 알아야 하지만 브라우저는 모릅니다. 따라서 실제 횟수는 더 적습니다. 적중률 범위는 저자의 데이터에서 관찰한 값이지 일반 법칙이 아닙니다.
AI Agent용 건강 점검 프롬프트
모든 질문을 같은 벡터 검색에 던지면 사실 확인과 아이디어 찾기를 같은 길로 보내는 셈입니다. 어느 쪽도 맞지 않습니다. 이 글에서 질문 의도에 따라 나눈 읽기 경로(단계별 분류, 다중 신호 정렬, 동적 가중치, 비용을 아끼는 Attention Gate 등)를 비교표처럼 사용하세요.
아래 내용을 AI에 붙여 넣고 이 글의 읽기 설계와 자신의 RAG/기억 시스템을 항목별로 비교해 보세요.
더 읽어보기
이 Read Track 설계에 실제로 영향을 준 자료입니다.
| 자료 | 중요한 이유 |
|---|---|
| HippoRAG (NeurIPS'24) | PPR Boost와 적중한 개체에서 그래프를 따라 이동하는 전략을 다룹니다. Cascade Recall의 LOCAL mode는 사실상 이 글을 구현한 것입니다 |
| LightRAG | LOCAL / GLOBAL / HYBRID라는 이름과 intent → mode 대응 규칙을 여기서 직접 빌렸습니다 |
| Microsoft GraphRAG | L0 / L1 / L2의 세 층과 L2 커뮤니티 요약으로 zero-latency recall을 수행하는 개념의 출처입니다. Read의 GLOBAL 모드는 미리 생성한 L2 view를 사용합니다 |
| CRAG: Corrective Retrieval-Augmented Generation | slow path에서만 실행하는 자체 평가 층입니다. CRAG의 evaluator로 rerank 뒤 품질 게이트를 두며, fast 모드에서는 token을 아끼기 위해 실행하지 않습니다 |
| Attention-Residual for Intent-Dependent Scoring | 11-stage scoring에서 intent-dependent 가중치의 이론적 근거입니다. 모든 질문에 같은 점수를 쓰지 않고 intent마다 신호의 가중치 벡터를 조정합니다 |
| Cormack et al. 2009: Reciprocal Rank Fusion | Dense + Sparse의 두 ranker 순위를 합치는 원래 방법입니다. Fast Search의 RRF 융합은 이 공식을 그대로 사용하며,k=60 도 이 글의 기본값입니다 |
| TheTom/turboquant_plus | Attention-gated Reranking의 조기 return 전략은 여기서 왔습니다. 제 세 가지 skip 규칙(후보가 너무 적음, 한 점수가 압도적임, 점수가 밀집됨)은 이 판단 논리를 다시 쓴 것입니다 |
| Kahneman — Maps of Bounded Rationality (Nobel Lecture) | Fast / Slow 이분법의 이론적 뼈대입니다.thinking_mode 원래는 사용자가 직접 골라야 했지만 나중에는 intent가 자동으로 결정하게 고쳤습니다. 다만 System 1 / System 2의 역할 분담은 그대로입니다. Cascade Recall이 slow mode에서만 시작되는 것도 이 계보에 속합니다 |
| VoiceAgentRAG (Salesforce AI Research) | Slow Thinker / 사전 검색의 영감이 된 자료입니다. 이중 에이전트 구조(백그라운드 Slow Thinker + 전면 Fast Talker + FAISS cache)는 이쪽의 slow_thinker.py + QueryJournal 예측 + Redis speculative cache와 대응합니다 |
| win4r / memory-lancedb-pro (LanceDB Pro autoRecall) | memvault 전체 설계에 가장 먼저 영감을 준 자료입니다. autoRecall의 “능동 주입” 철학(agent가 생각하기 전에 관련 기억을 context에 넣기), 다섯 겹의 검색 + 세 겹의 승격 + Weibull 감쇠는 memvault에서 각각의 구현으로 자라났습니다. YouTube 채널 AI超元域 이 openclaw를 소개할 때 알게 됐습니다 |
| memvault Write Track — 대화가 끝난 뒤 | 삼부작의 첫 글입니다. 읽으려면 먼저 읽을 것이 있어야 합니다. 세 gate, 이중 경로 쓰기, 출처 이력을 매기는 방법을 다룹니다 |
| memvault Background Track — 저장을 마친 뒤 | 삼부작의 둘째 글입니다. Read가 사용하는 L1/L2 요약, PPR, Interest Profile은 모두 Background가 만든 것입니다 |