vectara-agentic 0.1.4__tar.gz → 0.1.5__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.4/vectara_agentic.egg-info → vectara_agentic-0.1.5}/PKG-INFO +3 -2
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/README.md +1 -1
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/requirements.txt +1 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/setup.py +1 -1
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/tests/test_agent.py +2 -2
- vectara_agentic-0.1.5/vectara_agentic/agent.py +283 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/tools.py +53 -56
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/utils.py +22 -6
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5/vectara_agentic.egg-info}/PKG-INFO +3 -2
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic.egg-info/requires.txt +1 -0
- vectara_agentic-0.1.4/vectara_agentic/agent.py +0 -172
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/LICENSE +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/MANIFEST.in +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/setup.cfg +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/tests/test_tools.py +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/__init__.py +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/_callback.py +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/_prompts.py +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/tools_catalog.py +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic/types.py +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic.egg-info/SOURCES.txt +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/vectara_agentic.egg-info/dependency_links.txt +0 -0
- {vectara_agentic-0.1.4 → vectara_agentic-0.1.5}/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.5
|
|
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
|
|
@@ -37,6 +37,7 @@ Requires-Dist: pylint==3.2.6
|
|
|
37
37
|
Requires-Dist: flake8==7.1.0
|
|
38
38
|
Requires-Dist: pymongo==4.6.1
|
|
39
39
|
Requires-Dist: python-dotenv==1.0.1
|
|
40
|
+
Requires-Dist: tiktoken==0.7.0
|
|
40
41
|
|
|
41
42
|
# vectara-agentic
|
|
42
43
|
|
|
@@ -202,7 +203,7 @@ We have created a few example AI assistants that you can look at for inspiration
|
|
|
202
203
|
## 🤝 Contributing
|
|
203
204
|
|
|
204
205
|
Contributions, issues and feature requests are welcome and appreciated!<br />
|
|
205
|
-
Feel free to check [issues page](https://github.com/vectara/py-vectara-agentic/issues). You can also take a look at the [contributing guide](https://github.com/vectara/py-vectara-agentic/blob/
|
|
206
|
+
Feel free to check [issues page](https://github.com/vectara/py-vectara-agentic/issues). You can also take a look at the [contributing guide](https://github.com/vectara/py-vectara-agentic/blob/main/CONTRIBUTING.md).
|
|
206
207
|
|
|
207
208
|
## Show your support
|
|
208
209
|
|
|
@@ -162,7 +162,7 @@ We have created a few example AI assistants that you can look at for inspiration
|
|
|
162
162
|
## 🤝 Contributing
|
|
163
163
|
|
|
164
164
|
Contributions, issues and feature requests are welcome and appreciated!<br />
|
|
165
|
-
Feel free to check [issues page](https://github.com/vectara/py-vectara-agentic/issues). You can also take a look at the [contributing guide](https://github.com/vectara/py-vectara-agentic/blob/
|
|
165
|
+
Feel free to check [issues page](https://github.com/vectara/py-vectara-agentic/issues). You can also take a look at the [contributing guide](https://github.com/vectara/py-vectara-agentic/blob/main/CONTRIBUTING.md).
|
|
166
166
|
|
|
167
167
|
## Show your support
|
|
168
168
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from datetime import date
|
|
3
3
|
|
|
4
|
-
from vectara_agentic.agent import
|
|
4
|
+
from vectara_agentic.agent import _get_prompt, Agent, AgentType, FunctionTool
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class TestAgentPackage(unittest.TestCase):
|
|
@@ -15,7 +15,7 @@ class TestAgentPackage(unittest.TestCase):
|
|
|
15
15
|
+ " with Always do as your mother tells you!"
|
|
16
16
|
)
|
|
17
17
|
self.assertEqual(
|
|
18
|
-
|
|
18
|
+
_get_prompt(prompt_template, topic, custom_instructions), expected_output
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
def test_agent_init(self):
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the Agent class for handling different types of agents and their interactions.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Callable, Optional
|
|
6
|
+
import os
|
|
7
|
+
from datetime import date
|
|
8
|
+
|
|
9
|
+
from retrying import retry
|
|
10
|
+
from pydantic import Field, create_model
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
from llama_index.core.tools import FunctionTool
|
|
14
|
+
from llama_index.core.agent import ReActAgent
|
|
15
|
+
from llama_index.core.agent.react.formatter import ReActChatFormatter
|
|
16
|
+
from llama_index.core.callbacks import CallbackManager, TokenCountingHandler
|
|
17
|
+
from llama_index.agent.openai import OpenAIAgent
|
|
18
|
+
from llama_index.core.memory import ChatMemoryBuffer
|
|
19
|
+
|
|
20
|
+
from dotenv import load_dotenv
|
|
21
|
+
|
|
22
|
+
from .types import AgentType, AgentStatusType, LLMRole
|
|
23
|
+
from .utils import get_llm, get_tokenizer_for_model
|
|
24
|
+
from ._prompts import REACT_PROMPT_TEMPLATE, GENERAL_PROMPT_TEMPLATE
|
|
25
|
+
from ._callback import AgentCallbackHandler
|
|
26
|
+
from .tools import VectaraToolFactory
|
|
27
|
+
|
|
28
|
+
load_dotenv(override=True)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _get_prompt(prompt_template: str, topic: str, custom_instructions: str):
|
|
32
|
+
"""
|
|
33
|
+
Generate a prompt by replacing placeholders with topic and date.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
|
|
37
|
+
prompt_template (str): The template for the prompt.
|
|
38
|
+
topic (str): The topic to be included in the prompt.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
str: The formatted prompt.
|
|
42
|
+
"""
|
|
43
|
+
return (
|
|
44
|
+
prompt_template.replace("{chat_topic}", topic)
|
|
45
|
+
.replace("{today}", date.today().strftime("%A, %B %d, %Y"))
|
|
46
|
+
.replace("{custom_instructions}", custom_instructions)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _retry_if_exception(exception):
|
|
51
|
+
# Define the condition to retry on certain exceptions
|
|
52
|
+
return isinstance(
|
|
53
|
+
exception, (TimeoutError)
|
|
54
|
+
) # Replace SomeOtherException with other exceptions you want to catch
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Agent:
|
|
58
|
+
"""
|
|
59
|
+
Agent class for handling different types of agents and their interactions.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
tools: list[FunctionTool],
|
|
65
|
+
topic: str = "general",
|
|
66
|
+
custom_instructions: str = "",
|
|
67
|
+
verbose: bool = True,
|
|
68
|
+
update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Initialize the agent with the specified type, tools, topic, and system message.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
|
|
75
|
+
tools (list[FunctionTool]): A list of tools to be used by the agent.
|
|
76
|
+
topic (str, optional): The topic for the agent. Defaults to 'general'.
|
|
77
|
+
custom_instructions (str, optional): custom instructions for the agent. Defaults to ''.
|
|
78
|
+
update_func (Callable): a callback function the code calls on any agent updates.
|
|
79
|
+
"""
|
|
80
|
+
self.agent_type = AgentType(os.getenv("VECTARA_AGENTIC_AGENT_TYPE", "OPENAI"))
|
|
81
|
+
self.tools = tools
|
|
82
|
+
self.llm = get_llm(LLMRole.MAIN)
|
|
83
|
+
self._custom_instructions = custom_instructions
|
|
84
|
+
self._topic = topic
|
|
85
|
+
|
|
86
|
+
main_tok = get_tokenizer_for_model(role=LLMRole.MAIN)
|
|
87
|
+
self.main_token_counter = TokenCountingHandler(tokenizer = main_tok) if main_tok else None
|
|
88
|
+
tool_tok = get_tokenizer_for_model(role=LLMRole.TOOL)
|
|
89
|
+
self.tool_token_counter = TokenCountingHandler(tokenizer = tool_tok) if tool_tok else None
|
|
90
|
+
|
|
91
|
+
callbacks = [AgentCallbackHandler(update_func)]
|
|
92
|
+
if self.main_token_counter:
|
|
93
|
+
callbacks.append(self.main_token_counter)
|
|
94
|
+
if self.tool_token_counter:
|
|
95
|
+
callbacks.append(self.tool_token_counter)
|
|
96
|
+
callback_manager = CallbackManager(callbacks) # type: ignore
|
|
97
|
+
self.llm.callback_manager = callback_manager
|
|
98
|
+
|
|
99
|
+
memory = ChatMemoryBuffer.from_defaults(token_limit=128000)
|
|
100
|
+
if self.agent_type == AgentType.REACT:
|
|
101
|
+
prompt = _get_prompt(REACT_PROMPT_TEMPLATE, topic, custom_instructions)
|
|
102
|
+
self.agent = ReActAgent.from_tools(
|
|
103
|
+
tools=tools,
|
|
104
|
+
llm=self.llm,
|
|
105
|
+
memory=memory,
|
|
106
|
+
verbose=verbose,
|
|
107
|
+
react_chat_formatter=ReActChatFormatter(system_header=prompt),
|
|
108
|
+
max_iterations=20,
|
|
109
|
+
callable_manager=callback_manager,
|
|
110
|
+
)
|
|
111
|
+
elif self.agent_type == AgentType.OPENAI:
|
|
112
|
+
prompt = _get_prompt(GENERAL_PROMPT_TEMPLATE, topic, custom_instructions)
|
|
113
|
+
self.agent = OpenAIAgent.from_tools(
|
|
114
|
+
tools=tools,
|
|
115
|
+
llm=self.llm,
|
|
116
|
+
memory=memory,
|
|
117
|
+
verbose=verbose,
|
|
118
|
+
callable_manager=callback_manager,
|
|
119
|
+
max_function_calls=10,
|
|
120
|
+
system_prompt=prompt,
|
|
121
|
+
)
|
|
122
|
+
else:
|
|
123
|
+
raise ValueError(f"Unknown agent type: {self.agent_type}")
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def from_tools(
|
|
127
|
+
cls,
|
|
128
|
+
tools: List[FunctionTool],
|
|
129
|
+
topic: str = "general",
|
|
130
|
+
custom_instructions: str = "",
|
|
131
|
+
verbose: bool = True,
|
|
132
|
+
update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
133
|
+
) -> "Agent":
|
|
134
|
+
"""
|
|
135
|
+
Create an agent from tools, agent type, and language model.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
|
|
139
|
+
tools (list[FunctionTool]): A list of tools to be used by the agent.
|
|
140
|
+
topic (str, optional): The topic for the agent. Defaults to 'general'.
|
|
141
|
+
custom_instructions (str, optional): custom instructions for the agent. Defaults to ''.
|
|
142
|
+
llm (LLM): The language model to be used by the agent.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Agent: An instance of the Agent class.
|
|
146
|
+
"""
|
|
147
|
+
return cls(tools, topic, custom_instructions, verbose, update_func)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def from_corpus(
|
|
152
|
+
cls,
|
|
153
|
+
vectara_customer_id: str,
|
|
154
|
+
vectara_corpus_id: str,
|
|
155
|
+
vectara_api_key: str,
|
|
156
|
+
data_description: str,
|
|
157
|
+
assistant_specialty: str,
|
|
158
|
+
verbose: bool = False,
|
|
159
|
+
vectara_filter_fields: list[dict] = [],
|
|
160
|
+
vectara_lambda_val: float = 0.005,
|
|
161
|
+
vectara_reranker: str = "mmr",
|
|
162
|
+
vectara_rerank_k: int = 50,
|
|
163
|
+
vectara_n_sentences_before: int = 2,
|
|
164
|
+
vectara_n_sentences_after: int = 2,
|
|
165
|
+
vectara_summary_num_results: int = 10,
|
|
166
|
+
vectara_summarizer: str = "vectara-summary-ext-24-05-sml",
|
|
167
|
+
) -> "Agent":
|
|
168
|
+
"""
|
|
169
|
+
Create an agent from a single Vectara corpus
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
name (str): The name .
|
|
173
|
+
vectara_customer_id (str): The Vectara customer ID.
|
|
174
|
+
vectara_corpus_id (str): The Vectara corpus ID.
|
|
175
|
+
vectara_api_key (str): The Vectara API key.
|
|
176
|
+
data_description (str): The description of the data.
|
|
177
|
+
assistant_specialty (str): The specialty of the assistant.
|
|
178
|
+
verbose (bool): Whether to print verbose output.
|
|
179
|
+
vectara_filter_fields (List[dict]): The filterable attributes (each dict includes name, type, and description).
|
|
180
|
+
vectara_lambda_val (float): The lambda value for Vectara hybrid search.
|
|
181
|
+
vectara_reranker (str): The Vectara reranker name (default "mmr")
|
|
182
|
+
vectara_rerank_k (int): The number of results to use with reranking.
|
|
183
|
+
vectara_n_sentences_before (int): The number of sentences before the matching text
|
|
184
|
+
vectara_n_sentences_after (int): The number of sentences after the matching text.
|
|
185
|
+
vectara_summary_num_results (int): The number of results to use in summarization.
|
|
186
|
+
vectara_summarizer (str): The Vectara summarizer name.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Agent: An instance of the Agent class.
|
|
190
|
+
"""
|
|
191
|
+
vec_factory = VectaraToolFactory(vectara_api_key=vectara_api_key,
|
|
192
|
+
vectara_customer_id=vectara_customer_id,
|
|
193
|
+
vectara_corpus_id=vectara_corpus_id)
|
|
194
|
+
QueryArgs = create_model(
|
|
195
|
+
"QueryArgs",
|
|
196
|
+
query=(str, Field(description="The user query")),
|
|
197
|
+
**{
|
|
198
|
+
field['name']: (field['type'], Field(description=field['description'], default=None))
|
|
199
|
+
for field in vectara_filter_fields
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
vectara_tool = vec_factory.create_rag_tool(
|
|
204
|
+
tool_name = f"vectara_{vectara_corpus_id}",
|
|
205
|
+
tool_description = f"""
|
|
206
|
+
Given a user query,
|
|
207
|
+
returns a response (str) to a user question about {data_description}.
|
|
208
|
+
""",
|
|
209
|
+
tool_args_schema = QueryArgs,
|
|
210
|
+
reranker = vectara_reranker, rerank_k = vectara_rerank_k,
|
|
211
|
+
n_sentences_before = vectara_n_sentences_before,
|
|
212
|
+
n_sentences_after = vectara_n_sentences_after,
|
|
213
|
+
lambda_val = vectara_lambda_val,
|
|
214
|
+
summary_num_results = vectara_summary_num_results,
|
|
215
|
+
vectara_summarizer = vectara_summarizer,
|
|
216
|
+
include_citations = False,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
assistant_instructions = f"""
|
|
220
|
+
- You are a helpful {assistant_specialty} assistant.
|
|
221
|
+
- You can answer questions about {data_description}.
|
|
222
|
+
- Never discuss politics, and always respond politely.
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
return cls(
|
|
226
|
+
tools=[vectara_tool],
|
|
227
|
+
topic=assistant_specialty,
|
|
228
|
+
custom_instructions=assistant_instructions,
|
|
229
|
+
verbose=verbose,
|
|
230
|
+
update_func=None
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def report(self) -> str:
|
|
234
|
+
"""
|
|
235
|
+
Get a report from the agent.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
str: The report from the agent.
|
|
239
|
+
"""
|
|
240
|
+
print("Vectara agentic Report:")
|
|
241
|
+
print(f"Agent Type = {self.agent_type}")
|
|
242
|
+
print(f"Topic = {self._topic}")
|
|
243
|
+
print("Tools:")
|
|
244
|
+
for tool in self.tools:
|
|
245
|
+
print(f"- {tool._metadata.name}")
|
|
246
|
+
print(f"Agent LLM = {get_llm(LLMRole.MAIN).model}")
|
|
247
|
+
print(f"Tool LLM = {get_llm(LLMRole.TOOL).model}")
|
|
248
|
+
|
|
249
|
+
def token_counts(self) -> dict:
|
|
250
|
+
"""
|
|
251
|
+
Get the token counts for the agent and tools.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
dict: The token counts for the agent and tools.
|
|
255
|
+
"""
|
|
256
|
+
return {
|
|
257
|
+
"main token count": self.main_token_counter.total_llm_token_count if self.main_token_counter else -1,
|
|
258
|
+
"tool token count": self.tool_token_counter.total_llm_token_count if self.tool_token_counter else -1,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@retry(
|
|
262
|
+
retry_on_exception=_retry_if_exception,
|
|
263
|
+
stop_max_attempt_number=3,
|
|
264
|
+
wait_fixed=2000,
|
|
265
|
+
)
|
|
266
|
+
def chat(self, prompt: str) -> str:
|
|
267
|
+
"""
|
|
268
|
+
Interact with the agent using a chat prompt.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
prompt (str): The chat prompt.
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
str: The response from the agent.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
agent_response = self.agent.chat(prompt)
|
|
279
|
+
return agent_response.response
|
|
280
|
+
except Exception as e:
|
|
281
|
+
import traceback
|
|
282
|
+
|
|
283
|
+
return f"Vectara Agentic: encountered an exception ({e}) at ({traceback.format_exc()}), and can't respond."
|
|
@@ -13,6 +13,8 @@ from llama_index.core.tools import FunctionTool
|
|
|
13
13
|
from llama_index.core.base.response.schema import Response
|
|
14
14
|
from llama_index.indices.managed.vectara import VectaraIndex
|
|
15
15
|
from llama_index.core.utilities.sql_wrapper import SQLDatabase
|
|
16
|
+
from llama_index.core.tools.types import AsyncBaseTool, ToolMetadata
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
from .types import ToolType
|
|
18
20
|
from .tools_catalog import (
|
|
@@ -49,7 +51,7 @@ LI_packages = {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
class VectaraTool:
|
|
54
|
+
class VectaraTool(AsyncBaseTool):
|
|
53
55
|
"""
|
|
54
56
|
A wrapper of FunctionTool class for Vectara tools, adding the tool_type attribute.
|
|
55
57
|
"""
|
|
@@ -63,6 +65,26 @@ class VectaraTool:
|
|
|
63
65
|
|
|
64
66
|
def __call__(self, *args, **kwargs):
|
|
65
67
|
return self.function_tool(*args, **kwargs)
|
|
68
|
+
|
|
69
|
+
def call(self, *args, **kwargs):
|
|
70
|
+
return self.function_tool.call(*args, **kwargs)
|
|
71
|
+
|
|
72
|
+
def acall(self, *args, **kwargs):
|
|
73
|
+
return self.function_tool.acall(*args, **kwargs)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def metadata(self) -> ToolMetadata:
|
|
77
|
+
"""Metadata."""
|
|
78
|
+
return self.function_tool.metadata
|
|
79
|
+
|
|
80
|
+
def __repr__(self):
|
|
81
|
+
repr_str = f"""
|
|
82
|
+
Name: {self.function_tool._metadata.name}
|
|
83
|
+
Tool Type: {self.tool_type}
|
|
84
|
+
Description: {self.function_tool._metadata.description}
|
|
85
|
+
Schema: {inspect.signature(self.function_tool._metadata.fn_schema)}
|
|
86
|
+
"""
|
|
87
|
+
return repr_str
|
|
66
88
|
|
|
67
89
|
|
|
68
90
|
class VectaraToolFactory:
|
|
@@ -76,6 +98,13 @@ class VectaraToolFactory:
|
|
|
76
98
|
vectara_corpus_id: str,
|
|
77
99
|
vectara_api_key: str,
|
|
78
100
|
) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Initialize the VectaraToolFactory
|
|
103
|
+
Args:
|
|
104
|
+
vectara_customer_id (str): The Vectara customer ID.
|
|
105
|
+
vectara_corpus_id (str): The Vectara corpus ID.
|
|
106
|
+
vectara_api_key (str): The Vectara API key.
|
|
107
|
+
"""
|
|
79
108
|
self.vectara_customer_id = vectara_customer_id
|
|
80
109
|
self.vectara_corpus_id = vectara_corpus_id
|
|
81
110
|
self.vectara_api_key = vectara_api_key
|
|
@@ -100,7 +129,6 @@ class VectaraToolFactory:
|
|
|
100
129
|
Creates a RAG (Retrieve and Generate) tool.
|
|
101
130
|
|
|
102
131
|
Args:
|
|
103
|
-
|
|
104
132
|
tool_name (str): The name of the tool.
|
|
105
133
|
tool_description (str): The description of the tool.
|
|
106
134
|
tool_args_schema (BaseModel): The schema for the tool arguments.
|
|
@@ -125,7 +153,7 @@ class VectaraToolFactory:
|
|
|
125
153
|
vectara_corpus_id=self.vectara_corpus_id,
|
|
126
154
|
)
|
|
127
155
|
|
|
128
|
-
def
|
|
156
|
+
def _build_filter_string(kwargs):
|
|
129
157
|
filter_parts = []
|
|
130
158
|
for key, value in kwargs.items():
|
|
131
159
|
if value:
|
|
@@ -147,7 +175,7 @@ class VectaraToolFactory:
|
|
|
147
175
|
kwargs = bound_args.arguments
|
|
148
176
|
|
|
149
177
|
query = kwargs.pop("query")
|
|
150
|
-
filter_string =
|
|
178
|
+
filter_string = _build_filter_string(kwargs)
|
|
151
179
|
|
|
152
180
|
vectara_query_engine = vectara.as_query_engine(
|
|
153
181
|
summary_enabled=True,
|
|
@@ -189,65 +217,28 @@ class VectaraToolFactory:
|
|
|
189
217
|
}
|
|
190
218
|
return res
|
|
191
219
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
default
|
|
198
|
-
|
|
199
|
-
default = param.default_factory()
|
|
200
|
-
|
|
201
|
-
parameters.append(
|
|
202
|
-
inspect.Parameter(
|
|
203
|
-
name,
|
|
204
|
-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
205
|
-
default=default,
|
|
206
|
-
annotation=param.type_ if param.required else Optional[param.type_],
|
|
207
|
-
)
|
|
208
|
-
)
|
|
209
|
-
if (
|
|
210
|
-
"query" not in tool_args_schema.__fields__
|
|
211
|
-
): # Add 'query' parameter if it's not already in the schema
|
|
212
|
-
parameters.append(
|
|
213
|
-
inspect.Parameter(
|
|
214
|
-
"query", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=str
|
|
215
|
-
)
|
|
220
|
+
fields = tool_args_schema.__fields__
|
|
221
|
+
params = [
|
|
222
|
+
inspect.Parameter(
|
|
223
|
+
name=field_name,
|
|
224
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
225
|
+
default=field_info.default,
|
|
226
|
+
annotation=field_info.field_info,
|
|
216
227
|
)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
# Set the function name and docstring
|
|
221
|
-
doc_string = f"{tool_description}\n\n"
|
|
222
|
-
doc_string += "Parameters:\n"
|
|
223
|
-
for field_name, field in tool_args_schema.__fields__.items():
|
|
224
|
-
type_name = field.type_.__name__
|
|
225
|
-
if field.allow_none:
|
|
226
|
-
type_name = f"Optional[{type_name}]"
|
|
227
|
-
|
|
228
|
-
default_info = ""
|
|
229
|
-
if field.default is not None:
|
|
230
|
-
default_info = f" (default: {field.default})"
|
|
231
|
-
elif field.default_factory is not None:
|
|
232
|
-
default_info = " (default: set by factory)"
|
|
233
|
-
|
|
234
|
-
doc_string += f"- {field_name} ({type_name}): {field.field_info.description}{default_info}\n"
|
|
235
|
-
|
|
236
|
-
doc_string += "\nReturns: a dict[str, Any] with the following:\n"
|
|
237
|
-
doc_string += (
|
|
238
|
-
"- response: The response string in markdown format with citations.\n"
|
|
239
|
-
)
|
|
240
|
-
doc_string += "- citation_metadata: a dictionary of metadata for each citation included in the response string.\n"
|
|
241
|
-
doc_string += "- response_factual_consistency: a value representing confidence in the response being factually correct (1.0=high, 0.0=low).\n"
|
|
228
|
+
for field_name, field_info in fields.items()
|
|
229
|
+
]
|
|
242
230
|
|
|
231
|
+
# Create a new signature using the extracted parameters
|
|
232
|
+
sig = inspect.Signature(params)
|
|
233
|
+
rag_function.__signature__ = sig
|
|
234
|
+
rag_function.__annotations__['return'] = dict[str, Any]
|
|
243
235
|
rag_function.__name__ = "_" + re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
|
|
244
|
-
rag_function.__doc__ = doc_string
|
|
245
236
|
|
|
246
237
|
# Create the tool
|
|
247
238
|
tool = FunctionTool.from_defaults(
|
|
248
239
|
fn=rag_function,
|
|
249
240
|
name=tool_name,
|
|
250
|
-
description=
|
|
241
|
+
description=tool_description,
|
|
251
242
|
fn_schema=tool_args_schema,
|
|
252
243
|
)
|
|
253
244
|
return VectaraTool(tool, ToolType.QUERY)
|
|
@@ -283,7 +274,7 @@ class ToolsFactory:
|
|
|
283
274
|
"""
|
|
284
275
|
Get a tool from the llama_index hub.
|
|
285
276
|
|
|
286
|
-
|
|
277
|
+
Args:
|
|
287
278
|
tool_package_name (str): The name of the tool package.
|
|
288
279
|
tool_spec_name (str): The name of the tool spec.
|
|
289
280
|
tool_name_prefix (str): The prefix to add to the tool names (added to every tool in the spec).
|
|
@@ -329,6 +320,9 @@ class ToolsFactory:
|
|
|
329
320
|
return [self.create_tool(tool) for tool in [summarize_text, rephrase_text]]
|
|
330
321
|
|
|
331
322
|
def guardrail_tools(self) -> List[FunctionTool]:
|
|
323
|
+
"""
|
|
324
|
+
Create a list of guardrail tools to avoid controversial topics.
|
|
325
|
+
"""
|
|
332
326
|
return [
|
|
333
327
|
self.create_tool(tool)
|
|
334
328
|
for tool in [guardrails_no_politics, guardrails_be_polite]
|
|
@@ -341,6 +335,9 @@ class ToolsFactory:
|
|
|
341
335
|
return self.get_llama_index_tools("yahoo_finance", "YahooFinanceToolSpec")
|
|
342
336
|
|
|
343
337
|
def legal_tools(self) -> List[FunctionTool]:
|
|
338
|
+
"""
|
|
339
|
+
Create a list of legal tools.
|
|
340
|
+
"""
|
|
344
341
|
def summarize_legal_text(
|
|
345
342
|
text: str = Field(description="the original text."),
|
|
346
343
|
) -> str:
|
|
@@ -10,23 +10,22 @@ from llama_index.llms.anthropic import Anthropic
|
|
|
10
10
|
from llama_index.llms.together import TogetherLLM
|
|
11
11
|
from llama_index.llms.groq import Groq
|
|
12
12
|
from llama_index.llms.fireworks import Fireworks
|
|
13
|
+
import tiktoken
|
|
13
14
|
|
|
14
15
|
from .types import LLMRole, AgentType, ModelProvider
|
|
15
16
|
|
|
16
17
|
provider_to_default_model_name = {
|
|
17
|
-
ModelProvider.OPENAI: "gpt-4o",
|
|
18
|
+
ModelProvider.OPENAI: "gpt-4o-2024-08-06",
|
|
18
19
|
ModelProvider.ANTHROPIC: "claude-3-5-sonnet-20240620",
|
|
19
20
|
ModelProvider.TOGETHER: "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
|
|
20
|
-
ModelProvider.GROQ: "
|
|
21
|
+
ModelProvider.GROQ: "llama3-groq-70b-8192-tool-use-preview",
|
|
21
22
|
ModelProvider.FIREWORKS: "accounts/fireworks/models/firefunction-v2",
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
DEFAULT_MODEL_PROVIDER = ModelProvider.OPENAI
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"""Get the LLM for the specified role."""
|
|
29
|
-
agent_type = AgentType(os.getenv("VECTARA_AGENTIC_AGENT_TYPE", AgentType.OPENAI))
|
|
27
|
+
def _get_llm_params_for_role(role: LLMRole) -> tuple[str, str]:
|
|
28
|
+
"""Get the model provider and model name for the specified role."""
|
|
30
29
|
if role == LLMRole.TOOL:
|
|
31
30
|
model_provider = ModelProvider(
|
|
32
31
|
os.getenv("VECTARA_AGENTIC_TOOL_LLM_PROVIDER", DEFAULT_MODEL_PROVIDER)
|
|
@@ -44,6 +43,7 @@ def get_llm(role: LLMRole) -> LLM:
|
|
|
44
43
|
provider_to_default_model_name.get(model_provider),
|
|
45
44
|
)
|
|
46
45
|
|
|
46
|
+
agent_type = AgentType(os.getenv("VECTARA_AGENTIC_AGENT_TYPE", AgentType.OPENAI))
|
|
47
47
|
if (
|
|
48
48
|
role == LLMRole.MAIN
|
|
49
49
|
and agent_type == AgentType.OPENAI
|
|
@@ -53,6 +53,22 @@ def get_llm(role: LLMRole) -> LLM:
|
|
|
53
53
|
"OpenAI agent requested but main model provider is not OpenAI."
|
|
54
54
|
)
|
|
55
55
|
|
|
56
|
+
return model_provider, model_name
|
|
57
|
+
|
|
58
|
+
def get_tokenizer_for_model(role: LLMRole) -> str:
|
|
59
|
+
"""Get the tokenizer for the specified model."""
|
|
60
|
+
model_provider, model_name = _get_llm_params_for_role(role)
|
|
61
|
+
if model_provider == ModelProvider.OPENAI:
|
|
62
|
+
return tiktoken.encoding_for_model(model_name).encode
|
|
63
|
+
elif model_provider == ModelProvider.ANTHROPIC:
|
|
64
|
+
return Anthropic().tokenizer
|
|
65
|
+
else:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def get_llm(role: LLMRole) -> LLM:
|
|
69
|
+
"""Get the LLM for the specified role."""
|
|
70
|
+
model_provider, model_name = _get_llm_params_for_role(role)
|
|
71
|
+
|
|
56
72
|
if model_provider == ModelProvider.OPENAI:
|
|
57
73
|
llm = OpenAI(model=model_name, temperature=0)
|
|
58
74
|
elif model_provider == ModelProvider.ANTHROPIC:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vectara_agentic
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
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
|
|
@@ -37,6 +37,7 @@ Requires-Dist: pylint==3.2.6
|
|
|
37
37
|
Requires-Dist: flake8==7.1.0
|
|
38
38
|
Requires-Dist: pymongo==4.6.1
|
|
39
39
|
Requires-Dist: python-dotenv==1.0.1
|
|
40
|
+
Requires-Dist: tiktoken==0.7.0
|
|
40
41
|
|
|
41
42
|
# vectara-agentic
|
|
42
43
|
|
|
@@ -202,7 +203,7 @@ We have created a few example AI assistants that you can look at for inspiration
|
|
|
202
203
|
## 🤝 Contributing
|
|
203
204
|
|
|
204
205
|
Contributions, issues and feature requests are welcome and appreciated!<br />
|
|
205
|
-
Feel free to check [issues page](https://github.com/vectara/py-vectara-agentic/issues). You can also take a look at the [contributing guide](https://github.com/vectara/py-vectara-agentic/blob/
|
|
206
|
+
Feel free to check [issues page](https://github.com/vectara/py-vectara-agentic/issues). You can also take a look at the [contributing guide](https://github.com/vectara/py-vectara-agentic/blob/main/CONTRIBUTING.md).
|
|
206
207
|
|
|
207
208
|
## Show your support
|
|
208
209
|
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module contains the Agent class for handling different types of agents and their interactions.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import List, Callable, Optional
|
|
6
|
-
import os
|
|
7
|
-
from datetime import date
|
|
8
|
-
|
|
9
|
-
from retrying import retry
|
|
10
|
-
|
|
11
|
-
from llama_index.core.tools import FunctionTool
|
|
12
|
-
from llama_index.core.agent import ReActAgent
|
|
13
|
-
from llama_index.core.agent.react.formatter import ReActChatFormatter
|
|
14
|
-
from llama_index.core.callbacks import CallbackManager
|
|
15
|
-
from llama_index.agent.openai import OpenAIAgent
|
|
16
|
-
from llama_index.core.memory import ChatMemoryBuffer
|
|
17
|
-
|
|
18
|
-
from dotenv import load_dotenv
|
|
19
|
-
|
|
20
|
-
from .types import AgentType, AgentStatusType, LLMRole
|
|
21
|
-
from .utils import get_llm
|
|
22
|
-
from ._prompts import REACT_PROMPT_TEMPLATE, GENERAL_PROMPT_TEMPLATE
|
|
23
|
-
from ._callback import AgentCallbackHandler
|
|
24
|
-
|
|
25
|
-
load_dotenv(override=True)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def get_prompt(prompt_template: str, topic: str, custom_instructions: str):
|
|
29
|
-
"""
|
|
30
|
-
Generate a prompt by replacing placeholders with topic and date.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
|
|
34
|
-
prompt_template (str): The template for the prompt.
|
|
35
|
-
topic (str): The topic to be included in the prompt.
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
str: The formatted prompt.
|
|
39
|
-
"""
|
|
40
|
-
return (
|
|
41
|
-
prompt_template.replace("{chat_topic}", topic)
|
|
42
|
-
.replace("{today}", date.today().strftime("%A, %B %d, %Y"))
|
|
43
|
-
.replace("{custom_instructions}", custom_instructions)
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def retry_if_exception(exception):
|
|
48
|
-
# Define the condition to retry on certain exceptions
|
|
49
|
-
return isinstance(
|
|
50
|
-
exception, (TimeoutError)
|
|
51
|
-
) # Replace SomeOtherException with other exceptions you want to catch
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class Agent:
|
|
55
|
-
"""
|
|
56
|
-
Agent class for handling different types of agents and their interactions.
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
def __init__(
|
|
60
|
-
self,
|
|
61
|
-
tools: list[FunctionTool],
|
|
62
|
-
topic: str = "general",
|
|
63
|
-
custom_instructions: str = "",
|
|
64
|
-
update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
65
|
-
):
|
|
66
|
-
"""
|
|
67
|
-
Initialize the agent with the specified type, tools, topic, and system message.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
|
|
71
|
-
tools (list[FunctionTool]): A list of tools to be used by the agent.
|
|
72
|
-
topic (str, optional): The topic for the agent. Defaults to 'general'.
|
|
73
|
-
custom_instructions (str, optional): custom instructions for the agent. Defaults to ''.
|
|
74
|
-
update_func (Callable): a callback function the code calls on any agent updates.
|
|
75
|
-
"""
|
|
76
|
-
self.agent_type = AgentType(os.getenv("VECTARA_AGENTIC_AGENT_TYPE", "OPENAI"))
|
|
77
|
-
self.tools = tools
|
|
78
|
-
self.llm = get_llm(LLMRole.MAIN)
|
|
79
|
-
self._custom_instructions = custom_instructions
|
|
80
|
-
self._topic = topic
|
|
81
|
-
|
|
82
|
-
callback_manager = CallbackManager([AgentCallbackHandler(update_func)]) # type: ignore
|
|
83
|
-
self.llm.callback_manager = callback_manager
|
|
84
|
-
|
|
85
|
-
memory = ChatMemoryBuffer.from_defaults(token_limit=128000)
|
|
86
|
-
if self.agent_type == AgentType.REACT:
|
|
87
|
-
prompt = get_prompt(REACT_PROMPT_TEMPLATE, topic, custom_instructions)
|
|
88
|
-
self.agent = ReActAgent.from_tools(
|
|
89
|
-
tools=tools,
|
|
90
|
-
llm=self.llm,
|
|
91
|
-
memory=memory,
|
|
92
|
-
verbose=True,
|
|
93
|
-
react_chat_formatter=ReActChatFormatter(system_header=prompt),
|
|
94
|
-
max_iterations=20,
|
|
95
|
-
callable_manager=callback_manager,
|
|
96
|
-
)
|
|
97
|
-
elif self.agent_type == AgentType.OPENAI:
|
|
98
|
-
prompt = get_prompt(GENERAL_PROMPT_TEMPLATE, topic, custom_instructions)
|
|
99
|
-
self.agent = OpenAIAgent.from_tools(
|
|
100
|
-
tools=tools,
|
|
101
|
-
llm=self.llm,
|
|
102
|
-
memory=memory,
|
|
103
|
-
verbose=True,
|
|
104
|
-
callable_manager=callback_manager,
|
|
105
|
-
max_function_calls=10,
|
|
106
|
-
system_prompt=prompt,
|
|
107
|
-
)
|
|
108
|
-
else:
|
|
109
|
-
raise ValueError(f"Unknown agent type: {self.agent_type}")
|
|
110
|
-
|
|
111
|
-
@classmethod
|
|
112
|
-
def from_tools(
|
|
113
|
-
cls,
|
|
114
|
-
tools: List[FunctionTool],
|
|
115
|
-
topic: str = "general",
|
|
116
|
-
custom_instructions: str = "",
|
|
117
|
-
update_func: Optional[Callable[[AgentStatusType, str], None]] = None,
|
|
118
|
-
) -> "Agent":
|
|
119
|
-
"""
|
|
120
|
-
Create an agent from tools, agent type, and language model.
|
|
121
|
-
|
|
122
|
-
Args:
|
|
123
|
-
|
|
124
|
-
tools (list[FunctionTool]): A list of tools to be used by the agent.
|
|
125
|
-
topic (str, optional): The topic for the agent. Defaults to 'general'.
|
|
126
|
-
custom_instructions (str, optional): custom instructions for the agent. Defaults to ''.
|
|
127
|
-
llm (LLM): The language model to be used by the agent.
|
|
128
|
-
|
|
129
|
-
Returns:
|
|
130
|
-
Agent: An instance of the Agent class.
|
|
131
|
-
"""
|
|
132
|
-
return cls(tools, topic, custom_instructions, update_func)
|
|
133
|
-
|
|
134
|
-
def report(self) -> str:
|
|
135
|
-
"""
|
|
136
|
-
Get a report from the agent.
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
str: The report from the agent.
|
|
140
|
-
"""
|
|
141
|
-
print("Vectara agentic Report:")
|
|
142
|
-
print(f"Agent Type = {self.agent_type}")
|
|
143
|
-
print(f"Topic = {self._topic}")
|
|
144
|
-
print("Tools:")
|
|
145
|
-
for tool in self.tools:
|
|
146
|
-
print(f"- {tool._metadata.name}")
|
|
147
|
-
print(f"Agent LLM = {get_llm(LLMRole.MAIN).model}")
|
|
148
|
-
print(f"Tool LLM = {get_llm(LLMRole.TOOL).model}")
|
|
149
|
-
|
|
150
|
-
@retry(
|
|
151
|
-
retry_on_exception=retry_if_exception,
|
|
152
|
-
stop_max_attempt_number=3,
|
|
153
|
-
wait_fixed=2000,
|
|
154
|
-
)
|
|
155
|
-
def chat(self, prompt: str) -> str:
|
|
156
|
-
"""
|
|
157
|
-
Interact with the agent using a chat prompt.
|
|
158
|
-
|
|
159
|
-
Args:
|
|
160
|
-
prompt (str): The chat prompt.
|
|
161
|
-
|
|
162
|
-
Returns:
|
|
163
|
-
str: The response from the agent.
|
|
164
|
-
"""
|
|
165
|
-
|
|
166
|
-
try:
|
|
167
|
-
agent_response = self.agent.chat(prompt)
|
|
168
|
-
return agent_response.response
|
|
169
|
-
except Exception as e:
|
|
170
|
-
import traceback
|
|
171
|
-
|
|
172
|
-
return f"Vectara Agentic: encountered an exception ({e}) at ({traceback.format_exc()}), and can't respond."
|
|
File without changes
|
|
File without changes
|
|
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.4 → vectara_agentic-0.1.5}/vectara_agentic.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|