ហេតុអ្វីបានជា Model Hallucinate

មាតិកា

  1. ចម្លើយខុសដែលមានទំនុកចិត្ត
  2. ហេតុអ្វីបានជាកើតឡើង៖ ទំនងជាពិត មិនមែនពិត
  3. កង្វះ និងកំហុសក្នុងទិន្នន័យ training
  4. គ្មាន "ខ្ញុំមិនដឹង" ដែលភ្ជាប់មកស្រាប់
  5. ទំនុកចិត្តមិនមែនជាភាពត្រឹមត្រូវ
  6. ទម្រង់ជាច្រើននៃ Hallucination
  7. ដំណោះស្រាយទី 1៖ ផ្តល់ប្រភពឲ្យ model
  8. រូបមន្ត៖ Module grounding
  9. ដំណោះស្រាយទី 2៖ ស្នើសុំ citation
  10. ដំណោះស្រាយទី 3៖ ផ្ទៀងផ្ទាត់ដោយកូដ និង tool
  11. ដំណោះស្រាយទី 4៖ បន្ថយ temperature
  12. ដំណោះស្រាយទី 5៖ Eval និងការត្រួតពិនិត្យដោយមនុស្ស
  13. អ្វីដែល toy នេះមិនអាចធ្វើបាន
  14. សាកល្បងដោយខ្លួនឯង
  15. ពិនិត្យឡើងវិញរហ័ស: សំណួរទូទៅ

1. ចម្លើយខុសដែលមានទំនុកចិត្ត

សិស្សម្នាក់សួរជំនួយការ AI រកសៀវភៅអំពីប្រវត្តិសាស្ត្រកម្ពុជា។ ជំនួយការឆ្លើយមកជាមួយចំណងជើង អ្នកនិពន្ធ ឆ្នាំ និងសេចក្តីសង្ខេបខ្លីមួយ។ អ្វីៗស្តាប់ទៅល្អឥតខ្ចោះ។ សិស្សទៅបណ្ណាល័យ ហើយរកឃើញថាសៀវភៅនោះមិនមានពិតទេ។ គ្មាននរណាកុហកទេ។ model បានបង្កើតចំណងជើងដែលគួរឲ្យជឿ ព្រោះចំណងជើងដែលគួរឲ្យជឿ គឺជាអ្វីដែលវាពូកែសរសេរបំផុត។

នេះហៅថា hallucination៖ លទ្ធផលដែលស្ទាត់ជំនាញ និងមានទំនុកចិត្ត ប៉ុន្តែមិនពិត ឬគ្មានប្រភពណាមួយគាំទ្រ។ ពាក្យនេះខ្ចីមកពីបទពិសោធន៍របស់មនុស្ស ហើយវាបន្តិចបំភ័ន្ត ព្រោះ model មិនមែន "ឃើញរូបភាពបន្លំ" ទេ។ វាកំពុងធ្វើការងារធម្មតារបស់វា។ ជំពូកនេះពន្យល់ថាហេតុអ្វីការងារនោះបង្កើតសេចក្តីថ្លែងខុស ហើយបន្ទាប់មកអ្នកសាងសង់ឧបករណ៍តូចមួយដែលបង្ហាញថ្នាំព្យាបាលចម្បង៖ ឲ្យ model ឆ្លើយពីភស្តុតាង ហើយនិយាយថា "ខ្ញុំមិនដឹង" នៅពេលគ្មានភស្តុតាង។

អ្នកត្រូវការ toolkit ពីជំពូកមុនៗ ជាពិសេស tiny language model ពី Build a Tiny Language Model និង corpus ដែលប្រើរួមគ្នាពី What Is an LLM?។ ប្រសិនបើអ្នកមិនបានធ្វើតាម គំនិតសំខាន់ៗទាំងអស់ត្រូវបានលើកឡើងម្តងទៀតខាងក្រោម។

2. ហេតុអ្វីបានជាកើតឡើង៖ ទំនងជាពិត មិនមែនពិត

ចាំរង្វិលជុំនេះ៖ ទាយ token បន្ទាប់ បន្ថែមវា ធ្វើម្តងទៀត។ model ត្រូវបាន train ឲ្យធ្វើឲ្យការទាយរបស់វាត្រូវនឹងអត្ថបទដែលវាបានឃើញ (មើល How a Model Is Trained)។ គោលដៅនៃការ train គឺ "ទាយអត្ថបទដែលមើលទៅដូចអត្ថបទពិត"។ វាមិនដែលជា "និយាយតែរឿងពិត" ទេ។

ភាគច្រើនទំនងជាពិត និងពិតពិតទៅរួមគ្នា ព្រោះអត្ថបទភាគច្រើនដែលមនុស្សសរសេរគឺអំពីរឿងពិត។ ប្រសិនបើអ្នកសួររកទីក្រុងធំរបស់ប្រទេសបារាំង ពាក្យបន្ទាប់ដែលទំនងបំផុតក៏ជាពាក្យត្រឹមត្រូវដែរ។ បញ្ហាចាប់ផ្តើមនៅពេលទាំងពីរបែកគ្នា៖ ការពិតដ៏កម្រ ព្រឹត្តិការណ៍ថ្មីៗ ឬព័ត៌មានលម្អិតជាក់លាក់ណាមួយ។ ពេលនោះ model នៅតែបង្កើតអត្ថបទបន្តដែលទំនងបំផុត ហើយទំនងជាពិត មិនដូចគ្នានឹងត្រឹមត្រូវទេ។

អ្នកអាចឃើញរឿងនេះជាមួយ tiny model របស់អ្នកផ្ទាល់។ វាសរសេរប្រយោគដែលមិនដែលមាន ក្នុងអត្ថបទ training របស់វា។ រក្សាទុកកូដនេះជា demo9b.js (វាត្រូវការ src/bigram.js និង src/rng.js ពីជំពូកទី 3)៖

import { corpus, words } from "./src/corpus.js";
import { trainBigram, nextWordProbs, generate } from "./src/bigram.js";
import { mulberry32 } from "./src/rng.js";

const tokens = words(corpus);
const model = trainBigram(tokens);
const text = tokens.join(" ");

for (const seed of [1, 5, 6]) {
  const sentence = generate(model, "sokha", 9, mulberry32(seed));
  console.log(sentence);
  console.log("  appears in the training text:", text.includes(sentence));
}

