← Guides
Setup7 min read
Tracking LangChain LLM Costs with CostLynx
Add a CostLynxCallbackHandler to any LangChain LLM to automatically track token usage after every response — no changes to your chain logic.
Install
pip
pip install costlynx langchain langchain-openaiCostLynxCallbackHandler
Implement BaseCallbackHandler and override on_llm_end. LangChain calls it after every LLM response with the token usage in llm_output.
Callback handler
from typing import Any, Optional
from uuid import UUID
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.outputs import LLMResult
from costlynx import CostLynx
class CostLynxCallbackHandler(BaseCallbackHandler):
def __init__(self, clx: CostLynx, feature: Optional[str] = None) -> None:
super().__init__()
self._clx = clx
self._feature = feature
def on_llm_end(
self,
response: LLMResult,
*,
run_id: UUID,
**kwargs: Any,
) -> None:
try:
llm_output = response.llm_output or {}
usage = llm_output.get("token_usage") or {}
model_name = llm_output.get("model_name", "gpt-4o")
input_tokens = usage.get("prompt_tokens", 0)
output_tokens = usage.get("completion_tokens", 0)
if input_tokens or output_tokens:
self._clx.track(
provider="openai",
model=model_name,
input_tokens=input_tokens,
output_tokens=output_tokens,
feature=self._feature,
request_id=str(run_id),
)
except Exception:
pass # never break LangChain executionAttach to any LangChain LLM
Usage
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from costlynx import CostLynx
clx = CostLynx(
ingestion_key=os.environ["COSTLYNX_INGESTION_KEY"],
default_project="langchain-app",
default_environment="prod",
)
llm = ChatOpenAI(
model="gpt-4o-mini",
callbacks=[CostLynxCallbackHandler(clx, feature="qa-chain")],
)
response = llm.invoke([HumanMessage(content="What is LLM cost optimisation?")])
print(response.content)Tip
Pass a different feature= per chain to get per-chain cost breakdowns in the CostLynx dashboard.
LCEL / chain composition
The callback is inherited by any chain that uses the LLM. In LCEL you can pass callbacks at the LLM constructor level (as above) or at invoke time:
LCEL invoke-time callback
from langchain_core.runnables import RunnableConfig
handler = CostLynxCallbackHandler(clx, feature="summariser")
chain = prompt | llm | output_parser
result = chain.invoke(
{"text": "Summarise this..."},
config=RunnableConfig(callbacks=[handler]),
)Failure behaviour
- The handler wraps all tracking in a try/except — it never raises or breaks your chain.
- Network errors and API failures are silently swallowed in production.
- Enable debug=True on the CostLynx client to print errors to stderr during development.