[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M719K6SN9RM4TCTPFDWWZ1RT":3,"skill-same:01M719K6SN9RM4TCTPFDWWZ1RT":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":14,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M719K6SN9RM4TCTPFDWWZ1RT","prompt-caching",null,"Caching strategies for LLM prompts including Anthropic prompt caching, response caching, and CAG (Cache Augmented Generation)","sapsapshen\u002Fai-memory-router","sapsapshen","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F20347959?v=4","01M6XDQEF1DP50DKF37H81J3J5","shenmian","01M6XDQEJPE41Y3DT2763X8ZJN",0,"MIT","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fglobal\u002Fprompt-caching\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35],"prompt caching","prompt","caching","apache","cache","prompts","strategies","caching strategies","generation","for","spawner","2026","2026-11-10 10:12:30",false,"---\nname: prompt-caching\ndescription: Caching strategies for LLM prompts including Anthropic prompt\n  caching, response caching, and CAG (Cache Augmented Generation)\nrisk: none\nsource: vibeship-spawner-skills (Apache 2.0)\ndate_added: 2026-02-27\n---\n\n# Prompt Caching\n\nCaching strategies for LLM prompts including Anthropic prompt caching, response caching, and CAG (Cache Augmented Generation)\n\n## Capabilities\n\n- prompt-cache\n- response-cache\n- kv-cache\n- cag-patterns\n- cache-invalidation\n\n## Prerequisites\n\n- Knowledge: Caching fundamentals, LLM API usage, Hash functions\n- Skills_recommended: context-window-management\n\n## Scope\n\n- Does_not_cover: CDN caching, Database query caching, Static asset caching\n- Boundaries: Focus is LLM-specific caching, Covers prompt and response caching\n\n## Ecosystem\n\n### Primary_tools\n\n- Anthropic Prompt Caching - Native prompt caching in Claude API\n- Redis - In-memory cache for responses\n- OpenAI Caching - Automatic caching in OpenAI API\n\n## Patterns\n\n### Anthropic Prompt Caching\n\nUse Claude's native prompt caching for repeated prefixes\n\n**When to use**: Using Claude API with stable system prompts or context\n\nimport Anthropic from '@anthropic-ai\u002Fsdk';\n\nconst client = new Anthropic();\n\n\u002F\u002F Cache the stable parts of your prompt\nasync function queryWithCaching(userQuery: string) {\n    const response = await client.messages.create({\n        model: \"claude-sonnet-4-20250514\",\n        max_tokens: 1024,\n        system: [\n            {\n                type: \"text\",\n                text: LONG_SYSTEM_PROMPT,  \u002F\u002F Your detailed instructions\n                cache_control: { type: \"ephemeral\" }  \u002F\u002F Cache this!\n            },\n            {\n                type: \"text\",\n                text: KNOWLEDGE_BASE,  \u002F\u002F Large static context\n                cache_control: { type: \"ephemeral\" }\n            }\n        ],\n        messages: [\n            { role: \"user\", content: userQuery }  \u002F\u002F Dynamic part\n        ]\n    });\n\n    \u002F\u002F Check cache usage\n    console.log(`Cache read: ${response.usage.cache_read_input_tokens}`);\n    console.log(`Cache write: ${response.usage.cache_creation_input_tokens}`);\n\n    return response;\n}\n\n\u002F\u002F Cost savings: 90% reduction on cached tokens\n\u002F\u002F Latency savings: Up to 2x faster\n\n### Response Caching\n\nCache full LLM responses for identical or similar queries\n\n**When to use**: Same queries asked repeatedly\n\nimport { createHash } from 'crypto';\nimport Redis from 'ioredis';\n\nconst redis = new Redis(process.env.REDIS_URL);\n\nclass ResponseCache {\n    private ttl = 3600;  \u002F\u002F 1 hour default\n\n    \u002F\u002F Exact match caching\n    async getCached(prompt: string): Promise\u003Cstring | null> {\n        const key = this.hashPrompt(prompt);\n        return await redis.get(`response:${key}`);\n    }\n\n    async setCached(prompt: string, response: string): Promise\u003Cvoid> {\n        const key = this.hashPrompt(prompt);\n        await redis.set(`response:${key}`, response, 'EX', this.ttl);\n    }\n\n    private hashPrompt(prompt: string): string {\n        return createHash('sha256').update(prompt).digest('hex');\n    }\n\n    \u002F\u002F Semantic similarity caching\n    async getSemanticallySimilar(\n        prompt: string,\n        threshold: number = 0.95\n    ): Promise\u003Cstring | null> {\n        const embedding = await embed(prompt);\n        const similar = await this.vectorCache.search(embedding, 1);\n\n        if (similar.length && similar[0].similarity > threshold) {\n            return await redis.get(`response:${similar[0].id}`);\n        }\n        return null;\n    }\n\n    \u002F\u002F Temperature-aware caching\n    async getCachedWithParams(\n        prompt: string,\n        params: { temperature: number; model: string }\n    ): Promise\u003Cstring | null> {\n        \u002F\u002F Only cache low-temperature responses\n        if (params.temperature > 0.5) return null;\n\n        const key = this.hashPrompt(\n            `${prompt}|${params.model}|${params.temperature}`\n        );\n        return await redis.get(`response:${key}`);\n    }\n}\n\n### Cache Augmented Generation (CAG)\n\nPre-cache documents in prompt instead of RAG retrieval\n\n**When to use**: Document corpus is stable and fits in context\n\n\u002F\u002F CAG: Pre-compute document context, cache in prompt\n\u002F\u002F Better than RAG when:\n\u002F\u002F - Documents are stable\n\u002F\u002F - Total fits in context window\n\u002F\u002F - Latency is critical\n\nclass CAGSystem {\n    private cachedContext: string | null = null;\n    private lastUpdate: number = 0;\n\n    async buildCachedContext(documents: Document[]): Promise\u003Cvoid> {\n        \u002F\u002F Pre-process and format documents\n        const formatted = documents.map(d =>\n            `## ${d.title}\\n${d.content}`\n        ).join('\\n\\n');\n\n        \u002F\u002F Store with timestamp\n        this.cachedContext = formatted;\n        this.lastUpdate = Date.now();\n    }\n\n    async query(userQuery: string): Promise\u003Cstring> {\n        \u002F\u002F Use cached context directly in prompt\n        const response = await client.messages.create({\n            model: \"claude-sonnet-4-20250514\",\n            max_tokens: 1024,\n            system: [\n                {\n                    type: \"text\",\n                    text: \"You are a helpful assistant with access to the following documentation.\",\n                    cache_control: { type: \"ephemeral\" }\n                },\n                {\n                    type: \"text\",\n                    text: this.cachedContext!,  \u002F\u002F Pre-cached docs\n                    cache_control: { type: \"ephemeral\" }\n                }\n            ],\n            messages: [{ role: \"user\", content: userQuery }]\n        });\n\n        return response.content[0].text;\n    }\n\n    \u002F\u002F Periodic refresh\n    async refreshIfNeeded(documents: Document[]): Promise\u003Cvoid> {\n        const stale = Date.now() - this.lastUpdate > 3600000;  \u002F\u002F 1 hour\n        if (stale) {\n            await this.buildCachedContext(documents);\n        }\n    }\n}\n\n\u002F\u002F CAG vs RAG decision matrix:\n\u002F\u002F | Factor           | CAG Better | RAG Better |\n\u002F\u002F |------------------|------------|------------|\n\u002F\u002F | Corpus size      | \u003C 100K tokens | > 100K tokens |\n\u002F\u002F | Update frequency | Low | High |\n\u002F\u002F | Latency needs    | Critical | Flexible |\n\u002F\u002F | Query specificity| General | Specific |\n\n## Sharp Edges\n\n### Cache miss causes latency spike with additional overhead\n\nSeverity: HIGH\n\nSituation: Slow response when cache miss, slower than no caching\n\nSymptoms:\n- Slow responses on cache miss\n- Cache hit rate below 50%\n- Higher latency than uncached\n\nWhy this breaks:\nCache check adds latency.\nCache write adds more latency.\nMiss + overhead > no caching.\n\nRecommended fix:\n\n\u002F\u002F Optimize for cache misses, not just hits\n\nclass OptimizedCache {\n    async queryWithCache(prompt: string): Promise\u003Cstring> {\n        const cacheKey = this.hash(prompt);\n\n        \u002F\u002F Non-blocking cache check\n        const cachedPromise = this.cache.get(cacheKey);\n        const llmPromise = this.queryLLM(prompt);\n\n        \u002F\u002F Race: use cache if available before LLM returns\n        const cached = await Promise.race([\n            cachedPromise,\n            sleep(50).then(() => null)  \u002F\u002F 50ms cache timeout\n        ]);\n\n        if (cached) {\n            \u002F\u002F Cancel LLM request if possible\n            return cached;\n        }\n\n        \u002F\u002F Cache miss: continue with LLM\n        const response = await llmPromise;\n\n        \u002F\u002F Async cache write (don't block response)\n        this.cache.set(cacheKey, response).catch(console.error);\n\n        return response;\n    }\n}\n\n\u002F\u002F Alternative: Probabilistic caching\n\u002F\u002F Only cache if query matches known high-frequency patterns\nclass SelectiveCache {\n    private patterns: Map\u003Cstring, number> = new Map();\n\n    shouldCache(prompt: string): boolean {\n        const pattern = this.extractPattern(prompt);\n        const frequency = this.patterns.get(pattern) || 0;\n\n        \u002F\u002F Only cache high-frequency patterns\n        return frequency > 10;\n    }\n\n    recordQuery(prompt: string): void {\n        const pattern = this.extractPattern(prompt);\n        this.patterns.set(pattern, (this.patterns.get(pattern) || 0) + 1);\n    }\n}\n\n### Cached responses become incorrect over time\n\nSeverity: HIGH\n\nSituation: Users get outdated or wrong information from cache\n\nSymptoms:\n- Users report wrong information\n- Answers don't match current data\n- Complaints about outdated responses\n\nWhy this breaks:\nSource data changed.\nNo cache invalidation.\nLong TTLs for dynamic data.\n\nRecommended fix:\n\n\u002F\u002F Implement proper cache invalidation\n\nclass InvalidatingCache {\n    \u002F\u002F Version-based invalidation\n    private cacheVersion = 1;\n\n    getCacheKey(prompt: string): string {\n        return `v${this.cacheVersion}:${this.hash(prompt)}`;\n    }\n\n    invalidateAll(): void {\n        this.cacheVersion++;\n        \u002F\u002F Old keys automatically become orphaned\n    }\n\n    \u002F\u002F Content-hash invalidation\n    async setWithContentHash(\n        key: string,\n        response: string,\n        sourceContent: string\n    ): Promise\u003Cvoid> {\n        const contentHash = this.hash(sourceContent);\n        await this.cache.set(key, {\n            response,\n            contentHash,\n            timestamp: Date.now()\n        });\n    }\n\n    async getIfValid(\n        key: string,\n        currentSourceContent: string\n    ): Promise\u003Cstring | null> {\n        const cached = await this.cache.get(key);\n        if (!cached) return null;\n\n        \u002F\u002F Check if source content changed\n        const currentHash = this.hash(currentSourceContent);\n        if (cached.contentHash !== currentHash) {\n            await this.cache.delete(key);\n            return null;\n        }\n\n        return cached.response;\n    }\n\n    \u002F\u002F Event-based invalidation\n    onSourceUpdate(sourceId: string): void {\n        \u002F\u002F Invalidate all caches that used this source\n        this.invalidateByTag(`source:${sourceId}`);\n    }\n}\n\n### Prompt caching doesn't work due to prefix changes\n\nSeverity: MEDIUM\n\nSituation: Cache misses despite similar prompts\n\nSymptoms:\n- Cache hit rate lower than expected\n- Cache creation tokens high, read low\n- Similar prompts not hitting cache\n\nWhy this breaks:\nAnthropic caching requires exact prefix match.\nTimestamps or dynamic content in prefix.\nDifferent message order.\n\nRecommended fix:\n\n\u002F\u002F Structure prompts for optimal caching\n\nclass CacheOptimizedPrompts {\n    \u002F\u002F WRONG: Dynamic content in cached prefix\n    buildPromptBad(query: string): SystemMessage[] {\n        return [\n            {\n                type: \"text\",\n                text: `You are helpful. Current time: ${new Date()}`,  \u002F\u002F BREAKS CACHE!\n                cache_control: { type: \"ephemeral\" }\n            }\n        ];\n    }\n\n    \u002F\u002F RIGHT: Static prefix, dynamic at end\n    buildPromptGood(query: string): SystemMessage[] {\n        return [\n            {\n                type: \"text\",\n                text: STATIC_SYSTEM_PROMPT,  \u002F\u002F Never changes\n                cache_control: { type: \"ephemeral\" }\n            },\n            {\n                type: \"text\",\n                text: STATIC_KNOWLEDGE_BASE,  \u002F\u002F Rarely changes\n                cache_control: { type: \"ephemeral\" }\n            }\n            \u002F\u002F Dynamic content goes in messages, NOT system\n        ];\n    }\n\n    \u002F\u002F Prefix ordering matters\n    buildWithConsistentOrder(components: string[]): SystemMessage[] {\n        \u002F\u002F Sort components for consistent ordering\n        const sorted = [...components].sort();\n        return sorted.map((c, i) => ({\n            type: \"text\",\n            text: c,\n            cache_control: i === sorted.length - 1\n                ? { type: \"ephemeral\" }\n                : undefined  \u002F\u002F Only cache the full prefix\n        }));\n    }\n}\n\n## Validation Checks\n\n### Caching High Temperature Responses\n\nSeverity: WARNING\n\nMessage: Caching with high temperature. Responses are non-deterministic.\n\nFix action: Only cache responses with temperature \u003C= 0.5\n\n### Cache Without TTL\n\nSeverity: WARNING\n\nMessage: Cache without TTL. May serve stale data indefinitely.\n\nFix action: Set appropriate TTL based on data freshness requirements\n\n### Dynamic Content in Cached Prefix\n\nSeverity: WARNING\n\nMessage: Dynamic content in cached prefix. Will cause cache misses.\n\nFix action: Move dynamic content outside of cache_control blocks\n\n### No Cache Metrics\n\nSeverity: INFO\n\nMessage: Cache without hit\u002Fmiss tracking. Can't measure effectiveness.\n\nFix action: Add cache hit\u002Fmiss metrics and logging\n\n## Collaboration\n\n### Delegation Triggers\n\n- context window|token -> context-window-management (Need context optimization)\n- rag|retrieval -> rag-implementation (Need retrieval system)\n- memory -> conversation-memory (Need memory persistence)\n\n### High-Performance LLM System\n\nSkills: prompt-caching, context-window-management, rag-implementation\n\nWorkflow:\n\n```\n1. Analyze query patterns\n2. Implement prompt caching for stable prefixes\n3. Add response caching for frequent queries\n4. Consider CAG for stable document sets\n5. Monitor and optimize hit rates\n```\n\n## Related Skills\n\nWorks well with: `context-window-management`, `rag-implementation`, `conversation-memory`\n\n## When to Use\n\n- User mentions or implies: prompt caching\n- User mentions or implies: cache prompt\n- User mentions or implies: response cache\n- User mentions or implies: cag\n- User mentions or implies: cache augmented\n","# Prompt Caching\n\nCaching strategies for LLM prompts including Anthropic prompt caching, response caching, and CAG (Cache Augmented Generation)\n\n## Capabilities\n\n- prompt-cache\n- response-cache\n- kv-cache\n- cag-patterns\n- cache-invalidation\n\n## Prerequisites\n\n- Knowledge: Caching fundamentals, LLM API usage, Hash functions\n- Skills_recommended: context-window-management\n\n## Scope\n\n- Does_not_cover: CDN caching, Database query caching, Static asset caching\n- Boundaries: Focus is LLM-specific caching, Covers prompt and response caching\n\n## Ecosystem\n\n### Primary_tools\n\n- Anthropic Prompt Caching - Native prompt caching in Claude API\n- Redis - In-memory cache for responses\n- OpenAI Caching - Automatic caching in OpenAI API\n\n## Patterns\n\n### Anthropic Prompt Caching\n\nUse Claude's native prompt caching for repeated prefixes\n\n**When to use**: Using Claude API with stable system prompts or context\n\nimport Anthropic from '@anthropic-ai\u002Fsdk';\n\nconst client = new Anthropic();\n\n\u002F\u002F Cache the stable parts of your prompt\nasync function queryWithCaching(userQuery: string) {\n    const response = await client.messages.create({\n        model: \"claude-sonnet-4-20250514\",\n        max_tokens: 1024,\n        system: [\n            {\n                type: \"text\",\n                text: LONG_SYSTEM_PROMPT,  \u002F\u002F Your detailed instructions\n                cache_control: { type: \"ephemeral\" }  \u002F\u002F Cache this!\n            },\n            {\n                type: \"text\",\n                text: KNOWLEDGE_BASE,  \u002F\u002F Large static context\n                cache_control: { type: \"ephemeral\" }\n            }\n        ],\n        messages: [\n            { role: \"user\", content: userQuery }  \u002F\u002F Dynamic part\n        ]\n    });\n\n    \u002F\u002F Check cache usage\n    console.log(`Cache read: ${response.usage.cache_read_input_tokens}`);\n    console.log(`Cache write: ${response.usage.cache_creation_input_tokens}`);\n\n    return response;\n}\n\n\u002F\u002F Cost savings: 90% reduction on cached tokens\n\u002F\u002F Latency savings: Up to 2x faster\n\n### Response Caching\n\nCache full LLM responses for identical or similar queries\n\n**When to use**: Same queries asked repeatedly\n\nimport { createHash } from 'crypto';\nimport Redis from 'ioredis';\n\nconst redis = new Redis(process.env.REDIS_URL);\n\nclass ResponseCache {\n    private ttl = 3600;  \u002F\u002F 1 hour default\n\n    \u002F\u002F Exact match caching\n    async getCached(prompt: string): Promise\u003Cstring | null> {\n        const key = this.hashPrompt(prompt);\n        return await redis.get(`response:${key}`);\n    }\n\n    async setCached(prompt: string, response: string): Promise\u003Cvoid> {\n        const key = this.hashPrompt(prompt);\n        await redis.set(`response:${key}`, response, 'EX', this.ttl);\n    }\n\n    private hashPrompt(prompt: string): string {\n        return createHash('sha256').update(prompt).digest('hex');\n    }\n\n    \u002F\u002F Semantic similarity caching\n    async getSemanticallySimilar(\n        prompt: string,\n        threshold: number = 0.95\n    ): Promise\u003Cstring | null> {\n        const embedding = await embed(prompt);\n        const similar = await this.vectorCache.search(embedding, 1);\n\n        if (similar.length && similar[0].similarity > threshold) {\n            return await redis.get(`response:${similar[0].id}`);\n        }\n        return null;\n    }\n\n    \u002F\u002F Temperature-aware caching\n    async getCachedWithParams(\n        prompt: string,\n        params: { temperature: number; model: string }\n    ): Promise\u003Cstring | null> {\n        \u002F\u002F Only cache low-temperature responses\n        if (params.temperature > 0.5) return null;\n\n        const key = this.hashPrompt(\n            `${prompt}|${params.model}|${params.temperature}`\n        );\n        return await redis.get(`response:${key}`);\n    }\n}\n\n### Cache Augmented Generation (CAG)\n\nPre-cache documents in prompt instead of RAG retrieval\n\n**When to use**: Document corpus is stable and fits in context\n\n\u002F\u002F CAG: Pre-compute document context, cache in prompt\n\u002F\u002F Better than RAG when:\n\u002F\u002F - Documents are stable\n\u002F\u002F - Total fits in context window\n\u002F\u002F - Latency is critical\n\nclass CAGSystem {\n    private cachedContext: string | null = null;\n    private lastUpdate: number = 0;\n\n    async buildCachedContext(documents: Document[]): Promise\u003Cvoid> {\n        \u002F\u002F Pre-process and format documents\n        const formatted = documents.map(d =>\n            `## ${d.title}\\n${d.content}`\n        ).join('\\n\\n');\n\n        \u002F\u002F Store with timestamp\n        this.cachedContext = formatted;\n        this.lastUpdate = Date.now();\n    }\n\n    async query(userQuery: string): Promise\u003Cstring> {\n        \u002F\u002F Use cached context directly in prompt\n        const response = await client.messages.create({\n            model: \"claude-sonnet-4-20250514\",\n            max_tokens: 1024,\n            system: [\n                {\n                    type: \"text\",\n                    text: \"You are a helpful assistant with access to the following documentation.\",\n                    cache_control: { type: \"ephemeral\" }\n                },\n                {\n                    type: \"text\",\n                    text: this.cachedContext!,  \u002F\u002F Pre-cached docs\n                    cache_control: { type: \"ephemeral\" }\n                }\n            ],\n            messages: [{ role: \"user\", content: userQuery }]\n        });\n\n        return response.content[0].text;\n    }\n\n    \u002F\u002F Periodic refresh\n    async refreshIfNeeded(documents: Document[]): Promise\u003Cvoid> {\n        const stale = Date.now() - this.lastUpdate > 3600000;  \u002F\u002F 1 hour\n        if (stale) {\n            await this.buildCachedContext(documents);\n        }\n    }\n}\n\n\u002F\u002F CAG vs RAG decision matrix:\n\u002F\u002F | Factor           | CAG Better | RAG Better |\n\u002F\u002F |------------------|------------|------------|\n\u002F\u002F | Corpus size      | \u003C 100K tokens | > 100K tokens |\n\u002F\u002F | Update frequency | Low | High |\n\u002F\u002F | Latency needs    | Critical | Flexible |\n\u002F\u002F | Query specificity| General | Specific |\n\n## Sharp Edges\n\n### Cache miss causes latency spike with additional overhead\n\nSeverity: HIGH\n\nSituation: Slow response when cache miss, slower than no caching\n\nSymptoms:\n- Slow responses on cache miss\n- Cache hit rate below 50%\n- Higher latency than uncached\n\nWhy this breaks:\nCache check adds latency.\nCache write adds more latency.\nMiss + overhead > no caching.\n\nRecommended fix:\n\n\u002F\u002F Optimize for cache misses, not just hits\n\nclass OptimizedCache {\n    async queryWithCache(prompt: string): Promise\u003Cstring> {\n        const cacheKey = this.hash(prompt);\n\n        \u002F\u002F Non-blocking cache check\n        const cachedPromise = this.cache.get(cacheKey);\n        const llmPromise = this.queryLLM(prompt);\n\n        \u002F\u002F Race: use cache if available before LLM returns\n        const cached = await Promise.race([\n            cachedPromise,\n            sleep(50).then(() => null)  \u002F\u002F 50ms cache timeout\n        ]);\n\n        if (cached) {\n            \u002F\u002F Cancel LLM request if possible\n            return cached;\n        }\n\n        \u002F\u002F Cache miss: continue with LLM\n        const response = await llmPromise;\n\n        \u002F\u002F Async cache write (don't block response)\n        this.cache.set(cacheKey, response).catch(console.error);\n\n        return response;\n    }\n}\n\n\u002F\u002F Alternative: Probabilistic caching\n\u002F\u002F Only cache if query matches known high-frequency patterns\nclass SelectiveCache {\n    private patterns: Map\u003Cstring, number> = new Map();\n\n    shouldCache(prompt: string): boolean {\n        const pattern = this.extractPattern(prompt);\n        const frequency = this.patterns.get(pattern) || 0;\n\n        \u002F\u002F Only cache high-frequency patterns\n        return frequency > 10;\n    }\n\n    recordQuery(prompt: string): void {\n        const pattern = this.extractPattern(prompt);\n        this.patterns.set(pattern, (this.patterns.get(pattern) || 0) + 1);\n    }\n}\n\n### Cached responses become incorrect over time\n\nSeverity: HIGH\n\nSituation: Users get outdated or wrong information from cache\n\nSymptoms:\n- Users report wrong information\n- Answers don't match current data\n- Complaints about outdated responses\n\nWhy this breaks:\nSource data changed.\nNo cache invalidation.\nLong TTLs for dynamic data.\n\nRecommended fix:\n\n\u002F\u002F Implement proper cache invalidation\n\nclass InvalidatingCache {\n    \u002F\u002F Version-based invalidation\n    private cacheVersion = 1;\n\n    getCacheKey(prompt: string): string {\n        return `v${this.cacheVersion}:${this.hash(prompt)}`;\n    }\n\n    invalidateAll(): void {\n        this.cacheVersion++;\n        \u002F\u002F Old keys automatically become orphaned\n    }\n\n    \u002F\u002F Content-hash invalidation\n    async setWithContentHash(\n        key: string,\n        response: string,\n        sourceContent: string\n    ): Promise\u003Cvoid> {\n        const contentHash = this.hash(sourceContent);\n        await this.cache.set(key, {\n            response,\n            contentHash,\n            timestamp: Date.now()\n        });\n    }\n\n    async getIfValid(\n        key: string,\n        currentSourceContent: string\n    ): Promise\u003Cstring | null> {\n        const cached = await this.cache.get(key);\n        if (!cached) return null;\n\n        \u002F\u002F Check if source content changed\n        const currentHash = this.hash(currentSourceContent);\n        if (cached.contentHash !== currentHash) {\n            await this.cache.delete(key);\n            return null;\n        }\n\n        return cached.response;\n    }\n\n    \u002F\u002F Event-based invalidation\n    onSourceUpdate(sourceId: string): void {\n        \u002F\u002F Invalidate all caches that used this source\n        this.invalidateByTag(`source:${sourceId}`);\n    }\n}\n\n### Prompt caching doesn't work due to prefix changes\n\nSeverity: MEDIUM\n\nSituation: Cache misses despite similar prompts\n\nSymptoms:\n- Cache hit rate lower than expected\n- Cache creation tokens high, read low\n- Similar prompts not hitting cache\n\nWhy this breaks:\nAnthropic caching requires exact prefix match.\nTimestamps or dynamic content in prefix.\nDifferent message order.\n\nRecommended fix:\n\n\u002F\u002F Structure prompts for optimal caching\n\nclass CacheOptimizedPrompts {\n    \u002F\u002F WRONG: Dynamic content in cached prefix\n    buildPromptBad(query: string): SystemMessage[] {\n        return [\n            {\n                type: \"text\",\n                text: `You are helpful. Current time: ${new Date()}`,  \u002F\u002F BREAKS CACHE!\n                cache_control: { type: \"ephemeral\" }\n            }\n        ];\n    }\n\n    \u002F\u002F RIGHT: Static prefix, dynamic at end\n    buildPromptGood(query: string): SystemMessage[] {\n        return [\n            {\n                type: \"text\",\n                text: STATIC_SYSTEM_PROMPT,  \u002F\u002F Never changes\n                cache_control: { type: \"ephemeral\" }\n            },\n            {\n                type: \"text\",\n                text: STATIC_KNOWLEDGE_BASE,  \u002F\u002F Rarely changes\n                cache_control: { type: \"ephemeral\" }\n            }\n            \u002F\u002F Dynamic content goes in messages, NOT system\n        ];\n    }\n\n    \u002F\u002F Prefix ordering matters\n    buildWithConsistentOrder(components: string[]): SystemMessage[] {\n        \u002F\u002F Sort components for consistent ordering\n        const sorted = [...components].sort();\n        return sorted.map((c, i) => ({\n            type: \"text\",\n            text: c,\n            cache_control: i === sorted.length - 1\n                ? { type: \"ephemeral\" }\n                : undefined  \u002F\u002F Only cache the full prefix\n        }));\n    }\n}\n\n## Validation Checks\n\n### Caching High Temperature Responses\n\nSeverity: WARNING\n\nMessage: Caching with high temperature. Responses are non-deterministic.\n\nFix action: Only cache responses with temperature \u003C= 0.5\n\n### Cache Without TTL\n\nSeverity: WARNING\n\nMessage: Cache without TTL. May serve stale data indefinitely.\n\nFix action: Set appropriate TTL based on data freshness requirements\n\n### Dynamic Content in Cached Prefix\n\nSeverity: WARNING\n\nMessage: Dynamic content in cached prefix. Will cause cache misses.\n\nFix action: Move dynamic content outside of cache_control blocks\n\n### No Cache Metrics\n\nSeverity: INFO\n\nMessage: Cache without hit\u002Fmiss tracking. Can't measure effectiveness.\n\nFix action: Add cache hit\u002Fmiss metrics and logging\n\n## Collaboration\n\n### Delegation Triggers\n\n- context window|token -> context-window-management (Need context optimization)\n- rag|retrieval -> rag-implementation (Need retrieval system)\n- memory -> conversation-memory (Need memory persistence)\n\n### High-Performance LLM System\n\nSkills: prompt-caching, context-window-management, rag-implementation\n\nWorkflow:\n\n```\n1. Analyze query patterns\n2. Implement prompt caching for stable prefixes\n3. Add response caching for frequent queries\n4. Consider CAG for stable document sets\n5. Monitor and optimize hit rates\n```\n\n## Related Skills\n\nWorks well with: `context-window-management`, `rag-implementation`, `conversation-memory`\n\n## When to Use\n\n- User mentions or implies: prompt caching\n- User mentions or implies: cache prompt\n- User mentions or implies: response cache\n- User mentions or implies: cag\n- User mentions or implies: cache augmented\n",{"name":5,"risk":41,"source":42,"date_added":43,"description":7},"none","vibeship-spawner-skills (Apache 2.0)",1772150400000,"main","7a38d8e7073e61c16eda85681cb32fb68a8657a5","skills-store\u002Fglobal\u002Fprompt-caching","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router","https:\u002F\u002Fgithub.com\u002Fsapsapshen","2026-04-14 21:12:12",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add sapsapshen\u002Fai-memory-router --skill prompt-caching",{"tool":56,"command":57},"bunx","bunx skills add sapsapshen\u002Fai-memory-router --skill prompt-caching",{"tool":59,"command":60},"pnpm","pnpm dlx skills add sapsapshen\u002Fai-memory-router --skill prompt-caching","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fglobal\u002Fprompt-caching\u002FSKILL.md",true,[],[65,89,115,125,138,155],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":76,"publishedAt":36},"01M71ATQRKG48SH06FQ697T5G9","wechat-search","Search WeChat Official Account articles using OpenClaw's web search and fetch capabilities with compliance-focused design.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fwechat-search-release\u002FSKILL.md",[71],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[77,78,79,80,81,82,83,84,85,86,87,88],"wechat search","wechat","search","capabilities","openclaw","design","web search","compliance","web","official","fetch","with",{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":36},"01M71ATNAVGZB35PFYM2GC5N00","trend-tap","Real-time trending topics aggregator across 7 platforms (X\u002FTwitter, Reddit, Google Trends, Hacker News, Zhihu, Bilibili, Weibo). Trigger: when user says 'trend', 'trends', 'trend tap', '热点', '热搜', or asks what is trending\u002Fhot. Do NOT use web_search — this skill already fetches live data from all platforms with zero API keys.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftrend-tap\u002FSKILL.md",[],[96,97,98,99,100,101,79,102,103,104,105,106,107,108,109,110,111,112,113,114],"trend","trend tap","tap","api keys","Bash","time","trending","hacker","aggregator","do","when","brew","live","data","google","install","read","across","api",{"skillNo":116,"name":117,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":36},"01M71ATJ9AM5KM15AA8PS302EB","trend-radar","Real-time trending topics aggregator across 7 platforms (X\u002FTwitter, Reddit, Google Trends, Hacker News, Zhihu, Bilibili, Weibo). Trigger: when user says 'trend', 'trends', 'trend pulse', '热点', '热搜', or asks what is trending\u002Fhot. Do NOT use web_search — this skill already fetches live data from all platforms with zero API keys.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftrend-radar\u002FSKILL.md",[],[122,123,96,107,108,109,110,100,79,112,124,113,114,106,104,103,102,111,101,99],"trend radar","radar","pulse",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":36},"01M71ATGF095N3EJM9G8SD0BB5","tech-news-daily","每日科技新闻汇——从全球多个 RSS 源抓取最新科技新闻，翻译（英→中）、去重、排版成每日简报。当用户询问科技新闻、科技新鲜事、每日科技、技术动态、Daily Tech News 或类似表达时触发此技能。","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftech-news-daily\u002FSKILL.md",[],[132,133,134,135,136,137],"news","tech","tech news daily","daily","rss","翻译",{"skillNo":139,"name":140,"nameZh":6,"description":141,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":147,"publishedAt":36},"01M71ATFAEAMQ17M70NQNY7SR8","summarize","Summarize URLs or files with the summarize CLI (web, PDFs, images, audio, YouTube).","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fsummarize\u002FSKILL.md",[144],{"categoryNo":145,"categoryName":146,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",[140,85,148,149,150,88,107,151,152,153,98,154,111],"Audio","cli","youtube","images","https","files","pdfs",{"skillNo":156,"name":157,"nameZh":6,"description":158,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":159,"categories":160,"keywords":161,"publishedAt":36},"01M71ATDNS3R0M4H936PACQAWZ","sonoscli","Control Sonos speakers (discover\u002Fstatus\u002Fplay\u002Fvolume\u002Fgroup).","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fsonoscli\u002FSKILL.md",[],[157,162,163,164,111,165,152,166,167,168,169,170],"status","play","go","latest","github","discover","control","cmd","volume"]