Главная / Статьи / Практические заметки: Инженерия уздечек: Обнажённый агент: Почему ваша рамка передаёт контроль

Практические заметки: Инженерия уздечек: Обнажённый агент: Почему ваша рамка передаёт контроль

Пошаговое руководство по практическим заметкам: Harness Engineering: The Naked Agent: почему ваша архитектурная схема требует контрактов, проверок и готовых блоков кода для команд, использующих эту паттерн-архитектуру.

2011 слов

Используйте это как переработанную версию идей из материала «Harness Engineering: The Naked Agent: Why Your Framework Hands You a Loop, Not a Harness — I», ориентированную на операторов: четкие этапы, упорядоченные блоки кода и записи о восстановлении, сохраняющиеся при передаче задач.

Часть 1: Простой цикл агента кажется мощным, пока на него не поступит реальный трафик. Вот почему сбои в производственной среде обычно возникают из-за отсутствия необходимой структуры вокруг модели, а не из-за самой модели.

В части 1 простой этап работает лучше всего, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записи о возврате к предыдущему состоянию перед расширением объема работ. Документируйте как успешный ход выполнения задачи, так и процедуры восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Определите лимит токенов на каждый ход и сессию. Инструменты агентов активно расширяют объем контекста; жесткие ограничения предотвращают превращение демонстраций в неожиданные счета.

Большинство сбоев агентов связаны не с ошибками самой модели. Проблема кроется в отсутствии надлежащего уровня дисциплины вокруг нее. Вот как выглядит ИИ-агент без механизмов контроля в Claude Agent SDK и LangChain Deep Agents, а также три конкретных способа, которыми он выходит из строя при реальной нагрузке.

Для лучшего анализа сбоев агентов их следует рассматривать как измеримые показатели. Сначала соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объем работ. Лучше использовать небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое какого-либо шага причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций. Ограничьте количество токенов на раунд и сессию — инструменты агентов активно расширяют объем контекста; жесткие лимиты предотвращают неожиданные счета.

Модель — это не переменная

Модель работает наилучшим образом, если рассматривать её как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма задачи. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия создаваемым элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задачи. Установите лимит токенов на каждый ход и на всю сессию. Инструменты агентов активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов.

Что на самом деле означает «голый» формат

Подход «The What naked» наилучшим образом работает, когда его рассматривают как измеримую поверхность. Запишите один пример успешной работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Записывайте временные показатели, а также стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам. Используйте инструменты с узкими схемами и четкими метками о побочных эффектах. Хостам необходимо знать, какие вызовы изменяют состояние, прежде чем они автоматически одобрят их.

import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY
TOOLS = [
    {"name": "search_flights",
     "description": "Search flights between two cities for a date.",
     "input_schema": {"type": "object", "properties": {
         "origin": {"type": "string"}, "destination": {"type": "string"},
         "date": {"type": "string", "description": "YYYY-MM-DD"}},
         "required": ["origin", "destination", "date"]}},
    {"name": "book_flight",
     "description": "Book a specific flight.",
     "input_schema": {"type": "object", "properties": {
         "flight_id": {"type": "string"}, "passenger_name": {"type": "string"}},
         "required": ["flight_id", "passenger_name"]}},
]
def run_naked(user_msg: str) -> str:
    messages = [{"role": "user", "content": user_msg}]
    while True:                                   # ① no iteration cap
        resp = client.messages.create(
            model="claude-sonnet-4-6", max_tokens=1024,
            tools=TOOLS, messages=messages,
        )
        if resp.stop_reason != "tool_use":
            return resp.content[0].text
        call = next(b for b in resp.content if b.type == "tool_use")
        result = dispatch(call.name, call.input)
                                             # ② direct side effect, no check
        messages.extend([
                                             # ③ whole history, every turn
            {"role": "assistant", "content": resp.content},
            {"role": "user", "content": [{"type": "tool_result",
                "tool_use_id": call.id, "content": result}]},
        ])

Агент «The naked» в Claude Agent SDK

Агент в стадии разработки работает наилучшим образом, когда его рассматривают как измеримую среду. Соберите один эталонный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Используйте инструменты с узкими схемами и чёткими метками побочных эффектов. Хостам необходимо знать, какие вызовы изменяют состояние, прежде чем они автоматически одобрят операцию. Агент в стадии разработки работает наилучшим образом, когда его рассматривают как измеримую среду. Соберите один эталонный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. Когда какой-либо шаг срабатывает некорректно, причина сбоя должна указывать на конкретную ответственность, а не на запутанную цепочку операций.

import asyncio
from claude_agent_sdk import (
    query, ClaudeAgentOptions, tool,
    create_sdk_mcp_server, AssistantMessage, ResultMessage,
)

@tool("search_flights", "Search flights between two cities for a date.",
      {"origin": str, "destination": str, "date": str})
async def search_flights(args):
                                              # ① no check that date exists
    hits = flights_api.search(**args)
    return {"content": [{"type": "text", "text": str(hits)}]}
@tool("book_flight", "Book a specific flight.",
      {"flight_id": str, "passenger_name": str})
async def book_flight(args):
                                               # ② destructive, ungated
    confirmation = flights_api.book(**args)
    return {"content": [{"type": "text", "text": confirmation}]}
server = create_sdk_mcp_server("travel", tools=[search_flights, book_flight])
async def main():
    options = ClaudeAgentOptions(
        mcp_servers={"travel": server},
        allowed_tools=["mcp__travel__search_flights",
                       "mcp__travel__book_flight"],
    )
    async for msg in query(prompt="Rebook this customer for March 32nd.",
                           options=options):
        if isinstance(msg, AssistantMessage):
            for b in msg.content:
                if hasattr(b, "text"):
                    print(b.text)
        elif isinstance(msg, ResultMessage):
            print("done:", msg.subtype)
                                              # ③ no state survives this run

