AI

[LLM] 정적 시스템 프롬프트 매 턴 바뀐 섹션만 주입 델타 컨텍스트

jykim23 2026. 8. 1. 19:57
반응형

정적 시스템 프롬프트 캐싱 델타 컨텍스트 바뀐 섹션 주입 delivered ledger

부제: 시스템 프롬프트는 고정하고, 사용자 정보는 바뀐 부분만 다시 넣은 이유

토큰 비용을 아끼려면 프롬프트 캐싱이 중요하다.
캐시가 먹으려면 캐시되는 앞부분, 즉 시스템 프롬프트가 고정돼 있어야 한다.

문제는 사용자 정보가 매 턴 필요하다는 거였다.

왜 매 턴 사용자 정보가 필요했나

특히 "지금이 아침인지 저녁인지"를 모델이 알아야 했다.
저녁인데 오전 일정을 이야기하거나, 저녁에 아침 인사를 하면 대화가 어긋난다.
아침이면 아침 인사, 저녁이면 저녁에 맞는 응대를 하려면 시각 정보가 매 턴 들어가야 한다.

그런데 이걸 시스템 프롬프트에 넣으면 끝이다.
시각은 1분만 지나도 바뀌니, 캐시되는 앞부분이 계속 달라져 캐시가 매번 깨진다.
캐시를 살리려던 게 무너진다.

시스템 프롬프트는 건드리지 않는다

그래서 동적 정보를 시스템 프롬프트에서 빼고, 사용자 메시지 앞에 <context> 블록으로 붙였다.
시스템 프롬프트는 완전히 고정한 채, 변하는 건 전부 사용자 메시지 쪽에 실었다.

여기서부터 커졌다.
사용자 정보는 회원가입 정보에, 디바이스·커스텀 같은 추가 정보까지 여러 섹션이다.
이걸 매 턴 통째로 넣으면 이번엔 그게 토큰 낭비가 된다.

바뀐 섹션만 다시 넣는다

그래서 델타 방식으로 갔다.
전체 컨텍스트를 만들어두고, 매 턴 새로 빌드해서 이미 넣은 것과 비교한다.
바뀐 섹션만 다시 주입한다. 디바이스 정보만 바뀌었으면 <device>만 넣는 식이다.

영리했던 건 "무엇이 바뀌었나"를 판정하는 방법이었다.
소스의 수정 시각(updated_at) 같은 메타데이터를 추적하지 않았다.
대신 렌더된 텍스트 자체를 버전으로 봤다.
이번에 렌더한 결과가 지난번 넣은 것과 다르면 재주입한다.
이러면 데이터 스키마가 바뀌어도 별도 로직 없이 자동으로 맞는다.

대화 요약이 새로 생기면 이 원장을 통째로 비운다.
그럼 다음 턴에 모든 섹션이 다시 채워지고, 요약도 한 번 주입된다.

정리

  • 캐시를 살리려면 시스템 프롬프트가 고정돼야 하는데, 사용자 정보(특히 시각)는 매 턴 바뀐다
  • 동적 정보를 시스템 프롬프트에서 빼 사용자 메시지 앞 <context> 블록으로 옮겼다
  • 매 턴 전체를 넣으면 토큰 낭비 → 이미 넣은 것과 비교해 바뀐 섹션만 재주입(델타)
  • "바뀜" 판정은 소스 메타가 아니라 렌더된 텍스트 자체로 — 스키마 변화에 자동으로 견고
  • 요약이 생기면 원장을 비워 다음 턴에 전부 재주입

캐시를 살리려면 변하는 걸 캐시되는 자리에 두지 마라.
동적 정보는 사용자 메시지로 옮기되, 매번 전부가 아니라 바뀐 섹션만 넣는다.
무엇이 바뀌었는지는 렌더된 결과 자체로 판정하면 메타 추적 없이 튼튼하다.

반응형