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

Выбар агентнага фрэймворка па форме нагрузкі: шэсць восей і шлях рашэння

Выбірайце агентны фрэймворк па форме нагрузкі: LangGraph, CrewAI, AutoGen, Temporal ці ніякі — па дэтэрмінаванасці, працягласці жыцця, ідэмпатэнтнасці, аўдыце і кошце.

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

Крыніцы: Your AI Agent Framework Is Probably the Wrong One Here’s How to Actually Choose

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

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

Першы вось: насколькі неабходна дэтэрміністычнае рашэнне?

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

# A branch where non-determinism is FINE — picking a tone for a summary email.
# If the agent occasionally phrases things slightly differently, nobody's paged.
def draft_summary_tone(context: dict) -> str:
    return llm_call(
        prompt=f"Summarize this incident in a {context['audience']}-appropriate tone.",
        temperature=0.7,  # variability here is a feature, not a bug
    )

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

# A branch where non-determinism is NOT fine — deciding whether to page a human
# at 4am versus auto-remediating. This must be code, not a prompt.
def route_alert(alert: dict) -> str:
    if alert["severity"] == "critical" and alert["service"] in PAGE_ALWAYS_SERVICES:
        return "page_oncall"
    if alert["auto_remediation_available"] and alert["confidence"] > 0.9:
        return "auto_remediate"
    if alert["severity"] == "critical":
        return "page_oncall"
    return "log_and_monitor"

Калі важлівыя рашэнні ў рабочым прыеме выглядаюць як другая функцыя — дэтэрміністычная, практычна перагляджаемая, і такая, якую адпаведальны за салідарнасць хацеў бы прачытаць як звычны код, фрэймворк павінен захаваць гэтую логіку ад LLM. Умовныя рэшткі LangGraph чырпаюцься гэтаму добра, таму што функцыя маршрутацыі ёсць звычны Python, а мадэль чыпае толькі тыя часткі, якія яшчэ ўсвядома ёй даўця, такія як класыфікацыя чыстая або стварэнне праекта.

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

Другі ас: як дазго існуе елемент работы?

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

# Short-lived: starts and finishes inside one HTTP request.
# This is the "no framework needed" zone — a framework here is pure overhead.
async def handle_summarize_request(request: SummarizeRequest) -> SummarizeResponse:
    text = await fetch_document(request.doc_id)
    summary = await llm_summarize(text, max_tokens=300)
    return SummarizeResponse(summary=summary)

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

# Long-lived: this alert might sit in "awaiting human ack" for six hours
# while the on-call engineer is asleep, then resume on a completely
# different process after a deploy rotated the pods underneath it.
class AlertTriageWorkflow:
    async def run(self, alert: dict) -> dict:
        decision = await self.classify_and_route(alert)
        if decision == "page_oncall":
            await self.page(alert)
            await self.wait_for_ack(timeout_hours=1)  # this line is the whole ballgame
        ...

Калі задача надзвічайна швыдка ў выпанаванні і ўсё яе выконанне відбываецца ў памяці аднаго працэсу, то падыходы, пропонаваныя фрэймворкамі, верагодна, ўзаемна перэценены. Звычная асінхронная функцыя з дэкаратаром для павторных спроб лепшая за будзь-які фрэймворк з точкі зору простоты адтрымання, адколі не трэба нічога коордынаваць; кроме таго, вівучэнне мадэлі стану LangGraph чыя выкорыстанне кластэра Temporal для стварэння канцэнтры без стану ёсць зайвымі вітратамі без якога-лібо корысты.

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

Трэція аса: што, якшо крок будзе выконаны два разы?

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

# BEFORE — looks fine in a demo, is a live incident waiting to happen
async def auto_remediate(alert: dict):
    await restart_service(alert["service"])  # what if this activity gets retried?

Другая версія за сваёй структурой ёсць ідэмптантной.

# AFTER — idempotent by construction
async def auto_remediate(alert: dict, idempotency_key: str):
    if await remediation_ledger.already_applied(idempotency_key):
        logger.info("remediation already applied, skipping", key=idempotency_key)
        return await remediation_ledger.get_result(idempotency_key)
    result = await restart_service(alert["service"])
    await remediation_ledger.record(idempotency_key, result)
    return result

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

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

