Test to'plamlari: toza, shovqinli va real
Oltinchi qism
Oltinchi qism — halol benchmark haqida. Model qanchalik yaxshi ekanini faqat test ko'rsatadi, va test noto'g'ri bo'lsa, butun loyiha noto'g'ri yo'nalishga ketadi. Bu qismning uchta bobi: test to'plamlari qanday tuzilgan (shu bob), modellar qanday adolatli solishtiriladi (24-bob) va xatolar jurnali (25-bob).
Yigirmata to'plam
Tezning testlari — accuracy/suites papkasidagi yigirmata to'plam. Har birida savollar va kutilgan
javoblar:
import json import glob import pandas as pd qatorlar = [] for fayl in sorted(glob.glob(str(TEZ / "accuracy/suites/*/questions.json"))): nom = Path(fayl).parent.name savollar = json.load(open(fayl, encoding="utf-8")) tur = "real" if nom.startswith("real_") else "shovqinli" if nom.startswith("noisy_") else "toza" qatorlar.append({"to'plam": nom, "tur": tur, "savollar": len(savollar), "savol kerak": sum(s["expect"] == "ask" for s in savollar), "suhbat": sum("history" in s for s in savollar), "bir nechta to'g'ri javob": sum(isinstance(s["expect"], list) and len(s["expect"]) > 1 for s in savollar)}) jadval = pd.DataFrame(qatorlar) show(jadval, 25) print(jadval.groupby("tur")["savollar"].sum().to_dict(), "jami:", jadval["savollar"].sum())
{'real': 105, 'shovqinli': 320, 'toza': 320} jami: 745
| to'plam | tur | savollar | savol kerak | suhbat | bir nechta to'g'ri javob |
|---|---|---|---|---|---|
| cash_desk | toza | 60 | 4 | 10 | 4 |
| deposits | toza | 60 | 5 | 10 | 3 |
| loans | toza | 40 | 4 | 0 | 6 |
| noisy_cash_desk | shovqinli | 60 | 4 | 10 | 4 |
| noisy_deposits | shovqinli | 60 | 5 | 10 | 3 |
| noisy_loans | shovqinli | 40 | 4 | 0 | 6 |
| noisy_realistic_cash | shovqinli | 40 | 4 | 6 | 0 |
| noisy_realistic_deposits | shovqinli | 40 | 5 | 6 | 1 |
| noisy_realistic_loans | shovqinli | 40 | 4 | 6 | 4 |
| noisy_transactions | shovqinli | 40 | 4 | 0 | 5 |
| real_banks | real | 21 | 3 | 1 | 1 |
| real_credit_clients | real | 17 | 4 | 1 | 0 |
| real_fx_rates | real | 14 | 2 | 1 | 4 |
| real_industry | real | 13 | 2 | 1 | 1 |
| real_regions | real | 20 | 2 | 2 | 2 |
| real_retail | real | 20 | 2 | 1 | 4 |
| realistic_cash | toza | 40 | 4 | 6 | 0 |
| realistic_deposits | toza | 40 | 5 | 6 | 1 |
| realistic_loans | toza | 40 | 4 | 6 | 4 |
| transactions | toza | 40 | 4 | 0 | 5 |
Uch tur:
- Toza — yettita to'plam, 320 savol, to'rtta sintetik jadval ustida. "realistic_" to'plamlar xuddi shu jadvallarning haqiqiy hayotdagidek sarlavhali nusxasi ustida ("Сумма вклада", "Amount (UZS)").
- Shovqinli — yettita to'plam, xuddi o'sha 320 savol, lekin harf xatolari va boshqa shovqin bilan.
- Real — oltita to'plam, 105 savol, haqiqiy jadvallar ustida.
Bitta savol ichida
Har bir savol — kichik JSON yozuv:
savollar = json.load(open(TEZ / "accuracy/suites/deposits/questions.json", encoding="utf-8")) oddiy = savollar[0] suhbat = next(s for s in savollar if "history" in s) print(json.dumps(oddiy, ensure_ascii=False, indent=1)[:500]) print() print("suhbat ichidagi savol:") print(json.dumps(suhbat, ensure_ascii=False, indent=1)[:900])
{
"id": 1,
"language": "uz_latin",
"text": "Filiallar bo'yicha omonatlar jami summasini chiqar",
"expect": [
{
"steps": [
{
"tool": "group_and_total",
"args": {
"group_by": [
"Филиал"
],
"value_column": "Amount (UZS)",
"agg": "sum"
}
}
]
}
]
}
suhbat ichidagi savol:
{
"id": 51,
"language": "uz_latin",
"text": "endi kattasidan boshlab sarala",
"expect": [
{
"steps": [
{
"tool": "sort",
"args": {
"by": "Amount (UZS)",
"descending": true
}
}
]
}
],
"history": [
{
"request": "Filiallar bo'yicha jami summa",
"answer": {
"steps": [
{
"tool": "group_and_total",
"args": {
"group_by": [
"Филиал"
],
"value_column": "Amount (UZS)",
"agg": "sum"
}
}
]
}
}
]
}
text— foydalanuvchi so'rovi,language— tili.expect— kutilgan javob: planlar ro'yxati (bir nechta to'g'ri javob bo'lishi mumkin) yoki"ask".history— suhbat ichidagi savol uchun oldingi so'rov va javob. Test paytida engine avval oldingi javobni bajaradi, model esa oldingi qadamni promptda ko'radi (8-bob).
Baholash 10-bobdagi usul bilan: model plani va har bir kutilgan plan bajariladi, natijalar solishtiriladi. Bittasi mos kelsa — to'g'ri.
Bir nechta to'g'ri javob
Ba'zi so'rovlarni ikki xil ma'noda tushunish mumkin, va ikkalasi ham to'g'ri. Masalan:
real_kurs = json.load(open(TEZ / "accuracy/suites/real_fx_rates/questions.json", encoding="utf-8")) ikki = next(s for s in real_kurs if isinstance(s["expect"], list) and len(s["expect"]) > 1) print(ikki["text"]) for reja in ikki["expect"]: print(" ", json.dumps(reja["steps"], ensure_ascii=False))
dollar kursi
[{"tool": "filter", "args": {"column": "G1", "op": "=", "value": "USD"}}]
[{"tool": "filter", "args": {"column": "G7", "op": "=", "value": "AQSH dollari"}}]
[{"tool": "filter", "args": {"column": "G9", "op": "=", "value": "US Dollar"}}]
[{"tool": "filter", "args": {"column": "G6", "op": "=", "value": "Доллар США"}}]
"Dollar kursi" — to'rtta to'g'ri javob: valyuta kodi bo'yicha (USD), yoki o'zbekcha, inglizcha, ruscha nom
ustuni bo'yicha. To'rttalasi ham bir xil qatorni beradi. Lekin e'tibor bering: hammasi = bilan, jadvaldagi
aniq qiymat bilan. 6-qismdagi xatolar tahlilida tez8 bu savolga G6 contains "dollar" deb javob berdi —
ruscha "Доллар США" ichida lotincha "dollar" yo'q, va natija bo'sh. Kutilgan javoblar ro'yxati bunday holatlarni
qamraydi — aks holda test to'g'ri javobni xato deb hisoblaydi.
Shovqin
Haqiqiy tahlilchi shoshilib yozadi. Shovqinli to'plamlar toza savollardan kod bilan yasalgan:
accuracy/make_noisy.py. Har bir savolga beshta shovqin turidan bittasi qo'llanadi:
qoidalar = json.load(open(TEZ / "accuracy/noise.json", encoding="utf-8")) print("turlar:", qoidalar["kinds"]) toza = {s["id"]: s for s in json.load(open(TEZ / "accuracy/suites/transactions/questions.json", encoding="utf-8"))} shovqinli = json.load(open(TEZ / "accuracy/suites/noisy_transactions/questions.json", encoding="utf-8")) korsatilgan = set() for s in shovqinli: if s["noise"] not in korsatilgan: korsatilgan.add(s["noise"]) print(f"\n[{s['noise']}]") print(f" toza: {toza[s['id']]['text']}") print(f" shovqinli: {s['text']}")
turlar: ['no_apostrophes', 'lowercase', 'uppercase', 'typo', 'spaces'] [typo] toza: Filiallar bo'yicha jami summani hisobla shovqinli: Filiallar bo'iycha jami summani hisobla [lowercase] toza: Sana ustunidagi formatlarni to'g'irla shovqinli: sana ustunidagi formatlarni to'g'irla [uppercase] toza: Eng ko'p komissiya to'lagan 5 ta mijozni ko'rsat shovqinli: ENG KO'P KOMISSIYA TO'LAGAN 5 TA MIJOZNI KO'RSAT [spaces] toza: O'tgan oyga nisbatan filiallar bo'yicha savdoni solishtir shovqinli: O'tgan oyga nisbatan filiallar bo'yicha savdoni solishtir [no_apostrophes] toza: Muddati o'tgan kreditlarni ko'rsat shovqinli: Muddati otgan kreditlarni korsat
Bir muhim qoida: shovqin qiymatlarga tegmaydi. Agar savolda "Bekor qilindi" yoki "Toshkent" bo'lsa va u plandagi qiymat bo'lsa, harf xatosi u so'zga qo'yilmaydi:
from accuracy.make_noisy import protected_words namuna = next(s for s in toza.values() if s["expect"] != "ask" and protected_words(s, qoidalar["value_args"])) print(namuna["text"]) print("himoyalangan so'zlar:", protected_words(namuna, qoidalar["value_args"]))
Bekor qilingan operatsiyalarni olib tashla
himoyalangan so'zlar: {'Bekor', 'qilindi'}
Nega? Chunki qiymatni buzish savolning ma'nosini o'zgartiradi: "Toshkent" o'rniga "Tohskent" — bu endi boshqa savol, va kutilgan javob ham boshqa bo'lishi kerak edi. Shovqin faqat foydalanuvchining o'z so'zlarida.
Real to'plamlar
Eng muhim to'plamlar — real jadvallar ustidagilar. Ular tez9 tayyorlanayotganda yasaldi, va ularning maqsadi bitta: modelni o'zimiz yasamagan jadvallarda sinash.
real_qatorlar = [] for nom in sorted(Path(f).parent.name for f in glob.glob(str(TEZ / "accuracy/suites/real_*/questions.json"))): j = json.load(open(TEZ / f"prompt/domains/{nom}/table.json", encoding="utf-8")) real_qatorlar.append({"toplam": nom, "jadval qatorlari": j["rows"], "ustunlar": len(j["columns"]), "ustun nomlaridan namuna": ", ".join(c["name"] for c in j["columns"][:4])}) show(pd.DataFrame(real_qatorlar))
| toplam | jadval qatorlari | ustunlar | ustun nomlaridan namuna |
|---|---|---|---|
| real_banks | 36 | 9 | Banknomi, Aktivsumma, Aktivulushi, Kreditsumma |
| real_credit_clients | 30 000 | 25 | ID, LIMIT_BAL, SEX, EDUCATION |
| real_fx_rates | 75 | 9 | G1, G2, G3, G4 |
| real_industry | 9 | 6 | Korsatkichlarnomi, 01122023mlrdsom, 01122023ulushifoizda, 01032024mlrdsom |
| real_regions | 14 | 8 | №, Regions, Total loan portfolio, Total loan portfolio of which: individuals |
| real_retail | 541 909 | 8 | InvoiceNo, StockCode, Description, Quantity |
Jadvallar ikki manbadan:
- O'zbekiston bank statistikasi — ommaga ochiq e'lon qilingan jadvallar: banklar bo'yicha aktiv va kreditlar, hududlar bo'yicha kredit va depozitlar, sohalar bo'yicha ulushlar, valyuta kurslari. Bular — tahlilchi har kuni ko'radigan turdagi fayllar, ularning sarlavhalari, birliklari va "jami" qatorlari bilan.
- Ikkita mashhur ochiq ma'lumotlar to'plami (UCI Machine Learning Repository): kredit kartasi mijozlari (30 000 qator, kodli ustunlar bilan) va onlayn chakana savdo (yarim milliondan ortiq qator).
Hech birida maxfiy ma'lumot yo'q — hammasi ommaga ochiq. Va ularning ustun nomlari biz yasaydigan
jadvallardan butunlay farq qiladi: G1...G9, PAY_0, 01122023mlrdsom, Total loan portfolio of which:
individuals.
Hech qachon trainingga kirmaydi
Real to'plamlarning qiymati bitta shartga bog'liq: bu jadvallar trainingda bo'lmasligi kerak. Uchta o'qitilgan modelning training fayllarini tekshiramiz — biror qatorning promptida real jadval nomi bormi:
import re real_nomlar = {json.load(open(TEZ / f"prompt/domains/{r['toplam']}/table.json", encoding="utf-8"))["name"] for r in real_qatorlar} nom = re.compile(r'Table "([^"]+)" \(') for model in ("tez8", "tez9", "tez10"): korilgan = {nom.search(json.loads(q)["messages"][0]["content"]).group(1) for q in open(Path.home() / f"tez_runs/{model}/data/train.jsonl", encoding="utf-8")} print(f"{model}: o'qitishdagi jadvallar {len(korilgan)}, ulardan real jadvallar: {len(korilgan & real_nomlar)}")
tez8: o'qitishdagi jadvallar 14, ulardan real jadvallar: 0 tez9: o'qitishdagi jadvallar 18, ulardan real jadvallar: 0 tez10: o'qitishdagi jadvallar 18, ulardan real jadvallar: 0
Nol. Bu jadvallar model uchun har doim yangi.
Tuzoqlar
Real savollarning ko'pchiligida tuzoq belgisi bor — savol modelning qaysi zaif joyini sinashi:
from collections import Counter real_savollar = [(Path(f).parent.name, s) for f in sorted(glob.glob(str(TEZ / "accuracy/suites/real_*/questions.json"))) for s in json.load(open(f, encoding="utf-8"))] tuzoqlar = Counter(s.get("trap", "oddiy") for _, s in real_savollar) korilgan_tur = set() for toplam, s in real_savollar: tur = s.get("trap", "oddiy") if tur not in korilgan_tur and tur != "oddiy": korilgan_tur.add(tur) print(f"{tur:12s} ({tuzoqlar[tur]:2d}) {toplam}: {s['text']}") print(f"{'oddiy':12s} ({tuzoqlar['oddiy']:2d})")
totals ( 6) real_banks: kredit portfeli bo'yicha eng katta 5 ta bank percent ( 2) real_banks: kredit ulushi 5 foizdan yuqori banklar messy ( 7) real_banks: nomi yozilmagan bank bormi vague ( 6) real_banks: banklarni tahlil qil tool_gap ( 6) real_banks: har bir bankning kredit depozit nisbati groups ( 1) real_banks: davlat ulushi bor banklarning krediti followup ( 7) real_banks: faqat kapitali 10000 dan kattalari codes ( 3) real_credit_clients: ayol mijozlar cryptic (16) real_fx_rates: dollar kursi translation ( 9) real_regions: Samarqand viloyati units ( 2) real_regions: kredit portfeli 30 trln dan katta viloyatlar grand_total ( 1) real_regions: respublika bo'yicha jami kredit qancha returns ( 2) real_retail: qaytarilgan tovarlar oddiy (37)
Masalan, translation — so'rovda qiymat boshqa tilda ("Samarqand viloyati", jadvalda "Samarkand region");
units — so'rovda birlik boshqacha ("5 trillion", jadval milliardda); codes — ma'nosi yozilmagan kodlar;
tool_gap — toollar bilan bajarib bo'lmaydigan so'rov; cryptic — G1 kabi ma'nosiz sarlavhalar.
Kutilgan javoblar ham tekshiriladi
Test xatosi — eng xavfli xato: u yaxshi modelni yomon, yomon modelni yaxshi ko'rsatadi. Shuning uchun har bir kutilgan plan schema ga mos ekani test bilan tekshiriladi — ya'ni model grammar bilan yozishi mumkin bo'lgan javob:
cd /mnt/c/Users/Admin/Desktop/Offline/spikes/spike2_3_model PYTHONDONTWRITEBYTECODE=1 "$OLDPWD/.venv/bin/python" -m pytest prompt/test_build.py -q -p no:cacheprovider -k "suites" 2>&1 | tail -1
4 passed, 364 deselected in 3.54s
Lekin schema ga mos bo'lish — hali to'g'ri bo'lish degani emas. Real to'plamlardagi bir nechta kutilgan javob
keyinroq bahsli chiqdi: masalan, "код и курс" so'rovida "kod" — harfli kodmi (G1) yoki raqamli kodmi
(G2)? Test faqat G1 ni qabul qiladi. Bunday savollar 25-bobda va xatolar tahlilida alohida belgilangan, va
ularni o'zgartirish — tahlilchi bilan kelishib qilinadigan qaror.
Chegaralar
Halol bo'lish kerak:
- Real to'plamlardagi savollarni biz yozganmiz. Jadvallar haqiqiy, savollar — bizning tasavvurimiz. Tahlilchining haqiqiy savollari hali yo'q.
- 105 ta savol — kam. 21-bobda ko'rdik: bu hajmda ikki model orasidagi besh-olti savollik farqni ham ishonchli ajratib bo'lmaydi.
- Toza to'plamlar training uslubiga yaqin. Ularning jadvallari trainingda bo'lmagan (aynan bir xil matn ham yo'q — 15-bob), lekin ular bizning uslubimizda yozilgan. Toza to'plamdagi 98 foiz real hayotdagi 98 foizni anglatmaydi; real to'plamdagi raqam haqiqatga yaqinroq.
Xulosa
- Yigirmata to'plam, 745 savol: toza (320), shovqinli (o'sha 320, shovqin bilan) va real (105).
- Har bir savolda kutilgan planlar ro'yxati yoki "savol berish kerak"; suhbat savollarida oldingi qadam.
- Shovqin kod bilan qo'shiladi va qiymatlarga tegmaydi.
- Real to'plamlar — ommaga ochiq haqiqiy jadvallar; ular hech bir modelning trainingida yo'q. Tuzoq belgilari zaif joylarni alohida o'lchaydi.
- Kutilgan javoblar schema bo'yicha tekshiriladi, lekin ba'zilari bahsli; savollarni biz yozganmiz va ular kam.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.