Best Practices
Production-ready patterns for implementing Langfuse observability in your applications.
Naming Conventions
Use consistent, descriptive names for easy filtering and analysis.
Recommended Pattern
# Use prefixes to categorize operations
@observe(name="agent:plan_task")
@observe(name="tool:search_documents")
@observe(name="rag:retrieve_context")
@observe(name="llm:generate_response")
| Prefix | Use Case |
|---|---|
agent: | Agent orchestration and reasoning |
tool: | Tool/function executions |
rag: | Retrieval-augmented generation steps |
llm: | Direct LLM calls |
api: | External API interactions |
User & Session Tracking
Always Track Users
from caip_agents_sdk.observability import observe, propagate_attributes
@observe(name="api:handle_request")
async def handle_request(request: Request):
with propagate_attributes(
user_id=request.user.id,
session_id=request.headers.get("X-Session-ID")
):
return await process(request)
Benefits
| Feature | Benefit |
|---|---|
| User ID | Debug specific user issues |
| Session ID | View complete conversations |
| Filtering | Analyze usage patterns |
Metadata Strategy
What to Include
from caip_agents_sdk.observability import observe, get_client
@observe(
name="rag:search",
metadata={
"index_name": "products",
"search_type": "hybrid"
}
)
async def search(query: str) -> list:
results = await vector_store.search(query)
# Update span with dynamic metadata
client = get_client()
if client:
client.update_current_span(
metadata={
"result_count": len(results),
"top_score": results[0].score if results else 0
}
)
return results
Metadata Guidelines
| ✅ Do | ❌ Don't |
|---|---|
| Index names | PII (emails, names) |
| Search types | Full request bodies |
| Result counts | API keys or secrets |
| Feature flags | Large data payloads |
| Model versions | Sensitive user data |
Error Handling
Capture Errors with Context
from caip_agents_sdk.observability import observe, get_client
@observe(name="llm:generate")
async def generate(prompt: str) -> str:
try:
return await llm.complete(prompt)
except Exception as e:
client = get_client()
if client:
client.update_current_span(
metadata={
"error": str(e),
"error_type": type(e).__name__
}
)
raise
Performance Optimization
Graceful Shutdown
import atexit
from caip_agents_sdk.observability import flush
atexit.register(flush)
Production Checklist
Before Deployment
- Environment variables configured
- User/session tracking implemented
- Consistent naming conventions
- No PII in metadata
- Graceful shutdown with flush
- Error handling with context
Monitoring
| Check | Frequency |
|---|---|
| Trace volume | Daily |
| Error rates | Real-time alerts |
| Latency P95 | Daily |
| Token costs | Weekly |
Quick Reference
SDK Functions
| Function | Purpose |
|---|---|
@observe(name="...") | Wrap functions for tracing |
propagate_attributes() | Set user/session IDs |
get_client() | Get Langfuse client for advanced operations |
client.update_current_span() | Add dynamic metadata |
flush() | Force send pending traces |
Environment Variables
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_PUBLIC_KEY=pk-lf-...
# ROW
LANGFUSE_HOST=https://langfuse.caip.bmw.cloud
# CN
# LANGFUSE_HOST=https://langfuse.caip.bmwchina.cloud
LANGFUSE_ENV=production
LANGFUSE_DEBUG=true # Enable verbose trace logging (development only)
# Optional: disable Langfuse observability
# CAIP_LANGFUSE_OBSERVABILITY=false
SDK Auto-Generated Names
When using the CAIP Agents SDK, LLM calls are automatically named using the pattern caip.{framework}.{method}:
| Auto Name | Meaning |
|---|---|
caip.pydantic_ai.run | PydanticAI synchronous call |
caip.pydantic_ai.stream | PydanticAI streaming call |
caip.pydantic_ai.iter | PydanticAI iterative call |
caip.langchain.run | LangChain invoke call |
caip.langchain.stream | LangChain streaming call |
caip.tool.{name} | Tool invocation |
caip.api.{endpoint} | CAIP API call |
These names are set automatically — you do not need to configure them. Use the @observe naming conventions (above) for your own custom instrumentation.
Summary
Key Takeaways
- Name consistently — Use prefixes for categories
- Track users — Enable debugging and analytics
- Metadata wisely — Include context, exclude PII
- Handle errors — Capture context for debugging
- Flush on exit — Ensure all traces are sent
Next Steps
- Complete Examples — Ready-to-run code samples
- Getting Started — Set up Langfuse for your project
- Tracing Guide — Deep dive into trace instrumentation