Чэтырты ўзлок: хто чытае рашэнне пазней і як?

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

# A framework-agnostic audit record — this is what actually matters
# in a postmortem, regardless of what orchestrated the steps.
@dataclass
class DecisionRecord:
    alert_id: str
    timestamp: float
    step: str
    reasoning: str        # what the LLM said, verbatim
    decision: str         # the structured outcome, not prose
    confidence: float | None
    human_override: bool

async def log_decision(record: DecisionRecord):
    await audit_store.insert(record)
    # Also emit as a structured log line — cheap insurance for when
    # the audit store itself is the thing that's down during an incident.
    logger.info("agent_decision", **asdict(record))

Кожная платформа дазваляе логаваць певныя даны. Пытанне заключаецца ў тым, чыя бы ўсё гэта структура сама па сабе дае чысты, можна вышукваць след прынятых рашэнняў, чы то, каб яго атрымаць, трэба борацца з абстракцыяй. Об’ект стану LangGraph праходзіць праз іменаваныя вузлы, таму запіт пра тое, якім быў стан непразь які-небудзь рашэнне па маршрутацыі, ёсць прымітным запытам да TypedDict, які ніколі не ператвараўся ў вольны тэкст. Размову AutoGen трэба аналізаваць, каб перадаць тыя ж факты, адколькі яго власны фармат памяці — проза, а не структураваны стан. У всіх сферах, дзе ёсць обавесці па адпаведнасці, у команды аўдыту чы ў звычцы да рэштыльных аналізаў пасля завершэння задач, гэты аспект заслуговае на большую увагу, чым падазнае з маркетынгавых матэрыялаў.

Пяты ўзгалінні: што обмежвае швальнасць команды?

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

# Week-one prototype: prove the concept fast, accept the debt knowingly.
from crewai import Agent, Task, Crew

triage_agent = Agent(role="Alert Triage", goal="Decide how to handle infra alerts")
crew = Crew(agents=[triage_agent], tasks=[Task(description="Triage: {alert}", agent=triage_agent)])
crew.kickoff(inputs={"alert": alert_payload})

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

Аксія шасць: якая затрымка і бюджэт на вітраты за кожную рашэнне?

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

# Expensive pattern: every routing decision is its own LLM call,
# multiplied across a multi-agent conversation with several turns.
# At alert volumes (hundreds/day, sometimes bursts of thousands during
# a real incident), this is a real line item, not a rounding error.
async def route_via_llm(alert: dict) -> str:
    return await llm_call(f"How should we handle this alert? {alert}")

# Cheaper, faster, and more auditable: cheap deterministic pre-filtering
# in code, LLM reserved for genuinely ambiguous cases.
async def route_alert_efficiently(alert: dict) -> str:
    if alert["service"] in KNOWN_NOISY_SERVICES and alert["severity"] == "low":
        return "log_and_monitor"          # zero LLM calls for the common case
    if alert["signature"] in KNOWN_REMEDIATION_PLAYBOOK:
        return "auto_remediate"           # deterministic lookup, zero LLM calls
    return await llm_call(f"Novel alert, needs judgment: {alert}")  # LLM only when genuinely needed

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

Is this unit of work stateless and finishes in seconds?
  └─ YES → skip the framework entirely. Plain functions + retries. Ship it.
  └─ NO, continue.

Does it need to survive process restarts / wait on humans for hours-to-days?
  └─ YES → you need durable execution (Temporal or equivalent) as the backbone,
           regardless of what else you pick for the reasoning layer.
  └─ NO, continue.

Are the important branches safety- or compliance-critical
(money, infra changes, irreversible external actions)?
  └─ YES → LangGraph-style explicit graphs, keep LLM scoped to narrow nodes.
  └─ NO, mostly exploratory/creative → CrewAI or AutoGen are legitimate defaults.

