9.6 KiB
Text-to-SQL
рдЗрд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдореЗрдВ, рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдХреИрд╕реЗ smolagents рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдПрдЬреЗрдВрдЯ рдХреЛ SQL рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдЖрдЗрдП рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рд╢реНрди рд╕реЗ рд╢реБрд░реВ рдХрд░реЗрдВ: рдЗрд╕реЗ рд╕рд╛рдзрд╛рд░рдг рдХреНрдпреЛрдВ рдирд╣реАрдВ рд░рдЦреЗрдВ рдФрд░ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп text-to-SQL рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ?
рдПрдХ рд╕рд╛рдорд╛рдиреНрдп text-to-SQL рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдХрдордЬреЛрд░ рд╣реЛрддреА рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЙрддреНрдкрдиреНрди SQL рдХреНрд╡реЗрд░реА рдЧрд▓рдд рд╣реЛ рд╕рдХрддреА рд╣реИред рдЗрд╕рд╕реЗ рднреА рдмреБрд░реА рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдХреНрд╡реЗрд░реА рдЧрд▓рдд рд╣реЛ рд╕рдХрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдХреЛрдИ рдПрд░рд░ рдирд╣реАрдВ рджрд┐рдЦрд╛рдПрдЧреА, рдмрд▓реНрдХрд┐ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдЕрд▓рд╛рд░реНрдо рдХреЗ рдЧрд▓рдд/рдмреЗрдХрд╛рд░ рдЖрдЙрдЯрдкреБрдЯ рджреЗ рд╕рдХрддреА рд╣реИред
ЁЯСЙ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рдПрдХ рдПрдЬреЗрдВрдЯ рд╕рд┐рд╕реНрдЯрдо рдЖрдЙрдЯрдкреБрдЯ рдХрд╛ рдЧрдВрднреАрд░рддрд╛ рд╕реЗ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рддрдп рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдХреНрд╡реЗрд░реА рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдЗрд╕реЗ рдмреЗрд╣рддрд░ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдорджрдж рдорд┐рд▓рддреА рд╣реИред
рдЖрдЗрдП рдЗрд╕ рдПрдЬреЗрдВрдЯ рдХреЛ рдмрдирд╛рдПрдВ! ЁЯТк
рдкрд╣рд▓реЗ, рд╣рдо SQL рдПрдирд╡рд╛рдпрд░рдирдореЗрдВрдЯ рд╕реЗрдЯрдЕрдк рдХрд░рддреЗ рд╣реИрдВ:
from sqlalchemy import (
create_engine,
MetaData,
Table,
Column,
String,
Integer,
Float,
insert,
inspect,
text,
)
engine = create_engine("sqlite:///:memory:")
metadata_obj = MetaData()
# create city SQL table
table_name = "receipts"
receipts = Table(
table_name,
metadata_obj,
Column("receipt_id", Integer, primary_key=True),
Column("customer_name", String(16), primary_key=True),
Column("price", Float),
Column("tip", Float),
)
metadata_obj.create_all(engine)
rows = [
{"receipt_id": 1, "customer_name": "Alan Payne", "price": 12.06, "tip": 1.20},
{"receipt_id": 2, "customer_name": "Alex Mason", "price": 23.86, "tip": 0.24},
{"receipt_id": 3, "customer_name": "Woodrow Wilson", "price": 53.43, "tip": 5.43},
{"receipt_id": 4, "customer_name": "Margaret James", "price": 21.11, "tip": 1.00},
]
for row in rows:
stmt = insert(receipts).values(**row)
with engine.begin() as connection:
cursor = connection.execute(stmt)
Agent рдмрдирд╛рдПрдВ
рдЕрдм рдЖрдЗрдП рд╣рдорд╛рд░реА SQL рдЯреЗрдмрд▓ рдХреЛ рдПрдХ рдЯреВрд▓ рджреНрд╡рд╛рд░рд╛ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдмрдирд╛рдПрдВред
рдЯреВрд▓ рдХрд╛ рд╡рд┐рд╡рд░рдг рд╡рд┐рд╢реЗрд╖рддрд╛ рдПрдЬреЗрдВрдЯ рд╕рд┐рд╕реНрдЯрдо рджреНрд╡рд╛рд░рд╛ LLM рдХреЗ prompt рдореЗрдВ рдПрдореНрдмреЗрдб рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛: рдпрд╣ LLM рдХреЛ рдЯреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рджреЗрддрд╛ рд╣реИред рдпрд╣реАрдВ рдкрд░ рд╣рдо SQL рдЯреЗрдмрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
inspector = inspect(engine)
columns_info = [(col["name"], col["type"]) for col in inspector.get_columns("receipts")]
table_description = "Columns:\n" + "\n".join([f" - {name}: {col_type}" for name, col_type in columns_info])
print(table_description)
Columns:
- receipt_id: INTEGER
- customer_name: VARCHAR(16)
- price: FLOAT
- tip: FLOAT
рдЕрдм рдЖрдЗрдП рд╣рдорд╛рд░рд╛ рдЯреВрд▓ рдмрдирд╛рдПрдВред рдЗрд╕реЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: (рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП рдЯреВрд▓ doc рдкрдврд╝реЗрдВ)
- рдПрдХ рдбреЙрдХрд╕реНрдЯреНрд░рд┐рдВрдЧ рдЬрд┐рд╕рдореЗрдВ рдЖрд░реНрдЧреНрдпреБрдореЗрдВрдЯреНрд╕ рдХреА рд╕реВрдЪреА рд╡рд╛рд▓рд╛
Args:рднрд╛рдЧ рд╣реЛред - рдЗрдирдкреБрдЯ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рджреЛрдиреЛрдВ рдкрд░ рдЯрд╛рдЗрдк рд╣рд┐рдВрдЯреНрд╕ред
from smolagents import tool
@tool
def sql_engine(query: str) -> str:
"""
Allows you to perform SQL queries on the table. Returns a string representation of the result.
The table is named 'receipts'. Its description is as follows:
Columns:
- receipt_id: INTEGER
- customer_name: VARCHAR(16)
- price: FLOAT
- tip: FLOAT
Args:
query: The query to perform. This should be correct SQL.
"""
output = ""
with engine.connect() as con:
rows = con.execute(text(query))
for row in rows:
output += "\n" + str(row)
return output
рдЕрдм рдЖрдЗрдП рдПрдХ рдПрдЬреЗрдВрдЯ рдмрдирд╛рдПрдВ рдЬреЛ рдЗрд╕ рдЯреВрд▓ рдХрд╛ рд▓рд╛рдн рдЙрдард╛рддрд╛ рд╣реИред
рд╣рдо CodeAgent рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ smolagents рдХрд╛ рдореБрдЦреНрдп рдПрдЬреЗрдВрдЯ рдХреНрд▓рд╛рд╕ рд╣реИ: рдПрдХ рдПрдЬреЗрдВрдЯ рдЬреЛ рдХреЛрдб рдореЗрдВ рдПрдХреНрд╢рди рд▓рд┐рдЦрддрд╛ рд╣реИ рдФрд░ ReAct рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкрд┐рдЫрд▓реЗ рдЖрдЙрдЯрдкреБрдЯ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рдореЙрдбрд▓ рд╡рд╣ LLM рд╣реИ рдЬреЛ рдПрдЬреЗрдВрдЯ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рд╕рдВрдЪрд╛рд▓рд┐рдд рдХрд░рддрд╛ рд╣реИред InferenceClientModel рдЖрдкрдХреЛ HF рдХреЗ Inference API рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ LLM рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдпрд╛ рддреЛ рд╕рд░реНрд╡рд░рд▓реЗрд╕ рдпрд╛ рдбреЗрдбрд┐рдХреЗрдЯреЗрдб рдПрдВрдбрдкреЙрдЗрдВрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рд▓реЗрдХрд┐рди рдЖрдк рдХрд┐рд╕реА рднреА рдкреНрд░реЛрдкреНрд░рд╛рдЗрдЯрд░реА API рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
from smolagents import CodeAgent, InferenceClientModel
agent = CodeAgent(
tools=[sql_engine],
model=InferenceClientModel(model_id="meta-llama/Meta-Llama-3.1-8B-Instruct"),
)
agent.run("Can you give me the name of the client who got the most expensive receipt?")
рд▓реЗрд╡рд▓ 2: рдЯреЗрдмрд▓ рдЬреЙрдЗрдиреНрд╕
рдЕрдм рдЖрдЗрдП рдЗрд╕реЗ рдФрд░ рдЪреБрдиреМрддреАрдкреВрд░реНрдг рдмрдирд╛рдПрдВ! рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░рд╛ рдПрдЬреЗрдВрдЯ рдХрдИ рдЯреЗрдмрд▓реНрд╕ рдХреЗ рдмреАрдЪ рдЬреЙрдЗрди рдХреЛ рд╕рдВрднрд╛рд▓ рд╕рдХреЗред
рддреЛ рдЖрдЗрдП рд╣рдо рдкреНрд░рддреНрдпреЗрдХ receipt_id рдХреЗ рд▓рд┐рдП рд╡реЗрдЯрд░реНрд╕ рдХреЗ рдирд╛рдо рд░рд┐рдХреЙрд░реНрдб рдХрд░рдиреЗ рд╡рд╛рд▓реА рдПрдХ рджреВрд╕рд░реА рдЯреЗрдмрд▓ рдмрдирд╛рддреЗ рд╣реИрдВ!
table_name = "waiters"
receipts = Table(
table_name,
metadata_obj,
Column("receipt_id", Integer, primary_key=True),
Column("waiter_name", String(16), primary_key=True),
)
metadata_obj.create_all(engine)
rows = [
{"receipt_id": 1, "waiter_name": "Corey Johnson"},
{"receipt_id": 2, "waiter_name": "Michael Watts"},
{"receipt_id": 3, "waiter_name": "Michael Watts"},
{"receipt_id": 4, "waiter_name": "Margaret James"},
]
for row in rows:
stmt = insert(receipts).values(**row)
with engine.begin() as connection:
cursor = connection.execute(stmt)
рдЪреВрдВрдХрд┐ рд╣рдордиреЗ рдЯреЗрдмрд▓ рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рд╣реИ, рд╣рдо LLM рдХреЛ рдЗрд╕ рдЯреЗрдмрд▓ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдЙрдЪрд┐рдд рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдЯреЗрдмрд▓ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде SQLExecutorTool рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╣реИрдВред
updated_description = """Allows you to perform SQL queries on the table. Beware that this tool's output is a string representation of the execution output.
It can use the following tables:"""
inspector = inspect(engine)
for table in ["receipts", "waiters"]:
columns_info = [(col["name"], col["type"]) for col in inspector.get_columns(table)]
table_description = f"Table '{table}':\n"
table_description += "Columns:\n" + "\n".join([f" - {name}: {col_type}" for name, col_type in columns_info])
updated_description += "\n\n" + table_description
print(updated_description)
рдЪреВрдВрдХрд┐ рдпрд╣ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдкрд┐рдЫрд▓реЗ рд╡рд╛рд▓реЗ рд╕реЗ рдереЛрдбрд╝реА рдХрдард┐рди рд╣реИ, рд╣рдо LLM рдЗрдВрдЬрди рдХреЛ рдЕрдзрд┐рдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА Qwen/Qwen3-Next-80B-A3B-Thinking рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рд┐рдЪ рдХрд░реЗрдВрдЧреЗ!
sql_engine.description = updated_description
agent = CodeAgent(
tools=[sql_engine],
model=InferenceClientModel(model_id="Qwen/Qwen3-Next-80B-A3B-Thinking"),
)
agent.run("Which waiter got more total money from tips?")
рдпрд╣ рд╕реАрдзреЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ! рд╕реЗрдЯрдЕрдк рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд░реВрдк рд╕реЗ рд╕рд░рд▓ рдерд╛, рд╣реИ рдирд╛?
рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдкреВрд░рд╛ рд╣реЛ рдЧрдпрд╛! рд╣рдордиреЗ рдЗрди рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЛ рдЫреБрдЖ рд╣реИ:
- рдирдП рдЯреВрд▓реНрд╕ рдХрд╛ рдирд┐рд░реНрдорд╛рдгред
- рдЯреВрд▓ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ред
- рдПрдХ рдордЬрдмреВрдд LLM рдореЗрдВ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рд╕реЗ рдПрдЬреЗрдВрдЯ рдХреА рддрд░реНрдХрд╢рдХреНрддрд┐ рдореЗрдВ рдорджрдж рдорд┐рд▓рддреА рд╣реИред
тЬЕ рдЕрдм рдЖрдк рд╡рд╣ text-to-SQL рд╕рд┐рд╕реНрдЯрдо рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рд╕рдХрд╛ рдЖрдкрдиреЗ рд╣рдореЗрд╢рд╛ рд╕рдкрдирд╛ рджреЗрдЦрд╛ рд╣реИ! тЬи