XGEN 15일 무료 체험 — 설치 없이 브라우저에서 바로 시작하세요체험 신청
PlateerAI Labs
·Reading Time | 3 min
작성 | 김진수

실행 간 메모리의 범위와 우선순위 설계(8편)

한 실행의 작업 메모와 다음 실행에 남길 교훈을 나누고, session·workflow·user·platform 범위의 충돌과 수명주기를 다룹니다.

실행 간 메모리의 범위와 우선순위 설계(8편) — 커버 일러스트Series · 하네스 개발기시리즈 8번째 글 · 전체 10편 보기

에이전트 하네스 설계 · 8/10

모델과 실행 설정을 통제해도 다음 실행은 여전히 처음부터 시작했습니다. 한 세션에서 확인한 사용자 선호와 도구 사용상의 주의점, 판정에서 반복해서 나온 교정 사항이 다른 대화나 워크플로우에는 이어지지 않았습니다. 매번 대화 전문을 다시 넣으면 비용이 커지고, 오래된 판단과 현재 요청이 한 컨텍스트에서 충돌합니다.

이 문제 때문에 에이전트 메모리를 처음 검토한 것이 6월 12일이었습니다. 당시에는 작업 메모와 장기 기억, 압축과 회상 방식을 조사했지만 제품 실행 경로에 저장과 조회를 붙이지는 않았습니다.

구현은 6월 말 시작됐습니다. 먼저 실행 상태를 다시 읽을 수 있는 저장 구조가 선행했고, 6월 29일 엔진의 저장·회상 지점과 제품 저장소를 연결했습니다. 다음 이틀 동안 메모리를 session, workflow, user, platform 네 범위로 나누고 조회, 만료, 삭제 경로를 붙였습니다.

이 과정에서 메모리를 ‘과거 대화를 많이 보관하는 기능’으로 정의하지 않았습니다. 다음 판단을 바꿀 가치가 있는 작은 상태만 남기되 얼마나 오래, 누구에게, 어떤 우선순위로 적용할지를 함께 정하는 일이었습니다.

한 실행의 작업 메모와 다음 실행의 기억을 나눴습니다

긴 문서를 읽는 도중 중요한 문단을 표시하거나 여러 도구 결과 중 다시 볼 항목을 고르는 일도 메모리처럼 보입니다. 하지만 그 검색 결과가 다음 주의 다른 요청에도 유효하다는 보장은 없습니다. 현재 과제를 끝내는 데 필요한 관측과 실행을 넘어 남길 교훈은 수명이 다릅니다.

RecallSet은 한 실행 안에서만 쓰는 작업 메모입니다. 모델이 keep, check, discard 같은 의미를 붙인 항목을 모으고, 내용 지문으로 중복을 줄이며, 개수 상한 안에서 우선순위를 정합니다. 처음부터 모든 본문을 펼치지 않고 목록과 식별자를 보여 준 뒤 필요한 항목만 다시 읽게 합니다. 실행이 끝나면 이 집합도 사라집니다.

실행 간 메모리는 별도 MemoryStore를 사용합니다. 품질 판정이 답을 반려했다면 일반 오류 문자열이 아니라 구체적인 검증 피드백을 교훈 후보로 남깁니다. 실행이 정상적으로 끝난 뒤에는 보조 모델이 사용자 입력과 최종 출력을 읽고 다음 실행에 쓸 후보를 추출합니다. 전체 대화 로그를 그대로 저장하지는 않지만, 후보 하나하나가 별도 품질 판정을 통과한 뒤 저장되는 구조는 아닙니다.

현재 실행의 관측 → RecallSet → 실행 종료와 함께 폐기
판정 피드백·완료 결과 → 메모리 후보 추출 → MemoryStore → 다음 실행에서 선택적 회상

