1. Agent üçün niyə “production düşüncəsi” lazımdır
Adi backend yazanda “proda çıxmaq” ideyası avtomatik olaraq paranoya rejimini işə salır: avtorizasiya, loqlaşdırma, xəta emalı, limitlər, sirlər kodda yox, .env faylında və s.
Agentlə isə eyni rejimi, sadəcə daha sərt şəkildə aktivləşdirmək lazımdır. Səbəb sadədir: adi backend məhz yazdığınız şeyi icra edir, agent isə modelin ona verilmiş alətlər və təlimatlar çərçivəsində özünün qərar verdiyini icra edir. Burada nəzarət illüziyası klassik koddakından daha güclüdür: elə bil ki, prompt hər şeyi təsvir edir, amma əslində siz yalnız mühiti və mövcud hərəkətləri idarə edirsiniz, modelin bütün “fikirlərini” yox.
Ona görə də bu mühazirədə agentimizi tədricən “müdafiə təbəqələri” ilə əhatə edəcəyik:
- əvvəlcə onun nə edə biləcəyini məhdudlaşdıracağıq (alət hüquqları və agentlərin ayrılması),
- sonra icra mühitini izolə edəcəyik (sandbox və limitlər),
- sirlər və PII ilə qaydanı bərqərar edəcəyik,
- və nəhayət, müşahidəolunmanı aktivləşdirəcəyik: loglar, metriklər və baza treysinqi.
Məsələləri konkretləşdirmək üçün GiftGenius hekayəsi ilə davam edəcəyik: hədiyyə seçməyə kömək edən və bir az commerce dünyasına girən agent (sifariş və checkout vasitəsilə, hələ ACP detalları olmadan — bu sonra olacaq).
2. Hüquqlar: agentə “dünyadakı bütün düymələr” lazım deyil
Ən az səlahiyyət prinsipi (Least Privilege)
Birinci qayda: agent hər şeyi bacarmalı deyil. Alətlər nə qədər çox olsa, “o olmayan” funksiyanı “o olmayan” anda çağırma ehtimalı bir o qədər yüksəlir. Hər şeyi oxuyan və yazan monstrual manageEverything() əvəzinə heç olmasa oxu və yazını ayıran kiçik, dəqiq funksiyalar layihələndiririk.
GiftGenius üçün bu xüsusilə aydındır: bir məsələ — hədiyyə siyahısını və istifadəçi üstünlüklərini oxumaq, başqa məsələ — sifariş yaratmaq və ya təsdiqləmək (orada artıq pul var). Buna görə adətən belə edirik:
- təhlükəsiz “read‑only” alətlər toplusu (hədiyyə axtarışı, detallara baxış),
- ayrı “write” alətləri (sifariş qaralamasının yaradılması, sifarişin ləğvi),
- və ehtiyac varsa, xüsusilə təhlükəli əməliyyatlar üçün başqa bir səviyyə (ödəniş təsdiqi, kütləvi dəyişikliklər).
Fərqli tapşırıqlar üçün fərqli agentlər
Daha bir güclü fənd — agentləri məsuliyyət zonalarına görə ayırmaqdır. Bir agent — “hədiyyə seçimi”, digəri — “sifarişlərin idarə olunması”. Beləliklə, hətta əgər gift agentində model bir az “yoldan çıxsa” belə, o, ödəniş alətini fiziki olaraq çağıra bilməyəcək, çünki həmin alət onun konfiqurasiyasında ümumiyyətlə yoxdur.
Agent və alətlər üçün minimalistik konfiqurasiya tipini təsəvvür edək:
// Fikirların izahı üçün sadələşdirilmiş tiplər
type ToolName = 'suggest_gifts' | 'get_gift_details' |
'create_order_draft' | 'confirm_order';
type AgentConfig = {
id: string;
allowedTools: ToolName[];
maxSteps: number;
};
İndi iki GiftGenius agentini təsvir edək:
export const giftPlannerAgent: AgentConfig = {
id: 'gift-planner',
allowedTools: ['suggest_gifts', 'get_gift_details'],
maxSteps: 6,
};
export const orderAgent: AgentConfig = {
id: 'order-manager',
allowedTools: ['create_order_draft', 'confirm_order'],
maxSteps: 4,
};
Bəli, bu hələlik bir abstraksiyadır, amma məna sadədir: kodda hər dörd alət olsa belə, konkret agent yalnız lazım olan alt dəsti alır.
Hüquqların istifadəçiyə və rollara bağlanması
Unutmamaq vacibdir ki, iki ayrı mahiyyət var:
- istifadəçi və onun hüquqları (bu user_id ümumiyyətlə nəsə ala, ləğv edə, tarixçəni görə bilərmi),
- agent və ona icazə verilən alətlər.
İdeal halda hər alət çağırışı iki yoxlamadan keçməlidir: “agentə bu icazəlidirmi?” və “istifadəçiyə də bu icazəlidirmi?”.
Şərti olaraq:
type UserRole = 'guest' | 'customer' | 'admin';
function canUserCallTool(role: UserRole, tool: ToolName): boolean {
if (tool === 'confirm_order') {
return role === 'customer' || role === 'admin';
}
if (tool === 'create_order_draft') {
return role !== 'guest';
}
return true; // oxumağa hamıya icazə veririk
}
MCP/backend tərəfində tool çağırışını emal edərkən ikili yoxlama edə bilərik:
function assertToolAllowed(
agent: AgentConfig,
userRole: UserRole,
tool: ToolName,
) {
if (!agent.allowedTools.includes(tool)) {
throw new Error(`Tool ${tool} agent ${agent.id} üçün qadağandır`);
}
if (!canUserCallTool(userRole, tool)) {
throw new Error(`Rolu ${userRole} olan istifadəçi ${tool} çağırmaq hüququna malik deyil`);
}
}
Nəticədə hətta model qəfil “yanlış” agentdən və ya qonaq adından confirm_order çağırmağa qərar versə belə — çağırış bu yoxlamaya dirənəcək və planlaşdırılmamış ödəniş deyil, idarə olunan xətaya çevriləcək.
Mühitlərə görə fərqli konfiqurasiyalar
Dev və staging mühitlərində agentə daha çox azadlıq vermək istəyirsiniz: test alətləri, saxta ödəniş servisləri, eksperimental funksiyalar. Production-da isə əksinə, konfiqurasiya maksimum sərtdir: bəzi alətlər söndürülüb, endpoint-lər yalnız döyüş (canlı), tokenlər — yalnız realdır.
Ən sadə sxem:
type Env = 'dev' | 'staging' | 'production';
const env = (process.env.APP_ENV as Env) ?? 'dev';
const orderAgentByEnv: Record<Env, AgentConfig> = {
dev: {
id: 'order-manager-dev',
allowedTools: ['create_order_draft', 'confirm_order'],
maxSteps: 8,
},
staging: {
id: 'order-manager-staging',
allowedTools: ['create_order_draft', 'confirm_order'],
maxSteps: 6,
},
production: {
id: 'order-manager-prod',
allowedTools: ['create_order_draft'], // confirm yalnız ayrıca yolla
maxSteps: 4,
},
};
export const currentOrderAgent = orderAgentByEnv[env];
Production-da confirm_order ümumiyyətlə ayrıca “təhlükəli” agenta çıxarıla bilər; siz onu yalnız vidjetdə açıq “Sifarişi təsdiqlə” klikindən və əlavə yoxlamalardan sonra çağırırsınız.
3. Sandbox: agentə sizin kainata root‑akses lazım deyil
İzolasiya səviyyələri
Agentlər və istifadəçilər üçün hüquqları təyin etdikdən sonra növbəti qorunma səviyyəsinə — sandbox və icra mühitinin izoləsiyasına keçirik.
Agent və onun alətləri üçün sandbox-u şərti olaraq bir neçə səviyyəyə bölmək olar:
- Alət kodu səviyyəsi. Fayl sisteminə, şəbəkəyə və proses resurslarına çıxışı məhdudlaşdırırıq: hara gəldi yazmağa, ixtiyari domenlərə getməyə, CPU-da sonsuz fırlanmağa və ya gigabaytlarla yaddaş yeməyə icazə vermirik.
- Agents SDK səviyyəsi. Run dövrü üzrə addım limiti, tool çağırışlarının sayı və kontekst ölçüsü (token limit) təyin edirik. Model sonsuz “düşünə” və tool-calls çoxalda bilməz — bir məqamda run “addım limiti” və ya “vaxt limiti” xətası ilə bitəcək.
Bütün bunlar vizual sxem kimi təsəvvür etməyə rahat olan klassik “müdafiə arxitekturası”na yığılır.
graph TD
A[Prompt / system təlimatları] --> B[Alətlər üçün JSON Schema]
B --> C[Agent və istifadəçi icazələri]
C --> D[İnfrastruktur sandbox-u]
D --> E[Xarici servislər / DB]
subgraph Agent
A
B
C
end
subgraph İnfrastruktur
D
end
Prompt — ən zəif müdafiədir; real güc kodunuzun nə edə biləcəyini və hansı API-lərin əlçatan olduğunu fiziki olaraq məhdudlaşdırdığınız yerdən başlayır.
Run dövrünə limitlər: addımlar, vaxt, tool‑calls
Sandbox-un bir hissəsini elə agent konfiqurasiyasında ifadə etmək olar: maksimal addım sayı, ümumi icra vaxtı, tool çağırışları limiti. Bu təkcə runaway dövrlərdən müdafiə deyil, həm də xərclərə nəzarətdir.
Run seçimlərinin abstrakt konfiqurasiyası nümunəsi:
type RunLimits = {
maxSteps: number;
maxToolCalls: number;
timeoutMs: number;
};
const defaultLimits: RunLimits = {
maxSteps: 8,
maxToolCalls: 10,
timeoutMs: 30_000,
};
Bu cür limitləri sonra agenti işə salan örtüyə ötürürsünüz. Əgər model 11-ci dəfə aləti çağırmağa qərar verərsə — agentin işə salınmasını dayandırırsınız və istifadəçiyə dürüst deyirsiniz ki, tapşırıq çox mürəkkəbdir; agentin büdcəni nəzarətsiz yandırmasına imkan vermirsiniz.
Kod və şəbəkə izoləsiyası
Konteyner/proses səviyyəsində adi praktika belədir:
MCP serverinin və/və ya agent servisinin kodu yalnız oxunan fayl sistemi ilə (xüsusi ayrılmış iş kataloqu istisna olmaqla) və məhdud resurslarla (CPU, RAM) konteynerdə işə düşür. Şəbəkə allow‑list ilə qurulub: yalnız lazım olan xarici servislərə (sizin commerce backend, ödəniş xidməti, bir-iki xarici API) getmək olar, ixtiyari internetə yox.
Agent ssenarilərində bu xüsusilə kritikdir: model hansısa “yad” API-yə çıxmağa və ya gözlənilməz faylları oxumağa cəhd edə bilər və yaxşı olar ki, belə cəhdlərdə belə artıq resurslara fiziki çıxış hüququ olmasın.
Kodda bu adətən “sehrli TypeScript sətiri” yox, orkestratorunuzun (Docker Compose, Kubernetes, Vercel, Fly.io və s.) ayarları kimi görünür. Amma perspektivdə bunu layihələndirmə mərhələsində düşünmək faydalıdır:
- kənar kodu işə salan alət (məsələn, shell komandaları ilə hesabat generasiyası) ayrıca sərt izolə olunmuş mühitdə işləməlidir;
- alətlər yad faylları, sirləri, konfiqləri oxumaq imkanına malik olmamalıdır;
- şəbəkə çıxışını domenlərə və ya IP-lərə görə açıq şəkildə məhdudlaşdırmaq daha yaxşıdır.
4. Sirlər və məxfi məlumatlar: agentin bilməsinə ehtiyac olmayanlar
Sirlər harada yaşamalıdır, harada yox
Baza qayda: heç bir sirr — API açarları, parollar, access tokenlər — modelin promptuna, vidjetə, loglara və repozitoriyaya düşməməlidir. Onlar yaşayır:
- mühit dəyişənlərində (process.env.SOMETHING),
- secret manager-də (AWS Secrets Manager, GCP Secret Manager, Vault və s.),
- əlahiddə şifrələnmiş storlarda, çıxışı sərt şəkildə idarə olunan yerlərdə.
Məsələn, bizim GiftGenius-da mağazanın commerce‑API-si üçün açar var. Agentin MCP aləti vasitəsilə sifariş qaralaması yarada bilməsini istəyirik, amma model açarı görməməlidir.
// mcp/tools/createOrderDraft.ts
const COMMERCE_API_KEY = process.env.COMMERCE_API_KEY!;
export async function createOrderDraft(args: {
userId: string;
giftId: string;
quantity: number;
}) {
// Model heç vaxt COMMERCE_API_KEY görməyəcək — o yalnız burada, serverdədir
const res = await fetch(`${process.env.COMMERCE_API_URL}/orders/draft`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${COMMERCE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(args),
});
if (!res.ok) {
throw new Error(`Commerce API returned ${res.status}`);
}
return res.json(); // Cavabda agenta artıq təhlükəsiz obyekt qaytaracağıq
}
Vacibdir: alət cavabında açarları və digər həssas detalları “keçirməməlisiniz”. Agentə draftOrderId, mövqelərin siyahısı və bəlkə də status məlum olması kifayətdir.
PII və kontekstdə məlumatların minimallaşdırılması
Sirlərdən əlavə PII (istifadəçilərin şəxsi məlumatları) kateqoriyası da var: adlar, telefonlar, çatdırılma ünvanları, email və s. Agentə çox vaxt bu “xam” mətnin hamısı lazım deyil. Strukturlaşdırılmış profil kifayətdir: “stolüstü oyunları sevir”, “yaş 30–35”, “təxmini büdcə 50–70$”.
İstifadəçinin sifariş tarixçəsini tam halda prompta atmaq əvəzinə, artıq aqreqasiya olunmuş və anonimizə edilmiş profil qaytaran get_user_profile_summary adlı alət hazırlamaq olar.
type ProfileSummary = {
ageRange: '18-25' | '26-35' | '36-50' | '50+';
interests: string[];
preferredBudget: { min: number; max: number };
};
export async function getUserProfileSummary(userId: string): Promise<ProfileSummary> {
// Burada siz DB-yə girirsiniz, amma çölə yalnız aqreqasiya olunmuş məlumat çıxarılır
return {
ageRange: '26-35',
interests: ['stolüstü oyunlar', 'qadcetlər'],
preferredBudget: { min: 30, max: 80 },
};
}
Model yalnız hədiyyə seçimi üçün lazım olan miqdarda məlumat görür, daha artığını yox.
Logların skrablanması
Loglar — sirlər və PII-nin təsadüfən ortaya çıxa biləcəyi təbii yerdir. Xüsusən də “rahat” console.log(...) tipli loqger yazıb “hər şeyi çap edəndə”.
Yaxşı yanaşma — çapdan əvvəl yükə baxıb həssas sahələri maskalayan mərkəzi loqgerə sahib olmaqdır.
type LogPayload = Record<string, unknown>;
const SENSITIVE_KEYS = ['email', 'phone', 'cardNumber', 'token'];
function scrub(payload: LogPayload): LogPayload {
const result: LogPayload = {};
for (const [key, value] of Object.entries(payload)) {
if (SENSITIVE_KEYS.includes(key)) {
result[key] = '***redacted***';
} else {
result[key] = value;
}
}
return result;
}
export function logEvent(event: string, payload: LogPayload) {
const safe = scrub(payload);
console.log(JSON.stringify({ event, ...safe }));
}
İndi “biz artıq altı aydır müştərilərin telefonlarını və tokenlərini loqlaşdırırıq” kimi production insidentini nə vaxtsa tutmaq əvəzinə, sistemi elə əvvəldən bunun mümkün olmayacağı şəkildə qurursunuz. Bu təkcə dəqiqlik məsələsi deyil, həm də gələcək komplayens tələbləri (GDPR və yerli qanunlar) məsələsidir: loglarda PII nə qədər az olsa, məhsulun həyatı bir o qədər asandır.
5. Agentin monitorinqi və müşahidəolunması
Məhz nəyi görmək lazımdır
Agentin nə edə biləcəyini, hansı məlumatları gördüyünü və loglara nə düşdüyünü məhdudlaşdırdıq. Növbəti sual — bu “zooparkda” agentin prodda məhz düşündüyümüz kimi davrandığını necə anlamaq olar?
Adi “servis canlıdır / deyil” monitorinqi agent üçün demək olar ki, faydasızdır. Bizə yalnız prosesin canlı olduğunu bilmək yetmir, həm də davranışını anlamaq vacibdir: hansı addımları atır, hansı alətləri çağırır, harada səhv edir, harada loop-a düşür.
Hər run üçün minimal məlumat dəsti:
- agent_run_id — işə salmanın unikal identifikatoru;
- anonim user_id və ya sessiya ID-si;
- agent adı və mühit;
- çağırılan alətlərin siyahısı: ad, say, ümumi vaxt;
- workflow addımları və hansı addımda dayandığımız;
- yekun status: success, partial_success, failed, canceled, timeout, limits_exceeded.
Bunu struktur kimi tərtib etmək olar:
type RunStatus =
| 'success'
| 'partial_success'
| 'failed'
| 'canceled'
| 'timeout'
| 'limits_exceeded';
type ToolCallLog = {
name: ToolName;
durationMs: number;
success: boolean;
};
type AgentRunLog = {
runId: string;
agentId: string;
userId: string;
env: Env;
startedAt: string;
finishedAt: string;
status: RunStatus;
toolCalls: ToolCallLog[];
errorMessage?: string;
};
Agentin işə salınması ətrafında “örtük” nümunəsi
Tutaq ki, sizdə real Agents SDK çağırışını kapsulyasiya edən runAgent funksiyası var. Onu monitorinqlə örtək:
async function runAgentWithLogging(
agent: AgentConfig,
input: string,
userId: string,
): Promise<string> {
const runId = crypto.randomUUID();
const startedAt = new Date();
const toolCalls: ToolCallLog[] = [];
try {
const result = await runAgent(agent, input, {
userId,
limits: defaultLimits,
onToolCall: (name, durationMs, success) => {
toolCalls.push({ name, durationMs, success });
},
});
const finishedAt = new Date();
const log: AgentRunLog = {
runId,
agentId: agent.id,
userId,
env,
startedAt: startedAt.toISOString(),
finishedAt: finishedAt.toISOString(),
status: 'success',
toolCalls,
};
logEvent('agent_run', log);
return result;
} catch (err) {
const finishedAt = new Date();
const log: AgentRunLog = {
runId,
agentId: agent.id,
userId,
env,
startedAt: startedAt.toISOString(),
finishedAt: finishedAt.toISOString(),
status: 'failed',
toolCalls,
errorMessage: (err as Error).message,
};
logEvent('agent_run', log);
throw err;
}
}
Burada runAgent — real Agents SDK ilə reallaşdırıla bilən qara qutudur; biz isə konkret API-yə bağlanmadan müşahidəolunmanı necə əlavə etməyi göstəririk.
Loglar vs metriklər vs treysinq
Üç müşahidə səviyyəsini fərqləndirmək rahatdır:
| Səviyyə | Bu nədir | GiftGenius agenti üçün nümunə |
|---|---|---|
| Loglar | Konkret run-lar haqqında “hekayələr” | Addımlar və alətlərlə detallı AgentRunLog |
| Metriklər | Aqreqasiya olunmuş ədədi göstəricilər | Run-un p95 müddəti, orta tool‑call sayı, error‑rate |
| Treysinq | Sorğular və altsorğuların ağacı/qrafı | Run → addımlar → tool‑calls → xarici API çağırışları (commerce, DB və s.) |
Metriklər “ümumiyyətlə hər şey qaydasındadırmı?” sualına cavab üçündür (məsələn, son saat üzrə error‑rate). Loglar və treysinq isə “nəyə görə məhz burada pisdir?” sualını cavablandırmaq və konkret problemli run-u reproduksiya etmək üçündür.
Metriklərin ilkin variantını loglar üzərindən qurmaq olar: periodik tapşırıq agent_run hadisələrini aqreqasiya edir və p95 müddətləri, xəta sayını və s. hesablayır.
6. Bu, GiftGenius-da tam şəkildə necə görünür
Hər şeyin abstraksiyalar məcmusu kimi görünməməsi üçün tədris tətbiqimiz üçün mənzərəni yığaq.
Production mühitində gift-planner agenti yalnız təhlükəsiz alətlərə malikdir: hədiyyə seçimi və detalların alınması. O nə ödənişləri, nə də sifarişlərin idarə edilməsini görür. Onun system təlimatları istifadəçiyə “hər şeyi sizin üçün mən ödəyəcəyəm” deməməsini bildirir; maksimum — tövsiyələr hazırlamaq və bəlkə də hədiyyə siyahısının qaralamasını hazırlamaqdır.
order-manager agenti ayrıca mövcuddur və yalnız sifarişlərlə işləməyi bacarır. Production-da o yalnız sifarişin qaralamasını yarada bilər (create_order_draft), sifarişin təsdiqi (confirm_order) isə ya vidjetdə açıq UI trigeri vasitəsilə insan tərəfindən icra olunur, ya da yalnız dev/staging-də mümkündür. Onun alətləri sirləri (mağazanın API açarları) yalnız backend tərəfində istifadə edir və cavabda yalnız lazım olan sahələri proksi edir.
Hər iki agent runAgentWithLogging örtüyü ilə işə salınır; o isə limitlər tətbiq edir və agent_run_id, userId, mühit və alətlərin siyahısı ilə loglar yazır. Loglarda email və telefon yoxdur; bu sahələr əvvəlcədən skrablanır. İstifadəçi profili anonimizə olunmuş şəkildə istifadə edilir: yaş intervalı, maraqlar, büdcə, lakin alış tarixçəsinin tam mətni yox.
MCP serverinin və agent servisinin yaşadığı infrastruktur izolə olunub: yalnız oxunan fayl sistemi olan konteynerlər (/tmp və ya xüsusi ayrılmış kataloq istisna olmaqla), CPU/RAM məhdudiyyəti, allow‑list domenlər üzrə şəbəkə. Agent qəfil “yad nəsə” çağırmağa cəhd etsə, buna fiziki olaraq çata bilməyəcək.
Hər hansı bir anda “limits_exceeded statuslu run-ların payı” və ya “orta tool‑call sayı > 10” metrikində sıçrayış görsəniz, anlayırsınız ki, ya prompt həddindən artıq “danışqan” olub, ya da alətlərdən biri gicəllənir və agenti addımları yenidən başlatmağa məcbur edir.
Bu artıq “nə olsa olar” eksperimental agent deyil, yetkin bir servis davranışıdır.
7. Agentləri production-a çıxararkən tipik səhvlər
Yuxarıda müzakirə etdiklərimiz “düzgün” production agent mənzərəsidir. Təcrübədə isə çox vaxt tipik “minələr” rast gəlinir. Onları bir siyahıda toplayaq: bu səhvlərdən heç olmasa bir neçəsindən yayınsanız, proda çıxış xeyli sakit keçəcək.
Səhv №1: agenta “hər şeyə icazə verildi”.
Yayğın ssenari: siz bir yığın MCP aləti təsvir etmisiniz (axtarış, dəyişiklik, silmə, ödənişlər) və agenti yaradanda ona sadəcə bütün siyahını vermisiniz. Nəticədə model oxunu istədiyiniz yerdə təsadüfən silmə və ya ödənişi çağıra bilər. Çarəsi alətləri rollara görə bölmək və hər birinin öz allowedTools siyahısı olan bir neçə daha dar agent yaratmaqdır.
Səhv №2: hüquq yoxlanışı yalnız promptda.
Bəzən tərtibatçılar system təlimatlarına yazırlar: “istifadəçinin təsdiqi olmadan heç vaxt heç nə alma” və bununla sakitləşirlər. Amma prompt zəif müdafiədir, jailbreak-lər və sadəcə səhvlər hər zaman mümkündür. Backend səviyyəsində real yoxlamalar lazımdır: “bu alət agent üçün icazəlidirmi?” və “bu alət istifadəçi üçün icazəlidirmi?”, əks halda bir ehtiyatsız generasiya heç kimin gözləmədiyi hərəkətlərə gətirə bilər.
Səhv №3: sirlər promptlarda və loglarda.
Bəzən “inteqrasiyanı sürətləndirmək” istəyib API açarını system prompta qoymaq və ya alət arqumentlərində ötürmək istəyirlər ki, agent özü xarici API-yə getsin. Nəticədə açar həm modelin loqlarında, həm də potensial olaraq kənar sistemlərdə olur. Bu, sızmalara və Store-da ban-a birbaşa yoldur. Sirlər yalnız server tərəfində, mühit dəyişənlərində və ya secret manager-də yaşamalıdır və heç vaxt modelin kontekstinə düşməməlidir.
Səhv №4: skrab olmadan “xam” loglar.
Sazlama zamanı console.log(...) yazmaq rahatdır və sonra unudulur. Bir neçə aydan sonra məlum olur ki, loglarda istifadəçi ünvanları, telefonlar, PII ilə sifariş nömrələri yatıb. Xüsusilə GDPR və başqa tənzimləmələr dünyasında xoş deyil. Daha yaxşısı — dərhal mərkəzi loqger qurmaq və hətta “biz yalnız dev-də loqlaşdırırıq” kimi görünsə belə, həssas sahələrin avtomatik maskalanmasını tətbiq etməkdir.
Səhv №5: agent davranışına limitlərin olmaması.
Addımlara, vaxta və tool çağırışlarının sayına məhdudiyyətlər olmadan agent loop-a düşə bilər: eyni aləti dəfələrlə çağırmaq, eyni səhvi sonsuz düzəltməyə çalışmaq, tonlarla token sərf etmək və xarici API-ləri yükləmək. Yaxşı halda modellər üçün nəhəng hesablar alacaqsınız, pis halda backend-i yıxıb bütün istifadəçiləri əsəbiləşdirəcəksiniz. Run dövrünə limitlər və taymautlar üçün sağlam default-lar — konfiqurasiyanın məcburi hissəsidir.
Səhv №6: read və write əməliyyatlarını bir alətdə qarışdırmaq.
Bəzən getOrCreateOrder kimi “rahat” metodlar yaradırlar, hansı ki, sifariş yoxdursa, yenisini yaradır. Klassik backend üçün bu qəbuledilən pattern ola bilər, amma agentlər dünyasında gözlənilməz yan təsirlərə gətirə bilər: model sadəcə vəziyyəti bilmək istəyirdi, alət isə nəsə yaratdı. get_order_details və create_order_draftı ayırmaq xeyli təhlükəsizdir; belə olduqda hətta təkrar çağırışlarda nəticələr daha idarəolunandır.
Səhv №7: müşahidəolunmanın nəzərə alınmaması.
Bir çoxları “sonra loglar və metriklər qoşarıq, indi əsas odur ki, işləsin” deyə başlayır. Monitorinqsiz agentlər — qara qutudur: hansı alətləri çağırdıqlarını, neçə addım atdıqlarını, harada səhv etdiklərini bilmirsiniz. İstənilən istifadəçi şikayəti qaranlıq otaqda istintaqa çevrilir. Həddən artıq xaotik kodun üzərinə sonradan nəsə tikməyə çalışmaqdan daha asandır elə əvvəlcədən log strukturlarını (agent_run_id, alətlər, status) və baza metriklərini qoymaq.
GO TO FULL VERSION