Галоўная / Артыкулы

tool_use у Claude ад пачатку да канца: агентны цыкл за тры ітэрацыі

tool_use у Claude цалкам: адзін запыт Messages API праз агентны цыкл — вызначэнні інструментаў, tool_choice, паралельныя выклікі і правілы tool_result.

Выдавец: REACTAPP.TOP19 хв чытання4379 слоў

Крыніцы: Part III | ‘tool_use’, End to End: The Agentic Loop in Three Iterations

Чаму цікл трэба пісаць самостоятэльна

Работа з tool_use прымыткава праз Messages API (спачатку anthropic.Anthropic(), а потым client.messages.create(...)) дае вам можлівасць самім стварыць цікл. У вашам кодзе прызначаюцца інструменты, аналізуецца прычына зупінкі, парсуюцца запіты Claude, яны выкананы, і вяртаецца рэзультат ўжо выкананых дзеянняў. Рукамі напісаны такі цікл ёсць основай кожной сістэмы, якая вікорыстоўвае інструменты, і гэта стандартная тэма ў навучальным плане Claude Certified Architect.

Спачатку нагадка: Messages API не мае стану. Нічога не запам’ятваецца між вызывамі, таму кожны запіт несе ў сабе весь дыялог, а практыка вікорыстоўвання інструментаў зазвычай складаецца з калькі запытоў, а не з однаго, якія павтараюцца, пакуль Claude не отрымае неабходнае. Рэшта працэсу выконваецца за дапамогою аднаго запыту пры пераходзе па цыклу.

Прыгаючы прыклад — гэта невялікі асістэнт для планавання. Пользоватэль запытаецца, чы гэта трэба взяць парасольку на зустрэч у Ландане завтра, і калі трэба выйсці з дому, каб прыбыць у час. Для адказу трэба тры околічны факты: дэталі зустрэчы, прогназ пагоды і час паўтарання паўтары. Пазірце, як Claude дзеліць запыт на тры ітэраціі, і як вялікая частка працы падпадае на ваш код, а не на мадэль.

1. Форма ціклу

Кожны абмян пра выкарыстоўванне інструмента выконваецца за аднім чатырофазным цыклам:

  1. Актуальвацыя інструментаў у запытэ.
  2. Claude запытаецца пра адны чы роўналькі з іх, што пазначаецца кодам stop_reason: "tool_use".
  3. Ваш код заўодзіць іх і скупляе рэзультаты.
  4. Вы падаеце назад рэзультаты і зноў вызываеце API.

Фазы з 2-й па 4-ю павтараюцца, і кожны прыход залічаецца як адна ітэрацыя. Цыкл завершаецца, калі Claude перастае запрашваць інструменты і вяртае звычны рэзультат завершэння (end_turn) або іншую прычыну завершэння. Пакалькі API не мае стану, таму вы самі ствараеце дыялог і перадаеце яго ў кожны раз. Нічога не рухаецца далей, калі толькі ваш код гэта не зробіць.

2. Акцэнаванне інструментаў

Claude можа выкарыстоўваць толькі тыя інструменты, якія вы пераказалі. Яны знаходзяцца ў параметры tools верхньага рэвэля запыту, якая мае масэвую з маўчаннямі ўявленняў. Кожны раз, калі ёсць tools, API стварае супернечны сістэмны прапанунак на адной з падставаў паведамлення корыстніка. Гэты супернечны прапанунак таксуецца: кожна назва, апісанне і схема займаюць токены вхідных дадзеных у кожны запыт, нават калі Claude ніколі не выкарыстоўвае інструмент.

Кожны кліентскі інструмент патрэбуе трохоў полей:

  • name — гэта унікальны ідэнтыфікатор, які павінен адпаваць фармату ^[a-zA-Z0-9_-]{1,64}$. Гэта строка, якая вяртаецца ў блоке tool_use, і ваш код выкарыстоўвае яе для вызову правільнай функцыі.
  • description — гэта апіс у простай мове пра мэт прыемніка, правы момент яго выкарыстоўвання і значэнне кожнага параметра. Нічога іншага не вплывае на правільны вызов так сільна, таму напісайце яго як спецыфікацыю, а не як пазначку.
  • input_schema — гэта JSON Schema для аргументаў: іх тыпы, якія можуць быць required, і тое, што кожны з іх абначае.

Цікавіцеся, якія тры прыемнікі выкарыстоўваюцца ў прыкладзе:

"tools": [
  {
    "name": "get_calendar_event",
    "description": "Look up a calendar event by a natural-language query. Returns the event's start time and location.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "query": { "type": "string", "description": "What to search for, e.g. 'meeting in London tomorrow'" }
      },
      "required": ["query"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_weather",
    "description": "Get the forecast for a city on a given date. Returns condition and temperature in Celsius.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "city": { "type": "string", "description": "City name, e.g. 'London'" },
        "date": { "type": "string", "description": "ISO date, e.g. '2026-07-14'" }
      },
      "required": ["city", "date"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_travel_time",
    "description": "Estimate door-to-door travel time between two places. Returns minutes.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "origin": { "type": "string", "description": "Starting location" },
        "destination": { "type": "string", "description": "Ending location" }
      },
      "required": ["origin", "destination"],
      "additionalProperties": false
    }
  }
]

З’явірнайце іх адзёрнае. Кансалтатыванні Anthropic пра эфектывныя інструменты скарочваюцца да калькі прыёмоў:

  • Будзьце конкрэтныя ў назвах інструментаў. get_current_weather дае Claude больш інфармацыі, чым weather.
  • Называйце і апісвайце параметры без двусмысленнасці. Валіце user_id замест user, каб была задана правільная значэнне, і апісвайце кожны параметр, адтолькі што добра названая палата з нечыстым апісаннем таксама прымяча некарэктны вхідны даныя.
  • Залічвайце набор інструментаў малым. Занадта вялікі набор заплямоўвае створаны сістэмны прапан і робіць выбір модэлю нечыстым.
  • Перакананайце усё. Схема абмежвае структуру, а не намер, таму пераканайце кожны вхідны даныя, які прымае ваш код.

Два дадатковыя пункты ў гэтых вызначэннях заслуговуюць на адзёрнае розглядзенне.

  1. strict: true мае найбольшое значэнне. Ён знаходзіцца на верхнім рэвэлі кожнага інструмента разам з name, description і input_schema і актываўае працэс выбору дадзеных, якія паслухаюцца граматычным правілам для аргументаў інструмента, таму мадэль фізычна не можа стварыць input, які нарушае вашу схему. Калі яго не выключыць, Claude зазвычай выдае правільныя аргументы, але можа дапускаты пахыбкі, напрыклад "2" там, дзе была патрэбна цыфра 2, значэнне, якое не ўходзіць у enum, або відсутняя неабходная польна. Кожная такая пахыбка стае прычыной неудачы пад час выканання коду, які выкарыстоўвае вызов. Як толькі strict: true будзе актываўана, input у будзь-ям блоке tool_use обавязкова будзе паслухацца input_schema, а назва будзе без адной пахыбкі адна з вашых сэрвісаў.
  2. Адзін правілл схемы гарантуе, што кожны об’ект павінен задаць additionalProperties: false, таму ён прысутны ў кожным з вышэказаных інструментаў. Строгая адпаведнае інструментам настаўка ёсць часткай функцыі структураваных выходаў Anthropic. Калі гэта было напісана, гэта было загалова доступна для сучасных модэляў, такіх як Opus 4.8, а старэйшыя модэлі, такія як Sonnet 4.5, выкарыстоўвалі бета-загаловак structured-outputs-2025-11-13. Скомпільаваныя схемы залішаюцца у кэшы прыблізна 24 гадзіны, таму наявнасць «тэплага» кэшу значыць відсутнасць додатковых вітатаў на компіляцыю.

Вы таксама можэце прыўязаць cache_control да вызначэнняў інструментаў, каб кэшаваць іх між запытамі і ухіліцца ад платаў за перапрацавку, што ёсць цяжка важлівым, калі набор інструментаў вялікі і стабільны.

Вызначэнні опісваюць толькі вхідныя даны