이 경계는 일시적인 검색 결과와 실행 간 기억을 분리합니다. 다만 후보 추출과 저장 승인을 같은 것으로 보면 안 됩니다. 영향 범위가 큰 platform 제약처럼 잘못 저장됐을 때 피해가 큰 항목은 자동 추출만으로 승격하지 않고 별도 승인이나 결정론적 검사 경로를 두는 것이 안전합니다.

저장과 회상을 실행 경계의 양쪽에 뒀습니다

무엇을 저장할지 정해도 모델이 언제 읽는지가 불분명하면 효과가 실행마다 달라집니다. 답을 만드는 중간에 새 메모리를 곧바로 주입하면 같은 실행 안에서 아직 검증되지 않은 내용이 사실처럼 순환할 수 있습니다.

쓰기는 판정 결과가 확정된 뒤 일어납니다. 재시도라면 검증 피드백에서 교훈 후보를 추출하고, 완료라면 사용자 입력과 최종 결과에서 다음 실행에도 유효해 보이는 항목을 정리합니다. 읽기는 새 실행의 입력을 준비할 때 일어납니다. 허용된 범위의 메모리를 선택해 첫 모델 호출 전에 넣습니다.

저장과 회상 사이에 실행 경계를 둔 덕분에 테스트 조건도 분명해졌습니다. 판정 전에는 장기 메모리가 생기지 않아야 하고, 다음 실행의 첫 호출에는 선택된 메모리가 이미 들어 있어야 합니다. 저장 API가 성공했는지만 보지 않고 실제 다음 판단까지 도달했는지를 확인했습니다.

실행 상태 저장과 장기 메모리의 역할도 나눴습니다. 전자는 실행을 다시 설명할 수 있는 상태와 교훈의 흐름을 보존합니다. MemoryStore는 제품의 사용자와 워크플로우 범위에 맞춰 오래 남길 항목을 조회하고 관리합니다. 둘을 같은 저장 테이블로 취급하지 않고, 제품 연결 계층이 실행 상태와 제품 수명주기를 연결합니다.

같은 기억도 적용 범위가 달랐습니다

범용 엔진은 제품의 사용자와 워크플로우 체계를 알지 않습니다. 제품 연결 계층에서 메모리를 네 범위에 연결했습니다.

범위는 검색 필터용 태그가 아닙니다. 누가 읽을 수 있는지, 언제 만료되는지, 원본 객체를 삭제할 때 어디까지 정리해야 하는지를 결정합니다. 세션 메모리가 다른 세션으로 넘어가서는 안 되고, 워크플로우를 삭제했다면 그 범위의 기억도 더 이상 조회되지 않아야 합니다. 넓은 범위일수록 영향과 권한이 커지므로 플랫폼 메모리는 자동 추출만으로 쉽게 만들지 않습니다.

같은 memory_key가 여러 범위에 있을 때 단순히 최신 항목을 고르지 않았습니다. 내용의 종류와 적용 범위를 함께 봐야 했습니다.

제약과 선호는 반대 방향으로 우선했습니다

플랫폼 정책과 세션 요청이 충돌할 때 더 구체적인 세션을 무조건 우선하면 사용자가 정책을 덮어쓸 수 있습니다. 반대로 모든 경우에 플랫폼 범위를 먼저 따르면 워크플로우별 형식과 사용자 선호가 의미를 잃습니다.

그래서 메모리에 범위뿐 아니라 constraint, preference, lesson, fact, decision 같은 종류를 저장했습니다. 제약은 넓은 범위가 우선합니다. 플랫폼 제약은 사용자나 세션의 선택으로 해제되지 않습니다. 선호와 교훈은 현재 작업에 가까운 좁은 범위가 우선합니다. 세션과 워크플로우 요구가 일반적인 사용자 선호보다 구체적이기 때문입니다.

예를 들어 사용자가 평소 자세한 답을 선호해도 워크플로우가 세 줄 요약을 요구한다면 이번 작업에는 워크플로우 선호를 적용합니다. 그러나 개인정보를 출력하지 말라는 플랫폼 제약은 둘보다 앞섭니다. 상충하는 문장을 모두 프롬프트에 넣고 모델에게 해결을 맡기는 대신 회상 단계가 적용할 항목을 먼저 결정합니다.