// Walk through seed 6 and print how likely each chosen word was.
const rng = mulberry32(6);
let word = "sokha";
for (let i = 0; i < 8; i++) {
  const options = nextWordProbs(model, word);
  let r = rng();
  let pick = options.at(-1);
  for (const option of options) {
    if (r < option.prob) { pick = option; break; }
    r -= option.prob;
  }
  console.log(word.padEnd(8), "->", pick.word.padEnd(8), pick.prob.toFixed(2));
  word = pick.word;
}
// sokha opens the app saves time every morning the
//   appears in the training text: false
// sokha opens the students laugh and a small app
//   appears in the training text: false
// sokha makes iced tea the river and dara walks
//   appears in the training text: false
// sokha    -> makes    0.20
// makes    -> iced     1.00
// iced     -> tea      0.40
// tea      -> the      0.50
// the      -> river    0.13
// river    -> and      0.33
// and      -> dara     0.27
// dara     -> walks    0.14

ដោយសារ random generator ត្រូវបាន seed អ្នកនឹងទទួលបានបន្ទាត់ទាំងនេះយ៉ាងពិតប្រាកដគ្រប់ពេលដែលរត់។

អានប្រយោគទីបី៖ "sokha makes iced tea the river and dara walks"។ ផ្នែកដំបូង ("sokha makes iced tea") ជិតនឹងអ្វីដែលអត្ថបទនិយាយ ហើយបន្ទាប់មកវាវង្វេង៖ គូពាក្យជិតគ្នានីមួយៗគឺជាអ្វីដែល model បានឃើញពិតប្រាកដ ដូច្នេះគ្រប់ជំហានមើលទៅសមហេតុផល ប៉ុន្តែប្រយោគទាំងមូលគឺជាការអះអាងដែលមិនដែលត្រូវបានសរសេរនៅកន្លែងណាទេ ហើយគ្មាននរណាពិនិត្យវាទេ។ ប្រយោគទីពីរ "sokha opens the students laugh and a small app" គឺជាពាក្យឥតន័យដែលមើលទៅស្ទាត់។ model ពិតប្រាកដល្អជាងនេះឆ្ងាយ ដូច្នេះពាក្យឥតន័យរបស់វាពិបាកមើលឃើញជាងច្រើន ប៉ុន្តែយន្តការគឺដូចគ្នា៖ គ្រប់ជំហានទំនងជាត្រឹមត្រូវក្នុងតំបន់តូចមួយ ហើយគ្មានអ្វីពិនិត្យថាទាំងមូលត្រូវនឹងការពិតទេ។

3. កង្វះ និងកំហុសក្នុងទិន្នន័យ training

model អាចរៀនគំរូបានតែពីអ្វីដែលគេបង្ហាញវា។ ហេតុនេះនាំឲ្យមានបញ្ហាច្រើនប្រភេទ៖

  • ចំណេះដឹងដែលបាត់។ ប្រសិនបើប្រធានបទណាមួយលេចឡើងកម្រ ឬមិនដែលលេចឡើង model មានអ្វីតិចតួចដែលអាចពឹងលើបាន។ ប្រធានបទក្នុងស្រុកតូចៗ (ភូមិមួយ ក្រុមហ៊ុនតូចមួយ ប្រវត្តិសាលារៀនរបស់អ្នក) ច្រើនតែមានតិចតួចក្នុងទិន្នន័យ training។
  • ចំណេះដឹងចាស់។ ការ train ឈប់នៅកាលបរិច្ឆេទមួយ។ model មិនដឹងអំពីអ្វីក្រោយពេលនោះទេ លើកលែងតែអ្នកប្រាប់វានៅក្នុង prompt។
  • ចំណេះដឹងខុស។ អ៊ីនធឺណិតមានកំហុស ពាក្យចចាមអារ៉ាម និងរឿងកំប្លែង។ model ដែលរៀនពីពួកវាអាចនិយាយតាម។
  • ចំណេះដឹងស្រពិចស្រពិល។ model មិនរក្សាទុកបញ្ជីការពិតរៀបរយទេ។ វារក្សាទុកលេខរាប់ពាន់លាន ដែលរុញការទាយ។ ការពិតដែលត្រូវបានឃើញតែពីរបីដង អាចក្លាយជាចងចាំបានពាក់កណ្តាល ដូចពាក្យមួយនៅចុងអណ្តាត ហើយ model បំពេញចន្លោះដោយអ្វីដែលសមនឹងវា។

toy model របស់អ្នកបង្ហាញផ្នែក "ស្រពិចស្រពិល" យ៉ាងច្បាស់។ វាមិនដឹងថាអ្នកណាជាម្ចាស់ ហាងកាហ្វេទេ វាដឹងតែថាពាក្យណាតែងតែតាមពាក្យណា។ ប្រសិនបើអ្នកសួរវាអំពីអ្វីដែលវាមិនដែលឃើញ វានៅតែបង្កើតពាក្យ។

4. គ្មាន "ខ្ញុំមិនដឹង" ដែលភ្ជាប់មកស្រាប់

language model តែងតែមានចម្លើយចំពោះ "តើអ្វីមកបន្ទាប់?"។ ប្រូបាបបូកបាន 1 ជានិច្ច ហើយមាន token មួយត្រូវបានជ្រើសជានិច្ច។ គ្មានសញ្ញាពិសេស "ខ្ញុំគ្មានភស្តុតាង" នៅក្នុងរង្វិលជុំទេ។ ប្រៀបធៀបជាមួយ database query ដែលអាចត្រឡប់លទ្ធផលទទេបាន។

ដូច្នេះប្រសិនបើ model និយាយថា "ខ្ញុំមិនដឹង" នោះគឺដោយសារវារៀនគំរូនោះពីអត្ថបទ (មនុស្សសរសេរ "ខ្ញុំមិនប្រាកដ" នៅកន្លែងជាច្រើន) ឬដោយសារអ្នកបង្កើតវា train វា ឲ្យធ្វើដូច្នេះសម្រាប់សំណួរមួយចំនួនក្នុងអំឡុង fine-tuning។ ឥរិយាបថនោះត្រូវបានរៀន ហើយវាមិនល្អឥតខ្ចោះទេ។ model នៅតែអាចទាយដោយមានទំនុកចិត្ត នៅកន្លែងដែលមនុស្សប្រុងប្រយ័ត្ននឹងនិយាយថា "ខ្ញុំមិនប្រាកដ"។

