Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(llmobs): submit langchain embedding spans #9850

Merged
merged 78 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
e495578
Enable llmobs spans forwarding for embedding calls
yahya-mouman Jul 16, 2024
46b8d24
Add operations checklist to catch and log unknown operations
yahya-mouman Jul 16, 2024
ec37581
Add meta tags parser for embeddings
yahya-mouman Jul 16, 2024
c82559b
Rename parameter
yahya-mouman Jul 16, 2024
eab0a21
Update the embedding output to be number of embeddings generated
yahya-mouman Jul 16, 2024
824554d
add chunk size tag for embedd_documents calls
yahya-mouman Jul 18, 2024
c6ed269
re-use the function call for embeddings
yahya-mouman Jul 18, 2024
e2f42f2
order imports
yahya-mouman Jul 18, 2024
5a36731
return after operation check
yahya-mouman Jul 18, 2024
ca13fe8
Split parsing between workflow and embedding only cases
yahya-mouman Jul 18, 2024
f876bea
Update ddtrace/llmobs/_integrations/langchain.py
yahya-mouman Jul 19, 2024
a58ded9
Skipped checking for None as it's implied on the type checks
yahya-mouman Jul 19, 2024
f006ba0
reformatted input documents logic based on is_workflow state
yahya-mouman Jul 19, 2024
a89ff58
black format
yahya-mouman Jul 19, 2024
308276d
add release notes
yahya-mouman Jul 19, 2024
1f717e5
remove unused variable instantiation
yahya-mouman Jul 19, 2024
8457a17
add wrappers to embed query and documents
yahya-mouman Jul 19, 2024
6f508e8
add pytests for embed query and embed documents
yahya-mouman Jul 19, 2024
5c10196
black refactor
yahya-mouman Jul 19, 2024
07645c0
Update releasenotes/notes/feat-llmobs-submit-langchain-embedding-span…
yahya-mouman Jul 22, 2024
0ce94ff
remove chunk size
yahya-mouman Jul 22, 2024
c21a95e
Always output a documents list
yahya-mouman Jul 22, 2024
ebe80c2
Update tests and add langchain community tests
yahya-mouman Jul 22, 2024
f4ae74a
Add missing cassette for embedding documents
yahya-mouman Jul 22, 2024
4a43d8a
Fix testing cases
yahya-mouman Jul 22, 2024
bb0d168
get first span in trace test
yahya-mouman Jul 22, 2024
f5fcee0
lint checks fix
yahya-mouman Jul 23, 2024
2c931ae
add check for trace being a span
yahya-mouman Jul 23, 2024
b008a76
remove unnecessarily large cassette file
yahya-mouman Jul 23, 2024
c0e0bc4
remove unnecessarily large cassette file
yahya-mouman Jul 23, 2024
2ad9862
Use fake embedding in testing and fix count issue
yahya-mouman Jul 23, 2024
31b42e3
Switch to cassette use for the query test
yahya-mouman Jul 24, 2024
a0605e1
black format
yahya-mouman Jul 24, 2024
e7e0bb1
hatch lint fix
yahya-mouman Jul 24, 2024
512a60b
use openai embeddings
yahya-mouman Jul 24, 2024
b2465eb
use openai embeddings
yahya-mouman Jul 24, 2024
efe493f
switch from langchain_community to langchain_openai as it's a common …
yahya-mouman Jul 24, 2024
391eaa6
rename tests
yahya-mouman Jul 24, 2024
8a825d2
rename tests
yahya-mouman Jul 24, 2024
a571ec2
rename tests
yahya-mouman Jul 24, 2024
8f9a39e
add tests to check workflow vs embedding behaviour
yahya-mouman Jul 24, 2024
ae37dc9
Update tests/contrib/langchain/test_langchain_llmobs.py
yahya-mouman Jul 24, 2024
cc80f9f
black .
yahya-mouman Jul 24, 2024
52448cf
fix name of test
yahya-mouman Jul 24, 2024
a3b7e83
Update test_langchain_llmobs.py
yahya-mouman Jul 25, 2024
8b373a6
fi linting
yahya-mouman Jul 25, 2024
5293914
Test only workflow if openai is enabled
yahya-mouman Jul 25, 2024
35e0439
mcok get len safe embeddings
yahya-mouman Jul 25, 2024
1c7e14e
mock get len safe embeddings
yahya-mouman Jul 25, 2024
bed1231
mock get len safe embeddings
yahya-mouman Jul 25, 2024
84b1977
undo mock len safe embeddings
yahya-mouman Jul 25, 2024
6152655
correctly mock get len safe embeddings
yahya-mouman Jul 25, 2024
d4cf65a
Merge branch 'main' into yahya/add-langchain-embedding-support
yahya-mouman Jul 25, 2024
40e8550
Update tests/contrib/langchain/test_langchain_llmobs.py
yahya-mouman Jul 25, 2024
61e5b97
fix lint
yahya-mouman Jul 25, 2024
9e9bd2d
Merge branch 'main' into yahya/add-langchain-embedding-support
Yun-Kim Jul 25, 2024
812fdd5
rename tests
yahya-mouman Jul 25, 2024
8ae31a8
Merge remote-tracking branch 'origin/yahya/add-langchain-embedding-su…
yahya-mouman Jul 25, 2024
5d9efb8
fmt
Yun-Kim Jul 25, 2024
e32948b
tmp change - skip logic
Yun-Kim Jul 25, 2024
c9bd4c9
black
yahya-mouman Jul 26, 2024
ff66fb0
ruff check fix
yahya-mouman Jul 26, 2024
edffa8b
Fix version skipping
Yun-Kim Jul 26, 2024
eb55f38
Fix version skipping on langchain test files
Yun-Kim Jul 26, 2024
51290bf
WIP: comment out skipif by langchain version
Yun-Kim Jul 26, 2024
790f5ea
TMP WIP comment out sys version_info skipifs
Yun-Kim Jul 26, 2024
e5e5a9d
Undo langchain version gating
Yun-Kim Jul 27, 2024
af016f4
Revert langchain version gating change
Yun-Kim Jul 27, 2024
37db243
Revert tmp python version gating commenting
Yun-Kim Jul 27, 2024
23da90d
Merge branch 'main' into yahya/add-langchain-embedding-support
Yun-Kim Jul 30, 2024
c714c41
Regenerate cassette for embedding llmobs test
Yun-Kim Jul 30, 2024
1737d04
Update tests/contrib/langchain/test_langchain_llmobs.py
yahya-mouman Jul 31, 2024
ac6ae33
Merge branch 'main' into yahya/add-langchain-embedding-support
yahya-mouman Jul 31, 2024
b90842e
use 3.9 cassettes when available
yahya-mouman Jul 31, 2024
4858bb4
use input_tag_key
yahya-mouman Jul 31, 2024
1601844
remove agentless = true
yahya-mouman Jul 31, 2024
7f8cf92
Merge branch 'main' into yahya/add-langchain-embedding-support
yahya-mouman Jul 31, 2024
f99388d
Merge branch 'main' into yahya/add-langchain-embedding-support
Yun-Kim Jul 31, 2024
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
12 changes: 12 additions & 0 deletions ddtrace/contrib/langchain/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
"""
try:
input_texts = get_argument_value(args, kwargs, 0, "texts")
chunk_size = get_argument_value(args, kwargs, 1, "chunk_Size")
yahya-mouman marked this conversation as resolved.
Show resolved Hide resolved
except ArgumentError:
input_texts = get_argument_value(args, kwargs, 0, "text")

Expand All @@ -575,11 +576,13 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
span = integration.trace(
pin,
"%s.%s" % (instance.__module__, instance.__class__.__name__),
submit_to_llmobs=True,
interface_type="embedding",
provider=provider,
model=_extract_model_name(instance),
api_key=_extract_api_key(instance),
)
embeddings = None
try:
if isinstance(input_texts, str):
if integration.is_pc_sampled_span(span):
Expand All @@ -590,6 +593,7 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
for idx, text in enumerate(input_texts):
span.set_tag_str("langchain.request.inputs.%d.text" % idx, integration.trunc(text))
span.set_metric("langchain.request.input_count", len(input_texts))
span.set_tag_str("langchain.request.inputs.chunk_size", chunk_size)
yahya-mouman marked this conversation as resolved.
Show resolved Hide resolved
# langchain currently does not support token tracking for OpenAI embeddings:
# https://github.com/hwchase17/langchain/issues/945
embeddings = func(*args, **kwargs)
Expand All @@ -603,6 +607,14 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
integration.metric(span, "incr", "request.error", 1)
raise
finally:
if integration.is_pc_sampled_llmobs(span):
integration.llmobs_set_tags(
"embedding",
span,
input_texts=input_texts,
output_embedding=embeddings,
error=bool(span.error),
)
span.finish()
integration.metric(span, "dist", "request.duration", span.duration_ns)
if integration.is_pc_sampled_log(span):
Expand Down
69 changes: 63 additions & 6 deletions ddtrace/llmobs/_integrations/langchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ddtrace.constants import ERROR_TYPE
from ddtrace.internal.logger import get_logger
from ddtrace.llmobs import LLMObs
from ddtrace.llmobs._constants import INPUT_DOCUMENTS
from ddtrace.llmobs._constants import INPUT_MESSAGES
from ddtrace.llmobs._constants import INPUT_VALUE
from ddtrace.llmobs._constants import METADATA
Expand Down Expand Up @@ -42,21 +43,31 @@
"system": "system",
}

SUPPORTED_OPERATIONS = ["llm",
"chat",
"chain",
"embedding"
]


class LangChainIntegration(BaseLLMIntegration):
_integration_name = "langchain"

def llmobs_set_tags(
self,
operation: str, # oneof "llm","chat","chain"
span: Span,
inputs: Any,
response: Any = None,
error: bool = False,
self,
operation: str, # oneof "llm","chat","chain","embedding"
span: Span,
inputs: Any,
response: Any = None,
error: bool = False,
) -> None:
"""Sets meta tags and metrics for span events to be sent to LLMObs."""
if not self.llmobs_enabled:
return
if operation not in SUPPORTED_OPERATIONS:
log.warning("Unsupported operation : %s" % operation)
yahya-mouman marked this conversation as resolved.
Show resolved Hide resolved
return

model_provider = span.get_tag(PROVIDER)
self._llmobs_set_metadata(span, model_provider)

Expand All @@ -79,6 +90,8 @@ def llmobs_set_tags(
self._llmobs_set_meta_tags_from_chat_model(span, inputs, response, error, is_workflow=is_workflow)
elif operation == "chain":
self._llmobs_set_meta_tags_from_chain(span, inputs, response, error)
elif operation == "embedding":
self._llmobs_set_meta_tags_from_embedding(span, inputs, response, error, is_workflow=is_workflow)
span.set_tag_str(METRICS, json.dumps({}))

def _llmobs_set_metadata(self, span: Span, model_provider: Optional[str] = None) -> None:
Expand Down Expand Up @@ -194,6 +207,50 @@ def _llmobs_set_meta_tags_from_chain(
except TypeError:
log.warning("Failed to serialize chain output data to JSON")

def _llmobs_set_meta_tags_from_embedding(
self,
span: Span,
input_texts: Union[str, List[str]],
output_embedding: Union[List[float], List[List[float]], None],
error: bool = False,
is_workflow: bool = False,
) -> None:
span.set_tag_str(SPAN_KIND, "workflow" if is_workflow else "embedding")
span.set_tag_str(MODEL_NAME, span.get_tag(MODEL) or "")
span.set_tag_str(MODEL_PROVIDER, span.get_tag(PROVIDER) or "")

input_tag_key = INPUT_VALUE if is_workflow else INPUT_DOCUMENTS
output_tag_key = OUTPUT_VALUE

if (input_texts is not None
and (isinstance(input_texts, str) or all(isinstance(text, str) for text in input_texts))):
if is_workflow:
try:
formatted_inputs = self.format_io(input_texts)
if isinstance(input_texts, str):
yahya-mouman marked this conversation as resolved.
Show resolved Hide resolved
span.set_tag_str(input_tag_key, formatted_inputs)
else:
span.set_tag_str(input_tag_key, json.dumps(self.format_io(input_texts)))
except TypeError:
log.warning("Failed to serialize embedding input data to JSON")
else:
if isinstance(input_texts, str):
span.set_tag_str(input_tag_key, input_texts)
elif (isinstance(input_texts, list)
and all(isinstance(text, str) for text in input_texts) and not is_workflow):
json_documents_list = json.dumps(input_texts)
span.set_tag_str(input_tag_key, '{"documents":%s}' % json_documents_list)
yahya-mouman marked this conversation as resolved.
Show resolved Hide resolved

if error:
span.set_tag_str(output_tag_key, "")
elif output_embedding is not None:
if not isinstance(output_embedding[0], list):
output_embedding = [output_embedding]
embedding_dim = len(output_embedding[0])
span.set_tag_str(
output_tag_key, "[{} embedding(s) returned with size {}]".format(len(output_embedding), embedding_dim)
)

def _set_base_span_tags( # type: ignore[override]
self,
span: Span,
Expand Down
Loading