저장량보다 이번에 읽힐 양을 제한했습니다

범위와 우선순위를 정해도 장기 메모리가 계속 늘어나면 컨텍스트가 다시 커집니다. 관련 있어 보이는 내용을 모두 넣는 것은 전체 대화를 붙이는 방식과 크게 다르지 않습니다.

회상 경로는 항목별 길이와 항목 수를 먼저 제한하고 마지막에 전체 예산을 적용합니다. 같은 memory_key의 충돌을 정리한 뒤 현재 범위에 가깝고 우선순위가 높은 항목을 선택합니다. 모델에 전달할 때는 출처와 적용 범위를 함께 표시해 사용자 선호와 플랫폼 제약을 구분할 수 있게 합니다. 선택되지 않은 메모리는 삭제되는 것이 아니라 이번 컨텍스트에서만 빠집니다.

내용이 예산을 넘으면 생략된 양을 기록합니다. 현재 구현은 전체 문자 상한에서 문자열을 자를 수 있어 마지막 항목의 의미가 깨질 수 있습니다. 따라서 항목 전체를 우선순위대로 채우고, 들어가지 않는 항목은 통째로 제외하는 방식이 다음 보강 지점입니다.

저장 권한과 읽기 권한은 따로 확인합니다. 일반적인 비밀 키워드와 프롬프트 인젝션 패턴에 걸리는 후보는 거부하지만, 라벨 없이 값만 들어오거나 새 민감 필드가 추가된 경우까지 자동으로 알아내는 보장은 없습니다. 제품별 정책과 회귀 테스트를 함께 둬야 합니다.

만드는 경로와 지우는 경로를 함께 설계했습니다

메모리는 원본의 수명주기와 함께 움직여야 합니다. 워크플로우 삭제 시 해당 workflow 범위의 메모리와 실행 상태를 정리하고, 세션 종료 시 session 범위를 정리하는 훅을 구현했습니다. 만료된 항목은 저장소에 남아 있어도 회상 결과에서는 제외합니다. 다만 이 삭제 연결은 당시 기능 브랜치와 로컬 검증 범위였으며 운영 전체에 반영된 상태로 보아서는 안 됩니다.

삭제 연결은 본래의 워크플로우 삭제나 세션 종료를 막지 않는 best-effort 방식입니다. 메모리 저장소의 일시 장애 때문에 사용자의 본 작업 전체를 실패시키지 않는 장점이 있습니다. 대신 정리 실패가 경고로만 남고 항목이 잔존할 수 있으므로 운영에서는 재정리 경로와 잔존 범위를 함께 봐야 합니다.

이 시점에 엔진과 기능 경로에서 확인한 것은 범위별 저장과 회상, 충돌 정리, 만료 제외, 삭제 훅입니다. 오래된 기억의 신뢰도를 자동으로 낮추는 감쇠와 비슷한 기억을 주기적으로 병합하는 작업은 상시 실행 경로에 아직 포함하지 않았습니다. 관련 함수가 존재하는 것, 제품 수명주기에 연결된 것, 운영에 배포된 것은 서로 다른 사실입니다.

메모리의 품질은 얼마나 많이 저장했는지로 결정되지 않습니다. 현재 실행의 관측과 다음 실행의 교훈을 나누고, 범위와 종류로 충돌을 풀며, 읽힐 양과 삭제 경로를 통제해야 합니다. 다음 편에서는 시간에 따라 이어지는 기억에서 시선을 현재 실행으로 돌려, 연결된 도구와 출력 목적지를 모델에게 어느 수준까지 보여 줄지 살펴봅니다.


이전 편 → 모델을 비교하기 전에 실행 조건부터 통제하기(7편) 다음 편 → 도구 공개와 출력 전달을 실행 컨텍스트로 설계하기(9편)

#하네스#메모리#상태 관리
블로그 목록으로