Notes pratiques : Agent Text-to-SQL en Python : Tutoriel sur l’appel d’outils LLM
Guide pratique pas à pas : Agent Text-to-SQL en Python – Tutoriel sur l’utilisation d’outils LLM : contrats, vérifications et emplacements de code prêts à l’emploi pour les équipes qui mettent en œuvre ce modèle.
Ce guide reconstitue le parcours allant des matières premières à un système fonctionnel pour : Créer un agent Text-to-SQL en Python où seul le code constitue l’outil. L’accent est mis sur des étapes opérationnelles, des vérifications explicites, ainsi que du code que vous pouvez intégrer directement dans un dépôt sans devoir deviner son intention. Pour une vue d’ensemble, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès, et refusez toute complétion partielle silencieuse.
La séparation : définition versus mise en œuvre
Lorsque vous travaillez sur « The split: definition versus implementation », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Enregistrez les temps d’exécution ainsi que le coût en tokens ou en requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés. Journalisez l’ID de la requête, l’ID du modèle et le temps de latence pour chaque appel. Sans ce suivi, les erreurs intermittentes du fournisseur sont prises pour des bugs de l’application.
Ce dont vous avez besoin
Lorsque vous travaillez sur « What you need », notez d’abord les éléments du contrat : les entrées requises, le signal de succès, ainsi que ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les administrateurs peuvent auditer sans devoir lire l’ensemble du système. Enregistrez l’ID de la requête, l’ID du modèle et le temps de réponse pour chaque appel. Sans ces traces, les erreurs intermittentes du fournisseur sont prises pour des bugs de l’application.
pip install acruxcore
1. Créer une base de données intéressante à interroger
Lors de l’étape 1 consistant à créer une base de données valable pour les requêtes, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Documentez à la fois le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations apportées ultérieurement. Enregistrez l’ID de la requête, l’ID du modèle et le temps de réponse pour chaque appel. Sans ces traces, les erreurs intermittentes du fournisseur sont perçues comme des bugs de l’application. Lors de l’étape 1 consistant à créer une base de données valable pour les requêtes, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des critères de succès et refusez les terminations partielles silencieuses.
conn.executescript("""
CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, category TEXT, price REAL, stock INTEGER);
CREATE TABLE orders (id INTEGER PRIMARY KEY, product_id INTEGER REFERENCES products(id),
quantity INTEGER, order_date TEXT, customer TEXT);
""")
conn.executemany("INSERT INTO products VALUES (?, ?, ?, ?, ?)", PRODUCTS)
conn.executemany("INSERT INTO orders VALUES (?, ?, ?, ?, ?)", ORDERS)
python seed_db.py
# Seeded store.db: 8 products, 15 orders.
2. Enregistrer le modèle dans le tableau de bord
- L’enregistrement du modèle dans le tableau de bord fonctionne le mieux lorsque celui-ci est considéré comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Notez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés. Fixez l’interpréteur ainsi que le fichier de verrouillage des dépendances avant d’enseigner la boucle. Les différences entre l’ordinateur portable et les environnements CI constituent la cause la plus fréquente de dysfonctionnement silencieux dans les démonstrations API.
3. Rédiger la instruction dans le tableau de bord
- L’écriture des instructions dans le tableau de bord fonctionne le mieux lorsque celui-ci est considéré comme une surface mesurable. Capturez un exemple réussi, un cas d’échec ainsi que la note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système. Fixez l’interpréteur et le fichier de verrouillage des dépendances avant d’enseigner la boucle. Les différences entre l’ordinateur portable et l’environnement CI sont la cause la plus fréquente de dysfonctionnements silencieux dans les démos API.
You are a data analyst for an online store. Answer questions about products and
sales by querying a SQLite database with the query_database tool. Never guess —
always query.
Schema:
CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, category TEXT, price REAL, stock INTEGER);
CREATE TABLE orders (id INTEGER PRIMARY KEY, product_id INTEGER REFERENCES products(id), quantity INTEGER, order_date TEXT, customer TEXT);Write a single read-only SQLite SELECT, call query_database with it, then answer
in one or two sentences using only the rows it returns. Prices are in USD;
revenue = quantity * price; order_date is YYYY-MM-DD.
4. Définir l’outil dans le code — et le laisser se publier lui-même
- La méthode consistant à définir l’outil en code — et à le laisser se publier lui-même — fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Il convient de recueillir un exemple idéal de fonctionnement, un cas d’échec ainsi que des notes de réversion avant d’élargir le périmètre. Documentez en même temps le parcours normal et celui de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une étape de finition ultérieure. Fixez l’interpréteur et le fichier de verrouillage des dépendances avant d’expliquer le fonctionnement du boucle. Les différences entre l’ordinateur portable et l’environnement de test continu sont la cause la plus fréquente d’échecs silencieux lors des démonstrations API.
- La méthode consistant à définir l’outil en code — et à le laisser se publier lui-même — fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Il convient de recueillir un exemple idéal de fonctionnement, un cas d’échec ainsi que des notes de réversion avant d’élargir le périmètre. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des critères de succès et refusez toute complétion partielle silencieuse.
from acruxcore import AcruxCore, acrux
@acrux.tool
async def query_database(sql: str) -> list[dict]:
"""Run a read-only SQL SELECT against the store database. Args:
sql: A single read-only SQLite SELECT statement.
"""
statement = sql.strip().rstrip(";").strip()
if not statement.lower().startswith("select"):
raise ValueError("Only read-only SELECT statements are allowed.")
if ";" in statement:
raise ValueError("Only a single statement is allowed.")
conn = sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True)
conn.row_factory = sqlite3.Row
try:
return [dict(row) for row in conn.execute(statement).fetchall()]
finally:
conn.close()
{
"name": "query_database",
"description": "Run a read-only SQL SELECT against the store database.",
"parameters": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "A single read-only SQLite SELECT statement."}
},
"required": ["sql"]
}
}
async with AcruxCore() as hub:
await hub.tools.sync([query_database])
5. Laissez le tableau de bord gérer la formulation des outils
Pour « 5. Laissez le tableau de bord gérer la formulation des outils », définissez les entrées, l’ responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution ainsi que le coût des jetons ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le parcours passe d’un environnement de démonstration à des environnements partagés. Séparez la construction du client du cycle de messages afin que les fournisseurs puissent être remplacés sans avoir à réécrire la machine d’états de la conversation.
@acrux.tool
async def check_disclosure_policy(field: str) -> dict:
# No docstring, on purpose. See below — the absence is the mechanism.
sensitive = field.strip().lower() in {"customer", "customer_name", "email"}
return {
"field": field,
"may_disclose": not sensitive,
"guidance": (
"Do not name an individual customer. Report aggregate figures only."
if sensitive
else "This column may be shown to the user."
),
}
{
"name": "check_disclosure_policy",
"description": null,
"parameters": {
"type": "object",
"properties": {"field": {"type": "string"}},
"required": ["field"]
}
}
Published: ToolSyncResult(tool_id='2572965e-…', version_number=2, committed=False, alias='production', superseded_source=None)
6. Lancez-le
Pour le point 6 : exécutez-le, définissez les entrées, l’ responsable de l’étape ainsi que les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système. Séparez la construction du client du cycle de messages afin que les fournisseurs puissent être remplacés sans avoir à réécrire la machine à états de la conversation.
async def ask(hub: AcruxCore, question: str) -> str:
rendered = await hub.prompts.render("sql-analyst-agent", "production")
messages = [*rendered.messages, {"role": "user", "content": question}]
result = await hub.gateway.run_prompt_with_tools(
rendered,
messages=messages,
tools=[query_database, check_disclosure_policy],
trace={"name": "sql-analyst-agent", "session_id": "sql-agent-demo"},
)
print(f" (trace {result.trace_id})")
return result.content
export ACRUXCORE_API_KEY=<your personal api key>
export ACRUXCORE_BASE_URL=https://api.acruxcore.com/api/v1
python sql_agent.py
Q: Which product generated the most total revenue, and how much?
(trace 606dbd38-cb34-4cc3-a1a1-ec4dc9af87b2)
A: The **Aeron Chair** generated the most total revenue at **$4,185.00**.
Q: How many total units were ordered in June 2026?
(trace d1ace20b-ae00-4c4d-9294-a613327e1583)
A: In June 2026, a total of **93 units** were ordered.Q: Who is our biggest customer by total spend?
(trace ea57a392-9af2-41b6-bfd8-48297ee17a8c)
A: Our biggest customer by total spend has spent $6,995.00. I'm unable to disclose the
specific customer name due to privacy policy, but I can confirm this is our top
customer by total spending.
7. Lire le suivi
Pour le point 7 : lisez les traces, définissez les entrées, le responsable de l’étape ainsi que les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’une mise en forme ultérieure. Séparez la construction des requêtes côté client du cycle de traitement des messages afin que les fournisseurs puissent être remplacés sans avoir à réécrire la machine à états de la conversation. Pour le point 7 : lisez les traces, définissez les entrées, le responsable de l’étape ainsi que les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définissez des vérifications de succès et refusez les terminations partielles silencieuses.
8. Regrouper les exécutions en une session
Lorsque vous travaillez sur le groupe 8, lorsque vous rencontrez une session, notez d’abord les exigences : les entrées requises, le signal de succès, ainsi que ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Enregistrez les temps d’exécution ainsi que le coût des jetons ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés. Enregistrez l’ID de la requête, l’ID du modèle et le temps de latence pour chaque appel. Sans ce suivi, les erreurs intermittentes du fournisseur sont prises pour des bugs de l’application.
9. Le bénéfice : modifier le modèle sans toucher au code
Lorsque vous travaillez sur la section 9, le bénéfice réside dans la possibilité de modifier le modèle sans toucher au code : commencez par établir un contrat détaillant les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les administrateurs peuvent auditer sans avoir à lire l’ensemble du système. Enregistrez l’ID de la requête, l’ID du modèle et le temps de réponse pour chaque appel. Sans ces traces, les erreurs intermittentes du fournisseur sont prises pour des bugs de l’application.
Votre code doit-il vraiment posséder l’outil ?
Lorsque vous travaillez sur la question « Votre code devrait-il vraiment posséder l’outil ? », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations apportées ultérieurement. Enregistrez l’ID de la demande, l’ID du modèle et le temps de réponse pour chaque appel. Sans ce suivi, les erreurs intermittentes du fournisseur sont perçues comme des bugs de l’application. Lorsque vous travaillez sur la question « Votre code devrait-il vraiment posséder l’outil ? », notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez les terminations partielles silencieuses.
Où aller ensuite
La détermination de la prochaine étape est optimale lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Notez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe de la démonstration à des environnements partagés. Fixez l’interpréteur et le fichier de verrouillage des dépendances avant d’enseigner la boucle. Les différences entre l’ordinateur portable et les environnements CI constituent la cause la plus fréquente de dysfonctionnement silencieux dans les démonstrations API.
Liste de contrôle opérationnelle
La liste de contrôle opérationnelle est optimale lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre.
Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’erreur doit indiquer une seule responsabilité et non un processus embrouillé.
Fixez l’interpréteur ainsi que le fichier de verrouillage des dépendances avant d’expliquer la boucle. Les écarts entre l’ordinateur portable et l’environnement CI sont la cause la plus fréquente d’échecs silencieux lors des démonstrations API.
Authentifiez-vous au niveau du gateway et réautorisez-vous au niveau du plan de données. Un token porteur seul ne constitue pas une frontière entre les tenants.
Faites un point d’étape après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel LLM lorsque l’opérateur réessaie un nœud ultérieur.
Fixez les versions des dépendances et enregistrez le digest de l’image ayant exécuté la démonstration. La reproductibilité vaut mieux que les connaissances propres à un groupe.
Au préalable de promouvoir l’ensemble des composants, figez les versions, capturez une transcription exemplaire pour le chemin critique, et vérifiez les étapes de rollback. Les environnements partagés nécessitent des limites de débit, des contrôles de tenant, ainsi qu’un responsable clair pour la rotation des secrets. Préférez une fiabilité banale à des démonstrations originales mais temporaires.
Note de lot pour a664c3276a43 : éviter d’inclure les clés du fournisseur dans le répertoire, fixer une limite pour les tokens par session, et stocker les transcriptions à côté des fichiers de test afin que les remplacements ultérieurs de modèles restent comparables.
Lors du travail sur la note de renforcement 0, écrivez d’abord le contrat : entrées requises, signal de succès, et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé.
Détail de renforcement 0/766 : mesurez le temps d’exécution, la classe de l’erreur et la consommation de tokens pour cette note, puis décidez si vous souhaitez conserver la modification en vous basant sur un ensemble de questions prédéfini plutôt que sur des observations subjectives.
La note de renforcement 1 fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Notez les temps d’exécution ainsi que le coût des jetons ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés.
Détail de renforcement 1/766 : mesurez le temps d’exécution, la catégorie de l’erreur et la consommation de jetons pour cette note, puis décidez si vous souhaitez conserver la modification en vous basant sur un ensemble de questions prédéfini plutôt que sur des observations subjectives.
Pour la note de renforcement 2, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure.
Détail de renforcement 2/766 : mesurez le temps d’exécution, la classe d’erreur et la consommation de tokens pour cette note, puis décidez si vous souhaitez conserver le changement en vous basant sur un ensemble de questions prédéfini plutôt que sur des anecdotes.
Lorsque vous travaillez sur la note de renforcement 3, écrivez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications de code ultérieures. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définez les vérifications de succès et refusez toute exécution partielle silencieuse.
Détail de renforcement 3/766 : mesurez le temps d’exécution, la classe d’erreur et la consommation de tokens pour cette note, puis décidez si vous souhaitez conserver le changement en vous basant sur un ensemble de questions prédéfini plutôt que sur des anecdotes.
La note de renforcement 4 fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système.
Détail de renforcement 4/766 : mesurez le temps d’exécution, la classe d’erreur et l’utilisation des tokens pour cette note, puis décidez si vous souhaitez conserver la modification en vous basant sur un ensemble de questions prédéfinies plutôt que sur des observations subjectives.
Pour la note de renforcement 5, définissez les entrées, le responsable de l’étape et les critères d’achèvement avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé.
Détail de renforcement 5/766 : mesurez le temps d’exécution, la classe d’erreur et la consommation de tokens pour cette note, puis décidez si vous souhaitez conserver le changement en vous basant sur un ensemble de questions prédéfini plutôt que sur des observations anecdotiques.
Lorsque vous travaillez sur la note de renforcement 6, notez d’abord les éléments essentiels du contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications de code ultérieures. Enregistrez les temps d’exécution ainsi que le coût en tokens ou en requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les surprises financières lorsque le projet passe de l’environnement de démonstration à des environnements partagés.
Détail de renforcement 6/766 : mesurez le temps d’exécution, la classe d’erreur et la consommation de tokens pour cette note, puis décidez si vous souhaitez conserver le changement en vous basant sur un ensemble de questions prédéfini plutôt que sur des observations anecdotiques.
La note de renforcement 7 fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours optimal et le parcours de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure.
Détail de renforcement 7/766 : mesurez le temps d’exécution, la classe de l’erreur et l’utilisation des tokens pour cette note, puis décidez si vous souhaitez conserver la modification en vous basant sur un ensemble de questions prédéfini plutôt que sur des anecdotes.