Агент в LangChain Deep Agents

Для этапа «Обнаженный агент на сцене» необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Укажите названия результатов работы, определите критерии успеха и не допускайте молчаливого частичного завершения задачи. Аутентифицируйтесь у шлюза и повторно авторизуйтесь на уровне передачи данных. Одного только токена-носителя недостаточно для обозначения границы тенантности.

from langchain.tools import tool
from deepagents import create_deep_agent

@tool
def search_flights(origin: str, destination: str, date: str) -> str:
    """Search flights between two cities for a date (YYYY-MM-DD)."""
    return str(flights_api.search(origin, destination, date))
                                                # ① no date check
@tool
def book_flight(flight_id: str, passenger_name: str) -> str:
    """Book a specific flight."""
    return flights_api.book(flight_id, passenger_name)
                                                 # ② ungated side effect
agent = create_deep_agent(
                                                 # ③ the loop, no controls
    model="anthropic:claude-sonnet-4-6",
    tools=[search_flights, book_flight],
)
result = agent.invoke({"messages": [{"role": "user",
    "content": "Rebook this customer for March 32nd."}]})
print(result["messages"][-1].content)
# Ask a follow-up in a second invoke, and it starts from zero: no thread,
# no memory.

Смотрите, как он может сломаться тремя способами

Для мониторинга процесса его разделение на три этапа позволяет определить входные данные, ответственного за каждый этап и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить этап с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами необходимо записывать время выполнения и стоимость токена или запроса. Отображение затрат заранее предотвращает неожиданные счета при переходе из демо-среды в общедоступные среды. Аутентификация происходит на шлюзе, а повторная авторизация — на уровне данных. Один только токен-носитель не является границей аренды.

Сбой 1: некорректный аргумент попадает в разрушительную функцию

В случае сбоя типа «некорректная стадия» необходимо заранее определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь кодовый граф. Аутентифицируйтесь у шлюза и повторно авторизуйтесь на уровне передачи данных. Один только токен-носитель не является границей между тенантами. В случае сбоя типа «некорректная стадия» необходимо заранее определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. При сбое шага причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций.

book_flight(flight_id=”AC-PHANTOM”, passenger_name=”J. Moffatt”)
# -> “Booked.” The action fired. Nothing in the loop asked whether it should.

Сбой 2: контекст выходит из-под контроля, а качество тихо ухудшается

При работе над этапом сбоя 2, когда контекст выходит из-под контроля, сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и то, что происходит при частичном сбое. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия соответствующим элементам, определите критерии успешности и не допускайте тихого частичного выполнения задачи. Записывайте название инструмента, хеш аргументов, время задержки и результат каждого вызова. Без такой информации отладка занимает гораздо больше времени.

Сбой 3: инструмент дает ошибку, а агент сообщает о успехе

При работе над этапом инструмента «Сбой 3» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичном сбое. Такой чек-лист помогает сохранять честность при последующих изменениях кода. Рядом с функциональными результатами записывайте время выполнения, стоимость токенов или запросов. Отслеживание затрат с самого начала предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам. Для каждого вызова фиксируйте название инструмента, хэш аргументов, время задержки и результат. Без такой записи отладка занимает гораздо больше времени.

Формат, которого должна придерживаться каждая часть

При работе над этапом «Форма каждой части» сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой список помогает сохранять честность последующих изменений в коде. Храните конфигурацию отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Фиксируйте имя инструмента, хэш аргументов, время задержки и результат каждого вызова. Без такой записи отладка занимает часы. При работе над этапом «Форма каждой части» сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой список помогает сохранять честность последующих изменений в коде. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. Если какой-то шаг не сработает, причина должна указывать на конкретную ответственность, а не на запутанную цепочку операций.

Сделайте это сегодня

Этот этап «Сделайте это сегодня» работает наилучшим образом, если рассматривать его как измеримую основу. Соберите один идеальный пример выполнения, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия создаваемым элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задачи. Используйте инструменты с узкими схемами и четкими метками о побочных эффектах. У операторов должна быть возможность узнать, какие вызовы изменяют состояние, прежде чем они автоматически одобрят их.

Модель — это самая простая часть

Модель работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один пример успешной работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счёты при переходе от демо-версии к общедоступным средам. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентного типа активно расширяют контекст; жёсткие ограничения не позволяют демо-версиям превращаться в неожиданные счёты.

Чек-лист операционной работы

При работе над этапом чек-листа операционной работы сначала запишите условия использования: необходимые входные данные, сигнал успешного завершения и действия при частичном сбое. Такой чек-лист обеспечивает прозрачность последующих изменений в коде.

Документируйте одновременно успешный сценарий работы и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки.

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

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

При наличии бюджета добавляйте тесты на работоспособность критического пути в процессе интеграционного тестирования с использованием фикстур, а не реальных платных API.

Записывайте временные показатели, а также стоимость токенов или запросов вместе с функциональными результатами. Ознакомленность со стоимостью заранее предотвращает неожиданные счета при переходе с демо-среды в общедоступные.

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

Примечание к заданию с идентификатором 765280e2df21: не хранить ключи поставщиков в репозитории, установить лимит токенов на сессию и сохранять транскрипции рядом с фиксами для оценки, чтобы последующие замены моделей оставались сопоставимыми.