នេះជាហេតុដែលដំណោះស្រាយចំពោះ hallucination ជាធម្មតាមិនមែន "ធ្វើឲ្យ model ឆ្លាតជាង" ទេ ប៉ុន្តែគឺ "ដាក់ប្រព័ន្ធមួយជុំវិញ model"៖ ឲ្យវាភស្តុតាង ពិនិត្យចម្លើយរបស់វា ហើយអនុញ្ញាតឲ្យវាបដិសេធ។ បន្តិចទៀតអ្នកនឹងសាងសង់កំណែ toy នៃរឿងនោះ។

5. ទំនុកចិត្តមិនមែនជាភាពត្រឹមត្រូវ

សូមមើលលទ្ធផលក្នុងផ្នែកទី 2 ម្តងទៀត។ ជំហាន makes -> iced មានប្រូបាប 1.00៖ ក្នុងអត្ថបទ training "makes" តែងតែតាមដោយ "iced"។ ជំហាន the -> river មានប្រូបាប 0.13។ ប៉ុន្តែគ្មានសញ្ញាណាមួយក្នុងលទ្ធផលដែលបង្ហាញថាផ្នែកណាអាចទុកចិត្តបាន។ សំឡេងស្ទាត់មិនមានន័យថាការអះអាងពិតទេ ហើយសំឡេងមានទំនុកចិត្តមិនមានន័យថា model "ដឹង" ទេ។

កំហុសទូទៅពីរ៖

  1. ជឿលើសំឡេង។ model សរសេរដោយសំឡេងរលោង និងប្រាកដប្រជា សូម្បីតែពេលវាកំពុងទាយ ព្រោះអត្ថបទរលោងប្រាកដប្រជាគឺជាអ្វីដែលអត្ថបទ training ភាគច្រើនរបស់វាមើលទៅដូច។
  2. សួរ model ថាវាប្រាកដប៉ុនណា។ model អាចសរសេរ "ខ្ញុំប្រាកដ 95%" ប៉ុន្តែនោះក៏គ្រាន់តែជា អត្ថបទដែលបង្កើតឡើងដែរ។ ការស្រាវជ្រាវខ្លះបង្ហាញថា model មានអារម្មណ៍ខាងក្នុងដ៏មានប្រយោជន៍ អំពីភាពមិនប្រាកដ ហើយប្រព័ន្ធខ្លះព្យាយាមអានវាចេញមក ប៉ុន្តែប្រយោគនៃទំនុកចិត្តដែលវារាយការណ៍ដោយខ្លួនឯង មិនមែនជាការវាស់វែងដែលអ្នកអាចពឹងលើបានទេ។

ទម្លាប់ល្អសម្រាប់អ្នកប្រើ ឬអ្នកអភិវឌ្ឍន៍ណាមួយ៖ វិនិច្ឆ័យចម្លើយតាម ភស្តុតាង មិនមែនតាមសំឡេងទេ។

6. ទម្រង់ជាច្រើននៃ Hallucination

Hallucination មិនមែនជាបញ្ហាតែមួយទេ។ ការស្គាល់ប្រភេទនានាជួយអ្នកសម្រេចចិត្តថា ត្រូវការពារយ៉ាងណាចំពោះនីមួយៗ៖

ប្រភេទឧទាហរណ៍
ការពិតដែលបង្កើតឡើងកាលបរិច្ឆេទ ឈ្មោះ ឬលេខដែលស្តាប់ទៅត្រូវ ប៉ុន្តែខុស
ប្រភពដែលបង្កើតឡើងសៀវភៅ តំណ ឬអត្ថបទស្រាវជ្រាវដែលមិនមានពិត
Code API ដែលបង្កើតឡើងfunction ឬជម្រើសដែលស្តាប់ទៅត្រូវ ប៉ុន្តែមិនមានក្នុង library
ហេតុផលខុសជំហានគណិតវិទ្យា ឬតក្កវិជ្ជាដែលមើលទៅល្អ ប៉ុន្តែមានកំហុស
ចម្លើយហួសសម័យអ្វីដែលពិតនៅពេល train ប៉ុន្តែមិនពិតឥឡូវនេះ
មិនអើពើនឹង inputសង្ខេបឯកសារ ហើយបន្ថែមរឿងដែលមិនមានក្នុងវា

អ្នកអភិវឌ្ឍន៍ជួបប្រភេទ API ដែលបង្កើតឡើងរាល់ថ្ងៃ៖ model ណែនាំ array.removeItem(x) ព្រោះវាជាឈ្មោះធម្មជាតិ ប៉ុន្តែ JavaScript គ្មាន method បែបនោះទេ។ ដំណោះស្រាយគឺដូចគ្នានឹងការពិតដែរ៖ រត់កូដ អានឯកសារ ពិនិត្យប្រភពពិតប្រាកដ។

7. ដំណោះស្រាយទី 1៖ ផ្តល់ប្រភពឲ្យ model

ការការពារមានប្រសិទ្ធភាពបំផុតតែមួយគឺឈប់សុំឲ្យ model ឆ្លើយពីការចងចាំ។ ផ្ទុយទៅវិញ ប្រគល់អត្ថបទដែលពាក់ព័ន្ធឲ្យវា ហើយប្រាប់វាឲ្យឆ្លើយតែពីអត្ថបទនោះ។ ប្រសិនបើចម្លើយមិនមានក្នុងអត្ថបទ វាគួរតែនិយាយដូច្នោះ។ គំរូនេះច្រើនតែហៅថា grounding ហើយនៅពេលអត្ថបទត្រូវបានរកឃើញដោយស្វ័យប្រវត្តិដោយស្វែងរកក្នុងបណ្ណាល័យឯកសារ វាហៅថា retrieval-augmented generation (RAG)។ ស៊េរីក្រោយនឹងរៀបរាប់ពី RAG ឲ្យបានត្រឹមត្រូវ ហើយនៅទីនេះអ្នកសាងសង់គំនិតនេះជាទម្រង់តូច។

