AI-агент у production не з’яўляецца prompt з большым кантэкстным акном. Гэта сэрвіс, у якім мадэль выбірае дзеянні, назірае іх вынікі і працягвае працу, пакуль не дасягне абмежаванага выніку або не папросіць чалавека. Мадэль толькі адзін кампанент. Control plane вырашае, што мадэль можа бачыць, якія tools яна можа выклікаць, якія дзеянні патрабуюць approval, як state перажывае перазапуск і якія доказы патрэбны перад выпуском новай версіі.
Гэты артыкул прапануе reference architecture для аднаго агента з невялікім наборам інструментаў. Тыя ж межы падыходзяць workflow з фіксаванымі крокамі і будучай multi-agent сістэме. Пачынайце з найменшага цыклу, які выконвае задачу. У кіраўніцтве Anthropic пра эфектыўных агентаў таксама адрозніваюцца прадказальныя workflow і сістэмы, у якіх мадэль дынамічна кіруе выкарыстаннем tools. Аўтаномнасць з’яўляецца прадуктовым рашэннем, а не архітэктурным default.
Reference architecture
Аддзяліце шлях запыту, decision loop і effects, якія змяняюць знешні свет. Gateway аўтэнтыфікуе caller, стварае request ID і trace ID, ужывае quota і выдаляе або класіфікуе sensitive fields. Orchestrator валодае loop. Model adapter ператварае neutral state у provider request, а provider response, у невялікі decision type. Tool gateway правярае arguments, аўтарызуе actor principal, ужывае policy і выклікае isolated connector. State і event storage павінны быць па-за працэсам, каб worker мог працягнуць пасля збою.
[Карыстальнік або API-кліент]
|
[Gateway: identity, limits, request ID]
|
[Orchestrator: policy -> model -> tool loop]
/ | \
[State store] [Approval service] [Tool gateway]
| | |
[Memory/RAG] [Рашэнне чалавека] [API, файлы, чаргі]
|
[Events і traces]
Не давайце мадэлі raw credentials, неабмежаваны network access або прамы запіс у базу. Tool gateway павінен прапаноўваць вузкія аперацыі накшталт "search_orders", "draft_refund" і "send_message", а не generic HTTP client або SQL console. Для кожнай аперацыі патрэбны owner, input schema, permission, risk class, timeout і задакументаваны result shape.
Выкарыстоўвайце відавочны request envelope:
| Поле | Прызначэнне |
|---|---|
| tenantId і actorId | Прывязаць кожнае чытанне і effect да аўтэнтыфікаванага principal. |
| requestId і traceId | Звязаць retries, approvals, tool calls і logs. |
| goal | Захоўваць user goal асобна ад model messages. |
| policyVersion і modelVersion | Зрабіць run дастаткова reproducible для расследавання. |
| deadline і stepBudget | Абмежаваць час і колькасць model-tool turns. |
NIST AI RMF Generative AI Profile дапамагае арганізаваць працу з рызыкамі па ўсім lifecycle. Перакладзіце яго пытанні ў канкрэтныя controls у envelope і tool gateway. Framework сам па сабе не даказвае бяспеку пэўнага deployment.
Tool loop
У loop павінен быць адзін owner і бачны state transition на кожным ходзе:
- Загрузіць run, policy, conversation summary і дазволены tool catalog.
- Пабудаваць bounded model input. Пазначыць user text, retrieved text, tool output і system instructions як розныя trust classes.
- Папрасіць model вярнуць final response або typed tool call. Адхіліць няправільныя name і arguments да execution.
- Вырашыць authorization і risk policy па-за model. Сцвярджэнне мадэлі, што action бяспечны, не з’яўляецца рашэннем authorization.
- Калі action перасякае approval gate, захаваць pending action і спыніцца. Пасля explicit decision працягнуць са захаванага action.
- Выканаць connector з deadline і idempotency key. Запісаць redacted result і дадаць яго ў state.
- Праверыць step, token, cost і wall-clock budgets. Працягваць толькі калі policy дазваляе яшчэ адзін turn.
- Вярнуць адказ, які тлумачыць, што адбылося, што не адбылося і якая approval або uncertainty засталася.
Не змяшчайце model call у неабмежаваны "while" loop. Step budget не дазваляе prompt або tool ператварыць адзін request у дарагую chain. Deadline абараняе caller і worker pool. Repeated-call detector знаходзіць мадэль, якая зноў просіць тое самае няўдалае action. Circuit breaker можа часова адключыць degraded connector, пакінуўшы read-only tools.
Спецыфікацыя Model Context Protocol стандартызуе resources, prompts і tools, але не замяняе consent, authorization і isolation controls host application. Ставіцеся да MCP server як да external dependency. Зафіксуйце яго identity, праверце advertised tools, абмяжуйце data, якую перадаеце, і прымяняйце тую ж gateway policy, што і для in-house connector.
State, memory і context
State з’яўляецца durable record аднаго run. Захоўвайце user goal, messages або references, tool calls і results, approvals, policy decisions, model і tool versions, timestamps, status і error classification. Спачатку append events, пасля выводзьце current run view. Recovery і audit так прасцейшыя, чым пры mutation аднаго opaque JSON blob. Encrypt sensitive fields, ізалюйце tenants, вызначце retention і зрабіце deletion поўным для snapshots, indexes, traces і caches.
Conversation history не тое самае, што memory. Для current run захоўвайце кароткачасовы working context. User або business memory пакідайце толькі калі ёсць purpose, retention rule, source і спосаб выпраўлення карыстальнікам або адміністратарам. Facts павінны мець provenance і confidence або freshness field. Не запісвайце model guesses у durable memory толькі таму, што яны гучаць праўдападобна.
Retrieval з’яўляецца tool з trust boundary. Да ranking ужывайце tenant і authorization filters. Пераносьце source identifiers і timestamps у context. Скажыце model, што retrieved text з’яўляецца data, а не instructions. Абмяжоўвайце chunks, выдаляйце непатрэбныя secrets і па змаўчанні логуйце query і document identifiers без private content. У PostgreSQL параўноўвайце lexical і vector candidates і рабіце rerank толькі пасля authorization. Унутраны гайд па hybrid RAG з pgvector апісвае гэтую мяжу.
Context compaction павінна быць дастаткова deterministic для debugging. Рэзюмуючы старыя turns па fixed schema, захоўвайце decisions, unresolved questions, tool effects, citations і user constraints. Original event log трымайце па-за prompt. Калі summary мяняе сэнс pending action, спыніцеся і папрасіце review замест маўклівага працягу.
Tools і threat boundaries
Tool schema з’яўляецца security contract, а не толькі model metadata. Gateway павінен правяраць types, lengths, enum values, resource ownership і relationships паміж палямі. Пасля authorization ператварайце names у internal identifiers. Падзяляйце read і write tools. Давайце connectors кароткачасовыя credentials, абмежаваныя адным tenant і operation. Небяспечны code або file work выконвайце ў isolated worker з filesystem і network allowlist.
Лічыце ўвесь external content патэнцыйна варожым. Email, web page, issue, document, tool description або MCP resource могуць утрымліваць indirect prompt injection. Аддзяляйце яго ў model input, пры патрэбе прыбірайце executable markup і пакідайце рашэнне пра permissions application. Output validation павінна быць незалежнай ад model. Перад перадачай refund payment connector праверце amount, currency, actor permission і policy maximum.
Threat model павінен ахопліваць:
| Мяжа | Што трэба прадухіліць |
|---|---|
| User → gateway | Account takeover, oversized requests і чужыя tenant identifiers. |
| Model → tool gateway | Argument injection, privilege confusion і excessive agency. |
| Retrieval або MCP → model | Indirect prompt injection і malicious instructions у data. |
| Connector → external service | Credential leakage, SSRF, replay і data exfiltration. |
| Worker → state store | Tampered events, stale policy і няпоўная audit history. |
OWASP GenAI LLM Top 10 апісвае prompt injection, excessive agency, insecure output handling і unbounded consumption як risks, што патрабуюць application-level mitigations. Унутраны гайд па prompt injection і MCP security дае threat-focused checklist. System prompt карысны як guidance, але не з’яўляецца sandbox, authorization layer або secret store.
Approval gates і human control
Размяшчайце approvals вакол effects, а не harmless reasoning. Чытанне ўласнага calendar карыстальніка можа быць automatic. External message, змяненне record, выдача money, выдаленне data або deploy code звычайна патрабуюць policy decision з улікам actor, target, amount, reversibility і confidence. Gate павінен быць у application code, каб prompt не мог яго абысці.
Persist approval request з proposed tool, normalized arguments, affected resources, reason, policy version, expiration і hash адпаведнага state. Reviewer павінен бачыць тыя ж data. Прывяжыце яго decision да action hash і actor. Пасля approval паўторна праверце authorization, freshness і budget перад execution. Пасля rejection або expiry запішыце decision і паведамце model, што action не адбыўся. Старая approval не можа authorise зменены payload.
Рэжымы human-in-the-loop:
| Рэжым | Прыдатнае выкарыстанне |
|---|---|
| Observe | Запісваць або sampling low-risk actions, пакідаючы agent automatic. |
| Confirm | Прасіць approval непасрэдна перад irreversible effect. |
| Review | Даць чалавеку праверыць поўны draft і selected evidence. |
| Take over | Перадаць run operator з current state і lock. |
Праектуйце pause як звычайны state, а не exception. Queue можа даставіць pending approvals, notification можа expire, а worker resume run на іншым host. Карыстальнік павінен бачыць, ці agent думае, чакае data, approval, retry або скончыў.
Retries, idempotency і recovery
Класіфікуйце errors перад retry. Validation error патрабуе выпраўленага call або пытання карыстальніку. Authentication і authorization errors павінны спыняць. Rate limits павінны паважаць retry signal provider. Timeout і connection reset неадназначныя для writes, бо remote service магла ўжо прымяніць effect. Паўтарайце толькі operation, для якой semantics або idempotency key робяць паўтор бяспечным. Раздзел 9.2.2 RFC 9110 тлумачыць, чаму non-idempotent methods нельга аўтаматычна паўтараць без спосабу вызначыць бяспеку effect.
Генеруйце stable key з run і logical action, а не з attempt number. Connector захоўвае key і final result на працягу retry window. Калі той самы key прыходзіць з іншымі arguments, адхіляйце яго. Выкарыстоўвайце exponential backoff з jitter і невялікі maximum attempts. Retry не з’яўляецца новым model decision. Захоўвайце original call, attempt number, response class і connector request identifier.
Recovery з’яўляецца задачай state machine. Выкарыстоўвайце statuses "running", "waiting_for_approval", "retrying", "failed", "completed" і "cancelled". Lease не дае двум workers адначасова выканаць адзін run. Пасля страты lease спыніцеся перад наступным effect. Reconciler можа параўнаць pending actions з connector records пасля worker crash. Cancellation павінна распаўсюджвацца на model requests, tool calls, queues і approval requests, калі provider гэта падтрымлівае.
Observability
Стварайце адзін trace на user request і spans для model calls, retrieval, policy checks, approvals і tools. Запісвайце duration, status, retry count, input і output token counts калі яны даступныя, model і prompt versions, tool name, risk class і cost estimate. Redact secrets і sensitive content да export. Stable run ID звязвае approval або support ticket з trace, але не кладзіце personal data у baggage. OpenTelemetry context propagation апісвае сувязь trace context паміж services і папярэджвае пра untrusted headers і sensitive baggage.
Вымярайце task completion паводле rubric, successful tool-call rate, validation failures, approval rate, retry і timeout rate, p50 і p95 latency, token і tool cost на completed task, cancellation rate і policy blocks. Разразайце іх па model version, tool, tenant class і release. Low error count можа хаваць silent wrong answers, таму звязвайце traces з sampled transcripts і evaluator results. Не логуйце chain-of-thought. Захоўвайце кароткія decision metadata і user-visible reasoning або citations, дазволеныя policy.
Унутраны гайд па observability AI-агентаў паказвае, як зрабіць signals карыснымі і не ператварыць logs у другую базу secrets.
Evals да і пасля release
Agent eval з’яўляецца scenario з вызначанымі starting state, allowed tools, expected invariants і scoring rule. Final answer недастаткова. Правярайце, што agent выкарыстаў authorized tool, захаваў tenant scope, папрасіў approval калі трэба, не паўтарыў write, працытаваў правільны source і спыніўся на budget. Дадавайце adversarial scenarios: malicious retrieved text, unavailable connector, timeout пасля write, stale approval, ambiguous request і malformed tool data.
Выкарыстоўвайце layered suite:
- Deterministic unit tests для schemas, authorization, redaction, idempotency, state transitions і budget enforcement.
- Replay tests з recorded tool responses і fixed model decisions для праверкі recovery.
- Scenario tests з model і rubric для task outcome, safety і communication.
- Red-team tests для direct і indirect injection, data leakage, excessive agency і denial of service.
- Production sampling з privacy controls, human review і ператварэннем failures у regression cases.
Версіянуйце scenario, tools, policy, prompts, model і evaluator. Захоўвайце failures разам з trace і найменшым reproducing input. Параўноўвайце candidate release з baseline і не дапускайце regression hard safety invariants, нават калі average quality вырасла. Гайд Anthropic пра evals агентаў тлумачыць, чаму multi-turn tool use патрабуе trajectory-level evaluation. Унутраны гайд па evals AI-агентаў дае практычную test matrix.
Cost і latency
Кожны model turn, retrieved token, tool call, approval pause і retry дадае time або money. Задавайце budgets для класаў задач, а не адну global number. Выкарыстоўвайце меншую model для routing, extraction і policy prechecks, калі вымераная дакладнасць дастатковая. Больш моцную model пакідайце для ambiguous planning або final synthesis. Кешуйце stable tool catalogs і retrieval embeddings. Сціскайце context да таго, як ён вырасце, але вымярайце, ці summary не стварае дадатковых turns або страты facts.
Паралелізуйце незалежныя read-only calls, пасля аб’ядноўвайце вынікі з відавочным provenance. Writes пакідайце паслядоўнымі, калі connector не дае transaction або спраектаваную compensation. Паказвайце progress без раскрыцця secrets. Для доўгай працы persist job і дазвольце worker працягнуць пасля заканчэння HTTP request. Больш хуткая model не таннейшая, калі памылкі выклікаюць human review, compensating writes або паўторныя runs. Вымярайце total cost на correct і policy-compliant outcome.
Мінімальны runnable loop
Прыведзены protocol-independent TypeScript example выкарыстоўвае fake model і local tools, таму запускаецца без provider SDK або network access. Ён паказвае typed decision loop, write approval, bounded retries, stable idempotency key і duplicate effect guard. Сапраўдны adapter можа замяніць model, захаваўшы policy і tool boundary.
type ToolCall = { id: string; name: string; input: unknown };
type Message =
| { role: "user"; content: string }
| { role: "assistant"; content: string; toolCall?: ToolCall }
| { role: "tool"; callId: string; content: string };
type Decision =
| { kind: "answer"; text: string }
| { kind: "call"; call: ToolCall };
type Tool = {
sideEffect: "read" | "write";
run(input: unknown, idempotencyKey: string): Promise<string>;
};
const issued = new Set<string>();
const tools: Record<string, Tool> = {
getBalance: {
sideEffect: "read",
async run(): Promise<string> {
return JSON.stringify({ account: "demo", cents: 4200 });
},
},
sendInvoice: {
sideEffect: "write",
async run(input: unknown, idempotencyKey: string): Promise<string> {
if (issued.has(idempotencyKey)) return "already-sent";
if (typeof input !== "object" || input === null) throw new Error("invalid input");
issued.add(idempotencyKey);
return "invoice-sent";
},
},
};
const model = {
async decide(messages: readonly Message[]): Promise<Decision> {
const toolCount = messages.filter((message) => message.role === "tool").length;
if (toolCount === 0) {
return { kind: "call", call: { id: "balance-1", name: "getBalance", input: {} } };
}
if (toolCount === 1) {
return { kind: "call", call: { id: "invoice-1", name: "sendInvoice", input: { cents: 1200 } } };
}
return { kind: "answer", text: "The balance was checked and the invoice was sent." };
},
};
const wait = (milliseconds: number) => new Promise((resolve) => setTimeout(resolve, milliseconds));
async function execute(call: ToolCall, tool: Tool, key: string): Promise<string> {
for (let attempt = 0; attempt < 3; attempt += 1) {
try {
return await tool.run(call.input, key);
} catch (error) {
if (attempt === 2) throw error;
await wait(10 * 2 ** attempt);
}
}
throw new Error("unreachable");
}
async function run(): Promise<string> {
const state: { messages: Message[]; completed: Set<string> } = {
messages: [{ role: "user", content: "Check the balance and send the invoice." }],
completed: new Set<string>(),
};
const sessionId = "session-demo";
for (let step = 0; step < 6; step += 1) {
const decision = await model.decide(state.messages);
if (decision.kind === "answer") return decision.text;
const tool = tools[decision.call.name];
if (!tool) throw new Error("unknown tool");
const key = sessionId + ":" + decision.call.id;
if (tool.sideEffect === "write" && !process.argv.includes("--approve")) {
return "Paused for approval: " + decision.call.name;
}
if (state.completed.has(key)) continue;
const result = await execute(decision.call, tool, key);
state.completed.add(key);
state.messages.push(
{ role: "assistant", content: "", toolCall: decision.call },
{ role: "tool", callId: decision.call.id, content: result },
);
}
throw new Error("step budget exceeded");
}
run().then(console.log).catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
Скампілюйце код з дапамогай TypeScript toolchain праекта і запусціце emitted JavaScript без flag, каб убачыць approval pause, а потым з --approve, каб дазволіць write. Прыклад наўмысна захоўвае state у memory. У production state павінен быць durable, tenant-scoped, пры патрэбе encrypted і аднаўляцца lease-aware worker.
Парадак пабудовы
Вызначце task outcome і забароненыя effects да выбару model. Рэалізуйце адзін read tool і адзін reversible write tool за schemas і authorization. Дадайце durable events, budgets, approval states і idempotency да новых tools. Адразу instrument першы end-to-end trace. Стварайце eval scenarios з рэальных failure modes і запускайце іх пасля кожнай змены prompt, policy, tool або model. Дадавайце MCP або multi-agent delegation толькі калі вымераная патрэба апраўдвае дадатковую trust boundary.
Звязанае чытанне
- Prompt injection і MCP security
- Evals AI-агентаў
- Observability AI-агентаў
- Hybrid RAG з pgvector
- Anthropic: Building effective agents
- Anthropic: Demystifying evals for AI agents
- Model Context Protocol specification
- NIST AI RMF Generative AI Profile
- OWASP GenAI LLM Top 10
- OpenTelemetry context propagation
- RFC 9110 HTTP Semantics