Skip to main content
SimpleLLMFunc includes Langfuse integration for observing model calls, tool calls, and multi-step execution traces. You can use it as a production observability layer for inputs, outputs, token usage, and call structure.

Capabilities Overview

LLM Generation Tracking

Record input messages, output content, model parameters, and token usage.

Tool Call Observation

Track tool parameters, execution results, duration, and call hierarchy.

Nested Trace Support

Observe multi-layer call chains and follow-up generations.

Streaming Compatibility

Works with both streaming and non-streaming model responses.

Installation and Configuration

1

Install Langfuse dependencies

Langfuse is already included in the project dependencies. In an existing environment, you can also install it directly:
poetry install
2

Get project credentials

  1. Visit Langfuse
  2. Create a project
  3. Copy the public key and secret key
3

Set environment variables

export LANGFUSE_PUBLIC_KEY="your_public_key"
export LANGFUSE_SECRET_KEY="your_secret_key"
export LANGFUSE_BASE_URL="https://cloud.langfuse.com"
export LANGFUSE_EXPORT_ALL_SPANS="true"
export LANGFUSE_ENABLED="true"
4

Start using it

SimpleLLMFunc reads the environment variables automatically. You do not need to initialize the Langfuse client manually for basic usage.
from SimpleLLMFunc import llm_function

llm = ...

@llm_function(llm_interface=llm)
async def my_function(text: str) -> str:
    """Describe the function behavior."""
    pass

result = await my_function("test")
The current implementation does not automatically skip observability calls based on LANGFUSE_ENABLED. If you need environment-based enable/disable behavior, gate that logic explicitly at the application layer.

Configuration Methods

export LANGFUSE_PUBLIC_KEY="your_public_key"
export LANGFUSE_SECRET_KEY="your_secret_key"
export LANGFUSE_BASE_URL="https://cloud.langfuse.com"
export LANGFUSE_ENABLED="true"
If you want direct access to configuration and the Langfuse client:
from SimpleLLMFunc.observability import get_langfuse_client, langfuse_config

config = langfuse_config
print(f"Langfuse enabled: {config.LANGFUSE_ENABLED}")

client = get_langfuse_client()
if client:
    pass

Usage Examples

import asyncio

from SimpleLLMFunc import OpenAICompatible, llm_function

llm = OpenAICompatible.load_from_json_file("provider.json")["openai"]["gpt-3.5-turbo"]

@llm_function(llm_interface=llm)
async def analyze_text(text: str) -> str:
    """Analyze text and provide a concise summary."""
    pass

async def main():
    result = await analyze_text("This is a piece of text that needs analysis.")
    print(result)

asyncio.run(main())
from SimpleLLMFunc import llm_function, tool

@tool(name="calculate", description="Evaluate a mathematical expression")
async def calculate(expression: str) -> dict:
    result = eval(expression)
    return {"expression": expression, "result": result}

@llm_function(llm_interface=llm, toolkit=[calculate], max_tool_calls=3)
async def math_assistant(question: str) -> str:
    """Answer math questions and call tools when needed."""
    pass

result = await math_assistant("Calculate 15 * 8 + 32")
from SimpleLLMFunc import llm_chat

@llm_chat(llm_interface=llm, toolkit=[calculate], max_tool_calls=2)
async def chat_bot(message: str, history: list = None):
    """A chat assistant that can answer questions and perform calculations."""
    pass

history = []
async for response, updated_history in chat_bot("Please help me solve some math problems", history):
    if response.strip():
        print(response)
    history = updated_history

Trace Structure

Each LLM call creates a generation trace that typically includes:
  • input messages
  • output content and any tool calls
  • model name and parameters
  • token usage and cost data
  • streaming mode and related metadata
Each tool invocation records:
  • call parameters
  • execution result
  • tool call ID, duration, and related metadata
Function Call (Span)
├── Initial Generation
│   ├── Input: Messages
│   ├── Output: Response + Tool Calls
│   └── Usage: Token counts
├── Tool Call 1 (Tool)
│   ├── Input: Parameters
│   └── Output: Result
├── Tool Call 2 (Tool)
│   ├── Input: Parameters
│   └── Output: Result
└── Follow-up Generation
    ├── Input: Updated Messages
    ├── Output: Final Response
    └── Usage: Token counts

Configuration Options

Environment variables

VariableDescriptionDefaultRequired
LANGFUSE_PUBLIC_KEYLangfuse public key-Yes
LANGFUSE_SECRET_KEYLangfuse secret key-Yes
LANGFUSE_BASE_URLLangfuse server URLhttps://cloud.langfuse.comNo
LANGFUSE_EXPORT_ALL_SPANSExport all OpenTelemetry spanstrueNo
LANGFUSE_ENABLEDEnable observabilitytrueNo

Langfuse v4 notes

  • Langfuse v4 filters non-LLM OpenTelemetry spans by default; the framework keeps the older “export all spans” behavior unless you disable it explicitly.
  • Langfuse v4 also normalizes metadata values to strings and limits their length. The framework already stringifies metadata to match that behavior.

Best Practices

# Development
export LANGFUSE_ENABLED="false"

# Production
export LANGFUSE_ENABLED="true"
export LANGFUSE_PUBLIC_KEY="prod_public_key"
export LANGFUSE_SECRET_KEY="prod_secret_key"
Monitor application logs and Langfuse connectivity, especially in high-volume or long-running workflows.
  • Review what data is sent to Langfuse
  • Avoid uploading sensitive content without a clear policy
  • Tune provider timeouts and observability overhead for production

Troubleshooting

Check whether the required environment variables are set and whether the Langfuse package is installed.
Verify network access, credentials, and LANGFUSE_BASE_URL.
Confirm you are looking at the correct project and allow a short delay for ingestion.