Якщо ви не використовуєте ці три захисні механізми у своєму AI-агенті, він вже надіслав їх.
Покрокова інструкція: якщо ви не використовуєте ці три механізми захисту у своєму AI-агенті, він вже надіслав контракти, перевірки та готові шаблони коду для команд, які впроваджують цю модель.
Використовуйте цей документ як оновлену версію ідей зі статті “Якщо ви не використовуєте ці три механізми захисту у своєму AI-агенті, він вже надіслав ваші секрети постачальнику”, орієнтовану на операторів: чіткі етапи, впорядковані блоки коду та примітки з відновлення, які залишаються при передачі обов’язків. Етап Огляду найкраще функціонує, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітки щодо скасування змін перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.
Спочатку: що таке мідлверд та навіщо він існує?
На першому етапі «що таке мідлвейр» необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Призначте назви для кожних елементів, визначте критерії успіху та не допускайте мовчазного часткового завершення. Вимагайте людського схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повності виконання бізнес-завдань.
Механізм, який перешкоджає потраплянню конфіденційної інформації до моделі:
Для захисту етапу виконання необхідно перед змінами коду визначити вхідні дані, власника кроку та критерії завершення. Оператори мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. У разі, коли наступним кроком є код чи виклик інструменту, краще використовувати структуровані результати з перевіркою схеми, ніж вільний текст.
PIIMiddleware
Для етапу PIIMiddleware необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, яке оператори можуть перевірити, не читаючи весь алгоритм. Встановлюйте людське схвалення для кроків, які спричиняють витрати грошей чи змінюють дані у продакшені. Підключення на етапі компіляції не є гарантією повноти бізнес-логіки. Для етапу PIIMiddleware необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу.
from langchain.agents.middleware import PIIMiddleware
PIIMiddleware(
"email",
strategy="redact", # replaces match with [REDACTED_EMAIL]
apply_to_input=True, # scans what you type
apply_to_tool_results=True, # scans what tools return - never skip this
)
import re
API_KEY_PATTERN = r"(?:sk-|ghp_|AKIA)[a-zA-Z0-9]{20,48}"
# sk- → OpenAI and Anthropic keys
# ghp_ → GitHub personal access tokens
# AKIA → AWS access key IDs
PIIMiddleware(
"api_key",
detector=API_KEY_PATTERN,
strategy="redact",
apply_to_input=True,
apply_to_tool_results=True,
)
Блок схвалення, який запобігає тихим видаленням:
Під час роботи на цьому етапі спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та наслідки часткової невдачі. Такий перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте тихого часткового виконання завдань. Робіть перевірки після дорогих кроків. Система відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор намагається виконати наступний етап.
HumanInTheLoopMiddleware
Під час роботи над етапом HumanInTheLoopMiddleware спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Робіть перевірки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізніший етап.
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.sqlite import SqliteSaver
# The checkpointer is not optional. Without it, resume is impossible.
with SqliteSaver.from_conn_string("./review_agent.db") as checkpointer:
agent = create_agent(
model="anthropic:claude-sonnet-4-20250514",
tools=[read_file, list_directory, write_file, search_codebase],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"write_file": True, # always pause before writing
"read_file": False, # reading is safe - no pause needed
"list_directory": False,
"search_codebase": False,
}
),
],
checkpointer=checkpointer, # saved to SQLite, persists across restarts
)
# First call — agent hits the interrupt at write_file and pauses
result = agent.invoke(
{"messages": [{"role": "user", "content": "Review and fix the config files"}]},
config={"configurable": {"thread_id": "session-001"}}
# thread_id ties the saved state to this specific session
)
# result.interrupted == True
# result.pending_tool_call == {"name": "write_file", "args": {"path": "src/config.py", ...}}
# You show this to the user and wait for approval
# User approves - resume the same thread
final_result = agent.invoke(
Command(resume=True),
config={"configurable": {"thread_id": "session-001"}}
# same thread_id - loads state from the checkpointer and picks up where it stopped
)
Два ліміти швидкості, два різні способи збою – обидва вам потрібні
Під час роботи з двоступеневою системою обмежень швидкості спочатку складіть опис контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Робіть контрольні пункти після дорогих кроків. Функція відновлення не повинна знову стягувати плату за той самий виклик LLM, коли оператор перезапускає пізніший етап. Під час роботи з двоступеневою системою обмежень швидкості спочатку складіть опис контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Віддавайте перевагу малим, тестованим одиницям коду перед величезними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.
from langchain.agents.middleware import ModelCallLimitMiddleware, ToolCallLimitMiddleware
ModelCallLimitMiddleware(
max_calls=30,
on_limit="raise", # raises MaxCallsExceeded - catch this in your application
)
ToolCallLimitMiddleware(
max_calls=60,
on_limit="raise",
)
Правило порядку, про яке майже не згадують у навчальних матеріалах, і яке тихо руйнує ваш шар безпеки
Це правило порядку працює найкраще, коли його розглядати як вимірювану поверхню. Збережіть один ідеальний зразок роботи, один випадок невдачі та примітки щодо скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте тихого часткового виконання завдань. Зберігайте стан графа у простому та типованому вигляді. Вкладені структури приховують інформацію про те, який вузол заповнив певне поле, що ускладнює продовження роботи після перерв.
middleware=[
# PIIMiddleware always first — it must see raw, untransformed data
PIIMiddleware("api_key", detector=API_KEY_PATTERN, strategy="redact",
apply_to_input=True, apply_to_tool_results=True),
PIIMiddleware("email", strategy="redact",
apply_to_input=True, apply_to_tool_results=True),
# Limits next - exact position within the group is flexible
ModelCallLimitMiddleware(max_calls=30, on_limit="raise"),
ToolCallLimitMiddleware(max_calls=60, on_limit="raise"),
# Human-in-the-loop last in the safety group
# (it fires in the after_model hook regardless of list position,
# but last is a readable convention)
HumanInTheLoopMiddleware(interrupt_on={"write_file": True}),
]
Об’єднання елементів: агент перевірки коду з такими ж властивостями безпеки, як у Cursor
Щоб етап «Об’єднання» функціонував найкраще, його слід розглядати як вимірювану поверхню. Запишіть один ідеальний приклад роботи, один випадок невдачі та примітки щодо скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовища до спільних середовищ. Тримайте стан графа простим та типованим. Вкладені блоки приховують інформацію про те, який вузол записав яке поле, і ускладнюють продовження роботи після перерв.
from langchain.agents import create_agent
from langchain.agents.middleware import (
PIIMiddleware,
HumanInTheLoopMiddleware,
ModelCallLimitMiddleware,
ToolCallLimitMiddleware,
)
from langgraph.checkpoint.sqlite import SqliteSaver
# Custom pattern for secrets common in codebases
API_KEY_PATTERN = r"(?:sk-|ghp_|AKIA)[a-zA-Z0-9]{20,48}"
# sk- → OpenAI / Anthropic keys
# ghp_ → GitHub personal access tokens
# AKIA → AWS access key IDs
with SqliteSaver.from_conn_string("./review_agent.db") as checkpointer:
agent = create_agent(
model="anthropic:claude-sonnet-4-20250514",
tools=[read_file, list_directory, write_file, search_codebase],
middleware=[
# 1. Catch secrets before they reach the model - on both surfaces
PIIMiddleware(
"api_key",
detector=API_KEY_PATTERN,
strategy="redact",
apply_to_input=True,
apply_to_tool_results=True, # this is the one that catches .env reads
),
PIIMiddleware(
"email",
strategy="redact",
apply_to_input=True,
apply_to_tool_results=True,
),
# 2. Hard resource limits - stops infinite loops and runaway sessions
ModelCallLimitMiddleware(max_calls=30, on_limit="raise"),
ToolCallLimitMiddleware(max_calls=60, on_limit="raise"),
# 3. Approval gate - nothing gets written without your explicit sign-off
HumanInTheLoopMiddleware(
interrupt_on={
"write_file": True,
"read_file": False,
"list_directory": False,
"search_codebase": False,
}
),
],
checkpointer=checkpointer, # required for interrupt/resume to work
)
Agent: I'd like to update src/config.py to fix the circular import.
Here is what I plan to write:
--- src/config.py ---
from typing import Optional
from pydantic import BaseModel
class Settings(BaseModel):
debug: bool = False
database_url: str = "sqlite:///app.db"
...
Approve this change? (yes/no)
User: yes
Agent: Written. Moving to tests/test_config.py next.
The agent cannot touch anything silently. Every write surfaces for review before it happens. Secrets in any file the agent reads are replaced with [REDACTED_API_KEY] before reaching the model — which also means they never appear in the approval prompt you read. What you are reviewing is already clean.
Чек-лист операцій
Під час роботи за етапом «Чек-лист операцій» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей чек-лист забезпечує прозорість подальших змін у коді.
Документуйте одночасно шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за той самий виклик LLM, коли оператор намагається знову виконати пізніший етап.
Фіксуйте версії залежностей та записуйте хеш-значення зображення, яке використовувалося під час демонстрації. Відтворюваність краща за індивідуальні знання спеціалістів.
Віддавайте перевагу невеликим, тестованим одиницям коду перед складними скриптами. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.
Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за той самий виклик LLM, коли оператор намагається знову виконати пізніший етап.
Перш ніж запускати стек у продакшн, заморозьте версії, створіть «золотий» запис для критичного шляху та підтвердьте кроки відкату. У спільних середовищах необхідні обмеження швидкості, перевірки прав власності та чіткий власник для зміни секретів. Краще обирати надійність, ніж креативні одноразові демонстрації.
Примітка для 8540643b792a: не включайте ключі постачальника до репозиторію, встановіть ліміт токенів на сеанс та зберігайте записи поруч із фікстурами для оцінки, щоб подальша заміна моделей залишалася порівнянною.
Для запису про посилення безпеки на етапі 0 визначте вхідні дані, власника кроку та критерії завершення ще до зміни коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не здогадуючись про прихований стан. Документуйте як успішний, так і відновлювальний шляхи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
Деталь посилення безпеки 0/723: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.
Під час роботи над першим етапом запису про посилення безпеки спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового виконання.
Деталь посилення безпеки 1/723: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.
Етап 2 процедури посилення безпеки працює найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний зразок роботи системи, один випадок збою та запис про скасування змін перед розширенням обсягу робіт. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код додатку.
Деталь посилення безпеки 2/723: вимірюйте час виконання операції, клас помилки та кількість використаних токенів для цього запису, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.
Для третьої стадії процедури зміцнення необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних.
Деталь зміцнення 3/723: вимірюйте час виконання, клас помилки та кількість витрачених токенів для цього кроку, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі критеріїв, а не на індивідуальних спостереженнях.
Під час виконання 4-го етапу додаткових заходів зпрочнення спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Поруч із функціональними результатами задокументуйте час виконання та витрати на токени або запити. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища до спільних.
Деталь 4/723 щодо зпрочнення: виміряйте час виконання, клас помилки та витрати на токени для цього етапу, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на індивідуальних спостереженнях.
4-й етап додаткових заходів зпрочнения працює найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один ідеальний запис виконання, один випадок невдачі та запис про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки.
Деталі посилення безпеки 5/723: виміряйте час роботи системи, клас помилки та кількість використаних токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.