Trawling

AI 코딩 어시스턴트가 세션을 넘어 같은 실수를 반복하지 않게 하려면 — 여섯 메모리 시스템의 '결과 피드백 입력' 비교

AI 코딩 어시스턴트가 이전 세션에서 수정된 실수를 새 세션에서 반복하는 문제를 다룹니다. 저자는 Cognee, Mem0, Letta, Supermemory, Zep, Mnemoverse 여섯 메모리 시스템의 공식 문서를 읽고 '리콜 결과에 부정적 판정을 전달하는 공개 입력'이 있는지를 비교했습니다. 결론은 입력의 존재 여부가 아니라, 그 입력이 무엇에 붙어 있고 다음 읽기에서 실제로 무엇이 바뀌는지가 갈림길이라는 것입니다.

본문

화요일에 어시스턴트에게 마이그레이션 스크립트가 스테이징 데이터베이스를 건드리면 안 된다고 알려줬고, 어시스턴트는 동의하고 스크립트를 고쳤습니다. 그런데 목요일 새 세션에서 같은 실수를 반복했고, 이유를 설명한 메모는 메모리 안에 그대로 있었습니다 — 실패한 접근과 나란히 검색되면서 어느 쪽이 실패였는지 구분해주는 것이 없었기 때문입니다. 글이 던지는 핵심 질문은 기계적입니다. "리콜(recall)의 결과가 나빴을 때, 메모리 레이어에서 무엇인가가 바뀌는가?" 실수를 기록하는 것과 실수에서 배우는 것은 다른 연산입니다. 저장은 실수를 다시 읽을 수 있다는 뜻이고, 학습은 결과가 나빴기 때문에 시스템의 다음 동작이 달라진다는 뜻입니다. "나쁜 리콜을 보고해도 다음 읽기에서 아무것도 바뀌지 않는다면, 그것은 학습이 아니라 일기입니다."

여섯 시스템에 던진 한 가지 질문

저자는 자신이 일하는 Mnemoverse를 포함한 여섯 메모리 시스템의 공식 문서를 읽고 세 가지를 확인했습니다. 리콜에 대한 명시적 부정 판정을 받는 공개 입력이 있는가, 그것이 무엇에 붙어 있는가, 벤더가 그 효과에 대해 무엇이라고 적고 있는가. 첫 조사에서는 각 벤더 문서의 첫 페이지만 읽고 "거의 아무도 결과 입력을 공개하지 않는다"고 결론내렸지만 그것은 틀렸고, 그 이유 자체가 교훈적이었습니다 — 관련 페이지들이 루트에서 몇 단계 아래에 숨어 있었던 것입니다. 각 벤더의 문서 호스트에서 다시 읽은 결과, 다섯 시스템 중 넷이 부정 판정을 받는 입력을 공개하고 있었습니다. 차이는 존재 여부가 아니라 입력이 어디에 붙고 다음 읽기에서 무엇이 움직이는지에 있었습니다.

벤더별 비교 결과

Cognee는 가장 명확한 사례입니다. session.add_feedback은 세션 안의 답변 식별자에 1~5 점수와 피드백 텍스트를 붙이고, 문서는 "피드백이 향후 검색에 영향을 주려면 관련 session_ids로 improve()를 실행하라"고 명시합니다 — 피드백에서 다음 검색으로 이어지는 공개 경로가 존재합니다. Mem0는 POST /v1/feedback/으로 메모리 id에 POSITIVE, NEGATIVE, VERY_NEGATIVE 값을 받지만, 페이지는 무엇을 받는지만 말할 뿐 이후 순위 변화는 말하지 않습니다. 별도로 판정 없이 recency·frequency로 순위를 바꾸는 프로젝트 단위 decay 옵션(기본 off)이 있고, 벤더는 "decay는 후보를 재정렬할 뿐 절대 제거하지 않는다"고 씁니다. Letta의 PATCH /v1/steps/{step_id}/feedback은 실행 스텝에 positive/negative를 붙이는데, 관찰성과 평가에는 유용하지만 "검색된 메모리가 틀렸다"는 보고가 아니며 이후 읽기 재정렬과는 연결되지 않습니다. Supermemory의 approve/decline/undo 리뷰 엔드포인트는 사용자가 말한 메모리가 아니라 엔진이 추론한 메모리에 대한 판정으로, 리뷰되지 않은 추론 메모리는 "검색에서 down-weighted"되고 decline된 것은 "검색에서 완전히 제거"됩니다. 도출된 사실이 참인가와 리콜이 유용했는가는 다른 질문이므로 구분해야 합니다. Zep은 유일한 부재 주장 대상으로, 조사 당일 기계판독 인덱스와 사이트맵에 열거된 페이지들에서 리콜에 대한 판정 입력을 찾지 못했으며, 비공개 영역은 외부에서 읽을 수 없다는 한계를 명시합니다. Mnemoverse는 memory_feedback(atom_ids, outcome)으로 -1~+1 실수값을 리콜이 반환한 메모리들에 붙여 다음 읽기의 순서를 바꾸며, "unhelpful memories are out-ranked rather than erased" — 지워지는 것이 아니라 순위가 밀립니다.

