AI 에이전트가 하나일 때는 기억 문제가 단순해 보입니다. 대화 내용이나 작업 노트를 어딘가에 저장하면 됩니다. 하지만 터미널의 코딩 에이전트, 브라우저 챗봇, 백그라운드 작업 에이전트가 같은 프로젝트를 동시에 다루기 시작하면 문제가 달라집니다. 각자 따로 기억하면 맥락이 끊기고, 하나의 저장소에 모두 쓰게 하면 잘못된 정보가 곧바로 모두의 입력이 됩니다.

원문: https://newsletter.systemdesign.one/p/graph-based-agent-memory


기존 방식이 깨지는 이유

가장 쉬운 방법은 공유 폴더입니다. Notion, Google Drive, Confluence, 위키에 모든 에이전트가 문서를 남기게 하는 방식입니다. 사람에게는 익숙하지만 에이전트에게는 불리합니다. 파일은 많아지는데, 그 안의 개념이 무엇이고 서로 어떻게 연결되는지 알기 어렵기 때문입니다.

예를 들어 “이번 주 배포 중 어떤 서비스가 누구에 의해 변경됐는가?“라는 질문은 한 문서 안에 답이 있으면 쉽습니다. 하지만 답이 배포 기록, 담당자 문서, 장애 기록, 커밋 로그에 흩어져 있으면 에이전트는 많은 문서를 읽고 추측해야 합니다. 폴더는 텍스트를 저장할 뿐, 지식을 저장하지 않습니다.

벡터 데이터베이스도 완전한 답은 아닙니다. 의미가 비슷한 문단을 찾는 데는 강하지만, 고객과 티켓, 티켓과 담당자, 담당자와 커밋 사이의 명시적 관계를 직접 표현하지는 못합니다. “비슷한 조각"은 찾을 수 있지만, “이 사실에서 저 사실까지 어떤 경로로 연결되는가"는 별도로 해석해야 합니다.

더 큰 문제는 쓰기입니다. 에이전트가 하나가 아니라 여럿이면 동시에 같은 기억을 고칩니다. 공유 폴더에서는 마지막 저장이 앞선 저장을 덮을 수 있습니다. 벡터 데이터베이스에서는 잘못된 정보가 들어가면 곧바로 다른 에이전트의 검색 결과가 됩니다. 즉, 한 에이전트의 실수가 공유 맥락이 됩니다.

그래프 메모리의 기본 아이디어

그래프 메모리는 사실을 점으로, 관계를 선으로 다룹니다. 고객은 하나의 노드, 티켓도 하나의 노드, 담당자도 하나의 노드입니다. 그리고 고객은 티켓을 만들었고, 티켓은 담당자에게 배정됐고, 특정 커밋이 그 티켓과 연결될 수 있습니다.

이 구조에서는 질문이 문서 검색으로만 끝나지 않습니다. 에이전트는 관계를 따라 이동합니다.

Customer -> Ticket -> Engineer -> Commit

이런 경로가 이미 그래프 안에 있으므로, 에이전트는 모든 문서를 뒤지는 대신 연결된 사실을 따라가며 필요한 맥락을 만들 수 있습니다.

다만 그래프만으로도 부족합니다. 여러 에이전트가 같은 사건을 어떤 에이전트는 deploy, 다른 에이전트는 deployment, 또 다른 에이전트는 release로 기록하면, 그래프는 세 단어를 서로 다른 개념으로 저장할 수 있습니다. 사람에게는 비슷한 말이지만 시스템에게는 서로 다른 섬이 됩니다.

그래서 스키마가 필요합니다. 스키마는 어떤 노드 타입이 있고, 어떤 관계가 허용되며, 각 노드를 무엇으로 식별할지 정합니다. 에이전트가 같은 스키마를 읽고 쓰면, 서로 다른 말로 같은 개념을 흩뜨릴 가능성이 줄어듭니다. 스키마는 그래프의 문법입니다.

객체 저장소 위에서 원자적으로 쓰는 법

Omnigraph는 그래프 상태를 S3 같은 객체 저장소에 둡니다. 객체 저장소는 싸고 오래 보관하기 좋고 여러 에이전트가 함께 접근하기 쉽습니다. 하지만 데이터베이스처럼 여러 파일 변경을 하나의 트랜잭션으로 묶어 주지는 않습니다.

그래프 업데이트는 보통 여러 곳을 동시에 바꿉니다. 예를 들어 Alice가 checkout 서비스에 배포 d-913을 만들었다면, 배포 노드, 사람 노드, 배포와 사람을 잇는 엣지가 함께 바뀔 수 있습니다. 중간에 실패하면 배포는 있는데 누가 했는지 연결이 없는 이상한 상태가 됩니다.

Omnigraph는 이를 피하려고 데이터를 바로 덮어쓰지 않습니다. 노드 타입과 엣지 타입별로 저장소를 나누고, 각 저장소는 새 버전을 만듭니다. 기존 버전은 그대로 두고, 새 버전은 아직 보이지 않게 저장합니다.

마지막에 manifest가 어느 버전이 현재 살아 있는지를 가리킵니다. 새 배포 버전, 새 사람 버전, 새 엣지 버전을 모두 만든 뒤 manifest 포인터만 한 번에 바꾸면, 에이전트 입장에서는 예전 그래프 전체를 보거나 새 그래프 전체를 봅니다. 중간 상태는 보지 않습니다.

