fix(danisman): olasılık/vaat dili — prompt kalıpları, anahtarsız regex denetimi, Jev sorusu ve sürümü (iş 1) [KARAR]

(a) Prompt: yasak kalıp listesi + yerine ne denir örnekleri; 'olasılığı düşük' de yasak.
(b) cikti-denetimi.ts: anahtarsız regex (vaatDiliBul). Akışta Jev VEYA regex yakalarsa düzeltme notu.
    Ek model çağrısı yok, kredi etkilenmez; Jev atlanırsa regex yine koşar.
(c) Jev: model jev-1.13.0'a sabitlendi; soruya ölçüt (criteria) eklendi. 01 raporundaki ek cümle
    TEK BAŞINA gerçek cevaplarda 15 ihlalin 8'ini kaçırdı; 'olumsuz yöndeki tahmin de ihlaldir'
    cümlesiyle birlikte eklendi. Canlı eşik 0,50 kaldı (73 örnek: yanlış alarm 0/40, kaçan 3/33;
    regex ile birlikte 0/40 ve 0/33). Eval: danışmanda yerlesme_vaadi eşiği 0,25/0,35.
Kanıt (aynı 23 soru × 2, deepseek-v4-flash): geçen 13/46 → 25/46; jev:yerlesme_vaadi 'kaldı' 20 → 1;
canlı not eklenen cevap 2/46. Dosyalar: sonuc/*-sohbet-vaat-once.json, *-vaat-sonra.json, *-jev-kesif.json.
Akış tamponlanmadı: ihlalli cümle ekranda kalır, altına not düşer (bilinçli; [BİLAL] kararı).
Eval verisi: s060/s061/s062/s064 icermemeli kalıpları reddeden cümleye takılıyordu, kaldırıldı.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-10-05 08:23:07 +03:00
parent 080dcc9909
commit 151e44780f
12 changed files with 7355 additions and 101 deletions

View File

@@ -0,0 +1,77 @@
/**
* Danışman cevabının deterministik (anahtarsız) çıktı denetimi.
*
* Jev denetimi (jev.ts) anahtar yoksa, zaman aşımında ya da hata olursa
* atlanır ve "olasılığın düşük" türü cümlelere eşiğin altında değer
* verebiliyor (5 Eki 2026 eval: gri bölgedeki 18 kararın 13'ü gerçek ihlaldi).
* Buradaki kalıplar her cevapta, ağ çağrısı olmadan koşar; sohbet-akisi.ts
* ikisinden biri yakalarsa düzeltme notunu ekler.
*
* Ürün kuralı (KARARLAR.md: olasılık vermiyoruz): yerleşme garantisi YOK,
* yerleşmeyi olasılık / yüzde / ihtimal / şans diliyle tahmin etmek YOK —
* "olasılığın düşük" de buna dahil. İhlal SAYILMAYANLAR: reddeden cümleler
* ("garanti verilemez", "'kesin yerleşirsin' diyemem"), Güvenli / Az riskli /
* Riskli etiketleri, burs / doluluk / istihdam yüzdeleri.
*
* Saf modül: DB'ye ve ağa dokunmaz, Next dışından da çalışır.
*/
const tr = (s: string) => s.toLocaleLowerCase("tr-TR");
/**
* Reddeden / olumsuzlayan söz. Türkçede olumsuzluk yüklemin sonundadır; bu
* yüzden yalnız eşleşmeden SONRA ve aynı yan cümlede aranır ("garanti yok ama
* şansın yüksek" cümlesindeki "yok" ikinci yarıyı aklamaz).
*/
const RED =
/verme[mzy]|verem|verilem|vermiyor|veremiyor|değil|yok(?!sa)|diyem|demem|demiyor|denem|denilem|denmez|söyleyem|söylenem|söylemiyor|olmaz(?!sa)|edem|etmiyor|hesaplam|tahmin etm|anlamına gelm|kullanm|yapam|yapmıyor|sunam|bilinem|bilem|yanlış|yerine|doğru olmaz/;
/** Yan cümle sınırı: nokta, satır sonu ve "ama / ancak / fakat" bağlaçları. */
const YAN_CUMLE_SONU = /[.!?;\n]|\s(?:ama|ancak|fakat|yine de|lakin)\s/;
/** "girersin" bunların hemen ardından geliyorsa yerleşme değil, sisteme/sınava giriştir. */
const GIRIS_BAGLAMI = /ais|sınav|sistem|site|sayfa|hesab|panel|oturum/;
/** "iş bulma şansı", "istihdam olasılığı": yerleşme tahmini değil. */
const ISTIHDAM_BAGLAMI = /iş bulma|işe girme|istihdam|mezun/;
const VAAT_KALIPLARI: RegExp[] = [
// kesinlik zarfı + yerleşme fiili: "kesin yerleşirsin", "rahatça girersin", "en rahat yerleşeceğin"
/(?:kesin(?:likle)?|rahat(?:ça|lıkla)?|garanti(?:li)?|mutlaka|yüzde yüz|%\s?100)\s+(?:olarak\s+|bir\s+şekilde\s+)?(?:yerleş|gir(?:er|ebil|ecek)|kazan|tut(?:ar|acak)|gel(?:ir|ecek))/g,
// yalın vaat fiilleri
/(?:yerleşirsin|yerleşeceksin|yerleşirsiniz|yerleşeceksiniz|girersin|gireceksin|kazanırsın|kazanacaksın|açıkta kalmazsın|açıkta kalmayacaksın|açıkta kalman imkânsız)/g,
/(?:söz veriyorum|garanti (?:veriyorum|ediyorum|veriyoruz|ediyoruz))/g,
// olasılık dili (yüksek de düşük de): "yüksek ihtimal", "düşük bir olasılık", "büyük ihtimalle"
/(?:yüksek|büyük|güçlü|kuvvetli|düşük|zayıf|az|küçük)\s+(?:bir\s+)?(?:ihtimal|olasılık)/g,
/(?:yerleşme|yerleşebilme|girme|kazanma|tutma|gelme)\s+(?:şans|ihtimal|olasılı[kğ])\p{L}*/gu,
/(?:ihtimal|olasılı[kğ]|şans)\p{L}*\s+(?:çok\s+|daha\s+|oldukça\s+|epey\s+)*(?:yüksek|düşük|iyi|fazla|az|zayıf|güçlü|yarı yarıya)/gu,
/şans(?:ın|ınız)\s+var(?!\s*m[ıi])/g,
// sayıyla olasılık: "%80 ihtimalle", "yüzde seksen şans"
/(?:%\s?\d+|yüzde\s+[\p{L}\d]+)\s*(?:ihtimal|olasılık|şans)/gu,
// eski dilim adı
/garanti\s+(?:dilim|tercih|liste|seçenek)/g,
];
/**
* Metindeki garanti / olasılık dili adayları (çevresiyle birlikte kısa alıntı).
* Reddeden yan cümledekiler ve istihdam / sisteme giriş bağlamındakiler elenir.
* Boş dizi = temiz.
*/
export function vaatDiliBul(metin: string): string[] {
const m = tr(metin);
const bulunan: string[] = [];
for (const kalip of VAAT_KALIPLARI) {
for (const e of m.matchAll(kalip)) {
const i = e.index ?? 0;
const son = i + e[0].length;
const kalan = m.slice(son, son + 90);
const sinir = kalan.search(YAN_CUMLE_SONU);
const ardi = sinir < 0 ? kalan : kalan.slice(0, sinir);
if (RED.test(e[0]) || RED.test(ardi)) continue;
const once = m.slice(Math.max(0, i - 30), i);
if (/^gir/.test(e[0]) && GIRIS_BAGLAMI.test(once)) continue;
if (ISTIHDAM_BAGLAMI.test(once)) continue;
bulunan.push(m.slice(Math.max(0, i - 25), son + 25).replace(/\s+/g, " ").trim());
}
}
return bulunan;
}