Skip to content

Commit 52d40ac

Browse files
authored
feat(crewai): support tracing crewAI (#12497)
[MLOB-2281] This PR adds tracing and LLMObs tracing support for the CrewAI library. [CrewAI](https://docs.crewai.com/concepts/crews) is a LLM agentic workflow framework which involves crews (top level concept) that accomplish a list of tasks using a set of agents (which have their own set of tools and LLMs to accomplish said tasks with). ### Tracing This integration patches (and traces) the following methods in CrewAI: - `Crew.kickoff()` which encapsulates the overall crew (workflow) execution. - `Task._execute_core()` which encapsulates the task execution (both sync and async) - `Task.execute_async()` does not get traced, but we do extract the active ddtrace/llmobs contexts to then propagate in an async thread's invocation of `Task._execute_core()` to ensure async tracing propagates contexts correctly. - `Agent.execute_task()` which encapsulates the agent's execution of a given task. - `CrewStructuredTool.invoke()` which encapsulates a tool invocation. - `Crew._get_context()` does not get traced, but we use this to set span links between task execution (llmobs-specific). ### Span Linking (private preview) **note:** Span linking only happens if llmobs is enabled and span linking feature flag is enabled for the customer. Span linking in CrewAI aims to infer and declare causal/input-output relationships between spans in a trace. This PR implements the following: - Input-input and output-output linking from a crew span to its first task span, and its last task span to the crew span. - output-input linking from a task span to the next task span. - input-input and output-output linking from a task span to its first agent span, and its last agent span to the task span. (Note: this is assuming that a task is accomplished only by one agent.) - input-input and output-output linking from a tool span to its first agent span (usually only if used in a hierarchical crew process with a managing LLM/agent delegating tasks to other agents) ### Next steps: - Add span linking at the bottom tool/llm level. However, this is a challenge as llm spans can come from external integrations (i.e. openai, anthropic, gemini) and we don't have the shared contextual information in these cases to link these spans. ## 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) [MLOB-2281]: https://datadoghq.atlassian.net/browse/MLOB-2281?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent 4d93f80 commit 52d40ac

36 files changed

+4701
-16
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ ddtrace/contrib/internal/vertexai @DataDog/ml-observabilit
153153
ddtrace/contrib/_vertexai.py @DataDog/ml-observability
154154
ddtrace/contrib/internal/langgraph @DataDog/ml-observability
155155
ddtrace/contrib/_langgraph.py @DataDog/ml-observability
156+
ddtrace/contrib/internal/crewai @DataDog/ml-observability
157+
ddtrace/contrib/_crewai.py @DataDog/ml-observability
156158
tests/llmobs @DataDog/ml-observability
157159
tests/contrib/openai @DataDog/ml-observability
158160
tests/contrib/langchain @DataDog/ml-observability
@@ -164,6 +166,7 @@ tests/contrib/anthropic @DataDog/ml-observabilit
164166
tests/contrib/google_generativeai @DataDog/ml-observability
165167
tests/contrib/vertexai @DataDog/ml-observability
166168
tests/contrib/langgraph @DataDog/ml-observability
169+
tests/contrib/crewai @DataDog/ml-observability
167170
.gitlab/tests/llmobs.yml @DataDog/ml-observability
168171

169172
# Remote Config

.riot/requirements/1ce4995.txt

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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/1ce4995.in
6+
#
7+
aiohappyeyeballs==2.6.1
8+
aiohttp==3.11.14
9+
aiosignal==1.3.2
10+
annotated-types==0.7.0
11+
anyio==4.9.0
12+
appdirs==1.4.4
13+
asgiref==3.8.1
14+
asttokens==3.0.0
15+
attrs==25.3.0
16+
auth0-python==4.8.1
17+
backoff==2.2.1
18+
bcrypt==4.3.0
19+
blinker==1.9.0
20+
build==1.2.2.post1
21+
cachetools==5.5.2
22+
certifi==2025.1.31
23+
cffi==1.17.1
24+
charset-normalizer==3.4.1
25+
chroma-hnswlib==0.7.6
26+
chromadb==0.6.3
27+
click==8.1.8
28+
coloredlogs==15.0.1
29+
coverage[toml]==7.7.0
30+
crewai==0.108.0
31+
cryptography==44.0.2
32+
decorator==5.2.1
33+
deprecated==1.2.18
34+
distro==1.9.0
35+
docstring-parser==0.16
36+
durationpy==0.9
37+
et-xmlfile==2.0.0
38+
executing==2.2.0
39+
fastapi==0.115.11
40+
filelock==3.18.0
41+
flatbuffers==25.2.10
42+
frozenlist==1.5.0
43+
fsspec==2025.3.0
44+
google-auth==2.38.0
45+
googleapis-common-protos==1.69.2
46+
grpcio==1.71.0
47+
h11==0.14.0
48+
httpcore==1.0.7
49+
httptools==0.6.4
50+
httpx==0.27.2
51+
huggingface-hub==0.29.3
52+
humanfriendly==10.0
53+
hypothesis==6.45.0
54+
idna==3.10
55+
importlib-metadata==8.6.1
56+
importlib-resources==6.5.2
57+
iniconfig==2.0.0
58+
instructor==1.7.7
59+
ipython==9.0.2
60+
ipython-pygments-lexers==1.1.1
61+
jedi==0.19.2
62+
jinja2==3.1.6
63+
jiter==0.8.2
64+
json-repair==0.39.1
65+
json5==0.10.0
66+
jsonpickle==4.0.2
67+
jsonref==1.1.0
68+
jsonschema==4.23.0
69+
jsonschema-specifications==2024.10.1
70+
kubernetes==32.0.1
71+
litellm==1.60.2
72+
markdown-it-py==3.0.0
73+
markupsafe==3.0.2
74+
matplotlib-inline==0.1.7
75+
mdurl==0.1.2
76+
mmh3==5.1.0
77+
mock==5.2.0
78+
monotonic==1.6
79+
mpmath==1.3.0
80+
multidict==6.2.0
81+
networkx==3.4.2
82+
numpy==2.2.4
83+
oauthlib==3.2.2
84+
onnxruntime==1.21.0
85+
openai==1.66.3
86+
openpyxl==3.1.5
87+
opentelemetry-api==1.31.0
88+
opentelemetry-exporter-otlp-proto-common==1.31.0
89+
opentelemetry-exporter-otlp-proto-grpc==1.31.0
90+
opentelemetry-exporter-otlp-proto-http==1.31.0
91+
opentelemetry-instrumentation==0.52b0
92+
opentelemetry-instrumentation-asgi==0.52b0
93+
opentelemetry-instrumentation-fastapi==0.52b0
94+
opentelemetry-proto==1.31.0
95+
opentelemetry-sdk==1.31.0
96+
opentelemetry-semantic-conventions==0.52b0
97+
opentelemetry-util-http==0.52b0
98+
opentracing==2.4.0
99+
orjson==3.10.15
100+
overrides==7.7.0
101+
packaging==24.2
102+
parso==0.8.4
103+
pdfminer-six==20231228
104+
pdfplumber==0.11.5
105+
pexpect==4.9.0
106+
pillow==11.1.0
107+
pluggy==1.5.0
108+
posthog==3.21.0
109+
prompt-toolkit==3.0.50
110+
propcache==0.3.0
111+
protobuf==5.29.3
112+
ptyprocess==0.7.0
113+
pure-eval==0.2.3
114+
pyasn1==0.6.1
115+
pyasn1-modules==0.4.1
116+
pycparser==2.22
117+
pydantic==2.10.6
118+
pydantic-core==2.27.2
119+
pygments==2.19.1
120+
pyjwt==2.10.1
121+
pypdfium2==4.30.1
122+
pypika==0.48.9
123+
pyproject-hooks==1.2.0
124+
pytest==8.3.5
125+
pytest-asyncio==0.25.3
126+
pytest-cov==6.0.0
127+
pytest-mock==3.14.0
128+
python-dateutil==2.9.0.post0
129+
python-dotenv==1.0.1
130+
pyvis==0.3.2
131+
pyyaml==6.0.2
132+
referencing==0.36.2
133+
regex==2024.11.6
134+
requests==2.32.3
135+
requests-oauthlib==2.0.0
136+
rich==13.9.4
137+
rpds-py==0.23.1
138+
rsa==4.9
139+
shellingham==1.5.4
140+
six==1.17.0
141+
sniffio==1.3.1
142+
sortedcontainers==2.4.0
143+
stack-data==0.6.3
144+
starlette==0.46.1
145+
sympy==1.13.3
146+
tenacity==9.0.0
147+
tiktoken==0.9.0
148+
tokenizers==0.21.1
149+
tomli==2.2.1
150+
tomli-w==1.2.0
151+
tqdm==4.67.1
152+
traitlets==5.14.3
153+
typer==0.15.2
154+
typing-extensions==4.12.2
155+
urllib3==2.3.0
156+
uv==0.6.7
157+
uvicorn[standard]==0.34.0
158+
uvloop==0.21.0
159+
vcrpy==7.0.0
160+
watchfiles==1.0.4
161+
wcwidth==0.2.13
162+
websocket-client==1.8.0
163+
websockets==15.0.1
164+
wrapt==1.17.2
165+
yarl==1.18.3
166+
zipp==3.21.0

.riot/requirements/8b7e1b6.txt

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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/8b7e1b6.in
6+
#
7+
aiohappyeyeballs==2.6.1
8+
aiohttp==3.11.14
9+
aiosignal==1.3.2
10+
annotated-types==0.7.0
11+
anyio==4.9.0
12+
appdirs==1.4.4
13+
asgiref==3.8.1
14+
asttokens==3.0.0
15+
attrs==25.3.0
16+
auth0-python==4.8.1
17+
backoff==2.2.1
18+
bcrypt==4.3.0
19+
blinker==1.9.0
20+
build==1.2.2.post1
21+
cachetools==5.5.2
22+
certifi==2025.1.31
23+
cffi==1.17.1
24+
charset-normalizer==3.4.1
25+
chroma-hnswlib==0.7.6
26+
chromadb==0.6.3
27+
click==8.1.8
28+
coloredlogs==15.0.1
29+
coverage[toml]==7.7.0
30+
crewai==0.108.0
31+
cryptography==44.0.2
32+
decorator==5.2.1
33+
deprecated==1.2.18
34+
distro==1.9.0
35+
docstring-parser==0.16
36+
durationpy==0.9
37+
et-xmlfile==2.0.0
38+
executing==2.2.0
39+
fastapi==0.115.11
40+
filelock==3.18.0
41+
flatbuffers==25.2.10
42+
frozenlist==1.5.0
43+
fsspec==2025.3.0
44+
google-auth==2.38.0
45+
googleapis-common-protos==1.69.2
46+
grpcio==1.71.0
47+
h11==0.14.0
48+
httpcore==1.0.7
49+
httptools==0.6.4
50+
httpx==0.27.2
51+
huggingface-hub==0.29.3
52+
humanfriendly==10.0
53+
hypothesis==6.45.0
54+
idna==3.10
55+
importlib-metadata==8.6.1
56+
importlib-resources==6.5.2
57+
iniconfig==2.0.0
58+
instructor==1.7.7
59+
ipython==9.0.2
60+
ipython-pygments-lexers==1.1.1
61+
jedi==0.19.2
62+
jinja2==3.1.6
63+
jiter==0.8.2
64+
json-repair==0.39.1
65+
json5==0.10.0
66+
jsonpickle==4.0.2
67+
jsonref==1.1.0
68+
jsonschema==4.23.0
69+
jsonschema-specifications==2024.10.1
70+
kubernetes==32.0.1
71+
litellm==1.60.2
72+
markdown-it-py==3.0.0
73+
markupsafe==3.0.2
74+
matplotlib-inline==0.1.7
75+
mdurl==0.1.2
76+
mmh3==5.1.0
77+
mock==5.2.0
78+
monotonic==1.6
79+
mpmath==1.3.0
80+
multidict==6.2.0
81+
networkx==3.4.2
82+
numpy==2.2.4
83+
oauthlib==3.2.2
84+
onnxruntime==1.21.0
85+
openai==1.66.3
86+
openpyxl==3.1.5
87+
opentelemetry-api==1.31.0
88+
opentelemetry-exporter-otlp-proto-common==1.31.0
89+
opentelemetry-exporter-otlp-proto-grpc==1.31.0
90+
opentelemetry-exporter-otlp-proto-http==1.31.0
91+
opentelemetry-instrumentation==0.52b0
92+
opentelemetry-instrumentation-asgi==0.52b0
93+
opentelemetry-instrumentation-fastapi==0.52b0
94+
opentelemetry-proto==1.31.0
95+
opentelemetry-sdk==1.31.0
96+
opentelemetry-semantic-conventions==0.52b0
97+
opentelemetry-util-http==0.52b0
98+
opentracing==2.4.0
99+
orjson==3.10.15
100+
overrides==7.7.0
101+
packaging==24.2
102+
parso==0.8.4
103+
pdfminer-six==20231228
104+
pdfplumber==0.11.5
105+
pexpect==4.9.0
106+
pillow==11.1.0
107+
pluggy==1.5.0
108+
posthog==3.21.0
109+
prompt-toolkit==3.0.50
110+
propcache==0.3.0
111+
protobuf==5.29.3
112+
ptyprocess==0.7.0
113+
pure-eval==0.2.3
114+
pyasn1==0.6.1
115+
pyasn1-modules==0.4.1
116+
pycparser==2.22
117+
pydantic==2.10.6
118+
pydantic-core==2.27.2
119+
pygments==2.19.1
120+
pyjwt==2.10.1
121+
pypdfium2==4.30.1
122+
pypika==0.48.9
123+
pyproject-hooks==1.2.0
124+
pytest==8.3.5
125+
pytest-asyncio==0.25.3
126+
pytest-cov==6.0.0
127+
pytest-mock==3.14.0
128+
python-dateutil==2.9.0.post0
129+
python-dotenv==1.0.1
130+
pyvis==0.3.2
131+
pyyaml==6.0.2
132+
referencing==0.36.2
133+
regex==2024.11.6
134+
requests==2.32.3
135+
requests-oauthlib==2.0.0
136+
rich==13.9.4
137+
rpds-py==0.23.1
138+
rsa==4.9
139+
shellingham==1.5.4
140+
six==1.17.0
141+
sniffio==1.3.1
142+
sortedcontainers==2.4.0
143+
stack-data==0.6.3
144+
starlette==0.46.1
145+
sympy==1.13.3
146+
tenacity==9.0.0
147+
tiktoken==0.9.0
148+
tokenizers==0.21.1
149+
tomli==2.2.1
150+
tomli-w==1.2.0
151+
tqdm==4.67.1
152+
traitlets==5.14.3
153+
typer==0.15.2
154+
typing-extensions==4.12.2
155+
urllib3==2.3.0
156+
uv==0.6.7
157+
uvicorn[standard]==0.34.0
158+
uvloop==0.21.0
159+
vcrpy==7.0.0
160+
watchfiles==1.0.4
161+
wcwidth==0.2.13
162+
websocket-client==1.8.0
163+
websockets==15.0.1
164+
wrapt==1.17.2
165+
yarl==1.18.3
166+
zipp==3.21.0

0 commit comments

Comments
 (0)