llama-index-tools-database 0.0.1__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.
- llama_index_tools_database-0.0.1/PKG-INFO +53 -0
- llama_index_tools_database-0.0.1/README.md +36 -0
- llama_index_tools_database-0.0.1/llama_index/tools/database/__init__.py +6 -0
- llama_index_tools_database-0.0.1/llama_index/tools/database/base.py +135 -0
- llama_index_tools_database-0.0.1/pyproject.toml +49 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: llama-index-tools-database
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: llama-index tools database integration
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: you@example.com
|
|
8
|
+
Requires-Python: >=3.8.1,<3.12
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Requires-Dist: llama-index-core (>=0.9.32,<0.10.0)
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# Database Tool
|
|
18
|
+
|
|
19
|
+
This tool connects to a database (using SQLAlchemy under the hood) and allows an Agent to query the database and get information about the tables.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
This tool has more extensive example usage documented in a Jupyter notebook [here](https://github.com/emptycrown/llama-hub/tree/main/llama_hub/tools/notebooks/database.ipynb) and [here](https://github.com/emptycrown/llama-hub/tree/main/llama_hub/tools/notebooks/intro_to_tools.ipynb)
|
|
24
|
+
|
|
25
|
+
Here's an example usage of the DatabaseToolSpec.
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from llama_index.tools.database import DatabaseToolSpec
|
|
29
|
+
from llama_index.agent import OpenAIAgent
|
|
30
|
+
|
|
31
|
+
db_tools = DatabaseToolSpec(
|
|
32
|
+
scheme="postgresql", # Database Scheme
|
|
33
|
+
host="localhost", # Database Host
|
|
34
|
+
port="5432", # Database Port
|
|
35
|
+
user="postgres", # Database User
|
|
36
|
+
password="FakeExamplePassword", # Database Password
|
|
37
|
+
dbname="postgres", # Database Name
|
|
38
|
+
)
|
|
39
|
+
agent = OpenAIAgent.from_tools(db_tools.to_tool_list())
|
|
40
|
+
|
|
41
|
+
agent.chat("What tables does this database contain")
|
|
42
|
+
agent.chat("Describe the first table")
|
|
43
|
+
agent.chat("Retrieve the first row of that table")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The tools available are:
|
|
47
|
+
|
|
48
|
+
`list_tables`: A tool to list the tables in the database schema
|
|
49
|
+
`describe_tables`: A tool to describe the schema of a table
|
|
50
|
+
`load_data`: A tool that accepts an SQL query and returns the result
|
|
51
|
+
|
|
52
|
+
This loader is designed to be used as a way to load data as a Tool in a Agent. See [here](https://github.com/emptycrown/llama-hub/tree/main) for examples.
|
|
53
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Database Tool
|
|
2
|
+
|
|
3
|
+
This tool connects to a database (using SQLAlchemy under the hood) and allows an Agent to query the database and get information about the tables.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
This tool has more extensive example usage documented in a Jupyter notebook [here](https://github.com/emptycrown/llama-hub/tree/main/llama_hub/tools/notebooks/database.ipynb) and [here](https://github.com/emptycrown/llama-hub/tree/main/llama_hub/tools/notebooks/intro_to_tools.ipynb)
|
|
8
|
+
|
|
9
|
+
Here's an example usage of the DatabaseToolSpec.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from llama_index.tools.database import DatabaseToolSpec
|
|
13
|
+
from llama_index.agent import OpenAIAgent
|
|
14
|
+
|
|
15
|
+
db_tools = DatabaseToolSpec(
|
|
16
|
+
scheme="postgresql", # Database Scheme
|
|
17
|
+
host="localhost", # Database Host
|
|
18
|
+
port="5432", # Database Port
|
|
19
|
+
user="postgres", # Database User
|
|
20
|
+
password="FakeExamplePassword", # Database Password
|
|
21
|
+
dbname="postgres", # Database Name
|
|
22
|
+
)
|
|
23
|
+
agent = OpenAIAgent.from_tools(db_tools.to_tool_list())
|
|
24
|
+
|
|
25
|
+
agent.chat("What tables does this database contain")
|
|
26
|
+
agent.chat("Describe the first table")
|
|
27
|
+
agent.chat("Retrieve the first row of that table")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The tools available are:
|
|
31
|
+
|
|
32
|
+
`list_tables`: A tool to list the tables in the database schema
|
|
33
|
+
`describe_tables`: A tool to describe the schema of a table
|
|
34
|
+
`load_data`: A tool that accepts an SQL query and returns the result
|
|
35
|
+
|
|
36
|
+
This loader is designed to be used as a way to load data as a Tool in a Agent. See [here](https://github.com/emptycrown/llama-hub/tree/main) for examples.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Database Tool."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, List, Optional
|
|
4
|
+
|
|
5
|
+
from llama_index.core.utilities.sql_wrapper import SQLDatabase
|
|
6
|
+
from llama_index.core.readers.base import BaseReader
|
|
7
|
+
from llama_index.core.schema import Document
|
|
8
|
+
from llama_index.core.tools.tool_spec.base import BaseToolSpec
|
|
9
|
+
from sqlalchemy import MetaData, text
|
|
10
|
+
from sqlalchemy.engine import Engine
|
|
11
|
+
from sqlalchemy.exc import NoSuchTableError
|
|
12
|
+
from sqlalchemy.schema import CreateTable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DatabaseToolSpec(BaseToolSpec, BaseReader):
|
|
16
|
+
"""Simple Database tool.
|
|
17
|
+
|
|
18
|
+
Concatenates each row into Document used by LlamaIndex.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
sql_database (Optional[SQLDatabase]): SQL database to use,
|
|
22
|
+
including table names to specify.
|
|
23
|
+
See :ref:`Ref-Struct-Store` for more details.
|
|
24
|
+
|
|
25
|
+
OR
|
|
26
|
+
|
|
27
|
+
engine (Optional[Engine]): SQLAlchemy Engine object of the database connection.
|
|
28
|
+
|
|
29
|
+
OR
|
|
30
|
+
|
|
31
|
+
uri (Optional[str]): uri of the database connection.
|
|
32
|
+
|
|
33
|
+
OR
|
|
34
|
+
|
|
35
|
+
scheme (Optional[str]): scheme of the database connection.
|
|
36
|
+
host (Optional[str]): host of the database connection.
|
|
37
|
+
port (Optional[int]): port of the database connection.
|
|
38
|
+
user (Optional[str]): user of the database connection.
|
|
39
|
+
password (Optional[str]): password of the database connection.
|
|
40
|
+
dbname (Optional[str]): dbname of the database connection.
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
spec_functions = ["load_data", "describe_tables", "list_tables"]
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
sql_database: Optional[SQLDatabase] = None,
|
|
49
|
+
engine: Optional[Engine] = None,
|
|
50
|
+
uri: Optional[str] = None,
|
|
51
|
+
scheme: Optional[str] = None,
|
|
52
|
+
host: Optional[str] = None,
|
|
53
|
+
port: Optional[str] = None,
|
|
54
|
+
user: Optional[str] = None,
|
|
55
|
+
password: Optional[str] = None,
|
|
56
|
+
dbname: Optional[str] = None,
|
|
57
|
+
*args: Optional[Any],
|
|
58
|
+
**kwargs: Optional[Any],
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Initialize with parameters."""
|
|
61
|
+
if sql_database:
|
|
62
|
+
self.sql_database = sql_database
|
|
63
|
+
elif engine:
|
|
64
|
+
self.sql_database = SQLDatabase(engine, *args, **kwargs)
|
|
65
|
+
elif uri:
|
|
66
|
+
self.uri = uri
|
|
67
|
+
self.sql_database = SQLDatabase.from_uri(uri, *args, **kwargs)
|
|
68
|
+
elif scheme and host and port and user and password and dbname:
|
|
69
|
+
uri = f"{scheme}://{user}:{password}@{host}:{port}/{dbname}"
|
|
70
|
+
self.uri = uri
|
|
71
|
+
self.sql_database = SQLDatabase.from_uri(uri, *args, **kwargs)
|
|
72
|
+
else:
|
|
73
|
+
raise ValueError(
|
|
74
|
+
"You must provide either a SQLDatabase, "
|
|
75
|
+
"a SQL Alchemy Engine, a valid connection URI, or a valid "
|
|
76
|
+
"set of credentials."
|
|
77
|
+
)
|
|
78
|
+
self._metadata = MetaData()
|
|
79
|
+
self._metadata.reflect(bind=self.sql_database.engine)
|
|
80
|
+
|
|
81
|
+
def load_data(self, query: str) -> List[Document]:
|
|
82
|
+
"""Query and load data from the Database, returning a list of Documents.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
query (str): an SQL query to filter tables and rows.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
List[Document]: A list of Document objects.
|
|
89
|
+
"""
|
|
90
|
+
documents = []
|
|
91
|
+
with self.sql_database.engine.connect() as connection:
|
|
92
|
+
if query is None:
|
|
93
|
+
raise ValueError("A query parameter is necessary to filter the data")
|
|
94
|
+
else:
|
|
95
|
+
result = connection.execute(text(query))
|
|
96
|
+
|
|
97
|
+
for item in result.fetchall():
|
|
98
|
+
# fetch each item
|
|
99
|
+
doc_str = ", ".join([str(entry) for entry in item])
|
|
100
|
+
documents.append(Document(text=doc_str))
|
|
101
|
+
return documents
|
|
102
|
+
|
|
103
|
+
def list_tables(self) -> List[str]:
|
|
104
|
+
"""
|
|
105
|
+
Returns a list of available tables in the database.
|
|
106
|
+
To retrieve details about the columns of specfic tables, use
|
|
107
|
+
the describe_tables endpoint
|
|
108
|
+
"""
|
|
109
|
+
return list(map(lambda x: x.name, self._metadata.sorted_tables))
|
|
110
|
+
|
|
111
|
+
def describe_tables(self, tables: Optional[List[str]] = None) -> str:
|
|
112
|
+
"""
|
|
113
|
+
Describes the specifed tables in the database
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
tables (List[str]): A list of table names to retrieve details about
|
|
117
|
+
"""
|
|
118
|
+
table_names = tables or [table.name for table in self._metadata.sorted_tables]
|
|
119
|
+
table_schemas = []
|
|
120
|
+
|
|
121
|
+
for table_name in table_names:
|
|
122
|
+
table = next(
|
|
123
|
+
(
|
|
124
|
+
table
|
|
125
|
+
for table in self._metadata.sorted_tables
|
|
126
|
+
if table.name == table_name
|
|
127
|
+
),
|
|
128
|
+
None,
|
|
129
|
+
)
|
|
130
|
+
if table is None:
|
|
131
|
+
raise NoSuchTableError(f"Table '{table_name}' does not exist.")
|
|
132
|
+
schema = str(CreateTable(table).compile(self.sql_database._engine))
|
|
133
|
+
table_schemas.append(f"{schema}\n")
|
|
134
|
+
|
|
135
|
+
return "\n".join(table_schemas)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["poetry-core"]
|
|
3
|
+
build-backend = "poetry.core.masonry.api"
|
|
4
|
+
|
|
5
|
+
[tool.codespell]
|
|
6
|
+
check-filenames = true
|
|
7
|
+
check-hidden = true
|
|
8
|
+
# Feel free to un-skip examples, and experimental, you will just need to
|
|
9
|
+
# work through many typos (--write-changes and --interactive will help)
|
|
10
|
+
skip = "*.csv,*.html,*.json,*.jsonl,*.pdf,*.txt,*.ipynb"
|
|
11
|
+
|
|
12
|
+
[tool.mypy]
|
|
13
|
+
disallow_untyped_defs = true
|
|
14
|
+
# Remove venv skip when integrated with pre-commit
|
|
15
|
+
exclude = ["_static", "build", "examples", "notebooks", "venv"]
|
|
16
|
+
ignore_missing_imports = true
|
|
17
|
+
python_version = "3.8"
|
|
18
|
+
|
|
19
|
+
[tool.poetry]
|
|
20
|
+
name = "llama-index-tools-database"
|
|
21
|
+
version = "0.0.1"
|
|
22
|
+
description = "llama-index tools database integration"
|
|
23
|
+
authors = ["Your Name <you@example.com>"]
|
|
24
|
+
license = "MIT"
|
|
25
|
+
readme = "README.md"
|
|
26
|
+
packages = [{include = "llama_index/"}]
|
|
27
|
+
|
|
28
|
+
[tool.poetry.dependencies]
|
|
29
|
+
python = ">=3.8.1,<3.12"
|
|
30
|
+
llama-index-core = "^0.9.32"
|
|
31
|
+
|
|
32
|
+
[tool.poetry.group.dev.dependencies]
|
|
33
|
+
black = {extras = ["jupyter"], version = "<=23.9.1,>=23.7.0"}
|
|
34
|
+
codespell = {extras = ["toml"], version = ">=v2.2.6"}
|
|
35
|
+
ipython = "8.10.0"
|
|
36
|
+
jupyter = "^1.0.0"
|
|
37
|
+
mypy = "0.991"
|
|
38
|
+
pre-commit = "3.2.0"
|
|
39
|
+
pylint = "2.15.10"
|
|
40
|
+
pytest = "7.2.1"
|
|
41
|
+
pytest-mock = "3.11.1"
|
|
42
|
+
ruff = "0.0.292"
|
|
43
|
+
tree-sitter-languages = "^1.8.0"
|
|
44
|
+
types-Deprecated = ">=0.1.0"
|
|
45
|
+
types-PyYAML = "^6.0.12.12"
|
|
46
|
+
types-protobuf = "^4.24.0.4"
|
|
47
|
+
types-redis = "4.5.5.0"
|
|
48
|
+
types-requests = "2.28.11.8" # TODO: unpin when mypy>0.991
|
|
49
|
+
types-setuptools = "67.1.0.0"
|