Radicas Docs
Framework integrationsAgent frameworks

LangChain / LangGraph

Connect LangChain or LangGraph agents to Radicas via the OpenInference instrumentor — the first shim-required path.

Status: experimental — the strategy and the normalization maps are implemented, but the bench deep-dive (fixture capture per docs/add-a-framework.md) has not validated them end-to-end yet. The registry card openinference-langchain is a research-drafted stub.

One page covers both: classic LangChain AgentExecutor is legacy (LangChain itself points to LangGraph for agents) and both emit under the same instrumentation scope, so for Radicas they are one source.

Install

pip install "radicas[langchain]"   # = radicas + openinference-instrumentation-langchain

Use

import radicas

radicas.init(service="pricing-agent", feature="flight-pricing")
# instrument="auto" detects langchain/langgraph and activates
# LangChainInstrumentor().instrument() — or select explicitly:
# radicas.init(instrument=["langchain"])   # alias for openinference-langchain

from langgraph.prebuilt import create_react_agent
agent = create_react_agent(model, tools)
agent.invoke({"messages": [("user", prompt)]})
radicas.shutdown()

If the framework is installed but the instrumentor extra is not, explicit selection raises MissingInstrumentorError naming radicas[langchain]; "auto" skips with a warning.

What it emits

  • Scope name: openinference.instrumentation.langchain — from the OpenInference package (covers LangGraph).
  • Namespace: llm.* / openinference.* — NOT canonical gen_ai.*; hence the shim.
  • Span names: chain/llm/tool spans named after LangChain components (e.g. ChatAnthropic), not the canonical names — span-name mapping is pending fixture (the card's span_name_map is intentionally empty until verified).
  • Coverage (registry card, drafted from research — to confirm against a fixture):
FieldCovered
gen_ai.request.modelyes — mapped from llm.model_name
gen_ai.usage.input_tokensyes — mapped from llm.token_count.prompt
gen_ai.usage.output_tokensyes — mapped from llm.token_count.completion
reasoning tokenspartial (provider-dependent; to verify)
cache tokensexpected, pending fixture
finish reasonspartial
provider (gen_ai.system)partial
tool treepartial — chain/tool spans exist but not under the canonical names
contentpartial

Shim behavior

  • Client-side adapter: yes. The SDK's NormalizingSpanExporter applies the card's attribute maps at export (llm.model_namegen_ai.request.model, token counts) and stamps radicas.source_framework=openinference-langchain. Originals are kept.
  • Server-side OTTL: yes. The same maps run at Radicas ingest for non-SDK senders — SDK users simply arrive already-canonical.

Known limitations

  • Not fixture-verified: token/span coverage above is the card's honest draft, not evidence.
  • The alternative Traceloop route (opentelemetry-instrumentation-langchain, near-gen_ai.* with older names) is still under evaluation; the deep-dive will pick the official route.
  • No canonical invoke_agent root until the span-name map is confirmed. The default feature is only stamped on invoke_agent* roots, so it will not appear on these spans yet; a scoped with radicas.feature(...) block DOES stamp every span inside it and works today.

Verify it works

SELECT model, input_tokens, output_tokens, estimated_cost_usd
  FROM otel.llm_call ORDER BY ts DESC LIMIT 5;
-- which adapter fired:
SELECT DISTINCT SpanAttributes['radicas.source_framework'] FROM otel_traces
 WHERE ScopeName = 'openinference.instrumentation.langchain';

Bench example (agent runnable, telemetry pending): agents/langchain-langgraph/python in radicas-integrations.

On this page