arize-phoenix 0.0.39__py3-none-any.whl → 0.0.41__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

phoenix/trace/fixtures.py CHANGED
@@ -19,7 +19,7 @@ llama_index_rag_fixture = TracesFixture(
19
19
  file_name="llama_index_rag_v6.jsonl",
20
20
  )
21
21
 
22
- llama_index_calculator_agent = TracesFixture(
22
+ llama_index_calculator_agent_fixture = TracesFixture(
23
23
  name="llama_index_calculator_agent",
24
24
  description="Traces from running the llama_index with calculator tools.",
25
25
  file_name="llama_index_calculator_agent_v2.jsonl",
@@ -43,6 +43,12 @@ langchain_titanic_csv_agent_evaluator_fixture = TracesFixture(
43
43
  file_name="lc_titanic.jsonl",
44
44
  )
45
45
 
46
+ langchain_qa_with_sources_fixture = TracesFixture(
47
+ name="langchain_qa_with_sources",
48
+ description="LangChain QA with sources on financial data",
49
+ file_name="langchain_qa_with_sources_chain.jsonl",
50
+ )
51
+
46
52
  random_fixture = TracesFixture(
47
53
  name="random",
48
54
  description="Randomly generated traces",
@@ -55,7 +61,8 @@ TRACES_FIXTURES: List[TracesFixture] = [
55
61
  langchain_rag_stuff_document_chain_fixture,
56
62
  langchain_titanic_csv_agent_evaluator_fixture,
57
63
  random_fixture,
58
- llama_index_calculator_agent,
64
+ langchain_qa_with_sources_fixture,
65
+ llama_index_calculator_agent_fixture,
59
66
  ]
60
67
 
61
68
  NAME_TO_TRACES_FIXTURE = {fixture.name: fixture for fixture in TRACES_FIXTURES}
@@ -1,3 +1,4 @@
1
+ from .instrumentor import LangChainInstrumentor
1
2
  from .tracer import OpenInferenceTracer
2
3
 
3
- __all__ = ["OpenInferenceTracer"]
4
+ __all__ = ["OpenInferenceTracer", "LangChainInstrumentor"]
@@ -0,0 +1,37 @@
1
+ from typing import Any, Optional
2
+
3
+ from .tracer import OpenInferenceTracer
4
+
5
+
6
+ class LangChainInstrumentor:
7
+ """
8
+ Instruments the OpenInferenceTracer for LangChain automatically by patching the
9
+ BaseCallbackManager in LangChain.
10
+ """
11
+
12
+ def __init__(self, tracer: Optional[OpenInferenceTracer] = None) -> None:
13
+ self._tracer = tracer if tracer is not None else OpenInferenceTracer()
14
+
15
+ def instrument(self) -> None:
16
+ try:
17
+ from langchain.callbacks.base import BaseCallbackManager
18
+ except ImportError:
19
+ # Raise a cleaner error if LangChain is not installed
20
+ raise ImportError(
21
+ "LangChain is not installed. Please install LangChain first to use the instrumentor"
22
+ )
23
+
24
+ source_init = BaseCallbackManager.__init__
25
+
26
+ # Keep track of the source init so we can tell if the patching occurred
27
+ self._source_callback_manager_init = source_init
28
+
29
+ tracer = self._tracer
30
+
31
+ # Patch the init method of the BaseCallbackManager to add the tracer
32
+ # to all callback managers
33
+ def patched_init(self: BaseCallbackManager, *args: Any, **kwargs: Any) -> None:
34
+ source_init(self, *args, **kwargs)
35
+ self.add_handler(tracer, True)
36
+
37
+ BaseCallbackManager.__init__ = patched_init # type: ignore
@@ -106,14 +106,6 @@ def payload_to_semantic_attributes(
106
106
  if event_type in (CBEventType.NODE_PARSING, CBEventType.CHUNKING):
107
107
  # TODO(maybe): handle these events
108
108
  return attributes
109
- if event_type == CBEventType.TEMPLATING:
110
- if template := payload.get(EventPayload.TEMPLATE):
111
- attributes[LLM_PROMPT_TEMPLATE] = template
112
- if template_vars := payload.get(EventPayload.TEMPLATE_VARS):
113
- attributes[LLM_PROMPT_TEMPLATE_VARIABLES] = template_vars
114
- # TODO(maybe): other keys in the same payload
115
- # EventPayload.SYSTEM_PROMPT
116
- # EventPayload.QUERY_WRAPPER_PROMPT
117
109
  if EventPayload.CHUNKS in payload and EventPayload.EMBEDDINGS in payload:
118
110
  attributes[EMBEDDING_EMBEDDINGS] = [
119
111
  {EMBEDDING_TEXT: text, EMBEDDING_VECTOR: vector}
@@ -151,8 +143,6 @@ def payload_to_semantic_attributes(
151
143
  attributes.update(_get_output_messages(raw))
152
144
  if (usage := getattr(raw, "usage", None)) is not None:
153
145
  attributes.update(_get_token_counts(usage))
154
- if EventPayload.TEMPLATE in payload:
155
- ...
156
146
  if event_type is CBEventType.RERANKING:
157
147
  ... # TODO
158
148
  # if EventPayload.TOP_K in payload:
@@ -304,6 +294,20 @@ def _add_spans_to_tracer(
304
294
  parent_span_id, event_id = parent_child_id_stack.pop()
305
295
  event_data = event_id_to_event_data[event_id]
306
296
  event_type = event_data["event_type"]
297
+ attributes = event_data["attributes"]
298
+ if event_type is CBEventType.LLM:
299
+ while parent_child_id_stack:
300
+ preceding_event_parent_span_id, preceding_event_id = parent_child_id_stack[-1]
301
+ if preceding_event_parent_span_id != parent_span_id:
302
+ break
303
+ preceding_event_data = event_id_to_event_data[preceding_event_id]
304
+ if preceding_event_data["event_type"] is not CBEventType.TEMPLATING:
305
+ break
306
+ parent_child_id_stack.pop()
307
+ if payload := preceding_event_data["start_event"].payload:
308
+ # Add template attributes to the LLM span to which they belong.
309
+ attributes.update(_template_attributes(payload))
310
+
307
311
  start_event = event_data["start_event"]
308
312
  start_time = _timestamp_to_tz_aware_datetime(start_event.time)
309
313
  if event_type is CBEventType.EXCEPTION:
@@ -337,7 +341,7 @@ def _add_spans_to_tracer(
337
341
  status_code=SpanStatusCode.ERROR if span_exceptions else SpanStatusCode.OK,
338
342
  status_message="",
339
343
  parent_id=parent_span_id,
340
- attributes=event_data["attributes"],
344
+ attributes=attributes,
341
345
  events=sorted(span_exceptions, key=lambda event: event.timestamp) or None,
342
346
  conversation=None,
343
347
  )
@@ -490,3 +494,14 @@ def _get_token_counts(usage: object) -> Iterator[Tuple[str, Any]]:
490
494
  yield LLM_TOKEN_COUNT_COMPLETION, completion_tokens
491
495
  if (total_tokens := getattr(usage, "total_tokens", None)) is not None:
492
496
  yield LLM_TOKEN_COUNT_TOTAL, total_tokens
497
+
498
+
499
+ def _template_attributes(payload: Dict[str, Any]) -> Iterator[Tuple[str, Any]]:
500
+ """Yields template attributes if present"""
501
+ if template := payload.get(EventPayload.TEMPLATE):
502
+ yield LLM_PROMPT_TEMPLATE, template
503
+ if template_vars := payload.get(EventPayload.TEMPLATE_VARS):
504
+ yield LLM_PROMPT_TEMPLATE_VARIABLES, template_vars
505
+ # TODO(maybe): other keys in the same payload
506
+ # EventPayload.SYSTEM_PROMPT
507
+ # EventPayload.QUERY_WRAPPER_PROMPT