LLM 캐시 적중률 0%를 발견한 날

26년 06월 06일

캐시 적중률이 0%다

이날은 두 가지를 발견한 날이었다.

하나는 소설 생성 에이전트에서 LLM 캐시가 전혀 효과를 못 내고 있었다는 발견이다.

다른 하나는 깃에 시크릿이 노출되었다는 사고다.

하나는 최적화 기회이고 하나는 비상사태다.

소설 생성 프로젝트에서 LLM 호출 비용을 점검했다.

그러다

이상한 걸 발견했다.

Gemini API의 캐시 적중률이 0%였다.

LLM API는 프롬프트 접두사를 캐싱한다.

정적인 부분은 캐시에서 가져오니까 매번 다시 계산할 필요가 없다.

비용이 줄고 속도가 빨라진다.

근데 우리는 캐시를 전혀 못 쓰고 있었다.

원인: 단일 문자열 병합

원인은 프롬프트 구조에 있었다.

모든 컨텍스트를 하나의 문자열로 합치고 있었다.

스토리 바이블, 캐릭터 정보, 장소 정보, 요약, 최근 에피소드를 전부 하나의 문자열로 템플릿 치환해서 만든다.

그리고 이 문자열을 그대로 API에 보낸다.

문제는 정적인 부분과 동적인 부분이 분리되어 있지 않다는 거다.

스토리 바이블은 에피소드마다 바뀌지 않는다.

캐릭터 정보도 거의 바뀌지 않는다.

근데 에피소드 번호랑 새 내용은 매번 바뀐다.

이걸 하나의 문자열로 합치면 캐시가 어디까지가 정적인지 알 수 없다.

접두사가 매번 바뀌니까 캐시 적중이 안 된다.

정적인 부분도 매번 다시 계산되는 거다.

낭비 계산

낭비를 계산해봤다.

정적 컨텍스트가 약 5.5K 토큰이다.

시스템 프롬프트, 스토리 바이블, 캐릭터 정보, 부가 프롬프트. 에피소드 하나당 4에서 15번 LLM을 호출한다.

작성이랑 검토 루프다.

10개 에피소드를 만들면 40에서 150번 호출한다.

매번 5.5K 토큰을 다시 보낸다.

이걸 고치면 에피소드당 40~50% 토큰을 줄일 수 있다.

엄청난 낭비가 숨어 있었다.

해결 방향

해결은 프롬프트를 여러 부분으로 나누는 거다.

정적인 부분을 별도의 API 필드로 보낸다.

동적인 부분을 따로 보낸다.

이러면 캐시가 정적인 부분을 식별할 수 있다.

그리고 Gemini의 캐시 콘텐츠 API를 쓰면 고정된 시스템 프롬프트랑 스타일 가이드를 명시적으로 캐싱할 수 있다.

깃에 시크릿이 노출되다

캐시 발견보다 더 급한 일이 터졌다.

깃에 OAuth 토큰이 노출되었다.

파이어베이스에서 Supabase로 마이그레이션하는 커밋을 푸시했다.

근데 그 커밋에 Playwright MCP 캐시 디렉토리가 포함되어 있었다.

이 디렉토리 안에 OAuth 토큰 파일이 있었다.

깃허브의 시크릿 스캐너가 즉시 감지했다.

“시크릿이 노출되었습니다” 경고가 떴다.

제거 과정

깃이그노어에 해당 디렉토리를 추가했다.

근데 깃이그노어는 미래 커밋만 막는다.

이미 커밋된 파일은 여전히 추적된다.

그래서 git rm --cached로 추적을 해제했다.

그리고 인터랙티브 리베이스로 두 개 커밋을 수정했다.

각 커밋에서 캐시 파일을 제거하고 amend했다.

그리고 강제 푸시로 원격 기록을 덮어썼다.

깃이그노어의 함정

이 사건의 교훈은 깃이그노어가 이미 추적된 파일을 못 막는다는 거다.

깃이그노어는 “앞으로 커밋하지 마라”지, “이미 커밋된 걸 지워라”가 아니다.

이미 커밋된 파일을 제거하려면 git rm --cached로 추적을 해제해야 한다.

그리고 기록에서 완전히 지우려면 리베이스나 필터링 도구가 필요하다.

마무리

이날의 두 발견은 전혀 다른 성격이지만 같은 교훈이 있다.

“숨어 있는 낭비를 찾아라.” 캐시 낭비는 보이지 않는 비용이었다.

매번 5.5K 토큰을 다시 보내고 있었지만 기능은 정상 동작했으니까 아무도 몰랐다.

점검해보니까 0% 적중률이 나온 거다.

숨어 있는 낭비는 점검하지 않으면 보이지 않는다.

시크릿 노출도 숨어 있었다.

캐시 디렉토리가 커밋에 포함된 걸 몰랐다.

깃이그노어에 넣어놨다고 안심하면 안 된다.

이미 추적된 파일은 깃이그노어가 못 막는다.

주기적으로 추적되는 파일을 점검하는 습관이 필요하다.

숨어 있는 낭비, 숨어 있는 위험. 이 둘은 점검하지 않으면 드러나지 않는다.

“돌아가니까 괜찮다”고 넘어가지 말고 “돌아가지만 정말 효율적인가, 안전한가”를 확인해야 한다.