검색/AI 에이전트 메모리 서비스를 사용자별 기억이 섞이지 않게 만들기

AI 에이전트 메모리 서비스를 사용자별 기억이 섞이지 않게 만들기

AI 에이전트의 장기 메모리 서비스를 만들거나 확장할 때 쓴다. 메모리 뱅크마다 기억을 분리하고, 수집·검색·추론을 나누며, 데이터베이스 마이그레이션, API 클라이언트 갱신, 다른 모델이 판정하는 테스트, 테넌트나 뱅크별 설정까지 맞춘다.

이 AI 규칙을 사용하려면
## 기억 종류를 나누고 뱅크 사이에 데이터를 섞지 않기 수집, 검색, 추론에서 저장된 지식 유형을 서로 다르게 사용하므로 그 구분을 유지한다. ### 메모리를 명시적으로 모델링하기 - 세계 사실은 일반 지식을 나타낸다. - 경험 사실은 사용자나 에이전트에게 귀속되는 개인적인 사건을 나타낸다. - 멘탈 모델은 여러 사실에서 종합한 패턴을 통합한다. - 각 메모리 뱅크가 배경 맥락과 회의성, 문자주의, 공감 같은 성향 특성을 1–5 척도로 가질 수 있게 한다. - 성향은 성찰적 추론에만 적용하고, 사실을 회상하는 방식은 바꾸지 않는다. ### 뱅크 분리하기 - 각 뱅크를 한 사용자나 에이전트를 위한 독립적인 메모리 저장소로 취급한다. - 저장, 검색, 추론, 테스트에서 뱅크 간 유출을 방지한다. - API 요청마다 정확히 1개 뱅크만 처리한다. - 서버 경계를 약화하지 말고, 다중 뱅크 워크플로는 클라이언트가 오케스트레이션하게 한다. ## 수집·검색·추론을 나누고 여러 검색 방법을 합치기 모델, 임베딩, 엔터티, 순위 지정에는 안정적인 추상화를 공유하되 세 가지 주요 작업을 분리한다. ### 작업 의미 유지하기 - Retain은 콘텐츠를 수집하고 사실, 엔터티, 관계를 추출한다. - Recall은 성향 특성을 적용하지 않고 기존 메모리를 검색한다. - Reflect는 메모리와 통합된 멘탈 모델을 바탕으로 성향을 고려한 추론을 수행한다. - 오케스트레이션을 사실 추출, 엔터티 정규화, 링크 관리, 제공자 어댑터와 분리한다. ### 검색을 파이프라인으로 구축하기 - 상호 보완적인 4가지 검색 전략인 의미 검색, 어휘 BM25 검색, 그래프 검색, 시간 검색을 병렬로 실행한다. - 교차 인코더로 재정렬하기 전에 상호 순위 융합으로 순위 결과를 결합한다. - 그래프 확장을 검색 인터페이스 뒤에 두어 다른 전략과 교체할 수 있게 한다. - 책임 범위가 좁은 래퍼를 통해 로컬 및 원격 모델, 임베딩, 재정렬 제공자를 지원한다. ### API 계약 동기화하기 - 엔드포인트를 변경한 뒤 OpenAPI 사양을 다시 생성한다. - 사양을 변경한 뒤 Python, TypeScript, Rust를 포함해 지원되는 모든 클라이언트 SDK를 다시 생성한다. - API 매개변수가 변경되면 프록시 라우트, 요청 값 추출, SDK 호출, 클라이언트 타입, 이를 사용하는 모든 인터페이스를 함께 업데이트한다. ## PostgreSQL과 Oracle 모두에서 도는 마이그레이션 작성하기 방언 차이를 명시적으로 처리하면서 지원되는 모든 데이터베이스에 하나의 마이그레이션 이력을 사용한다. ### 리비전 정의하기 - 각 마이그레이션에 고유한 12자의 십육진수 리비전 식별자를 부여하고 `down_revision`이 직전 리비전을 가리키게 한다. - 업그레이드와 다운그레이드 동작을 한 쌍으로 유지한다. - 활성 연결에서 구현을 선택하는 하나의 방언 라우터를 통해 디스패치한다. - 디스패처가 없으면 마이그레이션 구조 테스트가 실패하게 한다. ### 방언별로 구현하기 - PostgreSQL과 Oracle 호환 데이터베이스에 각각 별도의 업그레이드 및 다운그레이드 함수를 제공한다. - 테넌트 스키마가 설정되어 있다면 원시 PostgreSQL SQL에 해당 스키마를 명시한다. - 특수한 벡터, 텍스트, 파티션 작업처럼 마이그레이션 프레임워크로 모델링할 수 없는 데이터베이스 작업에만 드라이버 수준 실행을 사용한다. - 마이그레이션이 실제로 1개 방언에만 적용된다면 다른 슬롯을 의도적으로 생략하며, 실수로 비워 두어서는 안 된다. - 검토할 때 방언 간 스키마 드리프트를 고려한다. ### 실행 검증하기 - 기본 스키마와 모든 테넌트 스키마에 마이그레이션을 실행한다. - 집중 검증을 위해 이름을 지정한 1개 테넌트 스키마만 대상으로 실행하는 기능도 지원한다. - 서비스 시작 시 마이그레이션을 자동으로 실행한다면 지원되는 모든 방언과 테넌트 범위에서 시작 과정을 테스트한다. ## push 전에 필수 검사와 코드 리뷰 통과하기 구현을 변경할 때마다 표준 도구 체인을 사용하고, 차단 결함과 권고 수준의 정리 작업을 구분한다. ### 필수 검사 실행하기 - Python이나 TypeScript를 변경한 뒤 포맷팅, 린팅, 타입 검사를 실행한다. - 사용하지 않는 import와 변수, 고립된 클라이언트 파일, 패키지 목록에 없는 의존성을 차단 오류로 취급한다. - 함수 전체가 사용되지 않거나 컴포넌트 라이브러리의 export 범위가 의도적으로 넓은 경우에는 프로젝트 정책에서 필수로 격상하지 않는 한 권고 사항으로 취급한다. - 저장소의 표준 명령으로 단위 테스트, API 통합 테스트, 관련 벤치마크를 실행한다. - 필요할 때 API 사양과 클라이언트를 다시 생성한 뒤, 커밋되지 않은 생성물 차이가 남지 않았는지 확인한다. ### 공개 전 검토하기 - 구현 뒤 구조화된 코드 검토를 수행한다. - 테스트 누락, 데드 코드, 타입 안전성, 데이터 분리, 생성 파일 드리프트와 관련된 모든 필수 수정 지적을 해결한다. - 필수 수정 지적을 모두 해결하기 전에는 코드를 푸시하거나 변경 요청을 만들지 않는다. - 출시되지 않은 변경 로그 항목을 수동으로 추가하지 말고, 릴리스 과정에서 버전이 지정된 항목을 생성하게 한다. ## 정해진 로직은 직접 테스트하고 모델 답변은 다른 모델이 판정하게 하기 동작이 기계적으로 결정되는지, 모델 해석에 따라 달라지는지에 맞춰 어서션을 선택한다. ### 결정론적 메커니즘을 직접 테스트하기 - 개수, 필수 필드, 프롬프트 조합, 억제 로직, 주입된 부분 문자열에는 직접 어서션을 사용한다. - 모의 모델이나 순수 함수를 사용해 대부분의 테스트를 빠르게 유지한다. - 모델 동작 테스트에는 그 주변의 결정론적 준비 과정을 다루는 단위 테스트를 함께 둔다. ### 모델의 의미 동작 판정하기 1. 단일 제공자 핵심 모델 작업용으로 시맨틱 테스트를 표시하고, 제공자 매트릭스 마커는 제공자 간 인수 테스트에만 사용한다. 2. 모의 객체가 아니라 실제로 설정된 파이프라인을 호출한다. 3. 평가에 필요한 시맨틱 레이블로 응답을 요약한다. 4. 제공된 맥락의 명시적인 기준을 응답이 충족하는지 독립된 판정 모델에 묻는다. 5. 테스트 대상과 동일한 모델 호출로 판정해서는 안 된다. - 분류, 귀속, 차원 보존, 지시 준수에는 판정 모델 어서션을 사용한다. - 모델과 실행에 따라 타당하게 달라질 수 있는 동작에 정확한 문자열이나 enum 값을 하드코딩하지 않는다. ## API 변경을 모든 클라이언트에 반영하고 새 통합에 CI 추가하기 런타임 동작, 테스트, 지속적 통합, 릴리스 등록, 클라이언트 인터페이스가 일치해야만 통합이 완료된다. ### API 사용 측 업데이트하기 - 요청 필드를 추가할 때 프록시 라우트에서 값을 추출해 SDK 호출에 전달한다. - 클라이언트 메서드 타입과 해당 필드를 제공하거나 읽는 모든 인터페이스를 업데이트한다. - 각 요청의 범위를 1개 뱅크로 제한하고, 다중 뱅크 사용 사례에서는 클라이언트 측 오케스트레이션을 유지한다. ### 통합 완성하기 - 외부 프레임워크 인터페이스를 모의하거나 실제로 실행하는 테스트를 추가하고, 통합이 메모리 서비스를 올바르게 호출하는지 확인한다. - 헬퍼만 테스트하는 단위 테스트를 충분한 통합 테스트 범위로 간주하지 않는다. - 변경 범위에 따라 실행되어 빌드, 의존성 설치, 통합 테스트를 수행하는 지속적 통합 작업을 추가한다. - 표준 릴리스 워크플로에 통합을 등록한다. - 구조화된 데이터에는 원시 딕셔너리 대신 타입이 지정된 구조를 사용하고 여러 항목의 튜플 반환을 피한다. - 테스트, CI 변경 감지, 릴리스 등록이 빠져 있는 동안에는 병합하거나 공개하지 않는다. ## 새 설정을 테넌트나 뱅크별로 바꿀 수 있는지 정하고 추가하기 구현 전에 모든 설정을 분류해 오버라이드 범위와 문서의 일관성을 유지한다. ### 구성 수준 선택하기 - 전역 환경 값부터 테넌트 오버라이드를 거쳐 뱅크 수준 데이터베이스 오버라이드에 이르는 순서로 계층형 설정을 해석한다. - 모델 제공자, 모델 이름, API 키, 작업별 옵션, 고객별 기능 플래그에 계층형 구성을 사용한다. - 데이터베이스 주소, 호스트, 포트, 전역 동시 실행 제한, 시스템 전체 플래그는 서버 수준에서 정적으로 유지한다. - 정적 필드를 원격 구성 가능 필드 집합에 추가하지 않는다. ### 필드를 완전하게 추가하기 1. 환경 변수 이름과 기본값을 정의한다. 2. 중앙 구성 객체에 타입이 지정된 필드를 추가한다. 3. 테넌트나 뱅크 오버라이드가 유효할 때만 구성 가능 필드 허용 목록에 추가한다. 4. 환경에서 해당 필드를 초기화한다. 5. 명령줄 오버라이드가 필요할 때만 명령줄 옵션을 추가한다. 6. 계층 값은 뱅크별 리졸버로, 정적 값은 전역 접근자로 읽는다. 7. 구성 참조 문서와 환경 템플릿에 설명, 기본값, 계층 상태를 반영한다. 8. 함께 제공되는 환경 템플릿의 모든 사본을 동기화하고 템플릿 동기화 테스트를 계속 통과시킨다. - 문서, 템플릿, 로그, 테스트에 실제 자격 증명 값을 절대로 노출하지 않는다.