Практычныя прыемы: Агент «Тэкст-у-SQL» у Python: Навучальныя інструкцыі па выкліканню інструмента LLM
Практычныя прыказкі: Агент Text-to-SQL у Python: Навучальны курс па викорыстоўванні інструмента LLM: кантракты, перакрыцчы і слоты для коду для команд, якія викорыстоўваюць гэты патэрн.
У гэтым карыце парадоксальная дорага ад сыр'ёў да рабочай системы для стварэння агента Text-to-SQL на Python, дзе ўсё, што ёсць — толькі код. Акцэнт ставяцца на практычныя крокі, чысткія перакананні і код, які можна проста падставіць у репазітарый без неабяснення меты. Для загальнага адгледжэння, перш чым зменяць код, неабходна визначыць вхідныя даны, адпаведальнага за крок і критэрыя завершэння. Аперацыёныя працавікі должны магчымае перадзваніць крок з вядомай точкі контролю, не спрабоўваючы з'ясаваць схованы стан. Спрыйміце гэты этап як кантракт межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы артыфактам, визначыце перакананні на успех і адмовіцеся ад тыхняй частковай завершэнні без паведамлення.
Разлік: вярніце проты рэалізацыі
Калі працюеце над «Разлучэнне: адзіначэнне проты рэалізацыі», спачатку запісайце умовы вярбавання: неабходныя данні, сігнал працэйнасці і тое, што выканаецца у разы ў частковай нявыполненасці. Такі список дапамагае залічыць зямныя змены ў кодзе.
Што вам патрэбна
Калі працуеце над раздзелам «Што вам патрэбна», спачатку запісайце умовы контракту: неабяжлівыя данні, сігнал успеху і тое, што выканаецца у разе частковага нявыпалення. Такі список контроля дапамагае заліцварыць будучыя змены ў кодзе. Зберагаюце настройкі пазырочна ад коду прыемліка. Файлы сераўнавання, хранільнікі секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аудыт без неабяжлівага чытання всей структуры. Запісвайце ID запытку, ID модэлю і час адклікання праз кожны вызов. Без такога лёгку, можна з’яўіцца, што патэнцыяльныя бяги прадаўца ёсць багамі прыемліка.
pip install acruxcore
1. Створыце базу дадзеных, якая паслужыць для запытанняў
Калі працюеце над пунктам 1. «Садзіце базу данных, якая паслужыць для запитоў», спачатку запісаце контракт: неабходныя даны, сигнал пра успех і тое, што выходзіць пад частковым нявыпаннем. Такі список контроля дапамагае заставіць пазнейшыя змены коду быць чыстымі. Документавацыя успешнаг і варыянтаг падходу трэба выконваць разам. Перапрыткі, людзкія перакрыцця і обробка некоректных паведамленняў ёсць частью продукту, а не пазнейшым дапрацоўкам. У кожным запыте фіксаваць ID запыту, ID модэлю і час адпаведзення. Без такога лёгкага следу періядычныя памылкі прадаўцоў выглядаюць як багі ў самай аплікацыі. Калі працюеце над пунктам 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. Зарэгіструйце модель у панелі керування
- Зарэгіструванне моделью ў панелі керування будзе эфектываўша, якщо ёё спрыята розглядаць як виміроўваную паверхню. Запісаце адна ідеальная транскрыпцыю, адзін прыклад неудачы і прыметку пра адвярненне змян перш чым расширваць сферу дзеяння. Запісвайце часы выконання і кост токена або запиту па боку функцыональных рэзультатаў. Відразлівае паказанне костаў з’являецца рана, што запобегае неспакою з боку расчыткаў, калі праця пераходзіць з дэмаверсіі ў спакульнаныя сераўысы. Зафіксавайце інтэрпретара і файл з правіламі залежнасцяў пры пачатку навучэння ціклу. Разлікы межаў лэптопа і CI ёсць найчымнейшым таямным абар’ятам для дэмаверсій API.
3. Запішыце запит у панелі керування
- Найкраща практыка запісу запитоў у панелі керування — адносіцца да яе як да вимірюванай плошчы. Зафіксавайце адна ідеальная версія роботы, адзін прыклад неудачы і запіс про відкатанне перш чым расширваць масштабы. Зберагаюце настройкі пазначаныя окрэмна ад коду прыемленае. Файлы сераўнавання супакоў, хранілішча секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць контроль без неабяжнага чытання всіх дадзеных. Закрепіце інтэрпретара і файл з блокаванням залежнасцей пры практыкуванні циклаў. Разлікы межа лептапам і системай 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. Апісацыя інструмента ў кодзе — і дазволенне яму самаму публікувацца
- Апрэцяванне інструмента ў коде — і дазвол чыніць яго публікацыю працуе наяўней калі яго спрыяваць як меравальную плошчу. Зберагучы адна ідеальная транскрыпцыю, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расширваць сферу дзеяння. Дакументавацыя успішнага і восстанавліваючага падхода трэба адмашчаць разам. Перапрыбуткі, людзкія контралі і обработка некоректных паведамленняў є часткай продукту, а не наступным этапам дорабачання. Зафіксаваць інтэрпретара і файл з блокірацыяй залежнасцей пры першай нарадзе з цикламі. Разніця межу лептапам і системай CI є найпашчэрэйшым тыхім абаранкам для дэмонстрацый API.
- Апрэцяванне інструмента ў коде — і дазвол чыніць яго публікацыю працуе наяўней калі яго спрыяваць як меравальную плошчу. Зберагучы адна ідеальная транскрыпцыю, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расширваць сферу дзеяння. Цей этап трэба спрыяваць як даговор межу вхіднымі данымі і перакананымі выходнымі рэзультатамі. Назваць артыфакты, апрэцяваць критэрыі успеху і не падтрымляць тыхое часткова завершэнне задання.
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. Рэзультат: зменіце модель без змены коду, спачатку запісайце контракт — неабяжлівыя даны, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі список пераканае ў тым, што пазнейшыя змены коду будуць чыстымі. Зберагаеце настройкі за межамі коду прыемліка. Файлы сераўнавання, храненні секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавіць аудыт без неабяжлівага чытання всей структуры. Запісваеце ID запытку, ID модэлю і час адпаведзення праз кожны вызов. Без такога лёгкага следу періядычныя памылкі прадастаўця выглядаюць як багі прыемліка.
Чы хаця бы ваш код павінен кантролюваць інструмент?
Калі працюеце над пытаннем «Чы гэты код усё-такі должен кераваць інструментам?», спачатку запісайце контракт: неабяжлівыя даннэ, сигнал працявання і тое, што выходзіць на частым неякшым рэзультатам. Такі чарточкі дапамагаюць залічваць пазнейшыя змены ў кодзе чыста.
Куды працаваць далей
Найкращы спосаб прымкнуць да наступных крокаў — адносіцца да гэтага як да вимернай паверхні. Зберажыце адны ідеальны прыклад роботы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Запісвайце часы виконання і косты токеноў або запытак па боку ад функцыйнальных рэзультатаў. Візуабельнае прадставленне костаў з самага пачатку запобегае неспакойным рахункам, калі процес пераходзіць з дэмавайнага режыма ў спяльныя сераўеры.
Чэк-ліст для эксплуатацыі
Чэк-ліст для эксплуатацыі найэфектывней працюе, калі яго адносяць да вимернай паверхні. Зберажыце адны ідеальны прыклад роботы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба.
Валідзіце маленькія, тэставаныя элементы замест большых скрыптаў. Калі якісь крок не выходзіць, неудача должна адносіцца да адной конкрэтнай відпаведальнасці, а не да заплутанага ланцуга задач.
Перш чым выкладваць інструкціі па викорыстоўванні цыклу, зафіксавайце версіі інтэрпретара та файлы блакавання залежнасцяў. Неспакоі межы ноутбука і системы 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 па спроўвачэнню захода з паўнейшага забезпечэння: меравайце час выканання, класію адзінакоў і колькасць выкарыстоўваных токенав для гэтага запісу, а пасля, на аднойчынных критэрыях, а не на асоціяціях, вынікніце рашэння пра тое, чым застаўці змены.