OpenAI API 및 모델 최적화
openai사의 모델을 이용해 서비스를 운용하는 곳들이 있을거다. (나도 소소하게 운영중이기도 하고)
성능, 비용, 속도 이 3박자를 맞추기란 참 어려운것 같다.
그럼 모델을 사용하는입장에서 저 3박자를 다 가져갈수 있을까에 대한 고민을 했던 부분을 정리해본다.
모델 프롬프트에는 시스템 프롬프트나 일반적인 지시사항과 같은 반복적인 내용이 자주 포함된다. OpenAI는 최근 동일한 프롬프트를 처리한 서버로 API 요청을 라우팅하여, 새로운 프롬프트를 처음부터 처리하는 것보다 더 저렴하고 빠르게 응답할 수 있도록 한다. 이를 통해 긴 프롬프트의 경우 지연 시간을 최대 80%까지 줄이고 비용을 50% 절감할 수 있다.
https://platform.openai.com/docs/guides/prompt-caching
프롬프트 캐싱을 지원하는 모델이 정해져있으니 항상 참고하길 바란다.
물론 역할별로 프롬프트의 길이를 먼저 줄이고, 그 후에 캐싱관련된 구조화를 고민해도 좋을거 같다.
캐싱은 프롬프트가 1024 토큰 이상일 때 자동으로 활성화된다. 캐싱은 1024 토큰 이상을 포함하는 프롬프트에 대해 적용되며, 캐시 히트는 128 토큰 단위로 발생한다. 따라서 요청에서 캐시된 토큰의 수는 항상 다음과 같은 시퀀스에 속하게 된다: 1024, 1152, 1280, 1408 등, 프롬프트 길이에 따라 다르다.
왜 128토큰 단위로 캐시 히트가 발생할까? '토큰 블록 단위'로 캐시를 적용하는 방식을 사용하고 있다.
GPT계열의 모델은 고정된 크기의 텍스트블록(청크)를 한번에 처리하는 구조다. 이 블록 단위를 효율적으로 관리 하려면 고정된 크기의 캐시 청크를 저장하고 검색하는 것이 유리하다. 128토큰 단위는 OpenAI가 최적화한 청크 크기일 가능성이 있다.
동작방식은 아래와 같다.
1. 캐시 조회 (Cache Lookup): 시스템은 프롬프트의 초기 부분(접두사)이 캐시에 저장되어 있는지 확인한다.
2. 캐시 히트 (Cache Hit): 일치하는 접두사가 발견되면 시스템은 캐시된 결과를 사용한다. 이를 통해 지연 시간이 크게 줄고 비용이 절감된다.
3. 캐시 미스 (Cache Miss): 일치하는 접두사가 없으면 시스템은 전체 프롬프트를 처리한다. 처리 후 프롬프트의 접두사는 향후 요청을 위해 캐시에 저장된다.
캐시 할수 있는 항목은 아래와 같다.
메시지 : 시스템, 사용자 및 어시스턴트 상호작용을 포함한 전체 메시지 배열
이미지: 사용자 메시지에 포함된 링크 또는 base64로 인코딩된 데이터로 제공된 이미지
도구 사용 : 메시지 배열 및 사용 가능한 도구 목록
구조화된 출력 : 구조화된 출력 스키마는 시스템 메시지의 접두어로 사용되며 캐시될 수 있습니다.
그럼 프롬프트가 길다고 가정하고 파인튜닝을 하지않는 다고 가정하고, 토큰을 최적화 vs 프롬프트캐싱 을 고민한다고 하면
- 1024토큰 시퀀스를 맞춰서 설계해야 할것이고
- 변동이 많은 프롬프트 예를 들면 사용자 이름이나 타임스탬프(년월일 말고 시분초포함한)는 캐싱이 어려울것이므로 이를 고려해야 한다.
프롬프트 캐시 - 베스트프랙티스 (정리중)
일치하는 접두어가 발견되면 시스템은 캐시된 결과를 사용하는데, 일치하는 접두어가 없으면 시스템이 전체 프롬프트를 처리한다.
캐시히트율을 높이기 위한 베스트프랙티스에대해서 정리를 해보려고 한다.
1) 캐시익스파이어를 시간적으로 조절할수 있는지 또는 특정환경에서만 적용하고 비교테스트를 해볼수 있는지
캐시는 비활성화 삭제일때 5~10분후에 발생하고, 비피크시간에는 최대 1시간 유지된다고 알고 있는데 비피크 시간은 오히려 처리량이 많아서 프롬프트캐시를 더 오래유지 해야 할거 같은데 비피크시간에 캐시가 더 길게 유지되는 이유는 무엇인지
2) 프롬프트캐싱이 출력토큰 생성이나, API의 최종 응답에 얼마나 영향을 미치는지
3) 테스트 하는 과정에서 캐시를 수동을 삭제 하고 싶은경우, 방법은 있는지 (ttl이 5분~10분이면 적당한가 싶기도 한데..)
시스템프롬프트에 날짜, 이름정보등 가변데이터가 뒷부분에 있다면 캐싱 적용될 가능성이 높다.
- 캐시는 1024 토큰 이상일 때 적용됨.
- 캐시 히트는 128 토큰 단위로 발생 → 1024, 1152, 1280, 1408, …
- 프롬프트의 첫 1024+ 토큰이 동일하면 캐시 가능!
- 즉, 변경되는 부분(날짜, 이름 등)이 1024+ 토큰 이후에 위치하면 캐싱이 됨.
- {
role: "system",
content: "지시사항프롬프트가 들어가있어"
... (1024+ 토큰) ...
### Today ###
10:13 AM on Tuesday, March 18, 2025 ⬅ [🔴 변동 가능]
### User Name ###
Name: 사용자 이름 ⬅ [🔴 변동 가능]
}
role: "system"
content: "지시사항프롬프트" 그리고 맨 뒤에 "오늘날짜에 대한 정보, 사용자이름" 즉 가변데이터가 포함
role: "assistant"
content: {
name: "DaumNewsTool"
result: [웹검색에 나온 후보군]
: {
role: "user"
content: "ooo 대한 정보를 제공" -- 이건 유저쿼리가 아니라 유저쿼리를 한번 Goal과 같은 형태로 변환
}
캐싱이 원하는대로 안된다면, 1024+ 토큰에 대한 부분을 고민해봐야한다. 이유는 날짜나 이름이 1024 토큰 내로 밀려들어오면 캐싱이 깨지기 때문이다.
OpenAI의 프롬프트 캐싱은 전체 입력을 해시(Hash) 값으로 저장한 후 비교하여 캐시를 적용하는 구조다.
즉, 프롬프트가 1024 토큰 이상일 때만 캐시가 활성화되고, 캐시는 전체 문자열이 동일해야 히트됨. (1024 토큰이 항상 동일해야 함.)