In diesem Tutorial werden wir sehen, wie man einen Agenten implementiert, der SQL mit smolagents
.
Beginnen wir mit der goldenen Frage: Warum sollte man es nicht einfach halten und eine standardmäßige Text-zu-SQL-Pipeline verwenden?
Eine standardmäßige Text-zu-SQL-Pipeline ist brüchig, da die generierte SQL-Abfrage falsch sein kann. Noch schlimmer ist, dass die Abfrage zwar falsch sein kann, aber keinen Fehler auslöst, sondern stattdessen einige falsche/unbrauchbare Ausgaben liefert, ohne einen Alarm auszulösen.
Stattdessen ist ein Agentensystem in der Lage, die Ausgaben kritisch zu prüfen und zu entscheiden, ob die Abfrage geändert werden muss oder nicht, wodurch es einen enormen Leistungsschub erhält.
Lasst uns diesen Agenten bauen! 💪
Zunächst richten wir die SQL-Umgebung ein:
Kopiert
from sqlalchemy importieren ( create_engine, MetaData, Tabelle, Spalte, String, Ganzzahl, Float, einfügen, prüfen, Text, ) engine = create_engine("sqlite:///:memory:") metadata_obj = MetaData() # SQL-Tabelle Stadt erstellen table_name = "Quittungen" quittungen = Tabelle( table_name, metadata_obj, Column("receipt_id", Integer, primary_key=True), Column("customer_name", String(16), primary_key=True), Column("price", Float), Spalte("Trinkgeld", Float), ) metadata_obj.create_all(engine) rows = [ {"receipt_id": 1, "customer_name": "Alan Payne", "price": 12.06, "tip": 1.20}, {"receipt_id": 2, "kunden_name": "Alex Mason", "preis": 23.86, "Trinkgeld": 0.24}, {"receipt_id": 3, "kunden_name": "Woodrow Wilson", "preis": 53.43, "Trinkgeld": 5.43}, {"receipt_id": 4, "kunden_name": "Margaret James", "preis": 21.11, "Trinkgeld": 1.00}, ] for row in rows: stmt = insert(receipts).values(**row) with engine.begin() as connection: cursor = connection.execute(stmt)
Bauen Sie unseren Agenten #
Lassen Sie uns nun unsere SQL-Tabelle mit einem Werkzeug abrufbar machen.
Das Beschreibungsattribut des Werkzeugs wird vom Agentensystem in die Eingabeaufforderung des LLM eingebettet: es gibt dem LLM Informationen darüber, wie das Werkzeug zu verwenden ist. An dieser Stelle wollen wir die SQL-Tabelle beschreiben.
Kopiert
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)
Kopiert
Spalten: - receipt_id: INTEGER - kunden_name: VARCHAR(16) - Preis: FLOAT - Trinkgeld: FLOAT
Lassen Sie uns nun unser Werkzeug bauen. Es benötigt das Folgende: (lesen das Tool doc für mehr Details)
- Ein Docstring mit einer
Args:
Teil Argumente auflisten. - Tippen Sie Hinweise zu den Ein- und Ausgängen.
Kopiert
von smolagents importieren Werkzeug @tool def sql_engine(abfrage: str) -> str: """ Ermöglicht die Durchführung von SQL-Abfragen auf die Tabelle. Gibt eine String-Repräsentation des Ergebnisses zurück. Die Tabelle hat den Namen "receipts". Ihre Beschreibung lautet wie folgt: Spalten: - receipt_id: INTEGER - kunden_name: VARCHAR(16) - Preis: FLOAT - Trinkgeld: FLOAT Args: Abfrage: Die auszuführende Abfrage. Dies sollte korrektes SQL sein. """ output = "" mit engine.connect() as con: rows = con.execute(text(query)) for row in rows: output += "\n" + str(row) return output
Lassen Sie uns nun einen Agenten erstellen, der dieses Werkzeug nutzt.
Wir verwenden die CodeAgent
ist die Hauptagenten-Klasse von smolagents: ein Agent, der Aktionen in Code schreibt und auf der Grundlage des ReAct-Frameworks die vorherigen Ausgaben wiederholen kann.
Das Modell ist die LLM, die das Agentensystem antreibt. Mit HfApiModel können Sie LLMs über die Inferenz-API von HF aufrufen, entweder über Serverless oder Dedicated Endpoint, aber Sie können auch eine beliebige proprietäre API verwenden.
Kopiert
von smolagents importieren CodeAgent, HfApiModel agent = CodeAgent( tools=[sql_engine], model=HfApiModel("meta-llama/Meta-Llama-3.1-8B-Instruct"), ) agent.run("Können Sie mir den Namen des Kunden nennen, der die teuerste Quittung erhalten hat?")
Ebene 2: Tabellenverknüpfungen #
Jetzt wollen wir es etwas anspruchsvoller machen! Wir wollen, dass unser Agent Joins über mehrere Tabellen hinweg verarbeitet.
Erstellen wir also eine zweite Tabelle, in der die Namen der Kellner für jede receipt_id gespeichert werden!
Kopiert
table_name = "kellner" quittungen = Tabelle( table_name, metadata_obj, Column("receipt_id", Integer, primary_key=True), Column("kellner_name", String(16), primary_key=True), ) metadata_obj.create_all(engine) rows = [ {"receipt_id": 1, "waiter_name": "Corey Johnson"}, {"receipt_id": 2, "kellner_name": "Michael Watts"}, {"receipt_id": 3, "kellner_name": "Michael Watts"}, {"receipt_id": 4, "kellner_name": "Margaret James"}, ] for row in rows: stmt = insert(quittungen).werte(**zeile) with engine.begin() as connection: cursor = connection.execute(stmt)
Da wir die Tabelle geändert haben, aktualisieren wir die SQLExecutorTool
mit der Beschreibung dieser Tabelle, damit der LLM die Informationen aus dieser Tabelle richtig nutzen kann.
Kopiert
updated_description = """Ermöglicht die Ausführung von SQL-Abfragen für die Tabelle. Beachten Sie, dass die Ausgabe dieses Tools eine String-Darstellung der Ausführungsausgabe ist. Es kann die folgenden Tabellen verwenden:""" inspector = inspect(engine) for table in ["receipts", "waiters"]: columns_info = [(col["name"], col["type"]) for col in inspector.get_columns(table)] table_description = f "Tabelle '{table}':\n" table_description += "Spalten:\n" + "\n".join([f" - {name}: {col_type}" for name, col_type in columns_info]) updated_description += "\n\n" + table_description print(aktualisierte_Beschreibung)
Da diese Anfrage etwas schwieriger ist als die vorherige, werden wir die LLM-Engine so umstellen, dass sie die leistungsfähigere Qwen/Qwen2.5-Coder-32B-Instruct!
Kopiert
sql_engine.description = updated_description agent = CodeAgent( tools=[sql_engine], model=HfApiModel("Qwen/Qwen2.5-Coder-32B-Instruct"), ) agent.run("Welcher Kellner hat insgesamt mehr Geld durch Trinkgeld eingenommen?")
Es funktioniert direkt! Die Einrichtung war erstaunlich einfach, nicht wahr?
Dieses Beispiel ist fertig! Wir haben uns mit diesen Konzepten beschäftigt:
- Bau neuer Werkzeuge.
- Aktualisierung der Beschreibung eines Werkzeugs.
- Der Wechsel zu einem stärkeren LLM hilft dem Agenten bei seiner Argumentation.
✅ Jetzt können Sie das Text-to-SQL-System aufbauen, von dem Sie schon immer geträumt haben! ✨