Is this still a prototype whose findings might get thrown away?
  └─ YES → optimize for speed of iteration over long-term correctness,
           but write down when you'll revisit that tradeoff.

Застосавшы гэты падход да агента для сортавання апавяшэнняў, атрымліваецца мнагаслоўны дызайн. Ён вытрымлівае перзапускі і чакае на людзей, таму патрэбна надзеямаеся шарае экзекуцыі. Яго найважлівейшыя веткі стосуюцца крытычных аспектаў безпекі — падача спавяшчэнняў протыра автаматычнага выправлення, таму ў кожным кроку патрэбна чыстае маршрутызаванне у стыле LangGraph. Калі ён включае прыстрой для падачы спавяшчэнняў, ён ўжо давно пераходзіць за межы этапы пратотыпа. Час стае основнай структурой, пры чым крок оркестрацыі LLM з адмежаваным дыяпазонам выступае як адна з актывацый ў ёй.

@activity.defn
async def classify_alert_activity(alert: dict) -> dict:
    # LangGraph-style graph runs here — bounded reasoning, deterministic routing —
    # inside an activity Temporal will retry and time-box like any other side effect.
    result = alert_triage_graph.invoke({"alert": alert, "audit_log": []})
    return {"decision": result["decision"], "confidence": result["confidence"]}

@workflow.defn
class AlertTriageWorkflow:
    def __init__(self):
        self._acked = False

    @workflow.signal
    async def acknowledge(self):
        self._acked = True

    @workflow.run
    async def run(self, alert: dict) -> dict:
        classification = await workflow.execute_activity(
            classify_alert_activity, alert,
            start_to_close_timeout=timedelta(seconds=20),
            retry_policy=workflow.RetryPolicy(maximum_attempts=3),
        )
        if classification["decision"] == "page_oncall":
            await workflow.execute_activity(page_oncall, alert, start_to_close_timeout=timedelta(seconds=10))
            await workflow.wait_condition(lambda: self._acked, timeout=timedelta(hours=1))
            if not self._acked:
                await workflow.execute_activity(escalate_to_secondary, alert, start_to_close_timeout=timedelta(seconds=10))
        elif classification["decision"] == "auto_remediate":
            await workflow.execute_activity(
                auto_remediate, alert, f"remediate-{alert['id']}",
                start_to_close_timeout=timedelta(minutes=2),
                retry_policy=workflow.RetryPolicy(maximum_attempts=2),
            )
        return {"alert_id": alert["id"], "decision": classification["decision"]}

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

Памылкі, якія продовжваюць павтарацца

  • Выбір на адвагу колькасці звёзд у GitHub. Популярнасць указвае на падтрымку спяльнай групы і на тое, сколькі адказоў існуе ў Інтэрнэце. Гэта нічога не сказвае пра тое, чы рэальны модэль выканання падходзіць па стойкасці і дэтэрмінізму да патрэб працы.
  • Дазволенне протатэпнаму фрэймворку стаць постацейным. Протатэп, які проста працаваў, пастае сістэмай для практычнага выкарыстоўвання, таму што перапісваўство механізмаў керавання здаецца не дадаючым новых функцый. Ён дадае надзеямасць, якая застаеўця непазірной, пакуль яе не нехапае.
  • Пачатак з моцнага дварчыка рабочых практык. Адваротная прыгматыка таксама рэальна: каманда чытае занадта многа паведамленняя пра выдатковыя аплыненні і размешчае Temporal за ботам для адпаведзення на запыткі, які ніколі не могуць прыжыць за межы перачынкі процэсу. Адзінство забавы павінна быць супараднай як у напрамку выдатковасці, так і ў напрамку ўсвоўвання рэсурсаў.
  • Адносаванне фрэймворку агентаў да ўсёўказальнай адпаведзі. Ён пакрывае шары логікі і выкарыстоўвання інструментаў, а рэдка — шары выдатковасці, ідэмпотэнцыі і стварэння статыстык, таму ўсе вышэказаны аспекты здзейчыцца пераважна парадульна ў маркетынгавых матэрыялах будзь-якога фрэймворка.
  • Праўдзіва адпаведзь

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

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

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