天天看點

ChatGPT+SQL - 結構化資料增強

作者:新缸中之腦

許多現代資料系統都依賴于結構化資料,例如 Postgres DB 或 Snowflake 資料倉庫。 LlamaIndex 提供了許多由 LLM 提供支援的進階功能,既可以從非結構化資料建立結構化資料,也可以通過增強的文本到 SQL 功能分析這些結構化資料。

ChatGPT+SQL - 結構化資料增強
推薦:用 NSDT場景設計器 快速搭建3D場景。

本指南有助于逐漸了解這些功能中的每一項。 具體來說,我們涵蓋以下主題:

  • 推斷結構化資料點:将非結構化資料轉換為結構化資料。
  • Text-to-SQL(基礎):如何使用自然語言查詢一組表。
  • 注入上下文:如何将每個表的上下文注入到 text-to-SQL 提示中。 上下文可以手動添加,也可以從非結構化文檔中派生。
  • 在索引中存儲表上下文:預設情況下,我們直接将上下文插入到提示中。 如果上下文很大,有時這是不可行的。 在這裡,我們展示了如何實際使用 LlamaIndex 資料結構來包含表上下文!

我們将浏覽一個包含城市/人口/國家資訊的示例資料庫。

1、設定

首先,我們使用 SQLAlchemy 來設定一個簡單的 sqlite 資料庫:

from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, select, column

engine = create_engine("sqlite:///:memory:")
metadata_obj = MetaData(bind=engine)           

然後我們建立一個 city_stats 表:

# create city SQL table
table_name = "city_stats"
city_stats_table = Table(
    table_name,
    metadata_obj,
    Column("city_name", String(16), primary_key=True),
    Column("population", Integer),
    Column("country", String(16), nullable=False),
)
metadata_obj.create_all()           

現在是時候插入一些資料點了!

如果你希望通過從非結構化資料推斷結構化資料點來研究填充此表,請檢視以下部分。 否則,可以選擇直接填充此表:

from sqlalchemy import insert
rows = [
    {"city_name": "Toronto", "population": 2731571, "country": "Canada"},
    {"city_name": "Tokyo", "population": 13929286, "country": "Japan"},
    {"city_name": "Berlin", "population": 600000, "country": "United States"},
]
for row in rows:
    stmt = insert(city_stats_table).values(**row)
    with engine.connect() as connection:
        cursor = connection.execute(stmt)           

最後,我們可以用我們的 SQLDatabase 包裝器包裝 SQLAlchemy 引擎; 這允許在 LlamaIndex 中使用資料庫:

from llama_index import SQLDatabase

sql_database = SQLDatabase(engine, include_tables=["city_stats"])           

如果資料庫中已經填充了資料,我們可以使用空白文檔清單執行個體化 SQL 索引。 否則請參閱以下部分。

index = GPTSQLStructStoreIndex(
    [],
    sql_database=sql_database, 
    table_name="city_stats",
)           

2、推斷結構化資料點

LlamaIndex 提供将非結構化資料點轉換為結構化資料的功能。 在本節中,我們将展示如何通過提取有關每個城市的維基百科文章來填充 city_stats 表。

首先,我們使用 LlamaHub 的維基百科閱讀器加載一些有關相關資料的頁面。

from llama_index import download_loader

WikipediaReader = download_loader("WikipediaReader")
wiki_docs = WikipediaReader().load_data(pages=['Toronto', 'Berlin', 'Tokyo'])           

當我們建立SQL索引時,我們可以指定這些文檔作為第一個輸入; 這些文檔将被轉換為結構化資料點并插入到資料庫中:

from llama_index import GPTSQLStructStoreIndex, SQLDatabase

sql_database = SQLDatabase(engine, include_tables=["city_stats"])
# NOTE: the table_name specified here is the table that you
# want to extract into from unstructured documents.
index = GPTSQLStructStoreIndex(
    wiki_docs, 
    sql_database=sql_database, 
    table_name="city_stats",
)           

你可以檢視目前表以驗證是否已插入資料點!

# view current table
stmt = select(
    [column("city_name"), column("population"), column("country")]
).select_from(city_stats_table)

with engine.connect() as connection:
    results = connection.execute(stmt).fetchall()
    print(results)           

3、文本到 SQL(基本)

