Use when integrating LLMs into applications — API client design, streaming, token management, cost optimization, retry/fallback, model selection, prompt versioning, structured output, function calling, embeddings, RAG, fine-tuning, evaluation, safety guardrails, and rate limiting.
설치
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
Use when integrating LLMs into applications — API client design, streaming, token management, cost optimization, retry/fallback, model selection, prompt versioning, structured output, function calling, embeddings, RAG, fine-tuning, evaluation, safety guardrails, and rate limiting.
user-invocable
true
allowed-tools
["Read","Write","Edit","Grep","Glob","Bash"]
LLM Integration Patterns for Applications
Patterns for integrating LLMs into production applications with reliability, cost control, and safety.
1. API Client Design
@dataclassclassLLMConfig:
provider: ModelProvider # ANTHROPIC, OPENAI
model: str
api_key: str
max_retries: int = 3
timeout_seconds: int = 60
max_tokens: int = 4096
temperature: float = 0.0
rate_limit_rpm: int = 60@dataclassclassLLMResponse:
content: str
model: str
input_tokens: int
output_tokens: int
latency_ms: float
cost_usd: float
cached: bool = False
Key principles: Wrap provider SDKs behind a unified interface. Store config externally. Track tokens/cost/latency on every call.
Rate limiting: Use token bucket per provider. Track RPM and TPM. Queue requests when approaching limits. Return Retry-After headers to callers.
3. Streaming
asyncdefstream_response(prompt: str) -> AsyncIterator[str]:
asyncwith client.messages.stream(model=model, messages=[{"role": "user", "content": prompt}]) as stream:
asyncfor text in stream.text_stream:
yield text
# SSE endpoint pattern (FastAPI)@app.post("/api/chat/stream")asyncdefchat_stream(request: ChatRequest):
asyncdefevent_generator():
asyncfor chunk in stream_response(request.message):
yieldf"data: {json.dumps({'text': chunk})}\n\n"yield"data: [DONE]\n\n"return StreamingResponse(event_generator(), media_type="text/event-stream")
4. Token Management and Cost Optimization
Strategy
Savings
Effort
Prompt caching (Anthropic)
50-90% on cache hits
Low
Semantic caching (Redis + embeddings)
30-60%
Medium
Shorter prompts (compress examples)
20-40%
Low
Smaller model for simple tasks
60-80%
Medium
Batch API (non-real-time)
50%
Low
Model routing: Classify request complexity, route simple queries to smaller/cheaper models, complex to larger. Use token counting (tiktoken for OpenAI, Anthropic API returns counts) for budget enforcement.
Validation strategy: Parse with Pydantic. On validation failure, retry with error message appended. After 2 failures, fall back to unstructured + regex extraction.
6. Function Calling / Tool Use
tools = [{
"name": "lookup_customer",
"description": "Look up customer by ID or name",
"input_schema": {
"type": "object",
"properties": {
"customer_id": {"type": "integer"},
"name": {"type": "string"},
},
},
}]
# Tool execution loop
response = client.messages.create(model=model, messages=messages, tools=tools)
while response.stop_reason == "tool_use":
tool_call = next(b for b in response.content if b.type == "tool_use")
result = execute_tool(tool_call.name, tool_call.input) # your dispatch
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": [{"type": "tool_result", "tool_use_id": tool_call.id, "content": str(result)}]})
response = client.messages.create(model=model, messages=messages, tools=tools)
Safety: Validate tool inputs. Whitelist allowed tools per user role. Log all tool executions. Set max iterations (default 10) to prevent infinite loops.
# Core RAG pipelinedefrag_query(question: str, top_k: int = 5) -> str:
query_embedding = embed(question)
chunks = vector_store.search(query_embedding, top_k=top_k * 3)
reranked = reranker.rank(question, chunks)[:top_k]
context = "\n---\n".join(f"[{c.source}]: {c.text}"for c in reranked)
return llm_call(f"Answer using ONLY the context below. Cite sources.\n\nContext:\n{context}\n\nQuestion: {question}")
Chunking strategies: Fixed-size (512 tokens, 50 overlap) for general docs. Semantic (by heading/section) for structured docs. Sentence-level for FAQ/support.
When to use RAG vs fine-tuning vs long context:
RAG: Dynamic data, need citations, large corpus (>100K tokens)
Fine-tuning: Consistent style/format, domain vocabulary, small fixed knowledge
Long context: Small corpus (<100K tokens), need full document reasoning
8. Embeddings
Model
Dimensions
Use Case
text-embedding-3-small
1536
Cost-effective general purpose
text-embedding-3-large
3072
Higher accuracy, larger index
Cohere embed-v3
1024
Multilingual
Local (e5-large)
1024
Privacy-sensitive, no API calls
Best practices: Normalize embeddings. Use cosine similarity. Store in pgvector, Pinecone, or Qdrant. Batch embed operations. Cache embeddings -- recompute only on content change.
9. Prompt Versioning
# prompts/invoice-extract/v3.yamlid:invoice-extractversion:3model:claude-sonnet-4-20250514temperature:0.0system:"You extract structured data from invoices."template:|
Extract the following from this invoice:
{schema}
Invoice text:
{document}
tests:-input: {document:"Invoice #123..."}
expected_keys: ["vendor", "total", "line_items"]
changelog:"v3: Added line_item extraction, switched to structured output"
Principles: Version-control prompts like code. Test on eval suite before deploying. Use feature flags for A/B testing prompt versions. Roll back instantly on regression.
Decision framework: Start with the smallest model that meets accuracy requirements. Upgrade only when eval scores demand it. Use larger models for complex/high-stakes tasks, smaller for classification/extraction/routing.
12. Production Checklist
Retry with exponential backoff on transient errors