1. Alət müqavilə kimi: nəyi dəqiq təsvir edirik
Aləti MCP‑serverində qeydiyyatdan keçirəndə, onu kiçik bir obyektlə təsvir edirsiniz. TypeScript‑SDK üçün sadələşdirilmiş struktur belə görünür:
server.registerTool(
"suggest_gifts",
{
title: "Suggest gifts",
description: "Alıcının profilinə görə hədiyyələr seçir.",
inputSchema: {
type: "object",
// indi məhz bu hissəyə dərinləşəcəyik
},
},
async ({ input }) => {
// sizin kodunuz
}
);
Model async emalçısının içində ({ input }) => { ... } nə olduğunu bilmir. Onun üçün cəmi üç şey var:
- name/title — alətin adı.
- description — onu nə vaxt istifadə etmək yerinə düşər.
- inputSchema — hansı arqumentlər və hansı formatda ötürülməlidir.
Bu mühazirədə etdiyimiz hər şey 3‑cü bəndə aiddir (və bir az sonra danışacağımız _meta/annotations metadatasına).
Anlamaq vacibdir: ChatGPT App kontekstində JSON Schema — darıxdırıcı bir validator deyil, model üçün promtun bir hissəsidir. Model sahələrin description hissəsini həqiqətən oxuyur, enum nədir başa düşür, minItems, format və s. kimi məhdudiyyətləri görür.
Yəni siz təkcə backend‑i qırıq məlumatlardan qorumur, həm də SI modelinə funksiyanızı düzgün necə çağırmağı izah edirsiniz.
2. suggest_gifts aləti üçün bazis JSON Schema
Sadədən başlayaq. Tutaq ki, belə bir ssenari var:
İstifadəçi yazır:
“25 yaşlı qardaş üçün hədiyyə seç, büdcə 50–70 dollar, videooyunları və stolüstü oyunları sevir”.
suggest_gifts aləti təxminən belə arqumentlər qəbul etməlidir:
- hədiyyə alanın yaşı;
- münasibət növü (qardaş, həmkar, tərəfdaş və s.);
- minimal və maksimal büdcə;
- maraq siyahısı.
Bunu Zod olmadan, “birbaşa” JSON Schema kimi, təmiz obyektlə təsvir edək:
const suggestGiftsInputSchema = {
type: "object",
properties: {
age: {
type: "integer",
minimum: 0,
maximum: 120,
description: "Hədiyyə alanın yaşı (illərlə).",
},
relationship: {
type: "string",
enum: ["friend", "partner", "sibling", "colleague", "parent"],
description:
"Münasibət növü: friend, partner, sibling (qardaş/bacı), colleague, parent.",
},
minBudget: {
type: "number",
minimum: 0,
description: "İstifadəçinin valyutasında minimal büdcə.",
},
maxBudget: {
type: "number",
minimum: 0,
description: "İstifadəçinin valyutasında maksimal büdcə.",
},
interests: {
type: "array",
items: {
type: "string",
description:
"Maraq üçün qısa ad, məsələn: videogames, boardgames, books.",
},
minItems: 1,
description: "Hədiyyə alanın maraqlarının siyahısı.",
},
},
required: ["relationship", "maxBudget"],
};
Burada dərhal qeyd etməyə dəyən bir neçə vacib məqam.
Birincisi, sahələrin description hissəsi. Adi API‑də onları yazmaya da bilərsiniz — frontend tərtibatçısı Swagger‑i oxuyub anlayar. Amma burada “müştəri” — mənanı ad və təsvirlərdən çıxarmağa çalışan modeldir. Nə qədər aydın desəniz: “yaş illərlə”, “məbləğ istifadəçinin valyutasındadır”, “enum sabit dəyərlərlədir” — bir o qədər az qəribə arqumentlər görəcəksiniz.
İkincisi, enum — modeli idarə etməyin ən güclü alətlərindən biridir. Əgər modelə relationship sahəsinə istənilən sətir yazmağa icazə versəniz, “bro”, “girlfriend”, “bestie”, “teammate” və daha “yaradıcı” bir şeylər görəcəksiniz. Əgər enum təyin etsəniz, model çox böyük ehtimalla yalnız bu dəyərlərdən seçim edəcək. Bu, arqumentlərdə “hallüsinasiyaların” sayını birbaşa azaldır.
Üçüncüsü, hər şeyi mütləq required etmək lazım deyil. Məsələn, age optional ola bilər: əgər istifadəçi onu göstərməyibsə, təsviri elə qurduğunuz halda model havadan “təxmini yaş” uydurmayacaq. Burada incə sənət başlayır: elastikliklə sərtlik arasında balans.
İndi bu sxemadan alətin qeydiyyatında istifadə edək:
server.registerTool(
"suggest_gifts",
{
title: "Suggest gifts",
description:
"Büdcəyə, münasibət növünə və hədiyyə alanın maraqlarına görə hədiyyə ideyaları seçir.",
inputSchema: suggestGiftsInputSchema,
},
async ({ input }) => {
// burada input artıq təxminən sxemə uyğundur
// ...
}
);
Belə “əl ilə” obyekt sürətli eksperimentlər üçün uyğundur. Lakin tətbiq böyüdükcə o, TypeScript tiplərinizlə asanlıqla uyğunsuzluğa düşən ayrıca bir dünyaya çevrilir. Bir qədər sonra bu problemi Zod və tiplərdən JSON Schema generasiyası ilə necə həll edəcəyimizə baxacağıq.
3. JSON Schema prompt kimi: description necə yazmalı ki, model əziyyət çəkməsin
Formal olaraq JSON Schema — validasiya haqqındadır. Qeyri‑formal olaraq, LLM dünyasında — həm də strukturlaşdırılmış promtdur. Bir neçə praktik qayda:
- Sahə description “bura nə qoymalı və hansı formatda” sualına cavab verməlidir.
“Tarix” kimi ifadə kömək etmir. “YYYY-MM-DD formatında ISO 8601 tarix, məsələn "2025-02-14"” — çox kömək edir. - Sahə pulla bağlıdırsa — vahidləri dəqiqləşdirin.
“Məbləğ istifadəçinin valyutasındadır” və ya “Məbləğ ABŞ dolları ilədir” kimi açıq yazmaq daha yaxşıdır. Əks halda model səmimi‑qəlbdən 50 yaza bilər və siz bunun 50 yen, yoxsa 50 avro olduğunu təxmin edəcəksiniz. - Sətir “kateqoriyaları” demək olar ki, həmişə enum ilə daha yaxşıdır.
Əgər sahə “kateqoriya” olan sətirdirsə, enum etmək və hər dəyəri alətin description hissəsində izah etmək daha yaxşıdır. Məsələn, relationship üçün alətin təsvirində belə yaza bilərsiniz: “relationship: bunlardan biri — friend (dost), partner (romantik tərəfdaş), sibling (qardaş və ya bacı), colleague (iş yoldaşı), parent (valideyn). Başqa dəyərlər uydurma.” - Massivlər üçün minItems təyin etmək və bunun nə siyahısı olduğunu izah etmək faydalıdır.
Əgər sahə massivdirsə, minItems göstərmək və bunun məhz nə siyahısı olduğunu qısa izah etmək faydalıdır. Məsələn, interests — “nəsə bədii təsvir” deyil, “qısa teqlər toplusudur”.
Bunlar bir az yorucu səslənsə də, praktikada “təsvirlər var” və “təsvirlər yoxdur” arasındakı fərq sabit tətbiqlə modelin bu gün nə göndərəcəyinin lotereyası arasında fərqdir.
Insight
MCP alətlərinin ölçü üzrə sərt limitləri var — və məhz onlar ən çox “mistik” çökmələrin, qəribə xətaların və assistentin qəfil sizin alətləri görməməsinin səbəbinə çevrilir.
Əsas qayda sadədir: alət tam olaraq ~4 KB JSON‑a sığmalıdır. Bu təkcə description mətni deyil, bütün strukturdur:
- alətin təsviri,
- arqumentlərin sxemi (inputSchema),
- daxili obyektlər və enum,
- _meta və annotasiyalar.
Alətiniz böyüdükcə, platforma qeyri‑proqnozlaşdırıla bilən cür davranmağa başlayır: "Tool description is too long", "Schema validation failed", "Manifest exceeds size limits" kimi xətalar görünür, bəzən isə ChatGPT sadəcə aləti yükləmir və ya onun mövcudluğunu “unudur”.
Tövsiyə: description-u 1000–2000 simvol daxilində saxlayın, bütün aləti isə “təhlükəsiz” ~4 KB həddində. Əgər təsvir həddən artıq uzanırsa, bu, demək olar ki, həmişə alətin birdən çox işi eyni anda gördüyünün əlamətidir. Ayrı alətlər daha dar və son dərəcə dəqiq olmalıdır — model onların sərhədlərini daha etibarlı anlayır və giriş məlumatlarında daha az səhv edir.
4. TypeScript və Zod: iki əvəzinə tək həqiqət mənbəyi
JSON‑sxemi əl ilə yazmaq TypeScript tərtibatçısı üçün ağrılıdır. Paralel iki dünya saxlamaq lazım gəlir:
- TS kodunda tiplər;
- model üçün JSON Schema.
Tətbiq böyüdükcə onlar ayrılmağa başlayır. Bu gün TypeScript tipində sahəni dəyişdiniz, sabah sxemi yeniləməyi unutdunuz — və bir həftə sonra prodda düşməni tutursunuz.
De‑fakto standart yanaşma TS dünyasında — Zod istifadə etmək və Zod‑dan -> JSON Schema konvertasiya etməkdir.
Asılılıqları quraşdıraq (hələ yoxdursa):
npm install zod zod-to-json-schema
suggest_gifts üçün giriş sxemini Zod ilə təsvir edək:
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const SuggestGiftsInputZod = z.object({
age: z
.number()
.int()
.min(0)
.max(120)
.describe("Hədiyyə alanın yaşı (illərlə)."),
relationship: z
.enum(["friend", "partner", "sibling", "colleague", "parent"])
.describe(
"Münasibət növü: friend (dost), partner (tərəfdaş), sibling (qardaş/bacı), colleague (həmkar), parent (valideyn)."
),
minBudget: z
.number()
.min(0)
.optional()
.describe("İstifadəçinin valyutasında minimal büdcə."),
maxBudget: z
.number()
.min(0)
.describe("İstifadəçinin valyutasında maksimal büdcə."),
interests: z
.array(
z
.string()
.min(1)
.describe(
"Qısa maraq teqi, məsələn: videogames, boardgames, books."
)
)
.min(1)
.describe("Hədiyyə alanın maraqlarının siyahısı."),
});
Artıq sizdə var:
- Runtime‑validasiya: SuggestGiftsInputZod.parse(input);
- TypeScript tipi: type SuggestGiftsInput = z.infer<typeof SuggestGiftsInputZod>;
- Model üçün JSON Schema: zodToJsonSchema(SuggestGiftsInputZod).
Bunu alətin qeydiyyatında istifadə edək:
type SuggestGiftsInput = z.infer<typeof SuggestGiftsInputZod>;
const suggestGiftsInputSchemaJson = zodToJsonSchema(
SuggestGiftsInputZod,
"SuggestGiftsInput"
);
server.registerTool(
"suggest_gifts",
{
title: "Suggest gifts",
description:
"Büdcəyə, münasibət növünə və hədiyyə alanın maraqlarına görə hədiyyə ideyaları seçir.",
inputSchema: suggestGiftsInputSchemaJson,
},
async ({ input }) => {
// burada input-u əlavə olaraq Zod ilə yoxlamaq olar:
const args = SuggestGiftsInputZod.parse(input) as SuggestGiftsInput;
// sonra tipləndirilmiş args ilə işləyirik
}
);
Bu yanaşma sizə həmin single source of truth — tək həqiqət mənbəyini verir: sxemi bir dəfə təsvir edirsiniz, TypeScript tipi və JSON Schema isə avtomatik generasiya olunur.
Reallıqda siz üstünə testlər də əlavə edəcəksiniz ki, zodToJsonSchema gözlənilən strukturu versin, amma bu artıq testlərlə bağlı modulun mövzusudur.
Insight: ChatGPT optional parametrlərlə pis işləyir
Prodda ən ağrılı təcrübələrdən biri: alət sxemələrində optional sahələrdən fəal istifadə etməyə başlayan kimi, tool‑call keyfiyyəti nəzərəçarpacaq dərəcədə düşür. Model nəzəriyyədə optional parametrin nə olduğunu “başadır”, amma praktikada çox vaxt onları ümumiyyətlə göndərmir — hətta biznes‑məntiq üzrə sizə çox lazım olanda belə.
Bu problem Response API‑də zərif şəkildə həll edilib: orada optional sahələr sadəcə çıxarılıb — alətin bütün parametrləri required kimi elan olunmalıdır. Amma problem yox olmur: “sahələrin yarısını optional qoyaram, model özü qərar verər” ideyası reallıqla toqquşur: adətən heç nə göndərmir.
5. “Sxema” harada bitir və “interfeys dizaynı” harada başlayır
İndiyə qədər biz daim inputSchema haqqında danışdıq — yəni aləti işə salmaq üçün modelin hansı arqumentləri generasiya etməli olduğunu. Amma alət çağırıldıqdan sonra həyat bitmir: nəticəni UI‑da göstərmək lazımdır.
Burada iki səviyyəni ayırmaq faydalıdır:
- Sxema alət üçün modelin generasiya etməli olduğu giriş arqumentlərini təsvir edir. Bu, MCP / tool‑call məkanında yaşayan JSON‑dur.
- UI komponenti (vidcet) toolOutput.structuredContent oxuyur və onun əsasında interfeys qurur. structuredContent formatını da özünüz layihələndirirsiniz, amma bu artıq model üçün JSON Schema deyil (baxmayaraq ki, özünüz üçün bunu da formallaşdıra bilərsiniz).
Bəzən tərtibatçılar bir JSON obyektlə iki dovşanı vurmağa çalışırlar — həm model girişlərini, həm də UI üçün məlumat formatını birləşdirmək. Bu nadir hallarda yaxşı bitir. Daha rahat olanı ayırmaqdır:
- inputSchema — modelin aləti işə salmaq üçün nəyə ehtiyac duyduğuna aiddir;
- structuredContent — UI‑ın nəticəni necə çəkməsinə aiddir.
Məsələn, inputSchema suggest_gifts üçün heç bir id saxlamır. Amma structuredContent əksinə — id, title, price, alış linki və s. olan kartların siyahısını saxlayır.
6. Annotasiyalar və _meta: UX və təhlükəsizliyə necə təsir etmək olar
Parametr sxeması və cavab strukturu ilə yanaşı daha bir qat var — platformanın alətə necə yanaşması və onu istifadəçiyə necə göstərməsi. Buna metadatalar və annotasiyalar cavabdehdir.
Standart title, description, inputSchema sahələrindən əlavə, alətin əlavə metadataları və annotasiyaları ola bilər. Apps SDK və MCP‑də bunların bir hissəsi _meta-da (məsələn, securitySchemes) yaşayır, başqa bir hissəsi isə OpenAI‑yə xas ipucları kimi xüsusi sahələrdə — readOnlyHint və destructiveHint.
Burada anlamaq vacibdir: bu annotasiyalar JSON Schema‑nı dəyişmir, amma ChatGPT‑nin aləti istifadəçiyə necə göstərməsinə və çağırışa necə yanaşmasına təsir edir.
Nümunə: readOnlyHint və destructiveHint
Tutaq ki, iki alətiniz var:
- list_gifts — sadəcə hədiyyələrin siyahısını almaq (təhlükəsiz);
- create_order — sifariş yaratmaq (potensial təhlükəli: pul, ünvan, məsələ ciddidir).
Onları təxminən belə nişanlaya bilərsiniz (psevdo‑kod):
server.registerTool(
"list_gifts",
{
title: "List gift suggestions",
description: "Verilən filtrlərə görə mövcud hədiyyələrin siyahısını alır.",
inputSchema: listGiftsInputSchema,
_meta: {
readOnlyHint: true,
},
},
async ({ input }) => { /* ... */ }
);
server.registerTool(
"create_order",
{
title: "Create gift order",
description:
"İstifadəçi adından konkret hədiyyə üçün sifariş yaradır. Yalnız açıq təsdiqdən sonra istifadə et.",
inputSchema: createOrderInputSchema,
_meta: {
destructiveHint: true,
},
},
async ({ input }) => { /* ... */ }
);
Semantika belədir. readOnlyHint ChatGPT‑yə alətin heç nəyi dəyişmədiyini və təhlükəsiz olduğunu siqnal verir; model və UI onu daha sərbəst çağıra bilər. destructiveHint alətin geri dönməyən və ya kritik hərəkətlər etdiyini bildirir, buna görə istifadəçidən daha tez‑tez təsdiqlər istəniləcək və model daha ehtiyatlı olacaq.
Sizin Gift tətbiqinizdə suggest_gifts açıq‑aşkar read‑only‑dir, sifariş tərtibi, vəsaitin çıxılması və istifadəçi məlumatlarının dəyişdirilməsi alətləri isə potensial destructive kimi nişanlanmalıdır.
openWorldHint və oxşar sahələr
Bəzi hallarda modelə alətin “açıq dünyada” işlədiyini, yəni nəticələrinin əhatəli olmadığını demək istəyirsiniz. Məsələn, search_products heç vaxt dünyada mövcud bütün malları qaytarmayacaq, yalnız aid olanları qaytaracaq.
Belə annotasiyalar modelə “əgər məhsul search_products‑da tapılmırsa, deməli o yoxdur” kimi güclü nəticələr çıxarmamağa kömək edir. Bu incə UX məqamıdır, amma prodakşn tətbiqlərdə fərqi yaxşı hiss olunur.
UI göstərilişi ətrafında _meta
Alətiniz nəticə qaytardıqda, _meta-da vidcetə təsir edən parametrləri əlavə göstərə bilərsiniz. Məsələn: hansı HTML şablondan output‑template kimi istifadə olunacaq, çərçivələr lazımdırmı, çağırış zamanı hansı yazı göstəriləcək və s.
Məsələn, rəsmi nümunədə server vidcetin HTML‑ini ayrıca MCP resursu kimi qeydiyyatdan keçirir və sonra ona _meta["openai/outputTemplate"] vasitəsilə istinad edir.
server.registerTool(
"suggest_gifts",
{
title: "Suggest gifts",
description: "Hədiyyə ideyaları seçir.",
inputSchema: suggestGiftsInputSchemaJson,
_meta: {
"openai/outputTemplate": "ui://widget/gifts.html", // Bu MCP resursunun id‑sidir: server.registerResource(...)
"openai/toolInvocation/invoking": "Hədiyyələri seçirəm…", // Axtarış prosesində göstərilir
"openai/toolInvocation/invoked": "Hədiyyə variantlarını tapdım", // Axtarış bitəndə göstərilir
},
},
async ({ input }) => {
// ...
return {
content: [],
structuredContent: { items: gifts },
};
}
);
Beləliklə, bir yerdə aşağıdakıları təsvir edirsiniz:
- model üçün giriş məlumatlarının formasını (inputSchema);
- alətin UI‑da necə görünəcəyini və davranacağını (_meta).
7. Sxem dizaynı: modeldən nə istəmək olar, nəyi isə yox
Tipik tələlərdən biri — bütün işi modelin üzərinə atmağa cəhd etməkdir. Məsələn, inputSchema-da giftId sahəsini təsvir edir və description-da yazırsınız: “bazamızda hədiyyənin UUID‑i”. Model əlbəttə "0f21b5f0-5a3a-4d1b-8f0b-9f1a6e3c1234"‑a bənzər UUID generasiya etməyə çalışacaq, amma problem ondadır ki, çox güman, sizdə belə bir hədiyyə mövcud deyil.
Yaxşı qayda: modeldən daxili dünyanıza bağlı texniki identifikatorlar və məlumatlar generasiya etməsini istəməyin.
Bunun əvəzinə çoxmərhələli ssenari qurmaq daha düzgündür:
- suggest_gifts id, title, price və s. ilə hədiyyələrin siyahısını qaytarır;
- UI/model istifadəçiyə təklif edilən variantlardan birini seçməyə imkan verir;
- create_order artıq mövcud dəstdən giftId qəbul edir.
Sxemlər baxımından bu o deməkdir ki:
- “Çölə” (istifadəçiyə) baxan alətlərin inputSchema-sı yalnız insanın məntiqli şəkildə daxil edə biləcəyi şeyləri təsvir edir: axtarış parametrləri, filtrlər, meyarlar;
- Daxili entitilərlə işləyən alətlərin inputSchema-sı artıq məlum olan id-lərə istinad edir və modeldən onları uydurmağı tələb etmir.
Sizin Gift tətbiqiniz üçün bu o deməkdir ki, suggest_gifts-də modeldən “SKU kodunu uydurmağı” istəmirsiniz, yalnız sorğunun parametrlərini. SKU‑ları backend tərəfdə bağlayacaqsınız, UI isə onları istifadəçiyə göstərəcək.
Qeyd: SKU — beynəlxalq unikal məhsul kodudur. Nümunə "GFT-CHC-500-BS".
8. Kiçik praktik blok: hamısını bir yerdə toplayaq
Gəlin yuxarıda danışdıqlarımızı bir yerdə toplayaq: Zod‑sxem, JSON Schema generasiyası, _meta ilə alətin qeydiyyatı və biznes‑məntiqdə sxemdən istifadə. Gift tətbiqi üçün minimal, amma əlaqəli bir nümunə yığaq.
Əvvəlcə Zod‑sxem və tip:
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const SuggestGiftsInputZod = z.object({
relationship: z
.enum(["friend", "partner", "sibling", "colleague", "parent"])
.describe("Hədiyyə alanla münasibət növü."),
maxBudget: z
.number()
.min(0)
.describe("İstifadəçinin valyutasında maksimal büdcə."),
interests: z
.array(
z
.string()
.min(1)
.describe("Qısa maraq teqi, məsələn: videogames.")
)
.min(1)
.describe("Hədiyyə alanın maraqlarının siyahısı."),
});
type SuggestGiftsInput = z.infer<typeof SuggestGiftsInputZod>;
const suggestGiftsInputSchemaJson = zodToJsonSchema(
SuggestGiftsInputZod,
"SuggestGiftsInput"
);
Daha sonra — UI üçün _meta ilə alətin qeydiyyatı:
server.registerTool(
"suggest_gifts",
{
title: "Suggest gifts",
description:
"Büdcə, münasibətlər və maraqlar üzrə hədiyyə ideyaları seçmək lazım olanda istifadə et.",
inputSchema: suggestGiftsInputSchemaJson,
_meta: {
"openai/outputTemplate": "ui://widget/gifts.html",
"openai/toolInvocation/invoking": "Hədiyyələri seçirəm…",
"openai/toolInvocation/invoked": "Hədiyyə variantlarını tapdım",
readOnlyHint: true,
},
},
async ({ input }) => {
const args = SuggestGiftsInputZod.parse(input) as SuggestGiftsInput;
const gifts = await findGifts(args); // sizin biznes‑məntiqiniz
return {
content: [],
structuredContent: {
items: gifts,
},
};
}
);
Yaxınlıqda tipli biznes funksiyanız olacaq:
async function findGifts(input: SuggestGiftsInput) {
// burada input.relationship, input.maxBudget, input.interests istifadə edə bilərsiniz
// və Gift tipində obyektlərdən ibarət massiv qaytarın
return [
{
id: "gift-1",
title: "Videooyun mövzulu stolüstü oyun",
price: 45,
currency: "USD",
},
];
}
Vidxet tərəfində sonra window.openai.toolOutput.structuredContent.items götürüb kartları çəkəcəksiniz, amma bunun haqqında ətraflı bir neçə mühazirə sonra danışacağıq.
9. Alətləri təsvir edərkən tipik səhvlər
Səhv №1: Sahələrin həddən artıq ümumi və ya mənasız təsvirləri.
Əgər description: "Tarix" və ya description: "Filtr parametri" yazırsınızsa, model təxminən sıfır faydalı məlumat alır. Bu, “metod vacib bir iş görür” tipli sənədləşdirmə kimidir. “Bura nə qoymalı” və “hansı formatda” suallarına cavab verən təsvirlərdən istifadə edin. Məsələn: “YYYY-MM-DD formatında ISO 8601 tarix, məsələn "2025-02-14"” və ya “İstifadəçinin valyutasında məbləğ, nümunə: 49.99”.
Səhv №2: Enum‑u tələb olunduğu yerdə qoymamaq.
Tez‑tez tərtibatçılar sətirləri enum-a çevirməyə “tənbəllik edir” və type: "string" saxlayırlar. Nəticədə model öz dəyərlərini uydurur, backend təəccüblənir, UI sınır. Əgər sabit seçimlər dəstiniz varsa (relationship, status tipləri, sortlama üsulları) — demək olar ki, həmişə enum etmək və mümkün dəyərləri sadalamaq mənalıdır. Bu, tool‑call‑ların proqnozlaşdırılmasını xeyli artırır.
Səhv №3: Sxem və tiplər üçün iki həqiqət mənbəyi.
Klassika: TypeScript‑də maxBudget sahəsini priceMax ilə əvəz edirsiniz, JSON Schema‑da isə unutursunuz. Model hələ də maxBudget göndərir, kod isə priceMax gözləyir — hər şey dayanır. Belə səhvlər çox vaxt prodda üzə çıxır. Ona görə başlanğıcdan Zod və ya oxşar alət istifadə etmək daha yaxşıdır ki, həm tip, həm də JSON Schema eyni deklarasiyadan generasiya olunsun.
Səhv №4: Modeldən daxili identifikatorları generasiya etməsini istəmək.
userId, giftId, orderId kimi sahələri “sistemimizdə istifadəçinin UUID‑i” kimi təsvir etsəniz, model labüd şəkildə uydurma dəyərlərlə dolduracaq. Hətta pattern ilə UUID üçün şablon versəniz belə, model sadəcə “düzgün görünən” UUID‑lər generasiya edəcək, amma heç nəyə uyğun gəlməyəcək. Belə sahələri modeldən istəməkdənsə, kontekstdən (autentifikasiya, əvvəlki tool‑call) backend‑də doldurmaq daha yaxşıdır.
Səhv №5: Hər şey üçün “ilahəvi” nəhəng sxemlər.
Bəzən do_everything adlı tək bir alət yaratmaq istəyirsiniz: nəhəng obyekt, sahələrin yarısı nullable, yarısı optional. Model bu suda boğulur. Funksionallığı bir neçə daha dar və anlaşılan alətə bölmək daha yaxşıdır: biri hədiyyə axtarışına cavabdehdir, digəri konkret hədiyyənin detallarına, üçüncüsü sifarişin yaradılmasına.
Səhv №6: _meta və annotasiyaları görməzdən gəlmək.
Bir çox tərtibatçı name, description və inputSchema ilə kifayətlənir, _meta sahələri kimi openai/outputTemplate və destructiveHint kimi hintləri qaçırır. Nəticədə “səssizcə” təhlükəli əməliyyatlar edən alətlər UI‑da ipucları və təsdiqlərlə müşayiət olunmur. Bu, istifadəçi etibarını azaldır və gözlənilməz əməliyyatlar riskini yaradır. Annotasiyalardan istifadə edin ki, read‑only və təhlükəli alətləri açıq nişanlayasınız, həmçinin yerinə yetirmə statuslarını dostyana şəkildə göstərə biləsiniz.
Səhv №7: Server tərəfində girişin validasiyasının olmaması.
JSON Schema və Zod hər şeyi təsvir etsə belə, yalnız modelə güvənmək risklidir. Bəzən model qismən valid məlumat verir və ya siz özünüz sxemi dəyişdirir, biznes məhdudiyyətləri unudursunuz. Emalçını try { parse } catch { ... } ilə bükmək — modelə arqumentləri düzəltmək şansı, sizə isə uğursuz bir tool‑call üzündən bütün servisi yıxmamaq imkanı verir.
GO TO FULL VERSION