Keyingi qadamlar
Qayerdamiz
Kitob oxiriga yetdi, loyiha esa yo'q. Bu bob — Tez qayerda turgani va keyingi qadamlar qaysi tartibda qo'yilishi haqida. Va har bir qadamning sababi — o'lchangan raqam.
Avval bitta raqam — kitob davomida eng muhim bo'lgan raqam. 10-bobda Tez uchun hallucination (gallyutsinatsiya) ni aniqladik: noto'g'ri plan ("different result") va berilmagan savol ("guessed instead of asking") yig'indisi. Bugungi mahsulot modeli tez8 da bu ulush:
import json import glob TOZA = ["loans", "deposits", "cash_desk", "transactions", "realistic_loans", "realistic_deposits", "realistic_cash"] GURUHLAR = {"toza": TOZA, "shovqinli": [f"noisy_{t}" for t in TOZA], "real": sorted(Path(f).parent.name for f in glob.glob(str(TEZ / "accuracy/suites/real_*/questions.json")))} for guruh, toplamlar in GURUHLAR.items(): javoblar = [json.loads(q) for t in toplamlar for q in open(TEZ / f"results/tez8g_cpu_{t}.jsonl", encoding="utf-8")] yolgon = sum(j["reason"] in ("different result", "guessed instead of asking") for j in javoblar) print(f"{guruh:10s} {len(javoblar):4d} savol: to'g'ri {sum(j['correct'] for j in javoblar):4d}, hallucination {yolgon:3d} ({yolgon / len(javoblar):.1%})")
toza 320 savol: to'g'ri 315, hallucination 5 (1.6%) shovqinli 320 savol: to'g'ri 311, hallucination 8 (2.5%) real 105 savol: to'g'ri 81, hallucination 24 (22.9%)
O'zimiz yasagan jadvallarda — juda past. Real jadvallarda — 22.9 foiz, deyarli to'rtta javobdan biri. Bu farq — keyingi ishlarning asosiy sababi.
Xatolar qayerdan keladi
tez8 ning real jadvallardagi har bir xatosi alohida tahlil qilingan va sababi bo'yicha guruhlangan. Tahlil
loyihaning 13-why-the-model-falls-short.md faylida; uning ilovasidagi jadvalni o'qib, sabablarni sanaymiz:
from collections import Counter tahlil = (TEZ.parent.parent / "13-why-the-model-falls-short.md").read_text(encoding="utf-8") ilova = tahlil.split("## Appendix")[1] sabablar = Counter() for qator in ilova.splitlines(): katak = [k.strip() for k in qator.strip().strip("|").split("|")] if len(katak) == 6 and katak[1].isdigit(): sabab = katak[5] if sabab.startswith("wrong plan") or sabab.startswith("guessed"): sabablar["model xato qildi: noto'g'ri reja yoki taxmin"] += 1 elif sabab.startswith("tool gap") or sabab.startswith("information not in table"): sabablar["asbob yo'q yoki ma'lumot jadvalda yo'q"] += 1 elif sabab.startswith("arguable"): sabablar["test bahsli"] += 1 else: sabablar["javob promptda ko'rinmagan"] += 1 for sabab, soni in sabablar.most_common(): print(f"{soni:3d} {sabab}") print(f"jami: {sum(sabablar.values())}")
9 javob promptda ko'rinmagan 8 model xato qildi: noto'g'ri reja yoki taxmin 6 asbob yo'q yoki ma'lumot jadvalda yo'q 1 test bahsli jami: 24
Bu jadval kitobning eng muhim xulosalaridan birini beradi: xatolarning kattaroq qismi modelning "aqli" muammosi emas. Javob promptda yo'q, yoki uni bajaradigan tool yo'q.
- "Javob promptda ko'rinmagan" — masalan, valyuta jadvalida namunalarda faqat uchta valyuta ko'rinadi, va model dollar qaysi qatorda ekanini bilmaydi; yoki "qaytarilgan tovarlar" — bu jadvalda manfiy miqdor ekanini hech kim aytmagan. Model ko'rmagan narsani hech qanday training o'rgatmaydi. Bu — jadval tavsifi va ilova ishi.
- "Tool yo'q" — nisbat, farq, bashorat. Bunga yo yangi tool kerak, yo "qila olmayman" deyish. Training modelga "qila olmayman" deyishni o'rgata oladi (17-bob), lekin to'g'ri javobni bera olmaydi.
- Qolgan qismi — model haqiqatan noto'g'ri plan tuzgan yoki so'rash o'rniga taxmin qilgan holatlar — keyingi training ma'lumotining ishi.
Model atrofidagi qatlamlar
22-bob qayta trainingning chegarasini ko'rsatdi: har bir training tez8 ning ikkilangan javoblarini aralashtiradi. Shuning uchun keyingi qadamlar modelning og'irliklariga tegmaydi. Ular model atrofida ishlaydi: model nimani ko'rishini yaxshilaydi, uning planini bajarilgandan keyin tekshiradi, va ikkilanganda to'xtatadi. Har bir qatlam alohida o'lchandi.
1. Jadval tavsifi
Yuqoridagi jadvalda eng katta guruhlardan biri — "javob promptda ko'rinmagan". Masalan, valyuta jadvalida namunalar faqat uchta valyutani ko'rsatardi. Jadval tavsifchisi (11-bob) endi matn ustunining hamma qiymatlarini yozadi, agar ular birgalikda 600 belgiga sig'sa:
sozlama = json.loads((TEZ / "training/settings.json").read_text(encoding="utf-8")) print("values_chars_limit:", sozlama["values_chars_limit"]) for t in ("real_fx_rates", "real_banks", "real_retail"): jadval = json.loads((TEZ / f"prompt/domains/{t}/table.json").read_text(encoding="utf-8")) toliq = [u["name"] for u in jadval["columns"] if "values" in u and u["type"] == "text"] print(f"{t:14s} hamma qiymatlari ko'rinadigan matn ustunlari: {toliq}")
values_chars_limit: 600 real_fx_rates hamma qiymatlari ko'rinadigan matn ustunlari: ['G1', 'G2'] real_banks hamma qiymatlari ko'rinadigan matn ustunlari: ['Banknomi'] real_retail hamma qiymatlari ko'rinadigan matn ustunlari: ['Country']
Model o'sha-o'sha tez8. Real jadvallarda faqat tavsif o'zgargan holda:
HAMMASI = sum(GURUHLAR.values(), []) def hukmlar(prefiks, toplamlar): return {(t, j["id"]): j for t in toplamlar for j in map(json.loads, open(TEZ / f"results/{prefiks}_cpu_{t}.jsonl", encoding="utf-8"))} def matritsa(prefiks, toplamlar): sanoq = Counter(j["reason"] if not j["reason"].startswith("plan failed") else "plan failed" for j in hukmlar(prefiks, toplamlar).values()) javoblar = sum(v for k, v in sanoq.items() if k not in ("asked", "asked on a clear request")) return sanoq["same result"], javoblar, sanoq["asked"], sanoq["asked"] + sanoq["guessed instead of asking"] def togrilar(prefiks, toplamlar): return sum(json.loads(q)["correct"] for t in toplamlar for q in open(TEZ / f"results/{prefiks}_cpu_{t}.jsonl", encoding="utf-8")) print(f"real 105 savol: eski tavsif {togrilar('tez8g', GURUHLAR['real'])}, yangi tavsif {togrilar('tez8d', GURUHLAR['real'])}")
real 105 savol: eski tavsif 81, yangi tavsif 84
Bitta qo'shimcha tuzatish shu yerda qilindi. Bank nomlarida uch xil tutuq belgisi bor edi (O‘z, Oz,O'z), foydalanuvchi esa oddiy'yozadi. Grammar modelni ro'yxatdagi qiymatlardan birini tanlashga majbur
qiladi (9-bob), va "O'zmilliybank" so'rovida model boshqa bankni tanlab qo'ygan edi. Endi ro'yxatdagi hamma
tutuq belgilari bitta oddiy'` ga keltiriladi; engine esa (10-bob) qiymatlarni solishtirishda baribir
tutuq belgilariga e'tibor bermaydi, shuning uchun haqiqiy ma'lumot bilan moslik buzilmaydi.
2. Validator
Model plani DuckDB da bajarilgandan keyin, natija foydalanuvchiga ko'rsatilishidan oldin, uni oddiy qoidalar tekshiradi — validator. Qoida shubhali natija topsa, Tez javob o'rniga savol beradi:
import ast manba = (TEZ / "accuracy/validate.py").read_text(encoding="utf-8") for tugun in ast.parse(manba).body: if isinstance(tugun, ast.FunctionDef) and tugun.name == "problems": print(ast.get_source_segment(manba, tugun))
def problems(steps, result, base_rows):
found = []
if not result["rows"]:
found.append("empty result")
if any(step["tool"] in FILTERS for step in steps) and len(result["rows"]) == base_rows:
found.append("filter kept every row")
if _grouped(steps) and len(result["rows"]) == base_rows:
found.append("grouping changed nothing")
if result["rows"] and _missing_previous(steps, result):
found.append("comparison without previous data")
return found
Har bir qoida bitta shart bilan qabul qilindi: saqlangan javoblarda u birorta to'g'ri javobga tegmasligi kerak. Uchta model (tez8, tez9, tez10) ning 20 to'plamdagi hamma rejalarida qoidalarni sinaymiz:
from accuracy.execute import effective_steps, run_plan from accuracy.run import BASE, _earlier, load_json, open_data from accuracy.tools import ToolError from accuracy.validate import problems FAYLLAR = {"loans": "loans", "deposits": "deposits", "cash_desk": "cash_desk", "transactions": "bank", "realistic_loans": "loans", "realistic_deposits": "deposits", "realistic_cash": "cash_desk"} def fayl(toplam): nom = toplam.removeprefix("noisy_") return f"/mnt/d/Tez_spikes/data/{FAYLLAR.get(nom, nom)}.csv" sozlama = load_json(TEZ / "accuracy/settings.json") qoidalar = Counter() for toplam in HAMMASI: savollar = {s["id"]: s for s in load_json(TEZ / f"accuracy/suites/{toplam}/questions.json")} baza = open_data(fayl(toplam)) qatorlar = baza.execute(f"SELECT count(*) FROM {BASE}").fetchone()[0] for prefiks in ("tez8g", "tez9g", "tez10g"): for j in map(json.loads, open(TEZ / f"results/{prefiks}_cpu_{toplam}.jsonl", encoding="utf-8")): try: javob = json.loads(j["output"]) qadamlar = effective_steps(_earlier(savollar[j["id"]]), javob) natija = run_plan(baza, BASE, qadamlar, sozlama) except (ValueError, KeyError, TypeError, ToolError): continue for qoida in problems(qadamlar, natija, qatorlar): qoidalar[(qoida, j["reason"] == "same result")] += 1 for qoida in sorted({k[0] for k in qoidalar}): print(f"{qoida:35s} noto'g'ri javoblarda {qoidalar[(qoida, False)]:3d}, to'g'ri javoblarda {qoidalar[(qoida, True)]}")
comparison without previous data noto'g'ri javoblarda 3, to'g'ri javoblarda 0 empty result noto'g'ri javoblarda 15, to'g'ri javoblarda 0 filter kept every row noto'g'ri javoblarda 8, to'g'ri javoblarda 0 grouping changed nothing noto'g'ri javoblarda 3, to'g'ri javoblarda 0
To'rtta qoida ham faqat noto'g'ri javoblarda ishladi. Boshqa qoidalar ham sinalgan edi (masalan, "kodli ustun bo'yicha filtr, so'rovda raqam yo'q") — ular to'g'ri javoblarga ham tegdi va olib tashlandi.
3. Ishonch darvozasi
22-bobda tez8 ning ishonchi o'zgaradigan javoblarni oldindan ajratganini ko'rdik. Bu raqam qayerdan
keladi? Model har bir token ni tanlaganda barcha mumkin bo'lgan token larga ehtimol beradi. llama-server
so'rovda "logprobs": true bo'lsa, tanlangan har bir token ning ehtimol logarifmini qaytaradi. Undan ikki
raqam chiqadi: eng past token ehtimoli va o'rtacha ehtimol (logarifmlar o'rtachasining eksponentasi):
manba = (TEZ / "accuracy/validate.py").read_text(encoding="utf-8") for tugun in ast.parse(manba).body: if isinstance(tugun, ast.FunctionDef) and tugun.name == "confidence": print(ast.get_source_segment(manba, tugun))
def confidence(tokens):
return math.exp(sum(token["logprob"] for token in tokens) / len(tokens)) if tokens else 0.0
Qaysi biri to'g'ri va noto'g'ri planlarni yaxshiroq ajratadi? O'lchov — AUC: tasodifiy olingan to'g'ri javobning ishonchi tasodifiy noto'g'ri javobnikidan yuqori bo'lish ehtimoli (0.5 — tanga, 1.0 — mukammal):
import math def ishonchlar(toplamlar): javoblar = [json.loads(q) for t in toplamlar for q in open(TEZ / f"results/tez8c_cpu_{t}.jsonl", encoding="utf-8")] return [j for j in javoblar if j["output"].startswith('{"steps"')] def auc(yaxshi, yomon): return sum((a > b) + 0.5 * (a == b) for a in yaxshi for b in yomon) / (len(yaxshi) * len(yomon)) SOZLASH = GURUHLAR["toza"] + GURUHLAR["shovqinli"] for nom, toplamlar in (("toza+shovqinli", SOZLASH), ("real", GURUHLAR["real"])): javoblar = ishonchlar(toplamlar) for olchov, qiymat in (("eng past token", lambda j: j["min_prob"]), ("o'rtacha", lambda j: math.exp(j["mean_logprob"]))): yaxshi = [qiymat(j) for j in javoblar if j["correct"]] yomon = [qiymat(j) for j in javoblar if not j["correct"]] print(f"{nom:15s} {olchov:15s} AUC {auc(yaxshi, yomon):.3f} ({len(yaxshi)} to'g'ri, {len(yomon)} noto'g'ri)")
toza+shovqinli eng past token AUC 0.836 (501 to'g'ri, 10 noto'g'ri) toza+shovqinli o'rtacha AUC 0.875 (501 to'g'ri, 10 noto'g'ri) real eng past token AUC 0.875 (69 to'g'ri, 23 noto'g'ri) real o'rtacha AUC 0.904 (69 to'g'ri, 23 noto'g'ri)
O'rtacha ehtimol ikkala guruhda ham yaxshiroq. Darvoza oddiy: o'rtacha ishonch chegaradan past bo'lsa, Tez javob o'rniga savol beradi. Chegara faqat toza va shovqinli to'plamlarda tanlandi, aniq qoida bilan: aniq so'rovlarga savol berish bir foizdan oshmasin. Real to'plam chegarani tanlashda ishlatilmadi:
print("tanlangan chegara:", sozlama["confidence_threshold"])
tanlangan chegara: 0.94
4. Hammasi birga
Uchala qatlam (tavsif, validator ning dastlabki uchta qoidasi, darvoza) ishga tushiriladigan kodga ulandi va 745 savol jonli, boshidan oxirigacha qayta o'tkazildi. Har bir javob yozuvida endi modelning o'z chiqishi, ishonchi va validator sababi bor:
for guruh, toplamlar in GURUHLAR.items(): a, b = hukmlar("tez8g", toplamlar), hukmlar("tez8s", toplamlar) togri, javoblar, topildi, savollar = matritsa("tez8s", toplamlar) yoqotildi = sum(a[k]["correct"] and not b[k]["correct"] for k in a) print(f"{guruh:10s} tez8 {sum(j['correct'] for j in a.values()):3d}, qatlamlar bilan {sum(j['correct'] for j in b.values()):3d};" f" precision {togri}/{javoblar} = {togri / javoblar:.1%}; yo'qotilgan to'g'ri javob: {yoqotildi}") to_xtatildi = Counter(j["held"] for j in hukmlar("tez8s", HAMMASI).values() if j["held"]) print("to'xtatilgan javoblar:", dict(to_xtatildi))
toza tez8 315, qatlamlar bilan 313; precision 284/289 = 98.3%; yo'qotilgan to'g'ri javob: 2
shovqinli tez8 311, qatlamlar bilan 309; precision 280/287 = 97.6%; yo'qotilgan to'g'ri javob: 3
real tez8 81, qatlamlar bilan 90; precision 79/89 = 88.8%; yo'qotilgan to'g'ri javob: 0
to'xtatilgan javoblar: {'low confidence': 11, 'filter kept every row': 2, 'empty result': 1, 'comparison without previous data': 2}
Real jadvallarda precision 75.8 foizdan 88.8 foizga ko'tarildi, va bitta ham to'g'ri javob yo'qolmadi. Toza va shovqinli to'plamlarda darvoza bir nechta to'g'ri javobni savolga aylantirdi — oldindan o'lchangan, bir foizdan kam narx.
"To'qson foizga bir-ikki savol qoldi" — shunday ko'rindi.
Yangi savollar haqiqati
Lekin bu 105 savol endi halol hakam emas edi. Jadval tavsifi, tutuq belgisi tuzatishi va validator qoidalari — hammasi shu savollardagi xatolarni o'rganib tanlangan. Test ustida sozlangan narsa testda yaxshi ko'rinadi. Haqiqiy javob uchun hech kim ko'rmagan savollar kerak edi.
Oltita real jadval uchun 92 ta yangi savol yozildi (14 tasi savol berilishi kerak bo'lgan), har birining kutilgan javobi haqiqiy ma'lumotda tekshirildi, va savollar git da muzlatildi — hech qaysi model ularni ko'rishidan oldin. Keyin bitta jonli o'tish:
from accuracy.run import expected_results, judge from runtime.client import parse_answer xom, qatlam = Counter(), Counter() for t in GURUHLAR["real"]: savollar = load_json(TEZ / f"accuracy/suites/{t}/fresh.json") lugat = {s["id"]: s for s in savollar} baza = open_data(fayl(t)) kutilgan = expected_results(baza, savollar, sozlama) for j in map(json.loads, open(TEZ / f"results/fresh8s_cpu_{t}.jsonl", encoding="utf-8")): _, sabab = judge(baza, lugat[j["id"]], parse_answer(j["output"]), kutilgan, sozlama) xom[sabab if not sabab.startswith("plan failed") else "plan failed"] += 1 qatlam[j["reason"] if not j["reason"].startswith("plan failed") else "plan failed"] += 1 for nom, sanoq in (("tez8 o'zi", xom), ("qatlamlar bilan", qatlam)): javoblar = sum(v for k, v in sanoq.items() if k not in ("asked", "asked on a clear request")) print(f"{nom:16s} precision {sanoq['same result']}/{javoblar} = {sanoq['same result'] / javoblar:.1%}, jim xato {sanoq['different result'] + sanoq['guessed instead of asking']}," f" savol topildi {sanoq['asked']}/{sanoq['asked'] + sanoq['guessed instead of asking']}")
tez8 o'zi precision 58/89 = 65.2%, jim xato 31, savol topildi 3/14 qatlamlar bilan precision 57/78 = 73.1%, jim xato 21, savol topildi 6/14
Qatlamlar yangi savollarda ham yordam berdi — precision bir necha punktga oshdi, jim xatolar kamaydi. Lekin 88.8 foiz emas. Eski 105 savoldagi raqam test ustida sozlash bilan shishgan edi. Jurnalda — 25-raqam:
for qator in Path("/mnt/c/Users/Admin/Desktop/Offline/12-mistakes-and-lessons.md").read_text(encoding="utf-8").splitlines(): if qator.startswith("| 25 |"): for ustun, matn in zip(("xato", "narxi", "qoida"), [q.strip() for q in qator.strip("|").split("|")][2:]): print(f"{ustun}: {matn}\n")
xato: Reported the stack as 88.8% precision, "1-2 questions from 90%", on the 105 real-table questions, although the descriptions, the apostrophe fix and the validator rules had all been chosen by looking at misses in those same questions. narxi: On 92 fresh questions frozen before any run, the same stack scored 73.1% (57/78); the 105-question figure was inflated by tuning on the test. qoida: Keep a frozen held-out set from the start; every fix is chosen on one set and the claim is made only on a set no fix has looked at.
Bu kitobdagi eng og'ir, lekin eng foydali raqam. Endi har bir tuzatish bitta to'plamda tanlanadi, va da'vo faqat hech qaysi tuzatish ko'rmagan to'plamda qilinadi.
Yangi savollardagi xatolar ham guruhlandi. Eng kattasi — bitta naqsh: foydalanuvchi bitta umumiy son
so'raganda ("jami depozitlar", "o'rtacha yosh") model biror ustun bo'yicha guruhlab qo'yadi. Ikkinchisi —
kodlarni taxmin qilish ("erkak mijozlar" uchun SEX = 2). Uchinchisi — bajarib bo'lmaydigan so'rovga
(daromad, nisbat) taxminiy javob.
Birinchisi uchun ikki narsa sinaldi. Validator ga to'rtinchi qoida qo'shildi: guruhlash hech narsani o'zgartirmagan bo'lsa (har bir guruh — bitta qator), bu shubhali (yuqoridagi jadvalda — "grouping changed nothing"). Va tizim promptiga bitta qator: "guruhlashni faqat foydalanuvchi nima bo'yicha guruhlashni aytganda qil". Qator 260 ta toza savoldan keyin to'xtatildi: uchta to'g'ri javobni buzdi, birortasini tuzatmadi — "menejerlar bo'yicha jami" so'rovida model guruhlashni olib tashladi. Model aynan shu prompt matnida o'qitilgan; uni o'zgartirish — qayta trainingning kichik nusxasi, xuddi shu almashinuv bilan.
Javob o'zini tushuntiradi
To'rtta javobdan biri noto'g'ri bo'lsa, tahlilchi buni ko'rishi kerak. Tezning plani — oddiy, aniq qadamlar ro'yxati; uni foydalanuvchi tilida oddiy jumlalarga aylantirish mumkin. Bu kod 12-bobdagi o'qituvchi uchun yozilgan edi (faqat inglizcha); endi u o'zbekcha (lotin va kirill), ruscha va inglizcha gapiradi, ustun nomlari va qiymatlarni esa jadvaldagidek qoldiradi. Yangi savollardagi haqiqiy noto'g'ri javoblarda:
from training.describe import explain, load_texts til = json.loads((TEZ / "training/explain.json").read_text(encoding="utf-8")) matnlar = load_texts(TEZ / "training", til) yozuv = json.loads((TEZ / "training/uzbek_script.json").read_text(encoding="utf-8")) for t, raqam in (("real_regions", 8), ("real_credit_clients", 3), ("real_fx_rates", 8), ("real_credit_clients", 5)): savol = {s["id"]: s for s in load_json(TEZ / f"accuracy/suites/{t}/fresh.json")}[raqam] javob = {j["id"]: j for j in map(json.loads, open(TEZ / f"results/fresh8s_cpu_{t}.jsonl", encoding="utf-8"))}[raqam] print(f"[{savol['language']}] {savol['text']}") print(explain(json.loads(javob["output"]), savol["language"], matnlar, til, yozuv), end="\n\n")
[uz_latin] jami depozitlar summasi 1. Har bir Regions uchun Total deposits bo'yicha jami hisoblanadi. [en] clients aged between 40 and 50 1. Keep only the rows where AGE is none of 40, 50. [ru] курсы рубля и тенге 1. Оставить только строки, где G1 одно из: 'RUB', 'TJS'. [uz_cyrillic] кейинги ойда тўлайдиганлар 1. Фақат default payment next month 1ga тенг бўлган қаторлар қолдирилади.
Har bir xato ko'rinib turibdi: "jami" so'ralgan — "har bir viloyat uchun" deyilgan; "40 dan 50 gacha"
so'ralgan — "40, 50 dan hech biri emas"; rubl va tenge so'ralgan — TJS (somoniy) tanlangan. Bu son
foizni oshirmaydi, lekin jim xatoni ko'rinadigan xatoga aylantiradi. Tahlilchi raqamni hisobotga
qo'yishdan oldin planni o'qiydi.
Kodlar lug'ati
Kod taxmin qilish xatosini train qilish emas, ma'lumot tuzatadi. Bank jadvallarida kodlar lug'ati bo'ladi:
SEX: 1 — erkak, 2 — ayol. Tezning promptida har bir jadval uchun lug'at joyi bor (8-bob), real jadvallar uchun
esa u bo'sh edi. Tahlilchi bir marta yozadigan lug'at bilan sinov:
lugat = json.load(open(DATA / "kodlar/glossary.json", encoding="utf-8")) for soz, ma_no in lugat.items(): print(f" {soz}: {ma_no}") savollar = {s["id"]: s for s in json.load(open(DATA / "kodlar/questions.json", encoding="utf-8"))} javoblar = [json.loads(q) for q in open(DATA / "kodlar/tez8_codes.jsonl", encoding="utf-8")] print(f"\nqat'iy hakam: {sum(j['correct'] for j in javoblar)}/{len(javoblar)}") for j in javoblar: if not j["correct"]: print(f" {savollar[j['id']]['text']}: {j['output']}")
erkak / мужчина / male: SEX = 1
ayol / женщина / female: SEX = 2
uylangan / женатый / married: MARRIAGE = 1
bo'ydoq / холостой / single: MARRIAGE = 2
magistratura / магистратура / graduate school: EDUCATION = 1
oliy ta'lim / высшее образование / university: EDUCATION = 2
o'rta maktab / средняя школа / high school: EDUCATION = 3
to'lamaydi / неплательщик / default: default payment next month = 1
qat'iy hakam: 9/12
мужчины старше 40 лет: {"steps":[{"tool":"filter","args":{"column":"SEX","op":"=","value":1}},{"tool":"filter","args":{"column":"AGE","op":">=","value":40}}]}
average limit of women: {"steps":[{"tool":"filter","args":{"column":"SEX","op":"=","value":2}},{"tool":"group_and_total","args":{"group_by":["SEX"],"value_column":"LIMIT_BAL","agg":"avg"}}]}
число неплательщиков среди женщин: {"steps":[{"tool":"filter","args":{"column":"SEX","op":"=","value":2}},{"tool":"filter","args":{"column":"default payment next month","op":"=","value":1}},{"tool":"group_and_total","args":{"group_by":["SEX"],"value_column":"default payment next month","agg":"count"}}]}
Kodlar hamma savolda to'g'ri ishlatildi. Uchta "xato"ning birortasi ham kod xatosi emas: "40 dan katta"
o'rniga >=, va ikki marta ayollarni ajratgandan keyin ortiqcha jinsi bo'yicha guruhlash — son to'g'ri,
yonida kod ustuni ortiqcha. Lug'atsiz tez8 xuddi shu turdagi savollarda kodni taxmin qilardi.
Uchta model, bir xil qatlamlar
Qatlamlar modelga bog'liq emas. Shuning uchun savol tug'ildi: 22-bobda yutqazgan tez10 va tez11a qatlamlar bilan yaxshiroq bo'lmaydimi? tez10 ko'proq savol beradi, darvoza esa aynan ishonchsiz javoblarni ushlaydi — ikkalasi birga nima beradi? Uchala model bir xil 92 ta yangi savolda, to'rt qoidali validator va darvoza bilan:
def hisob(qatorlar): javoblar = [q for q in qatorlar if not q["sorradi"]] togri = sum(q["togri"] for q in javoblar if not q["kerak"]) return togri, len(javoblar), sum(q["sorradi"] for q in qatorlar if q["kerak"]), sum(q["kerak"] for q in qatorlar) for model in ("tez8", "tez10", "tez11a"): xom, qatlam, yoqoldi = [], [], 0 for t in GURUHLAR["real"]: savollar = load_json(TEZ / f"accuracy/suites/{t}/fresh.json") lugat = {s["id"]: s for s in savollar} baza = open_data(fayl(t)) kutilgan = expected_results(baza, savollar, sozlama) for j in map(json.loads, open(TEZ / f"results/fresh{model}v_cpu_{t}.jsonl", encoding="utf-8")): javob = parse_answer(j["output"]) togri, _ = judge(baza, lugat[j["id"]], javob, kutilgan, sozlama) kerak = lugat[j["id"]]["expect"] == "ask" xom.append({"togri": togri, "sorradi": "ask" in javob, "kerak": kerak}) qatlam.append({"togri": j["correct"], "sorradi": j["reason"] in ("asked", "asked on a clear request"), "kerak": kerak}) yoqoldi += togri and not kerak and not j["correct"] for nom, qatorlar in (("o'zi", xom), ("qatlamlar", qatlam)): togri, javoblar, topildi, kerak = hisob(qatorlar) print(f"{model:7s} {nom:10s} to'g'ri {togri:3d} precision {togri}/{javoblar} = {togri / javoblar:.1%}" f" jim xato {javoblar - togri:3d} savol topildi {topildi}/{kerak}") print(f"{model:7s} qatlamlar yo'qotgan to'g'ri javob: {yoqoldi}\n")
tez8 o'zi to'g'ri 58 precision 58/89 = 65.2% jim xato 31 savol topildi 3/14 tez8 qatlamlar to'g'ri 57 precision 57/73 = 78.1% jim xato 16 savol topildi 8/14 tez8 qatlamlar yo'qotgan to'g'ri javob: 1 tez10 o'zi to'g'ri 54 precision 54/81 = 66.7% jim xato 27 savol topildi 9/14 tez10 qatlamlar to'g'ri 52 precision 52/62 = 83.9% jim xato 10 savol topildi 11/14 tez10 qatlamlar yo'qotgan to'g'ri javob: 2 tez11a o'zi to'g'ri 57 precision 57/83 = 68.7% jim xato 26 savol topildi 8/14 tez11a qatlamlar to'g'ri 55 precision 55/72 = 76.4% jim xato 17 savol topildi 10/14 tez11a qatlamlar yo'qotgan to'g'ri javob: 2
tez8 qatoridagi "qatlamlar" yuqoridagidan yaxshiroq — farq faqat to'rtinchi qoida (guruhlash hech narsani o'zgartirmadi): u guruhlash xatolarining bir qismini ushladi. tez10 eng yuqori precision ga chiqdi, lekin bepul emas: u ko'proq savol beradi, shuning uchun to'g'ri javoblar soni ham eng kam. 22-bobda u toza savollarda ham tez8 dan orqada edi. tez11a o'zi eng yuqori precision ga ega edi, lekin qatlamlar bilan eng past precision ga tushdi: qatlamlar uning xatolarini kamroq ushladi.
Bu yerda tanlov qoidasi muhim. Bu 92 savol endi ham halol hakam emas — to'rtinchi qoida aynan shular ustida tanlangan. Shuning uchun qaror shu yerda, ikkinchi yangi to'plamni ko'rishdan oldin qabul qilindi: mahsulot modeli tez8 bo'lib qoladi (ko'proq to'g'ri javob, toza savollarda ham yaxshiroq), tez10 esa taqqoslash uchun o'lchanadi. Natijaga qarab keyin tanlash — 25-xatoni yana bir marta qilish bo'lardi.
Halol raqam
Ikkinchi yangi to'plam — yana 92 savol (13 tasi savol berilishi kerak bo'lgan), birinchisi kabi yozilgan, git da muzlatilgan, va hech qaysi tuzatish uni ko'rmagan. Bu kitobdagi yagona da'vo shu to'plamda qilinadi:
for model in ("tez8", "tez10"): xom, qatlam, yoqoldi = [], [], 0 for t in GURUHLAR["real"]: savollar = load_json(TEZ / f"accuracy/suites/{t}/fresh2.json") lugat = {s["id"]: s for s in savollar} baza = open_data(fayl(t)) kutilgan = expected_results(baza, savollar, sozlama) for j in map(json.loads, open(TEZ / f"results/fresh2{model}_cpu_{t}.jsonl", encoding="utf-8")): javob = parse_answer(j["output"]) togri, _ = judge(baza, lugat[j["id"]], javob, kutilgan, sozlama) kerak = lugat[j["id"]]["expect"] == "ask" xom.append({"togri": togri, "sorradi": "ask" in javob, "kerak": kerak}) qatlam.append({"togri": j["correct"], "sorradi": j["reason"] in ("asked", "asked on a clear request"), "kerak": kerak}) yoqoldi += togri and not kerak and not j["correct"] for nom, qatorlar in (("o'zi", xom), ("qatlamlar", qatlam)): togri, javoblar, topildi, kerak = hisob(qatorlar) print(f"{model:7s} {nom:10s} to'g'ri {togri:3d} precision {togri}/{javoblar} = {togri / javoblar:.1%}" f" jim xato {javoblar - togri:3d} savol topildi {topildi}/{kerak}") print(f"{model:7s} qatlamlar yo'qotgan to'g'ri javob: {yoqoldi}\n")
tez8 o'zi to'g'ri 56 precision 56/89 = 62.9% jim xato 33 savol topildi 3/13 tez8 qatlamlar to'g'ri 56 precision 56/72 = 77.8% jim xato 16 savol topildi 10/13 tez8 qatlamlar yo'qotgan to'g'ri javob: 0 tez10 o'zi to'g'ri 54 precision 54/80 = 67.5% jim xato 26 savol topildi 10/13 tez10 qatlamlar to'g'ri 53 precision 53/63 = 84.1% jim xato 10 savol topildi 12/13 tez10 qatlamlar yo'qotgan to'g'ri javob: 1
Mahsulot — tez8 va qatlamlar: ko'rilmagan savollarda 77.8 foiz precision. Birinchi yangi to'plamdagi raqamga deyarli teng — demak bu safar raqam sozlash bilan shishmagan. Qatlamlar jim xatolarni ikki barobar kamaytirdi, savol berilishi kerak bo'lgan so'rovlarni uchtadan o'ntaga ko'tardi, va bitta ham to'g'ri javobni olmadi.
To'qson foiz emas. Javoblarning 22 foizi (72 tadan 16 tasi) hali ham noto'g'ri — lekin endi u tahlilchiga oddiy jumlalar bilan tushuntiriladi, va u raqamni hisobotga qo'yishdan oldin planni o'qiy oladi.
tez10 ikkala yangi to'plamda ham bir xil manzarani berdi: precision olti punktga yuqori, to'g'ri javob uch-beshtaga kam. Ikki mustaqil to'plam rozi — bu tasodif emas. Qaysi biri yaxshiroq — bu texnik emas, mahsulot savoli: tahlilchi uchun kamroq noto'g'ri javob muhimmi yoki ko'proq javob? Bu savol foydalanuvchi bilan hal qilinadi, va undan oldin tez10 qatlamlar bilan toza va shovqinli savollarda ham o'lchanishi kerak.
Tartib
Shu natijalardan keyingi qadamlar tartibi chiqadi:
1. Tahlilchining haqiqiy savollari. Hamma narsadan muhim. Ikkala yangi to'plam ham — hali bizning tasavvurimiz. Tahlilchidan o'ttiz-yuzta yozilgan savol va fayllarining ustun nomlari hamda kodlar lug'ati (qatorlar emas) — eng halol test to'plami bo'ladi.
2. tez8 yoki tez10. tez10 ni qatlamlar bilan hamma 745 savolda o'lchash, keyin tahlilchi bilan tanlash.
3. Hisoblangan ustun tooli. Ikki ustundan nisbat, farq yoki foiz — real xatolarning bir qismi aynan shu tool yo'qligidan. U schema ni o'zgartiradi, demak qayta training va hamma modellarni qayta sinash kerak; va 22-bobdagi saboq bo'yicha natija faqat yangi, muzlatilgan to'plamda baholanadi.
4. "Qila olmayman" o'rniga "shuni nazarda tutdingizmi?". Savol berish o'rniga model eng ehtimolli planni taklif qiladi va tushuntirishni ko'rsatadi; tahlilchi bitta bosish bilan tasdiqlaydi. Bu darvoza ushlagan javoblarning bir qismini qaytaradi — xavfsiz holda.
5. Haqiqiy 8 GB kompyuter. Tez ning o'z xotirasi o'lchandi (26-bob); Windows bilan birga va kuchsiz protsessorda — hali yo'q.
6. Ilova. Oyna, fayl tashlash, oldindan ko'rish va bekor qilish, grafik va Excelga saqlash, model serverini himoyalash (27-bob), fayl xeshini tekshirish (28-bob), ikki faylni solishtirish.
7. Kattaroq model. 9B model xatolarning "model xato qildi" qismini kamaytirishi mumkin. Uning xotirasi o'lchanmagan, lekin 4B ning o'zi 8 GB ning yarmidan ko'pini oladi (26-bob). Bu ofis serveri bilan birga ko'rib chiqiladi.
Har bir qadam uchun ikki qoida amal qiladi: har bir modelda bitta o'zgarish, va da'vo faqat hech qaysi tuzatish ko'rmagan to'plamda qilinadi.
Bu kitob qanday davom etadi
Bu kitob "kundalik" sifatida yozilgan (1-bob), va u loyiha bilan birga o'zgaradi. Bir nechta bob aniq qayta yoziladi: 26-bob — haqiqiy 8 GB kompyuterda sinovdan keyin; 27-bob — model serveri himoyalangandan keyin; shu bob — tahlilchining haqiqiy savollari kelganda.
Bitta narsa o'zgarmaydi: har bir raqam o'lchanadi, har bir xato yoziladi, va "bilmaymiz" degan joyda "bilmaymiz" deb yoziladi. Bu bobning o'zi bunga misol: 88.8 foiz deb yozilgan raqam yangi savollarda 77.8 foiz bo'lib chiqdi, va ikkalasi ham kitobda qoldi.
Xulosa
- tez8 ning hallucination ulushi: o'zimizning jadvallarda bir-ikki foiz, real jadvallarda 22.9 foiz.
- Real xatolarning kattaroq qismi — training muammosi emas: javob promptda ko'rinmagan yoki tool yo'q. Shuning uchun model atrofiga qatlamlar qurildi: jadval tavsifi, validator, ishonch darvozasi va tushuntirish.
- Sozlangan savollarda qatlamlar 88.8 foiz ko'rsatdi; hech kim ko'rmagan savollarda — 77.8 foiz precision, jim xatolar ikki barobar kam, birorta to'g'ri javob yo'qolmadi. Halol raqam — ikkinchisi.
- Har qanday qayta training yoki prompt o'zgarishi javoblarning oltidan birini o'zgartiradi — aynan model ishonchsiz bo'lganlarini. Shuning uchun o'qitilgan prompt matni muzlatilgan.
- tez10 qatlamlar bilan aniqroq, lekin kamroq javob beradi; tanlov — tahlilchi bilan.
- Tartib: tahlilchining savollari, tez8 yoki tez10, hisoblangan ustun, tasdiqlash oynasi, haqiqiy 8 GB kompyuter, ilova, kattaroq model.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.