Адзінклія інструмента абараняе толькі вхідныя даны, тыя самыя, якія Claude дае вам. Гэта дзівіць людзей з фрэймворкамі, якія заявляюць тыпы рэзультатаў. Проста кажучы:

  • У адзінкліі ўскладнены name, description і input_schema як обавязковыя элементы, а strict, input_examples і cache_control — як неабавязковыя дапаможныя элементы. Не існуе ні output_schema, ні error_schema.
  • Значэнні, які вяртаюцца, выконваюцца пад час працы вашым кодам, а пасля вяртаюцца ў блоке tool_result, опісанам у раздзеле 6. Поле content можа мець або строку, або спіс блакоў, і API не пераканальвае яго ні з чым, адколі няма схемы для пераканальвання. Адна практычная працавая прытаманнасць: інструмент можа вярнуць об’ект DTO, а стандартны парсер ператварае яго на звычную строку за дапамою методу toString. Выведэнне такой ператваранай формы працюе, але не ўсё так і ідэальна. Аднойчы ператварыце DTO-ы на структураваны JSON.
  • Адказы таксама ўзьязначаюцца пад час працы. Паведаміце пра невыпаны вызов за дапамою is_error: true у tool_result і інформатыўнага паведамлення ў content; у вызначэнні няма дэкларатыўнага тыпу адказу. За замовчаннем SDK перадае вызваную асывячанню Claude як адказ з адказам, і Claude яго корэгуе.
  • Неравнавесна структура ўмышленая. Апісанні існуюць для таго, каб показаць Claude, як запускаць інструмент. Рэзультат — цэла проста дадатковая інфармацыя, якая прыўязуецца да ціклу, таму, кроме tool_use_id, які прыўязуе яго да запіту, ніякіх дагавораў не патрэбна.
  • Хочаце гарантаванага фармата выходных дадзеных? Пераканайцеся сабе ў кодзе прытым, прышлівшы ўсё назад, або застосавайце структураваныя выходы (output_config.format) да адпаведнай адпаведзі, яку Claude піша на аднойчынку з тых рэзультатаў. Інструменты MCP прыносяць свой outputSchema, але гэта ўластка шара MCP, а не власнае апісанне.
  • Контроль за тым, чы робіць Claude вызов інструменту

    tool_choice вяршыць, чы можна запускаць інструменты ў певны момент і якія саме.

    • Этот поле знаходзіцца на верхнім рэвэлі запіту, праз tools і messages, і не належыць ніяму конкрэтнаму інструменту.
    • Ён обмежвае тое, што можа выдаты Claude. Логіка застаецца незменнай, таму што Claude чытае весь запрос без адміністрацыі.
    • Яго дыянне аплікуецца толькі да адного запросу, ніколі не да всіх. API ў стане без дадзеных, таму tool_choice керуе толькі адпаведным адпаведнаму запросу адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адпаведнаму адп
    {
      "type": "auto" | "any" | "tool" | "none",
      "name": "get_weather",              // required ONLY when type is "tool"
      "disable_parallel_tool_use": false  // optional; default false
    }
    

    type ўсёга неабходны і можа прымаць адна з чатырох значэнняў. name патрэбны толькі тады, калі type равнае "tool". disable_parallel_tool_use ўзлегкай можна не выкананы і он обмежвае колькісць інструментаў, якія можна вызваць за адну спробу.

    auto. Claude сама адлучвае: нуль, адзін чы несколькі інструментаў, чы тэкстовая адпаведзь. Дазволены паралельныя вызывы. Можна даць адпаведзь у простым тэксце, а Claude можа рассказаць прычыны перад вызывамі. Гэта стандартны рэжым, калі заданы tools. Калі задаць disable_parallel_tool_use: true, то дазволяе толькі адзін інструмент, хоць нуль таксама можлівы. Гэты рэжым падходзіць для чат-асістэнтов і агентных цыклаў, дзе для разных спроб патрэбны разныя дзеянні. Цэй ўдзінны рэжым, які дазволяе Claude голасна размышляць пры выкананні дзеяння, і ўдзінны рэжым, кроме none, які працуе з розгледам.

    any. Claude павінен вызваць адзін з інструментаў, але сам выбірае які. Выканана прынеймна адна вызовка, і адколькі паралельны выкарыстоўвання ўвесь час ўвімкнута, можа вернуцца калькі блакоў tool_use, не обав’язкова адна. Толькі адна вызовка выканана толькі тады, калі задаўмае значэнне disable_parallel_tool_use: true. Не дазволены просты тэкст, няма прадзеўнага абяснення, і гэта ніколі не ёсць стандартным станом. Оыкорыстоўваце яго, калі рэзультат, атрыманы за дапамогою інструмента, ёсць ўмовнай, але сам інструмент разны, як у разе рутэраў і класыфікатораў.

    tool. Claude павінен вызваць той апарат, які вы назвалі, таму name ўмовны. Адбываецца прынеймна адна вызовка гэтага апарата (яго можна вызваць калькі разоў паралельна), і толькі адна з параметрам disable_parallel_tool_use: true. Не павінна быць ніякога простага тэксту, ніякіх падставных пояснэнняў. Гэта падходзіць для структураванага выкарыстоўвання апарата ў аднай процэсе, як обавязковага першага крока, або для шаблона JSON праз апарат, напрыклад {"type": "tool", "name": "get_weather"}. Запрос з назвам апарата, якога няма ў tools, вяртаецца з кодам 400, а прымусовае выкарыстоўвання апарата не обмежвае яго адной вызовкай, калі толькі паралельнае выкарыстоўвання не заблокавана.

    none. Воблак не можа выкорыстаць жадных інструментаў у гэтым раундзе, нават якія бы тыя не былі занесеныя, а stop_reason не можа быць tool_use. Дазволеныя ўсе простыя тэксты, а таксама поясненні прычын. Гэта стандартны стан, калі не паведамленыя жадныя tools. Оыкорыстаюце яго, каб прымусіць раунд толькі з тэкстам, напрыклад для фінальнага сінтэзу, не змінюючы масэвую tools. Гэта выключае інструменты без правкі масэвы, хоця пераход на гэты стан все равно унічыляе запам’ятаваныя блакіткі паведамленняў.

    Існуе калькі дэталей, якія лёгка занедбаць:

    • У прымусовых рэжымах прамова выключаецца. У рэжымах any або tool API загадзя заповнюе частку асістэнта, таму блакітка tool_use прыходзіць без жадных пояснэнняў чы разумоў, незалежна ад вашага запіту. Для паказу разумоў трэба выбраць auto.
  • Для розсуванага спосабу развіювання думак утрэбны auto або none. Йго нельга яе ўжываць разам з прымусовым выкарыстоўваннем інструменту, і API адхіляе такую комбінацыю.
  • Правіла лічэння для disable_parallel_tool_use. auto означае не больш аднаго, any і tool — аднаго адносова, а стандартны значэнне false дазволяе паралельныя запыты да модэляў Claude 4.
  • Косць кэшавання. Змена tool_choice між запытамі анулюе кэшаваныя блакі змены. Апісанні інструментаў і сістэмны прапанун застаюцца у кэшы, але размова перапрацоўвана занова.
  • Ёго трэба яе ўжываць разам з strict. tool_choice гарантуе, што інструмент будзе выкананы, а strict — што яго аргументы будуць адпаведныя схеме. Разам яны забезпечваюць, што ў кожны момент будзе атрыманы структураваны, з тыпамі дадзеных, рэзультат.
  • У запіце:

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,
        tool_choice={"type": "any", "disable_parallel_tool_use": True},  # must call exactly one tool
        messages=messages,
    )
    

    З гэтага выйшлі два правілы дызайну. Заставіце вікорыстоўванне інструментаў толькі тады, калі абавесці ўпэўненыя ў тым, што трэба атрымаць рэзультат ад інструмента, а калі простая адпаведзь ўзятая з auto ўсё ў парадку, застаўце гэты рэжым. Таксама, калі інструмент класыфікацыі вымушаны быць вікорыстоўваным, дадзіце опцыю "other" у яго enum, каб Claude мог узяць на адмову тую катэгорыю замест таго, каб неправерна пазначыць вхідны даны, які ён не можа пасортаваць.

    3. Першая ітэрацыя: Claude прасіць пра інструменты

    Запрос адна об’едначае массів інструментаў, tool_choice з вашага выбору і запіт корыстніка:

    messages = [{"role": "user",
                 "content": "I have a meeting in London tomorrow
                             — should I bring an umbrella, and
                             when should I leave home to be on time?"}]
    
    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,                    # the three strict definitions from Section 2
        tool_choice={"type": "auto"},   # let Claude decide whether, and what, to call
        messages=messages,
    )
    

    Воблак разбірае запіт і бачыць, што два з трох прыемнаў не залежаць адзін ад другога: пашук у календары і прагнозаванне можна запускаць паралельна. Таму ён прасіць прыняць оба інструменты ў аднай адпаведзі. Незалежныя запыткі, якія вяртаюцца разам, называюцца паралельным выкарыстоўванням інструментаў, і яны праказваюцца як калькі блакоў tool_use у аднай раундзе.

    {
      "id": "msg_01...",
      "role": "assistant",
      "stop_reason": "tool_use",
      "content": [
        { "type": "text", "text": "Let me check your meeting details and the London forecast." },
        { "type": "tool_use", "id": "toolu_01Cal", "name": "get_calendar_event",
          "input": { "query": "meeting in London tomorrow" } },
        { "type": "tool_use", "id": "toolu_01Wx", "name": "get_weather",
          "input": { "city": "London", "date": "2026-07-14" } }
      ]
    }
    

    У той адказе выдзеляюця тры рэчы.

    1. stop_reason ў значэнні tool_use, што значыць, што раунд не завершаны і Claude чакае на вас.
    2. Масава content містыць сумешанне элементаў. Блок text з наратываючым тэкстам часта выклікаецца раней за блакі tool_use, таму вызывы інструментаў не знаходзяцца на фіксаванай пазіцыі.
    3. Кожны блак tool_use мае id (з прыметкай toolu_), name і об’ект input, які вялікай часткай падпадае пад вашу схему.

    Шукайце вызывы, пераглядаючы элементы content і фільтруючы ўжо за тыпам, а не за індэксам:

    tool_calls = [block for block in response.content if block.type == "tool_use"]
    

    Гэта дае два вызовы тут. Кожны id являецца ідэнтыфікатарам для атрымання рэзультата таго вызову, а спароўванне id з рэзультатам — гэта спосаб, якім Claude паўтарае адпаведзі на запытанні, калі існуе калькі запытанняў.

    Прымечанне для модэляў Claude 4: розглед можа вестыся паэтапна, таму логічныя выводы можу адбывацца як між вызывамі інструментаў, так і перад імі. Калі розглед увімкнуты, неабходна перадаць блакі розгледу разам з рэштой часткі працы асістэнта, інакш продажчык забудзе пра тыя выводы.

    4. Адкліканне інструментаў

    Цяпер задача пераходзіць да вашага коду. Claude запрашаў два інструменты, але ніжны не адкліканы. Выконайце усё, што ён запрашаў, зберыце всі рэзультаты і апрашчыце адзін наступны вызов, які будзе ўключаць іх усе. Claude чакае, пакуль кожны з яго вызоў не атрымае адпаведнага рэзультата.

    Гэта вы выбіраеце, чы рэалізацыя будзе паралельная чы последовальная, адколі Claude гэта не прызначае. У адпаведнай адпаведзі сказана, калі ўваходзіць вызначыць, а не як яго планаваць. Незалежныя вызывы, такія як запыты пра календар і погоду, можна адкрываць одночасна, ўскораючы час адпаведзі. Калі адны вызыв залежыць ад рэзультата іншага, яго трэба адкрываць па парадку. Мадэль парадкуюць пра залежнасці, групуючы незалежную работу ў паралельныя блокі і відкладаючы залежную работу на пазнейшы крок, што і адбываецца ў другой ітэрацыі. Ніткі, асінхронна работа чы очакальныя лісты — гэта выборы вашага цыклу, а не API.

    У прымэтнае працы спрыймайце рэалізацыю як ненадзеяны I/O, які можа зламацца:

    • Задаўце кожнаму інструменту таймаут, каб адзін повольны вызыв не заморажваў весь працэс.
    • Дапытайцеся ідэмпатэнтных операцый, калі гэта можліва, адколі перапрыбуткі і павторныя запыты ёсць немінучымі ў агенце.
  • Контролюйце адказы на кожны вызов. Калі аднай з двух паралельных адпрацоўчых сістэм выйдзе канфлікт, яшчэ такі час трэба адправіць рэзультат для яе (больш па is_error ніжэй), а не перываць выконанне.
  • Аналізуйце цікл. Зволікання для кожнай адпрацоўчай сістэмы, колькасць вызоў, выкарыстоўванне токенав і ступень канфліктав паказваюць, чы робат працуе нормальна чы поступова пагіршваецца.
  • 5. Крокі да і пасля выканання адпрацоўчай сістэмы

    Контроль ціклу значыць контроль двух перыодаў: перыоду між „Claude прагледзеў адпрацоўчую сістэму“ і „адпрацоўчая сістэма запрацавала“ і перыоду між „адпрацоўчая сістэма запрацавала“ і „рэзультат быў адправлены“. Ім трэба даць назвы, бо ступень ўжоўванняя іх у дзейнасці ёсць галоўная прычына разніцы між безпечным робатам і робатам з высокым рызыкам.

    Шаг пярэд выкананнем адпрацоўкі выкананы ў пярэдзе выканання. Ён аналізуе запрошаны вызов і прымечае, чы робіць яго без змян, змяніць чы адмовіць. Сюды і адбываецца рэалізацыя правілаў: Claude прымечае можлівасці, а ваш код прымечае рашэнне.

    Шаг пасля выканання адпрацоўкі выкананы пасля выканання і перад тым, як рэзультат вернуцца да Claude. Ён обрабоцоўвае неапрануты выходны даныя пасля выдалення частак, скорачэння, пераформатавання чы фіксаціі ў журнале.

    У цыкле Client SDK гэтыя элементы ўособліва ўособляюцца як функцыі, якія абгортваюць выкананне:

    for block in tool_calls:
        if not pre_tool_use(block):                       # validate / guard
            results.append(error_result(block.id, "Blocked by policy."))
            continue
        output = execute(block.name, block.input)         # run the tool
        output = post_tool_use(block, output)             # redact / log / reshape
        results.append(tool_result(block.id, output))
    

    Этап, які выкананыяюць перад вікорыстоўванням інструмента, — гэта тое месца, дзе знаходзяцца рэальныя механізмы контролю, і ўжо гэта завадзіба таго, хто інструмент рэалізуе, а не самай модэлі. Частыя патэрны выкарыстоўвання:

    • Пераканацца, што аргументы супакоўваюцца з вашай сябе політыкай, а таксама з схемай.
    • Катэгорычна адмовіцца ад разрушальных операцый: rm -rf для інструмента ў шэлі, DROP TABLE для інструмента базы дадзенаў.
    • Запытаць чалавека пра затверджэнне будзь-каго высокапатэнцыйяльнага дзеяння, напрыклад, запісу дадзеных у працоўную срэду.
    • Адмахнуць секрэты з аргументаў пры ўсіленні іх да зовнішньяго сервісу.
    • Запісваць кожны спробаваны вызов, каб было можна адбавіцца аўдытам і пераканацца у салідарнасці з правіламі.

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

    6. Вернуць рэзультаты

    Адказаеце на tool_use наступленне паштою user з лістам tool_result блакоў, аднаго на кожны tool_use блак у адказе, кожны з якіх прыязаны да свайго tool_use_id. Спачатку дадзіце наступленне асістэнта да чыннага ліста паштоў, а пасля рэзультаты як нова наступленне карыстальніка. Першая ітэрацыя выглядае так:

    {
      "role": "user",
      "content": [
        {
            "type": "tool_result",
            "tool_use_id": "toolu_01Cal",
            "content": "{\"start\": \"2026-07-14T15:00\", \"location\": \"Canary Wharf, London\"}"
        },
        {
            "type": "tool_result",
            "tool_use_id": "toolu_01Wx",
            "content": "{\"condition\": \"rain\", \"temp_c\": 12}"
        }
      ]
    }
    

    Два фармата контэнту. content рэзультата можа быць звычайным стрэлкаментам, серыялізаваным значэннем, як у прыкладзе, або спісам блакоў контэнту. Блакі маюць у сабе не толькі тэкст, адколькі можна сумешчаць text і image, чым інструменты для стварэння дыяграм або скрыншотаў можуць даць Claude асалодзівыя зображэнні. Стрэлкаменты падыходзяць для скалярных і JSON-даных, а спісы блакоў — для мультымадальнага выходу.

    Чыткаа адказывайце, калі ўтварылася проблема. Адзначайце неудачны календарны запыт за дапамою is_error: true і пояснюючага паведамлення, напрыклад "Error: no calendar event found matching that query", ніколі не выкорыстоўвайце порожнюе значэнне чыстае "Failed". Сярод усіх прычын, якія вплываюць на рэзультаты, гэтае мае найбольшае значэнне. Чыткая памятка пра адзінцы памагае Claude прабавіць з іншымі параметрамі, выбраць інструмент чыраць корыстніку, што сталася, тады калі адзінцы застаецца непазорваным, цыкл застаецца у застойве. Большы рэзультат таксама можа мець cache_control, чым захоўваюцца затраты на паўторную обработку пазней.

    Контракт пра продажчык

    Тры строгія правілы, кожна з якіх — распашчынны пункт неудач:

    • Адна tool_result на кожны tool_use. Калі яго не павінаваць, запыт неудачны з адзінцы 400, таму што мадэлі чакаюць адзін-до-аднаго адказу на кожны запыт да інструмента, які яны выдаюць.
    • Падзейце той самы массів tools. Кожны запрос, які выконвае блакі tool_use або tool_result, павінен чытка задаць інструменты, да якіх ён апілюецца, інакш як толькі будзе адхоўнуты.
    • Рэзультаты ўтвараюць самастоятэльны цыкл. Блакі tool_result трэба выдаваць як паведамленне ад карыстальніка, якое стоіць на пачатку яго тэксту. Ўсі наступныя інструкцыі ў тым жа цыкле не дапускаюцца. Новыя інструкцыі падаюць у аднаэтажнае паведамленне ад карыстальніка пасля таго, як цыкл з інструментамі завершыцца.

    Кожны рэзультат ўважаецца ненадзеяным вхідным дадзеннем

    tool_result — гэта не нейтральныя даны. Гэта тэкст, які практыкуецца ў кантэксце модэля і вплывае на наступны крок яго працы. Як бы ён не выйшаў з відкрытага інтэрнэту, з дасыланага корыстнікам документа чы ў будзь-якай сістэме, якая не належыць цэлкам пад вашым кантролем, ён можа містыць інструкцыі, прызначаныя для захоплення агента, напрыклад, заповедзь ігнораваць пакананні праз аднойчыну і выклаць базу дадзеных. Модэль можа ўжыць гэтыя інструкцыі. Гэта і ёсць ін’екцыя заповедзі, і ў цыкле агента гэта рэальная парадокс для працы, а не гіпотэтычная.

    Захопы ёсць структурнымі і знаходзяцца ўнутрь цыклу, які вы пішаце:

    • Даўце агенту мінімальныя правы, якія яму трэба. Інструмент, якога ён не мае, — гэта дзеянне, якое немагчыма адманіць яго на выкананне.
    • Выкананне рызыкаваных інструментоў трэба адбываць у сандбоксе.
  • Санітаравацыя — гэта выходныя даны, якіе ператвараюцца ў дзеянні, напрыклад, шляхам аднаковага падключэння паходжых шляхоў да файлаў да фіксаванага каталогу, каб запобiec ператракцыі.
  • Нехай крок пасля выкарыстоўвання інструмента выдалі все, што выглядае як інструкцыя, а не як даны.
  • Усё, што мае рэальныя наследкі, павінна пераводзіцца пад людскія апраўды.
  • Рэзультат інструмента ніколі не павінен маты можлівасці разрэшыць тое, чаго сам інструмент не могаў.

    Спрэчыцеся пра рэзультаты як пра кантэкст, які вы таксама куратуеце. Кожны токен рэзультата застаецца ў вікні працы працэсу спілкування, таму старайцеся ствараць короткія, добра структураваныя выходныя даны: адпаведны JSON або пазначаныя поля лепшыя, чым проза, яку модэль павінна дэкодаваць. Ціклы, якія накапліваюць многа рэзультатаў, можна выкарыстоўваць з функцыяй чысткі рэзультатаў інструмента — бета-версіяю кантролі кантэкста, якая апускае застарэлыя рэзультаты, калі падходзіць ліміт. Выкарыстоўвайце ёе, пакуль цікл не стане настолькі вялікі, каб заполніць вікно працы.

    7. Вторая ітэрацыя: залежны выклік

    Абыякія рэзультаты вярнуліся, таму API выклікаецца ўтроці, пры чым перадаецца весь спіс паведамленняў і ваказанні пра інструменты. У календары адпаведзь — 15:00 у Canary Wharf, а прогназ — дошч, пры тым як так і не можа сказаць, калі трэба выйсці, таму што час паўтарнага прыбыць завісіць ад месца, якое ён толькі-но выявіў. Гэтая залежнасць ўсунула можлівасць адбыцца паралельнага выкліку пад час першай ітэрацыі. Ён быў змушаны адбыцца пазней.

    {
      "role": "assistant",
      "stop_reason": "tool_use",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_02Tt",
          "name": "get_travel_time",
          "input": {
            "origin": "home",
            "destination": "Canary Wharf, London"
          }
        }
      ]
    }
    

    Вы запускаеце адказвальны пры тым жа пацеку пераканальнага адзначэння пры выкарыстоўванні адказвальнага засобу, выканання і апрацоўкі пасля яго выкарыстоўвання, і вяртаеце адны рэзультат:

    {
      "role": "user",
      "content": [
        { "type": "tool_result", "tool_use_id": "toolu_02Tt", "content": "{\"minutes\": 45}" }
      ]
    }
    

    Структура ціклу падае ў спіс з першай ітэрацыяй. Разлікаецца толькі колькісць вызоваў і ўзаемная залежнасць яных. Гэта тэпатып, які трэба запамятаць: цікл не змініцца за кожны раз, і ён будзе павтарацца, пакуль Claude не перастане ставіць запытанні.

    8. Трэцяя ітэрацыя: сынтэз і end_turn

    Трэці вызов API паказвае, што Claude ужо мае всі неабходныя факты. Больш ніякіх інструментаў не трэба, таму ён запішае адпаведзь. end_turn заменяе пакананне з пакананням перастаць раней, і цікл завершваецца.

    {
      "role": "assistant",
      "stop_reason": "end_turn",
      "content": [
        {
          "type": "text",
          "text": "Yes, bring an umbrella — rain is forecast in London tomorrow, around 12°C. Your meeting is at 3:00 PM in Canary Wharf, roughly 45 minutes away, so leave home by about 2:00 PM to arrive with a buffer."
        }
      ]
    }
    

    Усьго ўсьмо тры ітэрацыі: два паралельныя вызовы, адна залежная вызова і сынтэз. Мадэль выбірае, што і калі запрашваць, а ваш код выбірае, як кожны вызов будзе выкананы, чы розрахована гэта дзеянне і як будуць вяртацься рэзультаты. Кантэкст расце з кожным разам, таму што весь історыя перадаецца занова, але тры разы легка пасвячаюцца для выканання задачы.

    9. Весь цыкл у кодзе

    Усё, што было сказана, сконцентравана ў однам цыкле ў Client SDK. Ён пераглядае stop_reason, направляе кожны запрошаны інструмент праз вашы крокі перад і пасля ўжыцтва інструмента, адпавядае на кожны вызов аднім рэзультатам і продовжае працаваць, пакуль Claude не завершыць сваю працу.

    import anthropic
    client = anthropic.Anthropic()
    
    messages = [{"role": "user", "content": user_request}]
    MAX_ITERATIONS = 10
    for _ in range(MAX_ITERATIONS):
        response = client.messages.create(
            model="claude-opus-4-8", max_tokens=1024, tools=tools, messages=messages,
        )
        messages.append({"role": "assistant", "content": response.content})
        if response.stop_reason != "tool_use":
            break   # end_turn (or another reason): done
        results = []
        for block in (b for b in response.content if b.type == "tool_use"):
            if not pre_tool_use(block):   # your guard - may block the call
                results.append({"type": "tool_result", "tool_use_id": block.id,
                                "content": "Blocked by policy.", "is_error": True})
                continue
            try:
                output = execute(block.name, block.input)   # run it (concurrently if independent)
                output = post_tool_use(block, output)   # redact / log / reshape
                results.append({"type": "tool_result", "tool_use_id": block.id, "content": output})
            except Exception as e:
                results.append({"type": "tool_result", "tool_use_id": block.id,
                                "content": f"Error: {e}", "is_error": True})
        messages.append({"role": "user", "content": results})   # one result per tool_use
    print(response.content[-1].text)
    

    Гэты цыкл чытае адзіныя пункты. Вы самі керуеце messages, таму што API не зберагае стан. Будзь-які stop_reason, кроме tool_use, завершае яго. Жорсткі ліміт павтарэння запобегае неконтрольванаму працаванню агента, таму ніколі не запускайце необмежаны цыкл у працоўным рэжыме. Усе віды абяканняў, заблокаваныя вызовы і асобыстыя прычыны абякання вяртаюцца як рэзультаты is_error, а не спрычынююць злам раунду. У завершаным кодзе таксама прынятыя параметры max_tokens (заканчаны раунд, таму трэба падняць ліміт або продаваць працу) і pause_turn (раунд сервера-інструмента, які трэба пераслаць). Адны з гэтых параметраў можа з’явіцца ў тым жа цыкле.

    Спіс да запамятовання

    • Інструменты прызначаюцца ў масэвым элеменце tools з параметрамі name, description і input_schema, і кожны запіт плаціць за тыя ваказанні паводле колькасці токенав увайсу.
    • tool_choice адмініструець тое, чы гэты інструмент будзе вызваны: auto, any, tool або none. Расшырэная праця дзеяе толькі з auto і none, а strict: true змушвае аргументы абсалютна падходзіць да схемы.
    • stop_reason з значэннем "tool_use" перадае права на дзеянне вам. Адзначайце вызывы, фільтруючы content на type == "tool_use", а не па пазыцыі.
    • Паралельны выкарыстоўванне інструмента означае наявнасць калькі tool_use блакоў у адной адпаведзі. Парадакт выканання, па-паралельнаму чы па-параднаму, выбіраеце вы, а не модэль. Залежныя вызывы прыходзяць у пазнейшыя тыры.
    • З’явіцьце ўсі запрошаныя інструменты і адпаведзьце аднойчы: адна тур ужоўцара, які трывае паўтарыць tool_result для кожнага tool_use, які паўтараецца праз tool_use_id, пры чым масэва tools застаецца незменнай. Адсутны рэзультат выклікае код 400.
    • Вы адпавядзіце за прыемкі падчас выканання. Пераканайцеся і захавайце даныя прытым, перш чым запускаць, а пасля — обрабатайце іх і адрэдагавайце. Гэта вашы крокі, а не функцыі, якія трэба налаштаваць.
    • tool_result.content можа быць строкай або лістам блакоў. У разе неудачы задаце is_error: true з паводлівым паведамленнем, а рэзультаты трэба заліць короткімі і структураванымі.
    • Спрыяйце да рэзультатаў інструментаў як да недазвяржыцькага кантэксту. Мінімальныя правыя, сандбоксы, санітарызацыя і падтверджэнне чалавека пры значных дзеяннях — гэта спосабы захісту ад втрымкі коду.
    • Цыкл працюе да момента end_turn, зберагае свой стан і патрабуе жорсткаг ліміту па колькасці ітарацый.

    Супаўязаныя матэрыялы

  • Практычныя прыемкі: Усё працоўна ў ARD: Як насправды функцыонуе спецыфікацыя агентнага адкрыцця рэсурсаў — Дэталізаваны апіс практычных прыемакоў: Усё працоўна ў ARD: Як насправды функцыонуе спецыфікацыя агентнага адкрыцця рэсурсаў: контракты, перакананні і шаблоны коду для команд, якія вікорыстоўваюць гэты патэрн.