프롬프트 캐시를 설명할 때 “자주 쓰는 지침을 캐시에 넣는다”는 표현을 많이 씁니다. 이 말은 절반만 맞습니다. 캐시는 중요한 문장을 따로 보관하는 메모 상자가 아닙니다. 이전 요청과 이번 요청의 앞부분이 같을 때, 이미 처리한 접두 구간을 다시 활용하는 방식에 가깝습니다.
그래서 캐시를 잘 쓰는 첫 질문은 “무엇을 더 넣을까?”가 아닙니다.
“다음 요청에서도 어느 지점까지 똑같이 유지할 수 있을까?”
Hermes의 프롬프트 조립 구조는 이 질문을 코드로 드러냅니다. 시스템 프롬프트를 안정 구간, 작업 맥락 구간, 변동 구간으로 나누고, 턴마다 바뀌어야 하는 임시 정보는 API 호출 시점의 별도 층으로 보냅니다. 완성된 시스템 프롬프트 자체는 세션 안에서 고정합니다.[1][2]
한 문장으로 답하면: 캐시는 내용보다 경계를 본다
긴 공통 지침 뒤에 매번 달라지는 티켓 번호나 시각을 붙인다고 해봅시다.
[매번 같은 긴 작업 지침]
티켓: 1042
시각: 10:00
다음 호출에서는 끝의 두 값만 바뀝니다.
[매번 같은 긴 작업 지침]
티켓: 1043
시각: 10:05
전체를 하나의 원자적인 블록으로 취급하면 작은 꼬리 변화 때문에 긴 앞부분까지 새 블록처럼 다뤄질 수 있습니다. 반대로 “여기까지는 고정 접두사이고 그 뒤는 변동 입력”이라는 경계를 선언하면, 요청을 보낼 때 고정 부분과 변동 부분을 분리해 표시할 수 있습니다.[3][4]
중요한 것은 고정 접두사가 최종 문자열의 정확한 시작 부분이어야 한다는 점입니다. 비슷한 문장이나 같은 의미만으로는 충분하지 않습니다. 공백, 줄바꿈, 문서 순서가 달라져도 바이트 접두사가 달라집니다. Hermes의 경계 테스트는 등록된 문자열이 최종 메시지의 실제 접두사인지, 여러 후보가 있으면 가장 긴 접두사를 고르는지 확인합니다.[4]
Hermes가 시스템 프롬프트를 세 구간으로 나누는 이유
동결된 시스템 프롬프트 조립 코드는 세 이름을 사용합니다.[1][2]
안정 구간
에이전트 정체성, 보편적인 실행 원칙, 도구 사용 지침처럼 세션과 작업이 달라도 비교적 그대로 유지될 수 있는 앞부분입니다. 이 구간은 가능한 한 오래 같은 바이트를 유지해야 합니다.
작업 맥락 구간
현재 작업 폴더의 스냅샷, 프로젝트 컨텍스트 파일, 호출자가 준 시스템 메시지처럼 세션이 바뀌면 달라질 수 있지만 한 세션 안에서는 안정적으로 유지할 정보가 옵니다. 모든 변화를 안정 구간 앞에 섞지 않고 뒤로 미루면, 앞의 공통 접두사를 더 길게 재사용할 여지가 생깁니다.[1]
변동 구간
스킬 색인, 메모리 스냅샷, 사용자 프로필, 날짜처럼 재구성 시 달라질 가능성이 높은 내용이 마지막에 놓입니다. 여기서 “변동”은 매 턴 즉시 다시 읽는다는 뜻이 아닙니다. 완성된 시스템 프롬프트는 세션 수명 동안 캐시되며 압축이나 복원 같은 재구성 경계에서 이 구간이 달라질 수 있다는 뜻입니다.[1][2]
이 순서는 단순한 정리 취향이 아닙니다. 자주 바뀌는 내용을 앞에 놓으면 그 뒤의 긴 공통 지침까지 접두사 일치 범위에서 밀려납니다. 바뀔 가능성이 큰 항목을 뒤에 놓으면 변화가 생겨도 앞부분을 지킬 수 있습니다.
정말 매 턴 달라야 하는 것은 시스템 프롬프트 밖으로 뺀다
현재 시각, 이번 요청에만 유효한 게이트웨이 정보, 플러그인이 방금 가져온 회상 결과처럼 턴마다 달라지는 정보도 있습니다. 이를 시스템 프롬프트 안에 매번 끼워 넣으면 저장된 프롬프트와 접두사 안정성을 함께 흔듭니다.
Hermes의 공식 프롬프트 조립 문서는 이런 정보를 API 호출 시점 전용 층으로 분리합니다. 임시 시스템 프롬프트, 미리 채운 메시지, 게이트웨이 세션 덧씌움, 현재 턴에 주입되는 외부 회상 등이 이 범주입니다. 플러그인의 호출 직전 컨텍스트도 캐시된 시스템 프롬프트를 고치는 대신 현재 사용자 메시지에 붙습니다.[1]
이 원칙을 실무 문장으로 바꾸면 이렇습니다.
- 여러 턴에 걸쳐 같은 규칙은 앞쪽의 안정된 층에 둔다.
- 세션이나 작업 공간에 묶인 정보는 그 뒤에 둔다.
- 재구성 때 달라질 수 있는 스냅샷은 더 뒤로 보낸다.
- 이번 호출에서만 필요한 값은 시스템 프롬프트 자체를 고치지 않는다.
많이 넣는 것이 목표가 아니라, 변화의 주기가 다른 내용을 섞지 않는 것이 목표입니다.
캐시 표식은 저장된 대화를 바꾸지 않는다
Hermes의 캐시 구현은 저장된 시스템 프롬프트를 매번 쪼개서 보관하지 않습니다. 요청을 공급자 형식으로 만들 때만 안정 접두사와 나머지를 분리하고 캐시 제어 표식을 붙입니다. 이렇게 하면 세션 저장 형식과 다른 전송 방식은 그대로 두면서, 지원하는 공급자 요청에만 경계를 표현할 수 있습니다.[3]
구현은 안정 접두사가 시스템 메시지의 실제 시작과 정확히 일치할 때만 분리합니다. 일치하지 않으면 안전한 대체 경로를 쓰거나 표식을 생략합니다. 접두사 뒤가 비어 있으면 빈 텍스트 블록을 만들지 않고 전체를 하나의 블록으로 표시합니다. 전송 실패 후 다른 공급자로 넘길 때는 기존 표식을 제거한 뒤 새 대상의 정책에 맞게 다시 장식하며, 저장된 대화 원문을 고치지 않도록 복사본에서 처리합니다.[3]
웹훅이나 크론처럼 긴 공통 안내문 뒤에 짧은 가변 입력을 붙이는 호출에는 별도의 “빌더가 선언한 안정 접두사” 경계가 있습니다. 테스트는 티켓 값이나 시각이 바뀌어도 공통 안내문 경계가 최종 메시지의 접두사로 유지되는지, 입력 안에 경계처럼 보이는 문자열이 들어와도 그것을 다시 해석해 권한 있는 경계로 삼지 않는지 확인합니다.[4]
이 장치는 캐시 적중률을 자동으로 보장하지 않습니다. 공급자의 최소 캐시 길이, 보존 시간, 모델과 공급자 경계, 실제 요청 크기에 따라 효과는 달라질 수 있습니다. 코드가 경계를 올바르게 표시한다는 것과 비용이 몇 퍼센트 줄었다는 것은 별개의 주장입니다.
안전한 최소 재현: 고정 안내문과 가변 꼬리를 분리해 본다
외부 모델을 호출하지 않고 요청 장식 단계만 검사할 수 있습니다.
STATIC_SCAFFOLD_를 반복한 긴 고정 안내문을 만듭니다.- 뒤에
ticket=42 time=10:00을 붙여 첫 사용자 메시지를 만듭니다. - 고정 안내문을 안정 접두사로 등록하고 캐시 계획 함수를 호출합니다.
- 장식된 메시지가 고정 접두사 블록과 가변 꼬리 블록으로 나뉘었는지 확인합니다.
- 티켓과 시각만
ticket=43 time=10:05로 바꿔 다시 계획을 만듭니다. - 두 요청의 첫 블록이 바이트 단위로 같은지, 두 번째 블록만 달라졌는지 비교합니다.
- 대조군에서는 안정 접두사를 등록하지 않고 전체 메시지가 한 블록으로 취급되는지 확인합니다.
- 마지막으로 경계 제거 함수를 적용해 원래 문자열이 정확히 복원되는지 검사합니다.
판정값은 캐시 비용이 아니라 구조입니다.
고정 접두사 동일 여부
가변 꼬리만 변경됐는지
캐시 표식 개수와 위치
표식 제거 뒤 원문 일치 여부
입력 메시지 원본의 비변경 여부
실험에는 합성 문자열과 복사된 메시지만 사용합니다. 실제 API 키와 네트워크 호출은 필요하지 않습니다. 전송 함수에 도달하면 중단합 니다.
이번 글에서 관찰한 것과 기대 결과
이번 글에서 직접 확인한 것은 공식 문서, 시스템 프롬프트 조립 코드, 캐시 장식 코드, 회귀 테스트의 계약입니다. 조립 코드는 안정·작업 맥락·변동 구간을 순서대로 만들고 완성된 프롬프트를 세션 동안 고정합니다.[1][2] 캐시 코드는 전송 시점에 정확히 일치하는 안정 접두사를 분리하며, 남은 표식 예산을 최근 캐시 가능한 메시지나 도구 경계에 배치합니다.[3] 경계 테스트는 고정 안내문과 가변 입력의 분리, 가장 긴 접두사 선택, 요청별 복사와 원문 복원 조건을 확인합니다.[4][5]
위 합성 비교는 이번 글을 위해 새로 실행하지 않았습니다. 따라서 캐시 적중 횟수, 입력 토큰 절감량, 비용과 지연 개선치를 결과로 쓰지 않습니다. 코드 계약에 따른 기대 결과는 티켓과 시각을 바꿔도 고정 접두사 블록은 같고 가변 꼬리만 달라지는 것입니다. 대조군은 전체 문자열이 하나의 단위로 남아 작은 꼬리 변화와 고정 안내문을 분리해 표현하지 못합니다.
공식 테스트 통과도 전송 구조의 회귀 방지 근거일 뿐, 특정 공급자에서의 실제 절감 효과나 장기 운영 성능을 증명하지 않습니다.
프롬프트를 설계할 때 바로 적용할 기준
첫째, 날짜와 현재 시각을 긴 시스템 지침의 맨 앞에 넣지 않습니다. 둘째, 매 요청마다 달라지는 티켓·사용자 입력·조회 결과를 고정 안내문과 같은 문자열로 무심코 재작성하지 않습니다. 셋째, 의미가 같더라도 공백과 문서 순서를 계속 바꾸는 템플릿은 접두사 안정성을 해칠 수 있으므로 결정론적으로 렌더링합니다. 넷째, 시스템 프롬프트를 매 턴 최신 상태로 만드는 것과 캐시를 오래 유지하는 것은 긴장 관계가 있다는 점을 인정하고, 즉시성이 필요한 값은 호출 시점 층으로 보냅니다.
프롬프트 캐시는 “중요한 내용을 많이 저장하는 기능”이 아닙니다. 반복되는 앞부분을 반복되는 모습 그대로 남겨 두는 기술입니다. 그래서 최적화는 추가보다 분리, 분리보다 안정성에서 시작합니다.
확인 범위와 한계
이 글은 동결된 Hermes Agent의 프롬프트 조립 문서·코드, 캐시 장식 코드, 공식 회귀 테스트를 직접 읽은 범위입니다. 실제 공급자 호출, 캐시 적중 로그, 최소 캐시 길이, 보존 시간, 토큰·비용·지연 절감률은 확인하지 않았습니다. 요청 구조가 올바르게 분리된다는 테스트를 현장 효과로 승격하지 않았습니다.
Sources
[1] Hermes Agent — Prompt Assembly
[2] Hermes Agent — `agent/system_prompt.py`
[3] Hermes Agent — `agent/prompt_caching.py`