Lesson 5 / 31
Generations: Recording Model Calls
Record a model call with its model name, parameters, messages, token usage and cost.
By Rahul Agarwal · 15 years in web development
The special span for a model call
Most steps in a trace are generic spans, but a call to a language model deserves a richer record. Langfuse names this observation type a generation; LangSmith uses a run with run_type="llm". A generation stores the model identifier, model parameters (temperature, max tokens, top_p), the input as a list of chat messages, the output message, and usage: input tokens, output tokens and sometimes cached or reasoning tokens. From usage and a price table the tool computes cost. For streaming calls a generation may also record when the first token arrived, which gives you time to first token. Why separate it from a plain span? Because analytics depend on it: cost per user, tokens per model and latency per model all aggregate over generations only. If you log a model call as a plain span with the text in a string, the tool cannot add up tokens or money.
A generation record in Langfuse (manual style)
Uses the Langfuse Python SDK (v3 style). Replace the placeholder reply with your real model call; the drop-in OpenAI wrapper shown later fills these fields automatically.
from langfuse import get_client
langfuse = get_client() # reads LANGFUSE_PUBLIC_KEY / SECRET_KEY / HOST from env
with langfuse.start_as_current_generation(
name="draft-reply",
model="my-chat-model",
model_parameters={"temperature": 0.2},
input=[{"role": "user", "content": "Namaste! Where is my order?"}],
) as gen:
reply = "Your order is out for delivery." # call your model here
gen.update(output=reply, usage_details={"input": 14, "output": 8})
langfuse.flush()Let the tool count tokens when it can
Prefer the usage numbers returned by the provider's API over your own estimate; tokenizers differ by model and your count will drift. If you self-host a model that returns no usage, record your best estimate and label it as such in metadata.
Quick check: Why should model calls be recorded as generations (or llm runs) instead of plain spans?
- Plain spans cannot have inputs or outputs
- Only generations can be nested inside a trace
- Generations are stored for free while spans are billed
- Token usage and cost analytics aggregate over model-call records with model and usage fields
Answer
Token usage and cost analytics aggregate over model-call records with model and usage fields — Cost and token dashboards rely on the model and usage fields that the generation type carries. Plain spans still support input and output, but lack those semantics.