Skip to content

Commit b614655

Browse files
sabrennerYun-Kim
andauthored
feat(langgraph): submit spans from langgraph to APM and LLMObs (#11730)
This PR adds a simple integration and corresponding LLMObs plugin for the LangGraph framework. ### Enablement For both APM and LLMObs, this integration is disabled by default, and only enabled with `DD_TRACE_LANGGRAPH_ENABLED=true` or `patch(langgraph=True)`, along with `_DD_TRACE_LANGGRAPH_ENABLED=true`, due to its experimental nature. ### APM Tracing The APM integration adds basic tracing for LangGraph `Pregel` graph invocations, as well as the execution of each node/step in the graph (traced as `RunnableSeq`). ### LLM Observability Plugin The LLMObs plugin submits the traces to LLM Observability. #### Graph Invocation/Streaming Output Tagging Because we patch the `(a)stream` method for both streams and `(a)invoke`, since they rely on `(a)stream` under the hood, we are bound to the yields from the stream. The object shape and value depend on the `stream_mode` passed in to the stream function. For `invoke`, it defaults to `"values"`, which is perfect for our use case. However, if one were to call `stream` directly, and either pass in nothing or something like `stream_mode=["updates", "debug"]`, the output we would have for the graph span would appear as: ``` { "type": "task_result", "timestamp": "2025-01-03T14:45:26.087608+00:00", "step": "3", "payload": { "id": "399cfe0a-aefd-f67c-6909-fcea80ef508b", "name": "e", "error": "None", "result": [ "('a_list', ['e'])" ], "interrupts": [] } } ``` This is a known limitation for now, and a more thought-out solution for either adding on `"values"` to `stream_mode` and omitting their yields if it wasn't already present, or having some kind of clever joining, can be added in a later PR or by feature request. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) --------- Co-authored-by: Yun Kim <[email protected]> Co-authored-by: Yun Kim <[email protected]>
1 parent 6141812 commit b614655

23 files changed

+1314
-39
lines changed

.github/CODEOWNERS

+3
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ ddtrace/contrib/internal/google_generativeai @DataDog/ml-observabilit
145145
ddtrace/contrib/google_generativeai @DataDog/ml-observability
146146
ddtrace/contrib/internal/vertexai @DataDog/ml-observability
147147
ddtrace/contrib/vertexai @DataDog/ml-observability
148+
ddtrace/contrib/langgraph @DataDog/ml-observability
149+
ddtrace/contrib/internal/langgraph @DataDog/ml-observability
148150
tests/llmobs @DataDog/ml-observability
149151
tests/contrib/openai @DataDog/ml-observability
150152
tests/contrib/langchain @DataDog/ml-observability
@@ -154,6 +156,7 @@ tests/contrib/botocore/bedrock_cassettes @DataDog/ml-observabilit
154156
tests/contrib/anthropic @DataDog/ml-observability
155157
tests/contrib/google_generativeai @DataDog/ml-observability
156158
tests/contrib/vertexai @DataDog/ml-observability
159+
tests/contrib/langgraph @DataDog/ml-observability
157160
.gitlab/tests/llmobs.yml @DataDog/ml-observability
158161

159162
# Remote Config

.riot/requirements/115283d.txt

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#
2+
# This file is autogenerated by pip-compile with Python 3.12
3+
# by the following command:
4+
#
5+
# pip-compile --allow-unsafe --no-annotate .riot/requirements/115283d.in
6+
#
7+
anyio==4.7.0
8+
attrs==24.3.0
9+
certifi==2024.12.14
10+
charset-normalizer==3.4.1
11+
coverage[toml]==7.6.10
12+
h11==0.14.0
13+
httpcore==1.0.7
14+
httpx==0.28.1
15+
hypothesis==6.45.0
16+
idna==3.10
17+
iniconfig==2.0.0
18+
jsonpatch==1.33
19+
jsonpointer==3.0.0
20+
langchain-core==0.3.28
21+
langgraph==0.2.60
22+
langgraph-checkpoint==2.0.9
23+
langgraph-sdk==0.1.48
24+
langsmith==0.2.6
25+
mock==5.1.0
26+
msgpack==1.1.0
27+
opentracing==2.4.0
28+
orjson==3.10.12
29+
packaging==24.2
30+
pluggy==1.5.0
31+
pytest==8.3.4
32+
pytest-asyncio==0.25.0
33+
pytest-cov==6.0.0
34+
pytest-mock==3.14.0
35+
pyyaml==6.0.2
36+
requests==2.32.3
37+
requests-toolbelt==1.0.0
38+
sniffio==1.3.1
39+
sortedcontainers==2.4.0
40+
tenacity==9.0.0
41+
typing-extensions==4.12.2
42+
urllib3==2.3.0

.riot/requirements/18551a1.txt

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#
2+
# This file is autogenerated by pip-compile with Python 3.13
3+
# by the following command:
4+
#
5+
# pip-compile --allow-unsafe --no-annotate .riot/requirements/18551a1.in
6+
#
7+
annotated-types==0.7.0
8+
anyio==4.8.0
9+
attrs==24.3.0
10+
certifi==2024.12.14
11+
charset-normalizer==3.4.1
12+
coverage[toml]==7.6.10
13+
h11==0.14.0
14+
httpcore==1.0.7
15+
httpx==0.28.1
16+
hypothesis==6.45.0
17+
idna==3.10
18+
iniconfig==2.0.0
19+
jsonpatch==1.33
20+
jsonpointer==3.0.0
21+
langchain-core==0.3.29
22+
langgraph==0.2.61
23+
langgraph-checkpoint==2.0.9
24+
langgraph-sdk==0.1.48
25+
langsmith==0.2.10
26+
mock==5.1.0
27+
msgpack==1.1.0
28+
opentracing==2.4.0
29+
orjson==3.10.14
30+
packaging==24.2
31+
pluggy==1.5.0
32+
pydantic==2.10.5
33+
pydantic-core==2.27.2
34+
pytest==8.3.4
35+
pytest-asyncio==0.25.2
36+
pytest-cov==6.0.0
37+
pytest-mock==3.14.0
38+
pyyaml==6.0.2
39+
requests==2.32.3
40+
requests-toolbelt==1.0.0
41+
sniffio==1.3.1
42+
sortedcontainers==2.4.0
43+
tenacity==9.0.0
44+
typing-extensions==4.12.2
45+
urllib3==2.3.0

.riot/requirements/2bd0151.txt

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#
2+
# This file is autogenerated by pip-compile with Python 3.11
3+
# by the following command:
4+
#
5+
# pip-compile --allow-unsafe --no-annotate --resolver=backtracking .riot/requirements/2bd0151.in
6+
#
7+
annotated-types==0.7.0
8+
anyio==4.7.0
9+
attrs==24.3.0
10+
certifi==2024.12.14
11+
charset-normalizer==3.4.0
12+
coverage[toml]==7.6.9
13+
h11==0.14.0
14+
httpcore==1.0.7
15+
httpx==0.28.1
16+
hypothesis==6.45.0
17+
idna==3.10
18+
iniconfig==2.0.0
19+
jsonpatch==1.33
20+
jsonpointer==3.0.0
21+
langchain-core==0.3.28
22+
langgraph==0.2.60
23+
langgraph-checkpoint==2.0.9
24+
langgraph-sdk==0.1.48
25+
langsmith==0.2.4
26+
mock==5.1.0
27+
msgpack==1.1.0
28+
opentracing==2.4.0
29+
orjson==3.10.12
30+
packaging==24.2
31+
pluggy==1.5.0
32+
pydantic==2.10.4
33+
pydantic-core==2.27.2
34+
pytest==8.3.4
35+
pytest-asyncio==0.25.0
36+
pytest-cov==6.0.0
37+
pytest-mock==3.14.0
38+
pyyaml==6.0.2
39+
requests==2.32.3
40+
requests-toolbelt==1.0.0
41+
sniffio==1.3.1
42+
sortedcontainers==2.4.0
43+
tenacity==9.0.0
44+
typing-extensions==4.12.2
45+
urllib3==2.3.0

.riot/requirements/2e4fbd3.txt

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#
2+
# This file is autogenerated by pip-compile with Python 3.9
3+
# by the following command:
4+
#
5+
# pip-compile --allow-unsafe --no-annotate --resolver=backtracking .riot/requirements/2e4fbd3.in
6+
#
7+
annotated-types==0.7.0
8+
anyio==4.7.0
9+
attrs==24.3.0
10+
certifi==2024.12.14
11+
charset-normalizer==3.4.1
12+
coverage[toml]==7.6.10
13+
exceptiongroup==1.2.2
14+
h11==0.14.0
15+
httpcore==1.0.7
16+
httpx==0.28.1
17+
hypothesis==6.45.0
18+
idna==3.10
19+
iniconfig==2.0.0
20+
jsonpatch==1.33
21+
jsonpointer==3.0.0
22+
langchain-core==0.3.28
23+
langgraph==0.2.60
24+
langgraph-checkpoint==2.0.9
25+
langgraph-sdk==0.1.48
26+
langsmith==0.2.6
27+
mock==5.1.0
28+
msgpack==1.1.0
29+
opentracing==2.4.0
30+
orjson==3.10.12
31+
packaging==24.2
32+
pluggy==1.5.0
33+
pydantic==2.10.4
34+
pydantic-core==2.27.2
35+
pytest==8.3.4
36+
pytest-asyncio==0.25.0
37+
pytest-cov==6.0.0
38+
pytest-mock==3.14.0
39+
pyyaml==6.0.2
40+
requests==2.32.3
41+
requests-toolbelt==1.0.0
42+
sniffio==1.3.1
43+
sortedcontainers==2.4.0
44+
tenacity==9.0.0
45+
tomli==2.2.1
46+
typing-extensions==4.12.2
47+
urllib3==2.3.0

.riot/requirements/7dd4bcd.txt

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#
2+
# This file is autogenerated by pip-compile with Python 3.10
3+
# by the following command:
4+
#
5+
# pip-compile --allow-unsafe --no-annotate .riot/requirements/7dd4bcd.in
6+
#
7+
annotated-types==0.7.0
8+
anyio==4.7.0
9+
attrs==24.3.0
10+
certifi==2024.12.14
11+
charset-normalizer==3.4.1
12+
coverage[toml]==7.6.10
13+
exceptiongroup==1.2.2
14+
h11==0.14.0
15+
httpcore==1.0.7
16+
httpx==0.28.1
17+
hypothesis==6.45.0
18+
idna==3.10
19+
iniconfig==2.0.0
20+
jsonpatch==1.33
21+
jsonpointer==3.0.0
22+
langchain-core==0.3.28
23+
langgraph==0.2.60
24+
langgraph-checkpoint==2.0.9
25+
langgraph-sdk==0.1.48
26+
langsmith==0.2.6
27+
mock==5.1.0
28+
msgpack==1.1.0
29+
opentracing==2.4.0
30+
orjson==3.10.12
31+
packaging==24.2
32+
pluggy==1.5.0
33+
pydantic==2.10.4
34+
pydantic-core==2.27.2
35+
pytest==8.3.4
36+
pytest-asyncio==0.25.0
37+
pytest-cov==6.0.0
38+
pytest-mock==3.14.0
39+
pyyaml==6.0.2
40+
requests==2.32.3
41+
requests-toolbelt==1.0.0
42+
sniffio==1.3.1
43+
sortedcontainers==2.4.0
44+
tenacity==9.0.0
45+
tomli==2.2.1
46+
typing-extensions==4.12.2
47+
urllib3==2.3.0

ddtrace/_monkey.py

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"grpc": True,
5050
"httpx": True,
5151
"kafka": True,
52+
"langgraph": False,
5253
"mongoengine": True,
5354
"mysql": True,
5455
"mysqldb": True,
@@ -149,6 +150,10 @@
149150
"httplib": ("http.client",),
150151
"kafka": ("confluent_kafka",),
151152
"google_generativeai": ("google.generativeai",),
153+
"langgraph": (
154+
"langgraph",
155+
"langgraph.graph",
156+
),
152157
}
153158

154159

0 commit comments

Comments
 (0)