어휘의 비대칭과 유일한 반례

"downweight"를 붙여 쓴 형태로 다섯 벤더 조직의 코드 검색을 하면 0건이지만, 하이픈 형태는 Supermemory의 리뷰 문서와 Cognee의 가이드에 두 번 등장하며 그중 하나는 "우리 검색은 down-weight하지 않는다"는 부정문입니다. rerank는 어디에나 있지만 나쁜 결과를 근거로 아래로 내리는 방향은 거의 적혀 있지 않다는 것이 이 분야의 어휘 지형입니다. 한편 Letta의 리서치 포스트는 학습이 토큰 공간에서 "가중치가 아니라 학습된 컨텍스트의 갱신"으로 이뤄져야 한다고 주장하고, Supermemory도 "모든 사용자·태스크·테넌트의 컨텍스트를 추출하고 dream한다"고 씁니다 — 둘 다 "더 많이 넣고 더 나은 브리핑을 받는다"는 입장이지 결과의 좋고 나쁨에 대한 판정은 아닙니다. 그 Letta 페이지는 규모 있게 사용자 피드백으로 학습하는 유일한 출하된 메커니즘으로 Cursor의 탭 완성 모델을 지목하는데, 한계도 벤더의 말 그대로입니다 — 모두의 모델을 개선할 뿐 내 프로젝트용이 아니고, 추론·행동이 아니라 완성에만 적용됩니다.

직접 검증하는 방법과 네 가지 질문

독자가 직접 확인하는 절차도 제시됩니다. 도구가 잘못 알고 있는 메모리를 찾아 그 메모리가 답할 질문을 던지고, 보고 전에 새 세션에서 두세 번 같은 질문을 해 순서가 저절로 움직이는지 대조군을 확보한 뒤, 도구가 허용하는 방법(엔드포인트, 리뷰 액션, 슬래시 명령, 채팅 메시지)으로 틀렸다고 보고하고 새 세션에서 다시 물어보라는 것입니다. 보고 후에만 순서가 움직였다면 이 메커니즘의 후보이고, 그다음 읽을 것은 벤더의 설명입니다. 정리된 체크리스트는 네 가지 — 노트를 적는 곳이 아니라 결과(outcome)를 받는 입력이 있는가, 그것이 무엇에 붙는가(답변·메모리·스텝·저장된 추측 중 앞의 둘만 리콜에 관한 것), 무엇이 움직이는가(텍스트·가중치·다음 읽기의 순서), 그리고 누가 그것을 보내야 하는가. 마지막 답이 "일을 마친 뒤 아무도 지켜보지 않을 때 에이전트"라면 나머지를 그 관점에서 읽어야 합니다. 저자는 Mnemoverse 소속임을 밝히며, 자사 측정에서도 명시적 결과 피드백은 프로덕션 트래픽에서 거의 발생하지 않는다고 인정합니다 — "아무도 호출하지 않는 채널과 존재하지 않는 채널은 같은 반복되는 실수를 만든다"는 것이 이 카테고리의 현재에 대한 가장 공정한 요약입니다.

원문: dev.to / 번역·요약: Trawling

참고 자료

오류 제보