在当今这个数据驱动的时代,企业要取得成功,关键在于从海量数据集中提取有价值的洞察。然而,要做到这一点,往往需要一项专业技能:编写复杂的 SQL 查询。这构成了一个瓶颈,因为许多业务用户虽然是各自领域的专家,但缺乏直接与数据库交互的技术能力。而 大模型 (LLM) 的出现,特别是像 Ollama 结合 Granite 这样的模型,正在彻底改变非技术专业人员查询和理解数据的方式。
大模型赋能:自然语言到SQL的桥梁
想象一下,您可以毫不费力地将您的自然语言问题(例如“上个季度的销售额是多少?”或“哪些员工在市场部工作?”)转化为精确的 SQL 命令,而无需编写任何代码。大模型 正在弥合这一差距,充当智能翻译器,将人类语言转换为可执行的数据库查询。这不仅实现了数据访问的民主化,还使业务用户能够独立检索所需的信息,从而加速决策并培养更敏捷、更具数据素养的环境。例如,一位市场经理无需依赖IT部门,即可通过简单的“找出过去一个月社交媒体广告点击率最高的三个活动”这样的自然语言描述,快速生成相应的SQL查询,并获得活动数据,从而及时调整营销策略。这种效率的提升,直接转化为更快的市场响应速度和更高的营销ROI。
Ollama和Granite:强大的本地化大模型解决方案
Ollama 提供了一个方便的平台,可以在本地运行 大模型,而无需依赖云服务,从而保护了数据的安全性并降低了延迟。Granite,作为IBM开发的一系列高性能大模型,专为企业级应用设计,拥有卓越的性能和效率。将 Ollama 和 Granite 结合使用,企业可以在内部构建强大的 自然语言到SQL (Text-to-SQL) 解决方案,满足特定的业务需求。本文中的示例正是利用了Ollama本地运行Granite模型,将自然语言转化成SQL语句,然后执行查询。这意味着即使在没有网络连接的情况下,用户也可以进行数据查询和分析,这对一些安全性要求高的企业或需要离线操作的场景非常重要。
实例演示:使用Ollama和Granite构建数据库查询应用
为了简化演示,文章使用两个 SQLite 数据库来探索这个概念。一个数据库包含个人的个人信息,例如他们的名字、姓氏和出生日期;第二个数据库包含特定于员工的详细信息,包括工资、职位和部门。这两个数据库通过一个通用的唯一标识符链接,这使得我们可以通过一个简单的查询来组合来自两个来源的信息。
文章中给出了创建这两个数据库的Python代码(create-db.py
):
# create-db.py
import sqlite3
import os
def create_personal_data_db(db_name="personal_data.db"):
"""
Creates an SQLite database for personal employee data and populates it.
"""
conn = None
try:
conn = sqlite3.connect(db_name)
cursor = conn.cursor()
cursor.execute("DROP TABLE IF EXISTS employees_personal")
cursor.execute("""
CREATE TABLE employees_personal (
firstName TEXT NOT NULL,
lastName TEXT NOT NULL,
dateOfBirth TEXT NOT NULL,
uniqueID TEXT PRIMARY KEY
)
""")
sample_data = [
("Alice", "Smith", "1990-05-15", "EMP001"),
("Bob", "Johnson", "1985-11-22", "EMP002"),
("Charlie", "Brown", "1992-03-01", "EMP003")
]
cursor.executemany("INSERT INTO employees_personal (firstName, lastName, dateOfBirth, uniqueID) VALUES (?, ?, ?, ?)", sample_data)
conn.commit()
except sqlite3.Error as e:
print(f"An SQLite error occurred: {e}")
finally:
if conn:
conn.close()
def create_employment_data_db(db_name="employment_data.db"):
"""
Creates an SQLite database for employment data and populates it.
"""
conn = None
try:
conn = sqlite3.connect(db_name)
cursor = conn.cursor()
cursor.execute("DROP TABLE IF EXISTS employees_employment")
cursor.execute("""
CREATE TABLE employees_employment (
uniqueID TEXT PRIMARY KEY,
salary REAL NOT NULL,
jobTitle TEXT NOT NULL,
departmentId INTEGER NOT NULL
)
""")
sample_data = [
("EMP001", 60000.00, "Software Engineer", 101),
("EMP002", 75000.00, "Project Manager", 102),
("EMP003", 50000.00, "HR Specialist", 103)
]
cursor.executemany("INSERT INTO employees_employment (uniqueID, salary, jobTitle, departmentId) VALUES (?, ?, ?, ?)", sample_data)
conn.commit()
except sqlite3.Error as e:
print(f"An SQLite error occurred: {e}")
finally:
if conn:
conn.close()
if __name__ == "__main__":
create_personal_data_db()
create_employment_data_db()
print("\nApplication finished.")
以及用于读取数据库信息的代码(display-db.py
):
# display-db.py
import sqlite3
import os
def read_sqlite_database(db_name):
"""
Connects to an SQLite database, lists all tables, and then retrieves
and prints all rows from each table.
"""
if not os.path.exists(db_name):
print(f"Error: Database file '{db_name}' not found.")
return
conn = None
try:
conn = sqlite3.connect(db_name)
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = cursor.fetchall()
if not tables:
print("No tables found in this database.")
return
for table_name_tuple in tables:
table_name = table_name_tuple[0]
cursor.execute(f"PRAGMA table_info({table_name});")
columns_info = cursor.fetchall()
column_names = [col[1] for col in columns_info]
cursor.execute(f"SELECT * FROM {table_name}")
rows = cursor.fetchall()
if not rows:
print(f" No data in table '{table_name}'.")
else:
for row in rows:
print(f" {row}")
except sqlite3.Error as e:
print(f"An SQLite error occurred: {e}")
finally:
if conn:
conn.close()
if __name__ == "__main__":
db_file_input = input("Please enter the name of the SQLite database file (e.g., personal_data.db): ")
read_sqlite_database(db_file_input)
接下来,文章重点介绍了如何使用 大模型 生成 SQL 查询。 核心代码 ( text2sql.py
) 通过 Ollama 接口调用 Granite 模型,接收用户输入的 employee uniqueID 作为输入,并显示员工的雇佣信息以及生成的 SQL 查询。
# text2sql.py
import sqlite3
import os
import requests
import json
# Configuration for Ollama
OLLAMA_API_URL = "http://localhost:11434/api/chat"
OLLAMA_MODEL = "granite3.3:latest" # Ensure this model is pulled in your Ollama instance
# Database file names
PERSONAL_DB = "personal_data.db"
EMPLOYMENT_DB = "employment_data.db"
def get_employee_details(unique_id):
"""
Connects to both personal and employment databases, performs a join,
and retrieves employee details for a given uniqueID.
Displays the SQL query being executed.
"""
if not os.path.exists(PERSONAL_DB):
print(f"Error: Personal data database '{PERSONAL_DB}' not found.")
return None
if not os.path.exists(EMPLOYMENT_DB):
print(f"Error: Employment data database '{EMPLOYMENT_DB}' not found.")
return None
conn = None
try:
# Connect to the personal data database
conn = sqlite3.connect(PERSONAL_DB)
cursor = conn.cursor()
# Attach the employment data database
cursor.execute(f"ATTACH DATABASE '{EMPLOYMENT_DB}' AS employment_db;")
# Perform a JOIN query
query = f"""
SELECT
p.firstName,
p.lastName,
e.jobTitle
FROM
employees_personal AS p
JOIN
employment_db.employees_employment AS e
ON
p.uniqueID = e.uniqueID
WHERE
p.uniqueID = '{unique_id}'; -- Displaying the query with the ID for clarity
"""
print(f"\n--- Executing SQL Query ---")
print(query)
print(f"---------------------------\n")
cursor.execute(query) # Execute the query
result = cursor.fetchone() # Fetch one matching record
return result
except sqlite3.Error as e:
print(f"An SQLite error occurred during lookup: {e}")
return None
finally:
if conn:
# Detach the database before closing connection
try:
cursor.execute("DETACH DATABASE employment_db;")
except sqlite3.Error as e:
print(f"Warning: Could not detach employment_db: {e}")
conn.close()
def send_to_ollama(prompt):
"""
Sends a prompt to the local Ollama API and returns the LLM's response.
"""
messages = [
{"role": "system", "content": "You are a friendly assistant providing employee information. Respond concisely and helpfully."},
{"role": "user", "content": prompt}
]
payload = {
"model": OLLAMA_MODEL,
"messages": messages,
"stream": False # We want the full response at once
}
headers = {"Content-Type": "application/json"}
try:
response = requests.post(OLLAMA_API_URL, headers=headers, data=json.dumps(payload))
response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
response_data = response.json()
if 'message' in response_data and 'content' in response_data['message']:
return response_data['message']['content']
else:
return "Ollama: Unexpected response format."
except requests.exceptions.ConnectionError:
return "Ollama: Could not connect to the Ollama server. Please ensure it's running."
except requests.exceptions.RequestException as e:
return f"Ollama: An error occurred during the API call: {e}"
except json.JSONDecodeError:
return "Ollama: Failed to decode JSON response from Ollama."
def run_chat_app():
"""
Runs the main chat application loop.
"""
print(f"Welcome to the Employee Lookup Chatbot! (Using Ollama with {OLLAMA_MODEL})")
print("Type 'exit' or 'quit' to end the session.")
while True:
user_input = input("\nEnter employee Unique ID (e.g., EMP001): ").strip().upper()
if user_input in ["EXIT", "QUIT"]:
print("Goodbye!")
break
employee_data = get_employee_details(user_input)
if employee_data:
first_name, last_name, job_title = employee_data
llm_prompt = (
f"I found an employee with Unique ID {user_input}. "
f"Their first name is {first_name}, last name is {last_name}, "
f"and their job title is {job_title}. Please tell me this information "
f"in a friendly and concise way, confirming the ID."
)
else:
llm_prompt = (
f"I looked for an employee with Unique ID {user_input}, but I couldn't find them in the database. "
f"Please respond to the user that the employee was not found and suggest they try another ID."
)
llm_response = send_to_ollama(llm_prompt)
print(f"\nChatbot: {llm_response}")
if __name__ == "__main__":
run_chat_app()
此代码展示了如何将用户的输入传递给 Ollama 运行的 Granite 模型,并根据返回的数据构建一个友好的回复。值得注意的是,该代码示例展示的是直接执行SQL查询,而不是让 大模型 生成SQL。 虽然这是一个简化,但它仍然演示了如何使用 LLM 来处理和呈现数据库信息。 实际应用中,可以将用户输入转换为更复杂的自然语言描述,再由 大模型 生成 SQL 查询,从而支持更灵活的查询方式。
大模型选型:Granite的优势
文章选择 Granite 作为 大模型,是因为它在处理企业级数据查询方面具有优势。 Granite 模型经过专门训练,能够理解和生成准确的 SQL 查询,这对于确保数据分析的准确性和可靠性至关重要。 此外,Granite 还具有良好的可扩展性和安全性,可以满足企业对数据处理的各种需求。 当然,在实际应用中,企业可以根据自身的需求选择其他 大模型,例如 Llama 2、GPT-4 等。
结论:LLM赋能,数据驱动的未来
尽管本文提供的步骤非常简单,但它们展示了使用 大模型 构建强大应用程序以简化企业数据库中结构化信息的使用的潜力,使其触手可及。 通过将 Ollama 和 Granite 等 大模型 结合使用,企业可以构建 自然语言到SQL 解决方案,从而使业务用户能够更自主地完成日常任务,而无需了解数据库或复杂系统的使用。这种 大模型 赋能的方式,将加速企业的数字化转型,并最终实现数据驱动的未来。例如,在金融行业,分析师可以使用自然语言查询快速获取市场数据,从而更好地评估投资风险和机会。 在医疗保健领域,医生可以使用 大模型 驱动的应用程序,从电子病历中提取关键信息,从而更快速、更准确地做出诊断。 这些应用场景都表明, 大模型 将在各个行业发挥越来越重要的作用。