arize-phoenix 10.1.0__py3-none-any.whl → 10.2.0__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.

@@ -23,13 +23,18 @@ from google.protobuf.wrappers_pb2 import DoubleValue, StringValue
23
23
  import phoenix.trace.v1 as pb
24
24
  from phoenix.config import get_env_collector_endpoint, get_env_host, get_env_port
25
25
  from phoenix.session.client import Client
26
- from phoenix.trace.dsl.helpers import get_qa_with_reference, get_retrieved_documents
26
+ from phoenix.trace.dsl.helpers import (
27
+ get_called_tools,
28
+ get_qa_with_reference,
29
+ get_retrieved_documents,
30
+ )
27
31
  from phoenix.trace.exporter import HttpExporter
28
32
  from phoenix.trace.span_evaluations import Evaluations
29
33
 
30
34
  __all__ = [
31
35
  "get_retrieved_documents",
32
36
  "get_qa_with_reference",
37
+ "get_called_tools",
33
38
  "add_evaluations",
34
39
  ]
35
40
 
@@ -1,6 +1,7 @@
1
+ import json
1
2
  import warnings
2
3
  from datetime import datetime
3
- from typing import Optional, Protocol, Union, cast
4
+ from typing import Any, Iterable, Mapping, Optional, Protocol, Union, cast
4
5
 
5
6
  import pandas as pd
6
7
  from openinference.semconv.trace import DocumentAttributes, SpanAttributes
@@ -13,11 +14,16 @@ DOCUMENT_SCORE = DocumentAttributes.DOCUMENT_SCORE
13
14
  INPUT_VALUE = SpanAttributes.INPUT_VALUE
14
15
  OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE
15
16
  RETRIEVAL_DOCUMENTS = SpanAttributes.RETRIEVAL_DOCUMENTS
17
+ LLM_FUNCTION_CALL = SpanAttributes.LLM_FUNCTION_CALL
18
+ LLM_INPUT_MESSAGES = SpanAttributes.LLM_INPUT_MESSAGES
19
+ LLM_OUTPUT_MESSAGES = SpanAttributes.LLM_OUTPUT_MESSAGES
20
+
16
21
 
17
22
  INPUT = {"input": INPUT_VALUE}
18
23
  OUTPUT = {"output": OUTPUT_VALUE}
19
24
  IO = {**INPUT, **OUTPUT}
20
25
 
26
+
21
27
  IS_ROOT = "parent_id is None"
22
28
  IS_LLM = "span_kind == 'LLM'"
23
29
  IS_RETRIEVER = "span_kind == 'RETRIEVER'"
@@ -125,3 +131,86 @@ def get_qa_with_reference(
125
131
  df_ref = pd.DataFrame({"reference": ref})
126
132
  df_qa_ref = pd.concat([df_qa, df_ref], axis=1, join="inner").set_index("context.span_id")
127
133
  return df_qa_ref
134
+
135
+
136
+ def get_called_tools(
137
+ obj: CanQuerySpans,
138
+ *,
139
+ start_time: Optional[datetime] = None,
140
+ end_time: Optional[datetime] = None,
141
+ project_name: Optional[str] = None,
142
+ timeout: Optional[int] = DEFAULT_TIMEOUT_IN_SECONDS,
143
+ function_name_only: bool = False,
144
+ ) -> Optional[pd.DataFrame]:
145
+ """Retrieve tool calls made by LLM spans within a specified time range.
146
+
147
+ This function queries LLM spans and extracts tool calls from their output messages.
148
+ It can return either just the function names or full function calls with arguments.
149
+
150
+ Args:
151
+ obj: An object that implements the CanQuerySpans protocol for querying spans.
152
+ start_time: Optional start time to filter spans. If None, no start time filter is applied.
153
+ end_time: Optional end time to filter spans. If None, no end time filter is applied.
154
+ project_name: Optional project name to filter spans. If None, uses the environment project name.
155
+ timeout: Optional timeout in seconds for the query. Defaults to DEFAULT_TIMEOUT_IN_SECONDS.
156
+ function_name_only: If True, returns only function names. If False, returns full function calls
157
+ with arguments. Defaults to False.
158
+
159
+ Returns:
160
+ A pandas DataFrame containing the tool calls, or None if no spans are found.
161
+ The DataFrame includes columns for input messages, output messages, and tool calls.
162
+ """ # noqa: E501
163
+ project_name = project_name or get_env_project_name()
164
+
165
+ def extract_tool_calls(outputs: list[dict[str, Any]]) -> Optional[list[str]]:
166
+ if not isinstance(outputs, list) or not outputs:
167
+ return None
168
+ ans = []
169
+ if isinstance(message := outputs[0].get("message"), Mapping) and isinstance(
170
+ tool_calls := message.get("tool_calls"), Iterable
171
+ ):
172
+ for tool_call in tool_calls:
173
+ if not isinstance(tool_call, Mapping):
174
+ continue
175
+ if not isinstance(tc := tool_call.get("tool_call"), Mapping):
176
+ continue
177
+ if not isinstance(function := tc.get("function"), Mapping):
178
+ continue
179
+ if not isinstance(name := function.get("name"), str):
180
+ continue
181
+ if function_name_only:
182
+ ans.append(name)
183
+ continue
184
+ kwargs = {}
185
+ if isinstance(arguments := function.get("arguments"), str):
186
+ try:
187
+ kwargs = json.loads(arguments)
188
+ except Exception:
189
+ pass
190
+ kwargs_str = "" if not kwargs else ", ".join(f"{k}={v}" for k, v in kwargs.items())
191
+ ans.append(f"{name}({kwargs_str})")
192
+ return ans or None
193
+
194
+ df_qa = cast(
195
+ pd.DataFrame,
196
+ obj.query_spans(
197
+ SpanQuery()
198
+ .where(IS_LLM)
199
+ .select(
200
+ input=LLM_INPUT_MESSAGES,
201
+ output=LLM_OUTPUT_MESSAGES,
202
+ ),
203
+ start_time=start_time,
204
+ end_time=end_time,
205
+ project_name=project_name,
206
+ timeout=timeout,
207
+ ),
208
+ )
209
+
210
+ if df_qa is None:
211
+ print("No spans found.")
212
+ return None
213
+
214
+ df_qa["tool_call"] = df_qa["output"].apply(extract_tool_calls)
215
+
216
+ return df_qa
phoenix/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "10.1.0"
1
+ __version__ = "10.2.0"