Головна / Статті / Практичні нотатки: Агент тексту-до-SQL у Python: посібник з виклику інструментів LLM

Практичні нотатки: Агент тексту-до-SQL у Python: посібник з виклику інструментів LLM

Покрокове керівництво з практичних нотаток: агент Text-to-SQL у Python: посібник з використання інструментів LLM: контракти, перевірки та готові блоки коду для команд, які впроваджують цю схему.

2929 слів

Цей посібник описує процес створення системи, яка починається з сировини та закінчується функціональним інструментом для: створення агента Text-to-SQL у Python, де єдиним кодом є сам інструмент. Основна увага приділяється конкретним крокам виконання, чітким перевіркам та коду, який можна просто додати до репозиторію без необхідності здогадуватися щодо його призначення. Для загального огляду необхідно визначити вхідні дані, виконавця кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись здогадатися про прихований стан системи. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення роботи.

Розділення: визначення проти реалізації

Під час роботи над «Розділення: визначення проти реалізації» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Записуйте ідентифікатор запиту, ідентифікатор моделі та час затримки після кожного виклику. Без цих записів періодичні помилки постачальника виглядають як баги програми.

Що вам потрібно

Під час роботи над розділом «Що вам потрібно», спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успішне виконання та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Записуйте ідентифікатор запиту, ідентифікатор моделі та час відгуку для кожного виклику. Без цих записів періодичні помилки постачальника виглядають як баги додатку.

pip install acruxcore

1. Створіть базу даних, яку можна запитувати

Під час виконання кроку 1 «Заповнення бази даних, готової до запитів», спочатку описайте контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Фіксуйте ідентифікатор запиту, ідентифікатор моделі та час виконання кожного запиту. Без цих записів періодичні помилки постачальника виглядають як баги програми. Під час виконання кроку 1 «Заповнення бази даних, готової до запитів», спочатку описайте контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Назвіть всі елементи, визначте критерії успіху та не допускайте безповідомного часткового виконання.

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. Реєструйте модель у панелі керування

  1. Найкращий спосіб реєстрації моделі у панелі керування — розглядати її як вимірювану поверхню. Збережіть один ідеальний запис виконання, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільних середовищ. Закріпіть інтерпретатор та файл з параметрами залежностей перед навчанням циклу. Розбіжності між ноутбуком та системою CI є найпоширенішою причиною прихованих збоїв у демонстраціях API.

3. Напишіть запит у панелі керування

  1. Найкраще працює написання запиту в панелі керування, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний приклад роботи, один випадок збою та примітку про скасування змін перед розширенням обсягу завдань. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Забезпечте фіксацію інтерпретатора та файлу блокування залежностей перед поясненням логіки циклу. Розбіжності між ноутбуком та системою CI є найпоширенішою причиною прихованих збоїв у демонстраціях 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. Визначте інструмент у коді — та дозвольте йому самостійно публікуватися

  1. Найкращий спосіб роботи методу «Визначте інструмент у коді — нехай він сам себе публікує» полягає у тому, щоб розглядати його як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Забезпечте фіксацію версії інтерпретатора та файлу блокування залежностей перед тим, як пояснювати принцип роботи циклу. Розбіжності між ноутбуком та системою CI є найпоширенішою причиною безслухняних збоїв під час демонстрацій API.
  2. Визначте інструмент у коді — нехай він сам себе публікує» краще працює, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безслухняного часткового виконання завдань.
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. Дозвольте панелі керування визначати формулювання інструменту

Для пункту 5 «Дозвольте панелі керування визначати формулювання інструменту» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні середовища. Відокремте процес створення клієнта від циклу обробки повідомлень, щоб можна було змінювати постачальників без переписування машини станів розмови.

@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. Запустіть його

Для пункту 6: перед зміною коду запустіть процес, визначте вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь алгоритм. Розділіть процес створення клієнта від циклу обробки повідомлень, щоб можна було замінювати постачальників без переписування машини станів розмови.

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. Читання треку

Для пункту 7. Перед зміною коду прочитайте запис виконання, визначте вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість знову запустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як шлях успішного виконання, так і шлях відновлення одночасно. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Відокремте створення клієнта від циклу обробки повідомлень, щоб можна було замінювати постачальників без переписування машини станів розмови. Для пункту 7. Перед зміною коду прочитайте запис виконання, визначте вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість знову запустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення.

8. Об’єднання запусків у сеанс

