0Pricing
AI Prompt Engineering · บทเรียน

กลยุทธ์การแคชพรอมต์

การแคชเชิงความหมาย การแคชแบบตรงกันทุกประการ และการแคชพรอมต์ของ 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 rate

TTL ของแคชและกลยุทธ์การขับข้อมูลออก

ผลลัพธ์ที่แคชไว้จะล้าสมัยเมื่อความรู้พื้นฐานเปลี่ยนแปลงหรือโมเดลได้รับการปรับปรุง 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. กลยุทธ์การแคชพรอมต์
  2. การประมวลผลเป็นชุดและการทำงานแบบอะซิงโครนัส
  3. การกระจายโหลดระหว่างโมเดล
  4. การตรวจติดตามและแจ้งเตือนสำหรับไปป์ไลน์พรอมต์
← กลับไปที่ AI Prompt Engineering