Галоўная / Артыкулы / Практычныя прытамкі: Ёсць багато рук, але толькі адна ручка: кераванне агентамі без втраты

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

Практычныя прыказкі: «Многія руки, адна ручка»: каліткаванне агентаў без выхаду з контрактаў, пераказоў і слотаў для коду для команд, якія выкарыстоўваюць гэты патэрн.

2303 слоў

Існавайце гэта як перапрацоўаны варыянт ідэй з кнігі «Many Hands, One Pen: Orchestrating Agents Without Losing the Plot» для аператараў: чыстыя этапы, аранжаваныя блакіты коду і прыметкі па вяснаванню, якія застаюцца пасля перадачы заданняў. Этап «Апглэйв» найкраща працюе, калі яго розглядаць як мерыемую плошчу. Запісаўце адна ідеальная транскрыпцыя, адзін прыклад неудачы і прыметкі па адвярнуцьцю роботы прычым расшыроўваць масштабы. Валічыце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісьць крок не выйшаў, прычына неудачы павінна вказваць на адную адпаведальнасць, а не на заплутаны ланцужок заданняў.

071 · Выберыце стандартны прабэг роботы і дазволіце агенту здобыць сваю автаномію

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

REFUND_LIMIT = 50.00
def llm_step(prompt: str) -> str:
    """Called only where the written rules run out."""
    return model.complete(prompt).strip().lower()
def handle_refund(ticket):
    if ticket.days_since_purchase > 30:
        return deny(ticket, reason="outside window")
    if ticket.amount <= REFUND_LIMIT:
        return approve(ticket)          # a rule, not a judgement call
    intent = llm_step(
        f"Classify as fraud, defect, or remorse:\n{ticket.body}"
    )
    if intent == "fraud":
        return escalate(ticket, queue="risk")
    if intent == "defect":
        return approve(ticket)
    return route_to_human(ticket)

072 · Адкладзіце выкарыстоўванне Orchestrator, калі вы вялікі час ведаеце структуру

Для стадіі 072 «Праскочыць этап Orchestrator» неабяжна пазначыць вхідныя даны, адпаведальнага за шаг і крэтырыя выходу пры перадзеіснавленні коду. Аператары должны магчымаць перзапуск шагу з вядомай точкі контролю, не падозрываючы схованы стан. Запісваць час выконання і кост токена або запыту разам з функцыйнальнымі рэзултатамі. Відразы коста з самага пачатку запобегае неспакоўным рахункам, калі траекторыя пераходзіць з дэмавай версіі ў спяльныя сераўеры. Заставіць людзкую апрацоўку для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны ў працэсе. Працэс складання коду не ўзроўнаважваецца з повнасцю бізнес-процэсаў.

# Before: up to 15 planning calls to rediscover a fixed list
def run_orchestrated(doc):
    state = {"doc": doc}
    for _ in range(15):
        decision = orchestrator.plan(state)      # 1 LLM call per pass
        if decision.action == "finalize":
            break
        state = WORKERS[decision.worker](state)
    return state
# After: 0 planning calls, same four workers, same result
PIPELINE = [fetch, extract, summarize, format_report]
def run_static(doc):
    state = {"doc": doc}
    for step in PIPELINE:                        # 0 LLM calls here
        state = step(state)
    return state

073 · Раздзеляйце агентаў па межах контэксту, а не па тытулу работы

Для 073 Split Agents паэтапнае адзначэнне: перад змянайчом коду неабходна адзначыць вхідныя даны, адпаведнага адпрацоўніка крока і критэрыя завершэння. Адпрацоўнікі должны магчымае перзапускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Конфігурацыю трэба залічыць параду ад коду прыкладнення. Файлы сераўіса, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, якое адпрацоўнікі можаюць пераглядаць, не чытаючы весь ланцуг аперацый. Прызначайце людскія празборы для рэшэнняў, якія выкарыстоўваюць грошы або зміняюць даны у працэсе. Прыўязка на час компілявання не є падтверджэннем полныя адпрацоўкі бізнес-процэса. Для 073 Split Agents паэтапнае адзначэнне: перад змянайчом коду неабходна адзначыць вхідныя даны, адпаведнага адпрацоўніка крока і критэрыя завершэння. Адпрацоўнікі должны магчымае перзапускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Валічыце маленькія, тэставальныя елементы працэса ў працоўніку, а не вялікія скрыпты. Калі крок збываецца, прычына неудачы должна вказваць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцуг аперацый.

from dataclasses import dataclass
@dataclass
class Subtask:
    name: str
    needs: set[str]        # facts this subtask must read
    produces: set[str]     # facts this subtask decides