Під час роботи над розділом 8, коли зустрічається сеанс, спочатку запишіть умови використання: необхідні дані вхіду, сигнал про успішне виконання та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із результатами функціональності. Очевидність витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Фіксуйте ідентифікатор запиту, ідентифікатор моделі та час затримки при кожному виклику. Без цих записів періодичні помилки постачальника виглядають як баги програми.

9. Перевага: змінюйте модель, не торкаючись коду

Під час роботи над розділом 9. Користь: змінюйте модель, не торкаючись коду. Спочатку складіть опис контракту — необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Записуйте ідентифікатор запиту, ідентифікатор моделі та час відгуку після кожного виклику. Без цих записів періодичні помилки постачальника виглядають як баги додатку.

Чи взагалі має ваш код контролювати інструмент?

Під час роботи над питанням «Чи повинен ваш код володіти інструментом?» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Документуйте як шлях успішної роботи, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Зафіксуйте ідентифікатор запиту, ідентифікатор моделі та час виконання кожного виклику. Без цих даних періодичні помилки постачальника виглядають як баги програми. Під час роботи над питанням «Чи повинен ваш код володіти інструментом?» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Назвіть створювані елементи, визначте критерії успіху та не допускайте безповідомного часткового виконання.

Куди рухатися далі

Визначення наступного кроку найкраще робити, сприймаючи його як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи.

Чек-лист для експлуатації

Чек-лист для експлуатації найкраще використовувати, сприймаючи його як вимірювану структуру. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу.

Віддавайте перевагу невеликим, тестованим одиницям перед величезними скриптами. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій.

Забезпечте фіксацію версій інтерпретатора та файлу блокування залежностей перед тим, як пояснювати принцип циклу. Розбіжності між ноутбуком та середовищем CI є найпоширенішою причиною безслухового збою під час демонстрацій API.

Аутентифікуйтеся через шлюз та повторно авторизуйтесь у рівні обробки даних. Один лише токен-носій не є межею окремого тенантства.

Створюйте контрольні точки після дорогих операцій. Система відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор намагається знову виконати пізнішу операцію.

Фіксуйте версії залежностей та записуйте хеш образу, який використовувався під час демонстрації. Відтворюваність є кращою за індивідуальні знання.

Перед підвищенням версії стеку заморозьте всі версії, збережіть ідеальний запис для критичного шляху виконання та переконайтеся у наявності кроків для відкату. У спільних середовищах необхідні обмеження на частоту запитів, перевірки тенантства та чіткий власник для зміни секретів. Краща нудна надійність, ніж кмітливі одноразові демонстрації.

Примітка до пакету a664c3276a43: не включайте ключі постачальника до репозиторію, встановіть ліміт токенів на кожну сесію та зберігайте транскрипції поруч із фіксами для оцінки, щоб подальша заміна моделей залишалася порівнянною.

Під час роботи над приміткою 0 про посилення безпеки спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Віддавайте перевагу малим, тестованим одиницям перед об’ємними скриптами. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій.

Деталь посилення безпеки 0/766: вимірюйте час виконання, клас помилки та кількість витрачених токенів для цієї примітки, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

Примітка щодо посилення безпеки 1 найкраще функціонує, якщо її розглядати як вимірювану поверхню. Запишіть один ідеальний приклад роботи, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні середовища.

Деталь посилення безпеки 1/766: виміряйте час виконання, клас помилки та витрати на токени для цієї примітки, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих прикладах.

Для примітки щодо посилення безпеки 2 визначте вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не здогадуючись про прихований стан. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Деталь посилення безпеки 2/766: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

Під час роботи над записом посилення безпеки 3 спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового виконання.

Деталь посилення безпеки 3/766: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

Примітка щодо посилення безпеки 4 найкраще працює, якщо її розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код.

Деталь посилення безпеки 4/766: вимірюйте час виконання, клас помилки та кількість витрачених токенів для цієї примітки, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

Для примітки щодо посилення безпеки 5 визначте вхідні дані, власника кроку та критерії завершення ще до зміни коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не здогадуючись про прихований стан. Віддавайте перевагу невеликим, тестованим одиницям коду перед складними скриптами. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій.

Деталь посилення безпеки 5/766: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

Під час роботи над записом посилення безпеки 6 спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних.

Деталь посилення безпеки 6/766: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

Примітка щодо посилення безпеки 7 найкраще працює, якщо її розглядати як вимірювану поверхню. Збережіть один ідеальний приклад роботи, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Деталь посилення безпеки 7/766: вимірюйте час виконання, клас помилки та кількість витрачених токенів для цієї примітки, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.