LlamaIndex 提供“文本到 SQL”功能,既有最基本的水準,也有更進階的水準。 在本節中,我們将展示如何在基本級别上使用這些文本到 SQL 的功能。

此處顯示了一個簡單示例:

# set Logging to DEBUG for more detailed outputs
response = index.query("Which city has the highest population?", mode="default")
print(response)
           

你可以通過 response.extra_info['sql_query'] 通路底層派生的 SQL 查詢。 它應該看起來像這樣:

SELECT city_name, population
FROM city_stats
ORDER BY population DESC
LIMIT 1           

4、注入上下文

預設情況下,text-to-SQL 提示隻是将表架構資訊注入到提示中。 但是,通常你可能還想添加自己的上下文。 本節向你展示如何添加上下文,可以手動添加,也可以通過文檔提取。

我們為你提供上下文建構器類以更好地管理 SQL 表中的上下文:SQLContextContainerBuilder。 這個類接受 SQLDatabase 對象和一些其他可選參數,并建構一個 SQLContextContainer 對象,然後你可以在構造 + 查詢時将其傳遞給索引。

可以手動将上下文添加到上下文建構器。 下面的代碼片段展示了如何實作:

# manually set text
city_stats_text = (
    "This table gives information regarding the population and country of a given city.\n"
    "The user will query with codewords, where 'foo' corresponds to population and 'bar'"
    "corresponds to city."
)
table_context_dict={"city_stats": city_stats_text}
context_builder = SQLContextContainerBuilder(sql_database, context_dict=table_context_dict)
context_container = context_builder.build_context_container()

# building the index
index = GPTSQLStructStoreIndex(
    wiki_docs, 
    sql_database=sql_database, 
    table_name="city_stats",
    sql_context_container=context_container
)           

你還可以選擇從一組非結構化文檔中提取上下文。 為此,可以調用 SQLContextContainerBuilder.from_documents。 我們使用 TableContextPrompt 和 RefineTableContextPrompt(請參閱參考文檔)。

# this is a dummy document that we will extract context from
# in GPTSQLContextContainerBuilder
city_stats_text = (
    "This table gives information regarding the population and country of a given city.\n"
)
context_documents_dict = {"city_stats": [Document(city_stats_text)]}
context_builder = SQLContextContainerBuilder.from_documents(
    context_documents_dict, 
    sql_database
)
context_container = context_builder.build_context_container()

# building the index
index = GPTSQLStructStoreIndex(
    wiki_docs, 
    sql_database=sql_database, 
    table_name="city_stats",
    sql_context_container=context_container,
)           

5、在索引中存儲表上下文

一個資料庫集合可以有很多表,如果每個表有很多列+與之相關的描述,那麼整個上下文可能會非常大。

幸運的是,可以選擇使用 LlamaIndex 資料結構來存儲此表上下文! 然後,當查詢 SQL 索引時,我們可以使用這個“邊”索引來檢索可以輸入到文本到 SQL 提示中的正确上下文。

這裡我們使用 SQLContextContainerBuilder 中的 derive_index_from_context 函數來建立一個新索引。 你可以靈活地選擇要指定的索引類+要傳入的參數。然後我們使用一個名為 query_index_for_context 的輔助方法,它是 index.query 調用的簡單包裝器,它包裝了一個查詢模闆+将上下文存儲在生成的上下文容器中 .

然後你可以建構上下文容器,并在查詢期間将其傳遞給索引!

from gpt_index import GPTSQLStructStoreIndex, SQLDatabase, GPTSimpleVectorIndex
from gpt_index.indices.struct_store import SQLContextContainerBuilder

sql_database = SQLDatabase(engine)
# build a vector index from the table schema information
context_builder = SQLContextContainerBuilder(sql_database)
table_schema_index = context_builder.derive_index_from_context(
    GPTSimpleVectorIndex,
    store_index=True
)

query_str = "Which city has the highest population?"

# query the table schema index using the helper method
# to retrieve table context
SQLContextContainerBuilder.query_index_for_context(
    table_schema_index,
    query_str,
    store_context_str=True
)
context_container = context_builder.build_context_container()

# query the SQL index with the table context
response = index.query(query_str, sql_context_container=context_container)
print(response)
           

原文連結:http://www.bimant.com/blog/chatgpt-structural-data-augment/

繼續閱讀