RAG στην παραγωγή: chunking, retrieval και ειλικρινείς παραπομπές
Κόβετε τυφλά στους 512 χαρακτήρες και 4 από 32 απαντήσεις χάνονται πριν το retrieval. Μόνο το chunking φέρνει το rank 115 στο 3.
Σε αυτή τη σελίδα
Να μια πραγματική ερώτηση από πραγματικό χρήστη ενός πραγματικού assistant: το eval set μου έχει 20 στοιχεία, αρκεί για να εμπιστευτώ το score. Το σώμα κειμένων περιέχει την απάντηση — μια ολόκληρη ενότητά της. Αυτά είναι τα τέσσερα αποσπάσματα που ο retriever έβαλε πράγματι στο prompt.
[1] d=0.578 ship — that set has been used for fitting, and its score stops being
unbiased. Measured on this belt: sweeping the threshold on the
validation set picks 0.196, and the model then scores F1 = 0.4122…
[2] d=0.602 ng when the model is confidently **wrong**. Evaluate both at a few
scores, for an example whose true label is 1: | score | p | …
[3] d=0.613 ard and watch both numbers: | | reward model's score | true quality
| length produced | … The reward went up by a factor of 2.5. The…
[4] d=0.617 | 0.6 | +0.97 | +1.00 | +0.27 | … The reward model is working
perfectly. It has faithfully learned the preferences it was shown…Τρία από τα τέσσερα αρχίζουν στη μέση λέξης. Δύο είναι από διαφορετικό κεφάλαιο για διαφορετικό θέμα. Και το απόσπασμα που απαντά στην ερώτηση — αυτό που περιέχει το Seventeen out of twenty cannot distinguish an 85 % model from a 65 % one — επέστρεψε στο rank 115.
Τώρα η ίδια ερώτηση, το ίδιο embedding model, το ίδιο prompt template. Άλλαξε ένα πράγμα: πώς κόπηκαν τα έγγραφα.
[1] d=0.594 [Classification, Cross-Entropy… > How many test examples do I need?]
Read it backwards, which is how you will use it: ±5 points needs
about 200 examples. ±2 points needs about 1,230…
[2] d=0.598 [Classification, Cross-Entropy… > Three splits, and the leak…]
Why three splits and not two? Because the moment you use a set of
examples to *choose* anything…
[3] d=0.600 [Classification, Cross-Entropy… > How many test examples do I need?]
The honest reading of 17/20 is *somewhere between 64 % and 95 %*.
…Seventeen out of twenty cannot distinguish an 85 % model from a 65 % one.
[4] d=0.605 [Classification, Cross-Entropy… > How many test examples do I need?]
Suppose you score a model on 20 examples and it gets 17 right. You
report 85 %. …Wilson 95% CI : [0.6396, 0.9476]Από rank 115 σε rank 3. Κανείς δεν πείραξε το model, το prompt, το threshold ή τον αριθμό των slots. Αυτό το κεφάλαιο αφορά αυτό το χάσμα, και τα τέσσερα άλλα σημεία όπου ένα σύστημα retrieval σας λέει αθόρυβα ψέματα.
Εμφάνιση λεπτομερειών
Τι χρειάζεται αυτό το κεφάλαιο από τα προηγούμενα κεφάλαια, και το ένα σημείο όπου αλλάζει γλώσσα.
- Κεφάλαιο 1 όρισε το dot product και τη L2 norm. Η ενότητα για το threshold παρακάτω είναι αυτά τα δύο, και τίποτα άλλο.
- Κεφάλαιο 8 διαχώρισε τον embedding πίνακα ενός language model από ένα retrieval embedding model εκπαιδευμένο contrastively σε ζεύγη, μέτρησε cosine similarity, και έκλεισε υποσχόμενο ότι το Κεφάλαιο 19 θα έφτανε σε ένα συγκεκριμένο cut-off. Αυτή η υπόσχεση εξοφλείται εδώ. Τίποτα από αυτά δεν επαναλαμβάνεται.
- Κεφάλαιο 4 έχτισε το Wilson interval· Κεφάλαιο 15 έχτισε το evaluation harness. Κάθε πίνακας παρακάτω κουβαλά το πρώτο και παρήχθη από το δεύτερο.
- Κεφάλαιο 16 κοστολόγησε το context window. Το prompt που συναρμολογείται στο τέλος αυτού του κεφαλαίου κοστίζει 591 tokens, και αυτός είναι ο προϋπολογισμός για τον οποίο ανταγωνίζονται τα αποσπάσματα.
Όλα εδώ είναι TypeScript, όπως από το Κεφάλαιο 14, και αυτό το κεφάλαιο είναι εκεί όπου ο κανόνας δικαιώνεται: ingestion σημαίνει ουρές και αποθήκευση, search είναι network call, και η συναρμολόγηση ενός prompt με παραπομπές είναι δουλειά server. Η μέτρηση είναι ο ίδιος κώδικας με scoreboard γύρω του, επίτηδες — ένας retriever που βαθμολογείται από δεύτερη υλοποίηση είναι αριθμός για software που δεν στέλνετε, και το cosine threshold παρακάτω είναι πιστευτό μόνο επειδή το βλέπετε να σαρώνεται από τον chunker που θα τρέξει στην παραγωγή.
Το corpus, και τι μετρά ως σωστή απάντηση
Σύνδεσμος στην ενότητα: Το corpus, και τι μετρά ως σωστή απάντησηΌλα παρακάτω μετρώνται πάνω σε ένα corpus: τα πρώτα δεκατρία κεφάλαια αυτού του μαθήματος — 13 έγγραφα, 359.067 χαρακτήρες, 127 ενότητες, με αφαιρεμένα τα front matter και τις βιβλιογραφίες. Είναι ένα πραγματικό τεχνικό corpus, με πρόζα, πίνακες, τύπους και code blocks μέσα του, και είναι ακριβώς το είδος πράγματος που οι άνθρωποι φορτώνουν σε knowledge base και μετά παραπονιούνται.
Το ground truth είναι 32 ερωτήσεις, καθεμία συνδεδεμένη με μια βελόνα: μια σύντομη κατά λέξη πρόταση από το corpus που την απαντά. Κάθε βελόνα εμφανίζεται ακριβώς μία φορά στους 359.067 χαρακτήρες, και καμία δεν είναι heading ενότητας — αυτός ο έλεγχος έχει σημασία, επειδή ένας chunker που αντιγράφει headings σε κάθε chunk αλλιώς θα βαθμολογούσε τον εαυτό του. Κάθε ερώτηση τίθεται δύο φορές, μία στα αγγλικά του μαθήματος και μία όπως θα τη διατύπωνε ένα support ticket: 64 queries πάνω σε 32 ground truths.
Ένα retrieval είναι σωστό όταν ένα επιστρεφόμενο chunk περιέχει τη βελόνα ολόκληρη. Αυτός είναι ο μόνος ορισμός που ταιριάζει σε αυτό που χρειάζεται ο generator: μισή πρόταση στο prompt δεν είναι απάντηση, είναι κίνδυνος.
Το embedding model είναι all-MiniLM-L6-v2 — 384 διαστάσεις, mean-pooled και normalized, το contrastively trained model που μέτρησε το Κεφάλαιο 8. Η ευρετηρίαση του corpus παίρνει 20,8 δευτερόλεπτα σε CPU, 22 ms ανά chunk· το embedding ενός query παίρνει 13 ms.
Chunking, μετρημένο με έξι τρόπους
Σύνδεσμος στην ενότητα: Chunking, μετρημένο με έξι τρόπουςΈξι στρατηγικές από τρία ανεξάρτητα συστατικά. Blind κόβει κάθε 512 χαρακτήρες χωρίς να κοιτά το κείμενο. Boundaries δεν κόβει ποτέ μέσα σε παράγραφο, καταφεύγοντας σε όριο πρότασης μόνο όταν μια παράγραφος ξεπερνά τον προϋπολογισμό. Header προτάσσει σε κάθε chunk τον τίτλο του εγγράφου και το path της ενότητας. Overlap αντιγράφει τους τελευταίους 64 χαρακτήρες του προηγούμενου chunk στο επόμενο.
| strategy | chunks | answers destroyed | R@1 | R@4 | R@8 | R@20 | MRR |
|---|---|---|---|---|---|---|---|
| A blind 512 | 708 | 4 / 32 | 0.125 | 0.297 | 0.422 | 0.594 | 0.241 |
| B blind + overlap | 809 | 0 | 0.172 | 0.391 | 0.453 | 0.625 | 0.286 |
| C boundaries | 940 | 0 | 0.156 | 0.422 | 0.531 | 0.672 | 0.293 |
| D boundaries + overlap | 940 | 0 | 0.156 | 0.359 | 0.516 | 0.656 | 0.277 |
| E boundaries + header | 940 | 0 | 0.094 | 0.422 | 0.578 | 0.828 | 0.280 |
| F boundaries + header + overlap | 940 | 0 | 0.156 | 0.391 | 0.562 | 0.766 | 0.298 |
Με 64 queries, το 95 % Wilson interval στο R@20 είναι [0.471, 0.705] για το A και [0.718, 0.901] για το E — αυτά δεν επικαλύπτονται, αλλά οι περισσότερες άλλες στήλες επικαλύπτονται, και ένας unpaired πίνακας δεν μπορεί να τα ξεχωρίσει. Κάθε στρατηγική απαντά τα ίδια queries, άρα το τίμιο test είναι paired: μετρήστε τα wins και losses κάθε στρατηγικής απέναντι σε μια άλλη και τρέξτε sign test στα discordant pairs. Τρία αποτελέσματα το αντέχουν.
Το blind chunking καταστρέφει ολοκληρωτικά τέσσερις από τις τριάντα δύο απαντήσεις. Δεν τις κατατάσσει άσχημα — τις καταστρέφει. Η βελόνα διασχίζει όριο 512 χαρακτήρων, άρα κανένα chunk στο index δεν την περιέχει, και το recall ceiling για αυτά τα queries είναι μηδέν. Κανένα reranker δεν τις ανακτά, κανένα threshold δεν βοηθά, κανένα μεγαλύτερο model δεν βοηθά. Δεν μπορείτε να ανακτήσετε κείμενο που δεν υπάρχει ολόκληρο πουθενά στο index σας. Αυτή είναι η πιο υποαναφερόμενη αστοχία στο RAG, επειδή μοιάζει ακριβώς με κακό retriever.
Το overlap διορθώνει αυτό και τίποτα άλλο. Κάθε στρατηγική με overlap χάνει μηδέν απαντήσεις, που γι’ αυτό υπάρχει το overlap. Δεν βελτιώνει το ranking: το B απέναντι στο A στο R@8 είναι +8/−6, p = 0.79· στο R@20 είναι +9/−7, p = 0.80. Ακόμη χειρότερα, η προσθήκη overlap πάνω στο header βλάπτει ενεργά — το F απέναντι στο E είναι +2/−6 στο R@20 — και ο λόγος είναι μηχανικός. Το vector ενός chunk είναι μέσος όρος των tokens του, άρα 64 χαρακτήρες από το προηγούμενο chunk τραβούν αυτόν τον μέσο προς το θέμα του γείτονα. Το overlap είναι ασφάλεια απέναντι σε σπασμένη απάντηση, πληρωμένη σε precision.
Το contextual header είναι αυτό που αγοράζει retrieval. Το E απέναντι στο A είναι +18/−3 στο R@20, p = 0.0015. Και το ablation λέει ότι δεν το κάνουν τα boundaries: το E απέναντι στο C — ίδιες τομές, μόνο διαφορά το header — είναι +12/−2, p = 0.0129. Το να προτάξετε "Classification, Cross-Entropy, and How Not to Fool Yourself > How many test examples do I need?" σε μια παράγραφο λέει στο embedding model περί τίνος είναι η παράγραφος, κάτι που η ίδια η παράγραφος συχνά δεν λέει. Είναι resolver αντωνυμιών για έγγραφα.
Αυτό δίνει στον chunker το σχήμα του, και έναν κανόνα που είναι εύκολο να γίνει λάθος:
export interface Chunked {
/** What gets EMBEDDED: contextual header + this chunk's own content. */
text: string;
/** ONLY this chunk's own content: what is quoted back to the user. */
content: string;
section: string;
/** Character range in the document's canonical text. Sliceable. */
from: number;
to: number;
}
export function chunkDocument(doc: string, docTitle: string, target = 512): Chunked[] {
const out: Chunked[] = [];
const heads = [...doc.matchAll(/^## (.+)$/gm)].map((m) => ({ at: m.index!, title: m[1].trim() }));
const spans = heads.length
? heads.map((h, i) => ({ ...h, end: i + 1 < heads.length ? heads[i + 1].at : doc.length }))
: [{ at: 0, title: "", end: doc.length }];
for (const s of spans) {
const header = s.title ? `${docTitle} > ${s.title}` : docTitle;
const skip = /^## .+\n/.exec(doc.slice(s.at, s.end))?.[0].length ?? 0;
const body = doc.slice(s.at + skip, s.end);
const origin = s.at + skip;
// The offset is FOUND in the document, never accumulated: adding up
// lengths drifts by a character wherever a separator was normalised,
// and a citation anchor off by one points at the wrong line.
const emit = (from: number, to: number) => {
const raw = body.slice(from, to);
const lead = raw.length - raw.trimStart().length;
const content = raw.trim();
if (!content) return;
out.push({ text: `[${header}]\n${content}`, content, section: s.title,
from: origin + from + lead, to: origin + from + lead + content.length });
};
let open: [number, number] | null = null;
for (const m of body.matchAll(/[^\n]([^\n]|\n(?!\n))*/g)) { // paragraphs
const [pf, pt] = [m.index!, m.index! + m[0].length];
if (pt - pf > target) { // one huge paragraph
if (open) { emit(open[0], open[1]); open = null; }
let cur: [number, number] | null = null;
for (const sm of body.slice(pf, pt).matchAll(/[^.!?]*[.!?]*\s*/g)) {
if (!sm[0]) continue;
const [sf, st] = [pf + sm.index!, pf + sm.index! + sm[0].length];
if (cur && st - cur[0] > target) { emit(cur[0], cur[1]); cur = null; }
cur = cur ? [cur[0], st] : [sf, st];
}
if (cur) emit(cur[0], cur[1]);
continue;
}
if (open && pt - open[0] > target) { emit(open[0], open[1]); open = null; }
open = open ? [open[0], pt] : [pf, pt];
}
if (open) emit(open[0], open[1]);
}
return out;
}Δύο κείμενα, όχι ένα. text είναι αυτό που γίνεται embedded, με header και όλα. content είναι μόνο τα δικά του λόγια αυτού του chunk, και είναι αυτό που παρατίθεται πίσω στον χρήστη. Παραθέστε το text και η citation δείχνει header που δεν υπάρχει στο έγγραφο σε εκείνο το σημείο — και, με overlap, μια επαναλαμβανόμενη ουρά που ανήκει στο προηγούμενο απόσπασμα. Έπειτα εμφανίζει κείμενο που δεν βρίσκεται εκεί όπου λέει ότι βρίσκεται, κάτι χειρότερο από το να μην εμφανίζει τίποτα.
Το header δεν είναι δωρεάν. Στα 940 chunks κοστίζει 24.213 από τα 114.275 embedded tokens του index: 21,2 % αυτού που πληρώνετε για embedding είναι header που γράψατε εσείς. Επίσης σπρώχνει chunks προς το window του encoder. Το all-MiniLM-L6-v2 δέχεται 256 word-pieces· η στρατηγική E έχει 17 chunks πάνω από αυτή τη γραμμή και η F έχει 28, όλα σιωπηλά truncated χωρίς προειδοποίηση από πουθενά. Το effective chunk size σας δεν είναι ο αριθμός στο config σας — είναι το μικρότερο από εκείνον και το window του encoder σας.
Είκοσι γραμμές BM25, που όλοι προσπερνούν
Σύνδεσμος στην ενότητα: Είκοσι γραμμές BM25, που όλοι προσπερνούνΤο dense retrieval έχει μία συστηματική αδυναμία και δεν είναι λεπτή: ταιριάζει νόημα, άρα αδιαφορεί για το ποιο ακριβώς string πληκτρολογήσατε. Ένας κωδικός ανταλλακτικού, ένας κωδικός σφάλματος, ένα ακρωνύμιο, ένα επώνυμο — κανένα δεν έχει χρήσιμο νόημα για embedding, και ο nearest neighbour ενός κωδικού σφάλματος είναι κάθε άλλος κωδικός σφάλματος στο corpus σας.
Η κλασική απάντηση είναι παλιότερη από όλα αυτά και χωρά σε είκοσι γραμμές. BM25 βαθμολογεί ένα έγγραφο από το πόσο συχνά εμφανίζονται οι όροι του query σε αυτό, αποσβένοντας κάθε όρο όσο αυξάνεται η συχνότητά του και τιμωρώντας μακρά έγγραφα που συσσωρεύουν matches απλώς λόγω μήκους.1 Ο όρος συνεισφέρει
όπου είναι το πλήθος του όρου στο έγγραφο, το μήκος του, το μέσο μήκος, και και οι δύο συμβατικές σταθερές — ορίζει πόσο γρήγορα η επανάληψη σταματά να βοηθά, πόσο σκληρά τιμωρείται το μήκος.
const toks = (s: string) => s.toLowerCase().match(/[a-z0-9]+/g) ?? [];
export class BM25 {
private tf: Map<string, number>[] = [];
private len: number[] = [];
private idf = new Map<string, number>();
private avg = 0;
private k1: number; private b: number;
constructor(docs: string[], k1 = 1.2, b = 0.75) {
this.k1 = k1; this.b = b;
const df = new Map<string, number>();
for (const d of docs) {
const t = new Map<string, number>(); const ws = toks(d);
for (const w of ws) t.set(w, (t.get(w) ?? 0) + 1);
for (const w of t.keys()) df.set(w, (df.get(w) ?? 0) + 1);
this.tf.push(t); this.len.push(ws.length);
}
this.avg = this.len.reduce((a, b) => a + b, 0) / this.len.length;
const N = docs.length;
for (const [w, n] of df) this.idf.set(w, Math.log(1 + (N - n + 0.5) / (n + 0.5)));
}
scores(query: string): number[] {
const q = toks(query);
return this.tf.map((tf, i) => {
const L = this.len[i]; let s = 0;
for (const w of q) {
const f = tf.get(w); if (!f) continue;
s += (this.idf.get(w) ?? 0) * (f * (this.k1 + 1)) /
(f + this.k1 * (1 - this.b + (this.b * L) / this.avg));
}
return s;
});
}
}Πάνω σε 940 chunks, αυτό βαθμολογεί ένα query σε 1,14 ms χωρίς κανένα index πέρα από δύο hash maps. Και δεν είναι μουσειακό κομμάτι:
| retriever | R@1 | R@4 | R@8 | MRR | cost per query |
|---|---|---|---|---|---|
| dense (cosine) | 0.094 | 0.422 | 0.578 | 0.280 | 13 ms για embedding + 0,3 ms για scan |
| lexical (BM25) | 0.219 | 0.375 | 0.469 | 0.313 | 1,14 ms |
| hybrid (RRF) | 0.203 | 0.484 | 0.609 | 0.346 | και τα δύο |
| hybrid + cross-encoder | 0.312 | 0.578 | 0.703 | 0.447 | + 569 ms |
Το BM25 υπερδιπλασιάζει την top-1 ακρίβεια του dense retriever σε αυτό το corpus, και χάνει καθαρά από αυτόν έως το rank 8. Αποτυγχάνουν σε διαφορετικά queries, και αυτό είναι ολόκληρο το επιχείρημα για να τρέχετε και τα δύο.
Η συγχώνευσή τους είναι το ένα σημείο όπου η προφανής προσέγγιση είναι λάθος. Οι cosine distances και τα BM25 scores δεν είναι στην ίδια κλίμακα, δεν είναι bounded με τον ίδιο τρόπο, και η κανονικοποίησή τους ανά query κάνει το βάρος να εξαρτάται από το πόσο καλό έτυχε να είναι το καλύτερο hit. Το Reciprocal rank fusion πετά τα scores και κρατά μόνο τα ranks:2
/** Reciprocal rank fusion: ranks, not scores. Nothing to calibrate. */
export function rrf(lists: number[][], k = 60): number[] {
const acc = new Map<number, number>();
for (const list of lists)
list.forEach((id, r) => acc.set(id, (acc.get(id) ?? 0) + 1 / (k + r + 1)));
return [...acc.entries()].sort((a, b) => b[1] - a[1]).map(([id]) => id);
}Και εδώ η τίμια ανάγνωση του πίνακα έχει περισσότερη σημασία από τον πίνακα. Το hybrid κερδίζει το BM25 στο R@4 με +10/−3, p = 0.09. Κερδίζει το dense με +10/−6, p = 0.45. Σε αυτό το corpus, με 64 queries, το hybrid retrieval δεν διακρίνεται από το dense retrieval. Είναι καλύτερο και στα point estimates και σε κάθε στήλη recall, και τα evidence δεν φτάνουν σε significance. Σχεδόν κάθε blog post για hybrid search στο internet αναφέρει έναν πίνακα σαν τον παραπάνω και κανένα interval· αυτό λέει το interval.
Bi-encoder, cross-encoder, και πού βρίσκεται πραγματικά το lift
Σύνδεσμος στην ενότητα: Bi-encoder, cross-encoder, και πού βρίσκεται πραγματικά το liftΌλα μέχρι τώρα είναι bi-encoder: το query περνά από το model μόνο του, κάθε chunk πέρασε από αυτό μόνο του μήνες πριν, και τα δύο δεν συναντιούνται ποτέ παρά μόνο ως dot product. Αυτό κάνει ένα index δυνατό — κάνετε embed μία φορά, ξαναχρησιμοποιείτε για πάντα — και αυτό είναι επίσης το ταβάνι. Το model δεν κοιτά ποτέ το query και το chunk μαζί.
Ένας cross-encoder κάνει ακριβώς αυτό: παίρνει το ζεύγος ως ένα input και επιστρέφει relevance score. Τίποτα δεν μπορεί να προϋπολογιστεί, άρα δεν μπορεί να rankάρει index — αλλά μπορεί να rerankάρει shortlist. Το reranking των hybrid top 25 με ms-marco-MiniLM-L-6-v2 μετακινεί το R@1 από 0.094 (dense) σε 0.312 και το MRR από 0.280 σε 0.447: η μεγαλύτερη μεμονωμένη βελτίωση σε αυτό το κεφάλαιο, και η μόνη που αγγίζει την κορυφή της λίστας αντί για την ουρά.
Κοστίζει 569 ms ανά query σε CPU, έναντι 1,14 ms για BM25 και 0,3 ms για το vector scan. Περίπου δύο χιλιάδες φορές το κόστος retrieval, για είκοσι πέντε έγγραφα. Αυτό είναι όλο το tradeoff bi-encoder/cross-encoder σε έναν αριθμό, και γι’ αυτό η αρχιτεκτονική έχει πάντα το ίδιο σχήμα: φτηνός retriever με πλατύ recall, μετά ακριβός scorer πάνω σε shortlist που αντέχετε οικονομικά. Το ColBERT κάθεται ανάμεσα στα δύο, προϋπολογίζοντας per-token vectors και κάνοντας late interaction που είναι φθηνότερο από cross-encoder και πιο αιχμηρό από dot product.3
L2, cosine, και ένα threshold που δεν έχετε κερδίσει
Σύνδεσμος στην ενότητα: L2, cosine, και ένα threshold που δεν έχετε κερδίσειΟι vector databases αναφέρουν distances, και το ποια distance χρησιμοποιείται είναι επιλογή configuration. Σε normalized vectors η επιλογή είναι κοσμητική, και αξίζει να κάνουμε την ταυτότητα μία φορά επειδή όλα μετά εξαρτώνται από το αν τα vectors είναι πραγματικά unit. Για :
άρα η cosine distance είναι ακριβώς . Αυτό είναι το dot product και η norm του Κεφαλαίου 1, εξαργυρωμένα. Ελέγχθηκε σε δύο πραγματικά chunk vectors από το παραπάνω index, και έπειτα σε 40.000 ζεύγη:
||a|| = 1.000000 ||b|| = 1.000000
L2 = 0.795183 L2^2/2 = 0.316158 1 - cos = 0.316158 diff = 7.66e-08
max |L2^2/2 - (1 - cos)| over 200 x 200 pairs = 8.3e-07Ακριβές μέχρι τον θόρυβο floating-point — και μόνο επειδή τα vectors είναι normalized. Παραλείψτε την κανονικοποίηση και η ταυτότητα είναι ψευδής, το threshold σας δεν σημαίνει τίποτα, και η distance που αναφέρει ένα έγγραφο εξαρτάται από το πόσο μακρύ ήταν το κείμενό του.
Τώρα ο αριθμός που κανείς δεν παράγει. Ένας retriever πάντα επιστρέφει κάτι: ταξινομεί ολόκληρο το index και σας δίνει την κορυφή της λίστας, είτε η απάντηση υπάρχει κάπου στο corpus είτε όχι. Το threshold είναι το μόνο μέρος του συστήματος που μπορεί να πει όχι — και για να ορίσετε ένα, χρειάζεστε queries που πρέπει να μη φέρουν τίποτα πίσω. Εδώ είναι τριάντα: είκοσι ένα για πράγματα που αυτό το corpus πραγματικά δεν καλύπτει — streaming, rate limits, prompt caching, JSON schemas, agent loops, vector databases, prompt injection, image generation — και εννέα για παέγια, διαβατήρια και πολιτικές επιστροφών. Απέναντι στο ίδιο index:
| top-1 cosine distance | |
|---|---|
| in-domain queries, all 64 | mean 0.445, range 0.270 – 0.721 |
| in-domain, top-1 actually correct | mean 0.370 |
| in-domain, top-1 wrong | mean 0.452 |
| out-of-domain, all 30 | mean 0.699, range 0.497 – 0.867 |
Οι κατανομές χωρίζουν, και επικαλύπτονται. Το χειρότερο in-domain query είναι πιο μακριά από την απάντησή του (0.721) από ό,τι το καλύτερο out-of-domain query από μια άσχετη παράγραφο (0.497), άρα κανένα threshold δεν τα πετυχαίνει και τα δύο. Σαρώνοντάς το πάνω στην πραγματική πύλη — κρατήστε το πολύ τέσσερα chunks, και μόνο όσα είναι κάτω από το cut:
| threshold | in-domain answered | of which the answer was in | out-of-domain answered |
|---|---|---|---|
| 0.400 | 17 / 64 | 6 | 0 / 30 |
| 0.450 | 38 / 64 | 13 | 0 / 30 |
| 0.500 | 50 / 64 | 19 | 1 / 30 |
| 0.525 | 52 / 64 | 20 | 2 / 30 |
| 0.550 | 55 / 64 | 21 | 3 / 30 |
| 0.600 | 60 / 64 | 25 | 5 / 30 |
| 0.675 | 62 / 64 | 27 | 10 / 30 |
| 0.800 | 64 / 64 | 27 | 26 / 30 |
| none | 64 / 64 | 27 | 30 / 30 |
Διαβάστε την τελευταία στήλη ως μπλόφες. Χωρίς threshold, ο assistant παράγει μια σίγουρη, καλά cited απάντηση στο "how do I renew my Spanish passport" από ένα corpus για backpropagation, τριάντα φορές στις τριάντα. Στο 0.675 το κάνει δέκα φορές στις τριάντα. Στο 0.525 το κάνει δύο φορές, και εγκαταλείπει δώδεκα ερωτήσεις που θα μπορούσε να είχε απαντήσει.
Αυτό το tradeoff είναι απόφαση προϊόντος, και το σωστό άκρο του εξαρτάται από το τι σας κοστίζει μια λάθος απάντηση. Αυτό που δεν είναι διαπραγματεύσιμο είναι να υπάρχει καν η τελευταία στήλη. Αν δεν έχετε ποτέ μετρήσει τον retriever σας απέναντι σε ερωτήσεις που πρέπει να αρνηθεί, δεν έχετε threshold — έχετε έναν αριθμό.
Δύο από τις δέκα μπλόφες στο 0.675 δείχνουν τους δύο τρόπους με τους οποίους αποτυγχάνει.
query: "how much does prompt caching save on a long conversation"
[1] d=0.497 13-inference-optimization > Prefill and decode are two different machines
[2] d=0.532 13-inference-optimization > The cache is also the bill
query: "what is the capital of france"
[1] d=0.671 12-reasoning > The model does not think. It computes for longer.
"…it is why 'think step by step' does nothing for what is the capital of France."Η πρώτη είναι near miss: το corpus εξηγεί το KV cache λεπτομερώς, το query αφορά το prompt cache, οι λέξεις είναι οι ίδιες λέξεις, και το 0.497 είναι πιο κοντά από τις περισσότερες σωστές in-domain ανακτήσεις σε όλο το πείραμα. Ένα embedding δεν ξέρει ότι δύο caches με το ίδιο όνομα είναι διαφορετικές μηχανές. Η δεύτερη είναι literal match χωρίς απάντηση: το corpus περιέχει την ακριβή φράση "what is the capital of France", χρησιμοποιημένη ως παράδειγμα ερώτησης που δεν χρειάζεται reasoning. Ο retriever έχει δίκιο· η απάντηση δεν είναι εκεί. Οποιοδήποτε σύστημα διαβάζει το "βρήκα κάτι παρόμοιο" ως "βρήκα την απάντηση" θα ισχυριστεί το Παρίσι πάνω σε αυτά τα evidence — ή, χειρότερα, δεν θα το κάνει.
Γιατί το citation δεν γράφεται από το model
Σύνδεσμος στην ενότητα: Γιατί το citation δεν γράφεται από το modelΈνα model δεν έχει ξεχωριστή ικανότητα για facts. Το να παράγει μια αληθινή πρόταση και το να παράγει μια plausible πρόταση είναι η ίδια λειτουργία — η next-token prediction του Κεφαλαίου 8 — και τίποτα σε αυτή τη λειτουργία δεν σημειώνει ποιο είναι ποιο. Η ανάλυση του 2025 που το αναπλαισίωσε υποστηρίζει ότι το training και evaluation pipeline επιβραβεύει ενεργά την εικασία: τα benchmarks βαθμολογούν με binary accuracy και δεν δίνουν credit για abstention, άρα ένα model που απαντά πάντα υπερβαθμολογεί ένα ίδιο model που λέει "I don't know" όταν δεν ξέρει, και το post-training βελτιστοποιεί αναλόγως.6 Η hallucination σε αυτή την ανάγνωση δεν είναι μυστηριώδες ελάττωμα. Είναι αυτό που παίρνετε όταν βαθμολογείτε εξέταση multiple-choice χωρίς ποινή για λάθος απάντηση.
Δείτε το σχήμα της. Όταν ζητήθηκαν οκτώ papers για contrastive sentence embeddings, με identifiers, το Qwen2.5-0.5B-Instruct παρήγαγε οκτώ γραμμές σε τέλεια μορφή. Και οι οκτώ identifiers είναι well-formed. Και οι οκτώ οδηγούν σε πραγματικά papers στο arXiv. Μηδέν από τους οκτώ είναι το paper που ισχυρίζονται.
claimed arXiv:1907.06432 - Contrastive Sentence Embeddings for Text Retrieval
actual A Neural Turing~Machine for Conditional Transition Graph Modeling
claimed arXiv:1809.08669 - Contrastive Learning of Sentence Representations…
actual Collapsing Superstring Conjecture
claimed arXiv:1807.08669 - Contrastive Learning of Sentence Representations…
actual Automatic Speech Recognition for Humanitarian Applications in SomaliΑυτό είναι μικρό model και το rate είναι δικό του· ένα frontier model εφευρίσκει πολύ λιγότερα. Ο μηχανισμός γενικεύεται, και είναι ο λόγος για τον κανόνα που ακολουθεί. Ένας validator που ελέγχει "υπάρχει αυτός ο identifier" περνά και τους οκτώ, και ένας χρήστης που κάνει κλικ σε έναν φτάνει σε πραγματική σελίδα από πραγματικό archive χωρίς τρόπο να καταλάβει ότι η αντιστοίχιση εφευρέθηκε. Η αστοχία δεν είναι στον identifier ή στη μορφή. Είναι στη συσχέτιση — ακριβώς αυτό που ένα language model παράγει με plausibility.
Άρα: το model γράφει [1] και [2], και ποτέ δεν γράφει το link. Οι αριθμοί αναφέρονται σε αποσπάσματα που ανέκτησε ο server, και ο server — που ξέρει ακριβώς από ποιο έγγραφο και ποια offsets προήλθε κάθε αριθμός — επισυνάπτει μετά το έγγραφο, το label και το URL. Δεν υπάρχει τίποτα για να εφεύρει το model επειδή δεν του ζητείται ποτέ το ένα πράγμα που θα εφεύρισκε.
export function buildContext(question: string, hits: Scored[]) {
const citations: Citation[] = hits.map((h, i) => ({
index: i + 1,
documentId: h.chunk.documentId,
documentName: h.chunk.documentName,
locatorLabel: label(h.chunk),
fragment: `#char=${h.chunk.locator.flow.from},${h.chunk.locator.flow.to}`,
quote: h.chunk.content, // the OWN content, never `text`
cosineDistance: h.cosineDistance,
}));
const blocks = citations
.map((c) => `[${c.index}] ${c.documentName} - ${c.locatorLabel}\n${c.quote}`)
.join("\n\n");
const prompt =
`Answer using ONLY the numbered sources below. Cite every claim as [n].\n` +
`If the sources do not contain the answer, say so and stop.\n\n` +
`SOURCES\n${blocks}\n\nQUESTION\n${question}`;
return { prompt, citations };
}Τρέξτε το στην αρχική ερώτηση και τα τέσσερα chunks γίνονται prompt 591-token και ένας πίνακας που το model δεν βλέπει ποτέ:
[1] 04-classification How many test examples do I need? #char=28215,28701 d=0.594
[2] 04-classification Three splits, and the leak… #char=20329,20839 d=0.598
[3] 04-classification How many test examples do I need? #char=25873,26272 d=0.600
[4] 04-classification How many test examples do I need? #char=25554,25871 d=0.605Ο locator είναι το μέρος που οι άνθρωποι προσπερνούν και μετά δεν μπορούν να προσθέσουν αργότερα. Το #char=25873,26272 είναι range στο canonical text του εγγράφου· για PDF το ισοδύναμο είναι #page=12, για audio ή video #t=132.4,158.9, για spreadsheet ένα sheet και A1 range. Αυτά τα δύο δεν είναι εφευρέσεις — το #page= είναι PDF Open Parameters και το #t= είναι W3C Media Fragments, που υποστηρίζονται native από browsers σε video και audio elements. Citation χωρίς locator είναι όνομα εγγράφου, και όνομα εγγράφου δεν είναι citation· είναι πρόταση στον χρήστη να πάει να ψάξει.
Και όταν τίποτα δεν περνά το threshold, το pipeline δεν φτάνει ποτέ στο model:
NO ANSWER: nothing under cosine distance 0.675 for "what is the offside rule in football"
NO ANSWER: nothing under cosine distance 0.675 for "how do i renew my spanish passport"
NO ANSWER: nothing under cosine distance 0.675 for "how do i build an agent loop with tools"Αυτή είναι φθηνότερη και πιο αξιόπιστη άρνηση από οποιαδήποτε οδηγία σε system prompt, επειδή είναι σύγκριση ανάμεσα σε δύο αριθμούς αντί για αίτημα προς ένα probabilistic system.
Αξιολογήστε τον retriever χωριστά από τον generator
Σύνδεσμος στην ενότητα: Αξιολογήστε τον retriever χωριστά από τον generatorΚάθε μέτρηση σε αυτό το κεφάλαιο βαθμολογεί τον retriever και ούτε μία φορά δεν ζητά από model να γράψει απάντηση. Αυτό είναι σκόπιμο, και είναι το κομμάτι που οι περισσότερες ομάδες προσπερνούν.
Ένα σύστημα RAG έχει δύο failure modes που μοιάζουν ίδια από έξω. Ο retriever δεν βρήκε το passage· ή το βρήκε και ο generator το αγνόησε, το αντέκρουσε, ή το ανακάτεψε με κάτι που ήδη πίστευε. Βαθμολογήστε μόνο την τελική απάντηση και τα δύο δεν ξεχωρίζουν, άρα ρυθμίζετε prompts απέναντι σε πρόβλημα που ζει στον chunker σας. Recall@k, MRR και το answer-destroyed count δεν χρειάζονται καθόλου generation call, είναι αρκετά φθηνά για να τρέχουν σε κάθε deploy, και είναι το harness από το Κεφάλαιο 15 με διαφορετική scoring function — το ίδιο request, deadline, concurrency και tally, πάνω σε fixed question set αντί για live conversation.
Αναφέρετέ τα με intervals. Η αριθμητική του Κεφαλαίου 4 εφαρμόζεται αμετάβλητη: στα 64 queries, recall 0.5 κουβαλά 95 % Wilson interval περίπου ±0.12, άρα μια στρατηγική τέσσερις μονάδες μπροστά από μια άλλη δεν σας έχει πει τίποτα. Χρησιμοποιήστε το paired test όποτε και οι δύο στρατηγικές απαντούν τις ίδιες ερωτήσεις, όπως κάνουν πάντα εδώ — αυτό μετέτρεψε το "το E φαίνεται καλύτερο από το A" σε p = 0.0015.
Και η τελευταία ειλικρίνεια: Το RAG μειώνει την hallucination και δεν την αφαιρεί. Το να βάλετε το σωστό passage στο prompt δεν υποχρεώνει το model να το χρησιμοποιήσει, και η βιβλιογραφία το λέει από το αρχικό paper.7 Δύο πράγματα το χειροτερεύουν στην παραγωγή. Τα μεγάλα contexts υποβαθμίζονται — ένα model βρίσκει πληροφορίες στην αρχή και το τέλος ενός μεγάλου prompt πιο αξιόπιστα από ό,τι στη μέση, άρα είκοσι chunks αντί για τέσσερα μπορούν να μειώσουν την ακρίβεια ενώ αυξάνουν τον λογαριασμό, ένα effect που μετριέται στο Κεφάλαιο 24. Και το retrieval μπορεί να είναι σωστό και πάλι ανεπαρκές, όπως έδειξαν τα δύο caches παραπάνω. Το SelfCheckGPT επισημαίνει claims που δεν επιβιώνουν από resampling·8 το Self-RAG εκπαιδεύει το model να εκπέμπει τα δικά του retrieve-and-critique tokens·9 το TruthfulQA έκανε το failure mode αναγνώσιμο εξαρχής.10 Κανένα δεν κλείνει το χάσμα, και ένα σύστημα που παρουσιάζει retrieved text ως απόδειξη έχει μπερδέψει το sourced με το true.
Το μισό σύστημα που τρέχει πριν από οποιοδήποτε query
Σύνδεσμος στην ενότητα: Το μισό σύστημα που τρέχει πριν από οποιοδήποτε queryΈνας retriever είναι το ορατό μέρος ενός pipeline του οποίου όλες οι αστοχίες συμβαίνουν νωρίτερα, στο σκοτάδι. Τρεις επαναλαμβάνονται.
Το extraction είναι εκεί όπου πεθαίνει το περιεχόμενο. Ένα PDF δεν είναι κείμενο· είναι οδηγίες σχεδίασης. Two-column layouts μπλέκονται μεταξύ τους, οι πίνακες γίνονται word soup, τα page headers επαναλαμβάνονται σε κάθε chunk, και μια σκαναρισμένη σελίδα δεν έχει καθόλου κείμενο μέχρι το OCR να της δώσει, με confidence. Όλα όσα μετρήθηκαν παραπάνω υπέθεσαν ότι ο extractor έκανε τη δουλειά του· στην παραγωγή συχνά δεν την κάνει, και το σύμπτωμα εμφανίζεται ως κακό retrieval τρία layers μακριά.
Το index σφραγίζεται με το model που το έχτισε. Embeddings από δύο models δεν είναι συγκρίσιμα — όχι "λιγότερο ακριβή", μη συγκρίσιμα, επειδή είναι σημεία σε διαφορετικούς χώρους. Αλλάξτε το embedding model και κάθε vector στο store είναι σκουπίδι μέχρι να ξαναχτιστεί. Άρα το model name, το dimension count, το pipeline version και το extractor version γράφονται δίπλα σε κάθε έγγραφο τη στιγμή της ευρετηρίασης. Χωρίς αυτά, την ημέρα του upgrade, δεν μπορείτε να καταλάβετε ποια έγγραφα είναι stale και ποια current, και ένα μισομεταναστευμένο index επιστρέφει σίγουρες ανοησίες χωρίς κανένα error πουθενά.
Ένα χαλασμένο έγγραφο δεν πρέπει να χαλάει τον φάκελο, και οι counters πρέπει να μετρούν τι συνέβη. Ένα έγγραφο που αποτυγχάνει στο extraction καταλήγει σε κατάσταση failed με τον λόγο του, ορατή και retryable, ενώ τα άλλα ενενήντα εννέα μένουν searchable· και ο αριθμός των chunks που έγιναν indexed γράφεται από τον server όταν τελειώσει, όχι δηλώνεται από τον client όταν ανεβάζει. Ένας φάκελος που αναφέρει 400 fragments και κρατά 40 είναι ψέμα που εμφανίζεται μόνο ως αναπάντητη ερώτηση.
Πού πάει αυτό μετά
Σύνδεσμος στην ενότητα: Πού πάει αυτό μετάΤο σύστημα σε αυτό το κεφάλαιο απαντά ερωτήσεις των οποίων οι απαντήσεις είναι γραμμένες. Τις ανακτά, τις κατατάσσει, αρνείται όταν δεν μπορεί, και παραθέτει πού κοίταξε. Αυτό είναι το μεγαλύτερο μέρος αυτού που θέλει ο κόσμος από έναν assistant πάνω στα δικά του έγγραφα, και οριοθετείται με έναν συγκεκριμένο τρόπο: το retrieval μπορεί να επιστρέψει μόνο αυτό που κάποιος έγραψε.
Που αφήνει το άλλο μισό. Κάποια από όσα θέλετε να κάνει ένα model δεν είναι καθόλου fact σε έγγραφο — μια μορφή που πρέπει να κρατήσει, ένας τόνος, μια ταξινομία με τετρακόσια labels, ένας τρόπος απόφασης που ζει σε δέκα χιλιάδες παλιά παραδείγματα και σε καμία παράγραφο πουθενά. Το retrieval δεν μπορεί να τα παραδώσει, επειδή δεν υπάρχει τίποτα για ανάκτηση· ένα μεγαλύτερο prompt απλώς πληρώνει τον λογαριασμό του Κεφαλαίου 16 για περιγραφή ενός skill αντί για το skill.
Το Κεφάλαιο 20 είναι αυτή η απόφαση — fine-tune, retrieve ή prompt — και το εύρημά του είναι ότι η απόφαση είναι οικονομική πριν γίνει τεχνική: και τα τρία κοστολογούνται end to end στην ίδια ερώτηση, και το crossover είναι token count. Η ερώτηση που το ανοίγει είναι αυτή που αυτό το κεφάλαιο δεν μπορεί να απαντήσει. Όχι πού είναι γραμμένη η απάντηση, αλλά τι κάνετε όταν δεν γράφτηκε ποτέ.
Πηγές και μέθοδος
Σύνδεσμος στην ενότητα: Πηγές και μέθοδοςΌλα όσα μετρήθηκαν σε αυτό το κεφάλαιο χρησιμοποίησαν ένα corpus και ένα όργανο, και και τα δύο είναι reproducible. Το corpus είναι τα κεφάλαια 1 έως 13 αυτού του μαθήματος όπως υπήρχαν στις 7 Σεπτεμβρίου 2026 — 13 έγγραφα, 359.067 χαρακτήρες, 127 ενότητες, αφαιρέθηκαν front matter και βιβλιογραφίες. Εκείνα τα κεφάλαια συνεχίζουν να γίνονται edited, άρα η εφαρμογή του ίδιου κανόνα σήμερα μετρά μερικές χιλιάδες χαρακτήρες παραπάνω: το section count είναι αμετάβλητο και το ίδιο κάθε συμπέρασμα παρακάτω, αλλά το σύνολο χαρακτήρων είναι snapshot και χαρακτηρίζεται ως τέτοιο. Το ground truth είναι 32 ερωτήσεις, καθεμία paired με κατά λέξη πρόταση που εμφανίζεται ακριβώς μία φορά στο corpus και δεν είναι ποτέ section heading, διατυπωμένη με δύο τρόπους για 64 queries. Τα retrieval embeddings είναι sentence-transformers/all-MiniLM-L6-v2 (384 διαστάσεις, mean-pooled, L2-normalized, 256-token window)· το reranking είναι cross-encoder/ms-marco-MiniLM-L-6-v2 πάνω στα top 25· το παράδειγμα generation είναι Qwen/Qwen2.5-0.5B-Instruct με greedy decoding. Όλοι οι χρόνοι είναι single-threaded CPU. Δεν κλήθηκε paid API για να παραχθεί αυτό το κεφάλαιο, και γι’ αυτό κάθε latency εδώ είναι local και χαρακτηρίζεται ως τέτοιο.
Ο chunker που φαίνεται σε TypeScript είναι ο chunker που μετρήθηκε: το Python instrument που υλοποιεί τον ίδιο κανόνα και το ts/chunk.ts συγκρίθηκαν chunk προς chunk σε όλο το corpus και συμφωνούν και στα 940 chunks, τόσο στα κείμενα όσο και στα offsets. Τα intervals είναι Wilson στο 95 %· οι paired comparisons είναι two-sided exact sign tests στα discordant pairs.
Και οι δεκατέσσερις identifiers που παρατίθενται παραπάνω επιλύθηκαν απέναντι στο arXiv API και ελέγχθηκαν τίτλο προς τίτλο στις 7 Σεπτεμβρίου 2026 — κάτι που, δεδομένων των οκτώ που δεν ήταν, φάνηκε ως το ελάχιστο που μπορούσε να κάνει το συγκεκριμένο κεφάλαιο.
Παραπομπές
Σύνδεσμος στην ενότητα: Παραπομπές-
Robertson, S. and Zaragoza, H. The Probabilistic Relevance Framework: BM25 and Beyond. Foundations and Trends in Information Retrieval 3(4), pp. 333–389 (2009). Η πηγή της saturation function και των δύο σταθερών που χρησιμοποιούνται παραπάνω, και το σημείο για να διαβάσετε γιατί υπάρχει καν το . ↩
-
Cormack, G. V., Clarke, C. L. A. and Büttcher, S. Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning Methods. SIGIR 2009. Το είναι δικό τους, και το νόημα της μεθόδου είναι ότι δεν χρειάζεται calibration ανάμεσα στις score scales που συγχωνεύει. ↩
-
Khattab, O. and Zaharia, M. ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT. arXiv:2004.12832 (2020). Η μέση λύση ανάμεσα σε dot product και cross-encoder. Reimers, N. and Gurevych, I., Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks, arXiv:1908.10084 (2019), είναι ο bi-encoder πάνω στον οποίο χτίστηκε το index αυτού του κεφαλαίου και μετρήθηκε στο Κεφάλαιο 8. ↩
-
Malkov, Yu. A. and Yashunin, D. A. Efficient and Robust Approximate Nearest Neighbor Search using Hierarchical Navigable Small World Graphs. arXiv:1603.09320 (2016). Το graph index πίσω από τις περισσότερες vector databases που πωλούνται σήμερα. ↩
-
Johnson, J., Douze, M. and Jégou, H. Billion-scale Similarity Search with GPUs. arXiv:1702.08734 (2017). FAISS, και η reference implementation του IVF που μετρήθηκε στο παραπάνω πλαίσιο. ↩
-
Kalai, A. T., Nachum, O., Vempala, S. S. and Zhang, E. Why Language Models Hallucinate. arXiv:2509.04664 (2025). Το επιχείρημα ότι η hallucination παράγεται από binary-accuracy grading που δεν επιβραβεύει ποτέ abstention, και επομένως είναι πρόβλημα evaluation πριν γίνει modelling problem. ↩
-
Lewis, P., Perez, E., Piktus, A., Petroni, F., Karpukhin, V., Goyal, N., Küttler, H., Lewis, M., Yih, W., Rocktäschel, T., Riedel, S. and Kiela, D. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. arXiv:2005.11401 (2020). Το paper που ονόμασε το pattern και αυτό που πρέπει να διαβάσετε για το τι διορθώνει και τι δεν διορθώνει. Guu et al., REALM: Retrieval-Augmented Language Model Pre-Training, arXiv:2002.08909 (2020), είναι η σύγχρονη εργασία που εκπαιδεύει τον retriever από κοινού με το model αντί να τον κουμπώνει απ’ έξω· Karpukhin et al., Dense Passage Retrieval for Open-Domain Question Answering, arXiv:2004.04906 (2020), είναι από όπου προέρχεται ο two-encoder dense retriever που χρησιμοποιείται σε όλο αυτό το κεφάλαιο· και Izacard and Grave, Leveraging Passage Retrieval with Generative Models for Open Domain Question Answering, arXiv:2007.01282 (2020), είναι η fusion-in-decoder διάταξη για τροφοδότηση πολλών passages σε έναν generator. Gao et al., Retrieval-Augmented Generation for Large Language Models: A Survey, arXiv:2312.10997 (2023), είναι ο χάρτης όλων όσων ήρθαν μετά, συμπεριλαμβανομένου του HyDE (Gao et al., Precise Zero-Shot Dense Retrieval without Relevance Labels, arXiv:2212.10496, 2022), που κάνει embed μια υποθετική απάντηση αντί για την ερώτηση. ↩
-
Manakul, P., Liusie, A. and Gales, M. J. F. SelfCheckGPT: Zero-Resource Black-Box Hallucination Detection for Generative Large Language Models. arXiv:2303.08896 (2023). Detection με resampling, χωρίς πρόσβαση στα internals του model και χωρίς external knowledge base. ↩
-
Asai, A., Wu, Z., Wang, Y., Sil, A. and Hajishirzi, H. Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection. arXiv:2310.11511 (2023). Training του model ώστε να αποφασίζει πότε να retrieve, αντί να γίνεται retrieval σε κάθε turn. ↩
-
Lin, S., Hilton, J. and Evans, O. TruthfulQA: Measuring How Models Mimic Human Falsehoods. arXiv:2109.07958 (2021). Το benchmark χτισμένο από ερωτήσεις όπου η plausible απάντηση και η true απάντηση διαφέρουν, που είναι όλη η δυσκολία σε μία πρόταση. ↩