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

@@ -24,12 +24,22 @@ import {
} from "ai";
import { aracSeti, type AracBaglami } from "./araclar";
import { sohbetDilModeli } from "./client";
import { vaatDiliBul } from "./cikti-denetimi";
import { cevapIhlalOlasiligi, JEV_DUZELTME_NOTU, JEV_IHLAL_ESIGI } from "./jev";
/** Bir cevapta en fazla model adımı (araç turları + son cevap). */
const ARAC_TUR_SINIRI = 4;
const HATA_METNI = "Danışman şu anda yanıt veremiyor.";
export type CiktiDenetimi = {
/** Jev'in ihlal olasılığı; denetim yapılamadıysa null. */
jevP: number | null;
/** Regex'in yakaladığı garanti/olasılık ifadeleri (boş = temiz). */
vaatRegex: string[];
/** Cevabın sonuna düzeltme notu eklendi mi. */
vaatNotu: boolean;
};
export function danismanAkisi(opts: {
system: string;
mesajlar: ModelMessage[];
@@ -40,6 +50,8 @@ export function danismanAkisi(opts: {
onYarim: (metin: string) => Promise<void>;
/** Sağlayıcı bu sürede bitirmezse cevap yarım sayılır (varsayılan 120 sn). */
zamanAsimiMs?: number;
/** Çıktı denetiminin sonucu (gözlem/eval için; cevabı etkilemez). */
onDenetim?: (d: CiktiDenetimi) => void;
}): ReadableStream<UIMessageChunk> {
return createUIMessageStream<UIMessage>({
execute: async ({ writer }) => {
@@ -97,21 +109,24 @@ export function danismanAkisi(opts: {
if (zamanAsimi.aborted) throw new Error("Zaman aşımı: sağlayıcı cevabı bitirmedi");
if (!metin.trim()) throw new Error("Boş cevap");
// Çıktı denetimi (jev.ts): cevap garanti/olasılık dili içeriyorsa
// sonuna düzeltme notu eklenir. Akış zaten gittiği için cevap geri
// alınamaz; not hem ekrana hem kayda yazılır. Denetim yapılamazsa
// (anahtar yok, zaman aşımı) cevap olduğu gibi kalır.
const ihlalP = await cevapIhlalOlasiligi(metin);
if (ihlalP != null) {
console.info("[soru] jev ihlal olasılığı:", ihlalP.toFixed(2));
if (ihlalP >= JEV_IHLAL_ESIGI) {
const id = crypto.randomUUID();
metin += `\n\n${JEV_DUZELTME_NOTU}`;
writer.write({ type: "text-start", id });
writer.write({ type: "text-delta", id, delta: JEV_DUZELTME_NOTU });
writer.write({ type: "text-end", id });
}
// Çıktı denetimi: cevap garanti/olasılık dili içeriyorsa sonuna
// düzeltme notu eklenir. İki bağımsız denetimden biri yeter: Jev
// (jev.ts; anahtar yoksa ya da zaman aşımında atlanır) ve anahtarsız
// regex (cikti-denetimi.ts; her cevapta koşar). Akış zaten gittiği
// için cümle ekrandan geri alınamaz; not hem ekrana hem kayda yazılır.
// Ek model çağrısı yok; kredi etkilenmez.
const vaatRegex = vaatDiliBul(metin);
const jevP = await cevapIhlalOlasiligi(metin);
const vaatNotu = vaatRegex.length > 0 || (jevP != null && jevP >= JEV_IHLAL_ESIGI);
console.info("[soru] çıktı denetimi: jev", jevP == null ? "atlandı" : jevP.toFixed(2), "regex", vaatRegex.length, vaatNotu ? "→ not eklendi" : "");
if (vaatNotu) {
const id = crypto.randomUUID();
metin += `\n\n${JEV_DUZELTME_NOTU}`;
writer.write({ type: "text-start", id });
writer.write({ type: "text-delta", id, delta: JEV_DUZELTME_NOTU });
writer.write({ type: "text-end", id });
}
opts.onDenetim?.({ jevP, vaatRegex, vaatNotu });
await opts.onTamam(metin);
tamamlandi = true;
writer.write({ type: "finish" });