Skip to main content
Use uselemma-tracing with LangChain to get a top-level run trace from agent plus child spans for every LangChain step — chains, LLM calls, tools, retrievers, and more — via OpenInference’s LangChain instrumentor.

How It Works

register_otel() sets up the OTel transport. openinference-instrumentation-langchain patches LangChain’s callback system to emit a child span for every step in the chain. These spans nest under the agent root span.

Getting Started

Install

pip install uselemma-tracing langchain langchain-openai openinference-instrumentation-langchain

Register at startup

from uselemma_tracing import register_otel
from openinference.instrumentation.langchain import LangChainInstrumentation

register_otel()
LangChainInstrumentation().instrument()  # patches LangChain callbacks
Set LEMMA_API_KEY and LEMMA_PROJECT_ID environment variables. Find them in your Lemma project settings.

Examples

Chain tracing

from uselemma_tracing import agent, TraceContext
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("Answer briefly: {question}")
chain = prompt | llm | StrOutputParser()

async def run_agent(question: str, ctx: TraceContext) -> str:
    result = await chain.ainvoke({"question": question})
    return result
    return result

qaAgent = agent("qa-agent", run_agent)

res = await qaAgent("What is the speed of light?")
print(res.result)
print(res.run_id)

ReAct agent with tools

from uselemma_tracing import agent, TraceContext
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import tool as lc_tool
from langchain import hub

llm = ChatOpenAI(model="gpt-4o-mini")

@lc_tool
def lookup_order(order_id: str) -> str:
    """Look up an order status by order ID."""
    return f"Order {order_id} is shipped and arrives 2026-04-10."

prompt = hub.pull("hwchase17/react")
react_agent = create_react_agent(llm, [lookup_order], prompt)
executor = AgentExecutor(agent=react_agent, tools=[lookup_order], verbose=False)

async def run_agent(user_message: str, ctx: TraceContext) -> str:
    output = await executor.ainvoke({"input": user_message})
    result = output["output"]
    return result
    return result

reactAgent = agent("react-agent", run_agent)

res = await reactAgent("What is the status of order ORD-456?")
print(res.result)
print(res.run_id)

RAG pipeline

from uselemma_tracing import agent, retrieval, TraceContext
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

embeddings = OpenAIEmbeddings()
vectorstore = FAISS.load_local("my-index", embeddings)

@retrieval("vector-search")
async def retrieve_docs(query: str) -> list:
    docs = await vectorstore.asimilarity_search(query, k=3)
    return [doc.page_content for doc in docs]

llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template(
    "Answer using the context below.\nContext: {context}\nQuestion: {question}"
)
chain = prompt | llm | StrOutputParser()

async def run_agent(question: str, ctx: TraceContext) -> str:
    docs = await retrieve_docs(question)  # retrieval.vector-search span
    context = "\n".join(docs)
    result = await chain.ainvoke({"context": context, "question": question})
    return result
    return result

ragAgent = agent("rag-agent", run_agent)

res = await ragAgent("What does the refund policy say?")

What You’ll See in Lemma

SpanSourceContains
ai.agent.runagentFull run input, output, timing, run ID
LangChain spans (chain, llm, tool, etc.)OpenInferencePer-step prompts, completions, inputs, outputs
retrieval.vector-search@retrieval decoratorRetrieval query and returned documents

Next Steps