1. Workflow konteksti nədir və niyə ümumiyyətlə lazımdır
Adi veb‑tətbiqdə vəziyyətin harada saxlandığı barədə kifayət qədər aydın təsəvvür var: verilənlər bazası, keş, üstəlik front tərəfdə Redux və ya lokal React‑state kimi nələrsə. ChatGPT App‑də isə hər şey daha maraqlıdır: vəziyyət eyni anda üç dünyaya yayılıb — modelin daxilində (dialoq tarixi), vidjetin daxilində (UI‑state) və sizin serverinizdə/MCP‑də (biznes məlumatları).
Workflow konteksti dedikdə “hazırda hansı addımdayıq” və “artıq nə bilinir” suallarına cavab vermək üçün lazım olan bütün məlumatları nəzərdə tutacağıq. Tədris üçün seçdiyimiz GiftGenius nümunəsində kontekstə daxildir:
- hədiyyə alıcısının profili: yaş, cins, maraqlar;
- büdcə və bəlkə də valyuta;
- yaradılmış ideyaların siyahısı və istifadəçinin hansıları bəyəndiyi və ya gizlətdiyi;
- texniki şeylər: sessiya və ya workflow identifikatoru, status («profile_collected», «ideas_shown», «checkout_started»).
Bu kontekst təkcə backend‑mühəndis kimi sizə lazım deyil. O, modelin özünə də lazımdır ki, hansı sualların artıq verildiyini, hansı alətlərin çağırıldığını və ümumiyyətlə indi nə barədə danışıldığını anlasın. Və o, istifadəçiyə də lazımdır ki, çata qayıdanda hər şeyi sıfırdan başlamasın.
İstifadəçi intuisiya ilə “ChatGPT hər şeyi xatırlayır” kimi düşünür. Əslində model yalnız dialoqun mətnini və o da kontekst pəncərəsinə sığdığı müddətdə xatırlayır. order_id, cart_id kimi strukturlu şeylər və ya “bəyənilmiş ideyaların siyahısı” isə sizin serverdə saxlanmalıdır, əks halda UI‑də inamlı, amma səhv bəyanatlar yaradan mükəmməl bir maşın əldə edəcəksiniz.
2. Vəziyyətin üç səviyyəsi: UI, LLM, biznes
Kontekstin saxlanılmasını ən rahat üç state qatının modeli ilə başa düşmək olur. Buna da “State Triad” deyək.
Səviyyələr cədvəli
Kiçik bir cədvəldən istifadə edək:
| Səviyyə | Harada yaşayır | Ömür dövrü | Nəyə cavabdehdir | GiftGenius misalı |
|---|---|---|---|---|
| UI State | Vidjet (React, widgetState) | Çat/vidjetli mesaj açıq olduğu müddətcə | Vizual vəziyyət, lokal daxil etmə | Hansı kartlar vurğulanıb, formanın vəziyyəti |
| LLM Context | OpenAI‑də çat tarixçəsi | Mesaj kontekstə “sığdığı” müddətcə | Dialoqu anlama və məntiq yürütmə | «Anaya hədiyyə axtarırıq, büdcə $50» |
| Business State | MCP / sizin backend (VB/Redis) | İstədiyiniz qədər (davamlı) | Həqiqət: yoxlanmış məlumatlar, statuslar | { step: "ideas", budget: 50, liked: [42, 51] } |
UI qatı sürətli və çevikdir, amma çox kövrəkdir: siz tarixçədə yuxarı sürüşəndə ChatGPT vidjetli iframe‑i “unmount” edə bilər, sonra isə yenidən “mount” edə bilər. Məhz buna görə widgetState var — o, React komponentindən bir qədər uzun yaşayır və ChatGPT host‑klienti ilə sinxronlaşır.
LLM qatı modelə fasiləsiz dialoq hissini verir, amma yalnız mətn və tool çağırışlarını saxlayır. Oraya səbətinizi JSON kimi “qoya” bilərsiniz, lakin bu əslində sadəcə JSON‑u mətnə yapışdırmaqdır — model buna verilənlər bazası kimi yanaşmayacaq.
Biznes qatı — mühəndis kimi sizin nəzarət edə bildiyiniz yerdir: orada validasiya olunmuş məlumatlar, indekslər, sifariş statusları saxlanılır. Ciddi ssenari (hədiyyələr, bron etmə, təhsil) yaranan kimi vəziyyətin əsas həqiqət mənbəyi məhz bu qat olmalıdır.
Əsas mühəndislik problemi — bu üç qatın müxtəlif istiqamətlərə “sürüşməməsidir”. İstifadəçi vidjetdə büdcəni dəyişdi, model hələ də köhnə büdcəni düşünür, bazada isə üçüncü dəyər var — bu, qəribə davranış üçün klassik reseptdir.
3. Dəqiq nəyi saxlayırıq: WorkflowContext strukturu
Mövzunu konkretləşdirmək üçün GiftGenius üçün TypeScript‑də kontekst interfeysini təsvir edək. Tutaq ki, bizdə artıq bir neçə addım var: profilin toplanması, büdcənin seçilməsi, ideyaların generasiyası və baxış/bəyənmə.
Sadə bir strukturlə başlayaq:
// backend/types/workflow.ts
export type GiftWorkflowStep =
| "profile"
| "budget"
| "ideas"
| "checkout";
export interface GiftWorkflowContext {
id: string; // workflowId — ssenarinin identifikatoru
userId?: string; // artıq autentifikasiya qurulubsa
currentStep: GiftWorkflowStep;
profile?: {
age?: number;
gender?: string;
interests?: string[];
};
budget?: {
min?: number;
max?: number;
currency: string;
};
ideas?: {
id: string;
title: string;
}[];
likedIdeaIds: string[];
hiddenIdeaIds: string[];
updatedAt: number; // TTL/təmizləmə üçün timestamp
}
Bu hələ son sxem deyil, amma vacib elementlər artıq yerindədir. Var:
- workflow identifikatoru, bu identifikator üzrə konteksti tapacağıq;
- həm vidjetə, həm də modelə hara çatdığımızı anlamağa kömək edəcək cari addım;
- ayrı‑ayrı addımlarda doldurulacaq sahələr toplusu;
- yenilənmə vaxtı kimi xidmət sahələri.
İdentifikatorlar barədə ayrıca. Bu mühazirədə workflowId dedikdə backend/MCP daxilində konkret ssenarinin identifikatoru nəzərdə tutulur. O, ChatGPT dialoq sessiyasının identifikatoru ilə (sessionId) üst‑üstə düşə bilər, lakin buna güvənmirik. userId — sizin autentifikasiya sisteminizdəki istifadəçi identifikatorudur (əgər varsa); bir istifadəçinin bir neçə aktiv workflow‑u ola bilər. id sahəsində isə məhz həmin workflowId saxlanılır, biz də bu identifikatorla konteksti axtarıb yeniləyirik.
Növbəti bölmələrdə üç şeyi müzakirə edəcəyik: belə obyektləri harada saxlamaq, onları ora necə yazmaq və sonra necə geri çıxarmaq — həm vidjetə, həm də modelə.
4. Harada vəziyyəti saxlamaq: variantlar və kompromislər
Vəziyyətin saxlanması barədə iki müstəvidə düşünmək rahatdır: o harada saxlanılır və nə qədər yaşayır. Bu bölmədə məkan məsələsinə fokuslanacağıq, ömür müddətlərinə isə check‑list və tipik səhvlər blokunda qayıdacağıq.
Öncə saxlanma yerini anlayaq.
Dialoqun daxilində (promptda)
Bəzən demək istəyirsən: “Gəlin hər dəfə modelə cari vəziyyətin JSON‑unu qaytaraq, qoy özü başa düşsün”. Bu, çox sadə ssenarilər və qısa addım zəncirləri üçün işləyir, amma tez iki problemə dirənir: kontekst uzunluğu məhdudiyyəti və məlumat bütövlüyünə zəmanətlərin olmaması.
Bundan əlavə, MCP protokolu təbiəti etibarilə stateless‑dir: HTTP kimi, o, standart olaraq sorğular arasında vəziyyət saxlamır. Alət çağırışını konkret sessiyaya bağlamaq üçün siz açıq şəkildə identifikatoru — workflow və ya session id — ya alətin arqumentlərində, ya da metadata/headerlər vasitəsilə ötürməlisiniz.
Ona görə də biznes vəziyyətini yalnız dialoqda saxlamaq daha çox tədris eksperimenti, nəinki arxitekturdur.
Vidjetdə: UI + widgetState
UI səviyyəsində adi React‑state‑dən (useState, useReducer və s.) istifadə edirik, amma qeyd olunduğu kimi komponent unmount ola bilər. Apps SDK‑da bunun üçün React‑dən kənarda yaşayan və ChatGPT hostu ilə sinxronlaşan widgetState mexanizmi var. Vidjet mount olunanda ordan saxlanmış dəyəri çıxarırsınız, dəyişikliklərdə isə geri qoyursunuz — beləliklə, lokal, amma kifayət qədər rahat bir yaddaş əldə edirsiniz.
Bu yaddaş sırf vizual state üçün əladır: hansı kartlar hazırda yığılıb, hansı tabdəsiniz, istifadəçi “İrəli” düyməsini basmazdan əvvəl formaya nə daxil edib. Amma serverin yerini vermir: istifadəçi başqa cihazdan və ya bir həftə sonra çatı açan kimi widgetState artıq kömək etməyə bilər. Üstəlik, onun üzərində biznes məntiqi qurmaq da mübahisəlidir.
Serverdə/MCP: Map, Redis, VB
Nəhayət, prod üçün əsas işçi variant: GiftWorkflowContext‑i MCP server və ya backend servis tərəfində saxlayırıq. MCP müştərisi və serveri protokol üzrə stateless olduğundan hər alət çağırışında hansı konteksti yeniləməli olduğumuzu anlamaq üçün workflowId (və ya state_token) ötürməliyik.
Reallaşdırma üçün bir neçə variant var:
- Node.js‑də yaddaşdaxili Map — demo və dev mühitləri üçün uyğundur: hər şey sürətlidir, amma restartda itir;
- TTL‑li Redis və ya başqa yaddaşdaxili keş — qısa wizard ssenariləri üçün yaxşıdır (bir neçə addımdan ibarət ustadlar): bir‑iki saat yaşayır, sonra silmək olar;
- adi SQL/NoSQL bazası — “bir həftə sonra qayıtdı” və ya “qaralamalar və səbətlər” kimi ssenarilər üçün mütləqdir.
Bu mühazirədə konkret verilənlər bazasına dərindən girməyəcəyik, interfeysə və ora nəyin düşməli olduğuna fokuslanacağıq.
5. MCP serverində ən sadə storage: workflowId üzrə Map
Biraz daha yerə yaxın nədənsə başlayaq: MCP serverində yaddaşdaxili Map, burada açar — workflowId. Tədris demosunda onu dialoqun sessionId‑sinə bərabər tutmaq olar, amma prod‑da workflowId ssenarinin ayrıca identifikatoru kimi saxlanmalıdır. Həmin Map‑də dəyər GiftWorkflowContext olacaq. Real prod‑da bunu Redis və ya VB ilə əvəz edəcəksiniz, amma API eyni qalacaq.
Tutaq ki, MCP serverimiz TypeScript‑dədir. İlkləndirməyə yaxın yerə əlavə edək:
// mcp/workflowStore.ts
import { GiftWorkflowContext } from "../backend/types/workflow";
const workflows = new Map<string, GiftWorkflowContext>();
export function getWorkflow(id: string): GiftWorkflowContext | undefined {
return workflows.get(id);
}
export function saveWorkflow(ctx: GiftWorkflowContext): void {
workflows.set(ctx.id, { ...ctx, updatedAt: Date.now() });
}
Sonra — hədiyyə alıcısının profilini saxlayan alət. Vacibdir ki, o, workflowId və profil məlumatlarını qəbul edir, içəridə isə uyğun konteksti yeniləyir/yaradır:
// mcp/tools/setProfile.ts
import { jsonSchema } from "@modelcontextprotocol/sdk"; // alias
import { getWorkflow, saveWorkflow } from "../workflowStore";
export const setProfileTool = {
name: "gift_set_profile",
description: "Hədiyyə alıcısının profilini yadda saxlayır",
inputSchema: jsonSchema.object({
workflowId: jsonSchema.string(),
age: jsonSchema.number().optional(),
gender: jsonSchema.string().optional(),
interests: jsonSchema.array(jsonSchema.string()).optional()
}),
async run(input: any) {
const existing = getWorkflow(input.workflowId);
const ctx = existing ?? {
id: input.workflowId,
currentStep: "profile",
likedIdeaIds: [],
hiddenIdeaIds: []
};
ctx.profile = {
age: input.age,
gender: input.gender,
interests: input.interests ?? []
};
ctx.currentStep = "budget";
saveWorkflow(ctx);
return {
structuredContent: {
type: "profileSaved",
workflowId: ctx.id,
profile: ctx.profile,
nextStep: ctx.currentStep
}
};
}
};
Bu alət artıq iki vəzifəni həll edir: profili saxlayır və currentStep‑i növbəti addıma irəli çəkir. Real layihədə bəlkə də “məlumatı saxla” və “addıma keç” alətlərini ayırmaq istəyəcəksiniz, amma konsepsiyanı anlamaq üçün bu variant uyğundur.
Arqumentlərdəki workflowId‑a diqqət yetirin: məhz bu parametr alət çağırışını lazımi kontekstə bağlayır. Müştəri hissəsi (vidjet və ya agent) onu hardasa saxlamalı və ötürməlidir.
6. Apps SDK ilə əlaqə: workflowId və sessionId haradan alınır
ChatGPT Apps‑də “workflowId haradan götürək” sualı bir az fəlsəfidir. İmkanlar ondan asılıdır ki, siz autentifikasiya, MCP birbaşa, yoxsa Agents SDK istifadə edirsiniz. Ümumən variantlar belədir: ilk alət çağırışında server tərəfində generasiya etmək və ya vidjetdə generasiya edib aşağı ötürmək.
Tədris nümunəsi üçün fərz edək ki, ilk addım workflow yaradan MCP alətinin çağırılmasıdır, vidjet isə sonra onun id‑sini götürür.
Ən sadə variant:
// mcp/tools/startWorkflow.ts
import { randomUUID } from "crypto";
import { saveWorkflow } from "../workflowStore";
export const startWorkflowTool = {
name: "gift_start_workflow",
description: "Hədiyyə seçimi üçün yeni workflow yaradır",
inputSchema: { type: "object", properties: {} },
async run() {
const id = randomUUID();
saveWorkflow({
id,
currentStep: "profile",
likedIdeaIds: [],
hiddenIdeaIds: [],
updatedAt: Date.now()
});
return {
structuredContent: {
type: "workflowStarted",
workflowId: id,
currentStep: "profile"
}
};
}
};
Daha sonra model alətin cavabında workflowId aldıqda:
- onu kontekstdə gizli şəkildə saxlaya bilər;
- onu structuredContent vasitəsilə vidjetə verə bilər ki, vidjet bu dəyəri widgetState‑də saxlasın və növbəti alət çağırışlarında onu əlavə etsin.
Vidjet tərəfində kod təxminən belə olacaq.
7. Vidjetdə workflowId və lokal UI vəziyyətinin saxlanması
Tutaq ki, bizdə ideyalar siyahısı vidjeti var və o, hansı workflow‑u göstərdiyini bilməli, həm də komponent unmount olsa belə lokal bəyənmələri xatırlamalıdır. Sadələşdirilmiş formada:
// app/widgets/GiftIdeasWidget.tsx
import { useEffect, useState } from "react";
interface Idea {
id: string;
title: string;
}
interface WidgetProps {
widgetId: string;
workflowId: string; // structuredContent-dən gəlib
ideas: Idea[];
}
interface UiState {
liked: string[];
}
export function GiftIdeasWidget(props: WidgetProps) {
const [uiState, setUiState] = useState<UiState>({ liked: [] });
useEffect(() => {
window.openai.getWidgetState<UiState>(props.widgetId).then(saved => {
if (saved) setUiState(saved);
});
}, [props.widgetId]);
function toggleLike(id: string) {
const exists = uiState.liked.includes(id);
const next: UiState = {
liked: exists
? uiState.liked.filter(x => x !== id)
: [...uiState.liked, id]
};
setUiState(next);
window.openai.setWidgetState(props.widgetId, next);
// burada MCP‑tool "gift_like_idea" çağırmaq olar
}
return (
<ul>
{props.ideas.map(idea => (
<li key={idea.id}>
{idea.title}
<button onClick={() => toggleLike(idea.id)}>
{uiState.liked.includes(idea.id) ? "★" : "☆"}
</button>
</li>
))}
</ul>
);
}
Burada widgetState məhz UI qatı kimi istifadə olunur: hansı ideyaların vurğulandığını xatırlayırıq. Əslində bəyənmələri serverə də göndərmək lazımdır (MCP‑tool və ya Next.js‑də API endpoint vasitəsilə) ki, biznes qatı da istifadəçinin seçimini bilsin.
Bütün workflow‑u widgetState üzərində qurmağa cəhd göstərməyin. O, serverdəki biznes kontekstinə əlavə qat kimi olmalıdır.
8. Ssenarinin bərpası: istifadəçi qayıtdı
İndi daha maraqlı halı düşünək: istifadəçi ChatGPT‑ni bağladı, bir neçə saat və ya gün sonra geri dönüb eyni çatı açdı. Nə baş verməlidir?
İdeal UX belədir: model və App istifadəçinin yarımçıq qalmış workflow‑u olduğunu anlayır, konteksti çəkir və təxminən belə deyir: «Siz artıq profil və büdcəni göstərmisiniz, gəlin ideyaların seçimi ilə davam edək».
Arxitektura baxımından bu, belə görünür:
- Serverinizdə GiftWorkflowContext saxlanılır və o, hansısa userId‑yə və ya heç olmasa daxili workflowId‑yə bağlıdır.
- Yeni sorğu zamanı (və ya dialoq çərçivəsində ilk alət çağırışı vaxtı) App serverə müraciət edir: “Bu istifadəçi üçün aktiv workflow varmı?”.
- Əgər varsa, server onu və bəlkə də modelin cavabında istifadə ediləcək xüsusi resume bayrağını qaytarır.
Sadə monolitik demoda MCP server və Next.js tətbiqi eyni repoda (hətta prosesdə) yaşaya bilər, ona görə də API marşrutlarında eyni workflowStore‑dan istifadə edirik.
Next.js‑də bu, sadə bir API marşrutu ola bilər:
// app/api/gift/workflow/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getWorkflow } from "@/mcp/workflowStore"; // bu demoda MCP və Next.js eyni yaddaşı bölüşür
export async function GET(req: NextRequest) {
const id = req.nextUrl.searchParams.get("workflowId");
if (!id) return NextResponse.json({ error: "Missing workflowId" }, { status: 400 });
const ctx = getWorkflow(id);
if (!ctx) return NextResponse.json({ exists: false });
return NextResponse.json({
exists: true,
context: ctx
});
}
Vidjet (və ya MCP aləti) bu endpoint‑i vəziyyəti yeniləmək lazım olanda çağıra bilər: məsələn, ilk mount zamanı və ya addımı dəyişərkən. Tədris konfiqurasiyasında workflowId + Map storagedən ibarət bundle kifayətdir; real prod‑da isə ora avtorizasiya və istifadəçiyə məxsusluğun yoxlanmasını əlavə edəcəksiniz.
Əgər Agents SDK və ya daha mürəkkəb orkestrasiya istifadə edirsinizsə, ideyanı “checkpoint”lərə qədər genişləndirə bilərsiniz — iri addımların sonunda vəziyyəti saxlayıb agentin yenidən işə düşəndə oradan davam etməsi. Amma bu artıq növbəti modulun mövzusudur.
9. İrəli‑geri hərəkət və addımların tarixi
Qaçılmaz sual yaranır: “Geri bir addım qayıtmaq olarmı?” İstifadəçi üçün bu çox təbii istəkdir: büdcəni dəyişmək, maraqları düzəltmək, seçiminizdən artıq məhsulu çıxarmaq.
Texniki baxımdan bu, iki şeyi ifadə edir:
- təkcə cari addımı deyil, qəbul edilmiş qərarların tarixçəsini də saxlamaq lazımdır;
- geri dönüşdən sonra törəmə məlumatları diqqətlə yenidən hesablamaq lazımdır.
Variantlardan biri — kontekstə addımların snapshotlarını saxlayan history sahəsini əlavə etməkdir. Məsələn:
export interface StepSnapshot {
step: GiftWorkflowStep;
payload: any; // addımın konkret məlumatları
createdAt: number;
}
export interface GiftWorkflowContext {
// ...əvvəlki sahələr
history: StepSnapshot[];
}
İstifadəçi profili dolduranda tarixçəyə step snapshotı əlavə edirsiniz: "profile". Büdcəni dəyişəndə — daha bir snapshot. Profilə geri dönəndə:
- currentStep = "profile" yenilənir;
- istəyə görə tarixçə lazımi indeksə qədər kəsilir;
- törəmə dəyərlər yenidən hesablanır (məsələn, ideyalar və bəyənmələr büdcədən asılıdırsa, təmizlənir).
Model səviyyəsində sinxronluq vacibdir: istifadəçi vidjetdə “Geri” düyməsini basıbsa, biznes kontekstini yeniləyən və cavabda yeni vəziyyəti açıq şəkildə təsvir edən alət çağırışı göndərmək lazımdır. Əks halda klassik desinxron problemi alacaqsınız: UI 2‑ci addımı göstərir, model isə sizi 3‑cü addımda hesab edir.
Vidjet səviyyəsində geri dönüş sadə düymə kimi görünə bilər:
async function goBackToProfile() {
await fetch("/api/gift/workflow/back", {
method: "POST",
body: JSON.stringify({ workflowId, targetStep: "profile" })
});
// UI‑ni yeniləyirik, lokal state‑i təmizləyirik
}
Və artıq server kontekstdə dəqiq nəyi təmizləmək və modelə alət cavabı ilə hansı mesajı göndərmək barədə qərar verir.
10. Bütün bunları model ilə necə bağlamaq: reasoning üçün kontekst
State ilə etdiyimiz hər şey sonda təkcə istifadəçiyə yox, LLM‑ə də lazımdır. Model başa düşməlidir:
- artıq nə məlumdur (məsələn, alıcının profili və büdcə);
- hansı addımlardan keçilib;
- yarımçıq proseslər varmı.
Bu məlumatı modelə çatdırma üsulu App arxitekturasından asılıdır: onu system‑prompt‑a inject edə, ToolOutput içində strukturlu şəkildə qaytara və ya SDK dəstəkləyirsə xüsusi _meta/annotations sahələrindən istifadə edə bilərsiniz.
Tipik pattern belədir:
- MCP aləti structuredContent‑də kontekstin qısa snapshotını qaytarır: cari addım, əsas sahələr və bəlkə də workflowId.
- Apps SDK bunu vidjetə və ya mətn + gizli məlumatlara çevirir.
- Model structuredContent‑i görərək ssenarinin davam etdiyini başa düşür və növbəti hərəkəti buna uyğun qurur.
Bəzi hallarda, model vacib parametrləri “unudubsa” və ya halyusinasiyaya başlayıbsa, konteksti məcburi yeniləyə bilərsiniz: aktual vəziyyəti qaytaran xüsusi alət çağırın və model “kontekstə geri girsin”.
Bütün GiftWorkflowContext‑i son sahəsinə qədər modelə “soxmağa” çalışmayın. Açar şeylər kifayətdir: kimə hədiyyə axtarılır, büdcə nə qədərdir, neçə ideya göstərilib, yarımçıq checkout varmı.
11. WorkflowContext layihələndirərkən mini check‑list
Tipik səhvlərə keçməzdən əvvəl, workflow kontekstini layihələndirərkən özünüzə cavab verməli olduğunuz kiçik suallar toplusunu formalaşdırmaq faydalıdır (bunu interfeysin yanında sözün əsl mənasında qeyd edə bilərsiniz):
- Ssenaridə hansı addımlar var və hər birində minimal hansı məlumat lazımdır?
Bu, “birdən lazım olar” üçün nəhəng JSON monstrlarından qoruyacaq. - Nələri yalnız bir çat çərçivəsində xatırlamaq lazımdır, nələri isə sessiyalar və cihazlar arasında?
Birincini widgetState və promptlarda saxlamaq olar, ikincini mütləq server VB‑nə göndərin. - Kontekstin identifikatoru necə görünəcək?
Bu, userId + scenario dəsti, ayrıca workflowId və ya hər ikisi ola bilər. Əsas odur ki, bazada konteksti birmənalı tapa biləsiniz. - Köhnə workflow‑ları necə təmizləyəcəksiniz?
Demo üçün “heç vaxt təmizləmə” qəbul ediləndir, amma prod‑da ya TTL, ya da köhnə workflow‑ları silən fon işləri lazım olacaq. - İstifadəçiyə geri dönüş lazımdırmı və onu necə reallaşdıracaqsınız?
Şaxələr ağacını saxlayacaqsınız, yoxsa sadə geri dönüş imkanlı xətli addımlar siyahısı kifayətdir.
Və sonda: “istifadəçi bir həftə sonra başqa çatdan qayıtdı” ssenarisini beyninizdə canlandırın. App‑in köhnə workflow barədə necə xəbər tutacağını və ona nə göstərəcəyini izah edə bilmirsinizsə, davamlı saxlanma hissəsini gücləndirmək lazımdır.
12. Addımlar arasında kontekstlə işləyərkən tipik səhvlər
Xəta №1: hər şeyi yalnız dialoq tarixçəsində saxlamaq.
Bəzən belə bir cazibə yaranır: “Axı model mətndə hər şeyi görür, gəlin hər dəfə promptda büdcəni, məhsulları və istifadəçinin seçdiyini sadalayaq”. Bu yanaşma tez bir zamanda kontekst limitlərinə dəyir və heç bir bütövlük zəmanəti vermir: model asanlıqla vacib faktı “unta” və ya identifikatorları qarışdıra bilər. Biznes‑kritik şeylər (pul, bron etmələr, sifarişlər) backend/MCP‑də həqiqət mənbəyi kimi yaşamalıdır.
Xəta №2: bütün workflow‑u yalnız widgetState üzərində qurmaq cəhdi.
widgetState Apps SDK‑da vidjetin unmount/mount arasında UI‑vəziyyətinin “yaşamasını” təmin edir, uzunmüddətli workflow saxlanması üçün deyil. Onun vasitəsilə profil, səbət və addımlar tarixini saxlamağa çalışsanız, cihaz dəyişəndə xaos və uzun fasilədən sonra bərpa olunmama problemi ilə üzləşəcəksiniz. Vidjet vizual xırdalıqlara və lokal rahatlığa cavabdehdir. Ssenarinin bütün məntiqi serverdə yaşamalıdır.
Xəta №3: açıq workflowId və ya başqa açarın olmaması.
Bəzən developer conversation_id kimi qeyri‑aşkar identifikatorlara güvənir, amma öz workflow anlayışını gətirmir. Nəticədə bir ssenarini digərindən ayırmaq, paralel workflow‑ları bölmək və ya məhz lazımi olanı bərpa etmək mümkünsüzləşir. Alətlərdə və API endpointlərində sadə bir workflowId sətri bir çox problemi həll edir, xüsusən də protokol üzrə stateless olan MCP‑də.
Xəta №4: UI vəziyyəti ilə biznes məntiqini qarışdırmaq.
Klassik vəziyyət: widgetState‑ə yalnız “hansı tab açıqdır” yox, həm də “səbətdə hansı məhsullar var” kimi məlumatlar yığılır, sonra isə server tərəfdə bu state əsasında qərar qəbul edilməyə çalışılır. Nəticədə ən kiçik desinxronda (vidjet render olundu, amma sorğu hələ çatmadı, və ya əksinə) model bir reallığı, UI başqa, baza isə üçüncünü görür. Məsuliyyət sərhədi aydın olmalıdır: server biznes məlumatlarını saxlayır və validasiya edir, vidjet onları göstərir və istifadəçiyə onları dəyişmək üçün rahat üsul verir.
Xəta №5: bərpa və geri dönüş ssenarisinin olmaması.
Çox asandır gözəl “xoşbəxt yol” çəkmək: istifadəçi addımları ideal keçir, heç nə sınmır, ChatGPT yenidən yüklənmir, tunel qırılmır. Reallıqda isə hər addım düşə bilər, istifadəçi ortasında gedə bilər və bir həftə sonra qayıda bilər. Əgər siz WorkflowContext strukturunu düşünməmisinizsə, “aktiv” workflow‑u necə tapacağınızı planlaşdırmamısınızsa və “Geri” və “Sonra davam et” düymələrini nəzərdə tutmamısınızsa, ssenariniz kövrək və istifadəçilər üçün əsəbi olacaq. Düzgün düşünülmüş kontekst — davamlılıq üçün bazadır və bu barədə növbəti mühazirədə danışacağıq.
GO TO FULL VERSION