동시에 다른 에이전트가 먼저 바꿨는지도 확인합니다. Omnigraph는 compare-and-swap 방식으로 “내가 읽은 버전이 아직 현재 버전인가?“를 검사합니다. 아니면 커밋을 거절하고 최신 상태에서 다시 시도합니다. 이렇게 하면 보지 못한 변경을 덮어쓰는 사고를 막을 수 있습니다.

에이전트는 바로 main에 쓰지 않는다

원자적 쓰기는 “부분 반영"을 막지만, “틀린 내용"을 막지는 못합니다. 에이전트가 잘못 추론한 정보를 완전한 커밋으로 올리면, 그 정보는 여전히 공유 기억이 됩니다.

그래서 Omnigraph는 Git과 비슷한 흐름을 씁니다. 에이전트는 공유 진실인 main에 직접 쓰지 않습니다. 각자 브랜치를 만들고, 그 안에서 변경을 제안합니다. 브랜치는 제안일 뿐이고, 승인되어 병합되기 전까지는 공유 기억이 아닙니다.

충돌도 명시적으로 다룹니다. 두 에이전트가 서로 다른 부분을 바꾸면 자동으로 합칠 수 있습니다. 하지만 같은 배포의 상태를 한쪽은 rolled-back, 다른 쪽은 succeeded로 바꾸면 시스템이 임의로 고르지 않습니다. 어떤 노드의 어떤 필드에서 어떤 값이 충돌했는지 드러내고, 사람이나 정책이 결정하게 합니다.

권한도 HTTP 서버 바깥에만 두지 않습니다. CLI나 SDK로 접근해도 같은 검사를 받도록 엔진 내부에서 정책을 적용합니다. 원문은 Omnigraph가 Cedar 정책 언어를 사용해 누가 읽고, 브랜치를 만들고, 수정하고, main에 병합할 수 있는지 통제한다고 설명합니다.

검색은 세 가지를 함께 쓴다

에이전트가 좋은 답을 내려면 기억을 안전하게 저장하는 것만으로는 부족합니다. 필요한 맥락을 잘 찾아야 합니다. 원문은 검색을 세 종류로 나눕니다.

첫째, 관계 검색입니다. LoginService에서 출발해 어떤 서비스가 의존하는지, 어떤 장애와 연결되는지, 누가 소유자인지 따라갑니다.

둘째, 정확한 키워드 검색입니다. 에러 문자열, 서비스 이름, 티켓 ID처럼 정확한 단어를 아는 경우에는 전통적인 전체 텍스트 검색이 필요합니다.

셋째, 의미 검색입니다. 사용자가 “로그인이 안 된다"고 말했지만 관련 장애 제목은 “authentication failure"일 수 있습니다. 단어는 다르지만 뜻이 같은 경우에는 벡터 검색이 유용합니다.

문제는 이 세 가지를 별도 시스템으로 나누면 동기화 부담이 커진다는 점입니다. 그래프 데이터베이스, 검색 인덱스, 벡터 데이터베이스가 각자 사본을 들고 있으면 어느 하나가 뒤처질 수 있습니다. Omnigraph는 하나의 그래프 데이터를 기준으로 그래프 인덱스, 전체 텍스트 인덱스, 벡터 인덱스를 만든 뒤 결과 순위를 합칩니다.

언제 쓰고, 언제 쓰지 말아야 하나

그래프 메모리는 여러 에이전트가 같은 지식을 오래 읽고 쓰는 문제에 맞습니다. 회사 지식 그래프, 장기 에이전트 메모리, 코드베이스 지식 그래프, 개인 지식 그래프처럼 시간이 지나며 관계가 쌓이고 여러 작업자가 함께 업데이트하는 경우가 대표적입니다.

반대로 모든 기억 문제에 필요한 도구는 아닙니다. 객체 저장소 기반 쓰기는 보통 수십에서 수백 밀리초가 걸릴 수 있습니다. 에이전트가 몇 초씩 추론하는 환경에서는 괜찮은 비용이지만, 결제 처리, 클릭 카운터, 실시간 세션 상태처럼 초당 수천 번의 낮은 지연 쓰기가 필요한 곳에는 맞지 않습니다.

필요한 것이 의미 검색뿐이라면 벡터 데이터베이스가 더 단순합니다. 단일 애플리케이션에서 그래프 탐색만 필요하고 쓰기 주체가 제한적이라면 Neo4j 같은 전통적 그래프 데이터베이스가 더 적합할 수 있습니다. 고속 트랜잭션이 핵심이면 일반 트랜잭션 데이터베이스가 맞습니다.

결론 및 시사점

한 줄 결론: 여러 AI 에이전트가 같은 기억을 공유하려면 저장소보다 먼저 관계, 스키마, 승인, 되돌리기 가능한 변경 이력이 필요합니다.

이 글의 핵심은 “에이전트 메모리 = 더 큰 벡터 데이터베이스"가 아니라는 점입니다. 여러 에이전트가 동시에 읽고 쓰는 순간, 메모리는 검색 문제가 아니라 공유 상태 운영 문제가 됩니다.

그래프는 관계를 표현하고, 스키마는 언어를 맞추며, manifest 기반 커밋은 부분 반영을 막고, 브랜치와 병합은 틀린 변경이 곧바로 공유 진실이 되는 일을 늦춥니다. 결국 좋은 에이전트 메모리는 지식을 많이 저장하는 장치가 아니라, 무엇이 공유 지식이 될 자격이 있는지 관리하는 시스템에 가깝습니다.