vectara-agentic 0.1.8__tar.gz → 0.1.10__tar.gz
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.
- {vectara_agentic-0.1.8/vectara_agentic.egg-info → vectara_agentic-0.1.10}/PKG-INFO +30 -3
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/README.md +26 -1
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/requirements.txt +3 -1
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/setup.py +1 -1
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/tests/test_agent.py +14 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/tests/test_tools.py +20 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/__init__.py +1 -1
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/_prompts.py +4 -3
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/agent.py +188 -18
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/tools.py +39 -16
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10/vectara_agentic.egg-info}/PKG-INFO +30 -3
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic.egg-info/requires.txt +3 -1
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/LICENSE +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/MANIFEST.in +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/setup.cfg +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/_callback.py +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/tools_catalog.py +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/types.py +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic/utils.py +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic.egg-info/SOURCES.txt +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic.egg-info/dependency_links.txt +0 -0
- {vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vectara_agentic
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: A Python package for creating AI Assistants and AI Agents with Vectara
|
|
5
5
|
Home-page: https://github.com/vectara/py-vectara-agentic
|
|
6
6
|
Author: Ofer Mendelevitch
|
|
@@ -31,11 +31,13 @@ Requires-Dist: llama-index-tools-arxiv==0.2.0
|
|
|
31
31
|
Requires-Dist: llama-index-tools-database==0.2.0
|
|
32
32
|
Requires-Dist: llama-index-tools-google==0.2.0
|
|
33
33
|
Requires-Dist: llama-index-tools-tavily_research==0.2.0
|
|
34
|
+
Requires-Dist: llama-index-callbacks-arize-phoenix==0.2.1
|
|
34
35
|
Requires-Dist: pydantic==2.8.2
|
|
35
36
|
Requires-Dist: retrying==1.3.4
|
|
36
|
-
Requires-Dist: pymongo==4.6.
|
|
37
|
+
Requires-Dist: pymongo==4.6.3
|
|
37
38
|
Requires-Dist: python-dotenv==1.0.1
|
|
38
39
|
Requires-Dist: tiktoken==0.7.0
|
|
40
|
+
Requires-Dist: dill==0.3.8
|
|
39
41
|
|
|
40
42
|
# vectara-agentic
|
|
41
43
|
|
|
@@ -63,7 +65,7 @@ Requires-Dist: tiktoken==0.7.0
|
|
|
63
65
|
- [Vectara account](https://console.vectara.com/signup/?utm_source=github&utm_medium=code&utm_term=DevRel&utm_content=vectara-agentic&utm_campaign=github-code-DevRel-vectara-agentic)
|
|
64
66
|
- A Vectara corpus with an [API key](https://docs.vectara.com/docs/api-keys)
|
|
65
67
|
- [Python 3.10 or higher](https://www.python.org/downloads/)
|
|
66
|
-
- OpenAI API key (or API keys for Anthropic, TOGETHER.AI, Fireworks AI, Cohere
|
|
68
|
+
- OpenAI API key (or API keys for Anthropic, TOGETHER.AI, Fireworks AI, Cohere or GROQ)
|
|
67
69
|
|
|
68
70
|
## Installation
|
|
69
71
|
|
|
@@ -97,6 +99,8 @@ query_financial_reports = vec_factory.create_rag_tool(
|
|
|
97
99
|
)
|
|
98
100
|
```
|
|
99
101
|
|
|
102
|
+
Note that `VECTARA_CORPUS_ID` can be a single ID or a comma-separated list of IDs.
|
|
103
|
+
|
|
100
104
|
2. **Create other tools (optional)**
|
|
101
105
|
|
|
102
106
|
In addition to RAG tools, you can generate a lot of other types of tools the agent can use. These could be mathematical tools, tools
|
|
@@ -181,6 +185,29 @@ The `Agent` class defines a few helpful methods to help you understand the inter
|
|
|
181
185
|
* The `report()` method prints out the agent object’s type, the tools, and the LLMs used for the main agent and tool calling.
|
|
182
186
|
* The `token_counts()` method tells you how many tokens you have used in the current session for both the main agent and tool calling LLMs. This can be helpful if you want to track spend by token.
|
|
183
187
|
|
|
188
|
+
## Serialization
|
|
189
|
+
|
|
190
|
+
The `Agent` class supports serialization. Use the `dumps()` to serialize and `loads()` to read back from a serialized stream.
|
|
191
|
+
|
|
192
|
+
## Observability
|
|
193
|
+
|
|
194
|
+
vectara-agentic supports observability via the existing integration of LlamaIndex and Arize Phoenix.
|
|
195
|
+
To enable tracing of your vectara-agentic assistant, follow these steps (adapted from [here](https://docs.llamaindex.ai/en/stable/module_guides/observability/)):
|
|
196
|
+
1. Go to `https://llamatrace.com/login` an create an account, then create an API key and put it in the `PHOENIX_API_KEY` variable
|
|
197
|
+
2. `os["VECTARA_AGENTIC_OBSERVER_TYPE"] = "ARIZE_PHOENIX"`: to enable Arize Phoenix observability
|
|
198
|
+
3. `os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}"`
|
|
199
|
+
|
|
200
|
+
Now when you run your agent, all metrics are sent to LlamaTrace and recorded. You can view them at `https://llamatrace.com`.
|
|
201
|
+
If you do not include the `OTEL_EXPORTER_OTLP_HEADERS` a local instance of Arize Phoenix will be setup instead and you can view it at `http://localhost:6006`
|
|
202
|
+
|
|
203
|
+
## About Custom Instructions
|
|
204
|
+
|
|
205
|
+
The custom instructions you provide to the agent guide its behavior.
|
|
206
|
+
Here are some guidelines when creating your instructions:
|
|
207
|
+
- Write precise and clear instructions, without overcomplicating.
|
|
208
|
+
- Consider edge cases and unusual or atypical scenarios.
|
|
209
|
+
- Be cautious to not over-specify behavior based on your primary use-case, as it may limit the agent's ability to behave properly in others.
|
|
210
|
+
|
|
184
211
|
## Examples
|
|
185
212
|
|
|
186
213
|
Check out our example AI assistants:
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
- [Vectara account](https://console.vectara.com/signup/?utm_source=github&utm_medium=code&utm_term=DevRel&utm_content=vectara-agentic&utm_campaign=github-code-DevRel-vectara-agentic)
|
|
25
25
|
- A Vectara corpus with an [API key](https://docs.vectara.com/docs/api-keys)
|
|
26
26
|
- [Python 3.10 or higher](https://www.python.org/downloads/)
|
|
27
|
-
- OpenAI API key (or API keys for Anthropic, TOGETHER.AI, Fireworks AI, Cohere
|
|
27
|
+
- OpenAI API key (or API keys for Anthropic, TOGETHER.AI, Fireworks AI, Cohere or GROQ)
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
@@ -58,6 +58,8 @@ query_financial_reports = vec_factory.create_rag_tool(
|
|
|
58
58
|
)
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
Note that `VECTARA_CORPUS_ID` can be a single ID or a comma-separated list of IDs.
|
|
62
|
+
|
|
61
63
|
2. **Create other tools (optional)**
|
|
62
64
|
|
|
63
65
|
In addition to RAG tools, you can generate a lot of other types of tools the agent can use. These could be mathematical tools, tools
|
|
@@ -142,6 +144,29 @@ The `Agent` class defines a few helpful methods to help you understand the inter
|
|
|
142
144
|
* The `report()` method prints out the agent object’s type, the tools, and the LLMs used for the main agent and tool calling.
|
|
143
145
|
* The `token_counts()` method tells you how many tokens you have used in the current session for both the main agent and tool calling LLMs. This can be helpful if you want to track spend by token.
|
|
144
146
|
|
|
147
|
+
## Serialization
|
|
148
|
+
|
|
149
|
+
The `Agent` class supports serialization. Use the `dumps()` to serialize and `loads()` to read back from a serialized stream.
|
|
150
|
+
|
|
151
|
+
## Observability
|
|
152
|
+
|
|
153
|
+
vectara-agentic supports observability via the existing integration of LlamaIndex and Arize Phoenix.
|
|
154
|
+
To enable tracing of your vectara-agentic assistant, follow these steps (adapted from [here](https://docs.llamaindex.ai/en/stable/module_guides/observability/)):
|
|
155
|
+
1. Go to `https://llamatrace.com/login` an create an account, then create an API key and put it in the `PHOENIX_API_KEY` variable
|
|
156
|
+
2. `os["VECTARA_AGENTIC_OBSERVER_TYPE"] = "ARIZE_PHOENIX"`: to enable Arize Phoenix observability
|
|
157
|
+
3. `os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}"`
|
|
158
|
+
|
|
159
|
+
Now when you run your agent, all metrics are sent to LlamaTrace and recorded. You can view them at `https://llamatrace.com`.
|
|
160
|
+
If you do not include the `OTEL_EXPORTER_OTLP_HEADERS` a local instance of Arize Phoenix will be setup instead and you can view it at `http://localhost:6006`
|
|
161
|
+
|
|
162
|
+
## About Custom Instructions
|
|
163
|
+
|
|
164
|
+
The custom instructions you provide to the agent guide its behavior.
|
|
165
|
+
Here are some guidelines when creating your instructions:
|
|
166
|
+
- Write precise and clear instructions, without overcomplicating.
|
|
167
|
+
- Consider edge cases and unusual or atypical scenarios.
|
|
168
|
+
- Be cautious to not over-specify behavior based on your primary use-case, as it may limit the agent's ability to behave properly in others.
|
|
169
|
+
|
|
145
170
|
## Examples
|
|
146
171
|
|
|
147
172
|
Check out our example AI assistants:
|
|
@@ -13,8 +13,10 @@ llama-index-tools-arxiv==0.2.0
|
|
|
13
13
|
llama-index-tools-database==0.2.0
|
|
14
14
|
llama-index-tools-google==0.2.0
|
|
15
15
|
llama-index-tools-tavily_research==0.2.0
|
|
16
|
+
llama-index-callbacks-arize-phoenix==0.2.1
|
|
16
17
|
pydantic==2.8.2
|
|
17
18
|
retrying==1.3.4
|
|
18
|
-
pymongo==4.6.
|
|
19
|
+
pymongo==4.6.3
|
|
19
20
|
python-dotenv==1.0.1
|
|
20
21
|
tiktoken==0.7.0
|
|
22
|
+
dill==0.3.8
|
|
@@ -56,6 +56,20 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
56
56
|
self.assertIsInstance(agent, Agent)
|
|
57
57
|
self.assertEqual(agent._topic, "question answering")
|
|
58
58
|
|
|
59
|
+
def test_serialization(self):
|
|
60
|
+
agent = Agent.from_corpus(
|
|
61
|
+
tool_name="RAG Tool",
|
|
62
|
+
vectara_customer_id="4584783",
|
|
63
|
+
vectara_corpus_id="4",
|
|
64
|
+
vectara_api_key="api_key",
|
|
65
|
+
data_description="information",
|
|
66
|
+
assistant_specialty="question answering",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
agent_reloaded = agent.loads(agent.dumps())
|
|
70
|
+
self.assertIsInstance(agent_reloaded, Agent)
|
|
71
|
+
self.assertEqual(agent, agent_reloaded)
|
|
72
|
+
|
|
59
73
|
|
|
60
74
|
if __name__ == "__main__":
|
|
61
75
|
unittest.main()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
|
|
3
3
|
from vectara_agentic.tools import VectaraTool, VectaraToolFactory, ToolsFactory, ToolType
|
|
4
|
+
from vectara_agentic.agent import Agent
|
|
4
5
|
from pydantic import Field, BaseModel
|
|
5
6
|
from llama_index.core.tools import FunctionTool
|
|
6
7
|
|
|
@@ -57,6 +58,25 @@ class TestToolsPackage(unittest.TestCase):
|
|
|
57
58
|
self.assertIsInstance(arxiv_tool, FunctionTool)
|
|
58
59
|
self.assertEqual(arxiv_tool.tool_type, ToolType.QUERY)
|
|
59
60
|
|
|
61
|
+
def test_public_repo(self):
|
|
62
|
+
vectara_customer_id = "1366999410"
|
|
63
|
+
vectara_corpus_id = "1"
|
|
64
|
+
vectara_api_key = "zqt_UXrBcnI2UXINZkrv4g1tQPhzj02vfdtqYJIDiA"
|
|
65
|
+
|
|
66
|
+
class QueryToolArgs(BaseModel):
|
|
67
|
+
query: str = Field(description="The user query")
|
|
68
|
+
|
|
69
|
+
agent = Agent.from_corpus(
|
|
70
|
+
vectara_customer_id=vectara_customer_id,
|
|
71
|
+
vectara_corpus_id=vectara_corpus_id,
|
|
72
|
+
vectara_api_key=vectara_api_key,
|
|
73
|
+
tool_name="ask_vectara",
|
|
74
|
+
data_description="data from Vectara website",
|
|
75
|
+
assistant_specialty="RAG as a service",
|
|
76
|
+
vectara_summarizer="mockingbird-1.0-2024-07-16"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
self.assertContains(agent.chat("What is Vectara?"), "Vectara is an end-to-end platform")
|
|
60
80
|
|
|
61
81
|
if __name__ == "__main__":
|
|
62
82
|
unittest.main()
|
|
@@ -88,16 +88,17 @@ If this format is used, the user will respond in the following format:
|
|
|
88
88
|
Observation: tool response
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
You should keep repeating the above format till you have enough information to answer the question without using any more tools.
|
|
91
|
+
You should keep repeating the above format till you have enough information to answer the question without using any more tools.
|
|
92
|
+
At that point, you MUST respond in the one of the following two formats (and do not include any Action):
|
|
92
93
|
|
|
93
94
|
```
|
|
94
95
|
Thought: I can answer without using any more tools. I'll use the user's language to answer
|
|
95
|
-
Answer: [your answer here (In the same language as the user's question)]
|
|
96
|
+
Answer: [your answer here (In the same language as the user's question, and maintain any references/citations)]
|
|
96
97
|
```
|
|
97
98
|
|
|
98
99
|
```
|
|
99
100
|
Thought: I cannot answer the question with the provided tools.
|
|
100
|
-
Answer: [your answer here (In the same language as the user's question)]
|
|
101
|
+
Answer: [your answer here (In the same language as the user's question, and maintain any references/citations)]
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
## Current Conversation
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module contains the Agent class for handling different types of agents and their interactions.
|
|
3
3
|
"""
|
|
4
|
-
|
|
5
|
-
from typing import List, Callable, Optional
|
|
4
|
+
from typing import List, Callable, Optional, Dict, Any
|
|
6
5
|
import os
|
|
7
6
|
from datetime import date
|
|
8
7
|
import time
|
|
8
|
+
import json
|
|
9
|
+
import dill
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
logger = logging.getLogger('opentelemetry.exporter.otlp.proto.http.trace_exporter')
|
|
13
|
+
logger.setLevel(logging.CRITICAL)
|
|
9
14
|
|
|
10
15
|
from retrying import retry
|
|
11
16
|
from pydantic import Field, create_model
|
|
12
17
|
|
|
13
|
-
|
|
14
18
|
from llama_index.core.tools import FunctionTool
|
|
15
19
|
from llama_index.core.agent import ReActAgent
|
|
16
20
|
from llama_index.core.agent.react.formatter import ReActChatFormatter
|
|
@@ -20,15 +24,18 @@ from llama_index.core.callbacks.base_handler import BaseCallbackHandler
|
|
|
20
24
|
from llama_index.agent.openai import OpenAIAgent
|
|
21
25
|
from llama_index.core.memory import ChatMemoryBuffer
|
|
22
26
|
from llama_index.core import set_global_handler
|
|
27
|
+
from llama_index.core.tools.types import ToolMetadata
|
|
23
28
|
|
|
29
|
+
import phoenix as px
|
|
24
30
|
|
|
25
31
|
from dotenv import load_dotenv
|
|
26
32
|
|
|
27
|
-
from .types import AgentType, AgentStatusType, LLMRole, ObserverType
|
|
33
|
+
from .types import AgentType, AgentStatusType, LLMRole, ObserverType, ToolType
|
|
28
34
|
from .utils import get_llm, get_tokenizer_for_model
|
|
29
35
|
from ._prompts import REACT_PROMPT_TEMPLATE, GENERAL_PROMPT_TEMPLATE
|
|
30
36
|
from ._callback import AgentCallbackHandler
|
|
31
|
-
from .tools import VectaraToolFactory
|
|
37
|
+
from .tools import VectaraToolFactory, VectaraTool
|
|
38
|
+
|
|
32
39
|
|
|
33
40
|
load_dotenv(override=True)
|
|
34
41
|
|
|
@@ -64,7 +71,6 @@ class Agent:
|
|
|
64
71
|
"""
|
|
65
72
|
Agent class for handling different types of agents and their interactions.
|
|
66
73
|
"""
|
|
67
|
-
|
|
68
74
|
def __init__(
|
|
69
75
|
self,
|
|
70
76
|
tools: list[FunctionTool],
|
|
@@ -72,6 +78,7 @@ class Agent:
|
|
|
72
78
|
custom_instructions: str = "",
|
|
73
79
|
verbose: bool = True,
|
|
74
80
|
update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
81
|
+
agent_type: AgentType = AgentType(os.getenv("VECTARA_AGENTIC_AGENT_TYPE", "OPENAI")),
|
|
75
82
|
) -> None:
|
|
76
83
|
"""
|
|
77
84
|
Initialize the agent with the specified type, tools, topic, and system message.
|
|
@@ -84,7 +91,7 @@ class Agent:
|
|
|
84
91
|
verbose (bool, optional): Whether the agent should print its steps. Defaults to True.
|
|
85
92
|
update_func (Callable): A callback function the code calls on any agent updates.
|
|
86
93
|
"""
|
|
87
|
-
self.agent_type =
|
|
94
|
+
self.agent_type = agent_type
|
|
88
95
|
self.tools = tools
|
|
89
96
|
self.llm = get_llm(LLMRole.MAIN)
|
|
90
97
|
self._custom_instructions = custom_instructions
|
|
@@ -113,7 +120,7 @@ class Agent:
|
|
|
113
120
|
memory=memory,
|
|
114
121
|
verbose=verbose,
|
|
115
122
|
react_chat_formatter=ReActChatFormatter(system_header=prompt),
|
|
116
|
-
max_iterations=
|
|
123
|
+
max_iterations=30,
|
|
117
124
|
callable_manager=callback_manager,
|
|
118
125
|
)
|
|
119
126
|
elif self.agent_type == AgentType.OPENAI:
|
|
@@ -124,7 +131,7 @@ class Agent:
|
|
|
124
131
|
memory=memory,
|
|
125
132
|
verbose=verbose,
|
|
126
133
|
callable_manager=callback_manager,
|
|
127
|
-
max_function_calls=
|
|
134
|
+
max_function_calls=20,
|
|
128
135
|
system_prompt=prompt,
|
|
129
136
|
)
|
|
130
137
|
elif self.agent_type == AgentType.LLMCOMPILER:
|
|
@@ -139,11 +146,55 @@ class Agent:
|
|
|
139
146
|
|
|
140
147
|
observer = ObserverType(os.getenv("VECTARA_AGENTIC_OBSERVER_TYPE", "NO_OBSERVER"))
|
|
141
148
|
if observer == ObserverType.ARIZE_PHOENIX:
|
|
142
|
-
|
|
143
|
-
|
|
149
|
+
if os.environ.get("OTEL_EXPORTER_OTLP_HEADERS", None):
|
|
150
|
+
set_global_handler("arize_phoenix", endpoint="https://llamatrace.com/v1/traces")
|
|
151
|
+
print("Arize Phoenix observer set. https://llamatrace.com")
|
|
152
|
+
else:
|
|
153
|
+
px.launch_app()
|
|
154
|
+
set_global_handler("arize_phoenix", endpoint="http://localhost:6006/v1/traces")
|
|
155
|
+
print("Arize Phoenix observer set. http://localhost:6006/.")
|
|
144
156
|
else:
|
|
145
157
|
print("No observer set.")
|
|
146
158
|
|
|
159
|
+
def __eq__(self, other):
|
|
160
|
+
if not isinstance(other, Agent):
|
|
161
|
+
print(f"Comparison failed: other is not an instance of Agent. (self: {type(self)}, other: {type(other)})")
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
# Compare agent_type
|
|
165
|
+
if self.agent_type != other.agent_type:
|
|
166
|
+
print(f"Comparison failed: agent_type differs. (self.agent_type: {self.agent_type}, other.agent_type: {other.agent_type})")
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
# Compare tools
|
|
170
|
+
if self.tools != other.tools:
|
|
171
|
+
print(f"Comparison failed: tools differ. (self.tools: {self.tools}, other.tools: {other.tools})")
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
# Compare topic
|
|
175
|
+
if self._topic != other._topic:
|
|
176
|
+
print(f"Comparison failed: topic differs. (self.topic: {self._topic}, other.topic: {other._topic})")
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
# Compare custom_instructions
|
|
180
|
+
if self._custom_instructions != other._custom_instructions:
|
|
181
|
+
print(f"Comparison failed: custom_instructions differ. (self.custom_instructions: {self._custom_instructions}, other.custom_instructions: {other._custom_instructions})")
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
# Compare verbose
|
|
185
|
+
if self.verbose != other.verbose:
|
|
186
|
+
print(f"Comparison failed: verbose differs. (self.verbose: {self.verbose}, other.verbose: {other.verbose})")
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
# Compare agent
|
|
190
|
+
if self.agent.memory.chat_store != other.agent.memory.chat_store:
|
|
191
|
+
print(f"Comparison failed: agent memory differs. (self.agent: {repr(self.agent.memory.chat_store)}, other.agent: {repr(other.agent.memory.chat_store)})")
|
|
192
|
+
return False
|
|
193
|
+
|
|
194
|
+
# If all comparisons pass
|
|
195
|
+
print("All comparisons passed. Objects are equal.")
|
|
196
|
+
return True
|
|
197
|
+
|
|
147
198
|
@classmethod
|
|
148
199
|
def from_tools(
|
|
149
200
|
cls,
|
|
@@ -174,11 +225,11 @@ class Agent:
|
|
|
174
225
|
def from_corpus(
|
|
175
226
|
cls,
|
|
176
227
|
tool_name: str,
|
|
177
|
-
vectara_customer_id: str,
|
|
178
|
-
vectara_corpus_id: str,
|
|
179
|
-
vectara_api_key: str,
|
|
180
228
|
data_description: str,
|
|
181
229
|
assistant_specialty: str,
|
|
230
|
+
vectara_customer_id: str = str(os.environ.get("VECTARA_CUSTOMER_ID", "")),
|
|
231
|
+
vectara_corpus_id: str = str(os.environ.get("VECTARA_CORPUS_ID", "")),
|
|
232
|
+
vectara_api_key: str = str(os.environ.get("VECTARA_API_KEY", "")),
|
|
182
233
|
verbose: bool = False,
|
|
183
234
|
vectara_filter_fields: list[dict] = [],
|
|
184
235
|
vectara_lambda_val: float = 0.005,
|
|
@@ -195,12 +246,12 @@ class Agent:
|
|
|
195
246
|
Args:
|
|
196
247
|
tool_name (str): The name of Vectara tool used by the agent
|
|
197
248
|
vectara_customer_id (str): The Vectara customer ID.
|
|
198
|
-
vectara_corpus_id (str): The Vectara corpus ID.
|
|
249
|
+
vectara_corpus_id (str): The Vectara corpus ID (or comma separated list of IDs).
|
|
199
250
|
vectara_api_key (str): The Vectara API key.
|
|
200
251
|
data_description (str): The description of the data.
|
|
201
252
|
assistant_specialty (str): The specialty of the assistant.
|
|
202
253
|
verbose (bool, optional): Whether to print verbose output.
|
|
203
|
-
vectara_filter_fields (List[dict], optional): The filterable attributes (each dict
|
|
254
|
+
vectara_filter_fields (List[dict], optional): The filterable attributes (each dict maps field name to Tuple[type, description]).
|
|
204
255
|
vectara_lambda_val (float, optional): The lambda value for Vectara hybrid search.
|
|
205
256
|
vectara_reranker (str, optional): The Vectara reranker name (default "mmr")
|
|
206
257
|
vectara_rerank_k (int, optional): The number of results to use with reranking.
|
|
@@ -216,9 +267,10 @@ class Agent:
|
|
|
216
267
|
vectara_customer_id=vectara_customer_id,
|
|
217
268
|
vectara_corpus_id=vectara_corpus_id)
|
|
218
269
|
field_definitions = {}
|
|
219
|
-
field_definitions['query'] = (str, Field(description="The user query"))
|
|
270
|
+
field_definitions['query'] = (str, Field(description="The user query")) # type: ignore
|
|
220
271
|
for field in vectara_filter_fields:
|
|
221
|
-
field_definitions[field['name']] = (eval(field['type']),
|
|
272
|
+
field_definitions[field['name']] = (eval(field['type']),
|
|
273
|
+
Field(description=field['description'])) # type: ignore
|
|
222
274
|
QueryArgs = create_model( # type: ignore
|
|
223
275
|
"QueryArgs",
|
|
224
276
|
**field_definitions
|
|
@@ -307,3 +359,121 @@ class Agent:
|
|
|
307
359
|
except Exception as e:
|
|
308
360
|
import traceback
|
|
309
361
|
return f"Vectara Agentic: encountered an exception ({e}) at ({traceback.format_exc()}), and can't respond."
|
|
362
|
+
|
|
363
|
+
# Serialization methods
|
|
364
|
+
|
|
365
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
366
|
+
"""Serialize the Agent instance to a dictionary."""
|
|
367
|
+
tool_info = []
|
|
368
|
+
|
|
369
|
+
for tool in self.tools:
|
|
370
|
+
tool_dict = {
|
|
371
|
+
"tool_type": tool.tool_type.value,
|
|
372
|
+
"name": tool._metadata.name,
|
|
373
|
+
"description": tool._metadata.description,
|
|
374
|
+
"fn": dill.dumps(tool.fn).decode('latin-1') if tool.fn else None, # Serialize fn
|
|
375
|
+
"async_fn": dill.dumps(tool.async_fn).decode('latin-1') if tool.async_fn else None, # Serialize async_fn
|
|
376
|
+
}
|
|
377
|
+
tool_info.append(tool_dict)
|
|
378
|
+
|
|
379
|
+
return {
|
|
380
|
+
"agent_type": self.agent_type.value,
|
|
381
|
+
"tools": tool_info,
|
|
382
|
+
"topic": self._topic,
|
|
383
|
+
"custom_instructions": self._custom_instructions,
|
|
384
|
+
"verbose": self.verbose,
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def dumps(self) -> str:
|
|
389
|
+
"""Serialize the Agent instance to a JSON string."""
|
|
390
|
+
return json.dumps(self.to_dict())
|
|
391
|
+
|
|
392
|
+
@classmethod
|
|
393
|
+
def loads(cls, data: str) -> "Agent":
|
|
394
|
+
"""Create an Agent instance from a JSON string."""
|
|
395
|
+
return cls.from_dict(json.loads(data))
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
399
|
+
"""Serialize the Agent instance to a dictionary."""
|
|
400
|
+
tool_info = []
|
|
401
|
+
|
|
402
|
+
for tool in self.tools:
|
|
403
|
+
# Serialize each tool's metadata, function, and dynamic model schema (QueryArgs)
|
|
404
|
+
tool_dict = {
|
|
405
|
+
"tool_type": tool.tool_type.value,
|
|
406
|
+
"name": tool._metadata.name,
|
|
407
|
+
"description": tool._metadata.description,
|
|
408
|
+
"fn": dill.dumps(tool.fn).decode('latin-1') if tool.fn else None, # Serialize fn
|
|
409
|
+
"async_fn": dill.dumps(tool.async_fn).decode('latin-1') if tool.async_fn else None, # Serialize async_fn
|
|
410
|
+
"fn_schema": tool._metadata.fn_schema.model_json_schema() if hasattr(tool._metadata, 'fn_schema') else None, # Serialize schema if available
|
|
411
|
+
}
|
|
412
|
+
tool_info.append(tool_dict)
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
"agent_type": self.agent_type.value,
|
|
416
|
+
"memory": dill.dumps(self.agent.memory).decode('latin-1'),
|
|
417
|
+
"tools": tool_info,
|
|
418
|
+
"topic": self._topic,
|
|
419
|
+
"custom_instructions": self._custom_instructions,
|
|
420
|
+
"verbose": self.verbose,
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
@classmethod
|
|
424
|
+
def from_dict(cls, data: Dict[str, Any]) -> "Agent":
|
|
425
|
+
"""Create an Agent instance from a dictionary."""
|
|
426
|
+
agent_type = AgentType(data["agent_type"])
|
|
427
|
+
tools = []
|
|
428
|
+
|
|
429
|
+
JSON_TYPE_TO_PYTHON = {
|
|
430
|
+
"string": "str",
|
|
431
|
+
"integer": "int",
|
|
432
|
+
"boolean": "bool",
|
|
433
|
+
"array": "list",
|
|
434
|
+
"object": "dict",
|
|
435
|
+
"number": "float",
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
for tool_data in data["tools"]:
|
|
439
|
+
# Recreate the dynamic model using the schema info
|
|
440
|
+
if tool_data.get("fn_schema"):
|
|
441
|
+
field_definitions = {}
|
|
442
|
+
for field,values in tool_data["fn_schema"]["properties"].items():
|
|
443
|
+
if 'default' in values:
|
|
444
|
+
field_definitions[field] = (eval(JSON_TYPE_TO_PYTHON.get(values['type'], values['type'])),
|
|
445
|
+
Field(description=values['description'], default=values['default'])) # type: ignore
|
|
446
|
+
else:
|
|
447
|
+
field_definitions[field] = (eval(JSON_TYPE_TO_PYTHON.get(values['type'], values['type'])),
|
|
448
|
+
Field(description=values['description'])) # type: ignore
|
|
449
|
+
query_args_model = create_model( # type: ignore
|
|
450
|
+
"QueryArgs",
|
|
451
|
+
**field_definitions
|
|
452
|
+
)
|
|
453
|
+
else:
|
|
454
|
+
query_args_model = create_model("QueryArgs")
|
|
455
|
+
|
|
456
|
+
fn = dill.loads(tool_data["fn"].encode('latin-1')) if tool_data["fn"] else None
|
|
457
|
+
async_fn = dill.loads(tool_data["async_fn"].encode('latin-1')) if tool_data["async_fn"] else None
|
|
458
|
+
|
|
459
|
+
tool = VectaraTool.from_defaults(
|
|
460
|
+
tool_type=ToolType(tool_data["tool_type"]),
|
|
461
|
+
name=tool_data["name"],
|
|
462
|
+
description=tool_data["description"],
|
|
463
|
+
fn=fn,
|
|
464
|
+
async_fn=async_fn,
|
|
465
|
+
fn_schema=query_args_model # Re-assign the recreated dynamic model
|
|
466
|
+
)
|
|
467
|
+
tools.append(tool)
|
|
468
|
+
|
|
469
|
+
agent = cls(
|
|
470
|
+
tools=tools,
|
|
471
|
+
agent_type=agent_type,
|
|
472
|
+
topic=data["topic"],
|
|
473
|
+
custom_instructions=data["custom_instructions"],
|
|
474
|
+
verbose=data["verbose"],
|
|
475
|
+
)
|
|
476
|
+
memory = dill.loads(data["memory"].encode('latin-1')) if data.get("memory") else None
|
|
477
|
+
if memory:
|
|
478
|
+
agent.agent.memory = memory
|
|
479
|
+
return agent
|
|
@@ -5,6 +5,7 @@ This module contains the ToolsFactory class for creating agent tools.
|
|
|
5
5
|
import inspect
|
|
6
6
|
import re
|
|
7
7
|
import importlib
|
|
8
|
+
import os
|
|
8
9
|
|
|
9
10
|
from typing import Callable, List, Any, Optional, Type
|
|
10
11
|
from pydantic import BaseModel, Field
|
|
@@ -80,12 +81,31 @@ class VectaraTool(FunctionTool):
|
|
|
80
81
|
tool = FunctionTool.from_defaults(fn, name, description, return_direct, fn_schema, async_fn, tool_metadata)
|
|
81
82
|
vectara_tool = cls(
|
|
82
83
|
tool_type=tool_type,
|
|
83
|
-
fn=tool.
|
|
84
|
-
metadata=tool.
|
|
85
|
-
async_fn=tool.
|
|
84
|
+
fn=tool._fn,
|
|
85
|
+
metadata=tool._metadata,
|
|
86
|
+
async_fn=tool._async_fn
|
|
86
87
|
)
|
|
87
88
|
return vectara_tool
|
|
88
89
|
|
|
90
|
+
def __eq__(self, other):
|
|
91
|
+
if self.tool_type != other.tool_type:
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
# Check if fn_schema is an instance of a BaseModel or a class itself (metaclass)
|
|
95
|
+
self_schema_dict = self.metadata.fn_schema.model_fields
|
|
96
|
+
other_schema_dict = other.metadata.fn_schema.model_fields
|
|
97
|
+
is_equal = True
|
|
98
|
+
for key in self_schema_dict.keys():
|
|
99
|
+
if key not in other_schema_dict:
|
|
100
|
+
is_equal = False
|
|
101
|
+
break
|
|
102
|
+
if (self_schema_dict[key].annotation != other_schema_dict[key].annotation or
|
|
103
|
+
self_schema_dict[key].description != other_schema_dict[key].description or
|
|
104
|
+
self_schema_dict[key].is_required() != other_schema_dict[key].is_required()):
|
|
105
|
+
is_equal = False
|
|
106
|
+
break
|
|
107
|
+
return is_equal
|
|
108
|
+
|
|
89
109
|
|
|
90
110
|
class VectaraToolFactory:
|
|
91
111
|
"""
|
|
@@ -94,20 +114,21 @@ class VectaraToolFactory:
|
|
|
94
114
|
|
|
95
115
|
def __init__(
|
|
96
116
|
self,
|
|
97
|
-
vectara_customer_id: str,
|
|
98
|
-
vectara_corpus_id: str,
|
|
99
|
-
vectara_api_key: str,
|
|
117
|
+
vectara_customer_id: str = str(os.environ.get("VECTARA_CUSTOMER_ID", "")),
|
|
118
|
+
vectara_corpus_id: str = str(os.environ.get("VECTARA_CORPUS_ID", "")),
|
|
119
|
+
vectara_api_key: str = str(os.environ.get("VECTARA_API_KEY", "")),
|
|
100
120
|
) -> None:
|
|
101
121
|
"""
|
|
102
122
|
Initialize the VectaraToolFactory
|
|
103
123
|
Args:
|
|
104
124
|
vectara_customer_id (str): The Vectara customer ID.
|
|
105
|
-
vectara_corpus_id (str): The Vectara corpus ID.
|
|
125
|
+
vectara_corpus_id (str): The Vectara corpus ID (or comma separated list of IDs).
|
|
106
126
|
vectara_api_key (str): The Vectara API key.
|
|
107
127
|
"""
|
|
108
128
|
self.vectara_customer_id = vectara_customer_id
|
|
109
129
|
self.vectara_corpus_id = vectara_corpus_id
|
|
110
130
|
self.vectara_api_key = vectara_api_key
|
|
131
|
+
self.num_corpora = len(vectara_corpus_id.split(","))
|
|
111
132
|
|
|
112
133
|
def create_rag_tool(
|
|
113
134
|
self,
|
|
@@ -154,6 +175,7 @@ class VectaraToolFactory:
|
|
|
154
175
|
vectara_api_key=self.vectara_api_key,
|
|
155
176
|
vectara_customer_id=self.vectara_customer_id,
|
|
156
177
|
vectara_corpus_id=self.vectara_corpus_id,
|
|
178
|
+
x_source_str="vectara-agentic"
|
|
157
179
|
)
|
|
158
180
|
|
|
159
181
|
def _build_filter_string(kwargs):
|
|
@@ -186,7 +208,7 @@ class VectaraToolFactory:
|
|
|
186
208
|
summary_response_lang=summary_response_lang,
|
|
187
209
|
summary_prompt_name=vectara_summarizer,
|
|
188
210
|
reranker=reranker,
|
|
189
|
-
rerank_k=rerank_k,
|
|
211
|
+
rerank_k=rerank_k if rerank_k*self.num_corpora<=100 else int(100/self.num_corpora),
|
|
190
212
|
mmr_diversity_bias=mmr_diversity_bias,
|
|
191
213
|
n_sentence_before=n_sentences_before,
|
|
192
214
|
n_sentence_after=n_sentences_after,
|
|
@@ -233,17 +255,18 @@ class VectaraToolFactory:
|
|
|
233
255
|
raw_output={'response': msg}
|
|
234
256
|
)
|
|
235
257
|
|
|
236
|
-
|
|
237
258
|
res = {
|
|
238
259
|
"response": response.response,
|
|
239
260
|
"references_metadata": citation_metadata,
|
|
240
261
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
262
|
+
if len(citation_metadata) > 0:
|
|
263
|
+
tool_output = f"""
|
|
264
|
+
Response: '''{res['response']}'''
|
|
265
|
+
References:
|
|
266
|
+
{res['references_metadata']}
|
|
267
|
+
"""
|
|
268
|
+
else:
|
|
269
|
+
tool_output = f"Response: '''{res['response']}'''"
|
|
247
270
|
out = ToolOutput(
|
|
248
271
|
tool_name=rag_function.__name__,
|
|
249
272
|
content=tool_output,
|
|
@@ -252,7 +275,7 @@ class VectaraToolFactory:
|
|
|
252
275
|
)
|
|
253
276
|
return out
|
|
254
277
|
|
|
255
|
-
fields = tool_args_schema.
|
|
278
|
+
fields = tool_args_schema.model_fields
|
|
256
279
|
params = [
|
|
257
280
|
inspect.Parameter(
|
|
258
281
|
name=field_name,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vectara_agentic
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: A Python package for creating AI Assistants and AI Agents with Vectara
|
|
5
5
|
Home-page: https://github.com/vectara/py-vectara-agentic
|
|
6
6
|
Author: Ofer Mendelevitch
|
|
@@ -31,11 +31,13 @@ Requires-Dist: llama-index-tools-arxiv==0.2.0
|
|
|
31
31
|
Requires-Dist: llama-index-tools-database==0.2.0
|
|
32
32
|
Requires-Dist: llama-index-tools-google==0.2.0
|
|
33
33
|
Requires-Dist: llama-index-tools-tavily_research==0.2.0
|
|
34
|
+
Requires-Dist: llama-index-callbacks-arize-phoenix==0.2.1
|
|
34
35
|
Requires-Dist: pydantic==2.8.2
|
|
35
36
|
Requires-Dist: retrying==1.3.4
|
|
36
|
-
Requires-Dist: pymongo==4.6.
|
|
37
|
+
Requires-Dist: pymongo==4.6.3
|
|
37
38
|
Requires-Dist: python-dotenv==1.0.1
|
|
38
39
|
Requires-Dist: tiktoken==0.7.0
|
|
40
|
+
Requires-Dist: dill==0.3.8
|
|
39
41
|
|
|
40
42
|
# vectara-agentic
|
|
41
43
|
|
|
@@ -63,7 +65,7 @@ Requires-Dist: tiktoken==0.7.0
|
|
|
63
65
|
- [Vectara account](https://console.vectara.com/signup/?utm_source=github&utm_medium=code&utm_term=DevRel&utm_content=vectara-agentic&utm_campaign=github-code-DevRel-vectara-agentic)
|
|
64
66
|
- A Vectara corpus with an [API key](https://docs.vectara.com/docs/api-keys)
|
|
65
67
|
- [Python 3.10 or higher](https://www.python.org/downloads/)
|
|
66
|
-
- OpenAI API key (or API keys for Anthropic, TOGETHER.AI, Fireworks AI, Cohere
|
|
68
|
+
- OpenAI API key (or API keys for Anthropic, TOGETHER.AI, Fireworks AI, Cohere or GROQ)
|
|
67
69
|
|
|
68
70
|
## Installation
|
|
69
71
|
|
|
@@ -97,6 +99,8 @@ query_financial_reports = vec_factory.create_rag_tool(
|
|
|
97
99
|
)
|
|
98
100
|
```
|
|
99
101
|
|
|
102
|
+
Note that `VECTARA_CORPUS_ID` can be a single ID or a comma-separated list of IDs.
|
|
103
|
+
|
|
100
104
|
2. **Create other tools (optional)**
|
|
101
105
|
|
|
102
106
|
In addition to RAG tools, you can generate a lot of other types of tools the agent can use. These could be mathematical tools, tools
|
|
@@ -181,6 +185,29 @@ The `Agent` class defines a few helpful methods to help you understand the inter
|
|
|
181
185
|
* The `report()` method prints out the agent object’s type, the tools, and the LLMs used for the main agent and tool calling.
|
|
182
186
|
* The `token_counts()` method tells you how many tokens you have used in the current session for both the main agent and tool calling LLMs. This can be helpful if you want to track spend by token.
|
|
183
187
|
|
|
188
|
+
## Serialization
|
|
189
|
+
|
|
190
|
+
The `Agent` class supports serialization. Use the `dumps()` to serialize and `loads()` to read back from a serialized stream.
|
|
191
|
+
|
|
192
|
+
## Observability
|
|
193
|
+
|
|
194
|
+
vectara-agentic supports observability via the existing integration of LlamaIndex and Arize Phoenix.
|
|
195
|
+
To enable tracing of your vectara-agentic assistant, follow these steps (adapted from [here](https://docs.llamaindex.ai/en/stable/module_guides/observability/)):
|
|
196
|
+
1. Go to `https://llamatrace.com/login` an create an account, then create an API key and put it in the `PHOENIX_API_KEY` variable
|
|
197
|
+
2. `os["VECTARA_AGENTIC_OBSERVER_TYPE"] = "ARIZE_PHOENIX"`: to enable Arize Phoenix observability
|
|
198
|
+
3. `os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}"`
|
|
199
|
+
|
|
200
|
+
Now when you run your agent, all metrics are sent to LlamaTrace and recorded. You can view them at `https://llamatrace.com`.
|
|
201
|
+
If you do not include the `OTEL_EXPORTER_OTLP_HEADERS` a local instance of Arize Phoenix will be setup instead and you can view it at `http://localhost:6006`
|
|
202
|
+
|
|
203
|
+
## About Custom Instructions
|
|
204
|
+
|
|
205
|
+
The custom instructions you provide to the agent guide its behavior.
|
|
206
|
+
Here are some guidelines when creating your instructions:
|
|
207
|
+
- Write precise and clear instructions, without overcomplicating.
|
|
208
|
+
- Consider edge cases and unusual or atypical scenarios.
|
|
209
|
+
- Be cautious to not over-specify behavior based on your primary use-case, as it may limit the agent's ability to behave properly in others.
|
|
210
|
+
|
|
184
211
|
## Examples
|
|
185
212
|
|
|
186
213
|
Check out our example AI assistants:
|
|
@@ -13,8 +13,10 @@ llama-index-tools-arxiv==0.2.0
|
|
|
13
13
|
llama-index-tools-database==0.2.0
|
|
14
14
|
llama-index-tools-google==0.2.0
|
|
15
15
|
llama-index-tools-tavily_research==0.2.0
|
|
16
|
+
llama-index-callbacks-arize-phoenix==0.2.1
|
|
16
17
|
pydantic==2.8.2
|
|
17
18
|
retrying==1.3.4
|
|
18
|
-
pymongo==4.6.
|
|
19
|
+
pymongo==4.6.3
|
|
19
20
|
python-dotenv==1.0.1
|
|
20
21
|
tiktoken==0.7.0
|
|
22
|
+
dill==0.3.8
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vectara_agentic-0.1.8 → vectara_agentic-0.1.10}/vectara_agentic.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|