Μετάβαση στο περιεχόμενο
19/30Κεφάλαιο 19 από 30

RAG στην παραγωγή: chunking, retrieval και ειλικρινείς παραπομπές

Κόβετε τυφλά στους 512 χαρακτήρες και 4 από 32 απαντήσεις χάνονται πριν το retrieval. Μόνο το chunking φέρνει το rank 115 στο 3.

Σε αυτή τη σελίδα

Να μια πραγματική ερώτηση από πραγματικό χρήστη ενός πραγματικού assistant: το eval set μου έχει 20 στοιχεία, αρκεί για να εμπιστευτώ το score. Το σώμα κειμένων περιέχει την απάντηση — μια ολόκληρη ενότητά της. Αυτά είναι τα τέσσερα αποσπάσματα που ο retriever έβαλε πράγματι στο prompt.

four fragments, chunked blind at 512 charactersTEXT
[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. Άλλαξε ένα πράγμα: πώς κόπηκαν τα έγγραφα.

four fragments, cut on section boundaries with a contextual headerTEXT
[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: τα πρώτα δεκατρία κεφάλαια αυτού του μαθήματος — 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.

Έξι στρατηγικές από τρία ανεξάρτητα συστατικά. Blind κόβει κάθε 512 χαρακτήρες χωρίς να κοιτά το κείμενο. Boundaries δεν κόβει ποτέ μέσα σε παράγραφο, καταφεύγοντας σε όριο πρότασης μόνο όταν μια παράγραφος ξεπερνά τον προϋπολογισμό. Header προτάσσει σε κάθε chunk τον τίτλο του εγγράφου και το path της ενότητας. Overlap αντιγράφει τους τελευταίους 64 χαρακτήρες του προηγούμενου chunk στο επόμενο.

strategychunksanswers destroyedR@1R@4R@8R@20MRR
A blind 5127084 / 320.1250.2970.4220.5940.241
B blind + overlap80900.1720.3910.4530.6250.286
C boundaries94000.1560.4220.5310.6720.293
D boundaries + overlap94000.1560.3590.5160.6560.277
E boundaries + header94000.0940.4220.5780.8280.280
F boundaries + header + overlap94000.1560.3910.5620.7660.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 το σχήμα του, και έναν κανόνα που είναι εύκολο να γίνει λάθος:

chunk.tsTS
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 σας.

Το dense retrieval έχει μία συστηματική αδυναμία και δεν είναι λεπτή: ταιριάζει νόημα, άρα αδιαφορεί για το ποιο ακριβώς string πληκτρολογήσατε. Ένας κωδικός ανταλλακτικού, ένας κωδικός σφάλματος, ένα ακρωνύμιο, ένα επώνυμο — κανένα δεν έχει χρήσιμο νόημα για embedding, και ο nearest neighbour ενός κωδικού σφάλματος είναι κάθε άλλος κωδικός σφάλματος στο corpus σας.

Η κλασική απάντηση είναι παλιότερη από όλα αυτά και χωρά σε είκοσι γραμμές. BM25 βαθμολογεί ένα έγγραφο από το πόσο συχνά εμφανίζονται οι όροι του query σε αυτό, αποσβένοντας κάθε όρο όσο αυξάνεται η συχνότητά του και τιμωρώντας μακρά έγγραφα που συσσωρεύουν matches απλώς λόγω μήκους.1 Ο όρος tt συνεισφέρει

idf(t)ft,d(k1+1)ft,d+k1(1b+bdd)\mathrm{idf}(t)\cdot\frac{f_{t,d}\,(k_1+1)}{f_{t,d} + k_1\left(1 - b + b\,\frac{|d|}{\overline{|d|}}\right)}

όπου ft,df_{t,d} είναι το πλήθος του όρου στο έγγραφο, d|d| το μήκος του, d\overline{|d|} το μέσο μήκος, και k1=1.2k_1 = 1.2 και b=0.75b = 0.75 οι δύο συμβατικές σταθερές — k1k_1 ορίζει πόσο γρήγορα η επανάληψη σταματά να βοηθά, bb πόσο σκληρά τιμωρείται το μήκος.

bm25.tsTS
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. Και δεν είναι μουσειακό κομμάτι:

retrieverR@1R@4R@8MRRcost per query
dense (cosine)0.0940.4220.5780.28013 ms για embedding + 0,3 ms για scan
lexical (BM25)0.2190.3750.4690.3131,14 ms
hybrid (RRF)0.2030.4840.6090.346και τα δύο
hybrid + cross-encoder0.3120.5780.7030.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

RRF(d)=lists1k+rank(d),k=60\mathrm{RRF}(d) = \sum_{\text{lists}} \frac{1}{k + \mathrm{rank}(d)}, \qquad k = 60
retrieve.tsTS
/** 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

Οι vector databases αναφέρουν distances, και το ποια distance χρησιμοποιείται είναι επιλογή configuration. Σε normalized vectors η επιλογή είναι κοσμητική, και αξίζει να κάνουμε την ταυτότητα μία φορά επειδή όλα μετά εξαρτώνται από το αν τα vectors είναι πραγματικά unit. Για a=b=1\lVert a \rVert = \lVert b \rVert = 1:

ab2=a2+b22ab=22cosθ\lVert a - b \rVert^2 = \lVert a \rVert^2 + \lVert b \rVert^2 - 2\,a \cdot b = 2 - 2\cos\theta

άρα η cosine distance 1cosθ1 - \cos\theta είναι ακριβώς d2/2d^2/2. Αυτό είναι το dot product και η norm του Κεφαλαίου 1, εξαργυρωμένα. Ελέγχθηκε σε δύο πραγματικά chunk vectors από το παραπάνω index, και έπειτα σε 40.000 ζεύγη:

TEXT
||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 64mean 0.445, range 0.270 – 0.721
in-domain, top-1 actually correctmean 0.370
in-domain, top-1 wrongmean 0.452
out-of-domain, all 30mean 0.699, range 0.497 – 0.867

Οι κατανομές χωρίζουν, και επικαλύπτονται. Το χειρότερο in-domain query είναι πιο μακριά από την απάντησή του (0.721) από ό,τι το καλύτερο out-of-domain query από μια άσχετη παράγραφο (0.497), άρα κανένα threshold δεν τα πετυχαίνει και τα δύο. Σαρώνοντάς το πάνω στην πραγματική πύλη — κρατήστε το πολύ τέσσερα chunks, και μόνο όσα είναι κάτω από το cut:

thresholdin-domain answeredof which the answer was inout-of-domain answered
0.40017 / 6460 / 30
0.45038 / 64130 / 30
0.50050 / 64191 / 30
0.52552 / 64202 / 30
0.55055 / 64213 / 30
0.60060 / 64255 / 30
0.67562 / 642710 / 30
0.80064 / 642726 / 30
none64 / 642730 / 30

Διαβάστε την τελευταία στήλη ως μπλόφες. Χωρίς threshold, ο assistant παράγει μια σίγουρη, καλά cited απάντηση στο "how do I renew my Spanish passport" από ένα corpus για backpropagation, τριάντα φορές στις τριάντα. Στο 0.675 το κάνει δέκα φορές στις τριάντα. Στο 0.525 το κάνει δύο φορές, και εγκαταλείπει δώδεκα ερωτήσεις που θα μπορούσε να είχε απαντήσει.

Αυτό το tradeoff είναι απόφαση προϊόντος, και το σωστό άκρο του εξαρτάται από το τι σας κοστίζει μια λάθος απάντηση. Αυτό που δεν είναι διαπραγματεύσιμο είναι να υπάρχει καν η τελευταία στήλη. Αν δεν έχετε ποτέ μετρήσει τον retriever σας απέναντι σε ερωτήσεις που πρέπει να αρνηθεί, δεν έχετε threshold — έχετε έναν αριθμό.

Δύο από τις δέκα μπλόφες στο 0.675 δείχνουν τους δύο τρόπους με τους οποίους αποτυγχάνει.

the two shapes of a confident wrong retrievalTEXT
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 — ή, χειρότερα, δεν θα το κάνει.

Ένα 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 που ισχυρίζονται.

8 references, checked one by one against the arXiv APITEXT
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 επειδή δεν του ζητείται ποτέ το ένα πράγμα που θα εφεύρισκε.

prompt.tsTS
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 δεν βλέπει ποτέ:

TEXT
[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:

TEXT
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 και ούτε μία φορά δεν ζητά από 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 — κάτι που, δεδομένων των οκτώ που δεν ήταν, φάνηκε ως το ελάχιστο που μπορούσε να κάνει το συγκεκριμένο κεφάλαιο.

  1. 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 και των δύο σταθερών που χρησιμοποιούνται παραπάνω, και το σημείο για να διαβάσετε γιατί υπάρχει καν το bb.

  2. Cormack, G. V., Clarke, C. L. A. and Büttcher, S. Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning Methods. SIGIR 2009. Το k=60k = 60 είναι δικό τους, και το νόημα της μεθόδου είναι ότι δεν χρειάζεται calibration ανάμεσα στις score scales που συγχωνεύει.

  3. 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.

  4. 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 που πωλούνται σήμερα.

  5. Johnson, J., Douze, M. and Jégou, H. Billion-scale Similarity Search with GPUs. arXiv:1702.08734 (2017). FAISS, και η reference implementation του IVF που μετρήθηκε στο παραπάνω πλαίσιο.

  6. 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.

  7. 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 μια υποθετική απάντηση αντί για την ερώτηση.

  8. 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.

  9. 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.

  10. Lin, S., Hilton, J. and Evans, O. TruthfulQA: Measuring How Models Mimic Human Falsehoods. arXiv:2109.07958 (2021). Το benchmark χτισμένο από ερωτήσεις όπου η plausible απάντηση και η true απάντηση διαφέρουν, που είναι όλη η δυσκολία σε μία πρόταση.


Δημιουργήθηκε από

David Vicente Campos

Ιδρυτής της NeuraLIA Labs & συνιδρυτής του MyRealFood

Είμαι μηχανικός πληροφορικής, απόφοιτος του Πανεπιστημίου Λεόν. Συνίδρυσα το MyRealFood, όπου ως CTO έφτιαξα την εφαρμογή που έχουν χρησιμοποιήσει εκατομμύρια άνθρωποι για να τρώνε καλύτερα, και ίδρυσα τη NeuraLIA Labs, όπου δημιουργώ προϊόντα AI. Εδώ γράφω για όσα χρειάστηκε να κατανοήσω στην πορεία, όπως θα ήθελα να μου τα είχε εξηγήσει κάποιος.

Περισσότερα για τον συγγραφέα

Δημοσιεύτηκε από τη NeuraLIA Labs.

Λάβετε νέες αναρτήσεις στα εισερχόμενά σας

Νέα για AI, οδηγοί και ενημερώσεις προϊόντος — ένα σύντομο email όταν δημοσιεύουμε κάτι που αξίζει τον χρόνο σας.

Ευρετήριο μαθήματος

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev13 λεπτά ανάγνωσης

Το μοντέλο AI Jev είναι φτιαγμένο για αποφάσεις, όχι για πρόζα

Το Jev της TypeSafe AI τραβά την προσοχή επειδή αντιμετωπίζει την ευφυΐα στο λογισμικό ως πρόβλημα πιθανοτήτων: επιλέξτε το σωστό κλαδί, προσθέστε βεβαιότητα και αποφύγετε να πληρώνετε ένα LLM για να γράφει κείμενο όταν ο κώδικας χρειάζεται μια απόφαση.

Abstract legal research workspace with documents, search nodes and governance controls.
openai12 λεπτά ανάγνωσης

Το Astra for Law της OpenAI είναι νομικό σύστημα AI, όχι νέο μοντέλο

Το νομικό λανσάρισμα της OpenAI αφορά λιγότερο ένα νέο θεμελιώδες μοντέλο και περισσότερο το σύστημα γύρω από αυτό: ανάκτηση ανά τομέα, αξιόπιστα εργαλεία, δικαιώματα, benchmarks και διαδρομές ελέγχου.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering12 λεπτά ανάγνωσης

Context engineering for long-horizon AI agents

Long-running agents do not fail only because the window is small. They fail when files, tool outputs and stale history crowd out the task the agent was supposed to finish.

Έτοιμοι να αφήσετε τη LIA να επιλέγει;

Δημιουργήστε με κάθε μοντέλο AI σε ένα σημείο — ξεκινήστε δωρεάν σήμερα.