프롬프트 캐싱 디코딩: PagedAttention 원칙을 통해 10배 비용 절감 및 효율성 향상 @dejavucoder의 이 글은 @vllm_project의 PagedAttention 기술을 중심으로 프롬프트 캐싱의 기본 원리를 심층적으로 다룹니다. 개발 과정에서 겪었던 함정들을 직접 경험한 저자는 개발자들이 캐싱 메커니즘에 대해 흔히 가지고 있는 오해를 바로잡고 매우 실용적인 최적화 방안을 제시합니다. 핵심 오해와 진실: 캐싱은 개인 정보가 아닌 글로벌 정보입니다. 오해: 저자는 (많은 사람들처럼) 처음에는 프롬프트 캐싱이 "사용자 세션"에 기반한다고 생각했습니다. 즉, 동일한 대화 상자 내에서 동일한 사용자가 보낸 후속 메시지만 이전에 캐시된 메시지를 활용할 수 있다는 것입니다. 사실은 프롬프트 캐싱은 사용자 기반이 아니라 콘텐츠 기반이라는 것입니다. • 핵심 논리: 시스템 프롬프트나 도구 정의가 완전히 일관된 텍스트인 경우 사용자 A가 생성한 캐시를 사용자 B가 완전히 재사용할 수 있습니다. • 중요성: 이는 높은 동시성 시나리오에서 접두사가 일관되는 한 시스템이 "전역 재사용"을 달성하여 중복 계산을 크게 줄일 수 있음을 의미합니다. 캐싱이 필요한 이유는 무엇입니까? (비용 대 속도) LLM의 추론 과정은 두 단계로 나뉘며, 이러한 차이점을 이해하는 것은 캐싱의 가치를 이해하는 데 중요합니다. • 사전 채우기 단계: 이 단계에서는 입력된 대량의 프롬프트를 처리하고 키-값 캐시를 계산합니다. 이 프로세스는 계산 집약적이며 많은 컴퓨팅 파워를 소모합니다. • 디코딩 단계: 응답 토큰을 하나씩 생성합니다. 이 프로세스는 메모리와 대역폭을 많이 사용합니다. • 캐싱 없이: 요청이 들어올 때마다, 프롬프트의 처음 90%가 동일하더라도 사전 채우기를 위해 모델을 다시 계산해야 하므로 느리고 비용도 많이 듭니다. • 캐시 적중: 번거로운 사전 채우기 계산을 직접 건너뛰어 토큰 입력 비용을 10배 줄이고 첫 번째 문자 생성 속도를 크게 향상시킵니다. 기술 공개: PagedAttention 기존의 키-값 캐시 관리 방식은 매우 비효율적이어서, 연속된 비디오 메모리의 큰 블록을 미리 할당해야 하는데, 이로 인해 조각화와 낭비가 쉽게 발생합니다. vLLM은 운영 체제 메모리 관리의 개념인 페이징을 도입했습니다. • 블록: 시스템은 큰 연속적인 메모리 블록을 할당하는 대신, KV 캐시를 고정된 크기의 "블록"으로 나눕니다. 이러한 블록은 물리적 비디오 메모리 내에 분산되어 있고 연속적이지 않을 수 있습니다. • 블록 해싱 – 효과적인 캐싱의 핵심: 시스템은 "이 구절이 이전에 계산되었다"는 것을 어떻게 알 수 있을까요? 블록의 해시 값을 계산합니다. • 부모 블록 종속성: 블록의 해시 값은 자체 콘텐츠뿐만 아니라 이전 블록의 해시 값에도 따라 달라집니다. • 연쇄 반응: 블록체인과 유사합니다. 현재 해시 값은 "처음부터" 모든 것이 완벽하게 일치할 때만 일치합니다. 이는 인과 관계의 정확성을 보장합니다. 중간 부분을 그대로 재사용할 수 없으며, 접두사(prefix)가 정확히 일치해야 합니다. • 글로벌 검색: 새로운 요청이 들어오면 시스템은 해당 프롬프트 단어의 블록 해시를 계산하여 전역 해시 테이블에서 조회합니다. 일치하는 항목이 발견되면 추가 계산 없이 기존 메모리 블록을 직접 가리킵니다. 개발자를 위한 실용적인 조언: 시스템을 속여 캐시를 사용하는 방법은? 캐시 적중률을 극대화하려면 시스템이 서로 다른 요청을 "동일한" 요청으로 처리하도록 설정해야 합니다. 이 문서에서는 몇 가지 황금률을 제시합니다. • 안정적인 접두사를 유지합니다. 모든 정적 콘텐츠(시스템 프롬프트, 도구 정의, 샘플 텍스트)를 맨 처음에 배치합니다. • 반례: 프롬프트의 시작 부분에 "현재 시간"이나 "사용자 이름"을 넣으면 해시 체인 전체가 처음부터 끊어지고, 이후의 내용은 동일하더라도 캐시에서 재사용할 수 없습니다. • 결정론적 직렬화 JSON 형식을 사용하여 데이터를 전송할 때(예: 유틸리티 호출) 키 순서는 일정하게 유지되어야 합니다. 팁: Python에서 `json.dumps(..., sort_keys=True)`를 사용하세요. `{ "a": 1, "b": 2 }`와 `{ "b": 2, "a": 1 }`는 의미적으로는 동일하지만 서로 다른 문자열을 생성하여 캐시 미스를 발생시킵니다. • 추가 전용 모드 여러 차례의 대화 기록을 관리할 때는 마지막에만 새로운 콘텐츠를 추가하세요. 중간 기록을 수정하거나 자르지 마세요. 중간 기록이 변경되면 이후의 캐시 체인 전체가 무효화됩니다. • 도구 정의 변경에 주의하십시오. 도구 정의는 모델에 의해 시스템 프롬프트에 추가되는 경우가 많습니다. 사용자별로 다른 도구를 동적으로 활성화/비활성화하는 경우 접두사가 변경되어 캐시가 무효화됩니다. 요약하다 프롬프트 캐싱의 핵심은 "메모리"가 아니라 "연산 결과 재사용"입니다. 블록 및 해시 체인 메커니즘의 기본 원리를 이해하면 개발자는 "접두사"가 왜 그렇게 중요한지 이해할 수 있습니다. 간단히 말해서, 항상 변경되지 않는 것(시스템 명령, 배경 문서, 도구 목록)은 처음에 넣고, 변경되는 것(사용자 질문, 동적 변수)은 마지막에 넣으세요. 원본 텍스트를 읽어보세요
스레드를 불러오는 중
깔끔한 읽기 화면을 위해 X에서 원본 트윗을 가져오고 있어요.
보통 몇 초면 완료되니 잠시만 기다려 주세요.