រូបមន្តមានបីជំហាន៖

  1. Retrieve៖ រកឯកសារដែលទាក់ទងបំផុតនឹងសំណួរ។
  2. Decide៖ ប្រសិនបើរកមិនឃើញអ្វីពាក់ព័ន្ធ ឆ្លើយ "ខ្ញុំមិនដឹង"។
  3. ឆ្លើយពីភស្តុតាង ហើយប្រាប់ថាវាមកពីឯកសារណា។

ក្នុងប្រព័ន្ធពិតប្រាកដ ជំហានទី 1 ប្រើ embedding ដែលអ្នកបានជួបពីមុន (ស្វែងរកតាមអត្ថន័យ) ហើយជំហានទី 3 ធ្វើដោយ model អានអត្ថបទដែលបាន retrieve។ ក្នុង toy របស់យើង ជំហានទី 1 រាប់ keyword ដែលដូចគ្នា ហើយជំហានទី 3 ត្រឡប់ប្រយោគដែលត្រូវគ្នា។ រូបរាងនៃ pipeline គឺដូចគ្នា ហើយឥរិយាបថសំខាន់ក៏ដូចគ្នាដែរ៖ គ្មានភស្តុតាង គ្មានចម្លើយ។

8. រូបមន្ត៖ Module grounding

បង្កើត src/grounding.js។ វាប្រើ words ពី src/corpus.js ឡើងវិញ។

import { words } from "./corpus.js";

// Very common words carry no evidence, so we ignore them when matching.
const STOP = new Set([
  "a", "an", "the", "is", "are", "was", "and", "or", "of", "to", "in",
  "on", "at", "by", "for", "with", "what", "who", "when", "where", "how",
  "does", "do", "did", "it", "that", "this", "s", "after", "near",
]);

export function keywords(text) {
  return words(text).filter((w) => !STOP.has(w));
}

// Find the doc that shares the most keywords with the question.
export function retrieve(question, docs, minOverlap = 2) {
  const q = new Set(keywords(question));
  let best = null;
  for (const doc of docs) {
    const d = new Set(keywords(doc.text));
    const shared = [...q].filter((w) => d.has(w));
    if (shared.length >= minOverlap && (!best || shared.length > best.score)) {
      best = { doc, score: shared.length, shared };
    }
  }
  return best;
}

export function groundedAnswer(question, docs) {
  const hit = retrieve(question, docs);
  if (!hit) return { answer: "I don't know.", source: null };
  return { answer: hit.doc.text, source: hit.doc.id };
}

// Crude check: what share of the answer's keywords appear in the docs?
export function checkSupported(answer, docs, threshold = 0.8) {
  const known = new Set(docs.flatMap((d) => keywords(d.text)));
  const kws = keywords(answer);
  const missing = kws.filter((w) => !known.has(w));
  const coverage = kws.length ? (kws.length - missing.length) / kws.length : 1;
  return { supported: coverage >= threshold, coverage, missing };
}

// Show the reader where an answer came from.
export function withCitation({ answer, source }) {
  return source ? `${answer} [source: ${source}]` : answer;
}

អ្វីដែល export មាន៖

  • keywords(text) ត្រឡប់ពាក្យមានអត្ថន័យនៃអត្ថបទ (អក្សរតូច គ្មានវណ្ណយុត្តិ គ្មាន stop word)។
  • retrieve(question, docs, minOverlap = 2) ត្រឡប់ឯកសារដែលត្រូវគ្នាបំផុតជា { doc, score, shared } ឬ null ប្រសិនបើ keyword ដែលត្រូវគ្នាតិចជាង minOverlap។ ច្បាប់ minOverlap គឺជាច្រក "គ្មានភស្តុតាង"។
  • groundedAnswer(question, docs) ត្រឡប់ { answer, source } ជាមួយ "I don't know." និង source: null នៅពេលគ្មានភស្តុតាង។
  • checkSupported(answer, docs, threshold = 0.8) ត្រឡប់ { supported, coverage, missing }៖ ចំណែក keyword របស់ចម្លើយដែលរកឃើញនៅកន្លែងណាមួយក្នុងឯកសារ និង keyword ដែលរកមិនឃើញ។
  • withCitation({ answer, source }) បន្ថែម [source: id] ទៅចម្លើយ។

បន្ទាប់ គឺបណ្ណាល័យឯកសារតូចមួយ។ បង្កើត docs.js ក្នុងថតគម្រោង (មិនមែនក្នុង src/ ទេ)។ ឯកសារនីមួយៗមាន id និង text៖

export const docs = [
  { id: "shop-1", text: "Sokha opens the small coffee shop near the river every morning." },
  { id: "shop-2", text: "Sokha makes iced coffee with milk and iced tea with lime." },
  { id: "shop-3", text: "The students come to the coffee shop after school." },
  { id: "dara-1", text: "Dara is a student and Dara writes code at the table by the window." },
  { id: "app-1", text: "The app helps the coffee shop take orders on a phone." },
];

ទាំងនេះគឺជាប្រយោគពិតពី corpus ដែលធ្វើឲ្យវាក្លាយជា "បណ្ណាល័យដែលទុកចិត្តបាន" របស់យើង។ សាកល្បង module ក្នុង demo9.js៖

import { docs } from "./docs.js";
import { retrieve, groundedAnswer, checkSupported, keywords } from "./src/grounding.js";

console.log(keywords("Who opens the coffee shop?"));
const hit = retrieve("Who opens the coffee shop?", docs);
console.log(hit.doc.id, hit.score, hit.shared);
console.log(groundedAnswer("Who opens the coffee shop?", docs));
console.log(groundedAnswer("What is the wifi password?", docs));

console.log(checkSupported("Sokha opens the coffee shop near the river.", docs));
console.log(checkSupported("Sokha opens the shop at six o'clock with a robot.", docs));
console.log(checkSupported("Dara opens the coffee shop every morning.", docs));
// [ 'opens', 'coffee', 'shop' ]
// shop-1 3 [ 'opens', 'coffee', 'shop' ]
// {
//   answer: 'Sokha opens the small coffee shop near the river every morning.',
//   source: 'shop-1'
// }
// { answer: "I don't know.", source: null }
// { supported: true, coverage: 1, missing: [] }
// {
//   supported: false,
//   coverage: 0.42857142857142855,
//   missing: [ 'six', 'o', 'clock', 'robot' ]
// }
// { supported: true, coverage: 1, missing: [] }

