vectara-agentic 0.3.3__py3-none-any.whl → 0.4.1__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 vectara-agentic might be problematic. Click here for more details.
- tests/__init__.py +7 -0
- tests/conftest.py +316 -0
- tests/endpoint.py +54 -17
- tests/run_tests.py +112 -0
- tests/test_agent.py +35 -33
- tests/test_agent_fallback_memory.py +270 -0
- tests/test_agent_memory_consistency.py +229 -0
- tests/test_agent_type.py +86 -143
- tests/test_api_endpoint.py +4 -0
- tests/test_bedrock.py +50 -31
- tests/test_fallback.py +4 -0
- tests/test_gemini.py +27 -59
- tests/test_groq.py +50 -31
- tests/test_private_llm.py +11 -2
- tests/test_return_direct.py +6 -2
- tests/test_serialization.py +7 -6
- tests/test_session_memory.py +252 -0
- tests/test_streaming.py +109 -0
- tests/test_together.py +62 -0
- tests/test_tools.py +10 -82
- tests/test_vectara_llms.py +4 -0
- tests/test_vhc.py +67 -0
- tests/test_workflow.py +13 -28
- vectara_agentic/__init__.py +27 -4
- vectara_agentic/_callback.py +65 -67
- vectara_agentic/_observability.py +30 -30
- vectara_agentic/_version.py +1 -1
- vectara_agentic/agent.py +565 -859
- vectara_agentic/agent_config.py +15 -14
- vectara_agentic/agent_core/__init__.py +22 -0
- vectara_agentic/agent_core/factory.py +383 -0
- vectara_agentic/{_prompts.py → agent_core/prompts.py} +21 -46
- vectara_agentic/agent_core/serialization.py +348 -0
- vectara_agentic/agent_core/streaming.py +483 -0
- vectara_agentic/agent_core/utils/__init__.py +29 -0
- vectara_agentic/agent_core/utils/hallucination.py +157 -0
- vectara_agentic/agent_core/utils/logging.py +52 -0
- vectara_agentic/agent_core/utils/schemas.py +87 -0
- vectara_agentic/agent_core/utils/tools.py +125 -0
- vectara_agentic/agent_endpoint.py +4 -6
- vectara_agentic/db_tools.py +37 -12
- vectara_agentic/llm_utils.py +42 -43
- vectara_agentic/sub_query_workflow.py +9 -14
- vectara_agentic/tool_utils.py +138 -83
- vectara_agentic/tools.py +36 -21
- vectara_agentic/tools_catalog.py +16 -16
- vectara_agentic/types.py +106 -8
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.1.dist-info}/METADATA +111 -31
- vectara_agentic-0.4.1.dist-info/RECORD +53 -0
- tests/test_agent_planning.py +0 -64
- tests/test_hhem.py +0 -100
- vectara_agentic/hhem.py +0 -82
- vectara_agentic-0.3.3.dist-info/RECORD +0 -39
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.1.dist-info}/WHEEL +0 -0
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {vectara_agentic-0.3.3.dist-info → vectara_agentic-0.4.1.dist-info}/top_level.txt +0 -0
tests/test_workflow.py
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
|
+
# Suppress external dependency warnings before any other imports
|
|
2
|
+
import warnings
|
|
3
|
+
warnings.simplefilter("ignore", DeprecationWarning)
|
|
4
|
+
|
|
1
5
|
import unittest
|
|
2
6
|
|
|
3
7
|
from vectara_agentic.agent import Agent
|
|
4
8
|
from vectara_agentic.agent_config import AgentConfig
|
|
5
9
|
from vectara_agentic.tools import ToolsFactory
|
|
6
10
|
from vectara_agentic.sub_query_workflow import SubQuestionQueryWorkflow, SequentialSubQuestionsWorkflow
|
|
7
|
-
|
|
8
|
-
def mult(x: float, y: float):
|
|
9
|
-
"""
|
|
10
|
-
Multiply two numbers.
|
|
11
|
-
"""
|
|
12
|
-
return x * y
|
|
13
|
-
|
|
14
|
-
def add(x: float, y: float):
|
|
15
|
-
"""
|
|
16
|
-
Add two numbers.
|
|
17
|
-
"""
|
|
18
|
-
return x + y
|
|
11
|
+
from conftest import mult, add, STANDARD_TEST_TOPIC, WORKFLOW_TEST_INSTRUCTIONS
|
|
19
12
|
|
|
20
13
|
class TestWorkflowPackage(unittest.IsolatedAsyncioTestCase):
|
|
21
14
|
|
|
22
15
|
async def test_sub_query_workflow(self):
|
|
23
16
|
tools = [ToolsFactory().create_tool(mult)] + [ToolsFactory().create_tool(add)]
|
|
24
|
-
topic = "AI topic"
|
|
25
|
-
instructions = "You are a helpful AI assistant."
|
|
26
17
|
agent = Agent(
|
|
27
18
|
tools=tools,
|
|
28
|
-
topic=
|
|
29
|
-
custom_instructions=
|
|
19
|
+
topic=STANDARD_TEST_TOPIC,
|
|
20
|
+
custom_instructions=WORKFLOW_TEST_INSTRUCTIONS,
|
|
30
21
|
agent_config = AgentConfig(),
|
|
31
22
|
workflow_cls = SubQuestionQueryWorkflow,
|
|
32
23
|
)
|
|
@@ -46,12 +37,10 @@ class TestWorkflowPackage(unittest.IsolatedAsyncioTestCase):
|
|
|
46
37
|
|
|
47
38
|
async def test_seq_sub_query_workflow(self):
|
|
48
39
|
tools = [ToolsFactory().create_tool(mult)] + [ToolsFactory().create_tool(add)]
|
|
49
|
-
topic = "AI topic"
|
|
50
|
-
instructions = "You are a helpful AI assistant."
|
|
51
40
|
agent = Agent(
|
|
52
41
|
tools=tools,
|
|
53
|
-
topic=
|
|
54
|
-
custom_instructions=
|
|
42
|
+
topic=STANDARD_TEST_TOPIC,
|
|
43
|
+
custom_instructions=WORKFLOW_TEST_INSTRUCTIONS,
|
|
55
44
|
agent_config = AgentConfig(),
|
|
56
45
|
workflow_cls = SequentialSubQuestionsWorkflow,
|
|
57
46
|
)
|
|
@@ -66,12 +55,10 @@ class TestWorkflowFailure(unittest.IsolatedAsyncioTestCase):
|
|
|
66
55
|
|
|
67
56
|
async def test_workflow_failure_sub_question(self):
|
|
68
57
|
tools = [ToolsFactory().create_tool(mult)] + [ToolsFactory().create_tool(add)]
|
|
69
|
-
topic = "AI topic"
|
|
70
|
-
instructions = "You are a helpful AI assistant."
|
|
71
58
|
agent = Agent(
|
|
72
59
|
tools=tools,
|
|
73
|
-
topic=
|
|
74
|
-
custom_instructions=
|
|
60
|
+
topic=STANDARD_TEST_TOPIC,
|
|
61
|
+
custom_instructions=WORKFLOW_TEST_INSTRUCTIONS,
|
|
75
62
|
agent_config = AgentConfig(),
|
|
76
63
|
workflow_cls = SubQuestionQueryWorkflow,
|
|
77
64
|
workflow_timeout = 1
|
|
@@ -85,12 +72,10 @@ class TestWorkflowFailure(unittest.IsolatedAsyncioTestCase):
|
|
|
85
72
|
|
|
86
73
|
async def test_workflow_failure_seq_sub_question(self):
|
|
87
74
|
tools = [ToolsFactory().create_tool(mult)] + [ToolsFactory().create_tool(add)]
|
|
88
|
-
topic = "AI topic"
|
|
89
|
-
instructions = "You are a helpful AI assistant."
|
|
90
75
|
agent = Agent(
|
|
91
76
|
tools=tools,
|
|
92
|
-
topic=
|
|
93
|
-
custom_instructions=
|
|
77
|
+
topic=STANDARD_TEST_TOPIC,
|
|
78
|
+
custom_instructions=WORKFLOW_TEST_INSTRUCTIONS,
|
|
94
79
|
agent_config = AgentConfig(),
|
|
95
80
|
workflow_cls = SequentialSubQuestionsWorkflow,
|
|
96
81
|
workflow_timeout = 1
|
vectara_agentic/__init__.py
CHANGED
|
@@ -2,25 +2,48 @@
|
|
|
2
2
|
vectara_agentic package.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
# Simple global warning suppression for end users
|
|
6
|
+
import warnings
|
|
7
|
+
|
|
8
|
+
warnings.simplefilter("ignore", DeprecationWarning)
|
|
9
|
+
|
|
10
|
+
# pylint: disable=wrong-import-position
|
|
5
11
|
from .agent import Agent
|
|
6
12
|
from .tools import VectaraToolFactory, VectaraTool, ToolsFactory
|
|
7
13
|
from .tools_catalog import ToolsCatalog
|
|
8
14
|
from .agent_config import AgentConfig
|
|
9
15
|
from .agent_endpoint import create_app, start_app
|
|
10
16
|
from .types import (
|
|
11
|
-
AgentType,
|
|
17
|
+
AgentType,
|
|
18
|
+
ObserverType,
|
|
19
|
+
ModelProvider,
|
|
20
|
+
AgentStatusType,
|
|
21
|
+
LLMRole,
|
|
22
|
+
ToolType,
|
|
12
23
|
)
|
|
13
24
|
|
|
14
25
|
# Define the __all__ variable for wildcard imports
|
|
15
26
|
__all__ = [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
"Agent",
|
|
28
|
+
"VectaraToolFactory",
|
|
29
|
+
"VectaraTool",
|
|
30
|
+
"ToolsFactory",
|
|
31
|
+
"AgentConfig",
|
|
32
|
+
"create_app",
|
|
33
|
+
"start_app",
|
|
34
|
+
"ToolsCatalog",
|
|
35
|
+
"AgentType",
|
|
36
|
+
"ObserverType",
|
|
37
|
+
"ModelProvider",
|
|
38
|
+
"AgentStatusType",
|
|
39
|
+
"LLMRole",
|
|
40
|
+
"ToolType",
|
|
19
41
|
]
|
|
20
42
|
|
|
21
43
|
# Ensure package version is available
|
|
22
44
|
try:
|
|
23
45
|
import importlib.metadata
|
|
46
|
+
|
|
24
47
|
__version__ = importlib.metadata.version("vectara_agentic")
|
|
25
48
|
except Exception:
|
|
26
49
|
__version__ = "0.0.0" # fallback if not installed
|
vectara_agentic/_callback.py
CHANGED
|
@@ -3,14 +3,17 @@ Module to handle agent callbacks
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import inspect
|
|
6
|
+
import logging
|
|
6
7
|
from typing import Any, Dict, Optional, List, Callable
|
|
7
8
|
from functools import wraps
|
|
9
|
+
import traceback
|
|
8
10
|
|
|
9
11
|
from llama_index.core.callbacks.base_handler import BaseCallbackHandler
|
|
10
12
|
from llama_index.core.callbacks.schema import CBEventType, EventPayload
|
|
11
13
|
|
|
12
14
|
from .types import AgentStatusType
|
|
13
15
|
|
|
16
|
+
|
|
14
17
|
def wrap_callback_fn(callback):
|
|
15
18
|
"""
|
|
16
19
|
Wrap a callback function to ensure it only receives the parameters it can accept.
|
|
@@ -34,6 +37,7 @@ def wrap_callback_fn(callback):
|
|
|
34
37
|
|
|
35
38
|
return new_callback
|
|
36
39
|
|
|
40
|
+
|
|
37
41
|
class AgentCallbackHandler(BaseCallbackHandler):
|
|
38
42
|
"""
|
|
39
43
|
Callback handler to track agent status
|
|
@@ -153,10 +157,8 @@ class AgentCallbackHandler(BaseCallbackHandler):
|
|
|
153
157
|
self._handle_function_call(payload, event_id)
|
|
154
158
|
elif event_type == CBEventType.AGENT_STEP:
|
|
155
159
|
self._handle_agent_step(payload, event_id)
|
|
156
|
-
elif event_type == CBEventType.EXCEPTION:
|
|
157
|
-
print(f"Exception event in handle_event: {payload.get(EventPayload.EXCEPTION)}")
|
|
158
160
|
else:
|
|
159
|
-
|
|
161
|
+
pass
|
|
160
162
|
|
|
161
163
|
async def _ahandle_event(
|
|
162
164
|
self, event_type: CBEventType, payload: Dict[str, Any], event_id: str
|
|
@@ -167,10 +169,8 @@ class AgentCallbackHandler(BaseCallbackHandler):
|
|
|
167
169
|
await self._ahandle_function_call(payload, event_id)
|
|
168
170
|
elif event_type == CBEventType.AGENT_STEP:
|
|
169
171
|
await self._ahandle_agent_step(payload, event_id)
|
|
170
|
-
elif event_type == CBEventType.EXCEPTION:
|
|
171
|
-
print(f"Exception event in ahandle_event: {payload.get(EventPayload.EXCEPTION)}")
|
|
172
172
|
else:
|
|
173
|
-
|
|
173
|
+
pass
|
|
174
174
|
|
|
175
175
|
# Synchronous handlers
|
|
176
176
|
def _handle_llm(
|
|
@@ -196,37 +196,38 @@ class AgentCallbackHandler(BaseCallbackHandler):
|
|
|
196
196
|
event_id=event_id,
|
|
197
197
|
)
|
|
198
198
|
else:
|
|
199
|
-
|
|
200
|
-
f"vectara-agentic llm callback: no messages or prompt found in payload {payload}"
|
|
201
|
-
)
|
|
199
|
+
pass
|
|
202
200
|
|
|
203
201
|
def _handle_function_call(self, payload: dict, event_id: str) -> None:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if
|
|
202
|
+
try:
|
|
203
|
+
if EventPayload.FUNCTION_CALL in payload:
|
|
204
|
+
fcall = payload.get(EventPayload.FUNCTION_CALL)
|
|
205
|
+
tool = payload.get(EventPayload.TOOL)
|
|
206
|
+
|
|
207
|
+
if tool:
|
|
208
|
+
tool_name = tool.name
|
|
209
|
+
if self.fn:
|
|
210
|
+
self.fn(
|
|
211
|
+
status_type=AgentStatusType.TOOL_CALL,
|
|
212
|
+
msg={"tool_name": tool_name, "arguments": fcall},
|
|
213
|
+
event_id=event_id,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
elif EventPayload.FUNCTION_OUTPUT in payload:
|
|
217
|
+
response = payload.get(EventPayload.FUNCTION_OUTPUT)
|
|
218
|
+
tool = payload.get(EventPayload.TOOL)
|
|
219
|
+
|
|
220
|
+
if tool and self.fn:
|
|
210
221
|
self.fn(
|
|
211
|
-
status_type=AgentStatusType.
|
|
212
|
-
msg={
|
|
213
|
-
"tool_name": tool_name,
|
|
214
|
-
"arguments": fcall
|
|
215
|
-
},
|
|
222
|
+
status_type=AgentStatusType.TOOL_OUTPUT,
|
|
223
|
+
msg={"tool_name": tool.name, "content": response},
|
|
216
224
|
event_id=event_id,
|
|
217
225
|
)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
msg=response,
|
|
224
|
-
event_id=event_id,
|
|
225
|
-
)
|
|
226
|
-
else:
|
|
227
|
-
print(
|
|
228
|
-
f"Vectara-agentic callback handler: no function call or output found in payload {payload}"
|
|
229
|
-
)
|
|
226
|
+
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logging.error(f"Exception in _handle_function_call: {e}")
|
|
229
|
+
logging.error(f"Traceback: {traceback.format_exc()}")
|
|
230
|
+
# Continue execution to prevent callback failures from breaking the agent
|
|
230
231
|
|
|
231
232
|
def _handle_agent_step(self, payload: dict, event_id: str) -> None:
|
|
232
233
|
if EventPayload.MESSAGES in payload:
|
|
@@ -245,10 +246,6 @@ class AgentCallbackHandler(BaseCallbackHandler):
|
|
|
245
246
|
msg=response,
|
|
246
247
|
event_id=event_id,
|
|
247
248
|
)
|
|
248
|
-
else:
|
|
249
|
-
print(
|
|
250
|
-
f"Vectara-agentic agent_step: no messages or prompt found in payload {payload}"
|
|
251
|
-
)
|
|
252
249
|
|
|
253
250
|
# Asynchronous handlers
|
|
254
251
|
async def _ahandle_llm(self, payload: dict, event_id: str) -> None:
|
|
@@ -276,52 +273,55 @@ class AgentCallbackHandler(BaseCallbackHandler):
|
|
|
276
273
|
msg=prompt,
|
|
277
274
|
event_id=event_id,
|
|
278
275
|
)
|
|
279
|
-
else:
|
|
280
|
-
print(
|
|
281
|
-
f"vectara-agentic llm callback: no messages or prompt found in payload {payload}"
|
|
282
|
-
)
|
|
283
276
|
|
|
284
277
|
async def _ahandle_function_call(self, payload: dict, event_id: str) -> None:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
278
|
+
try:
|
|
279
|
+
if EventPayload.FUNCTION_CALL in payload:
|
|
280
|
+
fcall = payload.get(EventPayload.FUNCTION_CALL)
|
|
281
|
+
tool = payload.get(EventPayload.TOOL)
|
|
282
|
+
|
|
283
|
+
if tool and self.fn:
|
|
290
284
|
if inspect.iscoroutinefunction(self.fn):
|
|
291
285
|
await self.fn(
|
|
292
286
|
status_type=AgentStatusType.TOOL_CALL,
|
|
287
|
+
msg={"tool_name": tool.name, "arguments": fcall},
|
|
288
|
+
event_id=event_id,
|
|
289
|
+
)
|
|
290
|
+
else:
|
|
291
|
+
self.fn(
|
|
292
|
+
status_type=AgentStatusType.TOOL_CALL,
|
|
293
|
+
msg={"tool_name": tool.name, "arguments": fcall},
|
|
294
|
+
event_id=event_id,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
elif EventPayload.FUNCTION_OUTPUT in payload:
|
|
298
|
+
response = payload.get(EventPayload.FUNCTION_OUTPUT)
|
|
299
|
+
tool = payload.get(EventPayload.TOOL)
|
|
300
|
+
|
|
301
|
+
if tool and self.fn:
|
|
302
|
+
if inspect.iscoroutinefunction(self.fn):
|
|
303
|
+
await self.fn(
|
|
304
|
+
status_type=AgentStatusType.TOOL_OUTPUT,
|
|
293
305
|
msg={
|
|
294
306
|
"tool_name": tool.name,
|
|
295
|
-
"
|
|
307
|
+
"content": response,
|
|
296
308
|
},
|
|
297
309
|
event_id=event_id,
|
|
298
310
|
)
|
|
299
311
|
else:
|
|
300
312
|
self.fn(
|
|
301
|
-
status_type=AgentStatusType.
|
|
313
|
+
status_type=AgentStatusType.TOOL_OUTPUT,
|
|
302
314
|
msg={
|
|
303
315
|
"tool_name": tool.name,
|
|
304
|
-
"
|
|
316
|
+
"content": response,
|
|
305
317
|
},
|
|
306
318
|
event_id=event_id,
|
|
307
319
|
)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
status_type=AgentStatusType.TOOL_OUTPUT,
|
|
314
|
-
msg=response,
|
|
315
|
-
event_id=event_id,
|
|
316
|
-
)
|
|
317
|
-
else:
|
|
318
|
-
self.fn(
|
|
319
|
-
status_type=AgentStatusType.TOOL_OUTPUT,
|
|
320
|
-
msg=response,
|
|
321
|
-
event_id=event_id,
|
|
322
|
-
)
|
|
323
|
-
else:
|
|
324
|
-
print(f"No function call or output found in payload {payload}")
|
|
320
|
+
|
|
321
|
+
except Exception as e:
|
|
322
|
+
logging.error(f"Exception in _ahandle_function_call: {e}")
|
|
323
|
+
logging.error(f"Traceback: {traceback.format_exc()}")
|
|
324
|
+
# Continue execution to prevent callback failures from breaking the agent
|
|
325
325
|
|
|
326
326
|
async def _ahandle_agent_step(self, payload: dict, event_id: str) -> None:
|
|
327
327
|
if EventPayload.MESSAGES in payload:
|
|
@@ -354,5 +354,3 @@ class AgentCallbackHandler(BaseCallbackHandler):
|
|
|
354
354
|
msg=response,
|
|
355
355
|
event_id=event_id,
|
|
356
356
|
)
|
|
357
|
-
else:
|
|
358
|
-
print(f"No messages or prompt found in payload {payload}")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Observability for Vectara Agentic.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import os
|
|
5
6
|
import json
|
|
6
7
|
from typing import Optional, Union
|
|
@@ -13,9 +14,9 @@ SPAN_NAME: str = "VectaraQueryEngine._query"
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def setup_observer(config: AgentConfig, verbose: bool) -> bool:
|
|
16
|
-
|
|
17
|
+
"""
|
|
17
18
|
Setup the observer.
|
|
18
|
-
|
|
19
|
+
"""
|
|
19
20
|
if config.observer != ObserverType.ARIZE_PHOENIX:
|
|
20
21
|
if verbose:
|
|
21
22
|
print("No Phoenix observer set.")
|
|
@@ -38,9 +39,11 @@ def setup_observer(config: AgentConfig, verbose: bool) -> bool:
|
|
|
38
39
|
if not phoenix_endpoint:
|
|
39
40
|
print("Phoenix endpoint not set. Attempting to launch local Phoenix UI...")
|
|
40
41
|
px.launch_app()
|
|
41
|
-
print(
|
|
42
|
+
print(
|
|
43
|
+
"Local Phoenix UI launched. You can view traces at the UI address (usually http://localhost:6006)."
|
|
44
|
+
)
|
|
42
45
|
|
|
43
|
-
if phoenix_endpoint and
|
|
46
|
+
if phoenix_endpoint and "app.phoenix.arize.com" in phoenix_endpoint:
|
|
44
47
|
phoenix_api_key = os.getenv("PHOENIX_API_KEY")
|
|
45
48
|
if not phoenix_api_key:
|
|
46
49
|
raise ValueError(
|
|
@@ -50,7 +53,7 @@ def setup_observer(config: AgentConfig, verbose: bool) -> bool:
|
|
|
50
53
|
os.environ["PHOENIX_COLLECTOR_ENDPOINT"] = "https://app.phoenix.arize.com"
|
|
51
54
|
|
|
52
55
|
reg_kwargs = {
|
|
53
|
-
"endpoint": phoenix_endpoint or
|
|
56
|
+
"endpoint": phoenix_endpoint or "http://localhost:6006/v1/traces",
|
|
54
57
|
"project_name": PROJECT_NAME,
|
|
55
58
|
"batch": False,
|
|
56
59
|
"set_global_tracer_provider": False,
|
|
@@ -58,35 +61,35 @@ def setup_observer(config: AgentConfig, verbose: bool) -> bool:
|
|
|
58
61
|
tracer_provider = register(**reg_kwargs)
|
|
59
62
|
LlamaIndexInstrumentor().instrument(tracer_provider=tracer_provider)
|
|
60
63
|
if verbose:
|
|
61
|
-
print(
|
|
64
|
+
print(
|
|
65
|
+
f"Phoenix observer configured for project 'vectara-agentic' at endpoint: {reg_kwargs['endpoint']}"
|
|
66
|
+
)
|
|
62
67
|
return True
|
|
63
68
|
|
|
64
69
|
|
|
65
70
|
def _extract_fcs_value(output: Union[str, dict]) -> Optional[float]:
|
|
66
|
-
|
|
71
|
+
"""
|
|
67
72
|
Extract the FCS value from the output.
|
|
68
|
-
|
|
73
|
+
"""
|
|
69
74
|
try:
|
|
70
75
|
output_json = json.loads(output)
|
|
71
|
-
if
|
|
72
|
-
return output_json[
|
|
73
|
-
except
|
|
74
|
-
print(f"
|
|
75
|
-
except KeyError:
|
|
76
|
-
print(f"'fcs' not found in: {output_json}")
|
|
76
|
+
if "metadata" in output_json and "fcs" in output_json["metadata"]:
|
|
77
|
+
return output_json["metadata"]["fcs"]
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"Error extracting FCS value: {e}")
|
|
77
80
|
return None
|
|
78
81
|
|
|
79
82
|
|
|
80
83
|
def _find_top_level_parent_id(row: pd.Series, all_spans: pd.DataFrame) -> Optional[str]:
|
|
81
|
-
|
|
84
|
+
"""
|
|
82
85
|
Find the top level parent id for the given span.
|
|
83
|
-
|
|
84
|
-
current_id = row[
|
|
86
|
+
"""
|
|
87
|
+
current_id = row["parent_id"]
|
|
85
88
|
while current_id is not None:
|
|
86
89
|
parent_row = all_spans[all_spans.index == current_id]
|
|
87
90
|
if parent_row.empty:
|
|
88
91
|
break
|
|
89
|
-
new_parent_id = parent_row[
|
|
92
|
+
new_parent_id = parent_row["parent_id"].iloc[0]
|
|
90
93
|
if new_parent_id == current_id:
|
|
91
94
|
break
|
|
92
95
|
if new_parent_id is None:
|
|
@@ -96,17 +99,14 @@ def _find_top_level_parent_id(row: pd.Series, all_spans: pd.DataFrame) -> Option
|
|
|
96
99
|
|
|
97
100
|
|
|
98
101
|
def eval_fcs() -> None:
|
|
99
|
-
|
|
102
|
+
"""
|
|
100
103
|
Evaluate the FCS score for the VectaraQueryEngine._query span.
|
|
101
|
-
|
|
104
|
+
"""
|
|
102
105
|
import phoenix as px
|
|
103
106
|
from phoenix.trace.dsl import SpanQuery
|
|
104
107
|
from phoenix.trace import SpanEvaluations
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
"parent_id",
|
|
108
|
-
"name"
|
|
109
|
-
)
|
|
108
|
+
|
|
109
|
+
query = SpanQuery().select("output.value", "parent_id", "name")
|
|
110
110
|
try:
|
|
111
111
|
client = px.Client()
|
|
112
112
|
all_spans = client.query_spans(query, project_name=PROJECT_NAME)
|
|
@@ -114,17 +114,17 @@ def eval_fcs() -> None:
|
|
|
114
114
|
print(f"Failed to query spans: {e}")
|
|
115
115
|
return
|
|
116
116
|
|
|
117
|
-
vectara_spans = all_spans[all_spans[
|
|
118
|
-
vectara_spans[
|
|
117
|
+
vectara_spans = all_spans[all_spans["name"] == SPAN_NAME].copy()
|
|
118
|
+
vectara_spans["top_level_parent_id"] = vectara_spans.apply(
|
|
119
119
|
lambda row: _find_top_level_parent_id(row, all_spans), axis=1
|
|
120
120
|
)
|
|
121
|
-
vectara_spans[
|
|
121
|
+
vectara_spans["score"] = vectara_spans["output.value"].apply(_extract_fcs_value)
|
|
122
122
|
|
|
123
123
|
vectara_spans.reset_index(inplace=True)
|
|
124
124
|
top_level_spans = vectara_spans.copy()
|
|
125
|
-
top_level_spans[
|
|
125
|
+
top_level_spans["context.span_id"] = top_level_spans["top_level_parent_id"]
|
|
126
126
|
vectara_spans = pd.concat([vectara_spans, top_level_spans], ignore_index=True)
|
|
127
|
-
vectara_spans.set_index(
|
|
127
|
+
vectara_spans.set_index("context.span_id", inplace=True)
|
|
128
128
|
|
|
129
129
|
px.Client().log_evaluations(
|
|
130
130
|
SpanEvaluations(
|
vectara_agentic/_version.py
CHANGED