def should_split(a: Subtask, b: Subtask) -> bool:
    """Split only when neither side needs what the other decides."""
    shared = (a.needs & b.produces) | (b.needs & a.produces)
    return not shared
implement = Subtask("implement", {"spec"}, {"api_shape", "error_semantics"})
test = Subtask("test", {"spec", "api_shape", "error_semantics"}, {"cases"})
assert not should_split(implement, test)     # one agent writes both

074 · Архітектар распараджэнняяў должен выдаваць рашэнне, а не вызываць інструменты

Калі працуеце над этапам 074 «Архітектар распараджэнняяў должен», спачатку запісайце умовы кантракту: неабходныя данні, сигнал успеху і тое, што выходзіць у разе частковага невыпання. Такі список контролю дапамагае залічыць пазнейшыя змены ў кодзе. Спрыймайце гэты этап як кантракт межаў між вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы элементам, задаце критэрыя успеху і не падтрымайце частковае завершэння без паведамлення. Запісвайце назву інструмента, хэш аргументаў, час адпаведзі і рэзультат кожнага вызову. Без такога лёгкага следу дэбагаванне агента займае гадзіны.

from typing import Literal
from pydantic import BaseModel
class OrchestratorDecision(BaseModel):
    next_action: Literal["delegate", "replan", "finalize"]
    target_worker: str | None = None
    task_description: str | None = None
    reasoning: str
def orchestrator_step(state):
    d = decide(state)                    # model has zero tools attached
    if d.next_action == "finalize":
        return finalize(state, d.reasoning)
    if d.next_action == "replan":
        return state.reset_plan(d.reasoning)
    worker = WORKERS[d.target_worker]    # workers own every tool
    result = worker.run(d.task_description)
    return state.record(d.target_worker, result)

075 · Кожнаму падагенту неабходна задаць кантракт выходных дадзеных з адпаведным типам, а не проста текст

Калі працуеце над стадзіяй 075 «Дай кожнаму падрабандзі», спачатку запісайце контракт: неабяжлівыя даны, сигнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список перакладзець пазнейшыя змены коду ў правільным напрамку. Запісвайце часы выканання і кост токеноў або запытаў праза функцыйнае рэзультат. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавай версіі ў спяльныя сераўры. Зробіце перапаконтральную пазнік пасля дорогіх крокаў. Програма не должна зноў нараховваць косты той самай вызову LLM, калі аператар прабуюць зноў выконаць пазнейшы вузел.

from pydantic import BaseModel, Field, ValidationError
class SubagentResult(BaseModel):
    findings: list[str] = Field(max_length=5)   # hard cap, one sentence each
    sources: list[str]
    open_questions: list[str] = []
    completion_status: str                      # complete | partial | blocked
def parse_or_retry(worker, task, attempts=2):
    for _ in range(attempts):
        raw = worker.run(task, response_format=SubagentResult)
        try:
            return SubagentResult.model_validate_json(raw)
        except ValidationError as err:
            task = f"{task}\n\nRejected: {err}\nReturn only JSON in the schema."
    raise RuntimeError(f"{worker.name} returned no valid result")

076 · Чытанне па шырэнні, запіс прычыпленым чынам через адного падрабандзю

Працюючы над стадіяй 076 Fan Out Reads, спачатку запішыце умовы викорыстоўвання: неабходныя данні, сигнал успеху і тое, што выходзіць на падчасныя аберанцы. Такі чэк-ліст дапамагае заставіць пазнейшыя змены коду быць чыстымі. Хавайце настройкі парадульна ад коду прыемліка. Файлы сераўнавання, храненні секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць пераглядаць іх, не чытаючы весь граф. Стварайце контрольныя пункты пасля дорогіх крокаў. Функцыя вярнення до роботы не должна занова ставіць плату за той самы вызыв LLM, калі аператар перапрыяўляе роботу да наступнага вузла. Працюючы над стадіяй 076 Fan Out Reads, спачатку запішыце умовы викорыстоўвання: неабходныя данні, сигнал успеху і тое, што выходзіць на падчасныя аберанцы. Такі чэк-ліст дапамагае заставіць пазнейшыя змены коду быць чыстымі. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшаў, аберанця должна вказваць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач.

import asyncio
READ_TOOLS = ["search_repo", "read_file", "fetch_docs"]
async def gather_context(subtasks):
    workers = [Agent(name=t.name, tools=READ_TOOLS) for t in subtasks]
    return await asyncio.gather(
        *(w.run(t.prompt) for w, t in zip(workers, subtasks))
    )
async def build_feature(spec, subtasks):
    findings = await gather_context(subtasks)     # wide, parallel, read-only
    writer = Agent(name="writer", tools=["write_file", "apply_patch"])
    return await writer.run(spec, context=findings)   # one writer, one pass

