กลยุทธ์การแคชพรอมต์
การแคชเชิงความหมาย การแคชแบบตรงกันทุกประการ และการแคชพรอมต์ของ Anthropic
กลยุทธ์การแคชพรอมต์ เป็นบทเรียน AI Prompt Engineering ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Prompt Engineering และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องแคชผลลัพธ์ของพรอมต์
การเรียกใช้บริการ LLM มีค่าใช้จ่ายสูงและใช้เวลานาน แอปพลิเคชันที่ใช้งานจริงจำนวนมากส่งพรอมต์เดิมหรือพรอมต์ที่คล้ายกันมากซ้ำ ๆ การแคชจะส่งคืนผลลัพธ์ที่จัดเก็บไว้สำหรับคำขอซ้ำ จึงตัดการเรียกใช้บริการที่ไม่จำเป็นและลดทั้งต้นทุนกับเวลาแฝงลงอย่างมาก
การแคชแบบตรงกันทุกประการด้วยคีย์แฮช
แคชที่ง่ายที่สุดคือ แฮชสตริงพรอมต์แบบตรงกันทุกประการแล้วจัดเก็บผลลัพธ์ไว้ หากพบสตริงพรอมต์เดิมอีกครั้ง ก็ส่งคืนผลลัพธ์จากแคชโดยไม่เรียกใช้บริการ
import hashlib
import json
from functools import lru_cache
class ExactMatchCache:
def __init__(self, backend=None):
# backend: a dict (in-memory) or Redis client
self.store = backend or {}
def _key(self, messages, model, max_tokens):
content = json.dumps({'messages': messages, 'model': model,
'max_tokens': max_tokens}, sort_keys=True)
return 'llm:' + hashlib.sha256(content.encode()).hexdigest()
def get(self, messages, model, max_tokens):
key = self._key(messages, model, max_tokens)
return self.store.get(key)
def set(self, messages, model, max_tokens, result, ttl_seconds=3600):
key = self._key(messages, model, max_tokens)
self.store[key] = result
# In Redis: self.store.setex(key, ttl_seconds, json.dumps(result))
cache = ExactMatchCache()
# Usage
messages = [{'role': 'user', 'content': 'What is the capital of France?'}]
cached = cache.get(messages, 'gpt-4o-mini', 100)
if cached:
print('Cache HIT:', cached[:50])
else:
print('Cache MISS — calling API...')ไคลเอ็นต์ LLM ที่ห่อหุ้มด้วยแคช
ห่อหุ้มการเรียกใช้บริการ LLM ด้วยตัวตกแต่งสำหรับแคช เพื่อให้ผู้เรียกใช้ทั้งหมดได้รับความสามารถในการแคชโดยอัตโนมัติ โดยไม่ต้องเปลี่ยนโค้ด
import openai
from typing import Optional
client = openai.OpenAI(api_key='YOUR_API_KEY')
cache = ExactMatchCache()
def cached_completion(messages, model='gpt-4o-mini', max_tokens=500,
temperature=0.0, use_cache=True) -> str:
if use_cache and temperature == 0.0:
# Only cache deterministic requests (temperature=0)
cached = cache.get(messages, model, max_tokens)
if cached:
return cached
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=temperature
)
result = response.choices[0].message.content
if use_cache and temperature == 0.0:
cache.set(messages, model, max_tokens, result)
return result
# Important: only cache temperature=0 responses
# Non-deterministic responses (temp>0) may return stale results
print('Cache wrapping: only deterministic (temp=0) calls are cached.')การแคชเชิงความหมายด้วยเวกเตอร์ฝังตัว
การแคชเชิงความหมายจะส่งคืนผลลัพธ์จากแคชสำหรับคำค้นที่ มีความหมายคล้ายกัน ไม่ใช่เฉพาะสตริงที่เหมือนกันเท่านั้น วิธีนี้ใช้เวกเตอร์ฝังตัวและ cosine_similarity เพื่อค้นหาคำค้นที่ซ้ำกันเกือบทั้งหมด
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class SemanticCache:
def __init__(self, similarity_threshold=0.95):
self.entries = [] # [(embedding, query, result)]
self.threshold = similarity_threshold
def embed(self, text):
'''Get embedding for text using OpenAI embeddings API.'''
response = client.embeddings.create(
model='text-embedding-3-small',
input=text
)
return np.array(response.data[0].embedding)
def get(self, query):
if not self.entries:
return None
query_emb = self.embed(query)
for emb, stored_query, result in self.entries:
sim = cosine_similarity([query_emb], [emb])[0][0]
if sim >= self.threshold:
print(f'Semantic cache HIT (similarity={sim:.3f}): {stored_query[:40]}...')
return result
return None
def set(self, query, result):
emb = self.embed(query)
self.entries.append((emb, query, result))
sem_cache = SemanticCache(similarity_threshold=0.95)
print('Semantic cache ready. Threshold: 0.95 cosine similarity.')ไลบรารี GPTCache
GPTCache เป็นไลบรารีโอเพนซอร์สสำหรับการแคชเชิงความหมายที่รองรับโมเดลเวกเตอร์ฝังตัวหลายแบบ ระบบจัดเก็บความคล้ายกันหลายแบบ (FAISS, Redis) และกลยุทธ์การขับข้อมูลออกจากแคช ไลบรารีนี้ทำงานร่วมกับไคลเอ็นต์ OpenAI และ LangChain ได้โดยตรง
# pip install gptcache
# GPTCache integration example
# from gptcache import cache
# from gptcache.adapter import openai
# from gptcache.embedding import Onnx
# from gptcache.manager import CacheBase, VectorBase, get_data_manager
# from gptcache.similarity_evaluation.distance import SearchDistanceEvaluation
# Initialize GPTCache
# onnx = Onnx()
# data_manager = get_data_manager(
# CacheBase('sqlite'),
# VectorBase('faiss', dimension=onnx.dimension)
# )
# cache.init(
# embedding_func=onnx.to_embeddings,
# data_manager=data_manager,
# similarity_evaluation=SearchDistanceEvaluation(),
# )
# After init, use openai from gptcache.adapter instead of standard openai
# response = openai.ChatCompletion.create(
# model='gpt-4o-mini',
# messages=[{'role': 'user', 'content': 'What is Python?'}]
# )
# Same API, but cache is checked first
print('GPTCache: drop-in semantic cache for OpenAI API calls.')
print('Supports: FAISS, Redis, SQLite, Milvus as vector backends.')การแคชพรอมต์ของ Anthropic (แบบเนทีฟ)
Anthropic มี การแคชพรอมต์แบบเนทีฟ ซึ่งแคชการประมวลผลพรอมต์ระบบไว้บนเซิร์ฟเวอร์ของตน เมื่อพบข้อมูลในแคช คุณจะจ่ายเพียง 10% ของราคาปกติสำหรับโทเค็นข้อมูลนำเข้า วิธีนี้แยกจากการแคชผลลัพธ์ในระดับแอปพลิเคชัน
import anthropic
client = anthropic.Anthropic(api_key='YOUR_API_KEY')
LONG_SYSTEM_PROMPT = '''You are an expert financial analyst with 20 years of experience.
''' + 'Domain knowledge: ' + 'analysis context...' * 500 # large system prompt
# Enable prompt caching with cache_control
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=1024,
system=[
{
'type': 'text',
'text': LONG_SYSTEM_PROMPT,
'cache_control': {'type': 'ephemeral'} # cache this prefix
}
],
messages=[{'role': 'user', 'content': 'Analyze Q3 2024 earnings.'}]
)
print('Cache write tokens:', response.usage.cache_creation_input_tokens)
print('Cache read tokens: ', response.usage.cache_read_input_tokens)
print('Regular input tokens:', response.usage.input_tokens)
# On cache HIT: cache_read_input_tokens shows the cached tokens
# Cost: cached tokens charged at 10% of normal rateTTL ของแคชและกลยุทธ์การขับข้อมูลออก
ผลลัพธ์ที่แคชไว้จะล้าสมัยเมื่อความรู้พื้นฐานเปลี่ยนแปลงหรือโมเดลได้รับการปรับปรุง TTL (อายุการใช้งาน) และกลยุทธ์การขับข้อมูลออกช่วยจัดการความใหม่ของข้อมูล
import time
from collections import OrderedDict
class TTLCache:
def __init__(self, max_size=1000, default_ttl=3600):
self.store = OrderedDict() # key: (value, expire_at)
self.max_size = max_size
self.default_ttl = default_ttl
def set(self, key, value, ttl=None):
ttl = ttl or self.default_ttl
expire_at = time.time() + ttl
if key in self.store:
del self.store[key]
self.store[key] = (value, expire_at)
# LRU eviction: remove oldest if over capacity
if len(self.store) > self.max_size:
self.store.popitem(last=False)
def get(self, key):
if key not in self.store:
return None
value, expire_at = self.store[key]
if time.time() > expire_at:
del self.store[key]
return None # expired
# Move to end (LRU update)
self.store.move_to_end(key)
return value
# TTL strategy guidelines
ttl_guidelines = {
'Static knowledge': 86400, # 24h (facts, definitions)
'Semi-static': 3600, # 1h (product info, FAQs)
'Dynamic content': 300, # 5min (news, prices)
'Personalized': 0 # no cache (user-specific)
}
for k, v in ttl_guidelines.items():
print(f'{k}: {v}s TTL')รูปแบบการทำให้แคชเป็นโมฆะ
การทำให้แคชเป็นโมฆะ หรือการรู้ว่าเมื่อใดควรล้างข้อมูลที่ล้าสมัย เป็นหนึ่งในปัญหาที่ยากที่สุดของการประมวลผล สำหรับแคช LLM รูปแบบเหล่านี้รองรับความต้องการทั่วไปในการทำให้แคชเป็นโมฆะ
class InvalidationAwareCache(TTLCache):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tags = {} # key: set of tags
self.tag_index = {} # tag: set of keys
def set_with_tags(self, key, value, tags, ttl=None):
self.set(key, value, ttl)
self.tags[key] = set(tags)
for tag in tags:
self.tag_index.setdefault(tag, set()).add(key)
def invalidate_by_tag(self, tag):
keys_to_delete = self.tag_index.pop(tag, set())
for key in keys_to_delete:
self.store.pop(key, None)
self.tags.pop(key, None)
print(f'Invalidated {len(keys_to_delete)} entries with tag={tag}')
# Usage: tag cache entries by data source
cache = InvalidationAwareCache()
cache.set_with_tags('product_faq_123', 'Product FAQs...', tags=['product:123', 'faqs'])
cache.set_with_tags('product_spec_123', 'Spec sheet...', tags=['product:123', 'specs'])
# When product 123 is updated, invalidate all its cache entries
cache.invalidate_by_tag('product:123') # Invalidated 2 entriesการวัดประสิทธิภาพแคช
ติดตามตัวชี้วัดประสิทธิภาพแคชเพื่อทำความเข้าใจผลกระทบของการแคชต่อต้นทุนและเวลาแฝง แคชที่ปรับแต่งอย่างดีควรมีอัตราการพบข้อมูลในแคชมากกว่า 50% สำหรับกรณีใช้งานจริงส่วนใหญ่
class CacheMetrics:
def __init__(self):
self.hits = 0
self.misses = 0
self.total_latency_saved_ms = 0
self.total_cost_saved_usd = 0
self.avg_api_latency_ms = 1500 # typical LLM call latency
self.avg_api_cost_usd = 0.002 # typical cost per call
def record_hit(self):
self.hits += 1
self.total_latency_saved_ms += self.avg_api_latency_ms
self.total_cost_saved_usd += self.avg_api_cost_usd
def record_miss(self):
self.misses += 1
def report(self):
total = self.hits + self.misses
hit_rate = self.hits / total if total else 0
return {
'hit_rate': f'{hit_rate:.1%}',
'total_requests': total,
'cache_hits': self.hits,
'latency_saved_sec': round(self.total_latency_saved_ms / 1000, 1),
'cost_saved_usd': round(self.total_cost_saved_usd, 2)
}
metrics = CacheMetrics()
for i in range(100):
if i % 3 == 0: # simulate 33% hit rate
metrics.record_hit()
else:
metrics.record_miss()
print(metrics.report())แคชที่ใช้ Redis เป็นแหล่งจัดเก็บสำหรับระบบจริง
แคชในหน่วยความจำจะสูญหายเมื่อเริ่มระบบใหม่ และไม่สามารถใช้ร่วมกันระหว่างอินสแตนซ์เซิร์ฟเวอร์ได้ Redis มอบแคชถาวรที่ใช้ร่วมกันได้ ซึ่งทำงานข้ามเซิร์ฟเวอร์เอพีไอหลายเครื่องในการนำไปใช้งานจริง
import redis
import json
import hashlib
class RedisLLMCache:
def __init__(self, host='localhost', port=6379, db=0, default_ttl=3600):
self.client = redis.Redis(host=host, port=port, db=db,
decode_responses=True)
self.default_ttl = default_ttl
def _key(self, messages, model):
content = json.dumps({'messages': messages, 'model': model},
sort_keys=True)
return 'llmcache:' + hashlib.sha256(content.encode()).hexdigest()
def get(self, messages, model):
key = self._key(messages, model)
value = self.client.get(key)
if value:
self.client.expire(key, self.default_ttl) # refresh TTL on hit
return json.loads(value)
return None
def set(self, messages, model, result, ttl=None):
key = self._key(messages, model)
self.client.setex(key, ttl or self.default_ttl, json.dumps(result))
def stats(self):
keys = self.client.keys('llmcache:*')
return {'cached_entries': len(keys),
'memory_bytes': self.client.memory_usage('llmcache:') or 0}
# Usage: drop-in replacement for in-memory cache
# cache = RedisLLMCache(host='redis.internal', port=6379)
print('RedisLLMCache: shared across all server instances, survives restarts.')เมื่อไม่ควรใช้แคช
การแคชไม่เหมาะกับการเรียกใช้ LLM ทุกประเภท การทำความเข้าใจว่าควรข้ามการแคชเมื่อใดจะช่วยป้องกันการส่งผลลัพธ์เก่าหรือไม่ถูกต้องให้ผู้ใช้
DONT_CACHE_WHEN = {
'High temperature': (
'temperature > 0 produces different outputs for the same input. '
'Caching would always return the first generation, defeating the purpose.'
),
'Real-time data required': (
'Queries about current prices, live news, or real-time status '
'must always hit the API and live data source.'
),
'Personalized responses': (
'Responses that depend on user_id, session context, or personal data '
'should not be shared across users.'
),
'Safety-critical': (
'Medical, legal, or financial responses where staleness could cause harm '
'require fresh responses with the most current model version.'
),
'Non-deterministic tools': (
'If the prompt includes a current timestamp or random seed, '
'the response is by design non-repeatable.'
)
}
for condition, reason in DONT_CACHE_WHEN.items():
print(f'Skip cache: {condition}')
print(f' Reason: {reason[:60]}...')
print()ตรวจสอบความเข้าใจ
ความแตกต่างสำคัญระหว่างการแคชแบบตรงกันทุกประการกับการแคชเชิงความหมายสำหรับการตอบกลับของ LLM คืออะไร
สรุปกลยุทธ์การแคช
การแคชพรอมต์อย่างมีประสิทธิภาพต้องผสานหลายกลยุทธ์เข้าด้วยกัน:
- การตรงกันทุกประการ: ใช้แฮช ไม่มีค่าใช้จ่ายเพิ่มเมื่อพบรายการตรงกัน แต่อัตราการพบรายการต่ำเมื่อใช้ถ้อยคำหลากหลาย
- การแคชเชิงความหมาย: ใช้ความคล้ายคลึงของเวกเตอร์ฝังตัวเพื่อค้นหาข้อความที่มีความหมายเหมือนกันแต่ใช้ถ้อยคำต่างกัน จึงมีอัตราการพบรายการสูงกว่า
- GPTCache: ไลบรารีโอเพนซอร์สที่ผสานทั้งสองกลยุทธ์เข้ากับแบ็กเอนด์ FAISS/Redis
- การแคชในตัวของ Anthropic: การแคชพรอมต์ระบบฝั่งเซิร์ฟเวอร์ โดยมีต้นทุนโทเค็น 10%
- การกำจัดรายการด้วย TTL + LRU: ควบคุมความใหม่ของข้อมูลตามเวลาและจัดการความจุ
- การทำให้ใช้ไม่ได้ตามแท็ก: ทำให้รายการที่เกี่ยวข้องใช้ไม่ได้เมื่อข้อมูลต้นทางเปลี่ยนแปลง
- เมื่อไม่ควรใช้แคช: อุณหภูมิไม่เป็นศูนย์ ข้อมูลแบบเรียลไทม์ ข้อมูลเฉพาะบุคคล และงานที่มีความสำคัญด้านความปลอดภัย
คำถามที่พบบ่อย
บทเรียน “กลยุทธ์การแคชพรอมต์” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กลยุทธ์การแคชพรอมต์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Prompt Engineering ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กลยุทธ์การแคชพรอมต์”
การแคชเชิงความหมาย การแคชแบบตรงกันทุกประการ และการแคชพรอมต์ของ Anthropic คุณปฏิบัติ AI Prompt Engineering ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Prompt Engineering หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Prompt Engineering บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “กลยุทธ์การแคชพรอมต์” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Prompt Engineering นี้ได้ไหม
ได้ บทเรียน AI Prompt Engineering ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- กลยุทธ์การแคชพรอมต์
- การประมวลผลเป็นชุดและการทำงานแบบอะซิงโครนัส
- การกระจายโหลดระหว่างโมเดล
- การตรวจติดตามและแจ้งเตือนสำหรับไปป์ไลน์พรอมต์