Адзін раз — і готава: стан, затверджэнне і ідэмпотентнасць для дзейнуючых агентаў
Дазвольце даклэ научыцца, як чыстая формуліраванне праектаў, обавязковыя затверджэння, паўтарная верыфікацыя, ключы ідэмпотентнасці і пераканальванне рынку прыводзяць процес вярнення грошаў у рамках калькуляцыі з аднама агентам на такі, якому можна даверыць.
Крыніцы: The Architecture of a Multi-Agent System That Can Actually Take Action
Дэманстрацыя з участю калькуляў зазвычай заканчываецца пераканальным адказам. Система для практычнага выкарыстання пачынае свою найцяжэйшую работу адразу пасля цього, калі корыстнік падтверджуе: «Чудазна, працуйце далей», і програмне забезпечэння павінна ператворыць пропанацію, выданую пасля дыялогу, на рэальныя змяны ў іншай системе. У этой стацыі працаванне адзінаго запиту на вярненне грошаў адступлена праз координатора, спецыяліста-калькуля, збераганыя пропанаціі, падтверджэнне чалавекам і ўзгоджання, пры чым паказана, якія абавесці належыць модэлю, а якія павінны застацца ў коде прыемліка. У канцы вы павінны маты конкрэтны чарточку пераканання, якая дапаможа ці справаць з агентным прадзеянням готава да дзейства ў рэальным свеце.
Што зменяецца, калі асистэнт павінен дзейваць
Да часу затверджэння асистантаві было достатнья толькі пераклацаць запит і даць корыстную адказ. Калі паўтараецца схвалэнне, з’яўляецца іншы набор обавязак. Сістэма должна точна прыгадаць, што ёй было запрошана, знайсці правильны запис, выбраць элемент, які адпавядае за задачу, параканаліцца, чы робота яшчэ мае сенс, пераканаліцца, чы гэты паўтаральнік можа яе автарызаваць, вызваць зовнішню службу, расправіцца з неудачамі, і нарэшце выявіць тое, што здаецца простым, але рэдкасцю такім ёст: чы робота дзейсна адбылася.
Звычная архітектура дэмаверкіў пакрывае толькі першую частку. Оркестрайтар прымеяе запит, перадае яго спеціялістам, спецыялісты запускаюць інструменты, і прыходзіць адпаведнае адказа. Такая структура ўжо ценная, але для рэальных дзействаў яна ёсць толькі пунктам входу. Безпечнае дзействаванне выклікае неабходнасць чыткага статусу, автарызаціі, рабочых практык, якія вытрымліваюць чаканне, павторную пераўерку, ідэмпотентнасці, вярнення пасля нечыстае фаллов і доказа таго, што заданне завершана. Самэлькі ў гэты момент дизайн агента стае проблемай архітектуры, а не проблемай стварэння запытаў.
Аналіз адзінаго запыту на вярненне грошаў
Возьмім запыт, які кліент можа адправіць асистэнту падтрымкі: разглянем замовленне №4821, выявім, чырэшле яно падходзіць для вярнення грошаў, і якщо так, падготавім проект для затверджэння. Чалавечы агент разбіў бы гэта на працоўнае дзесять крокаў:
- З’ясавім, чаго прасіць кліент.
- З’явім замовленне.
У програмнаму забезпечэнні кожны з гэтых пераходаў патрабуе адпаведнага адпавядача і месца для выканання. Эфектыўная сэрія дзеянь пераводзіце запит від корыстувальніка да організатора, пасля чаго да спецыяліста, які збірае доказы і складзіць праект прыказу, які пасля таго затверджваецца, выкананы і нарэшце пераканальваецца.
- Распрацоўка запиту — гэта задача організатора.
- Спецыяліст адбывае дакладную перапытку тэматыки.
- Інструменты з’ѐеднаюць систему з дакументацыяй і актуальнымі данымі.
- Чыткі статус фіксуе запропанаванае дзеянне.
- Корыстувальнік затверджвае адзін конкрэтны праект прыказу.
Адна засада спаявае ўсё гэта:
Модель можа вырашыць, што павінна адбыцца; прыкладны праграма вырашае, што дазволена адбыцца.
Указаныя нижэй фрагменты — это архітектурныя эскізы на Python з викорыстаннем LlamaIndex. Конфігурацыя модэлі, інтеграцыя з системамі зберагчыка дадзеных і сервісамі не паказваны, а такія назывы, як llm і policy_retriever, практычна выступаюць заменайкамі для компонентаў, якія будзе запрошваць ваш прыкладны праграма. У дзеярых фрагментах таксама злічыненыя рэзкія перерывы (напрыклад, запаведзі з’едыненыя ў адной лініі), таму іх трэба чытаць як структурныя схемы, а не як код, які можна скопіюваць і вставляць.
Раз’ядрэнне маршрутацыі ад спецыялістскай роботы
Спадзейшы спосаб працэвухі агента — это даець яму ўсе засобы заодно: пошук дакументацыі, выкарыстоўванне інформацыі пра замовлення, пераконтаванне платежаў, вярненне грошаў, робота з электранамі, стварэнне атласоў. Для маленькага прыемніка гэта аблікована. Аднак, калі колькасць абавясцей зрастае, задачу агента становіцца важка описаць за адну фразу, і пытанне часу выконання працы змушана дзелаваць разам з аперацыяй, якая пераказвае грошы.
Чыстэйшая межа раздзеляе два аспекты: выбір таго, куды належы запит, і выкананне спецыялізаванай працы з яго. Для асистента падтрымкі гэта значыць координатора, який адпавядае на загальныя запытанні і перадае запытанні, якія стосуюцца вярнення грошаў, спецыялісту. Спецыяліст ствараецца на адной з баз LlamaIndex — FunctionAgent:
from llama_index.core.agent.workflow import FunctionAgent
Ягоў вызначэнне дае яму скураны мандат, тры інструменты і права на перадачу кантролю назад координатору. Заўважыце, што запит системы прасі яго паясніць свае доказы перш чым запропанаваць ўсё:
refund_specialist = FunctionAgent(
name="refund_specialist",
description="Checks refund eligibility and prepares proposals.",
system_prompt=(
"Check the order and the applicable policy. "
"Explain your evidence before proposing a refund. "
"Hand back unrelated requests to the coordinator."
),
tools=[get_order, search_policy, prepare_refund],
llm=llm,
can_handoff_to=["coordinator"],
)
Поле description не ўжо дэкорацыя; яно є часткаю архітектуры. Абаза такая як "падказчык-памочнік" нічога не выражае. Фраза "Перакантролюе правамо на вярненне грошаў і падготавіць прыказы" апісвае адпаведальнасць, якая можа быць перапытаная і аудытаваная. У LlamaIndex класы FunctionAgent і AgentWorkflow спроектаваны самэ для такога типу чыстай перадачы задач. Якщо вы яшчэ выбіраеце фреймворк, парабяранне LangChain і LlamaIndex пакрывае шырэйшыя аспекты выбору.
Дадзенне агентаў не ўсега являецца павышэннем качанства. Кожны спеціяліст стварае дапамогу для коордынацыі, таму кожны з іх павінен абясніць прычыны свайго існавання. У гэтым случае пара агентаў – коордынатор і спеціяліст па вярненню грошаў – стварае значыцьныя межы без дадатковых витатаў.
Паў’язка коордынатора зі спеціялістам
Коордынатор і рабочы процес, які спаўнае абох агентаў, выйшлі з таго ж модуля:
from llama_index.core.agent.workflow import AgentWorkflow
Коордынатор мае доступ да апштых запитаў для пошуку правіл і можа перадаць их спеціялісту па вярненню грошаў. AgentWorkflow рэгіструе абох агентаў і прызначае коордынатора як галоўную точку, якая прыме кожны запит. У даным фрагменте замкнутая складзінка коордынатора і прызначэння рабочага процесу знаходзяцца на адной лініи; це два разлычных запэўнення:
coordinator = FunctionAgent(
name="coordinator",
description="Answers general questions and routes refund requests.",
system_prompt=(
"Use documentation for general questions. "
"Hand refund requests to the refund specialist."
),
tools=[search_policy],
llm=llm,
can_handoff_to=["refund_specialist"],
)workflow = AgentWorkflow(
agents=[coordinator, refund_specialist],
root_agent="coordinator",
)
Калі гэта ўсталяна, запыт мае шлях. Коордынатор выявляе запыт пра вярненне грошэй і перадае його; спецыяліст запрашвае інформацыю пра замовленне, шукае відпаведныя правіла, фіксуе тое, што яшчэ не ўсталяна, і, калі доказы становяцца достатнімі, складае праект рашэння.
Шлях перадачы запыту па ходу размовы можа варыявацца. Адзін кліент заздалегідь наводзіць дату доставкі; іншы спачатку запытае пра правіла вярнення грошэй і толькі пасля троха паведамленняў згадвае пра замовленне. Агенты можу прыміць такія варыяцыі, тады як прылад продовжае визначаць, якія можлівасці існуюць і якія є меры ўжывання іх.
Размовы можу застацца гнеклівымі, тады як ключовыя операцыі застаюцца пад контролем.
Доказы прыямо перад перакананнем
Адправка запыту да правильнага агента не гарантуе, што ўжыванне яго будзе правым. Спецыяліст усё рава должен збіраць доказы.
Падзеймім, што правілы дазваляюць вярнуць невыкрытыя тавары прыблізна за 30 дней, а записы замовлення паказваюць, што замовленне №4821 прыбыло 12 дней тады. Гэтыя даныя прайшлі з двух разных систем, і абе яны неабяжны: правілы вказываюць норму, замовленне описвае ситуацыю, а право на вярненне выклікаецца толькі калі яны сумешаны. Таму выявленне стае аднам з етапаў рабочага процесу. Спецыяліст шукае дакументы з правіламі, адночасна завантажаючы актуальны запис замовлення.
Мінімалы інструмент для пошуку правіл пачынаецца з асінхроннага падпісу і докстрынгу, які поясняе агенту, для чаго праглядаецца інструмент:
async def search_policy(question: str) -> list[dict]:
"""Find policy passages relevant to a customer request."""
У тэле інструмента выявляюцься адпаведныя фрагменты, і кожны з яых вяртаецца разам з назвай ісходнага дакумента та роздзелам, да якога ён належыць. Как і у пярэднім фрагменте, вызов aretrieve і оператыва return павінны стаяць на разных лініях:
matches = await policy_retriever.aretrieve(question) return [
{
"text": match.node.get_content(),
"source": match.node.metadata.get("title"),
"section": match.node.metadata.get("section"),
}
for match in matches
]
Важна тое, што супакоўваецца з тэкстам: його паходжанне. Якшто асистэнт пазней стварыць прэтэнзію, што замовленне падпадае пад період вярнення грошаў, адпаведнае поясненне павінна магчымаць цитаванне часткі правіл, якая визначае гэты період. Аднак паходжанне мае свае меры:
Цітата не можа падтвердзіць, што тлумачэнне правильнае; яна проста дазволяе каму-небудзь яго пераканацца.
Стан, калі пакунак не быў ачынены, выкрывае прасоц: у системе замовлення няма жадных запісаў пра тое, чы розпаковваны пакунак. Правільны падход — не здагадваліцца, а запытаць кліента. Надзеяны дизайн явна паказвае нехапаку інфармацыі, замест таго каб неяснасці ператварыліся на абавеснай рэкамендацыю.
Історыя размовы — гэта не стан прыкладнага програмнага забезпечэння
Працюймо з гадкай, што розследаванне завершана. Спецыяліст адмаўляе, што замовленне №4821 па праву атрымлівае вярненне сумы 79 еўра, і запытае, чы хочаць працаваць далей. Пользователь адпавядае «так».
Механізм направлення, розследаванне і апараты вернулі свае доказы, пры тым застаёцца прасоўка. Сістэма не можа точна сказаць, што было затверджана: замовленне, сума і валюта, а таксама версія прадакту ўсе гэта толькі прыпускаюцца, а не фіксуюцца. Якщо пад час размовы йшлося пра два замовленні, або сума была перасчытана пасля прадакту, то слова «так» стае неодназначным.
Самэльчына прычына — дзеянні, якія вынікаюць з гэтага, не можу састаўляцца толькі з транскрыпцыі чату. Аплікацыя патрэбуе явнага фіксавання адпрацоўваных дзеянняў, такога як гэты:
pending_action = {
"proposal_id": "refund-proposal-17",
"order_id": "4821",
"amount_minor": 7900,
"currency": "EUR",
"status": "awaiting_approval",
"evidence": [
"returns-policy:section-3",
"order:4821",
],
}
Поле status ўжыткова, але самэй важлівым ёсць proposal_id. Апраўленне павінна адносіцца да самэй той прыяваркі, яю бачыў корыстнік. Якшо зменяецца сума, то гэта новая прыяварка. Якшо зменяецца порядак, то гэта новая прыяварка. Якшо свежыя доказы зменяюць рэкамендацію, то гэта новая прыяварка. Грошы зберагаюцца як amount_minor у відмовках цэнтав, што запобегае неспадзячаным абрабаткам з дапамою дробевых числаў, а ліст evidence зберагае інфармацыю пра тое, якая частка правіл і запис порядку падтрымалі даную прыяварку.
Транскрыпція існуе для розумэння; структураваны статус існуе для дзейства.
Размова памагае модэлю зрозумець, на шта натыкаецца падазрэлена фраза „працавац далей“. Зберажаная прыяварка дае програме ўсё, што неабходна для чыстага выканання задачі.
Апраўленне як даны, а не як слова
Наўмані спосаб запісу згоды — це проста факт:
user said yes
Безпечнейшыя моделі з’ўязуюць ідэнтыфікатор, пропозыцыю, дзеянне і контекст разам:
user X approved proposal Y,
containing action Z,
under the current conditions.
Этае размежаванне стае важлівым у той момент, калі агент можа вплываць на зовнішнія системы. Згода павинна прыязыць конкрэтную адзінку да конкрэтнага запрошанага дзеяння, а не да чагосьці, што модель пазначае пасля таго. Таму пропозыцыя павінна мець усі значныя тэхнічныя деталі:
- цэльвы рэкорд
- суму
- валюту
- доказы, якія падтрымліваюць пропозыцыю
- тэкучы статус
- унікальны ідэнтыфікатор пропозыцыі
Прыродны язык пояснюе дзеянне для пользователя; структураваная пропозыцыя задае яго для системы.
Чаканне ўскладнюе рабочы процес
Апраўка чалавекам таксама прыносіць паследствія з точкі гляду часу. Карыстаўцы можа адпаведзець негайна, пасля обеду чы наступнага дня пасля закрыцья прыгледчыка. Калі рабочы процес залежыць ад чалавека, паўза не ёсць выключэнным случаем, а стандартным етапам, таму робота, якая чакае на апраўку, павінна быть зафіксавана і продакументована пазней.
LlamaIndex апрантвае об’екты контэксту рабочага процесу і спосабы паўзы для чакання апраўкі чалавекам, што надае гэтай взаімадзейнасці певной структуры. Аднак стойкое зберагачэнне, автарызацыя, правілы выканання і весь жытнёвы цикл прыгледчыка застаюцца вашай адпаведнасцю.
Для такога значныя рэшэння, як варыцыя грошаў, правільны падзел працы заключаецца у тым, каб агент падготавіў праект рашэння, а звычны код прыгледчыка выканаў апраўленую операцыю. Процесар апраўкі спачатку завантажае зафіксаванный праект рашэння:
async def approve_refund(proposal_id, user):
proposal = await proposals.load(proposal_id)
Пасля чаго аплікацыя пераканаліваецца ў правыя на выконанне, паўтарна пераканаліваецца, што прыёмка яшчэ чакае на затверджэнне, вызывае службу платежаў з ідэнтыпатным ключам, якім ёсць ID прыёмкі, і фіксуе её наявнасць. У даным фрагменте гэтыя вызывы, якія чакаюць на завершэнне, выкананы разам у адной лініі; кожны await ёсць самастоятельным запэўненням:
await permissions.require(
user,
"approve_refund",
proposal,
) await proposals.require_pending(proposal) await refunds.revalidate(proposal) receipt = await payments.refund(
order_id=proposal.order_id,
amount_minor=proposal.amount_minor,
idempotency_key=proposal.id,
) await proposals.mark_completed(
proposal.id,
receipt,
) return receipt
У гэтай короткай функцыі схована калька граней:
- Прыёмка падае з захаванага стану, а не з пераказу.
- Автарызацыя контролюецца за межамі самой модэлі.
- Код паўтарна пераканаліваецца, што прыёмка яшчэ чакае на затверджэнне, што запобегае двойнаму выкананню через гэты пат.
- Пярэходна спроможнасць пераканаліваецца непразьдзе перед выконаннем дзейства.
- Вызыв платежаў несе стабільны ідэнтыпатны ключ.
- Раслед выкананняя захавляецца.
Гэты лянцуг выконваецца ад стварэння запрошэння, якое захаванае, через автарызаваная затверджэння, новую пераканальванне і сама експанцыя да захаванага рэзультата. Гэты лянцуг мае набагато большое значэнне, чым тое, чыі агент ідеальна сформулюваў свой паведамленне.
Негайна пераканальванне прытаму перед дзеянням
Чаму прабавляць знова, калі корыстнік вялікі час яўляе схваленне? Таму што свет продовжвае рухацца, пакуль система чакае. Замовленне могло быць вярнуто чераз іншы канал падтрымкі, статус аплатаў мог узменіцца, хтось мог змяніць замовленне, або паралельны процес мог уже выконаць гэтую операцыю.
Запрошэнне — это кадры таго, што здавалася правильным у момент яго стварэння. Експанцыя выконваецца пасля, інодзе значна пазней. Перад выкананням значныя операцыя прыкладнэнне павінна пераканацца, што прыязначэння, якія лежачы ў основе запрошэння, яшчэ актуальныя.
„Так“ дае разрэшэнне на дзеянне; гэта не спяшае зміны свету.
Чым дольш час працоўвае прапанова ў статусе чакання, тым важлівей гэта стае. Спалучэнне павтарной перапрацоўкі з часам выгорання прапаноў дапамагае захаваць межы для застарэлых прыпускаў.
Павторныя спробы не павінны перарабатваць тую ж дзеянне
Разглядзім другую няудачу: корыстнік схваліў, прыемліцель аплікацый надаў вярненне грошэй, прадаўець адпрацаваў платеж, але сеть з’явілася прычына для перерыву прыбутку адпаведзення. Кліент прабуе знову. Чы мае кліент атрымаць другія 79 еўро? Звычайна, ні.
Ідэмпотентнасць запобегае гэтам. Стабільны ідэнтыфікатор операцыі дазваляе будзь-ям зовнішнему сервісу, який падтрымляе ідэмпотентнасць, адазначыць два запиты як адну логічную операцыю. У замяне на тое, каб перапрытак прыймалі як „выдаць ўтратае падаткова вярненне“, сервіс спрацоўвае яго як запит пра статус аб рэзультат операцыі, якая вже прыязначана да прапановкі №17. Іспользованне ідэнтыфікатора прапановкі як ключа ўзялася, таму што кожная затверджаная прапановка должна даць максымум аднае вярненне. Механізмы на стороне сервера падробна расказаны ў разумеўцы ключоў ідэмпотентнасці ў Node.js POST-канцах.
Гэта рэдкая функцыя ў апрацоўваных дэмах з калькольніка агентаў. Але як толькі система можа перасылаць грошы, адправляць паведамленні, змяняць записы, ачынаць тыкеты аб ініціяваць будзь-які іншы рэальны эфект, перапрытакі стаюць часткай архітектуры.
„Не вядома“ — гэта легітымны рэзультат
Тепер самы ўскладнены случай: запуск платежа заканчываецца таймаутам. Можа, нічога не адбылася, а можа грошы былі пераказаны за момент до з’явлення працэзупінення. Для кліента разлік становіць 79 еўро.
Сказаць корыстніку, што вярненне грошаў не выйшла і будзе прабавана знову, было б некалькі, таму што нічога не падтрымляе такое тверджэнне. У системы є толькі відсутнасць паўтарнай падтверджэння, што ёсць іншы факт. Надзеяны процес работы дазволяе залишаць гэту невяснасць видной: замест таго, каб павтараць операцыю, система пераказвае статус ужо існуючай транзакцыі, а пад час таго паведамляе корыстніку точную інфармацыю, напрыклад, што завершэння не можа быць падтверджана і ў тэчасці пераказваецца статус.
Гэты прынцып дапамагае на кожным этапе, а не толькі пад час платежа:
- Калі пошук замовлення даў адмову, існаванне замовлення залишаецца не вядомым, а не спроставленым.
Надзеяныя системы адобразляюць гэты стан як окремыя станы, а не спаўнююць іх ў категорію «неудача» або «нэ знайдзена».
Праця, якая вернулася з інструмента, не значыць завершэння
У гэтым случае архітектура выходзіць за межы простага керавання. Праця, якая вернулася з інструмента, не ўзначае завершэння задання. Адпаведны адзінак означае, што задання не завершылася. Заканчэнне часу аператыва таксама означае, што задання не завершылася. Якщо прыкладнае програма не можа з’ясаваць, чыі сталася вярненне сумы, то задання абавязкова не завершылася.
Болей строгая дэфініцыя завершэння — гэта калі система можа паказаць доказы таго, што бажаны рэзультат справды стаўся. Гэта змінюе умовы працы. Мета не ёсьць такая:
call refund()
Мета ёсьць такая:
establish that refund proposal #17
for order #4821
was successfully processed exactly once
Это абсалютна разная гарантія, і самэ ўжо ёсць прычына, чаму оркестрайзеры і спецялісты ўсьмо толькі пачатак проектаў.
Дзевяць запытанняяў прыемна тое, калі система з калькольнікае агентаў можа дзейсцаваць
Перш чым праўяжаць робочы процес AI да операцый, якія маюць рэальныя наследкі, разглянуце этыя запытанняя:
- Чы ў кожнага агента ёсць часткавая адпаведальнасць, яку можна сказаць за адну фразу?
- Чы можна праследаваць важныя рашэнні да дакументаў і записаў, якія стояць за ўсім гэтым?
- Чы недастатак інфармацыі можа застацца явна невядомым, чы неяснасць таятачна ператвараецца на впэўненую рэкамендацыю?
- Чы запроектаваная дзеянне зберагаецца як структураваны стан, а не існуе толькі ў размове?
- Чы корыстнік затварджае адну конкрэтную пропозыцыю, так што „так“ даўа права на ўжо конкрэтную дзеянне?
Якшо да дзяўярэння калякх з гэтых пытанняў няма чыстага адказу, у вас можа ўсё ж быць выразны дэманстрацыйны прыклад, але, верагодна, яшчо не система, якой можна даваць доверлівасць у дзеяннях.
Заключэнне
Параканацеся даўнейшым запросам: пераканайцеся ў замовленні №4821 і падготавьце вярненне грошаў да затверджэння. Кожны элемент тут уже мае свое месца. Організатор распрацоўвае маршруты, спецыяліст сабіра доказы, інструменты падлягаюць задапісву ў дасяглібныя дакументы, спецыяльная група зберагае прыказку, адпаведная особа падписваецца пад конкрэтным заходам, код прыемліцтва пераканаецца ў правах і павторна апрацоўвае інформацыю, система платежаў выканае операцыю, а рэзультат зберагаецца і падтверджваецца. У такі момент асистэнт можа даты цікавую, але простую адпаведзь: вярненне сумы 79 еўра за замовлення №4821 было апрацавана, пры чым дадана падтверджэння. Гэтыя словы ўзлегкай можна дазволіць, таму што за імі стоіць усё вышэсказанае.
Калі система расте, тыя ж пытанні застаюцца актуальнымі. Чыя саме ўсё можлівасці належаць каму-небудзь? Чыму можна адразу паглядзець доказы, якія лежачы за рашэннем? Чы ход працы зберагае неяснасці і можа восстанавіцца, калі зламаецца якаясь залежнасць? Чы можа чалавек точна бачыць, што ён затверджвае, і чы можа система падтвердзіць, што адбыўся запланаваны рэзультат? Адказы паказваюць, дзе іншы спеціяліст-агент можа дадаць ценнасць, дзе паспрацуе звычная функцыя, і дзе патрэбны строгейшыя межы. Найлепшы досвід работы з агентамі можа завершыцца простым словам «Завершана», а архітектура — гэта тое, што робіць гэта правдападобным.