Notas prácticas: Agente Text-to-SQL en Python: Tutorial para llamar a herramientas de LLM
Guía paso a paso para utilizar las notas prácticas: Agente Text-to-SQL en Python: Tutorial de llamadas a herramientas LLM: contratos, verificaciones y espacios para código reutilizable para los equipos que implementan este patrón.
Esta guía reconstruye el proceso desde las materias primas hasta un sistema funcional para: crear un agente Text-to-SQL en Python donde solo el código constituye la herramienta. El enfoque está en pasos operativos claros, verificaciones explícitas y código que se puede incorporar directamente a un repositorio sin necesidad de adivinar su propósito. Para tener una visión general, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Considere esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y evite completaciones parciales silenciosas.
La división: definición versus implementación
Al trabajar en “The split: definition versus implementation”, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos. Registre el ID de la solicitud, el ID del modelo y la latencia en cada llamada. Sin ese registro, los errores intermitentes del proveedor parecen bugs de la aplicación.
Lo que necesita
Al trabajar en “What you need”, anote primero el contrato: los datos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Registre el ID de la solicitud, el ID del modelo y la latencia en cada llamada. Sin ese registro, los errores intermitentes del proveedor parecen ser bugs de la aplicación.
pip install acruxcore
1. Crear una base de datos adecuada para consultas
Al trabajar en el paso 1 de crear una base de datos que valga la pena consultar, anote primero el contrato: los ingresos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Documente tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no de mejoras posteriores. Registre el ID de la solicitud, el ID del modelo y la latencia en cada llamada. Sin ese registro, los errores intermitentes del proveedor parecen bugs de la aplicación. Al trabajar en el paso 1 de crear una base de datos que valga la pena consultar, anote primero el contrato: los ingresos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Trate esta etapa como un contrato entre los ingresos y las salidas validadas. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
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. Registrar el modelo en el panel de control
- Registrar el modelo en el panel de control funciona mejor cuando se trata como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo en tokens o consultas junto a los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la versión de demostración a entornos compartidos. Fije el intérprete y el archivo de bloqueo de dependencias antes de enseñar el bucle. La diferencia entre el portátil y los entornos CI es la causa más común de fallos silenciosos en las demostraciones de API.
3. Escribir la instrucción en el panel de control
- Es mejor tratar la instrucción escrita en el panel de control como una superficie medible. Capture una transcripción exitosa, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación; los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Fije el intérprete y el archivo de bloqueo de dependencias antes de explicar el bucle, ya que las diferencias entre la computadora portátil y los entornos de integración continua son la causa más común de fallos silenciosos en las demostraciones de 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. Defina la herramienta en código y permítale publicarse por sí misma
- Definir la herramienta en código — y permitir que se publique por sí misma funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son ajustes realizados posteriormente. Fije el intérprete y el archivo de bloqueo de dependencias antes de explicar el bucle. La diferencia entre usar una computadora portátil y entornos de integración continua es la causa más común de fallos silenciosos en las demostraciones de API.
- Definir la herramienta en código — y permitir que se publique por sí misma funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.
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. Deje que el panel de control controle la redacción de las herramientas
En el punto 5, “Deje que el panel de control controle la redacción de las herramientas”, defina los datos de entrada, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. La visibilidad temprana de los costos evita facturas inesperadas cuando el flujo pasa de entornos de demostración a entornos compartidos. Separe la construcción del cliente del bucle de mensajes para que sea posible cambiar los proveedores sin tener que reescribir la máquina de estados de la conversación.
@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. Ejécutelo
Para el punto 6: ejécutelo, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa desde un punto de control conocido sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema.
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. Lea el seguimiento
Para el punto 7: lea el registro, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Separe la construcción del cliente del bucle de mensajes para que sea posible cambiar los proveedores sin tener que reescribir la máquina de estados de la conversación. Para el punto 7: lea el registro, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa a partir de un punto de control conocido sin tener que adivinar el estado oculto. Considere esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.
8. Agrupar ejecuciones en una sesión
Cuando se trabaja en el grupo 8 y se encuentra con una sesión, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos. Registre el ID de la solicitud, el ID del modelo y la latencia en cada llamada. Sin ese registro, los errores intermitentes del proveedor parecen bugs de la aplicación.
9. La ventaja: cambiar el modelo sin tocar el código
Al trabajar en el punto 9, la recompensa es poder cambiar el modelo sin tocar el código; primero escribe el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Mantén la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Registra el ID de la solicitud, el ID del modelo y la latencia en cada llamada. Sin ese registro, los errores intermitentes del proveedor parecen ser bugs de la aplicación.
¿Debería tu código ser dueño de la herramienta en absoluto?
Al abordar la pregunta “¿Debería tu código ser dueño de la herramienta?”, anota primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Documenta tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no de mejoras posteriores. Registra el ID de la solicitud, el ID del modelo y la latencia en cada llamada. Sin ese registro, los errores intermitentes del proveedor parecen bugs de la aplicación. Al abordar la pregunta “¿Debería tu código ser dueño de la herramienta?”, anota primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Considera esta etapa como un contrato entre las entradas y las salidas validadas. Nombra los artefactos, define las verificaciones de éxito y rechaza las completaciones parciales silenciosas.
A dónde ir a continuación
Definir el siguiente paso a seguir funciona mejor cuando se trata como un elemento medible. Consiga una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos. Fije el intérprete y el archivo de bloqueo de dependencias antes de explicar los bucles. La diferencia entre usar una computadora portátil y entornos de integración continua es la causa más común de fallos silenciosos en las demostraciones de API.
Lista de verificación operativa
La lista de verificación operativa funciona mejor cuando se trata como un elemento medible. Consiga una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance.
Prefiera unidades pequeñas y probables sobre scripts extensos. Cuando un paso falla, el problema debe referirse a una sola responsabilidad y no a un proceso complicado.
Fije el intérprete y el archivo de bloqueo de dependencias antes de explicar el bucle. La diferencia entre la computadora portátil y los entornos de integración continua es la causa más común de fallos silenciosos en las demostraciones de API.
Autentíquese en la pasarela y vuelva a autorizarse en el plano de datos. Un token portador por sí solo no constituye un límite entre diferentes entornos de uso.
Haga una verificación después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior.
Fije las versiones de las dependencias y registre el resumen del archivo de imagen que se utilizó para ejecutar la demostración. La reproducibilidad es mejor que el conocimiento basado en prácticas internas.
Antes de promocionar la pila tecnológica, congele las versiones, guarde una transcripción de referencia para el camino crítico y confirme los pasos para realizar un rollback. Los entornos compartidos necesitan límites de velocidad, verificaciones de asignación de usuarios y un responsable claro para la rotación de credenciales secretas. Prefiera una fiabilidad sencilla a demostraciones ingeniosas pero puntuales.
Nota por lotes para a664c3276a43: mantenga las claves del proveedor fuera del repositorio, establezca un límite para los tokens por sesión y almacene las transcripciones junto a los archivos de evaluación para que los cambios posteriores en el modelo sigan siendo comparables.
Al trabajar en la nota de fortalecimiento 0, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Prefiera unidades pequeñas y verificables sobre scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
Detalle de fortalecimiento 0/766: mida el tiempo de ejecución, la clase del error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en observaciones anecdóticas.
La nota de fortalecimiento 1 funciona mejor cuando se trata como una superficie medible. Capture una transcripción exitosa, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos.
Detalle de fortalecimiento 1/766: mida el tiempo total de ejecución, la clase del error y el gasto en tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
Para la nota de fortalecimiento 2, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son algo que se añade posteriormente.
Detalle de reforzamiento 2/766: mida el tiempo de ejecución, la clase de error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
Al trabajar en la nota de reforzamiento 3, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Trate esta etapa como un contrato entre entradas y salidas validadas. Asigne nombres a los artefactos, defina las comprobaciones de éxito y rechace las completaciones parciales silenciosas.
Detalle de reforzamiento 3/766: mida el tiempo de ejecución, la clase de error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
La nota de fortalecimiento 4 funciona mejor cuando se trata como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema.
Detalle de fortalecimiento 4/766: mida el tiempo de ejecución, la clase del error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
Para la nota de fortalecimiento 5, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
Detalle de refuerzo 5/766: mida el tiempo de ejecución, la clase de error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
Al trabajar en la nota de refuerzo 6, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo en tokens o consultas junto a los resultados funcionales. La visibilidad temprana de los costos evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos.
Detalle de refuerzo 6/766: mida el tiempo de ejecución, la clase de error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
La nota de fortalecimiento 7 funciona mejor cuando se trata como una superficie medible. Capture una transcripción exitosa, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino óptimo como el camino de recuperación juntos. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores.
Detalle de fortalecimiento 7/766: mida el tiempo de ejecución, la clase del error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
Lecturas relacionadas
- Notas prácticas: Construye tu propio flujo de trabajo local de agente LLM en 400 líneas de Python — Guía paso a paso de las Notas prácticas: Construye tu propio flujo de trabajo local de agente LLM en 400 líneas de Python: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Notas prácticas: Esenciales de LangGraph en Python: Construye flujos de trabajo de agente AI con — Guía paso a paso de las Notas prácticas: Esenciales de LangGraph en Python: Construye flujos de trabajo de agente AI con: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.