← /geode/portfolioGEODE . 문서
GitHub
설정
레퍼런스

프롬프트 캐싱

STATIC/DYNAMIC 경계로 구분되는 Anthropic ephemeral 캐싱. agentic 어댑터와 router의 non-agentic 헬퍼, 두 호출 지점에 적용됩니다.

경계 마커

core/agent/system_prompt.py:35에 정의되어 있습니다. v0.93부터 9개 prompt 파일의 16개 marker가 XML 래퍼로 전환됩니다. 경계 자체는 동일 sentinel 문자열이지만, marker가 노출되는 영역은 <dynamic_context> XML 안으로 캡슐화됩니다.

PROMPT_CACHE_BOUNDARY = "__GEODE_PROMPT_CACHE_BOUNDARY__"

# v0.93+ XML 래퍼 (system prompt 안에서)
... STATIC 영역 ...
__GEODE_PROMPT_CACHE_BOUNDARY__
<dynamic_context>
... DYNAMIC 영역 ...
</dynamic_context>

build_system_prompt()이 이 marker를 두 섹션 사이에 삽입합니다. audit-mode는 dynamic 블록을 strip합니다 (System Prompt Modes 참조).

  • STATIC (마커 이전). router 템플릿, GEODE.md 의 아이덴티티. 턴 간 안정적.
  • DYNAMIC (마커 이후). 현재 날짜, 모델 카드, 프로젝트 메모리 (G2-G4), 사용자 컨텍스트. 매 턴 변경됨.

어댑터의 분할 방식

core/llm/providers/anthropic.py:476-495의 agentic 어댑터.

from core.agent.system_prompt import PROMPT_CACHE_BOUNDARY

if PROMPT_CACHE_BOUNDARY in system:
    static_part, dynamic_part = system.split(PROMPT_CACHE_BOUNDARY, 1)
    sys_blocks = [
        {"type": "text", "text": static_part.rstrip(),
         "cache_control": {"type": "ephemeral"}},
        {"type": "text", "text": dynamic_part.lstrip()},
    ]
else:
    sys_blocks = [
        {"type": "text", "text": system,
         "cache_control": {"type": "ephemeral"}},
    ]

STATIC 블록은 캐시 마커를 받지만 DYNAMIC 블록은 받지 않습니다. Anthropic은 STATIC 프리픽스를 서버 측에서 캐싱하며, 5분 TTL 안의 후속 턴은 DYNAMIC 접미부와 새 user 메시지에 대해서만 과금됩니다.

Non-agentic 호출 지점

core/llm/router.py의 네 호출 지점 (라인 481, 582, 749, 901)은 더 단순한 헬퍼 system_with_cache(system)를 써서 system prompt 전체를 단일 ephemeral 블록으로 감쌉니다. 이들은 STATIC/DYNAMIC 구조화 system prompt를 조립하지 않는 non-agentic LLM 호출 (단발 prompt, 평가 호출) 입니다.

캐시되는 것, 캐시되지 않는 것

대상캐시 여부
Anthropic system prompt . STATIC 섹션Yes (ephemeral)
Anthropic system prompt . DYNAMIC 섹션No (매 턴 변경)
Anthropic non-agentic system prompt (전체)Yes (단일 ephemeral 블록)
Anthropic messages 배열Yes. 최근 3개 non-system 메시지 (PR #864, 헬퍼 anthropic.py:175, 호출 :501)
OpenAI / Codex system promptGEODE 측 명시 wiring 없음 (OpenAI가 서버 측에서 자동 캐싱)
GLM system prompt프로바이더 관리

messages history 캐싱 (PR #864)

Anthropic은 요청당 최대 4개의 캐시 breakpoint를 허용합니다. 어댑터는 messages.create 직전에 apply_messages_cache_control(messages)를 적용해 최근 3개 non-system 메시지의 마지막 content 블록에 cache_control: ephemeral을 붙입니다. 위의 system 블록과 합치면 4개 슬롯을 모두 채워 롤링 히스토리가 캐시됩니다.

# core/llm/providers/anthropic.py:175 (helper) and :501 (call site)
cached_messages = apply_messages_cache_control(messages)
create_kwargs = {
    "system": sys_blocks,
    "messages": cached_messages,
    ...
}

헬퍼는 비-변형 (얕은 복사된 새 리스트 반환) 이며, strlist[block] content를 모두 처리하고 빈 리스트 content는 조용히 건너뜁니다. 19개 케이스가 tests/test_anthropic_messages_cache.py에서 검증됩니다.

캐시 무효화

캐시 키는 캐시된 블록의 바이트 단위 콘텐츠와 모델 ID입니다. STATIC 섹션의 어떤 변경 (예. 업데이트된 GEODE.md 아이덴티티, 새 도메인 예제 목록, router 템플릿 수정) 도 캐시를 무효화하며, 후속 턴이 다시 캐시에 적중하기 전에 한 번의 전체 요청 비용을 지불해야 합니다.

이것이 prompt drift 감지 (Prompt Hashing) 와 prompt 캐싱이 설계상 긴밀하게 결합된 이유입니다. 조용한 prompt 변경은 조용한 캐시 무효화로 이어지며, 해시 잠금장치는 그런 변경을 의식적인 단계로 강제합니다.