Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,44 @@ jobs:
- name: Run tests
run: uvx --with tox-uv tox -e py313-test-instrumentation-claude-agent-sdk-latest -- -ra

py312-test-instrumentation-langchain_ubuntu-latest:
name: instrumentation-langchain 3.12 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python 3.12
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"

- name: Set up uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0

- name: Run tests
run: uvx --with tox-uv tox -e py312-test-instrumentation-langchain -- -ra

py313-test-instrumentation-langchain_ubuntu-latest:
name: instrumentation-langchain 3.13 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python 3.13
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"

- name: Set up uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0

- name: Run tests
run: uvx --with tox-uv tox -e py313-test-instrumentation-langchain -- -ra

py312-test-instrumentation-langchain-conformance_ubuntu-latest:
name: instrumentation-langchain-conformance 3.12 Ubuntu
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add LangChain workflow and agent span support
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

"""
ReAct agent example built with LangGraph.

Uses LangGraph's prebuilt create_react_agent with simple calculator tools.
OpenTelemetry LangChain instrumentation traces the LLM calls made by the agent.
"""

from uuid import uuid4

from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

from opentelemetry import _logs, metrics, trace
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
OTLPLogExporter,
)
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
OTLPMetricExporter,
)
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
OTLPSpanExporter,
)
from opentelemetry.instrumentation.langchain import LangChainInstrumentor
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# Configure tracing
trace.set_tracer_provider(TracerProvider())
span_processor = BatchSpanProcessor(OTLPSpanExporter())
trace.get_tracer_provider().add_span_processor(span_processor)

# Configure logging
_logs.set_logger_provider(LoggerProvider())
_logs.get_logger_provider().add_log_record_processor(
BatchLogRecordProcessor(OTLPLogExporter())
)

# Configure metrics
metrics.set_meter_provider(
MeterProvider(
metric_readers=[
PeriodicExportingMetricReader(
OTLPMetricExporter(),
),
]
)
)


@tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers together."""
return a * b


@tool
def add(a: float, b: float) -> float:
"""Add two numbers together."""
return a + b


def main():
LangChainInstrumentor().instrument()

llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0.1,
max_tokens=100,
top_p=0.9,
seed=100,
)

session_id = str(uuid4())
agent = create_react_agent(llm, tools=[multiply, add]).with_config(
{
"metadata": {
"agent_name": "coordinator",
"session_id": session_id,
},
}
)

result = agent.invoke(
{"messages": [HumanMessage(content="What is (3 * 4) + 7?")]}
)

print("Agent output:")
for msg in result["messages"]:
print(f" {type(msg).__name__}: {msg.content}")

LangChainInstrumentor().uninstrument()


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
langchain==0.3.21
langchain_openai
langgraph
opentelemetry-sdk>=1.42.0
opentelemetry-exporter-otlp-proto-grpc>=1.42.0
Comment thread
wrisa marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

"""
Single-node agent example built with StateGraph.

A single ReAct agent answers arithmetic questions using calculator tools.
OpenTelemetry LangChain instrumentation traces all LLM calls.
"""

from uuid import uuid4

from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph.prebuilt import create_react_agent

from opentelemetry import _logs, metrics, trace
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
OTLPLogExporter,
)
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
OTLPMetricExporter,
)
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
OTLPSpanExporter,
)
from opentelemetry.instrumentation.langchain import LangChainInstrumentor
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# Configure tracing
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(OTLPSpanExporter())
)

# Configure logging
_logs.set_logger_provider(LoggerProvider())
_logs.get_logger_provider().add_log_record_processor(
BatchLogRecordProcessor(OTLPLogExporter())
)

# Configure metrics
metrics.set_meter_provider(
MeterProvider(
metric_readers=[PeriodicExportingMetricReader(OTLPMetricExporter())]
)
)


# --- Tools ----------------------------------------------------------------


@tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers."""
return a * b


@tool
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b


# --- Graph ----------------------------------------------------------------


def build_single_node_graph(llm: ChatOpenAI):
session_id = str(uuid4())

agent = create_react_agent(
llm, tools=[multiply, add], name="math_agent"
).with_config(
{
"metadata": {
"agent_name": "math_agent",
"session_id": session_id,
},
}
)

def run_agent(state: MessagesState) -> dict:
result = agent.invoke({"messages": state["messages"]})
return {"messages": result["messages"]}

builder = StateGraph(MessagesState)
builder.add_node("math_agent", run_agent)
builder.add_edge(START, "math_agent")
builder.add_edge("math_agent", END)

return builder.compile()


def main():
LangChainInstrumentor().instrument()

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.1, seed=100)
graph = build_single_node_graph(llm)

questions = [
"What is 12 multiplied by 7?",
"What is 15 plus 27?",
]

for question in questions:
print(f"\nQuestion: {question}")
result = graph.invoke({"messages": [HumanMessage(content=question)]})
last = result["messages"][-1]
print(f" Answer: {last.content}")

LangChainInstrumentor().uninstrument()


if __name__ == "__main__":
main()
Loading