លទ្ធផលទាំងអស់នេះមានស្ថេរភាព (គ្មានភាពចៃដន្យ)។ សូមកត់សម្គាល់បីចំណុច៖

  1. សំណួរអំពីពាក្យសម្ងាត់ wifi គ្មាន keyword ដូចគ្នានឹងឯកសារណាមួយទេ ដូច្នេះចម្លើយគឺ I don't know. ប្រព័ន្ធបដិសេធជំនួសឲ្យការទាយ។
  2. ប្រយោគដែលបង្កើតឡើង "Sokha opens the shop at six o'clock with a robot" ត្រូវបានចាប់ទង់៖ six, o, clock និង robot មិនមាននៅកន្លែងណាក្នុង បណ្ណាល័យទេ។ (o និង clock មកពីរបៀបដែល words បំបែក o'clock ត្រង់សញ្ញាអបូស្ត្រូហ្វ។)
  3. បន្ទាត់ចុងក្រោយគឺជាការបរាជ័យដ៏ស្មោះត្រង់។ "Dara opens the coffee shop every morning" គឺ មិនពិត (Sokha ជាអ្នកបើក) ប៉ុន្តែ checkSupported ថាវាត្រូវបានគាំទ្រ ព្រោះគ្រប់ពាក្យមាននៅក្នុងបណ្ណាល័យ។ ការពិនិត្យមើលពាក្យ មិនមែនអត្ថន័យទេ។ វាចាប់បានព័ត៌មានលម្អិតដែលបង្កើតឡើង ហើយខកខានការពិតដែលត្រូវបានប្តូរគ្នា។

ចំណុចទីបីនោះសំខាន់លើសពី toy។ ការពិនិត្យការគាំទ្រពិតប្រាកដ (ពេលខ្លះធ្វើដោយ model ទីពីរ ពេលខ្លះដោយឧបករណ៍ឯកទេស) ល្អជាងការរាប់ពាក្យឆ្ងាយ ប៉ុន្តែគ្មានមួយណាល្អឥតខ្ចោះទេ។ ចាត់ទុកវាជាសំណាញ់សុវត្ថិភាព មិនមែនការធានាទេ។

9. ដំណោះស្រាយទី 2៖ ស្នើសុំ citation

ចម្លើយដែលមានមូលដ្ឋានគួរតែមាន ប្រភព របស់វា ដើម្បីឲ្យមនុស្សអាចពិនិត្យក្នុងរយៈពេលប៉ុន្មានវិនាទី ជំនួសឲ្យការជឿ។ withCitation ធ្វើរឿងនេះក្នុង toy៖

import { docs } from "./docs.js";
import { groundedAnswer, withCitation } from "./src/grounding.js";

console.log(withCitation(groundedAnswer("Who opens the coffee shop?", docs)));
console.log(withCitation(groundedAnswer("What is the wifi password?", docs)));
// Sokha opens the small coffee shop near the river every morning. [source: shop-1]
// I don't know.

ជាមួយ model ពិតប្រាកដ អ្នកធ្វើរឿងនេះក្នុង prompt៖ "ឆ្លើយដោយប្រើតែឯកសារខាងក្រោម។ បន្ទាប់ពីការអះអាងនីមួយៗ សូមដកស្រង់ id ឯកសារក្នុងតង្កៀប។ ប្រសិនបើឯកសារមិនមានចម្លើយ សូមនិយាយថាអ្នកមិនដឹង។" អ្នកនឹងសរសេរ prompt បែបនេះក្នុងស៊េរីបន្ទាប់។

ការព្រមានដ៏ស្មោះត្រង់មួយ៖ model ក៏អាចបង្កើត citation បានដែរ។ model អាចសរសេរ [source: shop-9] សម្រាប់ឯកសារដែលមិនមាន ឬដកស្រង់ឯកសារពិតដែលមិនគាំទ្រការអះអាង។ ដូច្នេះកូដរបស់អ្នកគួរពិនិត្យថា id ដែលដកស្រង់ទាំងអស់មាននៅក្នុងបញ្ជីដែលអ្នកបានផ្ញើ ហើយ (កន្លែងដែលសំខាន់) ថាអត្ថបទដែលដកស្រង់គាំទ្រការអះអាងពិតប្រាកដ។ Citation ធ្វើឲ្យការពិនិត្យងាយស្រួល។ វាមិនធ្វើឲ្យការពិនិត្យមិនចាំបាច់ទេ។

10. ដំណោះស្រាយទី 3៖ ផ្ទៀងផ្ទាត់ដោយកូដ និង tool

ការអះអាងខ្លះអាចត្រូវបានពិនិត្យដោយម៉ាស៊ីន ដូច្នេះសូមពិនិត្យដោយម៉ាស៊ីន។ model ស្ទាត់ជំនាញជាមួយលេខ ប៉ុន្តែអាចរអិលលើនព្វន្ធដែលត្រូវការភាពច្បាស់លាស់ ជាពិសេសការគណនាវែងដែលធ្វើ "ក្នុងក្បាល"។ កុំឲ្យពួកវាធ្វើអ្វីដែលម៉ាស៊ីនគិតលេខធ្វើបានយ៉ាងល្អឥតខ្ចោះ។

// Verify a model's claim with code instead of trusting it.
const claim = { text: "17 * 24 = 418", a: 17, b: 24, said: 418 };
const real = claim.a * claim.b;
console.log(claim.text, "->", real === claim.said ? "correct" : `wrong, it is ${real}`);
// 17 * 24 = 418 -> wrong, it is 408

គំរូនេះលេចឡើងគ្រប់ទីកន្លែងក្នុងវិស្វកម្ម AI៖

  • ការគណនា៖ ហៅ function ម៉ាស៊ីនគិតលេខ ជំនួសឲ្យការសួរ model។
  • កូដដែល model សរសេរ៖ រត់ test រត់ linter រត់វាក្នុង sandbox (មើល Docker Sandbox Crash Course)។
  • ការពិតដែលស្ថិតក្នុង database៖ query database ហើយបញ្ជូនលទ្ធផលទៅ model។
  • កាលបរិច្ឆេទ និងពេលវេលា៖ ប្រើនាឡិកា មិនមែន model ទេ។
  • ទម្រង់ output៖ parse JSON ហើយ validate key ដូចអ្វីដែលអ្នកបានធ្វើក្នុង Prompts, Roles and Structured Output។

model ដែលបង្ហោះ (hosted) ជាច្រើនអាចត្រូវបានផ្តល់ tool (function ដែល model អាចស្នើឲ្យ កម្មវិធីរបស់អ្នកហៅ)។ ពេលនោះ model សម្រេចចិត្តថា ពេលណា ត្រូវហៅម៉ាស៊ីនគិតលេខ ឬ database ហើយកូដរបស់អ្នកធ្វើការងារត្រឹមត្រូវ។ នេះជាទឹកដីនៃស៊េរីបន្ទាប់។

11. ដំណោះស្រាយទី 4៖ បន្ថយ temperature

ពី Probabilities, Temperature and Sampling អ្នកដឹងថា temperature ទាបធ្វើឲ្យ model ជ្រើស token ដែលទំនងបំផុតញឹកញាប់ជាង។ សម្រាប់ការងារដែលអ្នកចង់បានចម្លើយស្មោះត្រង់ និងស្របគ្នា (extraction, classification, ឆ្លើយពីឯកសារ) temperature ទាបជាធម្មតាកាត់បន្ថយកំហុសចៃដន្យ។

ប៉ុន្តែត្រូវប្រុងប្រយ័ត្នអំពីអ្វីដែលវា មិន ធ្វើ។ temperature ទាបមិនបន្ថែមចំណេះដឹងទេ។ ប្រសិនបើអត្ថបទបន្តដែលទំនងបំផុតគឺខុស model នឹងជ្រើសខុសរាល់ពេល គ្រាន់តែស្របគ្នាជាង។ ការបន្ថយ temperature កាត់បន្ថយកំហុសចៃដន្យខ្លះ វាមិនជួសជុលចន្លោះចំណេះដឹងទេ។ Grounding ការផ្ទៀងផ្ទាត់ និង eval សំខាន់ជាង។

12. ដំណោះស្រាយទី 5៖ Eval និងការត្រួតពិនិត្យដោយមនុស្ស

តើអ្នកដឹងដោយរបៀបណាថាប្រព័ន្ធរបស់អ្នកកំពុងប្រសើរឡើង មិនមែនអាក្រក់ទៅ? អ្នក វាស់ វា។ eval (evaluation) គឺជាបញ្ជីសំណួរសាកល្បងថេរ ជាមួយលទ្ធផលត្រឹមត្រូវដែលស្គាល់ ដែលរត់រាល់ពេលអ្នកផ្លាស់ប្តូរអ្វីមួយ។ វាជា unit test សម្រាប់ឥរិយាបថ AI។

ដាក់សំណួរ ដែលមិនអាចឆ្លើយបាន ក្នុងបញ្ជីរបស់អ្នក។ ប្រព័ន្ធដែលឆ្លើយគ្រប់សំណួរដែលអាចឆ្លើយបាន ប៉ុន្តែក៏បង្កើតចម្លើយសម្រាប់សំណួរដែលមិនអាចឆ្លើយបានដែរ គឺគ្រោះថ្នាក់។ បង្កើត evals.js៖

import { docs } from "./docs.js";
import { groundedAnswer, retrieve } from "./src/grounding.js";

const cases = [
  { q: "Who opens the coffee shop?", source: "shop-1" },
  { q: "What does Sokha make with lime?", source: "shop-2" },
  { q: "Where does Dara write code?", source: "dara-1" },
  { q: "What is the wifi password?", source: null },
  { q: "When does the shop close on Sunday?", source: null },
];

// A bot that always answers, even with no evidence (like a model with no "I don't know").
function eagerAnswer(q) {
  const hit = retrieve(q, docs, 0);
  return { answer: hit.doc.text, source: hit.doc.id };
}

function runEval(name, answerFn) {
  let passed = 0;
  console.log(`--- ${name} ---`);
  for (const c of cases) {
    const got = answerFn(c.q);
    const ok = got.source === c.source;
    if (ok) passed++;
    console.log(ok ? "PASS" : "FAIL", c.q, "->", got.source ?? "I don't know");
  }
  console.log(`${passed}/${cases.length} passed`);
  return passed;
}

runEval("grounded", (q) => groundedAnswer(q, docs));
runEval("eager", eagerAnswer);

console.log(groundedAnswer("How much does iced tea cost?", docs));
// --- grounded ---
// PASS Who opens the coffee shop? -> shop-1
// PASS What does Sokha make with lime? -> shop-2
// PASS Where does Dara write code? -> dara-1
// PASS What is the wifi password? -> I don't know
// PASS When does the shop close on Sunday? -> I don't know
// 5/5 passed
// --- eager ---
// PASS Who opens the coffee shop? -> shop-1
// PASS What does Sokha make with lime? -> shop-2
// PASS Where does Dara write code? -> dara-1
// FAIL What is the wifi password? -> shop-1
// FAIL When does the shop close on Sunday? -> shop-1
// 3/5 passed
// {
//   answer: 'Sokha makes iced coffee with milk and iced tea with lime.',
//   source: 'shop-2'
// }

លទ្ធផលមានលក្ខណៈកំណត់ច្បាស់លាស់។ bot ទាំងពីរឆ្លងកាត់សំណួរបីដែលអាចឆ្លើយបាន។ មានតែ bot ដែលមានមូលដ្ឋាន (grounded) ទេដែលឆ្លងកាត់សំណួរពីរដែលមិនអាចឆ្លើយបាន។ bot "eager" តែងតែមានចម្លើយ ដូចគ្នានឹង model ដែលគ្មានវិធីបដិសេធភ្ជាប់មកស្រាប់។ ពិន្ទុ 3/5 លាក់ថាវាអាក្រក់ប៉ុនណា ដែលជាហេតុដែលអ្នកគួរមើលថា ករណីណា ដែលបរាជ័យ មិនមែនត្រឹមតែចំនួនសរុបទេ។

បន្ទាត់ចុងក្រោយគឺជាការបរាជ័យដ៏ស្មោះត្រង់មួយទៀត។ "How much does iced tea cost?" ចែករំលែកពាក្យ iced និង tea ជាមួយឯកសារ shop-2 ដូច្នេះជំហាន retrieval ឲ្យវាឆ្លងកាត់ ហើយប្រព័ន្ធត្រឡប់ប្រយោគដែលនិយាយអំពីតែទឹកកក ប៉ុន្តែមិននិយាយអ្វីអំពីតម្លៃទេ។ eval មិនចាប់វាបាន ព្រោះយើងមិនដែលសរសេរសំណួរនោះក្នុង cases។ មេរៀន៖ eval ល្អត្រឹមសំណួរដែលមាននៅក្នុងវា។ នៅពេលអ្នករកឃើញការបរាជ័យក្នុងការប្រើប្រាស់ពិត បន្ថែមវាទៅក្នុងបញ្ជី ដើម្បីកុំឲ្យវាត្រឡប់មកវិញដោយមិនមានអ្នកកត់សម្គាល់។ សាកល្បងធ្វើដូច្នោះក្នុងលំហាត់។

ចុងក្រោយ សម្រាប់អ្វីដែលមានហានិភ័យខ្ពស់ (សុខភាព ច្បាប់ លុយ ពិន្ទុសាលា សុវត្ថិភាព) ត្រូវរក្សា មនុស្សនៅក្នុងរង្វិលជុំ។ Eval និងការពិនិត្យកាត់បន្ថយហានិភ័យ ហើយមនុស្សដែលយល់ពីមុខវិជ្ជាចាប់បានអ្វីដែលវាខកខាន។ ច្បាប់ល្អ៖ កាន់តែឈឺចាប់ពេលខុស មនុស្សកាន់តែគួរពិនិត្យ។

13. អ្វីដែល toy នេះមិនអាចធ្វើបាន

សូមច្បាស់ថាអ្វីខ្លះត្រូវបានធ្វើឲ្យសាមញ្ញនៅទីនេះ៖

  • Retrieval ពិតប្រាកដស្វែងរកតាម អត្ថន័យ ដោយប្រើ embedding ដូច្នេះវារក "price" ឃើញនៅពេលឯកសារនិយាយ "cost"។ របស់យើងត្រូវគ្នាតែពាក្យពិតប្រាកដប៉ុណ្ណោះ។
  • model ពិតប្រាកដ សរសេរ ចម្លើយថ្មីពីអត្ថបទដែលបាន retrieve។ របស់យើងត្រឡប់ប្រយោគដែលត្រូវគ្នាដោយមិនកែប្រែ។
  • ការពិនិត្យការគាំទ្រពិតប្រាកដប្រើវិធីសាស្ត្រខ្លាំងជាងការរាប់ keyword ដូចដែល Dara opens the coffee shop បានបង្ហាញ។
  • ប្រព័ន្ធពិតប្រាកដនៅតែ hallucinate សូម្បីតែពេលមានមូលដ្ឋាន។ model អាចអានឯកសារខុស លាយឯកសារពីរចូលគ្នា ឬបន្ថែមព័ត៌មានលម្អិតពីការចងចាំរបស់វា។ Grounding បន្ថយអត្រា ប៉ុន្តែមិនលុបបំបាត់វាទេ។

មេរៀនដែលត្រូវរក្សាមិនមែនជាកូដទេ។ វាគឺជាគោលការណ៍រចនា៖ កុំទុកចិត្តការចងចាំរបស់ model សម្រាប់ការពិតដែលសំខាន់ ផ្តល់ភស្តុតាងឲ្យវា ស្នើសុំប្រភព ពិនិត្យអ្វីដែលអ្នកអាចពិនិត្យបាន ហើយវាស់វែង។

14. សាកល្បងដោយខ្លួនឯង

  1. ចាប់ hallucination។ រត់ demo9b.js ជាមួយ seed ពី 1 ដល់ 8 (ប្តូរបញ្ជី for)។ សម្រាប់ប្រយោគនីមួយៗ សម្រេចចិត្តថាវាពិត មិនពិត ឬឥតន័យ តាម corpus។ តើមានប៉ុន្មានប្រយោគដែលអ្នកនឹងសម្គាល់ថា "ស្ទាត់ ប៉ុន្តែមិនពិត"?
  2. បន្ថែមឯកសារ។ corpus និយាយថាហាងកាហ្វេស្ងប់ស្ងាត់ពេលព្រឹក និងមមាញឹកពេលថ្ងៃត្រង់។ បន្ថែមឯកសារដែលមាន id shop-4 ដែលបញ្ជាក់ការពិតពេលថ្ងៃត្រង់ដោយពាក្យរបស់អ្នកផ្ទាល់។ សួរ "When is the coffee shop busy?" ហើយពិនិត្យថា shop-4 គឺជាឯកសារដែលត្រូវបានត្រឡប់។
  3. ជួសជុលបញ្ហាតម្លៃ។ ធ្វើឲ្យ "How much does iced tea cost?" ត្រឡប់ I don't know។ គន្លឹះ៖ ពាក្យសំណួរដូចជា cost ដែលមិនមានក្នុងឯកសារណាមួយ គឺជាសញ្ញាថាភស្តុតាងបាត់។ សាកល្បងតម្រូវឲ្យឯកសារឈ្នះមាន keyword លើសពីពាក់កណ្តាលនៃ keyword របស់សំណួរ មិនមែនគ្រាន់តែពីរទេ។ បន្ថែមសំណួរទៅ cases ក្នុង evals.js ហើយមើលវាឆ្លងកាត់ (ហើយពិនិត្យថាករណីផ្សេងទៀតនៅតែឆ្លងកាត់)។
  4. បំបែក checker។ សរសេរប្រយោគមិនពិតបីដែល checkSupported នៅតែសម្គាល់ថាត្រូវបានគាំទ្រ (ប្រើពាក្យពីឯកសារឡើងវិញ)។ បន្ទាប់មកសរសេរការពិនិត្យតឹងរ៉ឹងជាង (ឧទាហរណ៍ តម្រូវឲ្យគូ keyword ជិតគ្នានីមួយៗក្នុងចម្លើយ លេចឡើងជាមួយគ្នាក្នុងឯកសារមួយ) ហើយសាកល្បងវា។
  5. Validate citation។ សរសេរ validateCitations(text, docs) ដែល រកគ្រប់ [source: id] ក្នុង string ហើយត្រឡប់ id ដែលមិនមាននៅក្នុង docs។ សាកល្បងជាមួយ "... [source: shop-9]"។
  6. បង្កើន eval។ បន្ថែមករណីច្រើនទៀតប្រាំទៅ evals.js យ៉ាងតិចបីករណី ជាសំណួរដែលមិនអាចឆ្លើយបាន។ តើ bot ដែលមានមូលដ្ឋានឆ្លងកាត់អ្វីៗទាំងអស់នៅឡើយទេ? ប្រសិនបើមិនទេ ច្បាប់ណាត្រូវផ្លាស់ប្តូរ?

15. ពិនិត្យឡើងវិញរហ័ស: សំណួរទូទៅ

សំណួរដែលអ្នកចាប់ផ្ដើមតែងសួរអំពីជំពូកនេះ។ សាកល្បងឆ្លើយខ្លួនឯងសិន រួចចុចលើសំណួរដើម្បីបើកមើលចម្លើយ។

ហេតុអ្វី AI បង្កើតរឿងឡើង?

ព្រោះការងាររបស់វាគឺបន្តអត្ថបទតាមរបៀបដែលទំនងជាពិត មិនមែនរកមើលការពិតទេ។ នៅពេលវាដឹងច្រើនអំពីប្រធានបទមួយ ទំនងជាពិត និងពិត ជាធម្មតាត្រូវគ្នា។ នៅពេលវាដឹងតិច វានៅតែបង្កើតអ្វីមួយដែលស្តាប់ទៅត្រូវ ព្រោះវាគ្មានសំឡេងរោទ៍ភ្ជាប់មកស្រាប់សម្រាប់ "ខ្ញុំគ្មានភស្តុតាង"។

តើ hallucination ជា bug ដែលនឹងត្រូវជួសជុលឆាប់ៗទេ?

វាជាផលរំលែកពីរបៀបដែល model ទាំងនេះដំណើរការ ហើយវាកាន់តែកម្រក្នុងប្រព័ន្ធជាច្រើន ប៉ុន្តែគ្មាននរណាអាចសន្យាដោយស្មោះត្រង់ថាវានឹងបាត់ទៅទេ។ ការរចនាសម្រាប់វាប្រសើរជាង៖ ធ្វើឲ្យចម្លើយមានមូលដ្ឋានលើប្រភព ផ្ទៀងផ្ទាត់អ្វីដែលអាចធ្វើបាន ហើយឲ្យមនុស្សចូលរួមនៅពេលហានិភ័យខ្ពស់។

តើខ្ញុំមិនអាចសួរ AI ថាចម្លើយរបស់វាត្រឹមត្រូវទេឬ?

អ្នកអាចសួរ ហើយពេលខ្លះវាចាប់កំហុសបាន ប៉ុន្តែចម្លើយទីពីរក៏ជាអត្ថបទដែលបង្កើតឡើងដែរ ហើយអាចខុសដោយទំនុកចិត្តដូចគ្នា។ ការពិនិត្យដែលប្រើភស្តុតាងខាងក្រៅ (ឯកសារ ម៉ាស៊ីនគិតលេខ test) គួរឲ្យទុកចិត្តជាងច្រើន ជាងការឲ្យ model ដាក់ពិន្ទុខ្លួនឯង។

ហេតុអ្វីវាស្តាប់ទៅប្រាកដប្រជាម្ល៉េះ ពេលវាខុស?

ព្រោះអត្ថបទភាគច្រើនដែលវារៀនពីវាសរសេរដោយសំឡេងប្រាកដប្រជា ហើយសំឡេងងាយចម្លង។ ពាក្យសម្ដីរបស់ model មិនបង្ហាញដោយអាចទុកចិត្តបានថាវាប្រាកដប៉ុនណាទេ។ វិនិច្ឆ័យចម្លើយតាមភស្តុតាងដែលមកជាមួយវា។

តើការផ្តល់ឯកសារឲ្យវា (RAG) បញ្ឈប់ hallucination ទេ?

វាកាត់បន្ថយបានច្រើនសម្រាប់សំណួរដែលឯកសារអាចឆ្លើយបាន ប៉ុន្តែមិនលុបបំបាត់ទេ។ model នៅតែអាចអានខុស លាយច្រឡំ ឬបន្ថែមលើអត្ថបទ ហើយជំហាន retrieval អាចទាញយកឯកសារខុស។ ដូច្នេះប្រព័ន្ធល្អក៏បង្ហាញ citation និងមាន eval ដែរ។

សំណួរប្រភេទណាមានហានិភ័យ?

ការពិតជាក់លាក់ (កាលបរិច្ឆេទ លេខ ឈ្មោះ) អ្វីៗដែលថ្មីៗ ប្រធានបទតូច ឬក្នុងស្រុក citation និងតំណ ហើយការគណនាច្រើនជំហានវែងៗ។ ប្រធានបទទូលំទូលាយដែលល្បីល្បាញ និងការងារដូចជាសរសេរឡើងវិញ ឬសង្ខេបអត្ថបទដែលអ្នកផ្តល់ជាទូទៅមានសុវត្ថិភាពជាង ប៉ុន្តែនៅតែគួរមើលម្តង។

តើសិស្សគួរជៀសវាង AI ដោយសារវាអាចខុសទេ?

ទេ ប្រើវា ប៉ុន្តែប្រើវាដូចដៃគូសិក្សាដ៏លឿនម្នាក់ដែលពេលខ្លះនិយាយបន្លំ។ សុំឲ្យវាពន្យល់ បន្ទាប់មកផ្ទៀងផ្ទាត់ផ្នែកសំខាន់ៗជាមួយសៀវភៅសិក្សា គ្រូ ឬកូដដែលរត់បាន។ ការរៀនពិនិត្យគឺជាជំនាញដែលសំខាន់ជាងមុន មិនមែនតិចជាងទេ។

ទៅបន្តទៀត។ ឥឡូវនេះអ្នកដឹងហេតុអ្វី model បង្កើតរឿងឡើង និងអ្វីដែលអ្នកអភិវឌ្ឍន៍ប្រុងប្រយ័ត្នធ្វើអំពីវា។ ជំពូកចុងក្រោយប្រមូលស៊េរីទាំងមូលចូលគ្នា៖ token ថ្លៃដើម ដែនកំណត់ context សំណួរដែលទស្សនិកជនរបស់អ្នកនឹងសួរ និងរបាយការណ៍ command-line តូចមួយដែលអ្នកអាចបង្ហាញ៖ Limits, Cost and Common Questions។

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!