03 β Messages API chuqur¶
β¬ οΈ Oldingi: 02 β O'rnatish va birinchi chaqiruv Β· π README Β· Keyingi: 04 β Streaming (oqimli javob) β‘οΈ
Bu bobda: Messages API ning eng muhim sirini ochamiz β u holatsiz (stateless): model chaqiruvlar orasida hech narsani eslamaydi. Suhbat qurish uchun tarixni SIZ saqlaysiz va har safar hammasini yuborasiz. Rollarni (
user/assistant),systempromptni,max_tokensvastop_reasonni, content bloklarini vausageni o'rganamiz β so'ng tarixni eslab qoladigan ishlaydigan CLI chatbot quramiz.
Nega bu bob muhim?¶
02-bobda biz birinchi messages.create() chaqiruvini yubordik va javob oldik. Ishladi. Lekin agar siz ikkita savol ketma-ket bersangiz, ajablanarli narsa sodir bo'ladi:
// 1-chaqiruv
await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
messages: [{ role: "user", content: "Mening ismim Aziz." }],
});
// 2-chaqiruv β alohida chaqiruv
const r = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
messages: [{ role: "user", content: "Mening ismim nima edi?" }],
});
// Model: "Kechirasiz, ismingizni bilmayman." β nega?!
Model "Aziz" ni unutdi. Bu xato emas β bu API ning eng asosiy xususiyati. Buni tushunmasdan turib chat, agent yoki RAG qura olmaysiz. Keling, sirni ochamiz.
1. API HOLATSIZ β model hech narsani eslamaydi¶
Bu bobning eng muhim jumlasi, uni yodlab oling:
Anthropic Messages API holatsiz (stateless). Model chaqiruvlar orasida hech narsani saqlamaydi. Suhbat bo'lishi uchun butun tarixni HAR safar SIZ yuborasiz.
Analogiya. Har bir API chaqiruvini shunday tasavvur qiling: siz har gal yangi xodimga murojaat qilyapsiz. Bu xodim juda aqlli, lekin u faqat siz qo'liga bergan qog'ozda yozilgan narsani biladi. Kecha bilan, hatto bir daqiqa oldin bilan, u sizni umuman ko'rmagan. Agar oldingi suhbatni eslashini xohlasangiz β o'sha suhbatni qog'ozga yozib, unga qaytadan berishingiz kerak.
ChatGPT yoki Claude veb-saytida yozganda "u eslab turadi" deb o'ylashingiz mumkin. Aslida o'sha ilovalar ham xuddi shu narsani qiladi: tarixni o'zlarida saqlaydi va har xabaringizda butun suhbatni modelga qayta jo'natadi. Sehr yo'q β shunchaki tarixni saqlash va qayta yuborish.
Demak suhbat = tarixni o'zingiz boshqarish. Har yangi xabardan keyin:
- Foydalanuvchi xabarini massivga qo'shasiz.
- Modelning javobini ham massivga qo'shasiz.
- Keyingi savolda β butun massivni qaytadan yuborasiz.
Bu juda kuchli g'oya, chunki u sizga to'liq nazorat beradi: tarixni qisqartirish, tahrirlash, eski qismlarni o'chirish β hammasi sizning qo'lingizda. Lekin u bilan birga mas'uliyat ham keladi (narx haqida pastda gaplashamiz).
2. Rollar: user va assistant¶
messages β bu obyektlar massivi. Har obyektda ikkita maydon bor: role va content.
role |
Kim bu? |
|---|---|
"user" |
Siz / inson. Savol, ko'rsatma, ma'lumot. |
"assistant" |
Model. Uning oldingi javoblari. |
Ikkita oddiy qoida bor:
- Birinchi xabar
userbo'lishi shart. Suhbatni har doim siz boshlaysiz. Birinchi bo'libassistantqo'yib bo'lmaydi (400 xato). - Rollar navbatlashadi:
userβassistantβuserβ ... (ketma-ket bir xil rol qo'yilsa, API ularni bitta turga birlashtiradi, lekin odatda navbatlashtirgan toza bo'ladi).
Mana ikki bosqichli (multi-turn) suhbatning to'liq massivi:
const messages = [
{ role: "user", content: "Quyosh tizimida nechta sayyora bor?" },
{ role: "assistant", content: "Sakkizta sayyora bor." },
{ role: "user", content: "Eng kattasi qaysi?" },
];
Uchinchi savolni ("Eng kattasi qaysi?") modelga yuborganingizda, u butun massivni "ko'radi" β shu sababli "Yupiter" deb javob bera oladi, garchi savolda Quyosh tizimi tilga olinmagan bo'lsa ham. Kontekst tarixda turibdi.
3. system prompt β alohida parametr (rol emas)¶
Ko'pchilik adashadi: system β bu messages massividagi rol emas. Bu create() ning top-level (yuqori darajadagi) parametri. U modelga "kim ekanligini" va "qanday tutishini" aytadi.
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
system: "Sen o'zbekcha gapiruvchi yordamchi ustozsan. Qisqa va aniq javob ber.",
messages: [{ role: "user", content: "Rekursiya nima?" }],
});
Nega system, nega user emas? Farqi β barqarorlikda:
system= barqaror qoidalar. Persona, til, javob uslubi, cheklovlar. Butun suhbat davomida o'zgarmaydi. "Sen kimsan va qanday ishlaysan."user= haqiqiy so'rov. Bu safar nimani so'rayapsiz. Har turda o'zgaradi.
Ko'rsatmani system ga qo'yish modelga "bu mening doimiy qoidam" degan signal beradi va u so'rovning o'zidan ajralib turadi. Bu, shuningdek, prompt caching (15-bob) uchun ham foydali β barqaror system keshlanadi.
systemhaqida chuqurroq β rol berish, uslubni boshqarish, eng yaxshi amaliyotlar β 05-bob: Prompt engineering da. (Eslatma: suhbat o'rtasida operator ko'rsatmasini yuborish uchunmessagesmassiviga{ role: "system", ... }qo'shish imkoni ham bor β bu beta xususiyat; bu yerda chuqur kirmaymiz.)
4. Javob qanday ko'rinadi: content bloklar¶
content ni yuborayotganda u oddiy matn (string) bo'lishi mumkin (eng oson yo'l) β yuqoridagi misollarda shunday qildik. Lekin u bloklar massivi ham bo'lishi mumkin (rasm, hujjat, vosita uchun β 07 va 09-boblar).
Muhim nuqta: javobning content maydoni HAR DOIM massiv β hatto oddiy matn javobida ham. Shu sababli undan matnni shunchaki .content deb olib bo'lmaydi; massivni aylanib chiqib, har blokning .type ini tekshirish kerak:
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
messages: [{ role: "user", content: "Salom!" }],
});
// msg.content β bu bloklar massivi: [{ type: "text", text: "..." }, ...]
for (const block of msg.content) {
if (block.type === "text") {
console.log(block.text);
}
}
// Yoki birinchi matn blokini qisqa olish:
const javob = msg.content.find((b) => b.type === "text")?.text ?? "";
block.type "text" dan tashqari "thinking" (10-bob) yoki "tool_use" (07-bob) ham bo'lishi mumkin. Shuning uchun .type ni tekshirish odat qiling.
Modelning javobini suhbatga qaytarib qo'shganda, eng oddiy holatda matnni string sifatida saqlasangiz bo'ladi:
const javobMatni = msg.content.find((b) => b.type === "text")?.text ?? "";
messages.push({ role: "assistant", content: javobMatni });
5. Ko'p bosqichli suhbat qurish¶
Endi hammasini birlashtiramiz. Suhbat qurishning kaliti β har javobdan keyin tarixni yangilash:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // ANTHROPIC_API_KEY muhitdan o'qiladi
const messages = [];
async function yubor(matn) {
// 1. Foydalanuvchi xabarini tarixga qo'shamiz
messages.push({ role: "user", content: matn });
// 2. BUTUN tarixni yuboramiz
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
system: "Sen do'stona o'zbekcha yordamchisan.",
messages, // β butun massiv
});
// 3. Modelning javobini tarixga qo'shamiz
const javob = msg.content.find((b) => b.type === "text")?.text ?? "";
messages.push({ role: "assistant", content: javob });
return javob;
}
console.log(await yubor("Mening ismim Aziz."));
console.log(await yubor("Mening ismim nima edi?")); // β "Sizning ismingiz Aziz."
Ikkinchi chaqiruvda model "Aziz" ni eslaydi β chunki tarixda u turibdi. Sehr emas: biz uni qayta yubordik.
ConversationManager klassi¶
Buni qayta ishlatiladigan klassga o'rab qo'yaylik. Bu real ilovalarda ko'p uchraydigan andoza:
import Anthropic from "@anthropic-ai/sdk";
class ConversationManager {
constructor({ model = "claude-opus-4-8", system, maxTokens = 1024 } = {}) {
this.client = new Anthropic();
this.model = model;
this.system = system;
this.maxTokens = maxTokens;
this.messages = []; // tarix shu yerda yashaydi
}
async send(userText) {
this.messages.push({ role: "user", content: userText });
const msg = await this.client.messages.create({
model: this.model,
max_tokens: this.maxTokens,
system: this.system,
messages: this.messages,
});
const text = msg.content.find((b) => b.type === "text")?.text ?? "";
this.messages.push({ role: "assistant", content: text });
return { text, stopReason: msg.stop_reason, usage: msg.usage };
}
}
// Foydalanish:
const chat = new ConversationManager({
system: "Sen o'zbekcha gapiruvchi yordamchi ustozsan. Qisqa javob ber.",
});
const a = await chat.send("Men frontend dasturchiman.");
const b = await chat.send("Menga qaysi tilni o'rganishni maslahat berasan?");
// Model "frontend dasturchi" ekanligingizni eslaydi β JS/TS maslahat beradi
Diqqat qiling: messages massivi klass ichida yashaydi va har send() da ham o'sadi. Model "frontend" faktini ikkinchi savolda ham biladi, chunki u tarixda saqlanib qoldi.
6. Parametrlar: max_tokens va stop_sequences¶
max_tokens β chiqishni cheklaydi¶
max_tokens β modelning chiqishi uchun yuqori chegara (tokenlarda). U kirishni emas, faqat javob uzunligini cheklaydi. Bu maydon majburiy.
Agar model bu chegaraga yetib qolsa, javob kesiladi va stop_reason "max_tokens" bo'ladi (pastda batafsil). Yechim β max_tokens ni oshirish yoki streaming ishlatish (04-bob).
// Juda kichik β javob o'rtada kesiladi:
const r = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 20, // β juda oz!
messages: [{ role: "user", content: "Fotosintezni batafsil tushuntir." }],
});
console.log(r.stop_reason); // "max_tokens" β javob to'liq emas
Maslahat:
max_tokensni juda kam qo'ymang. Streaming bo'lmagan chaqiruvlar uchun~16000, streaming uchun~64000yaxshi standart. Faqat aniq sabab bo'lsa kamaytiring (masalan, tasniflash uchun256). Opus 4.8 128K gacha chiqarishi mumkin, lekin katta qiymatlarda streaming kerak bo'ladi.
stop_sequences β erta to'xtatish¶
stop_sequences β modelga "shu matnga duch kelsang, to'xta" deyish. Belgilangan ketma-ketlikka yetganda model generatsiyani to'xtatadi.
const r = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
stop_sequences: ["\n\n"], // ikki yangi qatorga yetganda to'xta
messages: [{ role: "user", content: "Bitta qisqa jumla yoz." }],
});
// Bu holatda stop_reason "stop_sequence" bo'ladi
temperature haqida halol gap¶
Avvalgi modellarda temperature (va top_p/top_k) javob "tasodifiyligini" boshqarar edi. Opus 4.8 da bu parametrlar olib tashlangan β ularni yuborsangiz API 400 xato qaytaradi. Modelning xulqini endi sampling parametrlari bilan emas, prompting bilan boshqarasiz: aniq ko'rsatma bering, kerakli uslubni system da tasvirlang. Agar "ijodiy turlilik" kerak bo'lsa β promptda so'rang ("har safar boshqacha so'z tuzilishidan foydalan"), temperature bilan emas.
7. stop_reason β model nega to'xtadi?¶
Har javobda stop_reason maydoni bor β u modelning nega to'xtaganini aytadi. Javobni qayta ishlashdan oldin shuni tekshirish β yaxshi odat.
stop_reason |
Ma'nosi | Nima qilish |
|---|---|---|
"end_turn" |
Model tabiiy ravishda tugatdi. Javob to'liq. | Hech narsa β matnni ishlating. |
"max_tokens" |
max_tokens chegarasiga urildi. Javob kesilgan. |
max_tokens ni oshiring yoki streaming ishlating. |
"stop_sequence" |
Sizning stop_sequences dan biriga yetdi. |
Kutilgan β davom eting. |
"tool_use" |
Model vosita chaqirmoqchi (07-bob). | Vositani bajaring, natijani qaytaring. |
"refusal" |
Xavfsizlik sababli rad etdi. | Foydalanuvchiga bildiring; aynan shu prompt bilan qayta urinmang. |
Ishlab chiqarishga tayyor kodda har holatni hisobga oling:
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
messages,
});
switch (msg.stop_reason) {
case "end_turn":
// Javob to'liq β odatdagidek ishlating
break;
case "max_tokens":
console.warn("Javob kesilgan! max_tokens ni oshiring.");
break;
case "tool_use":
// Vositani bajaramiz (07-bobda)
break;
case "refusal":
console.warn("Model rad etdi (xavfsizlik).");
break;
}
stop_reasonthinking(adaptiv o'ylash) bilan birga qanday ishlashi haqida 10-bob: Adaptiv thinking va effort da batafsil.
8. usage β narx tarix bilan o'sadi¶
Har javobda usage obyekti bor:
| Maydon | Ma'nosi |
|---|---|
input_tokens |
Siz yuborgan tokenlar (kirish). |
output_tokens |
Model chiqargan tokenlar (javob). |
cache_read_input_tokens |
Keshdan o'qilgan tokenlar (15-bob). |
Endi muhim xulosa. API holatsiz bo'lgani uchun, har chaqiruvda butun tarixni qayta yuborasiz. Demak suhbat uzaygani sayin input_tokens ham o'sib boradi β chunki har gal hammasi qayta jo'natiladi. 20 ta xabardan keyin har chaqiruv 20 ta xabarning hammasini kirish sifatida hisoblaydi.
1-turn: input β 10 token
5-turn: input β 200 token (oldingi 4 turn + system qayta yuboriladi)
20-turn: input β 2000 token (hammasi har safar!)
Bu narx uzun suhbatda o'sishini bildiradi. Bu holatsizlikning narxi.
Yechim? Bir xil barqaror prefiks (system, eski tarix) ni qayta-qayta yuborganingizda, prompt caching (15-bob) uni keshlab, 90% gacha tejaydi.
cache_read_input_tokensana shuni o'lchaydi. Hozircha shuni bilib qo'ying: uzun suhbat = ko'proq kirish tokeni = ko'proq narx.
9. Loyiha: ishlaydigan CLI chatbot¶
Hammasini birlashtirib, terminalda ishlaydigan, tarixni eslab qoladigan chatbot quramiz. Node ning readline moduli bilan.
// chatbot.js
import Anthropic from "@anthropic-ai/sdk";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";
const client = new Anthropic(); // ANTHROPIC_API_KEY .env / muhitdan
const rl = readline.createInterface({ input, output });
const messages = []; // β suhbat tarixi shu yerda
const system =
"Sen do'stona, o'zbekcha gapiruvchi yordamchisan. Qisqa va tushunarli javob ber.";
console.log("Chatbot tayyor. Chiqish uchun: 'chiqish'\n");
while (true) {
const savol = await rl.question("Siz: ");
if (savol.trim().toLowerCase() === "chiqish") break;
messages.push({ role: "user", content: savol });
const msg = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
system,
messages, // butun tarix
});
const javob = msg.content.find((b) => b.type === "text")?.text ?? "";
messages.push({ role: "assistant", content: javob }); // javobni ham saqlaymiz
console.log(`Bot: ${javob}`);
if (msg.stop_reason === "max_tokens") {
console.log(" (β οΈ javob kesilgan β max_tokens ni oshiring)");
}
console.log(` (tokenlar: kirish ${msg.usage.input_tokens}, chiqish ${msg.usage.output_tokens})\n`);
}
rl.close();
console.log("Xayr!");
Ishga tushiring va sinab ko'ring:
Siz: Mening sevimli rangim ko'k.
Bot: Yaxshi! Ko'k β tinchlik va osmonni eslatadigan chiroyli rang.
(tokenlar: kirish 38, chiqish 19)
Siz: Mening sevimli rangim qaysi edi?
Bot: Sizning sevimli rangingiz ko'k edi.
(tokenlar: kirish 71, chiqish 11) β kirish o'sdi: tarix qayta yuborildi
E'tibor bering: ikkinchi savolda input_tokens oshdi (38 β 71), chunki butun tarix qayta yuborildi. Va bot "ko'k" ni esladi β biz tarixni saqlaganimiz uchun. Holatsizlik amalda shunday ishlaydi.
Xulosa¶
- Messages API holatsiz β model chaqiruvlar orasida hech narsani eslamaydi. Suhbat = tarixni o'zingiz saqlash va har safar hammasini yuborish.
messagesβ{ role, content }massivi.user= siz,assistant= model. Birinchi xabaruserbo'lishi shart; rollar navbatlashadi.systemβ rol emas, top-level parametr. Barqaror qoidalar/persona uchun.useresa har safargi haqiqiy so'rov.- Suhbat qurish: har javobdan keyin
{role:"assistant", content}ni, keyin yangi{role:"user", ...}nipushqilib, qayta yuboring. max_tokenschiqishni cheklaydi; chegara urilsastop_reason: "max_tokens".temperatureOpus 4.8 da olib tashlangan β xulqni prompting bilan boshqaring.contentjavobda har doim massiv β.typeni tekshirib, matnni oling.usage.input_tokenstarix bilan o'sadi β narx uzun suhbatda oshadi (yechim: prompt caching, 15-bob).
Mashqlar¶
1-mashq. O'z so'zlaringiz bilan tushuntiring: "API holatsiz" nimani anglatadi va shuning uchun suhbat qurish uchun nima qilishingiz kerak? "Yangi xodim" analogiyasidan foydalaning.
2-mashq. Quyidagi kod nega ishlamaydi (400 xato qaytaradi)? Tuzating.
const messages = [
{ role: "assistant", content: "Salom! Sizga qanday yordam bera olaman?" },
{ role: "user", content: "Bugun ob-havo qanday?" },
];
3-mashq. ConversationManager klassiga reset() metodini qo'shing β u tarixni tozalaydi (suhbatni noldan boshlaydi), lekin system va model ni saqlab qoladi.
4-mashq. Javobning content maydoni har doim massiv ekanligini eslang. Quyidagi kod nega xavfli/noto'g'ri, uni qanday tuzatasiz?
const msg = await client.messages.create({ /* ... */ });
console.log(msg.content); // [object Object] yoki [{...}] chiqaradi β matn emas!
5-mashq. stop_reason "max_tokens" bo'lganda nima sodir bo'lgan? Foydalanuvchi to'liq javob olish uchun ikkita yo'lni ayting.
6-mashq. Bir suhbat 15 ta xabardan iborat. Nega 15-chaqiruv 1-chaqiruvga qaraganda qimmatroq turadi? usage qaysi maydoni buni ko'rsatadi va qanday yechim bor?
Yechimlar
1-mashq. "API holatsiz" β model bir chaqiruvdan keyingi chaqiruvga hech qanday xotira saqlamaydi degani. Har chaqiruv mustaqil: u faqat o'sha so'rovda yuborilgan messages ni "ko'radi". "Yangi xodim" analogiyasi: har gal yangi, aqlli, lekin sizni umuman tanimaydigan xodimga murojaat qilasiz β u faqat siz qo'liga bergan qog'ozdagi (ya'ni messages massividagi) ma'lumotni biladi. Shuning uchun suhbat bo'lishi uchun tarixni o'zingiz saqlab, har xabarda butun massivni (oldingi user va assistant turlari bilan) qayta yuborishingiz kerak.
2-mashq. Xato β birinchi xabar assistant rolida. Birinchi xabar har doim user bo'lishi shart. Suhbatni doim foydalanuvchi boshlaydi. Tuzatish β assistant xabarini olib tashlash (yoki uni user xabaridan keyinga qo'yish):
(Agar "Salom!" salomlashuvini boshlang'ich kontekst sifatida ko'rsatmoqchi bo'lsangiz, uni system ga qo'ying yoki birinchi user xabaridan keyin assistant sifatida qo'shing.)
3-mashq.
class ConversationManager {
constructor({ model = "claude-opus-4-8", system, maxTokens = 1024 } = {}) {
this.client = new Anthropic();
this.model = model;
this.system = system;
this.maxTokens = maxTokens;
this.messages = [];
}
reset() {
this.messages = []; // faqat tarixni tozalaymiz
// this.system va this.model o'zgarmaydi β saqlanib qoladi
}
async send(userText) {
this.messages.push({ role: "user", content: userText });
const msg = await this.client.messages.create({
model: this.model,
max_tokens: this.maxTokens,
system: this.system,
messages: this.messages,
});
const text = msg.content.find((b) => b.type === "text")?.text ?? "";
this.messages.push({ role: "assistant", content: text });
return text;
}
}
4-mashq. msg.content β bu bloklar massivi ([{ type: "text", text: "..." }]), oddiy string emas. Uni to'g'ridan-to'g'ri console.log qilsangiz, matn o'rniga obyekt(lar) chiqadi. To'g'ri yo'l β massivni aylanib chiqib, type === "text" blokidan .text ni olish:
.find() ishlatishimiz sababi β content da thinking yoki tool_use kabi boshqa turdagi bloklar ham bo'lishi mumkin, shuning uchun .type ni tekshirish shart.
5-mashq. "max_tokens" β model max_tokens chegarasiga yetgani uchun o'rtada to'xtab qolgan; javob to'liq emas, kesilgan. To'liq javob olish uchun ikki yo'l:
1. max_tokens ni oshirish β modelga ko'proq joy berish (masalan, 1024 β 16000).
2. Streaming ishlatish (04-bob) β client.messages.stream() bilan uzun javoblarni oqim sifatida olish (timeout muammosisiz).
6-mashq. API holatsiz bo'lgani uchun har chaqiruvda butun tarix qayta yuboriladi. 15-chaqiruvda oldingi 14 ta xabar + system hammasi kirish sifatida qayta jo'natiladi, 1-chaqiruvda esa atigi bitta xabar bor edi. Buni usage.input_tokens ko'rsatadi β u tarix bilan o'sib boradi. Yechim: prompt caching (15-bob) β barqaror prefiksni (system + eski tarix) keshlab, qayta o'qishda ~0.1Γ narxda oladi, bu 90% gacha tejashi mumkin. Keshdan o'qilgan tokenlar usage.cache_read_input_tokens da ko'rinadi.
β¬ οΈ Oldingi: 02 β O'rnatish va birinchi chaqiruv Β· π README Β· Keyingi: 04 β Streaming (oqimli javob) β‘οΈ