077 · Запісуйце умовы завершэння: агенты практычна не ведаюць, калі трэба зупыніцца

Этап 077 «Запіс умов завершэння» працюе найкраща, калі яго розглядаць як вимерную плошчу. Зафіксавце адны ідеальны прыклад, адну справу з бягам і прымітку па вярнэнню да пачатковага стану, прычым расширваючы масштаб. Разглядвайце гэты этап як кантракт межа вхіднымі даннымі і паверыжанымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце критэрыя успеху і адмовіцеся ад тыхоўскага частковага завершэння. Храніце стан графа простым і з адначытаемымі дадзеннямі. Вкладаныя блокі маскуюць, який вузел запісаў кожны поле, і спакоююць працу пасля перарываў.

CHECKLIST = [
    "every requested section exists",
    "each claim cites a retrieved source",
    "open questions are listed, or explicitly none",
]
def verify_complete(objective, checklist, output) -> bool:
    for item in checklist:
        verdict = judge(f"Objective: {objective}\nCheck: {item}\n\n{output}")
        if not verdict.passed:
            log.info("termination blocked by: %s", item)
            return False
    return judge(f"Does this satisfy the objective?\n{objective}\n\n{output}").passed
def finish(state):
    if verify_complete(state.objective, CHECKLIST, state.draft):
        return state.done()
    return state.keep_working(reason="checklist not satisfied")

Чэк-ліст для эксплуатацыі

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

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

Зробіце контрольны пункт пасля дорогіх крокаў. Функцыя продазвучання не должна знову нараховваць плата за той самы вызыв LLM, калі аператар перапрыбуе пазнейшы вузел.

Зафіксавайце версіі залежнасцяў і запісвайце хэш адпаведнага зображэння, якое викорыстоўвалася для дэманстрацыі. Возможнасць перадарабаткі важлівейшая за традыцыйныя знання.

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

Зробіце контрольны пункт пасля дорогіх крокаў. Функцыя продазвучання не должна знову нараховваць плата за той самы вызыв LLM, калі аператар перапрыбуе пазнейшы вузел.

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

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

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

Дзеянне паўжасткі 0/768: звярніце увагу на час выканання, клас памылакі і колькасць викорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынай сэтце запытаў, а не на асобістых спазыраннях, выявіце, чы хацеце застаўіць змяну.

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

Дзеянне паўжасткі 1/768: звярніце увагу на час выканання, клас памылакі і колькасць викорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынай сэтце запытаў, а не на асобістых спазыраннях, выявіце, чы хацеце застаўіць змяну.

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

Дзялей 2/768 прыцелення на зміцнэнне: вимеравайце час выканання, класію памылак і витрату токенав для гэтага запісу, а пасля вырашайце, чы рашыцца застаўіць змяну, спакоюючыся на адзіной наборе пытанняў, а не на індывідуальных прыкладах.

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

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

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

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

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

Дзеянне паўжасткі 5/768: звярніце увагу на час выканання, класы паказчыкаў і колькасць токенаў, якія былі выкарыстаны для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на індывідуальных прыкладах, выявіце, чы хачаце застаўіць змяну.

Для 6-й стадзіі паўжасткі неабходна перад змянай коду адзначыць вхідныя даны, адпаведальнага за выкананне крока і критэрыяы завершэння. Аперацыйныя працавнікі должны магчыма было перазапускаць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Штую стадзію трэба спрыятаць як кантрактом межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Назвіце артыфакты, адзначыце критэрыя успеху і не прабывайце прыймаць часткова завершаныя рэзультаты без падтверджэння.

Дзеянне паўжасткі 6/768: звярніце увагу на час выканання, класы паказчыкаў і колькасць токенаў, якія былі выкарыстаны для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на індывідуальных прыкладах, выявіце, чы хачаце застаўіць змяну.

Калі працюеце над 7-й стадзіяю практыкы забезпечэння безпекі, спачатку запісайце умовы кантракту: неабяжлівыя данні, сігнал успеху і тое, што выходзіць на частым неудачам. Такі список контроля дапамагае залічваць пазнейшыя змены ў кодзе чыста і адкрыта. Зберагайце настройкі паза кодам прыемліка. Файлы сераўнавання, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аудыт без неабяжлівага чытання всей структуры.

Дзялённе 7/768 практыкы забезпечэння безпекі: вы мераваеце час выканання, класыя ошибакі і витрату токенаў для гэтай стадзіяй, а пасля выявляеце, чы хацеце застаўіць змену, спынюючыся на апранаванай сэтце пытанняў, а не на індывідуальных спазырэннях.