🔎 RAG with Python: let a model read your documents · RAG ด้วย Python: ให้โมเดลอ่านเอกสารของคุณ · 用 Python 做 RAG:让模型读你的文档

This page teaches RAG, retrieval-augmented generation: a program first looks up the passages of your own documents that fit a question, and then a language model answers with those passages in front of it. You build it in Python on an ordinary laptop with no graphics card, with two small models, no account and no API key. You test it on 50 questions, read what it gets wrong, change a fact without training anything, and see how all this differs from the LoRA and the full fine-tuning of the last page. Every number on this page was measured on a real run. · หน้านี้สอน RAG หรือ retrieval-augmented generation คือให้โปรแกรมค้นหาท่อนข้อความในเอกสารของคุณเองที่ตรงกับคำถามก่อน แล้วให้โมเดลภาษาตอบโดยมีท่อนเหล่านั้นวางอยู่ตรงหน้า คุณจะสร้างมันด้วย Python บนแล็ปท็อปธรรมดาที่ไม่มีการ์ดจอ ใช้โมเดลเล็ก ๆ สองตัว ไม่ต้องมีบัญชี และไม่ต้องมี API key คุณจะทดสอบมันกับคำถาม 50 ข้อ อ่านว่ามันตอบผิดตรงไหน เปลี่ยนข้อเท็จจริงโดยไม่ต้องฝึกอะไรเลย แล้วดูว่าทั้งหมดนี้ต่างจาก LoRA และการปรับจูนแบบเต็มของหน้าที่แล้วอย่างไร ตัวเลขทุกตัวในหน้านี้วัดจากการรันจริง · 这一页讲 RAG,也就是检索增强生成(retrieval-augmented generation):程序先在你自己的文档里查出和问题对得上的段落,再让语言模型看着这些段落来回答。全程用 Python,在一台没有显卡的普通笔记本电脑上完成,用两个小模型,不需要账号,也不需要 API key。你会用 50 个问题测试它,读一读它答错的地方,不做任何训练就改掉一条事实,再看看这一切和上一页的 LoRA、全量微调有什么不同。这一页里的每个数字,都是在真实运行中测出来的。

🇬🇧 English

A language model knows what was in the text it was trained on, and nothing else. It has never seen your shop's price list, your school's timetable or the report you wrote last week. Ask it about them and it does one of two things. It says that it cannot help, or it makes up an answer that sounds right.

RAG is the simplest way round this, and its name says what it does. Retrieval: a program looks through your documents and takes out the few passages that fit the question. Augmented: it puts those passages into the prompt, in front of the question. Generation: the model writes its answer with the passages in front of it. Nothing about the model changes. It is the same model, with better things to read.

The job on this page continues the last one. The noodle shop in Chiang Mai whose orders we taught a model to read now has a name, Three Geckos Noodles, and customers who ask questions. What time do you close? How much is the khao soi? What is the Wi-Fi password? The answers are in the shop's handbook, a text file of 26 short passages. We invented the shop and wrote the handbook for this page, so no model can have seen it. We also wrote 50 test questions: 40 that the handbook answers, and 10 that it does not, because a good assistant must also know when it cannot answer.

With no handbook, the small model on this page gets 2 of the 40 right. With the three passages that the search finds for each question, it gets 31. You will also see what went wrong with the other 9: for 2 of them the search did not find the right passage, and for 7 the passage was there and the model still got it wrong. And you will see the weakness that RAG does not cure. Of the 10 questions that the handbook cannot answer, the model refused 3 and made something up for the other 7.

On this page you will:

  1. turn sentences into numbers, and search a handbook with them;
  2. look at the exact text that the model is given to read;
  3. ask the handbook a question, from start to finish, in one file;
  4. test it on 50 questions, three ways: with no handbook, with the passages found, and with the whole handbook;
  5. read the wrong answers, and find out whether the search or the model made each mistake;
  6. change a fact in the handbook and get the new answer, with no training;
  7. compare RAG with the LoRA and the full fine-tuning of the last page.

Nothing here was copied from a manual in the hope that it works. Each file was run on a Windows 11 laptop with no graphics card, and what it printed is shown under it. Both models run on that laptop. Once they are downloaded, nothing you ask and nothing in your documents leaves the computer: we ran the page's program with every connection to other computers shut, and it answered.

🇹🇭 ไทย

โมเดลภาษารู้เฉพาะสิ่งที่อยู่ในข้อความที่มันถูกฝึกมา นอกนั้นไม่รู้อะไรเลย มันไม่เคยเห็นใบราคาของร้านคุณ ตารางเรียนของโรงเรียนคุณ หรือรายงานที่คุณเขียนเมื่อสัปดาห์ก่อน ถ้าถามเรื่องพวกนี้ มันจะทำอย่างใดอย่างหนึ่งในสองอย่าง คือบอกว่าช่วยไม่ได้ หรือแต่งคำตอบที่ฟังดูถูกขึ้นมาเอง

RAG คือทางแก้ที่ง่ายที่สุด และชื่อของมันก็บอกอยู่แล้วว่ามันทำอะไร Retrieval (ค้นคืน): โปรแกรมไล่ดูเอกสารของคุณ แล้วหยิบท่อนข้อความไม่กี่ท่อนที่ตรงกับคำถามออกมา Augmented (เสริม): มันใส่ท่อนเหล่านั้นลงในพรอมต์ ไว้ข้างหน้าคำถาม Generation (สร้างคำตอบ): โมเดลเขียนคำตอบโดยมีท่อนเหล่านั้นวางอยู่ตรงหน้า ตัวโมเดลไม่ได้เปลี่ยนอะไรเลย มันคือโมเดลตัวเดิม ที่มีของดีกว่าเดิมให้อ่าน

งานในหน้านี้ต่อจากหน้าที่แล้ว ร้านก๋วยเตี๋ยวในเชียงใหม่ที่เราสอนโมเดลให้อ่านออร์เดอร์ ตอนนี้มีชื่อแล้วว่า Three Geckos Noodles และมีลูกค้าที่ถามคำถาม ร้านปิดกี่โมง ข้าวซอยราคาเท่าไร รหัส Wi-Fi คืออะไร คำตอบอยู่ในคู่มือของร้าน ซึ่งเป็นไฟล์ข้อความที่มีท่อนสั้น ๆ 26 ท่อน เราแต่งร้านนี้ขึ้นมาและเขียนคู่มือขึ้นเพื่อหน้านี้ จึงไม่มีโมเดลตัวไหนเคยเห็นมันมาก่อน เรายังเขียนคำถามทดสอบไว้ 50 ข้อ เป็นคำถามที่คู่มือตอบได้ 40 ข้อ และที่คู่มือตอบไม่ได้ 10 ข้อ เพราะผู้ช่วยที่ดีต้องรู้ด้วยว่าเมื่อไรที่ตัวเองตอบไม่ได้

เมื่อไม่มีคู่มือ โมเดลตัวเล็กในหน้านี้ตอบถูก 2 จาก 40 ข้อ เมื่อมีสามท่อนที่การค้นหาเจอสำหรับแต่ละคำถาม มันตอบถูก 31 ข้อ คุณจะได้เห็นด้วยว่าอีก 9 ข้อผิดเพราะอะไร มี 2 ข้อที่การค้นหาหาท่อนที่ถูกไม่เจอ และอีก 7 ข้อที่ท่อนนั้นอยู่ตรงหน้าแล้วแต่โมเดลก็ยังตอบผิด และคุณจะได้เห็นจุดอ่อนที่ RAG แก้ไม่ได้ ในคำถาม 10 ข้อที่คู่มือตอบไม่ได้ โมเดลปฏิเสธ 3 ข้อ และแต่งคำตอบขึ้นเองอีก 7 ข้อ

ในหน้านี้คุณจะ:

  1. เปลี่ยนประโยคเป็นตัวเลข แล้วใช้ตัวเลขนั้นค้นหาในคู่มือ
  2. ดูข้อความจริง ๆ ที่โมเดลได้รับให้อ่าน
  3. ถามคู่มือหนึ่งคำถาม ตั้งแต่ต้นจนจบ ในไฟล์เดียว
  4. ทดสอบกับคำถาม 50 ข้อ สามแบบ คือไม่มีคู่มือ มีท่อนที่ค้นเจอ และมีคู่มือทั้งเล่ม
  5. อ่านคำตอบที่ผิด แล้วหาว่าความผิดแต่ละข้อเป็นของการค้นหาหรือของโมเดล
  6. เปลี่ยนข้อเท็จจริงในคู่มือ แล้วได้คำตอบใหม่ โดยไม่ต้องฝึก
  7. เทียบ RAG กับ LoRA และการปรับจูนแบบเต็มของหน้าที่แล้ว

ไม่มีอะไรในหน้านี้ที่ลอกมาจากคู่มือการใช้งานแล้วหวังว่าจะใช้ได้ ไฟล์ทุกไฟล์ถูกรันจริงบนแล็ปท็อป Windows 11 ที่ไม่มีการ์ดจอ และสิ่งที่มันพิมพ์ออกมาก็แสดงไว้ใต้ไฟล์นั้น โมเดลทั้งสองตัวรันบนแล็ปท็อปเครื่องนั้น เมื่อดาวน์โหลดเสร็จแล้ว ไม่มีคำถามของคุณและไม่มีอะไรในเอกสารของคุณออกไปจากคอมพิวเตอร์ เรารันโปรแกรมของหน้านี้โดยปิดการเชื่อมต่อไปยังคอมพิวเตอร์เครื่องอื่นทั้งหมด และมันก็ยังตอบได้

🇨🇳 中文

语言模型只知道它训练时读过的文字里有什么,别的一概不知。它从没见过你店里的价目表、你学校的课表,或者你上周写的报告。问它这些,它只会做两件事中的一件:要么说帮不上忙,要么编一个听起来很对的答案。

RAG 是绕开这个问题最简单的办法,名字本身就说明了它做什么。Retrieval(检索):程序翻一遍你的文档,取出和问题对得上的那几段。Augmented(增强):把这几段放进提示词,放在问题前面。Generation(生成):模型看着这几段写出回答。模型本身一点没变。还是同一个模型,只是有了更好的东西可读。

这一页的任务接着上一页往下做。清迈那家面馆,我们教过模型读它的订单;现在它有了名字,叫 Three Geckos Noodles,也有了来问问题的顾客。你们几点关门?khao soi 多少钱?Wi-Fi 密码是什么?答案都在店里的手册里,那是一个文本文件,有 26 个短段落。这家店是我们虚构的,手册也是为这一页写的,所以没有哪个模型见过它。我们还写了 50 个测试问题:40 个手册能回答,10 个手册回答不了,因为一个好助手还得知道自己什么时候答不上来。

没有手册时,这一页的小模型在 40 个问题里答对 2 个。把搜索为每个问题找到的三段交给它,它答对 31 个。你还会看到另外 9 个错在哪里:其中 2 个是搜索没找到正确的段落,7 个是段落明明在眼前,模型还是答错了。你也会看到 RAG 治不好的那个弱点:在手册回答不了的 10 个问题里,模型拒答了 3 个,另外 7 个它编了答案。

在这一页里,你会:

  1. 把句子变成数字,再用这些数字搜索一本手册;
  2. 看一看交给模型去读的那段文字,一字不差;
  3. 在一个文件里,从头到尾向手册问一个问题;
  4. 用 50 个问题测试它,三种方式:不给手册、给找到的段落、给整本手册;
  5. 读一读答错的回答,弄清每个错误是搜索的,还是模型的;
  6. 改掉手册里的一条事实,不做训练就得到新的答案;
  7. 把 RAG 和上一页的 LoRA、全量微调放在一起比较。

这里没有哪一步是从说明书上抄来、指望它能用的。每个文件都在一台没有显卡的 Windows 11 笔记本上真正运行过,它打印的内容就显示在文件下面。两个模型都在那台笔记本上运行。下载完之后,你问的话和你文档里的内容都不会离开这台电脑:我们把通往其他电脑的连接全部切断,再运行这一页的程序,它照样回答了。

1Retrieve
Find the three passages of the handbook that fit the question best.หาสามท่อนในคู่มือที่ตรงกับคำถามที่สุด在手册里找出和问题最对得上的三段。
search.py
2Augment
Put those passages into the prompt, in front of the question.ใส่ท่อนเหล่านั้นลงในพรอมต์ ไว้ข้างหน้าคำถาม把这三段放进提示词,放在问题前面。
prompt.py
3Generate
The model reads all of it and writes the answer.โมเดลอ่านทั้งหมดนั้น แล้วเขียนคำตอบ模型把这些全部读完,写出回答。
ask.py
RAG CHANGES WHAT THE MODEL READS. FINE-TUNING CHANGES THE MODEL. The last page taught a model a new habit by changing its numbers: all of them with full fine-tuning, or a small add-on beside them with LoRA. RAG changes no number at all. It changes the prompt. So the knowledge ends up in different places. After fine-tuning it is inside the model, where nobody can read it or correct it. With RAG it stays in a text file that you can open and edit.That is why the two are not rivals. Facts are for looking up, and habits are for training. Steps 8 and 9 put RAG, LoRA and full fine-tuning side by side, with what each one costs when a fact changes.หน้าที่แล้วสอนนิสัยใหม่ให้โมเดลด้วยการเปลี่ยนตัวเลขของมัน เปลี่ยนทุกตัวเมื่อใช้การปรับจูนแบบเต็ม หรือเปลี่ยนตัวเสริมเล็ก ๆ ที่วางอยู่ข้างกันเมื่อใช้ LoRA ส่วน RAG ไม่เปลี่ยนตัวเลขเลยสักตัว มันเปลี่ยนพรอมต์ ความรู้จึงไปอยู่คนละที่ หลังการปรับจูน ความรู้อยู่ข้างในโมเดล ซึ่งไม่มีใครอ่านหรือแก้ได้ แต่กับ RAG ความรู้ยังอยู่ในไฟล์ข้อความที่คุณเปิดและแก้ไขได้เพราะอย่างนี้สองวิธีนี้จึงไม่ใช่คู่แข่งกัน ข้อเท็จจริงมีไว้ค้นดู ส่วนนิสัยมีไว้ฝึก ขั้นที่ 8 และ 9 วาง RAG, LoRA และการปรับจูนแบบเต็มไว้เทียบกัน พร้อมสิ่งที่แต่ละวิธีต้องจ่ายเมื่อข้อเท็จจริงเปลี่ยน上一页通过改动模型的数字,教给它一个新习惯:全量微调改动全部数字,LoRA 改动放在旁边的一个小附加模块。RAG 一个数字都不改。它改的是提示词。于是知识落在了不同的地方。微调之后,知识在模型里面,谁也读不了、改不了。用 RAG,知识留在一个你可以打开、可以编辑的文本文件里。所以这两样并不是对手。事实靠查,习惯靠练。第 8 步和第 9 步把 RAG、LoRA 和全量微调并排放在一起,也列出事实变了的时候各要付出什么。
Fileไฟล์文件What it isคืออะไร它是什么Where you use itใช้ตรงไหน用在哪里
handbook.txtThe shop's handbook: the passages that hold the facts. Download it.คู่มือของร้าน: ท่อนข้อความที่เก็บข้อเท็จจริงไว้ ดาวน์โหลดไฟล์นี้ไว้店里的手册:存放事实的那些段落。请下载它。Step 1, and every step after itขั้นที่ 1 และทุกขั้นหลังจากนั้น第 1 步,以及之后的每一步
questions.jsonlThe test: 50 questions, each with the answers we accept. Download it.ชุดทดสอบ: คำถาม 50 ข้อ แต่ละข้อมีคำตอบที่เรายอมรับกำกับไว้ ดาวน์โหลดไฟล์นี้ไว้测试:50 个问题,每个都附有我们认可的答案。请下载它。Steps 3 and 6ขั้นที่ 3 และ 6第 3 步和第 6 步
embed.pyTurns four sentences into numbers and compares them.เปลี่ยนประโยคสี่ประโยคเป็นตัวเลข แล้วเทียบกัน把四个句子变成数字,再互相比较。Step 2ขั้นที่ 2第 2 步
search.pyFinds the three best passages for every test question.หาสามท่อนที่ดีที่สุดให้คำถามทดสอบทุกข้อ为每个测试问题找出最好的三段。Step 3ขั้นที่ 3第 3 步
prompt.pyShows the whole text that the model is given to read.แสดงข้อความทั้งหมดที่โมเดลได้รับให้อ่าน显示交给模型去读的全部文字。Step 4ขั้นที่ 4第 4 步
ask.pyAsks the handbook one question.ถามคู่มือหนึ่งคำถาม向手册问一个问题。Steps 5 and 8ขั้นที่ 5 และ 8第 5 步和第 8 步
answer.pyAsks all 50 test questions, one of three ways, and marks the replies.ถามคำถามทดสอบทั้ง 50 ข้อ ด้วยแบบใดแบบหนึ่งในสามแบบ แล้วตรวจคำตอบ用三种方式之一问完全部 50 个测试问题,并给回复判分。Steps 6 and 7ขั้นที่ 6 และ 7第 6 步和第 7 步
YOU NEED PYTHON 3.10 OR NEWER, 2 GB OF DISK, AND NO GRAPHICS CARD You type the commands on this page into a terminal: PowerShell on Windows, Terminal on a Mac. The libraries take 1041.7 MB of disk, the model that searches 91.6 MB, and the model that answers 712.0 MB. The largest run on this page held 1.9 GB of memory. On our laptop one answer took 2.0 seconds.You do not need the files of the last page. The page is easier to follow if you have read it, because it uses the same shop and the same three calls to load a model and get a reply from it.คำสั่งในหน้านี้พิมพ์ลงในเทอร์มินัล บน Windows คือ PowerShell บนแมคคือ Terminal ไลบรารีใช้พื้นที่ดิสก์ 1041.7 MB โมเดลที่ใช้ค้นหาใช้ 91.6 MB และโมเดลที่ใช้ตอบใช้ 712.0 MB การรันที่ใหญ่ที่สุดในหน้านี้ใช้หน่วยความจำ 1.9 GB บนแล็ปท็อปของเรา คำตอบหนึ่งข้อใช้เวลา 2.0 วินาทีคุณไม่จำเป็นต้องมีไฟล์ของหน้าที่แล้ว แต่หน้านี้จะตามง่ายขึ้นถ้าคุณอ่านหน้านั้นมาก่อน เพราะใช้ร้านเดียวกัน และใช้สามคำสั่งเดิมในการโหลดโมเดลและรับคำตอบจากมัน这一页的命令要在终端里输入:Windows 上是 PowerShell,Mac 上是“终端”。库占 1041.7 MB 磁盘,负责搜索的模型占 91.6 MB,负责回答的模型占 712.0 MB。这一页里最大的一次运行占用了 1.9 GB 内存。在我们的笔记本上,一个回答用时 2.0 秒。你不需要上一页的文件。不过读过上一页会更容易跟上,因为这里用的是同一家店,加载模型、拿到回复用的也是同样的三个调用。
Wordคำ词What it means on this pageความหมายในหน้านี้在这一页里的意思
RAGRetrieval-augmented generation. Look up the passages that fit a question, put them into the prompt, and let a language model write the answer from them.Retrieval-augmented generation คือค้นหาท่อนข้อความที่ตรงกับคำถาม ใส่ลงในพรอมต์ แล้วให้โมเดลภาษาเขียนคำตอบจากท่อนเหล่านั้น检索增强生成(retrieval-augmented generation)。先查出和问题对得上的段落,放进提示词,再让语言模型根据它们写出回答。
retrievalFinding the passages that fit a question. This page also calls it the search.การค้นคืน: การหาท่อนข้อความที่ตรงกับคำถาม หน้านี้เรียกมันว่าการค้นหาด้วย检索:找出和问题对得上的段落。这一页也把它叫作搜索。
embedding, vectorA list of numbers that stands for the meaning of a piece of text. Two texts that mean nearly the same get nearly the same numbers. A vector is any list of numbers; an embedding is a vector made from a text.เอมเบดดิ้ง: รายการตัวเลขที่ใช้แทนความหมายของข้อความชิ้นหนึ่ง ข้อความสองชิ้นที่มีความหมายเกือบเหมือนกันจะได้ตัวเลขที่เกือบเหมือนกัน เวกเตอร์คือรายการตัวเลขอะไรก็ได้ ส่วนเอมเบดดิ้งคือเวกเตอร์ที่สร้างมาจากข้อความ嵌入:一串数字,代表一段文字的意思。意思差不多的两段文字,得到的数字也差不多。向量指任何一串数字;嵌入是由一段文字得来的向量。
embedding modelA small model that turns a text into its embedding. It writes nothing.โมเดลเอมเบดดิ้ง: โมเดลตัวเล็กที่เปลี่ยนข้อความเป็นเอมเบดดิ้งของมัน มันไม่เขียนอะไรออกมาเลย嵌入模型:把一段文字变成它的嵌入的小模型。它什么也不写。
passage, chunkA piece of a document, small enough to be about one thing. Most people who write about RAG call it a chunk, and cutting a document into pieces is called chunking.ท่อนข้อความ: ชิ้นส่วนของเอกสารที่เล็กพอจะพูดถึงเรื่องเดียว คนส่วนใหญ่ที่เขียนเรื่อง RAG เรียกมันว่า chunk และเรียกการตัดเอกสารเป็นชิ้น ๆ ว่า chunking段落:文档的一小块,小到只讲一件事。写 RAG 的人大多把它叫作 chunk(块),把文档切成小块叫作 chunking(切块)。
scoreOne number that says how near two embeddings are. Its full name is cosine similarity. Near 1, the two texts mean nearly the same. Near 0, they have little to do with each other.คะแนน: ตัวเลขหนึ่งตัวที่บอกว่าเอมเบดดิ้งสองชุดอยู่ใกล้กันแค่ไหน ชื่อเต็มของมันคือ cosine similarity ถ้าใกล้ 1 ข้อความสองชิ้นมีความหมายเกือบเหมือนกัน ถ้าใกล้ 0 สองชิ้นนั้นแทบไม่เกี่ยวกัน分数:一个数字,表示两个嵌入靠得有多近。它的全名是余弦相似度(cosine similarity)。接近 1,两段文字意思差不多;接近 0,两者没什么关系。
promptThe whole text that a model is given to read: the instruction, the passages, and the question.พรอมต์: ข้อความทั้งหมดที่โมเดลได้รับให้อ่าน คือคำสั่ง ท่อนข้อความ และคำถาม提示词:交给模型去读的全部文字:指令、段落和问题。
documentIn a prompt, one piece of text that the model should answer from. On this page each document is one passage of the handbook.เอกสาร: ในพรอมต์ หมายถึงข้อความหนึ่งชิ้นที่โมเดลควรใช้ตอบ ในหน้านี้เอกสารแต่ละชิ้นคือหนึ่งท่อนของคู่มือ文档:在提示词里,指模型应当据以回答的一段文字。在这一页里,每个文档就是手册的一个段落。
chat templateA small program that comes with a model. It writes a chat, and the documents, out as the one piece of text the model was trained on.แชตเทมเพลต: โปรแกรมเล็ก ๆ ที่มากับโมเดล มันเขียนบทสนทนาและเอกสารออกมาเป็นข้อความชิ้นเดียว ในรูปแบบที่โมเดลถูกฝึกมา聊天模板:随模型一起来的一小段程序。它把对话和文档写成一整段文字,就是模型训练时用的那种格式。
readerThe language model that reads the prompt and writes the answer.ตัวอ่าน: โมเดลภาษาที่อ่านพรอมต์แล้วเขียนคำตอบ阅读模型:读提示词并写出回答的那个语言模型。
to make upTo write an answer that sounds right and is not in the documents. The usual word for it is hallucination.แต่งขึ้นเอง: เขียนคำตอบที่ฟังดูถูกแต่ไม่มีอยู่ในเอกสาร คำที่ใช้เรียกกันทั่วไปคือ hallucination编造:写出一个听起来很对、文档里却没有的答案。通常的说法是幻觉(hallucination)。
refusalA reply in which the model says that it cannot answer. For a question that the documents do not answer, a refusal is the right reply.การปฏิเสธ: คำตอบที่โมเดลบอกว่ามันตอบไม่ได้ สำหรับคำถามที่เอกสารไม่มีคำตอบ การปฏิเสธคือคำตอบที่ถูก拒答:模型说自己答不了的回复。对于文档里没有答案的问题,拒答才是正确的回复。
tokenA piece of text that a model handles as one unit: a word, a part of a word, or a punctuation mark. A longer prompt has more tokens, and takes longer to read.โทเคน: ชิ้นของข้อความที่โมเดลจัดการเป็นหนึ่งหน่วย อาจเป็นคำ ส่วนหนึ่งของคำ หรือเครื่องหมายวรรคตอน พรอมต์ที่ยาวกว่ามีโทเคนมากกว่า และใช้เวลาอ่านนานกว่า模型当作一个单位来处理的一小段文字:一个词、词的一部分,或者一个标点。提示词越长,token 越多,读起来也越久。
vector databaseA program that stores a great many embeddings and finds the nearest ones quickly. This page does not need one: its handbook has 26 passages.ฐานข้อมูลเวกเตอร์: โปรแกรมที่เก็บเอมเบดดิ้งจำนวนมหาศาล และหาตัวที่ใกล้ที่สุดได้อย่างรวดเร็ว หน้านี้ไม่จำเป็นต้องใช้ เพราะคู่มือมีแค่ 26 ท่อน向量数据库:存放大量嵌入、并能很快找出最近的那些的程序。这一页用不着它:手册只有 26 个段落。

1 One more library, and a handbook · ไลบรารีอีกหนึ่งตัว กับคู่มือหนึ่งเล่ม · 再装一个库,再加一本手册

🇬🇧 English

Make a new folder for this page and open a terminal in it. The first command below makes a virtual environment, which is a separate copy of Python with its own libraries, kept in a folder named venv. The second installs three libraries into it.

torch and transformers are the two libraries of the last page. PyTorch does the arithmetic. transformers knows how to download a model, how to turn text into tokens, and how to run the model. sentence-transformers is the new one. It runs embedding models, the small models that this page searches with. It is built on the other two and would bring them along by itself; the command names all three so that you can see what you depend on.

If you still have the folder of the last page, you can work in it and add the one new library to its venv with venv\Scripts\python -m pip install sentence-transformers. We ran the files of this page both ways. On a Mac, write venv/bin/python wherever this page writes venv\Scripts\python. On Linux, first read the note about the small torch in step 1 of the last page.

🇹🇭 ไทย

สร้างโฟลเดอร์ใหม่สำหรับหน้านี้ แล้วเปิดเทอร์มินัลในโฟลเดอร์นั้น คำสั่งแรกข้างล่างสร้างสภาพแวดล้อมเสมือน ซึ่งก็คือ Python อีกชุดที่แยกออกมา มีไลบรารีเป็นของตัวเอง เก็บอยู่ในโฟลเดอร์ชื่อ venv คำสั่งที่สองติดตั้งไลบรารีสามตัวลงไปในนั้น

torch และ transformers คือไลบรารีสองตัวของหน้าที่แล้ว PyTorch ทำหน้าที่คำนวณ ส่วน transformers รู้วิธีดาวน์โหลดโมเดล วิธีแปลงข้อความเป็นโทเคน และวิธีรันโมเดล sentence-transformers คือตัวใหม่ มันรันโมเดลเอมเบดดิ้ง ซึ่งเป็นโมเดลตัวเล็กที่หน้านี้ใช้ค้นหา มันสร้างอยู่บนอีกสองตัว และจะดึงสองตัวนั้นมาเองอยู่แล้ว แต่คำสั่งนี้ระบุชื่อทั้งสามตัว เพื่อให้คุณเห็นว่าคุณพึ่งพาอะไรบ้าง

ถ้าคุณยังมีโฟลเดอร์ของหน้าที่แล้วอยู่ คุณทำงานในโฟลเดอร์นั้นได้เลย แล้วเพิ่มไลบรารีใหม่ตัวเดียวลงใน venv ของมันด้วย venv\Scripts\python -m pip install sentence-transformers เรารันไฟล์ของหน้านี้ทั้งสองแบบแล้ว บนแมค ให้พิมพ์ venv/bin/python ในทุกที่ที่หน้านี้เขียนว่า venv\Scripts\python บน Linux ให้อ่านหมายเหตุเรื่อง torch ตัวเล็กในขั้นที่ 1 ของหน้าที่แล้วก่อน

🇨🇳 中文

为这一页新建一个文件夹,并在里面打开终端。下面第一条命令创建一个虚拟环境,也就是一份单独的 Python,有自己的一套库,放在名叫 venv 的文件夹里。第二条命令往里面安装三个库。

torch 和 transformers 是上一页的那两个库。PyTorch 负责运算。transformers 会下载模型,会把文字变成 token,也会运行模型。sentence-transformers 是新来的。它用来运行嵌入模型,也就是这一页用来搜索的小模型。它建立在另外两个库之上,本来会自动把它们带进来;命令里把三个都写出来,是为了让你看清自己依赖了什么。

如果上一页的文件夹还在,你可以直接在里面做,往它的 venv 里加上这一个新库:venv\Scripts\python -m pip install sentence-transformers。这一页的文件,两种方式我们都运行过。在 Mac 上,凡是这一页写 venv\Scripts\python 的地方,都要写成 venv/bin/python。在 Linux 上,请先读上一页第 1 步里关于小版本 torch 的说明。

🪟 WINDOWS

python -m venv venv
venv\Scripts\python -m pip install torch transformers sentence-transformers

🍎 MAC · not run by us · เราไม่ได้รันเอง · 我们没有运行过

python3 -m venv venv
venv/bin/python -m pip install torch transformers sentence-transformers

🇬🇧 English

Then save two files into the folder. Each is folded away below, with a Download button above it.

handbook.txt is everything the shop knows: 26 passages of 22 to 41 words. Each passage begins with a title in capital letters and ends with an empty line. Open it and read a few. Nothing in this file is special to RAG. It is plain text that a person could have typed, and that is the point of the method.

questions.jsonl is the test: 50 questions, one on each line. answer_in names the passage that holds the answer, and accept lists the ways of writing the answer that we count as right. For 10 of the questions answer_in is null. The handbook does not say, and the right reply is to say so.

🇹🇭 ไทย

จากนั้นบันทึกไฟล์สองไฟล์ลงในโฟลเดอร์ แต่ละไฟล์พับเก็บไว้ข้างล่าง มีปุ่มดาวน์โหลดอยู่ข้างบน

handbook.txt คือทุกอย่างที่ร้านรู้: 26 ท่อน ยาวท่อนละ 22 ถึง 41 คำ แต่ละท่อนขึ้นต้นด้วยชื่อหัวข้อเป็นตัวพิมพ์ใหญ่ และจบด้วยบรรทัดว่าง เปิดดูแล้วอ่านสักสองสามท่อน ไม่มีอะไรในไฟล์นี้ที่ทำมาเพื่อ RAG โดยเฉพาะ มันเป็นข้อความธรรมดาที่คนพิมพ์เองได้ และนั่นคือหัวใจของวิธีนี้

questions.jsonl คือชุดทดสอบ: คำถาม 50 ข้อ บรรทัดละข้อ answer_in บอกชื่อท่อนที่มีคำตอบ และ accept คือรายการวิธีเขียนคำตอบที่เรานับว่าถูก มีคำถาม 10 ข้อที่ answer_in เป็น null คือคู่มือไม่ได้บอกไว้ และคำตอบที่ถูกคือการบอกว่าไม่มีคำตอบ

🇨🇳 中文

然后把两个文件存进这个文件夹。它们都折叠在下面,上方各有一个下载按钮。

handbook.txt 是这家店知道的全部:26 个段落,每段 22 到 41 个词。每个段落以一行大写的标题开头,以一个空行结束。打开它,读上几段。这个文件里没有任何专为 RAG 准备的东西。它就是一个人可以敲出来的普通文字,而这正是这种方法的要点。

questions.jsonl 是测试:50 个问题,一行一个。answer_in 写的是答案所在段落的标题,accept 列出我们算作正确的几种答案写法。其中 10 个问题的 answer_in 是 null:手册没说,正确的回复就是说明这一点。

handbook.txt, the whole of it · handbook.txt ทั้งไฟล์ · handbook.txt,完整内容
OPENING HOURS
Three Geckos Noodles is open from 10 in the morning until 9 at night. The kitchen takes its last orders at 8:30 pm. The shop is closed every Wednesday.

WHERE WE ARE
The shop is on Suthep Road in Chiang Mai, 200 metres west of the Ton Payom market, next to a bicycle repair shop. Look for the green sign with three geckos on it.

THE FOUR DISHES
Khao soi costs 60 baht. Nam ngiao costs 50 baht. Pad thai costs 60 baht. Pad see ew costs 55 baht. A large bowl of any dish is 15 baht more.

MEAT, TOFU AND EGG
Every dish comes with chicken, pork, beef or tofu. Beef costs 10 baht extra. A fried egg on top is 10 baht.

HOW SPICY
There are four levels: none, mild, medium and hot. If a customer does not say, the cook makes the dish medium. Chilli flakes and pickled chillies are on every table for people who want more.

DRINKS
Thai iced tea is 30 baht, longan juice is 25 baht, and a bottle of water is 10 baht. The shop does not sell beer or any other alcohol.

DESSERT
Mango sticky rice costs 70 baht. It is only on the menu from March to June, when mangoes are in season. For the rest of the year the dessert is coconut ice cream at 35 baht.

VEGETARIAN FOOD
Any dish can be made with tofu. The curry paste in the usual khao soi contains shrimp paste, so it is not vegetarian. Ask for the jay khao soi, which uses a paste without shrimp and costs the same.

ALLERGIES
Pad thai is made with crushed peanuts and with fish sauce. The cook can leave the peanuts out. The egg noodles in khao soi contain wheat and egg. The rice noodles in the other three dishes contain neither.

TAKEAWAY
Takeaway food goes in a paper box, which costs 5 baht. A customer who brings a container from home gets 5 baht off instead. The soup is packed in its own bag so that the noodles stay firm.

DELIVERY
A rider on a motorbike delivers to addresses within 3 kilometres of the shop. Delivery costs 20 baht, and it is free for orders over 300 baht. Delivery runs from 11 am to 8 pm.

HOW TO PAY
The shop takes cash and PromptPay. The QR code is at the counter. It does not take credit cards.

SEATS
There are 24 seats inside and 8 more at the tables on the pavement. The room inside has fans but no air conditioning.

BOOKING A TABLE
The shop does not take bookings for small groups. A group of 8 or more should book one day ahead with a LINE message.

CATERING
The shop cooks for parties and offices. The smallest catering order is 20 bowls, and it needs three days' notice. A catering bowl costs the same as a bowl in the shop.

HOLIDAYS
The shop is closed from 13 to 15 April for Songkran, and on 31 December and 1 January. On the night of Loy Krathong it stays open until 11 pm.

WI-FI
Customers can use the Wi-Fi network named ThreeGeckos. The password is khaosoi2026. It is written on the wall beside the fridge.

PARKING
Motorbikes park in front of the shop. There are four spaces for cars behind the building. When those are full, the car park of the temple across the road costs 20 baht.

THE LOYALTY CARD
The shop stamps a card for every bowl. The tenth bowl is free. A card is valid for six months from its first stamp.

WHO WE ARE
Auntie Noi opened the shop in 2011 and still owns it. Her brother, Uncle Daeng, is the cook. The khao soi recipe came from their grandmother in Lampang.

CHILDREN
A child's bowl is a half portion for 35 baht, and it is never spicy. The shop has two high chairs.

BUSY TIMES
The shop is busiest from noon to 1 pm, when the wait for a table can be 20 minutes. The quietest time is between 3 and 5 in the afternoon.

HOW TO REACH US
The LINE account is @threegeckos. The phone number is 053 555 0142. Messages are answered during opening hours.

KHAO SOI
Khao soi is egg noodles in a curry soup made with coconut milk. It is topped with crispy fried noodles and served with pickled mustard greens, shallots and a wedge of lime.

NAM NGIAO
Nam ngiao is thin rice noodles in a sour tomato broth, with the dried flowers of the red cotton tree. It is the oldest dish on the menu.

LOST THINGS
Things left in the shop are kept in a box under the counter for 30 days. After that they are given to the temple.
questions.jsonl, all 50 lines · questions.jsonl ครบทั้ง 50 บรรทัด · questions.jsonl,全部 50 行
{"question": "What time do you close?", "answer_in": "OPENING HOURS", "accept": ["9 pm", "9pm", "9 at night", "9:00", "21:00"]}
{"question": "Are you open on Wednesdays?", "answer_in": "OPENING HOURS", "accept": ["closed", "not open"]}
{"question": "What is the latest I can order in the evening?", "answer_in": "OPENING HOURS", "accept": ["8:30"]}
{"question": "Which road is the shop on?", "answer_in": "WHERE WE ARE", "accept": ["Suthep"]}
{"question": "How much is a bowl of khao soi?", "answer_in": "THE FOUR DISHES", "accept": ["60"]}
{"question": "What does nam ngiao cost?", "answer_in": "THE FOUR DISHES", "accept": ["50"]}
{"question": "How much more is a large bowl?", "answer_in": "THE FOUR DISHES", "accept": ["15"]}
{"question": "What does a fried egg on top cost?", "answer_in": "MEAT, TOFU AND EGG", "accept": ["10"]}
{"question": "How spicy will my food be if I say nothing about it?", "answer_in": "HOW SPICY", "accept": ["medium"]}
{"question": "How much is a Thai iced tea?", "answer_in": "DRINKS", "accept": ["30"]}
{"question": "What kind of juice do you have?", "answer_in": "DRINKS", "accept": ["longan"]}
{"question": "In which months can I get mango sticky rice?", "answer_in": "DESSERT", "accept": ["March"]}
{"question": "What is the dessert in October?", "answer_in": "DESSERT", "accept": ["coconut ice cream"]}
{"question": "I am vegetarian. Which khao soi should I ask for?", "answer_in": "VEGETARIAN FOOD", "accept": ["jay"]}
{"question": "My son cannot eat peanuts. Which dish has them?", "answer_in": "ALLERGIES", "accept": ["pad thai"]}
{"question": "What do I pay for the takeaway box?", "answer_in": "TAKEAWAY", "accept": ["5 baht"]}
{"question": "How far from the shop will you bring food?", "answer_in": "DELIVERY", "accept": ["3 kilometres", "3 kilometers", "3 km", "3km"]}
{"question": "What is the charge for delivery?", "answer_in": "DELIVERY", "accept": ["20"]}
{"question": "How much must I order to get it delivered for free?", "answer_in": "DELIVERY", "accept": ["300"]}
{"question": "I have no cash. How else can I pay?", "answer_in": "HOW TO PAY", "accept": ["promptpay"]}
{"question": "How many people can sit inside?", "answer_in": "SEATS", "accept": ["24"]}
{"question": "We are ten people. How long ahead must we book?", "answer_in": "BOOKING A TABLE", "accept": ["one day", "a day", "1 day"]}
{"question": "What is the smallest order you will cater?", "answer_in": "CATERING", "accept": ["20"]}
{"question": "How much warning do you need for a party order?", "answer_in": "CATERING", "accept": ["three days", "3 days"]}
{"question": "Are you open during Songkran?", "answer_in": "HOLIDAYS", "accept": ["closed", "not open"]}
{"question": "How late do you stay open on Loy Krathong?", "answer_in": "HOLIDAYS", "accept": ["11 pm", "11pm", "11:00", "23:00"]}
{"question": "What is the password for the internet?", "answer_in": "WI-FI", "accept": ["khaosoi2026"]}
{"question": "Where can I leave my car?", "answer_in": "PARKING", "accept": ["behind", "temple"]}
{"question": "Which bowl do I get for nothing with the stamp card?", "answer_in": "THE LOYALTY CARD", "accept": ["tenth", "10th"]}
{"question": "For how long can I use my stamp card?", "answer_in": "THE LOYALTY CARD", "accept": ["six months", "6 months"]}
{"question": "Who is the owner?", "answer_in": "WHO WE ARE", "accept": ["Noi"]}
{"question": "Who does the cooking?", "answer_in": "WHO WE ARE", "accept": ["Daeng"]}
{"question": "In what year did the shop open?", "answer_in": "WHO WE ARE", "accept": ["2011"]}
{"question": "What does a bowl for a small child cost?", "answer_in": "CHILDREN", "accept": ["35"]}
{"question": "How long might I wait for a table at lunchtime?", "answer_in": "BUSY TIMES", "accept": ["20 minutes", "twenty minutes"]}
{"question": "What number do I call?", "answer_in": "HOW TO REACH US", "accept": ["053 555 0142", "053-555-0142", "0535550142"]}
{"question": "What is your LINE name?", "answer_in": "HOW TO REACH US", "accept": ["threegeckos"]}
{"question": "What goes on top of the khao soi?", "answer_in": "KHAO SOI", "accept": ["crispy"]}
{"question": "What is the soup of nam ngiao made from?", "answer_in": "NAM NGIAO", "accept": ["tomato"]}
{"question": "I left my umbrella in the shop last week. Where would it be?", "answer_in": "LOST THINGS", "accept": ["under the counter", "box"]}
{"question": "Do you have a second shop in Bangkok?", "answer_in": null, "accept": []}
{"question": "How much is a bowl of ramen?", "answer_in": null, "accept": []}
{"question": "Which football team does the cook support?", "answer_in": null, "accept": []}
{"question": "Do you sell gift cards?", "answer_in": null, "accept": []}
{"question": "May I bring my dog inside?", "answer_in": null, "accept": []}
{"question": "Is there a toilet for customers?", "answer_in": null, "accept": []}
{"question": "What is the name of the bicycle repair shop next door?", "answer_in": null, "accept": []}
{"question": "How many calories are in the pad thai?", "answer_in": null, "accept": []}
{"question": "Who painted the sign?", "answer_in": null, "accept": []}
{"question": "What is Auntie Noi's phone number at home?", "answer_in": null, "accept": []}
YOU GET A folder named venv of 1041.7 MB. Ours held torch 2.14.1, transformers 5.19.0 and sentence-transformers 6.1.0, and every result on this page comes from those versions. And two small text files: a handbook of 802 words, and a test of 50 questions.โฟลเดอร์ชื่อ venv ขนาด 1041.7 MB ของเรามี torch 2.14.1, transformers 5.19.0 และ sentence-transformers 6.1.0 และผลลัพธ์ทุกอย่างในหน้านี้ได้จากเวอร์ชันเหล่านี้ กับไฟล์ข้อความเล็ก ๆ สองไฟล์ คือคู่มือ 802 คำ และชุดทดสอบ 50 ข้อ一个名叫 venv 的文件夹,1041.7 MB。我们的环境里是 torch 2.14.1、transformers 5.19.0 和 sentence-transformers 6.1.0,这一页的所有结果都出自这几个版本。还有两个小小的文本文件:一本 802 个词的手册,和一份 50 个问题的测试。

2 Sentences into numbers · เปลี่ยนประโยคเป็นตัวเลข · 把句子变成数字

🇬🇧 English

An embedding model reads a piece of text and gives back a list of numbers. The one on this page, all-MiniLM-L6-v2, gives 384 numbers for any text, whether the text is three words or a paragraph. The list is called an embedding, or a vector.

The numbers mean nothing one by one. What matters is how the model learned to make them. It was trained on more than a billion pairs of sentences that belong together, and it learned to tell, for one sentence of a pair, which of many other sentences was its partner. So two texts that belong together get numbers that lie near each other, even when they share no word.

embedder.encode turns a text into its numbers. To compare two embeddings, you multiply them number by number and add everything up, and that is all the @ in this file does. With normalize_embeddings=True the result is a score between -1 and 1. Near 1, the two texts mean nearly the same. Near 0, they have little to do with each other.

🇹🇭 ไทย

โมเดลเอมเบดดิ้งอ่านข้อความชิ้นหนึ่ง แล้วคืนรายการตัวเลขกลับมา ตัวที่ใช้ในหน้านี้คือ all-MiniLM-L6-v2 ให้ตัวเลข 384 ตัวสำหรับข้อความใดก็ตาม ไม่ว่าข้อความนั้นจะยาวสามคำหรือหนึ่งย่อหน้า รายการตัวเลขนี้เรียกว่าเอมเบดดิ้ง หรือเวกเตอร์

ตัวเลขแต่ละตัวไม่มีความหมายในตัวเอง สิ่งที่สำคัญคือโมเดลเรียนรู้ที่จะสร้างมันมาอย่างไร มันถูกฝึกด้วยคู่ประโยคที่เข้าคู่กันมากกว่าหนึ่งพันล้านคู่ และเรียนรู้ที่จะบอกให้ได้ว่า ประโยคหนึ่งในคู่นั้นมีประโยคไหนในบรรดาประโยคอื่นจำนวนมากเป็นคู่ของมัน ข้อความสองชิ้นที่เข้าคู่กันจึงได้ตัวเลขที่อยู่ใกล้กัน แม้จะไม่มีคำไหนตรงกันเลย

embedder.encode เปลี่ยนข้อความเป็นตัวเลขของมัน การเทียบเอมเบดดิ้งสองชุดทำได้โดยคูณกันทีละตัวแล้วบวกทั้งหมดเข้าด้วยกัน และ @ ในไฟล์นี้ก็ทำแค่นั้น เมื่อใช้ normalize_embeddings=True ผลลัพธ์จะเป็นคะแนนระหว่าง -1 ถึง 1 ถ้าใกล้ 1 ข้อความสองชิ้นมีความหมายเกือบเหมือนกัน ถ้าใกล้ 0 สองชิ้นนั้นแทบไม่เกี่ยวกัน

🇨🇳 中文

嵌入模型读一段文字,交回一串数字。这一页用的是 all-MiniLM-L6-v2,不管文字是三个词还是一整段,它都给出 384 个数字。这串数字叫作嵌入,也叫向量。

这些数字单个看没有任何意思。要紧的是模型是怎样学会造出它们的。它用十亿多对彼此相配的句子训练过,学的是:给出一对里的一句,从许多别的句子当中认出哪一句是它的搭档。所以相配的两段文字,得到的数字彼此靠近,哪怕它们没有一个词相同。

embedder.encode 把一段文字变成它的数字。比较两个嵌入,就是把它们一个数一个数地相乘,再全部加起来,这个文件里的 @ 做的就只是这件事。加上 normalize_embeddings=True,结果是一个 -1 到 1 之间的分数。接近 1,两段文字意思差不多;接近 0,两者没什么关系。

💻 RUN IT

venv\Scripts\python embed.py

📄 NEW FILE · embed.py

"""embed.py - turn sentences into numbers, and see which ones lie near each other.

    python embed.py

The first run downloads the embedding model, about 90 MB.
"""
from sentence_transformers import SentenceTransformer

EMBEDDER = "sentence-transformers/all-MiniLM-L6-v2"
QUESTION = "Is there somewhere to park?"
SENTENCES = [
    "There are four spaces for cars behind the building.",
    "The shop is closed every Wednesday.",
    "Khao soi is egg noodles in a curry soup made with coconut milk.",
]


def main():
    embedder = SentenceTransformer(EMBEDDER)
    # normalize_embeddings=True scales the numbers, so that the scores
    # further down come out between -1 and 1.
    question_vector = embedder.encode(QUESTION, normalize_embeddings=True)
    print(f"The question became {len(question_vector)} numbers. The first five:")
    print(question_vector[:5])
    print()

    sentence_vectors = embedder.encode(SENTENCES, normalize_embeddings=True)
    # @ multiplies each sentence's numbers with the question's, pair by pair,
    # and adds them up. That gives one score for each sentence: near 1 when it
    # means nearly the same as the question, near 0 when it means something else.
    scores = sentence_vectors @ question_vector
    print(QUESTION)
    for place in range(len(SENTENCES)):
        print(f"{scores[place]:8.2f}  {SENTENCES[place]}")


if __name__ == "__main__":
    main()

🖨️ WHAT IT PRINTED

The question became 384 numbers. The first five:
[0.10762142 0.00705895 0.02602852 0.00239098 0.02153246]

Is there somewhere to park?
    0.30  There are four spaces for cars behind the building.
    0.07  The shop is closed every Wednesday.
   -0.00  Khao soi is egg noodles in a curry soup made with coconut milk.

🇬🇧 English

The question asks where to park. The first sentence never says park. It says spaces for cars. It still scores 0.30, far above the sentence about Wednesdays, at 0.07, and the one about khao soi, at -0.00. A search for the word would have found nothing. A search by meaning found the right sentence.

Notice how low the winning score is. 0.30 is nowhere near 1. A score from this model is good for one thing only: comparing passages with each other, for the same question. It is not a mark out of 1, and it does not say how sure the search is. Step 3 has a warning about that.

Our page Meaning, as a row of numbers spends much longer on embeddings: what they tell apart, what they confuse, and how the same idea works across languages.

🇹🇭 ไทย

คำถามถามว่าจอดรถได้ที่ไหน ประโยคแรกไม่มีคำว่า park เลย มันเขียนว่า spaces for cars แต่ก็ยังได้คะแนน 0.30 สูงกว่าประโยคเรื่องวันพุธที่ได้ 0.07 และประโยคเรื่องข้าวซอยที่ได้ -0.00 อยู่มาก การค้นหาด้วยคำจะไม่เจออะไรเลย แต่การค้นหาด้วยความหมายเจอประโยคที่ถูก

สังเกตว่าคะแนนที่ชนะนั้นต่ำแค่ไหน 0.30 ไม่ได้ใกล้ 1 เลย คะแนนจากโมเดลนี้ใช้ได้กับเรื่องเดียว คือเทียบท่อนต่าง ๆ กันเองสำหรับคำถามเดียวกัน มันไม่ใช่คะแนนเต็ม 1 และไม่ได้บอกว่าการค้นหามั่นใจแค่ไหน ขั้นที่ 3 มีคำเตือนเรื่องนี้

หน้า ความหมาย ในรูปแถวของตัวเลข ของเราพูดเรื่องเอมเบดดิ้งไว้ยาวกว่านี้มาก ว่ามันแยกอะไรออกจากกันได้ สับสนอะไรบ้าง และแนวคิดเดียวกันนี้ใช้ข้ามภาษาได้อย่างไร

🇨🇳 中文

问题问的是哪里可以停车。第一个句子从头到尾没有 park 这个词,它写的是 spaces for cars。它还是得了 0.30 分,远高于讲星期三的那句(0.07)和讲 khao soi 的那句(-0.00)。按词去搜,什么也找不到。按意思去搜,找到了正确的句子。

注意赢的那个分数有多低。0.30 离 1 远得很。这个模型给出的分数只有一个用处:针对同一个问题,在几个段落之间互相比较。它不是满分为 1 的成绩,也不说明搜索有多大把握。第 3 步对此有一条提醒。

我们的另一页《意思,就是一排数字》用长得多的篇幅讲嵌入:它们分得清什么,会混淆什么,以及同样的想法怎样跨语言使用。

YOU GET A model of 91.6 MB that turns any sentence into 384 numbers, and a way to find the sentence that fits a question without matching a single word.โมเดลขนาด 91.6 MB ที่เปลี่ยนประโยคใดก็ได้เป็นตัวเลข 384 ตัว และวิธีหาประโยคที่ตรงกับคำถามโดยไม่ต้องมีคำไหนตรงกันเลยสักคำ一个 91.6 MB 的模型,能把任何句子变成 384 个数字;还有一种办法,一个词都不用对上,就能找到和问题相配的句子。
THIS EMBEDDING MODEL READS ENGLISH, AND ONLY THE START OF A LONG TEXT all-MiniLM-L6-v2 was trained on English. Our handbook and our questions are in English, so it fits. For documents in Thai or Chinese you need an embedding model that was trained on those languages, and Meaning, as a row of numbers shows a search across languages.It also reads only the first 256 tokens of a text, and drops the rest without telling you. Our longest passage is 55 tokens, so nothing is lost here. It is one reason to cut a document into short passages before you embed it.all-MiniLM-L6-v2 ถูกฝึกด้วยภาษาอังกฤษ คู่มือและคำถามของเราเป็นภาษาอังกฤษ จึงใช้ได้พอดี สำหรับเอกสารภาษาไทยหรือภาษาจีน คุณต้องใช้โมเดลเอมเบดดิ้งที่ฝึกมากับภาษานั้น ๆ และหน้า ความหมาย ในรูปแถวของตัวเลข มีตัวอย่างการค้นหาข้ามภาษามันยังอ่านแค่ 256 โทเคนแรกของข้อความ และทิ้งส่วนที่เหลือไปโดยไม่บอกคุณ ท่อนที่ยาวที่สุดของเรายาว 55 โทเคน จึงไม่มีอะไรหายไปในที่นี้ นี่เป็นเหตุผลหนึ่งที่ควรตัดเอกสารเป็นท่อนสั้น ๆ ก่อนทำเอมเบดดิ้งall-MiniLM-L6-v2 是用英语训练的。我们的手册和问题都是英语,所以正合适。如果文档是泰语或中文,就需要用这些语言训练过的嵌入模型,《意思,就是一排数字》那一页演示了跨语言的搜索。它还只读一段文字的前 256 个 token,剩下的悄悄丢掉,不会告诉你。我们最长的段落是 55 个 token,所以这里什么也没丢。这也是做嵌入之前要把文档切成短段落的一个原因。

3 search.py: find the passages for a question · search.py: หาท่อนที่ตรงกับคำถาม · search.py:为一个问题找出段落

🇬🇧 English

search.py searches the whole handbook. It works in four moves.

  • Cut. read_passages cuts the handbook at every empty line, which gives 26 passages. Each one is about a single subject. This cutting is called chunking, and it decides more than anything else how well a search can work, because a piece that covers two subjects gets an embedding that is about neither. Our handbook was written in short sections, so cutting it is easy. A real document is not so tidy, and cutting it well is most of the work.
  • Embed, once. One call turns all the passages into passage_vectors: a table with one row for each passage and 384 numbers in each row.
  • Score. For a question, passage_vectors @ question_vector gives 26 scores at once, one for each passage.
  • Take the best three. argsort gives the places of the scores in order, from the lowest score to the highest. So the last three places belong to the best three passages, and best_places returns them with the best one first.

The test file says which passage holds each answer. So the program can mark its own search: did the right passage come first, and was it among the three?

🇹🇭 ไทย

search.py ค้นหาทั้งคู่มือ มันทำงานเป็นสี่จังหวะ

  • ตัด read_passages ตัดคู่มือตรงบรรทัดว่างทุกบรรทัด ได้ออกมา 26 ท่อน แต่ละท่อนพูดถึงเรื่องเดียว การตัดแบบนี้เรียกว่า chunking และเป็นสิ่งที่กำหนดมากกว่าอะไรทั้งหมดว่าการค้นหาจะทำงานได้ดีแค่ไหน เพราะชิ้นที่ครอบคลุมสองเรื่องจะได้เอมเบดดิ้งที่ไม่ตรงกับเรื่องไหนเลย คู่มือของเราเขียนเป็นหัวข้อสั้น ๆ อยู่แล้ว การตัดจึงง่าย เอกสารจริงไม่เป็นระเบียบแบบนี้ และการตัดให้ดีคืองานส่วนใหญ่
  • ทำเอมเบดดิ้ง ครั้งเดียว คำสั่งเดียวเปลี่ยนทุกท่อนเป็น passage_vectors คือตารางที่มีหนึ่งแถวต่อหนึ่งท่อน และมีตัวเลข 384 ตัวในแต่ละแถว
  • ให้คะแนน สำหรับคำถามหนึ่งข้อ passage_vectors @ question_vector ให้คะแนนออกมาทีเดียว 26 ตัว ท่อนละหนึ่งตัว
  • เอาสามอันดับแรก argsort ให้ตำแหน่งของคะแนนเรียงตามลำดับ จากคะแนนต่ำสุดไปสูงสุด สามตำแหน่งสุดท้ายจึงเป็นของสามท่อนที่ดีที่สุด และ best_places คืนตำแหน่งเหล่านั้นโดยเอาตัวที่ดีที่สุดไว้ก่อน

ไฟล์ทดสอบบอกไว้ว่าท่อนไหนมีคำตอบของแต่ละข้อ โปรแกรมจึงตรวจการค้นหาของตัวเองได้ ว่าท่อนที่ถูกมาเป็นอันดับแรกไหม และอยู่ในสามท่อนนั้นไหม

🇨🇳 中文

search.py 搜索整本手册。它分四步走。

  • 切。read_passages 在每个空行处把手册切开,得到 26 个段落。每一段只讲一件事。这种切法叫作 chunking(切块),搜索能做得多好,它比什么都更有决定性,因为一块里要是讲了两件事,它的嵌入就哪一件都不像。我们的手册本来就是一小节一小节写的,所以切起来很容易。真实的文档没有这么整齐,把它切好就是大部分的功夫。
  • 做嵌入,只做一次。一次调用就把所有段落变成 passage_vectors:一张表,每个段落一行,每行 384 个数字。
  • 打分。对一个问题,passage_vectors @ question_vector 一下子给出 26 个分数,每个段落一个。
  • 取最好的三个。argsort 按分数从低到高,给出它们各自所在的位置。所以最后三个位置就属于最好的三个段落,best_places 把它们交回来,最好的排在最前面。

测试文件写明了每个答案在哪个段落里。所以程序可以给自己的搜索打分:正确的段落排在第一吗?它在这三段里面吗?

💻 RUN IT

venv\Scripts\python search.py

📄 NEW FILE · search.py

"""search.py - find the passages of the handbook that fit each test question.

    python search.py

It needs handbook.txt and questions.jsonl in the same folder. No language model
writes anything here: this file only searches.
"""
import json

from sentence_transformers import SentenceTransformer

EMBEDDER = "sentence-transformers/all-MiniLM-L6-v2"


def read_passages(name):
    """The handbook, cut into passages at every empty line."""
    with open(name, encoding="utf-8") as file:
        text = file.read()
    passages = []
    # "\n" is the end of a line, so "\n\n" is a line with nothing on it.
    for part in text.split("\n\n"):
        if part.strip():                # skip a part that is empty too
            passages.append(part.strip())
    return passages


def read_questions(name):
    """Every line of the file is one question, written as JSON."""
    questions = []
    with open(name, encoding="utf-8") as file:
        for line in file:
            questions.append(json.loads(line))
    return questions


def title_of(passage):
    """A passage's first line is its title."""
    return passage.split("\n")[0]


def best_places(scores, how_many):
    """Where the highest scores stand in the list, the highest first."""
    places = list(scores.argsort())     # every place, from the lowest score up
    best = places[-how_many:]           # so the best ones are the last ones
    best.reverse()
    return best


def main():
    embedder = SentenceTransformer(EMBEDDER)
    passages = read_passages("handbook.txt")
    # Do this once: every passage becomes one row of numbers.
    passage_vectors = embedder.encode(passages, normalize_embeddings=True)
    print(f"{len(passages)} passages, each one now"
          f" {passage_vectors.shape[1]} numbers")
    print()

    asked = 0
    came_first = 0
    among_three = 0
    for question in read_questions("questions.jsonl"):
        if question["answer_in"] is None:   # the handbook has no answer to this one
            continue
        asked = asked + 1
        question_vector = embedder.encode(
            question["question"], normalize_embeddings=True)
        scores = passage_vectors @ question_vector      # one score for each passage
        print(question["question"])
        titles = []
        for place in best_places(scores, 3):
            title = title_of(passages[place])
            titles.append(title)
            arrow = ""
            if title == question["answer_in"]:
                arrow = "   <- the answer is in this one"
            print(f"{scores[place]:8.2f}  {title}{arrow}")
        if titles[0] == question["answer_in"]:
            came_first = came_first + 1
        if question["answer_in"] in titles:
            among_three = among_three + 1
        else:
            print(f"          not found: the answer is in {question['answer_in']}")
    print()
    print(f"The right passage came first for {came_first} of {asked} questions,")
    print(f"and was among the first three for {among_three} of {asked}.")


if __name__ == "__main__":
    main()

🖨️ WHAT IT PRINTED

All of it: three passages for each of the 40 questions · ทั้งหมด: สามท่อนสำหรับคำถามแต่ละข้อจาก 40 ข้อ · 全部内容:40 个问题各自的三个段落
26 passages, each one now 384 numbers

What time do you close?
    0.49  OPENING HOURS   <- the answer is in this one
    0.47  HOLIDAYS
    0.46  BUSY TIMES
Are you open on Wednesdays?
    0.45  OPENING HOURS   <- the answer is in this one
    0.43  HOLIDAYS
    0.34  BOOKING A TABLE
What is the latest I can order in the evening?
    0.28  OPENING HOURS   <- the answer is in this one
    0.25  BUSY TIMES
    0.25  CATERING
Which road is the shop on?
    0.53  WHERE WE ARE   <- the answer is in this one
    0.43  PARKING
    0.32  BUSY TIMES
How much is a bowl of khao soi?
    0.67  THE FOUR DISHES   <- the answer is in this one
    0.58  KHAO SOI
    0.54  WHO WE ARE
What does nam ngiao cost?
    0.64  NAM NGIAO
    0.60  THE FOUR DISHES   <- the answer is in this one
    0.36  WHO WE ARE
How much more is a large bowl?
    0.48  CATERING
    0.48  CHILDREN
    0.30  THE FOUR DISHES   <- the answer is in this one
What does a fried egg on top cost?
    0.59  MEAT, TOFU AND EGG   <- the answer is in this one
    0.31  TAKEAWAY
    0.30  DESSERT
How spicy will my food be if I say nothing about it?
    0.56  HOW SPICY   <- the answer is in this one
    0.43  CHILDREN
    0.26  ALLERGIES
How much is a Thai iced tea?
    0.70  DRINKS   <- the answer is in this one
    0.48  THE FOUR DISHES
    0.47  DESSERT
What kind of juice do you have?
    0.29  DRINKS   <- the answer is in this one
    0.16  HOW SPICY
    0.16  DESSERT
In which months can I get mango sticky rice?
    0.68  DESSERT   <- the answer is in this one
    0.36  NAM NGIAO
    0.32  ALLERGIES
What is the dessert in October?
    0.29  WHO WE ARE
    0.28  DESSERT   <- the answer is in this one
    0.25  HOLIDAYS
I am vegetarian. Which khao soi should I ask for?
    0.62  VEGETARIAN FOOD   <- the answer is in this one
    0.51  KHAO SOI
    0.47  THE FOUR DISHES
My son cannot eat peanuts. Which dish has them?
    0.44  ALLERGIES   <- the answer is in this one
    0.36  CHILDREN
    0.30  VEGETARIAN FOOD
What do I pay for the takeaway box?
    0.54  TAKEAWAY   <- the answer is in this one
    0.38  HOW TO PAY
    0.33  LOST THINGS
How far from the shop will you bring food?
    0.46  CATERING
    0.41  BUSY TIMES
    0.38  TAKEAWAY
          not found: the answer is in DELIVERY
What is the charge for delivery?
    0.48  DELIVERY   <- the answer is in this one
    0.26  CATERING
    0.25  HOW TO PAY
How much must I order to get it delivered for free?
    0.43  DELIVERY   <- the answer is in this one
    0.34  CATERING
    0.29  DESSERT
I have no cash. How else can I pay?
    0.47  HOW TO PAY   <- the answer is in this one
    0.20  HOW TO REACH US
    0.18  THE LOYALTY CARD
How many people can sit inside?
    0.55  SEATS   <- the answer is in this one
    0.30  CHILDREN
    0.29  BOOKING A TABLE
We are ten people. How long ahead must we book?
    0.40  BOOKING A TABLE   <- the answer is in this one
    0.29  BUSY TIMES
    0.22  OPENING HOURS
What is the smallest order you will cater?
    0.55  CATERING   <- the answer is in this one
    0.32  BOOKING A TABLE
    0.29  CHILDREN
How much warning do you need for a party order?
    0.39  CATERING   <- the answer is in this one
    0.34  BOOKING A TABLE
    0.23  THE LOYALTY CARD
Are you open during Songkran?
    0.55  HOLIDAYS   <- the answer is in this one
    0.37  OPENING HOURS
    0.22  BUSY TIMES
How late do you stay open on Loy Krathong?
    0.67  HOLIDAYS   <- the answer is in this one
    0.52  OPENING HOURS
    0.34  BUSY TIMES
What is the password for the internet?
    0.58  WI-FI   <- the answer is in this one
    0.24  HOW TO REACH US
    0.13  THE LOYALTY CARD
Where can I leave my car?
    0.34  PARKING   <- the answer is in this one
    0.22  WHERE WE ARE
    0.20  SEATS
Which bowl do I get for nothing with the stamp card?
    0.70  THE LOYALTY CARD   <- the answer is in this one
    0.45  CATERING
    0.30  CHILDREN
For how long can I use my stamp card?
    0.41  THE LOYALTY CARD   <- the answer is in this one
    0.20  HOW TO PAY
    0.19  LOST THINGS
Who is the owner?
    0.33  WHO WE ARE   <- the answer is in this one
    0.26  WHERE WE ARE
    0.21  PARKING
Who does the cooking?
    0.47  WHO WE ARE   <- the answer is in this one
    0.33  CATERING
    0.32  MEAT, TOFU AND EGG
In what year did the shop open?
    0.50  HOLIDAYS
    0.38  BUSY TIMES
    0.35  WHERE WE ARE
          not found: the answer is in WHO WE ARE
What does a bowl for a small child cost?
    0.61  CHILDREN   <- the answer is in this one
    0.54  CATERING
    0.47  THE LOYALTY CARD
How long might I wait for a table at lunchtime?
    0.64  BUSY TIMES   <- the answer is in this one
    0.41  BOOKING A TABLE
    0.37  CATERING
What number do I call?
    0.46  HOW TO REACH US   <- the answer is in this one
    0.27  HOW TO PAY
    0.25  WI-FI
What is your LINE name?
    0.31  HOW TO REACH US   <- the answer is in this one
    0.14  BOOKING A TABLE
    0.14  WHO WE ARE
What goes on top of the khao soi?
    0.66  KHAO SOI   <- the answer is in this one
    0.56  WHO WE ARE
    0.50  THE FOUR DISHES
What is the soup of nam ngiao made from?
    0.75  NAM NGIAO   <- the answer is in this one
    0.52  KHAO SOI
    0.51  WHO WE ARE
I left my umbrella in the shop last week. Where would it be?
    0.42  WHERE WE ARE
    0.35  LOST THINGS   <- the answer is in this one
    0.29  PARKING

The right passage came first for 34 of 40 questions,
and was among the first three for 38 of 40.

What the search found, question by questionการค้นหาเจออะไร ทีละคำถาม搜索找到了什么,一个问题一个问题地看

Each square is one of the questions that the handbook answers. The number in it is the place where the right passage came: 1, 2 or 3. A dash means that it was not among the three. Choose a square to see the three passages and their scores. The picture reads the output above.แต่ละช่องคือคำถามหนึ่งข้อที่คู่มือตอบได้ ตัวเลขในช่องคืออันดับที่ท่อนที่ถูกมาอยู่ คือ 1, 2 หรือ 3 ขีดหมายความว่ามันไม่ได้อยู่ในสามท่อนนั้น เลือกช่องเพื่อดูสามท่อนกับคะแนนของมัน ภาพนี้อ่านข้อมูลจากผลลัพธ์ข้างบน每个方块是手册能回答的一个问题。方块里的数字是正确段落排到的位置:1、2 或 3。一道横线表示它不在这三段当中。选一个方块,就能看到那三个段落和它们的分数。这张图读的是上面的输出。

🇬🇧 English

The right passage came first for 34 of the 40 questions, and it was among the first three for 38. That is why the program takes three passages and not one: for 4 questions the right passage came second or third.

Look at the 2 questions it missed. For How far from the shop will you bring food? the search offers CATERING, BUSY TIMES and TAKEAWAY. The answer is in DELIVERY, whose own words are rider, motorbike and addresses, and the question uses none of them. For In what year did the shop open? it offers HOLIDAYS, BUSY TIMES and WHERE WE ARE, which are about the shop's days, its hours and its place. The answer is in WHO WE ARE: Auntie Noi opened the shop in 2011. An embedding sums up a whole passage in one list of numbers, and a small fact inside the passage can get lost in it.

🇹🇭 ไทย

ท่อนที่ถูกมาเป็นอันดับแรกใน 34 จาก 40 คำถาม และอยู่ในสามอันดับแรกใน 38 ข้อ นี่คือเหตุผลที่โปรแกรมเอาสามท่อน ไม่ใช่ท่อนเดียว เพราะมี 4 คำถามที่ท่อนที่ถูกมาเป็นอันดับสองหรือสาม

ดู 2 คำถามที่มันพลาด สำหรับ How far from the shop will you bring food? การค้นหาเสนอ CATERING, BUSY TIMES และ TAKEAWAY แต่คำตอบอยู่ใน DELIVERY ซึ่งคำของมันเองคือ rider, motorbike และ addresses และคำถามไม่ได้ใช้คำไหนในนี้เลย สำหรับ In what year did the shop open? มันเสนอ HOLIDAYS, BUSY TIMES และ WHERE WE ARE ซึ่งเป็นเรื่องวัน เวลา และที่ตั้งของร้าน แต่คำตอบอยู่ใน WHO WE ARE: Auntie Noi opened the shop in 2011 เอมเบดดิ้งสรุปทั้งท่อนลงในรายการตัวเลขชุดเดียว ข้อเท็จจริงเล็ก ๆ ข้างในท่อนจึงหายไปในนั้นได้

🇨🇳 中文

在 40 个问题里,正确的段落有 34 次排在第一,有 38 次排在前三。这就是程序取三段而不是一段的原因:有 4 个问题,正确的段落排在第二或第三。

看看它漏掉的那 2 个问题。对 How far from the shop will you bring food?,搜索给出的是 CATERING、BUSY TIMES 和 TAKEAWAY。答案在 DELIVERY 里,那一段自己的用词是 rider、motorbike 和 addresses,问题里一个也没用到。对 In what year did the shop open?,它给出的是 HOLIDAYS、BUSY TIMES 和 WHERE WE ARE,讲的是这家店的日子、钟点和地点。答案在 WHO WE ARE 里:Auntie Noi opened the shop in 2011。嵌入把一整段概括成一串数字,段落里的一个小事实可能就淹没在里面了。

YOU GET A search of the whole handbook in a few lines, with no language model, and its two scores: the right passage first for 34 of 40 questions, and among the first three for 38.การค้นหาทั้งคู่มือในไม่กี่บรรทัด โดยไม่ใช้โมเดลภาษา กับคะแนนสองตัวของมัน คือท่อนที่ถูกมาเป็นอันดับแรกใน 34 จาก 40 คำถาม และอยู่ในสามอันดับแรกใน 38 ข้อ只用几行代码、不用语言模型,就能搜索整本手册;还有它的两个成绩:40 个问题里,正确的段落 34 次排第一,38 次排在前三。
THE SEARCH NEVER COMES BACK EMPTY Ask about ramen, which this shop does not sell, and the search still returns three passages: the three that are least unlike ramen. Nothing in it says not found. You might hope that a low score would give it away. It does not. For the 10 test questions that the handbook cannot answer, the best score ran from 0.28 to 0.57. For the 40 that it can answer, the best score ran from 0.28 to 0.75, and 27 of them scored lower than 0.57.So no score can be the line between found and not in the handbook. Deciding that the three passages do not answer the question is left to the language model, and step 7 shows how well it does that.ลองถามเรื่องราเมง ซึ่งร้านนี้ไม่ได้ขาย การค้นหาก็ยังคืนมาสามท่อนอยู่ดี คือสามท่อนที่ต่างจากราเมงน้อยที่สุด ไม่มีอะไรในนั้นที่บอกว่า not found คุณอาจหวังว่าคะแนนที่ต่ำจะเป็นตัวบอก แต่มันไม่บอก สำหรับคำถามทดสอบ 10 ข้อที่คู่มือตอบไม่ได้ คะแนนที่ดีที่สุดอยู่ระหว่าง 0.28 ถึง 0.57 ส่วน 40 ข้อที่คู่มือตอบได้ คะแนนที่ดีที่สุดอยู่ระหว่าง 0.28 ถึง 0.75 และมี 27 ข้อในนั้นที่ได้คะแนนต่ำกว่า 0.57จึงไม่มีคะแนนค่าไหนที่ใช้เป็นเส้นแบ่งระหว่าง found กับ not in the handbook ได้ การตัดสินว่าสามท่อนนั้นไม่ได้ตอบคำถามจึงตกเป็นหน้าที่ของโมเดลภาษา และขั้นที่ 7 จะแสดงว่ามันทำเรื่องนี้ได้ดีแค่ไหน问一问拉面的事,这家店并不卖拉面,搜索照样交回三个段落:和拉面最不离谱的那三段。它里面没有任何东西会说 not found。你也许指望分数低能露出马脚。并不能。手册回答不了的 10 个测试问题,最高分从 0.28 到 0.57。手册能回答的 40 个问题,最高分从 0.28 到 0.75,其中 27 个的分数低于 0.57。所以没有哪个分数能当作 found 和 not in the handbook 之间的分界线。判断这三段到底答不答得了问题,只能交给语言模型,第 7 步会让你看到它做得怎么样。

📖 Tutorial 2 — The answer · บทที่ 2 — คำตอบ · 教程 2 —— 回答

🇬🇧 English

The search hands over three passages. Now a language model has to read them and answer. On the last page the language model was SmolLM2-135M. It is too small for this job. On 20 practice questions, with the passages in front of it, it answered 9 of 15, and it never once said that it could not answer.

This page uses Granite 4.0 350M, made by IBM. It has 352,379,904 numbers, 2.6 times as many as SmolLM2-135M, which is still very small for a language model. Its licence, Apache-2.0, lets you use it and change it freely. Answering from documents that it is given is one of the things its makers list it for. Its card lists twelve languages that it handles, English and Chinese among them. Thai is not one of the twelve.

We chose it with the practice questions, which are not in the test. The whole comparison is folded away at the end of step 7.

🇹🇭 ไทย

การค้นหาส่งมาให้สามท่อน ตอนนี้โมเดลภาษาต้องอ่านมันแล้วตอบ ในหน้าที่แล้วโมเดลภาษาคือ SmolLM2-135M ซึ่งเล็กเกินไปสำหรับงานนี้ กับคำถามฝึกซ้อม 20 ข้อ โดยมีท่อนข้อความวางอยู่ตรงหน้า มันตอบถูก 9 จาก 15 ข้อ และไม่เคยบอกเลยสักครั้งว่าตัวเองตอบไม่ได้

หน้านี้ใช้ Granite 4.0 350M ของ IBM มันมีตัวเลข 352,379,904 ตัว มากกว่า SmolLM2-135M 2.6 เท่า ซึ่งก็ยังถือว่าเล็กมากสำหรับโมเดลภาษา สัญญาอนุญาตของมันคือ Apache-2.0 ซึ่งให้คุณใช้และแก้ไขได้อย่างเสรี การตอบจากเอกสารที่ได้รับเป็นหนึ่งในงานที่ผู้สร้างระบุไว้ว่ามันทำได้ การ์ดของโมเดลระบุสิบสองภาษาที่มันรองรับ มีภาษาอังกฤษและภาษาจีนอยู่ในนั้น แต่ภาษาไทยไม่ได้อยู่ในสิบสองภาษานั้น

เราเลือกมันด้วยคำถามฝึกซ้อม ซึ่งไม่ได้อยู่ในชุดทดสอบ การเปรียบเทียบทั้งหมดพับเก็บไว้ท้ายขั้นที่ 7

🇨🇳 中文

搜索交来了三个段落。现在得有一个语言模型把它们读完并回答。上一页的语言模型是 SmolLM2-135M。做这件事它太小了。在 20 个练习题上,段落就摆在眼前,它在 15 个里答对 9 个,而且一次也没有说过自己答不了。

这一页用的是 IBM 出品的 Granite 4.0 350M。它有 352,379,904 个数字,是 SmolLM2-135M 的 2.6 倍,对语言模型来说仍然非常小。它的许可证是 Apache-2.0,允许你自由使用和修改。根据交给它的文档来回答,是它的制作者列出的用途之一。它的模型卡列出了它能处理的十二种语言,其中有英语和中文。泰语不在这十二种里。

我们是用练习题选中它的,练习题不在测试里。完整的比较折叠在第 7 步的末尾。

4 prompt.py: the passages go into the prompt · prompt.py: ใส่ท่อนที่เจอลงในพรอมต์ · prompt.py:把段落放进提示词

🇬🇧 English

Before any model answers, look at what it will be given to read. prompt.py searches the handbook for one question, How much is a bowl of khao soi?, and prints the whole prompt. The first run downloads the tokenizer of the language model, which is small.

One argument is new. apply_chat_template takes documents: a list of dictionaries, each with a title and a text. as_document makes such a dictionary from a passage. What becomes of the documents is decided by the model's chat template, the small program that comes with every model and writes a chat out as the one piece of text the model was trained on.

🇹🇭 ไทย

ก่อนที่โมเดลตัวไหนจะตอบ ให้ดูก่อนว่ามันจะได้รับอะไรให้อ่าน prompt.py ค้นหาในคู่มือสำหรับคำถามหนึ่งข้อ คือ How much is a bowl of khao soi? แล้วพิมพ์พรอมต์ทั้งหมดออกมา การรันครั้งแรกจะดาวน์โหลด tokenizer ของโมเดลภาษา ซึ่งมีขนาดเล็ก

มีอาร์กิวเมนต์ใหม่หนึ่งตัว apply_chat_template รับ documents ซึ่งเป็นลิสต์ของดิกชันนารี แต่ละตัวมี title และ text as_document สร้างดิกชันนารีแบบนั้นจากท่อนข้อความหนึ่งท่อน ส่วนเอกสารพวกนี้จะกลายเป็นอะไรนั้น แชตเทมเพลตของโมเดลเป็นตัวตัดสิน มันคือโปรแกรมเล็ก ๆ ที่มากับทุกโมเดล และเขียนบทสนทนาออกมาเป็นข้อความชิ้นเดียวในรูปแบบที่โมเดลถูกฝึกมา

🇨🇳 中文

在任何模型回答之前,先看看它会拿到什么来读。prompt.py 为一个问题搜索手册,这个问题是 How much is a bowl of khao soi?,然后把整个提示词打印出来。第一次运行会下载语言模型的分词器,它很小。

有一个参数是新的。apply_chat_template 可以接收 documents:一个由字典组成的列表,每个字典有一个 title 和一个 text。as_document 把一个段落做成这样的字典。这些文档最后变成什么样,由模型的聊天模板决定:它是每个模型都自带的一小段程序,把对话写成一整段文字,就是模型训练时用的那种格式。

💻 RUN IT

venv\Scripts\python prompt.py

📄 NEW FILE · prompt.py

"""prompt.py - show what the model is given to read for one question.

    python prompt.py

It searches the handbook, then prints the whole text that would go to the
model. No model answers here. It needs handbook.txt in the same folder.
"""
from sentence_transformers import SentenceTransformer
from transformers import AutoTokenizer

EMBEDDER = "sentence-transformers/all-MiniLM-L6-v2"
MODEL = "ibm-granite/granite-4.0-350m"
INSTRUCTION = ("You answer customers of Three Geckos Noodles, a noodle shop in"
               " Chiang Mai. Answer in one short sentence.")
QUESTION = "How much is a bowl of khao soi?"


def read_passages(name):
    """The handbook, cut into passages at every empty line."""
    with open(name, encoding="utf-8") as file:
        text = file.read()
    passages = []
    # "\n" is the end of a line, so "\n\n" is a line with nothing on it.
    for part in text.split("\n\n"):
        if part.strip():                # skip a part that is empty too
            passages.append(part.strip())
    return passages


def best_places(scores, how_many):
    """Where the highest scores stand in the list, the highest first."""
    places = list(scores.argsort())     # every place, from the lowest score up
    best = places[-how_many:]           # so the best ones are the last ones
    best.reverse()
    return best


def as_document(passage):
    """A passage as a title and a text: the shape a chat template takes."""
    lines = passage.split("\n")         # the first line is the title
    return {"title": lines[0], "text": " ".join(lines[1:])}


def main():
    passages = read_passages("handbook.txt")
    embedder = SentenceTransformer(EMBEDDER)
    passage_vectors = embedder.encode(passages, normalize_embeddings=True)
    question_vector = embedder.encode(QUESTION, normalize_embeddings=True)
    scores = passage_vectors @ question_vector      # one score for each passage

    documents = []
    for place in best_places(scores, 3):
        documents.append(as_document(passages[place]))
    chat = [
        {"role": "system", "content": INSTRUCTION},
        {"role": "user", "content": QUESTION},
    ]
    tokenizer = AutoTokenizer.from_pretrained(MODEL)
    # documents= is the chat template's own place for text to answer from.
    # tokenize=False gives the text itself, so that we can read it.
    prompt_text = tokenizer.apply_chat_template(
        chat, documents=documents, tokenize=False, add_generation_prompt=True)
    print(prompt_text)
    print()
    prompt_tokens = tokenizer(prompt_text, add_special_tokens=False)["input_ids"]
    print(f"{len(prompt_tokens)} tokens for the model to read")


if __name__ == "__main__":
    main()

🖨️ WHAT IT PRINTED

<|start_of_role|>system<|end_of_role|>You answer customers of Three Geckos Noodles, a noodle shop in Chiang Mai. Answer in one short sentence.

You are a helpful assistant with access to the following documents. You may use one or more documents to assist with the user query.

You are given a list of documents within <documents></documents> XML tags:
<documents>
{"title": "THE FOUR DISHES", "text": "Khao soi costs 60 baht. Nam ngiao costs 50 baht. Pad thai costs 60 baht. Pad see ew costs 55 baht. A large bowl of any dish is 15 baht more."}
{"title": "KHAO SOI", "text": "Khao soi is egg noodles in a curry soup made with coconut milk. It is topped with crispy fried noodles and served with pickled mustard greens, shallots and a wedge of lime."}
{"title": "WHO WE ARE", "text": "Auntie Noi opened the shop in 2011 and still owns it. Her brother, Uncle Daeng, is the cook. The khao soi recipe came from their grandmother in Lampang."}
</documents>

Write the response to the user's input by strictly aligning with the facts in the provided documents. If the information needed to answer the question is not available in the documents, inform the user that the question cannot be answered based on the available data.<|end_of_text|>
<|start_of_role|>user<|end_of_role|>How much is a bowl of khao soi?<|end_of_text|>
<|start_of_role|>assistant<|end_of_role|>

317 tokens for the model to read

🇬🇧 English

Read it from the top. The first sentence is our instruction. Everything else in that first block was written by the template. It adds You are a helpful assistant with access to the following documents, then the three passages, each as one line of JSON, and then two rules of its own. The model is to answer by strictly aligning with the facts in the provided documents. And if the answer is not there, it is to inform the user that the question cannot be answered based on the available data.

We wrote none of that. Those are the words that this model's makers put around documents. The model answers much better from documents that arrive in this way than from passages we paste in ourselves, and the box below has the numbers.

The answer is in plain sight in the first document: Khao soi costs 60 baht. The whole prompt is 317 tokens.

🇹🇭 ไทย

อ่านจากบนลงล่าง ประโยคแรกคือคำสั่งของเรา ที่เหลือทั้งหมดในบล็อกแรกนั้นเทมเพลตเป็นคนเขียน มันเติม You are a helpful assistant with access to the following documents ตามด้วยสามท่อน ท่อนละหนึ่งบรรทัดในรูป JSON แล้วตามด้วยกฎของมันเองอีกสองข้อ คือให้โมเดลตอบโดย strictly aligning with the facts in the provided documents และถ้าคำตอบไม่ได้อยู่ในนั้น ก็ให้ inform the user that the question cannot be answered based on the available data

เราไม่ได้เขียนสิ่งเหล่านั้นเลย มันคือถ้อยคำที่ผู้สร้างโมเดลตัวนี้วางครอบเอกสารไว้ โมเดลตอบจากเอกสารที่มาถึงในรูปแบบนี้ได้ดีกว่าท่อนข้อความที่เราแปะลงไปเองมาก และกล่องข้างล่างมีตัวเลขให้ดู

คำตอบเห็นได้ชัด ๆ อยู่ในเอกสารชิ้นแรก: Khao soi costs 60 baht. พรอมต์ทั้งหมดยาว 317 โทเคน

🇨🇳 中文

从上往下读。第一句是我们的指令。第一块里其余的内容全是模板写的。它加上了 You are a helpful assistant with access to the following documents,然后是三个段落,每个段落是一行 JSON,再后面是它自己的两条规则:模型要 strictly aligning with the facts in the provided documents 来回答;如果答案不在其中,就要 inform the user that the question cannot be answered based on the available data。

这些我们一个字也没写。这是这个模型的制作者围在文档四周的话。文档以这种方式送到时,模型答得比我们自己把段落贴进去要好得多,下面的方框里有数字。

答案就明明白白地在第一个文档里:Khao soi costs 60 baht. 整个提示词有 317 个 token。

WHY NOT PASTE THE PASSAGES INTO THE INSTRUCTION YOURSELF? You can, and for many models you must. We tried both ways with this model on the practice questions. With the passages pasted into the instruction, under rules that we wrote ourselves, it answered 7 of 15. Each of its 8 misses was the same reply, I don't know., to a question whose answer was in front of it. Handed over through documents, it answered 13.The usual explanation is that a model reads best what looks like its training. When a model's template has its own way of taking documents, use it.ทำได้ และกับโมเดลหลายตัวคุณต้องทำแบบนั้นด้วย เราลองทั้งสองแบบกับโมเดลตัวนี้โดยใช้คำถามฝึกซ้อม เมื่อแปะท่อนข้อความลงในคำสั่ง ภายใต้กฎที่เราเขียนเอง มันตอบถูก 7 จาก 15 ข้อ ทั้ง 8 ข้อที่มันพลาดเป็นคำตอบเดียวกันหมด คือ I don't know. ทั้งที่คำตอบอยู่ตรงหน้ามัน เมื่อส่งผ่าน documents มันตอบถูก 13 ข้อคำอธิบายที่ใช้กันทั่วไปคือ โมเดลอ่านได้ดีที่สุดเมื่อสิ่งที่อ่านมีหน้าตาเหมือนตอนที่มันถูกฝึก ถ้าเทมเพลตของโมเดลมีวิธีรับเอกสารของมันเอง ก็ให้ใช้วิธีนั้น可以,而且对很多模型来说只能这样做。我们用练习题在这个模型上把两种做法都试了。把段落贴进指令、配上我们自己写的规则,它在 15 个里答对 7 个。它答错的 8 个全是同一句回复:I don't know.,而答案明明就在它眼前。通过 documents 交给它,它答对 13 个。通常的解释是:东西长得越像训练时见过的样子,模型读得越好。只要模型的模板有自己接收文档的方式,就用它。
A TEMPLATE WITH NO PLACE FOR DOCUMENTS DROPS THEM, AND SAYS NOTHING documents does something only if the model's template uses it. The documentation of transformers says so: If the template does not support RAG, this argument will have no effect. We tried it. The templates of SmolLM2 and of Qwen2.5 have no place for documents. Pass them three passages and there is no error, and no passage in the prompt. The model then answers from nothing, and you may not notice.So print the prompt once for every new model, as this file does.documents จะมีผลก็ต่อเมื่อเทมเพลตของโมเดลใช้มัน เอกสารของ transformers ก็บอกไว้อย่างนั้น: If the template does not support RAG, this argument will have no effect. เราลองแล้ว เทมเพลตของ SmolLM2 และของ Qwen2.5 ไม่มีที่สำหรับเอกสาร ส่งสามท่อนให้มัน ก็ไม่มีข้อผิดพลาดขึ้น และไม่มีท่อนไหนอยู่ในพรอมต์เลย โมเดลจึงตอบจากความว่างเปล่า และคุณอาจไม่ทันสังเกตดังนั้นให้พิมพ์พรอมต์ออกมาดูหนึ่งครั้งสำหรับโมเดลใหม่ทุกตัว อย่างที่ไฟล์นี้ทำ只有当模型的模板用到 documents 时,它才起作用。transformers 的文档就是这么说的:If the template does not support RAG, this argument will have no effect. 我们试过了。SmolLM2 和 Qwen2.5 的模板没有放文档的位置。把三个段落传给它们,不会报错,提示词里也没有任何段落。模型于是凭空回答,而你可能根本没发现。所以每换一个新模型,都像这个文件一样,把提示词打印出来看一次。

5 ask.py: one question, from start to finish · ask.py: คำถามหนึ่งข้อ ตั้งแต่ต้นจนจบ · ask.py:一个问题,从头到尾

🇬🇧 English

ask.py is the whole of RAG in one file. Its main has three numbered comments, one for each word of the name. Retrieve: embed the handbook and the question, take the three best passages, and print their titles so that you can see what was found. Augment: build the prompt with those passages in it. Generate: load the language model and let it write up to 40 tokens.

You have seen every part of it before, on this page or on the last one. do_sample=False makes the model take its most likely token every time, so the same question gets the same answer on every run. The first run downloads the language model, 712.0 MB.

🇹🇭 ไทย

ask.py คือ RAG ทั้งหมดในไฟล์เดียว main ของมันมีคอมเมนต์ที่ใส่เลขไว้สามข้อ ข้อละหนึ่งคำของชื่อ Retrieve: ทำเอมเบดดิ้งให้คู่มือและคำถาม เอาสามท่อนที่ดีที่สุด แล้วพิมพ์ชื่อหัวข้อออกมาเพื่อให้คุณเห็นว่าเจออะไร Augment: สร้างพรอมต์ที่มีท่อนเหล่านั้นอยู่ข้างใน Generate: โหลดโมเดลภาษา แล้วให้มันเขียนได้ไม่เกิน 40 โทเคน

ทุกส่วนของมันคุณเคยเห็นมาแล้ว ไม่ในหน้านี้ก็ในหน้าที่แล้ว do_sample=False ทำให้โมเดลเลือกโทเคนที่น่าจะเป็นที่สุดทุกครั้ง คำถามเดิมจึงได้คำตอบเดิมทุกครั้งที่รัน การรันครั้งแรกจะดาวน์โหลดโมเดลภาษา 712.0 MB

🇨🇳 中文

ask.py 是装在一个文件里的整个 RAG。它的 main 里有三条带编号的注释,名字里的每个词各一条。Retrieve:给手册和问题做嵌入,取最好的三个段落,并把它们的标题打印出来,让你看到找到了什么。Augment:把这几段放进去,拼出提示词。Generate:加载语言模型,让它最多写 40 个 token。

它的每一部分你都见过,不是在这一页,就是在上一页。do_sample=False 让模型每次都取最可能的那个 token,所以同一个问题每次运行都得到同一个回答。第一次运行会下载语言模型,712.0 MB。

💻 RUN IT

venv\Scripts\python ask.py "How much is a bowl of khao soi?"

📄 NEW FILE · ask.py

"""ask.py - ask the handbook one question.

    python ask.py "How much is a bowl of khao soi?"

It prints the passages the search found, and then the model's answer.
It needs handbook.txt in the same folder.
"""
import sys

import torch
from sentence_transformers import SentenceTransformer
from transformers import AutoModelForCausalLM, AutoTokenizer

EMBEDDER = "sentence-transformers/all-MiniLM-L6-v2"
MODEL = "ibm-granite/granite-4.0-350m"
INSTRUCTION = ("You answer customers of Three Geckos Noodles, a noodle shop in"
               " Chiang Mai. Answer in one short sentence.")


def read_passages(name):
    """The handbook, cut into passages at every empty line."""
    with open(name, encoding="utf-8") as file:
        text = file.read()
    passages = []
    # "\n" is the end of a line, so "\n\n" is a line with nothing on it.
    for part in text.split("\n\n"):
        if part.strip():                # skip a part that is empty too
            passages.append(part.strip())
    return passages


def best_places(scores, how_many):
    """Where the highest scores stand in the list, the highest first."""
    places = list(scores.argsort())     # every place, from the lowest score up
    best = places[-how_many:]           # so the best ones are the last ones
    best.reverse()
    return best


def as_document(passage):
    """A passage as a title and a text: the shape a chat template takes."""
    lines = passage.split("\n")         # the first line is the title
    return {"title": lines[0], "text": " ".join(lines[1:])}


def prompt_as_tokens(tokenizer, question_text, documents):
    """The tokens the model reads: instruction, documents, question, "your turn"."""
    chat = [
        {"role": "system", "content": INSTRUCTION},
        {"role": "user", "content": question_text},
    ]
    # documents= is the chat template's own place for text to answer from.
    chat_tokens = tokenizer.apply_chat_template(
        chat, documents=documents, add_generation_prompt=True, return_tensors="pt")
    return chat_tokens["input_ids"]


def reply_to(model, tokenizer, prompt_tokens):
    """What the model writes after the prompt, on one line."""
    output = model.generate(prompt_tokens, max_new_tokens=40, do_sample=False)
    # output is the prompt and then the reply. Keep the reply.
    reply_tokens = output[0][prompt_tokens.shape[1]:]
    reply = tokenizer.decode(reply_tokens, skip_special_tokens=True)
    return " ".join(reply.split())


def main():
    question_text = sys.argv[1]         # the words in quotes after ask.py
    passages = read_passages("handbook.txt")

    # 1. Retrieve: the three passages whose numbers lie nearest to the question's.
    embedder = SentenceTransformer(EMBEDDER)
    passage_vectors = embedder.encode(passages, normalize_embeddings=True)
    question_vector = embedder.encode(question_text, normalize_embeddings=True)
    scores = passage_vectors @ question_vector      # one score for each passage
    documents = []
    print("Found in the handbook:")
    for place in best_places(scores, 3):
        document = as_document(passages[place])
        documents.append(document)
        print(f"{scores[place]:8.2f}  {document['title']}")
    print()

    # 2. Augment: those passages go into the prompt, in front of the question.
    tokenizer = AutoTokenizer.from_pretrained(MODEL)
    prompt_tokens = prompt_as_tokens(tokenizer, question_text, documents)

    # 3. Generate: the model reads all of it and writes the answer.
    model = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.float32)
    print(question_text)
    print(reply_to(model, tokenizer, prompt_tokens))


if __name__ == "__main__":
    main()

🖨️ WHAT IT PRINTED

Found in the handbook:
    0.67  THE FOUR DISHES
    0.58  KHAO SOI
    0.54  WHO WE ARE

How much is a bowl of khao soi?
A bowl of khao soi costs 60 baht.

💻 AND ANOTHER QUESTION

venv\Scripts\python ask.py "Can I pay by card?"

🖨️ WHAT IT PRINTED

Found in the handbook:
    0.51  HOW TO PAY
    0.38  THE LOYALTY CARD
    0.22  HOW TO REACH US

Can I pay by card?
Yes, you can pay by card at the shop.

🇬🇧 English

The first answer is right, and the model cannot have known it. The price is in the handbook and nowhere else. Step 6 shows what the same model says when it has no handbook.

The second answer is wrong. The search did its work: HOW TO PAY came first, and that passage says It does not take credit cards. The model was given that sentence, and it wrote Yes, you can pay by card at the shop. Perhaps the second passage, about the loyalty card, pulled it the wrong way. We cannot see inside the model. What we can do is count how often this happens.

🇹🇭 ไทย

คำตอบแรกถูก และโมเดลไม่มีทางรู้เรื่องนี้ได้เอง ราคานี้อยู่ในคู่มือและไม่มีที่อื่นอีก ขั้นที่ 6 จะแสดงว่าโมเดลตัวเดียวกันนี้พูดว่าอะไรเมื่อไม่มีคู่มือ

คำตอบที่สองผิด การค้นหาทำงานของมันแล้ว HOW TO PAY มาเป็นอันดับแรก และท่อนนั้นเขียนว่า It does not take credit cards. โมเดลได้รับประโยคนั้นไปแล้ว แต่กลับเขียนว่า Yes, you can pay by card at the shop. บางทีท่อนที่สอง ซึ่งเป็นเรื่องบัตรสะสมแต้ม อาจดึงมันไปผิดทาง เรามองเข้าไปข้างในโมเดลไม่ได้ สิ่งที่เราทำได้คือนับว่าเรื่องแบบนี้เกิดขึ้นบ่อยแค่ไหน

🇨🇳 中文

第一个回答是对的,而且模型不可能本来就知道。这个价格只在手册里,别处没有。第 6 步会让你看到,同一个模型在没有手册的时候说了什么。

第二个回答是错的。搜索尽了它的本分:HOW TO PAY 排在第一,那一段写着 It does not take credit cards. 这句话已经交到模型手里,它却写了 Yes, you can pay by card at the shop. 也许是第二个段落,讲积分卡的那一段,把它带偏了。我们看不到模型里面。我们能做的,是数一数这种事多久发生一次。

YOU GET A program of under a hundred lines that answers questions from a text file you can edit. And one right answer and one wrong answer, which is all that two questions can tell you.โปรแกรมยาวไม่ถึงร้อยบรรทัดที่ตอบคำถามจากไฟล์ข้อความที่คุณแก้ไขได้ กับคำตอบที่ถูกหนึ่งข้อและคำตอบที่ผิดหนึ่งข้อ ซึ่งเป็นทั้งหมดที่คำถามสองข้อบอกคุณได้一个不到一百行的程序,能根据一个你可以编辑的文本文件回答问题。还有一个对的回答和一个错的回答,两个问题能告诉你的也就这么多。
FOUND IS NOT THE SAME AS READ RAG can go wrong in two places, and they need different cures. The search can fail to find the passage. Or the search finds it, and the model reads it badly.The answer alone does not tell you which of the two happened. That is why ask.py prints the titles of the passages it found. Look at them before you blame the model, and before you blame the search.RAG ผิดได้สองจุด และแต่ละจุดต้องแก้คนละแบบ การค้นหาอาจหาท่อนนั้นไม่เจอ หรือการค้นหาเจอแล้ว แต่โมเดลอ่านมันผิดดูแค่คำตอบอย่างเดียวบอกไม่ได้ว่าเกิดแบบไหน ask.py จึงพิมพ์ชื่อหัวข้อของท่อนที่มันเจอออกมา ให้ดูตรงนั้นก่อนจะโทษโมเดล และก่อนจะโทษการค้นหาRAG 会在两个地方出错,两处要用不同的办法来治。搜索可能没找到那个段落。也可能搜索找到了,模型却读错了。光看回答,分不出发生的是哪一种。所以 ask.py 会把它找到的段落的标题打印出来。在怪模型之前,也在怪搜索之前,先看看这些标题。

🎯 Tutorial 3 — Does it work? · บทที่ 3 — ได้ผลไหม · 教程 3 —— 管用吗?

🇬🇧 English

Two questions prove nothing. The test is the 50 questions of questions.jsonl, and one thing about it matters more than its size. We wrote it before any model had read the handbook.

We then tried two models on it that read too badly to use, and that taught us to stop looking at the test. The reader of this page, and the way of handing the passages to it, were chosen with other questions, the practice set. That reader met the test only after it had been chosen.

One thing was changed after that, and step 6 names it: we had to repair the rule that marks the replies.

🇹🇭 ไทย

คำถามสองข้อพิสูจน์อะไรไม่ได้ ชุดทดสอบคือคำถาม 50 ข้อใน questions.jsonl และมีเรื่องหนึ่งเกี่ยวกับมันที่สำคัญกว่าขนาด คือเราเขียนมันก่อนที่โมเดลตัวไหนจะได้อ่านคู่มือ

จากนั้นเราลองโมเดลสองตัวกับชุดทดสอบนี้ ซึ่งอ่านได้แย่เกินกว่าจะใช้ และนั่นสอนให้เราเลิกดูชุดทดสอบ ตัวอ่านของหน้านี้ และวิธีส่งท่อนข้อความให้มัน ถูกเลือกด้วยคำถามชุดอื่น คือชุดฝึกซ้อม ตัวอ่านตัวนั้นได้เจอชุดทดสอบก็ต่อเมื่อถูกเลือกแล้วเท่านั้น

หลังจากนั้นมีสิ่งเดียวที่ถูกเปลี่ยน และขั้นที่ 6 จะบอกว่าคืออะไร คือเราต้องซ่อมกฎที่ใช้ตรวจคำตอบ

🇨🇳 中文

两个问题什么也证明不了。测试是 questions.jsonl 里的 50 个问题,关于它,有一点比它的大小更要紧:我们是在任何模型读到手册之前把它写好的。

随后我们拿它试了两个模型,它们读得太差,没法用,这也让我们明白不该再去看测试。这一页的阅读模型,还有把段落交给它的方式,是用另一批问题选出来的,也就是练习题。那个阅读模型是在被选定之后,才第一次碰到测试。

在那之后只改过一样东西,第 6 步会说明是什么:我们不得不修理给回复判分的规则。

6 answer.py: 50 questions, three ways · answer.py: คำถาม 50 ข้อ สามแบบ · answer.py:50 个问题,三种方式

🇬🇧 English

answer.py asks the model all 50 questions and marks the replies. One word after its name chooses what the model is given to read.

  • nothing: the question, and our one-line instruction. This shows what the model knows by itself.
  • found: also the three passages that the search found for that question. This is RAG.
  • everything: also all 26 passages, the whole handbook, for every question. This asks whether the search is needed at all.

In the file, those are the three branches of one if in main. Nothing else differs between the three runs.

is_right marks a reply. A reply is right when it contains one of the accepted answers. holds looks for the answer in the reply, and turns it down when it is only a piece of a longer number, so that 15 is not found inside 150,000. For the 10 questions that the handbook cannot answer, the right reply is a refusal, and the list REFUSALS holds the wordings that count as one.

The program counts the two kinds of question apart. It also counts the tokens that the model had to read, and the seconds that each answer took.

🇹🇭 ไทย

answer.py ถามโมเดลครบทั้ง 50 คำถาม แล้วตรวจคำตอบ คำหนึ่งคำที่ตามหลังชื่อไฟล์เป็นตัวเลือกว่าโมเดลจะได้รับอะไรให้อ่าน

  • nothing: คำถาม กับคำสั่งบรรทัดเดียวของเรา แบบนี้แสดงว่าโมเดลรู้อะไรด้วยตัวเอง
  • found: เพิ่มสามท่อนที่การค้นหาเจอสำหรับคำถามนั้น แบบนี้คือ RAG
  • everything: เพิ่มครบทั้ง 26 ท่อน คือคู่มือทั้งเล่ม สำหรับทุกคำถาม แบบนี้ถามว่าจำเป็นต้องมีการค้นหาหรือเปล่า

ในไฟล์ สามแบบนี้คือสามกิ่งของ if ตัวเดียวใน main ไม่มีอย่างอื่นที่ต่างกันระหว่างการรันทั้งสามครั้ง

is_right เป็นตัวตรวจคำตอบ คำตอบถือว่าถูกเมื่อมีคำตอบที่ยอมรับข้อใดข้อหนึ่งอยู่ในนั้น holds มองหาคำตอบในข้อความที่โมเดลตอบ และไม่นับเมื่อมันเป็นแค่ส่วนหนึ่งของตัวเลขที่ยาวกว่า เพื่อไม่ให้เจอ 15 อยู่ข้างใน 150,000 สำหรับคำถาม 10 ข้อที่คู่มือตอบไม่ได้ คำตอบที่ถูกคือการปฏิเสธ และลิสต์ REFUSALS เก็บถ้อยคำที่นับว่าเป็นการปฏิเสธ

โปรแกรมนับคำถามสองชนิดนี้แยกกัน และยังนับโทเคนที่โมเดลต้องอ่าน กับจำนวนวินาทีที่ใช้ต่อหนึ่งคำตอบ

🇨🇳 中文

answer.py 把全部 50 个问题问一遍,并给回复判分。文件名后面的一个词,决定交给模型读的是什么。

  • nothing:只有问题,和我们那一行指令。这能看出模型自己知道些什么。
  • found:再加上搜索为这个问题找到的三个段落。这就是 RAG。
  • everything:再加上全部 26 个段落,也就是整本手册,每个问题都给。这是在问:到底需不需要搜索。

在文件里,这就是 main 中同一个 if 的三个分支。三次运行之间,别的什么都不变。

is_right 给一个回复判分。回复里含有任何一个被认可的答案,就算对。holds 在回复里找这个答案,如果它只是一个更长的数字的一部分,就不算,这样 15 就不会在 150,000 里被找到。对手册回答不了的 10 个问题,正确的回复是拒答,列表 REFUSALS 里放的就是算作拒答的各种说法。

程序把两类问题分开计数。它还数出模型要读的 token,以及每个回答花的秒数。

💻 RUN IT, THREE TIMES

venv\Scripts\python answer.py nothing
venv\Scripts\python answer.py found
venv\Scripts\python answer.py everything

📄 NEW FILE · answer.py

"""answer.py - ask the model every test question, and count its right answers.

    python answer.py nothing       the model reads the question and no more
    python answer.py found         and the three passages the search found
    python answer.py everything    and the whole handbook, every time

It needs handbook.txt and questions.jsonl in the same folder.
"""
import json
import sys
import time

import torch
from sentence_transformers import SentenceTransformer
from transformers import AutoModelForCausalLM, AutoTokenizer

EMBEDDER = "sentence-transformers/all-MiniLM-L6-v2"
MODEL = "ibm-granite/granite-4.0-350m"
INSTRUCTION = ("You answer customers of Three Geckos Noodles, a noodle shop in"
               " Chiang Mai. Answer in one short sentence.")
# The ways a model says that it has no answer.
REFUSALS = [
    "don't know", "do not know", "unanswerable", "cannot be answered",
    "can't answer", "cannot answer", "can't assist", "cannot assist",
    "can't help", "cannot help", "can't provide", "cannot provide",
    "unable to", "not able to", "no information", "have information",
    "have any information", "have specific information", "have real-time information",
]


def read_passages(name):
    """The handbook, cut into passages at every empty line."""
    with open(name, encoding="utf-8") as file:
        text = file.read()
    passages = []
    # "\n" is the end of a line, so "\n\n" is a line with nothing on it.
    for part in text.split("\n\n"):
        if part.strip():                # skip a part that is empty too
            passages.append(part.strip())
    return passages


def read_questions(name):
    """Every line of the file is one question, written as JSON."""
    questions = []
    with open(name, encoding="utf-8") as file:
        for line in file:
            questions.append(json.loads(line))
    return questions


def best_places(scores, how_many):
    """Where the highest scores stand in the list, the highest first."""
    places = list(scores.argsort())     # every place, from the lowest score up
    best = places[-how_many:]           # so the best ones are the last ones
    best.reverse()
    return best


def nearest(embedder, passages, passage_vectors, question_text):
    """The three passages whose numbers lie nearest to the question's."""
    question_vector = embedder.encode(question_text, normalize_embeddings=True)
    scores = passage_vectors @ question_vector      # one score for each passage
    found = []
    for place in best_places(scores, 3):
        found.append(passages[place])
    return found


def as_document(passage):
    """A passage as a title and a text: the shape a chat template takes."""
    lines = passage.split("\n")         # the first line is the title
    return {"title": lines[0], "text": " ".join(lines[1:])}


def prompt_as_tokens(tokenizer, question_text, documents):
    """The tokens the model reads: instruction, documents, question, "your turn"."""
    chat = [
        {"role": "system", "content": INSTRUCTION},
        {"role": "user", "content": question_text},
    ]
    # documents= is the chat template's own place for text to answer from.
    chat_tokens = tokenizer.apply_chat_template(
        chat, documents=documents, add_generation_prompt=True, return_tensors="pt")
    return chat_tokens["input_ids"]


def reply_to(model, tokenizer, prompt_tokens):
    """What the model writes after the prompt, on one line."""
    output = model.generate(prompt_tokens, max_new_tokens=40, do_sample=False)
    # output is the prompt and then the reply. Keep the reply.
    reply_tokens = output[0][prompt_tokens.shape[1]:]
    reply = tokenizer.decode(reply_tokens, skip_special_tokens=True)
    return " ".join(reply.split())


def holds(reply, answer):
    """True when the answer is in the reply, and not as a piece of a longer number."""
    reply = " " + reply + " "           # so that its two ends have neighbours too
    for place in range(1, len(reply) - len(answer)):
        if reply[place:place + len(answer)] != answer:
            continue
        before = reply[place - 1]
        after = reply[place + len(answer)]
        if not before.isdigit() and not after.isdigit():
            return True
    return False


def is_right(reply, question):
    """True when the reply has an accepted answer, or rightly says there is none."""
    accepted = question["accept"]
    if question["answer_in"] is None:   # the handbook has no answer to this one,
        accepted = REFUSALS             # so the right reply is to say so
    reply = reply.lower().replace(",", "")      # "150,000" must read as one number
    for answer in accepted:
        if holds(reply, answer.lower()):
            return True
    return False


def main():
    given = sys.argv[1]                 # the word after answer.py
    passages = read_passages("handbook.txt")
    if given == "found":                # only this way searches
        embedder = SentenceTransformer(EMBEDDER)
        passage_vectors = embedder.encode(passages, normalize_embeddings=True)
    tokenizer = AutoTokenizer.from_pretrained(MODEL)
    model = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.float32)

    right = 0
    in_handbook = 0
    refused = 0
    not_in_handbook = 0
    tokens_read = 0
    started = time.perf_counter()
    for question in read_questions("questions.jsonl"):
        question_text = question["question"]
        if given == "nothing":
            to_read = []
        elif given == "found":
            to_read = nearest(embedder, passages, passage_vectors, question_text)
        else:
            to_read = passages
        documents = []
        for passage in to_read:
            documents.append(as_document(passage))

        prompt_tokens = prompt_as_tokens(tokenizer, question_text, documents)
        tokens_read = tokens_read + prompt_tokens.shape[1]
        reply = reply_to(model, tokenizer, prompt_tokens)
        mark = "WRONG"
        if is_right(reply, question):
            mark = "right"
        print(question_text)
        print(f"    {mark}  {reply}")

        # Two kinds of question, counted apart. Either the handbook has the
        # answer, or it has none, and then the right reply is a refusal.
        if question["answer_in"] is None:
            not_in_handbook = not_in_handbook + 1
            if mark == "right":
                refused = refused + 1
        else:
            in_handbook = in_handbook + 1
            if mark == "right":
                right = right + 1

    asked = in_handbook + not_in_handbook
    seconds = time.perf_counter() - started
    print()
    print(f"{given}: {right} of {in_handbook} right,"
          " where the handbook has the answer")
    print(f"{given}: {refused} of {not_in_handbook} refused,"
          " where the handbook has none")
    print(f"{given}: {tokens_read / asked:.0f} tokens to read for one question,"
          f" {seconds / asked:.1f} seconds for one answer")


if __name__ == "__main__":
    main()

🖨️ WHAT IT PRINTED

answer.py nothing: every question and reply · answer.py nothing: ทุกคำถามและคำตอบ · answer.py nothing:每个问题和回复
What time do you close?
    WRONG  I am a noodle shop in Chiang Mai.
Are you open on Wednesdays?
    right  No, we are not open on Wednesdays.
What is the latest I can order in the evening?
    WRONG  I'm sorry, I can only assist with ordering food at the noodle shop in Chiang Mai.
Which road is the shop on?
    WRONG  I'm sorry, I can't assist with that.
How much is a bowl of khao soi?
    WRONG  I'm sorry, I can't provide real-time pricing information.
What does nam ngiao cost?
    WRONG  Nam ngiao is a noodle dish.
How much more is a large bowl?
    WRONG  A large bowl costs 150,000 NGN.
What does a fried egg on top cost?
    WRONG  A fried egg on top costs around 50,000 THB.
How spicy will my food be if I say nothing about it?
    WRONG  I am unable to provide information on the spiciness of my food.
How much is a Thai iced tea?
    WRONG  I'm sorry, I can't provide real-time pricing information.
What kind of juice do you have?
    WRONG  I offer a variety of fresh and homemade juices.
In which months can I get mango sticky rice?
    WRONG  Mango sticky rice is available in the spring and summer months.
What is the dessert in October?
    WRONG  I'm sorry, I can only provide information about the noodle shop in Chiang Mai.
I am vegetarian. Which khao soi should I ask for?
    WRONG  You can ask for a vegetarian khao soi.
My son cannot eat peanuts. Which dish has them?
    WRONG  I'm sorry, but I can't assist with that.
What do I pay for the takeaway box?
    WRONG  The price of the takeaway box is charged to your credit card.
How far from the shop will you bring food?
    WRONG  I am a noodle shop in Chiang Mai and I am located in the city center.
What is the charge for delivery?
    WRONG  The charge for delivery is based on the distance from your location to the delivery point.
How much must I order to get it delivered for free?
    WRONG  I'm sorry, I can't assist with that.
I have no cash. How else can I pay?
    WRONG  You can pay with a credit card or by using a mobile payment app.
How many people can sit inside?
    WRONG  I'm sorry, I can't provide information on the seating capacity of the Three Geckos Noodles restaurant.
We are ten people. How long ahead must we book?
    WRONG  I'm sorry, I can only assist with customer inquiries at Three Geckos Noodles.
What is the smallest order you will cater?
    WRONG  I am a noodle shop in Chiang Mai.
How much warning do you need for a party order?
    WRONG  I'm sorry, I can't assist with that.
Are you open during Songkran?
    right  No, we are not open during Songkran.
How late do you stay open on Loy Krathong?
    WRONG  I stay open until 10 PM on Loy Krathong.
What is the password for the internet?
    WRONG  I'm sorry, I can't assist with that.
Where can I leave my car?
    WRONG  You can leave your car at the Three Geckos Noodles location in Chiang Mai.
Which bowl do I get for nothing with the stamp card?
    WRONG  I'm sorry, I can't assist with that.
For how long can I use my stamp card?
    WRONG  Your stamp card can be used for a maximum of 30 days.
Who is the owner?
    WRONG  The owner of Three Geckos Noodles is Mr. Lee, a renowned chef and owner of the noodle shop in Chiang Mai.
Who does the cooking?
    WRONG  I am a noodle shop in Chiang Mai.
In what year did the shop open?
    WRONG  The shop opened in 2010.
What does a bowl for a small child cost?
    WRONG  A bowl for a small child typically costs around 100,000 to 150,000 THB.
How long might I wait for a table at lunchtime?
    WRONG  I'm sorry, but I can't provide information on dining times.
What number do I call?
    WRONG  I'm an AI assistant and I'm here to assist you with your questions about Three Geckos Noodles.
What is your LINE name?
    WRONG  I am a language model developed by IBM Research.
What goes on top of the khao soi?
    WRONG  The khao soi is typically served with a side of fresh vegetables or noodles.
What is the soup of nam ngiao made from?
    WRONG  The soup of nam ngiao is made from noodles, broth, and various ingredients like vegetables, tofu, and seafood.
I left my umbrella in the shop last week. Where would it be?
    WRONG  I'm sorry, but I can't assist with that.
Do you have a second shop in Bangkok?
    WRONG  No, I don't have a second shop in Bangkok.
How much is a bowl of ramen?
    right  I'm sorry, I can't provide real-time pricing information.
Which football team does the cook support?
    right  I'm sorry, I can't assist with that.
Do you sell gift cards?
    WRONG  No, I don't sell gift cards.
May I bring my dog inside?
    WRONG  I'm an AI assistant and I'm here to assist you with your noodle shopping needs.
Is there a toilet for customers?
    WRONG  No, there is no toilet for customers at Three Geckos Noodles.
What is the name of the bicycle repair shop next door?
    right  I'm sorry, I can't assist with that.
How many calories are in the pad thai?
    WRONG  The pad thai contains approximately 250 calories.
Who painted the sign?
    right  I am unable to provide information on who painted the sign at Three Geckos Noodles.
What is Auntie Noi's phone number at home?
    right  I'm sorry, I can't assist with that.

nothing: 2 of 40 right, where the handbook has the answer
nothing: 5 of 10 refused, where the handbook has none
nothing: 48 tokens to read for one question, 1.1 seconds for one answer
answer.py found: every question and reply · answer.py found: ทุกคำถามและคำตอบ · answer.py found:每个问题和回复
What time do you close?
    WRONG  Three Geckos Noodles is closed on 13 to 15 April for Songkran and on 31 December and 1 January.
Are you open on Wednesdays?
    right  No, the shop is closed on Wednesdays.
What is the latest I can order in the evening?
    WRONG  The latest I can order in the evening is a catering bowl for 20 bowls, which needs three days' notice.
Which road is the shop on?
    right  The shop is on Suthep Road.
How much is a bowl of khao soi?
    right  A bowl of khao soi costs 60 baht.
What does nam ngiao cost?
    right  Nam ngiao costs 50 baht.
How much more is a large bowl?
    right  A large bowl of any dish is 15 baht more.
What does a fried egg on top cost?
    right  A fried egg on top costs 10 baht.
How spicy will my food be if I say nothing about it?
    right  If you do not say anything about it, the cook makes the dish medium.
How much is a Thai iced tea?
    right  Thai iced tea costs 30 baht.
What kind of juice do you have?
    right  Longan juice is available.
In which months can I get mango sticky rice?
    right  Mango sticky rice is only on the menu from March to June.
What is the dessert in October?
    right  The dessert in October is coconut ice cream.
I am vegetarian. Which khao soi should I ask for?
    right  You should ask for the jay khao soi, which uses a paste without shrimp and costs the same.
My son cannot eat peanuts. Which dish has them?
    right  Pad thai
What do I pay for the takeaway box?
    WRONG  You pay for the takeaway box by bringing a container from home.
How far from the shop will you bring food?
    WRONG  You can bring food to the shop from 20 minutes to 3 pm.
What is the charge for delivery?
    right  The charge for delivery is 20 baht.
How much must I order to get it delivered for free?
    WRONG  You must order a catering order of 20 bowls to get it delivered for free.
I have no cash. How else can I pay?
    WRONG  You can pay with cash or use the QR code at the counter.
How many people can sit inside?
    right  There are 24 seats inside and 8 more at the tables on the pavement.
We are ten people. How long ahead must we book?
    right  You should book one day ahead with a LINE message.
What is the smallest order you will cater?
    right  The smallest order is 20 bowls.
How much warning do you need for a party order?
    right  A party order needs three days' notice.
Are you open during Songkran?
    right  Yes, the shop is closed on 13 to 15 April for Songkran.
How late do you stay open on Loy Krathong?
    right  On Loy Krathong, you stay open until 11 pm.
What is the password for the internet?
    right  The password for the internet is khaosoi2026.
Where can I leave my car?
    WRONG  You can park your car in front of the shop on Suthep Road in Chiang Mai.
Which bowl do I get for nothing with the stamp card?
    WRONG  A card is valid for six months from its first stamp.
For how long can I use my stamp card?
    right  Your stamp card is valid for six months from its first stamp.
Who is the owner?
    right  Auntie Noi is the owner of the noodle shop.
Who does the cooking?
    right  Auntie Noi and Uncle Daeng cook at Auntie Noi's noodle shop in Chiang Mai.
In what year did the shop open?
    WRONG  The shop opened in 2018.
What does a bowl for a small child cost?
    right  A child's bowl is a half portion for 35 baht.
How long might I wait for a table at lunchtime?
    right  The wait for a table at lunchtime can be 20 minutes.
What number do I call?
    right  You can call the LINE account at 053 555 0142.
What is your LINE name?
    right  @threegeckos
What goes on top of the khao soi?
    right  Crispy fried noodles.
What is the soup of nam ngiao made from?
    right  The soup of Nam ngiao is made from sour tomato broth.
I left my umbrella in the shop last week. Where would it be?
    right  The umbrella is kept in a box under the counter for 30 days.
Do you have a second shop in Bangkok?
    WRONG  No, I am a noodle shop in Chiang Mai.
How much is a bowl of ramen?
    WRONG  A bowl of ramen costs 35 baht.
Which football team does the cook support?
    right  Sorry, I am not able to answer that question.
Do you sell gift cards?
    WRONG  No, I do not sell gift cards.
May I bring my dog inside?
    right  I am sorry, I cannot assist with that.
Is there a toilet for customers?
    WRONG  No, there is no toilet for customers at the Three Geckos Noodles noodle shop in Chiang Mai.
What is the name of the bicycle repair shop next door?
    WRONG  The shop is next door to the Three Geckos Noodles.
How many calories are in the pad thai?
    right  I am sorry, the question is unanswerable from the available information.
Who painted the sign?
    WRONG  The sign with three geckos on it was painted by Auntie Noi.
What is Auntie Noi's phone number at home?
    WRONG  The phone number for Auntie Noi is 053 555 0142.

found: 31 of 40 right, where the handbook has the answer
found: 3 of 10 refused, where the handbook has none
found: 294 tokens to read for one question, 2.0 seconds for one answer
answer.py everything: every question and reply · answer.py everything: ทุกคำถามและคำตอบ · answer.py everything:每个问题和回复
What time do you close?
    right  Three Geckos Noodles is open from 10 in the morning until 9 at night. The kitchen takes its last orders at 8:30 pm. The shop is closed every Wednesday.
Are you open on Wednesdays?
    right  No, Three Geckos Noodles is closed on Wednesdays.
What is the latest I can order in the evening?
    WRONG  The shop is open from 10 in the morning until 9 at night.
Which road is the shop on?
    right  The shop is located on Suthep Road in Chiang Mai.
How much is a bowl of khao soi?
    right  A bowl of khao soi costs 60 baht.
What does nam ngiao cost?
    right  Nam ngiao costs 50 baht.
How much more is a large bowl?
    right  A large bowl of any dish is 15 baht more.
What does a fried egg on top cost?
    right  A fried egg on top costs 10 baht.
How spicy will my food be if I say nothing about it?
    right  If you do not specify a level of spiciness, the cook will make the dish medium.
How much is a Thai iced tea?
    right  Thai iced tea costs 30 baht.
What kind of juice do you have?
    WRONG  Thai iced tea is available.
In which months can I get mango sticky rice?
    right  Mango sticky rice is available from March to June.
What is the dessert in October?
    right  The dessert in October is coconut ice cream.
I am vegetarian. Which khao soi should I ask for?
    right  The curry paste in the usual khao soi contains shrimp paste, so it is not vegetarian. Ask for the jay khao soi, which uses a paste without shrimp and costs the same
My son cannot eat peanuts. Which dish has them?
    WRONG  The curry paste in the usual khao soi contains shrimp paste, so it is not vegetarian. Ask for the jay khao soi, which uses a paste without shrimp and costs the same
What do I pay for the takeaway box?
    right  The takeaway box costs 5 baht.
How far from the shop will you bring food?
    WRONG  You can bring food to a distance of 200 meters from the shop.
What is the charge for delivery?
    right  The delivery charge for Three Geckos Noodles is 20 baht.
How much must I order to get it delivered for free?
    WRONG  The delivery costs 20 baht.
I have no cash. How else can I pay?
    right  You can pay with cash, PromptPay, or QR code.
How many people can sit inside?
    right  There are 24 seats inside and 8 more at the tables on the pavement.
We are ten people. How long ahead must we book?
    WRONG  You should book 24 hours in advance.
What is the smallest order you will cater?
    right  The smallest order you can cater is 20 bowls.
How much warning do you need for a party order?
    WRONG  A party order can be made for up to 300 baht.
Are you open during Songkran?
    right  No, Songkran is not open.
How late do you stay open on Loy Krathong?
    WRONG  Loy Krathong is closed on 13 to 15 April and on 31 December and 1 January.
What is the password for the internet?
    right  The password for the internet is khaosoi2026.
Where can I leave my car?
    right  There are four parking spaces for cars behind the building.
Which bowl do I get for nothing with the stamp card?
    WRONG  A child's bowl is a half portion for 35 baht.
For how long can I use my stamp card?
    right  Your loyalty card can be used for up to 6 months.
Who is the owner?
    right  Auntie Noi is the owner of Three Geckos Noodles.
Who does the cooking?
    right  Uncle Daeng is the cook at Three Geckos Noodles.
In what year did the shop open?
    right  Auntie Noi opened the shop in 2011.
What does a bowl for a small child cost?
    right  A child's bowl is a half portion for 35 baht.
How long might I wait for a table at lunchtime?
    right  You might wait up to 20 minutes for a table at lunchtime.
What number do I call?
    right  The phone number for Three Geckos Noodles is 053 555 0142.
What is your LINE name?
    right  @threegeckos
What goes on top of the khao soi?
    WRONG  The fried egg on top of the khao soi is a common topping.
What is the soup of nam ngiao made from?
    right  Nam ngiao is made with a sour tomato broth.
I left my umbrella in the shop last week. Where would it be?
    WRONG  Sorry, I don't have information about umbrellas in the shop.
Do you have a second shop in Bangkok?
    WRONG  Yes, there is a noodle shop in Bangkok called Three Geckos Noodles.
How much is a bowl of ramen?
    WRONG  A bowl of ramen costs 15 baht.
Which football team does the cook support?
    right  Sorry, I am not able to answer that question.
Do you sell gift cards?
    WRONG  No, gift cards are not available at Three Geckos Noodles.
May I bring my dog inside?
    right  Sorry, I am unable to assist with that.
Is there a toilet for customers?
    WRONG  No, there is no toilet for customers.
What is the name of the bicycle repair shop next door?
    WRONG  The bicycle repair shop is next door.
How many calories are in the pad thai?
    WRONG  Pad Thai contains 60 calories.
Who painted the sign?
    WRONG  The sign with three geckos on it was painted by Auntie Noi.
What is Auntie Noi's phone number at home?
    right  Sorry, I am not able to answer that question.

everything: 29 of 40 right, where the handbook has the answer
everything: 3 of 10 refused, where the handbook has none
everything: 1474 tokens to read for one question, 5.9 seconds for one answer

The same model and the same 50 questions, three waysโมเดลตัวเดิม คำถาม 50 ข้อชุดเดิม สามแบบ同一个模型,同样的 50 个问题,三种方式

The numbers are read from the last lines of the three outputs above.ตัวเลขอ่านมาจากบรรทัดท้าย ๆ ของผลลัพธ์ทั้งสามข้างบน这些数字读自上面三个输出的最后几行。

Right answers, of the 40 questions that the handbook answersคำตอบที่ถูก จาก 40 คำถามที่คู่มือตอบได้手册能回答的 40 个问题里,答对的

nothingไม่ให้อะไรเลย什么都不给
the three found passagesสามท่อนที่ค้นเจอ找到的三段
the whole handbookคู่มือทั้งเล่ม整本手册

Refusals, of the 10 questions that the handbook cannot answerการปฏิเสธ จาก 10 คำถามที่คู่มือตอบไม่ได้手册回答不了的 10 个问题里,拒答的

nothingไม่ให้อะไรเลย什么都不给
the three found passagesสามท่อนที่ค้นเจอ找到的三段
the whole handbookคู่มือทั้งเล่ม整本手册
The model is givenโมเดลได้รับ交给模型的是Right, of 40ถูก จาก 40答对(共 40)Refused, of 10ปฏิเสธ จาก 10拒答(共 10)Tokens to read for one questionโทเคนที่ต้องอ่านต่อหนึ่งคำถาม每个问题要读的 token 数Seconds for one answerวินาทีต่อหนึ่งคำตอบ每个回答用的秒数
nothingไม่ให้อะไรเลย什么都不给25481.1
the three found passagesสามท่อนที่ค้นเจอ找到的三段3132942.0
the whole handbookคู่มือทั้งเล่ม整本手册29314745.9

🇬🇧 English

Nothing: 2 of 40. Both are yes-or-no questions, and it guessed. Asked Are you open on Wednesdays? it wrote No, we are not open on Wednesdays. It knows nothing about this shop. It gives the owner a name, Mr. Lee, a renowned chef, and it prices a fried egg at around 50,000 THB. For many questions it says honestly that it cannot help: I'm sorry, I can't provide real-time pricing information.

The three found passages: 31 of 40. This is the same model with the same questions, and about 246 more tokens to read each time.

The whole handbook: 29 of 40. That is no better than the search. A difference of a question or two between 31 and 29 is too small to mean anything. The cost is not small: 1474 tokens and 5.9 seconds for each answer, where the search needs 294 and 2.0.

🇹🇭 ไทย

ไม่ให้อะไรเลย: 2 จาก 40 ทั้งสองข้อเป็นคำถามแบบใช่หรือไม่ และมันเดาเอา เมื่อถามว่า Are you open on Wednesdays? มันเขียนว่า No, we are not open on Wednesdays. มันไม่รู้อะไรเกี่ยวกับร้านนี้เลย มันตั้งชื่อให้เจ้าของร้านว่า Mr. Lee, a renowned chef และตั้งราคาไข่ดาวไว้ที่ around 50,000 THB สำหรับคำถามจำนวนมาก มันบอกตรง ๆ ว่าช่วยไม่ได้: I'm sorry, I can't provide real-time pricing information.

สามท่อนที่ค้นเจอ: 31 จาก 40 นี่คือโมเดลตัวเดิมกับคำถามชุดเดิม และมีโทเคนให้อ่านเพิ่มขึ้นราว 246 โทเคนในแต่ละครั้ง

คู่มือทั้งเล่ม: 29 จาก 40 ซึ่งไม่ได้ดีกว่าการค้นหา ความต่างแค่ข้อสองข้อระหว่าง 31 กับ 29 น้อยเกินกว่าจะมีความหมาย แต่ต้นทุนไม่น้อยเลย คือ 1474 โทเคนและ 5.9 วินาทีต่อหนึ่งคำตอบ ขณะที่การค้นหาใช้ 294 โทเคนและ 2.0 วินาที

🇨🇳 中文

什么都不给:40 个里对 2 个。这两个都是“是或不是”的问题,它是蒙的。问它 Are you open on Wednesdays?,它写 No, we are not open on Wednesdays. 它对这家店一无所知。它给店主起了个名字,Mr. Lee, a renowned chef,还给煎蛋标了价:around 50,000 THB。对不少问题,它老实地说自己帮不上忙:I'm sorry, I can't provide real-time pricing information.

找到的三段:40 个里对 31 个。还是同一个模型、同样的问题,只是每次多读大约 246 个 token。

整本手册:40 个里对 29 个。这并不比搜索好。31 和 29 之间一两个问题的差距太小,说明不了什么。代价却不小:每个回答要读 1474 个 token、花 5.9 秒,而搜索只要 294 个和 2.0 秒。

WHY SEARCH AT ALL, WHEN THE WHOLE HANDBOOK FITS IN THE PROMPT? Because reading costs time on every single question, and because more text is not more help. Our handbook is 1,098 tokens, and this model can read 32,768 at once, so the whole of it fits easily. Reading all of it still took 3.0 times as long for each answer, and it got no more answers right.A real handbook does not fit. One only 30 times the size of ours, about 24,000 words, would already be past what this model can read. The search is what lets a small model answer about a large pile of text. However long the handbook, the model reads three passages.เพราะการอ่านกินเวลากับทุก ๆ คำถาม และเพราะข้อความที่มากขึ้นไม่ได้ช่วยมากขึ้น คู่มือของเรายาว 1,098 โทเคน และโมเดลตัวนี้อ่านได้ทีเดียว 32,768 โทเคน ทั้งเล่มจึงใส่ลงไปได้สบาย แต่การอ่านทั้งหมดก็ยังใช้เวลานานเป็น 3.0 เท่าต่อหนึ่งคำตอบ และไม่ได้ตอบถูกมากขึ้นเลยคู่มือจริงใส่ไม่พอ เล่มที่ใหญ่เป็น 30 เท่าของเราเท่านั้น หรือราว 24,000 คำ ก็เกินกว่าที่โมเดลตัวนี้จะอ่านได้แล้ว การค้นหาคือสิ่งที่ทำให้โมเดลตัวเล็กตอบเรื่องกองข้อความขนาดใหญ่ได้ ไม่ว่าคู่มือจะยาวแค่ไหน โมเดลก็อ่านแค่สามท่อน因为每一个问题,读都要花时间,也因为文字更多并不等于帮助更大。我们的手册有 1,098 个 token,这个模型一次能读 32,768 个,所以整本放进去绰绰有余。可是把它全读一遍,每个回答花的时间仍然是原来的 3.0 倍,答对的也没有变多。真正的手册是放不下的。只要是我们这本的 30 倍大,大约 24,000 个词,就已经超出这个模型能读的范围了。正是搜索让一个小模型能回答一大堆文字里的问题:手册再长,模型读的也只是三段。
YOU GET Three scores from one file: 2, 31 and 29 of 40. The handbook is what made the difference, and three passages did as much as all 26.คะแนนสามตัวจากไฟล์เดียว: 2, 31 และ 29 จาก 40 คู่มือคือสิ่งที่ทำให้ต่างกัน และสามท่อนก็ทำได้เท่ากับครบทั้ง 26 ท่อน一个文件给出的三个成绩:40 个里对 2、31 和 29 个。造成差别的是手册,而三个段落起到的作用和全部 26 个一样大。
WE CHANGED THE MARKING AFTER THE FIRST RUN, AND ONLY THE MARKING The first time we ran this test, the marking was simpler. A reply was right if an accepted answer stood anywhere in it, and a refusal had to use one of a few phrases. Then we read every reply, and the marking was wrong in two ways. It had counted A large bowl costs 150,000 NGN. as right, because the accepted answer 15 is inside 150,000. And it had counted honest refusals such as I'm sorry, I can't assist with that. as wrong, because we had not listed that wording. We repaired the rule. It is the holds and the REFUSALS that you see in the file. Then we ran everything again. The questions, the accepted answers, the handbook, the model and the prompt were not touched.Marking free answers with a program is always rough. Whatever rule you write, read the replies.ครั้งแรกที่เรารันชุดทดสอบนี้ การตรวจคำตอบง่ายกว่านี้ คำตอบถือว่าถูกถ้ามีคำตอบที่ยอมรับอยู่ตรงไหนก็ได้ในนั้น และการปฏิเสธต้องใช้วลีใดวลีหนึ่งในไม่กี่วลี จากนั้นเราอ่านคำตอบทุกข้อ และพบว่าการตรวจผิดอยู่สองทาง มันนับ A large bowl costs 150,000 NGN. ว่าถูก เพราะคำตอบที่ยอมรับคือ 15 อยู่ข้างใน 150,000 และมันนับการปฏิเสธอย่างซื่อตรงเช่น I'm sorry, I can't assist with that. ว่าผิด เพราะเราไม่ได้ใส่ถ้อยคำแบบนั้นไว้ในรายการ เราจึงซ่อมกฎ ซึ่งก็คือ holds และ REFUSALS ที่คุณเห็นในไฟล์ แล้วรันทุกอย่างใหม่อีกครั้ง คำถาม คำตอบที่ยอมรับ คู่มือ โมเดล และพรอมต์ ไม่ได้ถูกแตะเลยการตรวจคำตอบแบบอิสระด้วยโปรแกรมนั้นหยาบเสมอ ไม่ว่าคุณจะเขียนกฎแบบไหน ให้อ่านคำตอบด้วย我们第一次运行这份测试时,判分的办法更简单:回复里任何地方出现一个被认可的答案,就算对;拒答则必须用上少数几种说法之一。后来我们把每一条回复都读了一遍,发现判分错在两个地方。它把 A large bowl costs 150,000 NGN. 算成了对的,因为被认可的答案 15 就在 150,000 里面。它又把 I'm sorry, I can't assist with that. 这类老实的拒答算成了错的,因为我们没有把这种说法列进去。我们修好了规则,也就是你在文件里看到的 holds 和 REFUSALS,然后把所有东西重新运行了一遍。问题、被认可的答案、手册、模型和提示词,一样都没有动。用程序给自由作答判分,总是粗糙的。不管你写的是什么规则,都要把回复读一读。

7 Read the wrong answers · อ่านคำตอบที่ผิด · 读一读答错的回答

🇬🇧 English

A score says how often. Only reading says why. The picture below holds every reply of the three runs. Choose a question and read what the model wrote each way.

🇹🇭 ไทย

คะแนนบอกว่าบ่อยแค่ไหน มีแต่การอ่านที่บอกว่าเพราะอะไร ภาพข้างล่างเก็บคำตอบทุกข้อของการรันทั้งสามครั้งไว้ เลือกคำถาม แล้วอ่านว่าโมเดลเขียนอะไรในแต่ละแบบ

🇨🇳 中文

分数说明的是多经常。只有读,才说明为什么。下面这张图里有三次运行的每一条回复。选一个问题,读一读模型在每种方式下写了什么。

Every question, three waysทุกคำถาม สามแบบ每一个问题,三种方式

Each row has one square for every question, in the order of the test. A filled square is a reply that was marked right, and a hollow square is one that was marked wrong. The last ten squares, set a little apart, are the questions that the handbook cannot answer: there a filled square is a refusal. Move the slider, or point at a square, to choose a question. The picture reads the outputs of steps 3 and 6.แต่ละแถวมีหนึ่งช่องต่อหนึ่งคำถาม เรียงตามลำดับในชุดทดสอบ ช่องทึบคือคำตอบที่ถูกตรวจว่าถูก ช่องโปร่งคือคำตอบที่ถูกตรวจว่าผิด สิบช่องสุดท้ายที่วางแยกออกมาเล็กน้อย คือคำถามที่คู่มือตอบไม่ได้ ในส่วนนั้นช่องทึบหมายถึงการปฏิเสธ เลื่อนแถบเลื่อน หรือชี้ที่ช่อง เพื่อเลือกคำถาม ภาพนี้อ่านข้อมูลจากผลลัพธ์ของขั้นที่ 3 และ 6每一行里,每个问题有一个方块,按测试里的顺序排列。实心方块是被判为正确的回复,空心方块是被判为错误的回复。最后十个方块稍微隔开一点,是手册回答不了的问题:在那里,实心方块表示拒答。拖动滑块,或者把指针移到某个方块上,选一个问题。这张图读的是第 3 步和第 6 步的输出。

Marks of every reply in the three runs
1

🇬🇧 English

Start with the 9 wrong answers of the run with the three found passages. They are of two kinds.

  • The search missed, and the model made something up: 2. These are the two questions that step 3 could not find a passage for. Asked In what year did the shop open?, with no passage that says it, the model wrote The shop opened in 2018. It did not say that it could not tell.
  • The passage was there, and the model read it badly: 7. Asked Where can I leave my car?, with PARKING in front of it, the model wrote You can park your car in front of the shop. That is where the motorbikes go: the right passage, and the wrong sentence of it. Asked Which bowl do I get for nothing with the stamp card? it copied the wrong sentence again: A card is valid for six months from its first stamp. Asked What time do you close? it answered from HOLIDAYS, which was the second passage.

So most of the mistakes, 7 of 9, are the reader's and not the search's. That is worth knowing before you spend a week on a better search.

Now the 10 questions that the handbook cannot answer. The model refused 3 of them and answered the other 7 anyway. A bowl of ramen costs 35 baht. The sign with three geckos on it was painted by Auntie Noi. No, there is no toilet for customers. Each of these is built from true pieces of the handbook: 35 baht is what a child's bowl costs, the sign does have three geckos on it, and Auntie Noi does own the shop. That is what makes such answers dangerous. They sound like the handbook.

One more thing, which we did not expect. With no handbook at all, the same model refused 5 of these 10. With three passages in front of it that had something to do with the question, it refused 3. Ten questions are too few to be sure of this. It is the opposite of what one hopes for.

🇹🇭 ไทย

เริ่มจากคำตอบที่ผิด 9 ข้อของการรันที่ให้สามท่อนที่ค้นเจอ มันแบ่งได้เป็นสองแบบ

  • การค้นหาพลาด แล้วโมเดลแต่งคำตอบขึ้นเอง: 2 ข้อ นี่คือสองคำถามที่ขั้นที่ 3 หาท่อนให้ไม่ได้ เมื่อถามว่า In what year did the shop open? โดยไม่มีท่อนไหนบอกเรื่องนี้ โมเดลเขียนว่า The shop opened in 2018. มันไม่ได้บอกว่าตัวเองตอบไม่ได้
  • ท่อนนั้นอยู่ตรงหน้า แต่โมเดลอ่านผิด: 7 ข้อ เมื่อถามว่า Where can I leave my car? โดยมี PARKING อยู่ตรงหน้า โมเดลเขียนว่า You can park your car in front of the shop ซึ่งเป็นที่จอดของมอเตอร์ไซค์ คือท่อนถูก แต่หยิบประโยคผิด เมื่อถามว่า Which bowl do I get for nothing with the stamp card? มันก็ลอกประโยคผิดมาอีก: A card is valid for six months from its first stamp. เมื่อถามว่า What time do you close? มันตอบจาก HOLIDAYS ซึ่งเป็นท่อนอันดับสอง

ความผิดส่วนใหญ่ คือ 7 จาก 9 ข้อ จึงเป็นของตัวอ่าน ไม่ใช่ของการค้นหา เรื่องนี้ควรรู้ไว้ก่อนจะใช้เวลาทั้งสัปดาห์ไปกับการทำให้การค้นหาดีขึ้น

ทีนี้มาดูคำถาม 10 ข้อที่คู่มือตอบไม่ได้ โมเดลปฏิเสธ 3 ข้อ และตอบอีก 7 ข้อไปทั้งอย่างนั้น A bowl of ramen costs 35 baht. The sign with three geckos on it was painted by Auntie Noi. No, there is no toilet for customers แต่ละคำตอบสร้างขึ้นจากชิ้นส่วนที่เป็นจริงของคู่มือ 35 บาทคือราคาชามเด็ก ป้ายร้านมีตุ๊กแกสามตัวอยู่จริง และ Auntie Noi ก็เป็นเจ้าของร้านจริง นี่แหละที่ทำให้คำตอบแบบนี้อันตราย เพราะมันฟังดูเหมือนคู่มือ

อีกเรื่องหนึ่งที่เราไม่ได้คาดไว้ เมื่อไม่มีคู่มือเลย โมเดลตัวเดียวกันนี้ปฏิเสธ 5 จาก 10 ข้อนี้ แต่เมื่อมีสามท่อนที่เกี่ยวกับคำถามอยู่บ้างวางอยู่ตรงหน้า มันปฏิเสธ 3 ข้อ คำถามสิบข้อน้อยเกินกว่าจะมั่นใจในเรื่องนี้ได้ แต่มันตรงข้ามกับสิ่งที่เราหวัง

🇨🇳 中文

先看给了三个找到的段落的那次运行里,答错的 9 个。它们分成两类。

  • 搜索漏掉了,模型就编了一个:2 个。这就是第 3 步里找不到段落的那两个问题。问它 In what year did the shop open?,眼前没有一个段落讲这件事,模型写了 The shop opened in 2018. 它没有说自己答不上来。
  • 段落就在那里,模型却读错了:7 个。问它 Where can I leave my car?,PARKING 就在眼前,模型写了 You can park your car in front of the shop。那是停摩托车的地方:段落找对了,句子挑错了。问它 Which bowl do I get for nothing with the stamp card?,它又抄错了句子:A card is valid for six months from its first stamp. 问它 What time do you close?,它根据 HOLIDAYS 作答,那是排在第二的段落。

所以大多数错误,9 个里的 7 个,是阅读模型的,不是搜索的。在你花一个星期去改进搜索之前,这一点值得先知道。

再看手册回答不了的 10 个问题。模型拒答了其中 3 个,另外 7 个它照答不误。A bowl of ramen costs 35 baht. The sign with three geckos on it was painted by Auntie Noi. No, there is no toilet for customers。每一个都是用手册里真实的碎片拼出来的:35 泰铢是儿童碗的价格,招牌上确实有三只壁虎,Auntie Noi 也确实是店主。这类回答危险就危险在这里:它们听起来就像手册。

还有一件事,是我们没有料到的。完全没有手册时,同一个模型在这 10 个问题里拒答了 5 个。眼前摆着三个和问题沾点边的段落时,它拒答了 3 个。十个问题太少,还不足以断定这一点。但这和人们希望的正好相反。

🇬🇧 English

Does a bigger reader help? We ran the same test once more with one thing changed. The reader was Granite 4.0 1B, from the same makers, with 1,632 million numbers, 4.6 times as many. The search, the handbook, the instruction, the questions and the marking stayed as they were.

It got 38 of 40 right. That is every question for which the search had found the passage. The 2 that it missed are the two that the search missed, and to one of them it gave the honest reply: The question is unanswerable from the available information. So the bigger reader cured the misreading.

It did not cure the making up. Of the 10 questions that the handbook cannot answer, it refused 3, the same number as the small reader. Asked May I bring my dog inside? it wrote No, dogs are not allowed inside Three Geckos Noodles. The handbook has no rule about dogs.

And the bigger reader is not free. It took 8.5 seconds for each answer where the small one took 2.0, it held 6.8 GB of memory, and it is a download of 3.3 GB. That is why its run is a check and not a step of this page. Its output is folded away below, with the comparison on the practice questions by which we chose the reader.

🇹🇭 ไทย

ตัวอ่านที่ใหญ่กว่าช่วยได้ไหม เรารันชุดทดสอบเดิมอีกครั้งโดยเปลี่ยนสิ่งเดียว ตัวอ่านคือ Granite 4.0 1B จากผู้สร้างรายเดียวกัน มีตัวเลข 1,632 ล้านตัว มากกว่า 4.6 เท่า ส่วนการค้นหา คู่มือ คำสั่ง คำถาม และการตรวจคำตอบ ยังคงเหมือนเดิม

มันตอบถูก 38 จาก 40 ข้อ ซึ่งก็คือทุกคำถามที่การค้นหาเจอท่อนที่ถูก 2 ข้อที่มันพลาดคือสองข้อที่การค้นหาพลาด และกับข้อหนึ่งในนั้นมันให้คำตอบที่ซื่อตรง: The question is unanswerable from the available information. ตัวอ่านที่ใหญ่กว่าจึงแก้ปัญหาการอ่านผิดได้

แต่มันไม่ได้แก้ปัญหาการแต่งคำตอบขึ้นเอง ในคำถาม 10 ข้อที่คู่มือตอบไม่ได้ มันปฏิเสธ 3 ข้อ เท่ากับตัวอ่านตัวเล็ก เมื่อถามว่า May I bring my dog inside? มันเขียนว่า No, dogs are not allowed inside Three Geckos Noodles. ทั้งที่คู่มือไม่มีกฎเรื่องสุนัขเลย

และตัวอ่านที่ใหญ่กว่าก็ไม่ได้มาฟรี ๆ มันใช้เวลา 8.5 วินาทีต่อหนึ่งคำตอบ ขณะที่ตัวเล็กใช้ 2.0 วินาที ใช้หน่วยความจำ 6.8 GB และต้องดาวน์โหลด 3.3 GB การรันของมันจึงเป็นตัวตรวจ ไม่ใช่ขั้นหนึ่งของหน้านี้ ผลลัพธ์ของมันพับเก็บไว้ข้างล่าง พร้อมการเปรียบเทียบด้วยคำถามฝึกซ้อมที่เราใช้เลือกตัวอ่าน

🇨🇳 中文

换一个更大的阅读模型有用吗?我们把同一份测试又运行了一遍,只改了一样东西。阅读模型换成了同一家出品的 Granite 4.0 1B,它有 1,632 百万个数字,是原来的 4.6 倍。搜索、手册、指令、问题和判分都保持原样。

40 个里它答对了 38 个。也就是说,凡是搜索找到了段落的问题,它全都答对了。它答错的 2 个正是搜索漏掉的那两个,而且对其中一个它给出了老实的回复:The question is unanswerable from the available information. 所以,更大的阅读模型治好了读错的毛病。

它没有治好编造的毛病。在手册回答不了的 10 个问题里,它拒答了 3 个,和小的阅读模型一样多。问它 May I bring my dog inside?,它写 No, dogs are not allowed inside Three Geckos Noodles. 手册里并没有关于狗的规定。

而且更大的阅读模型不是白来的。它每个回答要 8.5 秒,小的只要 2.0 秒;它占用 6.8 GB 内存,下载量是 3.3 GB。所以它的这次运行只是一项检查,不是这一页的一个步骤。它的输出折叠在下面,同时折叠在那里的,还有我们用练习题挑选阅读模型时做的比较。

The same test with the bigger reader: every question and reply · ชุดทดสอบเดิมกับตัวอ่านที่ใหญ่กว่า: ทุกคำถามและคำตอบ · 换成更大的阅读模型的同一份测试:每个问题和回复
python answer.py found, with MODEL = 'ibm-granite/granite-4.0-1b'
that model, as downloaded: 3.3 GB in 12 files

What time do you close?
    right  Three Geckos Noodles closes at 9 at night.
Are you open on Wednesdays?
    right  No, the shop is closed every Wednesday.
What is the latest I can order in the evening?
    right  The latest you can order in the evening is 8:30 pm.
Which road is the shop on?
    right  The shop is on Suthep Road in Chiang Mai.
How much is a bowl of khao soi?
    right  A bowl of khao soi costs 60 baht.
What does nam ngiao cost?
    right  Nam ngiao costs 50 baht.
How much more is a large bowl?
    right  A large bowl costs 15 baht more than a regular bowl.
What does a fried egg on top cost?
    right  A fried egg on top costs 10 baht.
How spicy will my food be if I say nothing about it?
    right  If you say nothing, your food will be medium spicy.
How much is a Thai iced tea?
    right  A Thai iced tea costs 30 baht.
What kind of juice do you have?
    right  You have longan juice available for 25 baht.
In which months can I get mango sticky rice?
    right  Mango sticky rice is available from March to June.
What is the dessert in October?
    right  In October, the dessert is coconut ice cream at 35 baht.
I am vegetarian. Which khao soi should I ask for?
    right  Ask for the jay khao soi, which uses a paste without shrimp.
My son cannot eat peanuts. Which dish has them?
    right  Your son cannot eat peanuts in the pad thai dish.
What do I pay for the takeaway box?
    right  You pay 5 baht for the takeaway box.
How far from the shop will you bring food?
    WRONG  The catering order needs three days' notice.
What is the charge for delivery?
    right  Delivery costs 20 baht.
How much must I order to get it delivered for free?
    right  Orders over 300 baht get free delivery.
I have no cash. How else can I pay?
    right  You can pay using PromptPay at the counter.
How many people can sit inside?
    right  There are 24 seats inside.
We are ten people. How long ahead must we book?
    right  For a group of 10, you should book one day ahead with a LINE message.
What is the smallest order you will cater?
    right  The smallest catering order is 20 bowls.
How much warning do you need for a party order?
    right  For a party order, you need three days' notice.
Are you open during Songkran?
    right  No, the shop is closed during Songkran.
How late do you stay open on Loy Krathong?
    right  The shop stays open until 11 pm on Loy Krathong.
What is the password for the internet?
    right  The password for the internet is khaosoi2026.
Where can I leave my car?
    right  If the car parking spaces behind the shop are full, you can park your car in the temple's car park across the road for 20 baht.
Which bowl do I get for nothing with the stamp card?
    right  The tenth bowl is free with the stamp card.
For how long can I use my stamp card?
    right  Your stamp card is valid for six months from its first stamp.
Who is the owner?
    right  Auntie Noi owns Three Geckos Noodles.
Who does the cooking?
    right  The cooking is done by Uncle Daeng.
In what year did the shop open?
    WRONG  The question is unanswerable from the available information.
What does a bowl for a small child cost?
    right  A bowl for a small child costs 35 baht.
How long might I wait for a table at lunchtime?
    right  You might wait 20 minutes for a table at lunchtime.
What number do I call?
    right  You can call 053 555 0142 to reach Three Geckos Noodles.
What is your LINE name?
    right  The LINE account is @threegeckos.
What goes on top of the khao soi?
    right  Crispy fried noodles go on top of the khao soi.
What is the soup of nam ngiao made from?
    right  The soup of nam ngiao is made from sour tomato broth.
I left my umbrella in the shop last week. Where would it be?
    right  Your umbrella would be in the box under the counter for 30 days.
Do you have a second shop in Bangkok?
    WRONG  No, Three Geckos Noodles only has one shop in Chiang Mai.
How much is a bowl of ramen?
    WRONG  A bowl of ramen costs 35 baht.
Which football team does the cook support?
    right  I am not able to answer that question as my knowledge is focused on Three Geckos Noodles and its offerings.
Do you sell gift cards?
    WRONG  No, Three Geckos Noodles does not sell gift cards.
May I bring my dog inside?
    WRONG  No, dogs are not allowed inside Three Geckos Noodles.
Is there a toilet for customers?
    right  The question is unanswerable from the available information.
What is the name of the bicycle repair shop next door?
    WRONG  The bicycle repair shop next door is called Three Geckos.
How many calories are in the pad thai?
    right  The question is unanswerable from the available information.
Who painted the sign?
    WRONG  The sign is green with three geckos on it.
What is Auntie Noi's phone number at home?
    WRONG  The phone number is 053 555 0142.

found: 38 of 40 right, where the handbook has the answer
found: 3 of 10 refused, where the handbook has none
found: 294 tokens to read for one question, 8.5 seconds for one answer
How we chose the reader: five small models on 20 practice questions · เราเลือกตัวอ่านอย่างไร: โมเดลเล็กห้าตัวกับคำถามฝึกซ้อม 20 ข้อ · 我们是怎样选出阅读模型的:五个小模型,20 个练习题
20 practice questions: the handbook answers 15 and has nothing on 5.

HuggingFaceTB/SmolLM2-135M-Instruct: a prompt made with documents= has NO passage in it,
    and no error either. Its chat template has no place for documents.

HuggingFaceTB/SmolLM2-135M-Instruct, passages given by hand
    What colour is the sign outside?
        The sign outside the Three Geckos Noodles shop is red.
    How much is the pad see ew?
        The pad see ew costs 15 baht.
    What is the price of a bottle of water?
        The price of a bottle of water is 15 baht.
    Until what time in the evening do you deliver?
        I deliver from 10:30 am to 8:30 pm.
    What does it cost to park at the temple?
        The temple is located on Suthep Road in Chiang Mai, 200 metres west of the Ton Payom market, next to a bicycle repair shop. The cost to park at the temple
    Which dish have you sold for the longest time?
        I sold the largest dish, the khao soi, for 150 baht.
    What is Uncle Daeng's favourite dish?
        Uncle Daeng's favourite dish is khao soi, but he also likes to make khao soi with shrimp and shrimp paste. He also makes khao soi with fried noodles and
    Is there a bus stop near the shop?
        Yes, there is a bus stop near the shop. It is located at the intersection of Suthep Road and the road to the north. The bus stop is about 100 metres from
    How old is Auntie Noi?
        Auntie Noi is 85 years old.
    What music do you play in the shop?
        The shop is a little bit of a jazz club, and we play a lot of jazz. We have a big jazz band that plays a lot of the songs from the 1940s
    Do you sell T-shirts?
        Yes, we do sell T-shirts. We have a large selection of colors and designs, and we offer a variety of sizes and styles. We also have a special "T-shirt of the

ibm-granite/granite-4.0-350m: a prompt made with documents= has the passages in it

ibm-granite/granite-4.0-350m, passages given by hand
    When do you open in the morning?
        I don't know.
    How much extra do I pay for beef?
        I don't know.
    What is the price of a bottle of water?
        I don't know.
    How much do I save if I bring my own container?
        I don't know.
    Until what time in the evening do you deliver?
        I don't know.
    How many seats are there outside?
        I don't know.
    For how many days do you keep things that people forget?
        I don't know.
    Which dish have you sold for the longest time?
        I don't know.
    How old is Auntie Noi?
        Auntie Noi is 35 years old.
    Do you sell T-shirts?
        No, I don't sell T-shirts.

ibm-granite/granite-4.0-350m, passages given documents=
    How many seats are there outside?
        There are 24 seats outside.
    Which dish have you sold for the longest time?
        I have sold the Khao soi dish for the longest time.
    What is Uncle Daeng's favourite dish?
        Uncle Daeng's favourite dish is Auntie Noi's khao soi.
    Is there a bus stop near the shop?
        Yes, there is a bus stop near the shop.
    How old is Auntie Noi?
        Auntie Noi opened the shop in 2011.
    Do you sell T-shirts?
        No, I do not sell T-shirts.

HuggingFaceTB/SmolLM2-360M-Instruct: a prompt made with documents= has NO passage in it,
    and no error either. Its chat template has no place for documents.

HuggingFaceTB/SmolLM2-360M-Instruct, passages given by hand
    When do you open in the morning?
        I don't have a specific opening time in the morning.
    For how many days do you keep things that people forget?
        I don't know.
    Which dish have you sold for the longest time?
        I've been selling khao soi for 10 years now. It's a popular dish, and people come from all around to try it.
    What is Uncle Daeng's favourite dish?
        Uncle Daeng's favourite dish is pad thai. He says it's the best in the shop.
    Is there a bus stop near the shop?
        Yes, there is a bus stop near the shop. It is located on the opposite side of the road from the shop, and is marked with a sign with a bus number.
    How old is Auntie Noi?
        Auntie Noi is 65 years old.
    What music do you play in the shop?
        The shop is equipped with a sound system that plays a variety of music, including classical, pop, and electronic. We also have a selection of local and international music.
    Do you sell T-shirts?
        I don't sell T-shirts.

Qwen/Qwen2.5-0.5B-Instruct: a prompt made with documents= has NO passage in it,
    and no error either. Its chat template has no place for documents.

Qwen/Qwen2.5-0.5B-Instruct, passages given by hand
    When do you open in the morning?
        I don't know.
    How much extra do I pay for beef?
        I don't know.
    Which dish have you sold for the longest time?
        Pad Thai has been sold for the longest time at Three Geckos Noodles.
    What is Uncle Daeng's favourite dish?
        Uncle Daeng's favorite dish is khao soi.
    Is there a bus stop near the shop?
        Yes, there is a bus stop nearby.
    How old is Auntie Noi?
        Auntie Noi opened the shop in 2011.
    Do you sell T-shirts?
        Yes, we offer T-shirts as an accessory.

ibm-granite/granite-4.0-1b: a prompt made with documents= has the passages in it

ibm-granite/granite-4.0-1b, passages given by hand
    Which dish have you sold for the longest time?
        Khao soi
    How old is Auntie Noi?
        Auntie Noi opened the shop in 2011 and still owns it.

ibm-granite/granite-4.0-1b, passages given documents=
    Which dish have you sold for the longest time?
        The khao soi dish has been sold for the longest time at Three Geckos Noodles.
    What is Uncle Daeng's favourite dish?
        Uncle Daeng's favorite dish is khao soi.
    How old is Auntie Noi?
        Auntie Noi opened the shop in 2011 and still owns it.

model                                 numbers   passages       right   refused   a reply
HuggingFaceTB/SmolLM2-135M-Instruct     135 M   by hand      9 of 15   0 of 5     1.1 s
ibm-granite/granite-4.0-350m            352 M   by hand      7 of 15   3 of 5     0.8 s
ibm-granite/granite-4.0-350m            352 M   documents=  13 of 15   1 of 5     1.3 s
HuggingFaceTB/SmolLM2-360M-Instruct     362 M   by hand     12 of 15   0 of 5     1.7 s
Qwen/Qwen2.5-0.5B-Instruct              494 M   by hand     12 of 15   1 of 5     1.6 s
ibm-granite/granite-4.0-1b             1632 M   by hand     14 of 15   4 of 5     4.9 s
ibm-granite/granite-4.0-1b             1632 M   documents=  14 of 15   3 of 5     8.3 s
RAG DOES NOT STOP A MODEL FROM MAKING THINGS UP RAG gives the model the facts. It does not make the model stay with them. Shown passages that did not hold the answer, the small reader answered anyway for 7 of 10 questions, and so did the reader that is 4.6 times its size.If a wrong answer could do harm, a person must be able to see where the answer came from. Showing the passages beside the answer, as ask.py does, is the least that a real system should do.RAG ให้ข้อเท็จจริงกับโมเดล แต่ไม่ได้ทำให้โมเดลยึดอยู่กับข้อเท็จจริงนั้น เมื่อได้เห็นท่อนข้อความซึ่งไม่มีคำตอบ ตัวอ่านตัวเล็กก็ยังตอบไปทั้งอย่างนั้นใน 7 จาก 10 คำถาม และตัวอ่านที่ใหญ่กว่ามัน 4.6 เท่าก็ทำแบบเดียวกันถ้าคำตอบที่ผิดอาจก่อความเสียหายได้ คนต้องมองเห็นได้ว่าคำตอบมาจากไหน การแสดงท่อนข้อความไว้ข้างคำตอบอย่างที่ ask.py ทำ คือขั้นต่ำสุดที่ระบบจริงควรทำRAG 把事实交给模型。它并不能让模型守着这些事实。看到的段落里没有答案时,小的阅读模型在 10 个问题里有 7 个照答不误,是它 4.6 倍大的那个阅读模型也一样。如果答错会造成损害,就必须让人能看到答案是从哪里来的。像 ask.py 那样把段落显示在回答旁边,是一个真实系统至少该做到的。
YOU GET The two numbers that describe any RAG system, kept apart: how often the search finds the passage, and how often the reader then reads it right. With the small reader, the search is the stronger half. With the bigger one, every mistake that is left is the search's.ตัวเลขสองตัวที่ใช้บรรยายระบบ RAG ระบบไหนก็ได้ โดยแยกออกจากกัน คือการค้นหาเจอท่อนที่ถูกบ่อยแค่ไหน และหลังจากนั้นตัวอ่านอ่านมันถูกบ่อยแค่ไหน กับตัวอ่านตัวเล็ก การค้นหาคือครึ่งที่แข็งแรงกว่า กับตัวที่ใหญ่กว่า ความผิดที่เหลืออยู่ทุกข้อเป็นของการค้นหา能描述任何一个 RAG 系统的两个数字,而且是分开来看的:搜索多经常找到那个段落,阅读模型接着又多经常把它读对。用小的阅读模型时,搜索是更强的那一半。用大的那个时,剩下的每一个错误都是搜索的。

⚖️ Tutorial 4 — RAG, LoRA and full fine-tuning · บทที่ 4 — RAG, LoRA และการปรับจูนแบบเต็ม · 教程 4 —— RAG、LoRA 与全量微调

🇬🇧 English

The last page changed a model. This page changed a prompt. This tutorial puts the two next to each other. It begins with the thing that RAG does best.

🇹🇭 ไทย

หน้าที่แล้วเปลี่ยนโมเดล หน้านี้เปลี่ยนพรอมต์ บทนี้วางสองอย่างไว้ข้างกัน โดยเริ่มจากสิ่งที่ RAG ทำได้ดีที่สุด

🇨🇳 中文

上一页改的是模型。这一页改的是提示词。这个教程把两者摆在一起,先从 RAG 最拿手的事情说起。

8 Change a fact, and train nothing · เปลี่ยนข้อเท็จจริง โดยไม่ต้องฝึกอะไรเลย · 改一条事实,什么都不用训练

🇬🇧 English

The shop puts the price of khao soi up to 70 baht. On this page that is one edit in a text file. Open handbook.txt, change Khao soi costs 60 baht. to Khao soi costs 70 baht., save, and ask again.

The check change_a_fact.py does exactly that. It works on a copy of the handbook, so that yours stays as it was for the test. It asks the price, edits the line, and asks again. Then it asks a question that the handbook cannot answer, adds a new passage to the end, and asks that again too. Each time it runs the ask.py of step 5, unchanged.

🇹🇭 ไทย

ร้านขึ้นราคาข้าวซอยเป็น 70 บาท ในหน้านี้ เรื่องนี้คือการแก้ไฟล์ข้อความหนึ่งจุด เปิด handbook.txt เปลี่ยน Khao soi costs 60 baht. เป็น Khao soi costs 70 baht. บันทึก แล้วถามใหม่

ตัวตรวจ change_a_fact.py ทำแบบนั้นเป๊ะ มันทำงานกับสำเนาของคู่มือ เพื่อให้คู่มือของคุณยังคงเดิมสำหรับชุดทดสอบ มันถามราคา แก้บรรทัดนั้น แล้วถามอีกครั้ง จากนั้นถามคำถามที่คู่มือตอบไม่ได้ เพิ่มท่อนใหม่ต่อท้าย แล้วถามคำถามนั้นอีกครั้งเช่นกัน ทุกครั้งมันรัน ask.py ของขั้นที่ 5 โดยไม่ได้แก้อะไรเลย

🇨🇳 中文

店里把 khao soi 的价格涨到 70 泰铢。在这一页,这只是文本文件里的一处改动。打开 handbook.txt,把 Khao soi costs 60 baht. 改成 Khao soi costs 70 baht.,保存,再问一次。

检查脚本 change_a_fact.py 做的正是这件事。它在手册的一份副本上动手,这样你的手册为了测试保持原样。它先问价格,改掉那一行,再问一次。然后它问一个手册回答不了的问题,在末尾加上一个新段落,再把那个问题也问一次。每一次它运行的都是第 5 步的 ask.py,一字未改。

🖨️ WHAT THE CHECK PRINTED

1. The handbook as it is
    Found in the handbook:
        0.67  THE FOUR DISHES
        0.58  KHAO SOI
        0.54  WHO WE ARE
    
    How much is a bowl of khao soi?
    A bowl of khao soi costs 60 baht.

   edited one line: Khao soi costs 60 baht.  ->  Khao soi costs 70 baht.

2. After the edit
    Found in the handbook:
        0.67  THE FOUR DISHES
        0.58  KHAO SOI
        0.54  WHO WE ARE
    
    How much is a bowl of khao soi?
    A bowl of khao soi costs 70 baht.

3. A question the handbook cannot answer
    Found in the handbook:
        0.33  THE LOYALTY CARD
        0.22  DESSERT
        0.21  BOOKING A TABLE
    
    Is there a discount for students?
    No, the loyalty card is not associated with any discounts for students.

   added one passage to the end of the handbook:
       STUDENTS
       A student who shows a student card gets 10 baht off any dish. The discount is for weekdays before 5 pm.

4. After the new passage
    Found in the handbook:
        0.61  STUDENTS
        0.33  THE LOYALTY CARD
        0.22  DESSERT
    
    Is there a discount for students?
    Yes, students get a 10 baht discount for any dish on weekdays before 5 pm.

Turning all 27 passages into numbers again: 0.14 seconds. No training.

🇬🇧 English

70 baht, on the very next question. ask.py turns the handbook into numbers each time it starts, and for all 27 passages that took 0.14 seconds. There was nothing else to do.

The second pair shows both sides of this page. Before the new passage, the model made up an answer about students from the passage about the loyalty card. After it, the search put STUDENTS first, and the answer is right.

Now think how the same change goes when a fact has been trained into a model. We did not do this, so what follows is reasoning and not a measurement. The model goes on saying 60 baht until someone writes new examples and trains it again. On the last page, training took 195 seconds with LoRA and 431 seconds the full way, and before that came the examples to train on, 400 of them. And until then, nobody can open the model and see that its price is out of date.

🇹🇭 ไทย

70 บาท ในคำถามถัดไปทันที ask.py เปลี่ยนคู่มือเป็นตัวเลขทุกครั้งที่มันเริ่มทำงาน และสำหรับครบทั้ง 27 ท่อน ใช้เวลา 0.14 วินาที ไม่มีอะไรต้องทำอีก

คู่ที่สองแสดงทั้งสองด้านของหน้านี้ ก่อนมีท่อนใหม่ โมเดลแต่งคำตอบเรื่องนักเรียนขึ้นมาจากท่อนเรื่องบัตรสะสมแต้ม หลังมีท่อนใหม่ การค้นหาจัดให้ STUDENTS มาเป็นอันดับแรก และคำตอบก็ถูก

ทีนี้ลองคิดดูว่าการเปลี่ยนแบบเดียวกันจะเป็นอย่างไร ถ้าข้อเท็จจริงถูกฝึกเข้าไปในโมเดล เราไม่ได้ทำเรื่องนี้ สิ่งที่ตามมาจึงเป็นการให้เหตุผล ไม่ใช่การวัด โมเดลจะพูดว่า 60 บาทต่อไปเรื่อย ๆ จนกว่าจะมีคนเขียนตัวอย่างใหม่แล้วฝึกมันอีกรอบ ในหน้าที่แล้ว การฝึกใช้เวลา 195 วินาทีด้วย LoRA และ 431 วินาทีแบบเต็ม และก่อนหน้านั้นยังต้องมีตัวอย่างสำหรับฝึกอีก 400 ชุด และระหว่างนั้น ไม่มีใครเปิดโมเดลดูแล้วเห็นได้ว่าราคาของมันล้าสมัยไปแล้ว

🇨🇳 中文

70 泰铢,就在紧接着的下一个问题上。ask.py 每次启动都把手册重新变成数字,全部 27 个段落花了 0.14 秒。此外什么也不用做。

第二对问答把这一页的两面都展示了出来。新段落加进去之前,模型根据讲积分卡的那一段,编了一个关于学生的答案。加进去之后,搜索把 STUDENTS 排在第一,回答也对了。

现在想一想,如果一条事实是训练进模型里的,同样的改动会怎么样。这件事我们没有做,所以下面是推理,不是测量。模型会一直说 60 泰铢,直到有人写出新的样例、再训练它一遍。在上一页,训练用 LoRA 花了 195 秒,全量花了 431 秒,在那之前还得先有用来训练的样例,一共 400 个。而在那之前,谁也没法打开模型,看出它的价格已经过时了。

YOU GET A system whose facts you change with a text editor. A new price was live after 0.14 seconds, and a new passage worked on the next question.ระบบที่คุณเปลี่ยนข้อเท็จจริงได้ด้วยโปรแกรมแก้ไขข้อความ ราคาใหม่ใช้งานได้หลังผ่านไป 0.14 วินาที และท่อนใหม่ใช้ได้ตั้งแต่คำถามถัดไป一个用文本编辑器就能改事实的系统。新价格在 0.14 秒之后就生效了,新段落在下一个问题上就起了作用。

9 What each one changes · แต่ละวิธีเปลี่ยนอะไร · 每一种改的是什么

🇬🇧 English

LoRA and full fine-tuning are two ways of doing one thing: training a model that already exists on new examples. The last page did both, and they differ only in how many of the model's numbers may move. RAG is another kind of thing. It trains nothing. The table puts the three side by side. The numbers in the first column are from this page, and the numbers in the other two are from the last page.

🇹🇭 ไทย

LoRA กับการปรับจูนแบบเต็มคือสองวิธีของการทำสิ่งเดียวกัน คือการฝึกโมเดลที่มีอยู่แล้วด้วยตัวอย่างใหม่ หน้าที่แล้วทำทั้งสองแบบ และมันต่างกันแค่ว่ายอมให้ตัวเลขของโมเดลขยับได้กี่ตัว ส่วน RAG เป็นของอีกประเภทหนึ่ง มันไม่ได้ฝึกอะไรเลย ตารางนี้วางทั้งสามไว้ข้างกัน ตัวเลขในคอลัมน์แรกมาจากหน้านี้ และตัวเลขในอีกสองคอลัมน์มาจากหน้าที่แล้ว

🇨🇳 中文

LoRA 和全量微调是做同一件事的两种方式:用新的样例训练一个已经存在的模型。上一页两种都做了,它们的差别只在于允许模型的多少个数字动。RAG 是另一类东西。它什么都不训练。下面的表把三者并排放在一起。第一列的数字出自这一页,另外两列的数字出自上一页。

RAGRAGRAGLoRALoRALoRAFull fine-tuningการปรับจูนแบบเต็ม全量微调
What it changesเปลี่ยนอะไร它改的是什么The prompt. The model stays exactly as it was downloaded.พรอมต์ ตัวโมเดลยังคงเหมือนตอนดาวน์โหลดมาทุกประการ提示词。模型和下载下来时一模一样。A small add-on beside the model: 460,800 new numbers. The model's own numbers are frozen.ตัวเสริมเล็ก ๆ ข้างโมเดล: ตัวเลขใหม่ 460,800 ตัว ส่วนตัวเลขของโมเดลเองถูกล็อกไว้模型旁边的一个小附加模块:460,800 个新数字。模型自己的数字被冻结。Every number in the model: 134,515,008 of them.ตัวเลขทุกตัวในโมเดล: 134,515,008 ตัว模型里的每一个数字:共 134,515,008 个。
Where the new knowledge isความรู้ใหม่อยู่ที่ไหน新知识在哪里In a text file that you can read: handbook.txt, 802 words.ในไฟล์ข้อความที่คุณอ่านได้: handbook.txt ยาว 802 คำ在一个你读得懂的文本文件里:handbook.txt,802 个词。In the add-on's numbers: a folder of 1.9 MB that nobody can read.ในตัวเลขของตัวเสริม: โฟลเดอร์ขนาด 1.9 MB ที่ไม่มีใครอ่านออก在附加模块的数字里:一个 1.9 MB 的文件夹,谁也读不懂。In the model's numbers: a folder of 538.1 MB that nobody can read.ในตัวเลขของโมเดล: โฟลเดอร์ขนาด 538.1 MB ที่ไม่มีใครอ่านออก在模型的数字里:一个 538.1 MB 的文件夹,谁也读不懂。
What you prepareต้องเตรียมอะไร你要准备什么The documents, cut into passages. No examples.เอกสารที่ตัดเป็นท่อนแล้ว ไม่ต้องมีตัวอย่าง切成段落的文档。不需要样例。Examples of the job: 400 on the last page.ตัวอย่างของงาน: 400 ชุดในหน้าที่แล้ว这件事的样例:上一页用了 400 个。The same examples.ตัวอย่างชุดเดียวกัน同样的样例。
Computing before it can answerการคำนวณก่อนจะตอบได้能回答之前要算多久0.14 seconds, to turn the handbook into numbers.0.14 วินาที เพื่อเปลี่ยนคู่มือเป็นตัวเลข0.14 秒,用来把手册变成数字。195 seconds of training.ฝึก 195 วินาที训练 195 秒。431 seconds of training.ฝึก 431 วินาที训练 431 秒。
When a fact changesเมื่อข้อเท็จจริงเปลี่ยน事实变了的时候Edit the file. The next answer uses it.แก้ไฟล์ คำตอบถัดไปก็ใช้ข้อมูลใหม่เลย改文件。下一个回答就用上了。Write new examples and train again.เขียนตัวอย่างใหม่ แล้วฝึกอีกรอบ写新的样例,再训练一遍。Write new examples and train again.เขียนตัวอย่างใหม่ แล้วฝึกอีกรอบ写新的样例,再训练一遍。
What every question costsต้นทุนของทุกคำถาม每个问题的代价A longer prompt: 294 tokens where the bare question needs 48, and a search before it.พรอมต์ที่ยาวขึ้น: 294 โทเคน ขณะที่คำถามเปล่า ๆ ใช้ 48 และต้องค้นหาก่อนหนึ่งรอบ更长的提示词:294 个 token,而光是问题只要 48 个;之前还要先搜索一次。Nothing extra. A trained model needs only a short instruction.ไม่มีอะไรเพิ่ม โมเดลที่ฝึกแล้วใช้แค่คำสั่งสั้น ๆ没有额外的代价。训练过的模型只需要一条短指令。Nothing extra.ไม่มีอะไรเพิ่ม没有额外的代价。
Can it show where an answer came from?บอกได้ไหมว่าคำตอบมาจากไหน它能说出答案是从哪里来的吗?Yes. The passages it was given can be shown beside the answer.ได้ แสดงท่อนข้อความที่มันได้รับไว้ข้างคำตอบได้能。交给它的段落可以显示在回答旁边。No.ไม่ได้不能。No.ไม่ได้不能。
What it is good forเหมาะกับอะไร它擅长什么Facts: ones that change, ones that are private, ones that fill more pages than a model can read.ข้อเท็จจริง: ทั้งที่เปลี่ยนได้ ที่เป็นความลับ และที่มีมากเกินกว่าโมเดลจะอ่านได้หมด事实:会变的事实,不公开的事实,多到模型读不完的事实。A habit: a fixed form of answer, a voice, one narrow job done well.นิสัย: รูปแบบคำตอบที่ตายตัว น้ำเสียงแบบหนึ่ง งานแคบ ๆ อย่างเดียวที่ทำได้ดี习惯:固定的回答格式,某种语气,把一件很窄的事做好。The same, when LoRA is not enough.เหมือนกัน เมื่อ LoRA ยังไม่พอ同上,在 LoRA 不够用的时候。
How it went wrong for usของเราผิดพลาดอย่างไร在我们这里它是怎么出错的The search missed 2 of 40. The reader misread 7 more, and made up answers to 7 of 10 questions that had none.การค้นหาพลาด 2 จาก 40 ข้อ ตัวอ่านอ่านผิดอีก 7 ข้อ และแต่งคำตอบให้ 7 จาก 10 คำถามที่ไม่มีคำตอบ40 个问题里,搜索漏掉了 2 个。阅读模型又读错了 7 个,还给 10 个没有答案的问题里的 7 个编了答案。It got 39 of 50 handwritten orders right. The misses were wordings that its examples never showed it.มันตอบถูก 39 จาก 50 ออร์เดอร์ที่คนเขียนเอง ข้อที่พลาดคือถ้อยคำที่ตัวอย่างของมันไม่เคยแสดงให้เห็น50 条手写订单里它答对 39 条。答错的都是它的样例里从没出现过的说法。It got 38 of 50 right, with misses of the same kind.มันตอบถูก 38 จาก 50 ข้อ และพลาดในแบบเดียวกัน50 条里它答对 38 条,错法也是同一类。

🇬🇧 English

They are not rivals, and good systems use both. Look again at the program at the end of the last page. The model there had learned one habit by LoRA: to write an order as JSON. The prices were not in the model. They were in a Python dictionary named PRICES, and the program looked them up. That was already the same division of work: the habit was trained, and the facts were looked up.

It also shows what could come next here. The weakness of this page's system is not a missing fact. It is a habit: the reader answers when it should refuse, and a reader 4.6 times the size had the same habit. A habit is what fine-tuning is for. One could train the reader with LoRA on examples of questions whose passages do not hold the answer, each with a refusal as the right reply. We did not do that, and we do not know how well it would work on a model this small.

🇹🇭 ไทย

ทั้งสองไม่ใช่คู่แข่งกัน และระบบที่ดีใช้ทั้งคู่ ลองดูโปรแกรมตอนท้ายของหน้าที่แล้วอีกครั้ง โมเดลในนั้นเรียนนิสัยหนึ่งอย่างด้วย LoRA คือการเขียนออร์เดอร์เป็น JSON แต่ราคาไม่ได้อยู่ในโมเดล มันอยู่ในดิกชันนารีของ Python ชื่อ PRICES และโปรแกรมเป็นคนค้นดู นั่นก็คือการแบ่งงานแบบเดียวกันอยู่แล้ว นิสัยถูกฝึก ส่วนข้อเท็จจริงถูกค้นดู

มันยังบอกด้วยว่าอะไรอาจมาเป็นขั้นต่อไปของหน้านี้ จุดอ่อนของระบบในหน้านี้ไม่ใช่ข้อเท็จจริงที่ขาดไป มันเป็นนิสัย คือตัวอ่านตอบในตอนที่ควรปฏิเสธ และตัวอ่านที่ใหญ่กว่า 4.6 เท่าก็มีนิสัยเดียวกัน นิสัยคือสิ่งที่การปรับจูนมีไว้แก้ เราอาจฝึกตัวอ่านด้วย LoRA โดยใช้ตัวอย่างคำถามที่ท่อนข้อความไม่มีคำตอบ แต่ละข้อมีการปฏิเสธเป็นคำตอบที่ถูก เราไม่ได้ทำเรื่องนั้น และเราไม่รู้ว่ามันจะได้ผลดีแค่ไหนกับโมเดลที่เล็กขนาดนี้

🇨🇳 中文

它们不是对手,好的系统两样都用。再看一眼上一页末尾的那个程序。那里的模型用 LoRA 学会了一个习惯:把订单写成 JSON。价格并不在模型里。价格在一个名叫 PRICES 的 Python 字典里,由程序去查。那已经是同样的分工了:习惯是练出来的,事实是查出来的。

它也说明了这里接下来可以做什么。这一页的系统,弱点不是缺了哪条事实。它是一个习惯:阅读模型在该拒答的时候作了答,是它 4.6 倍大的那个阅读模型也有同样的习惯。习惯正是微调要对付的东西。可以用 LoRA 训练阅读模型,样例是那些段落里并没有答案的问题,每个都以拒答作为正确的回复。这件事我们没有做,也不知道在这么小的模型上它能有多大效果。

🧭 Which one, and when · ใช้วิธีไหน เมื่อไร · 该用哪一种,什么时候用

🇬🇧 English

Ask what is missing, and the choice is usually plain.

  • A fact is missing, and it is written down somewhere. Use RAG. This holds even more when the facts change, when they are private, or when somebody must be able to check the answer against its source.
  • A way of behaving is missing. The model knows enough, and it will not answer in your form, in your voice, or as briefly as you need. First try a better prompt. If that is not enough, fine-tune, with LoRA first.
  • Everything the model needs fits in the prompt, and the answers come fast enough. Then put it in the prompt and stop. You need neither a search nor a training. Step 6 measured that choice for our handbook: it worked as well, and it was 3.0 times as slow.
  • The model reads badly. Then neither RAG nor a better search will save it. Take a bigger model if your computer can carry one. Step 7 measured that too: a reader 4.6 times the size read every passage right that the search had found.

A real system adds to each half of this page. For the search: a vector database once there are too many passages to score one by one, more careful ways of cutting documents, a search for words beside the search for meaning, and a second model that puts the found passages into a better order. For the reader: a larger model. Every one of those is a way to raise one of the two numbers of step 7. So measure the two numbers first, and you will know which half to work on.

You do not have to write all of it by hand, as we did here so that every part could be seen. Our page NotebookLM, and taking the research home builds the same three steps with a library, LlamaIndex, and a larger model that runs on your own computer.

🇹🇭 ไทย

ถามว่าขาดอะไรอยู่ แล้วทางเลือกมักจะชัดเอง

  • ขาดข้อเท็จจริง และข้อเท็จจริงนั้นถูกเขียนไว้ที่ไหนสักแห่ง ใช้ RAG ยิ่งถ้าข้อเท็จจริงเปลี่ยนได้ เป็นความลับ หรือต้องมีคนตรวจคำตอบเทียบกับที่มาได้ ก็ยิ่งควรใช้
  • ขาดวิธีทำตัว โมเดลรู้พอแล้ว แต่ไม่ยอมตอบในรูปแบบของคุณ ในน้ำเสียงของคุณ หรือสั้นเท่าที่คุณต้องการ ให้ลองเขียนพรอมต์ให้ดีขึ้นก่อน ถ้ายังไม่พอ ค่อยปรับจูน โดยเริ่มจาก LoRA
  • ทุกอย่างที่โมเดลต้องใช้ใส่ลงในพรอมต์ได้พอ และคำตอบมาเร็วพอ ถ้าอย่างนั้นก็ใส่ลงในพรอมต์แล้วจบแค่นั้น ไม่ต้องมีทั้งการค้นหาและการฝึก ขั้นที่ 6 วัดทางเลือกนี้กับคู่มือของเราแล้ว คือได้ผลดีพอกัน และใช้เวลานานเป็น 3.0 เท่า
  • โมเดลอ่านได้แย่ ถ้าอย่างนั้นทั้ง RAG และการค้นหาที่ดีขึ้นก็ช่วยไม่ได้ ให้ใช้โมเดลที่ใหญ่ขึ้นถ้าคอมพิวเตอร์ของคุณรับไหว ขั้นที่ 7 วัดเรื่องนี้ไว้ด้วย: ตัวอ่านที่ใหญ่กว่า 4.6 เท่าอ่านถูกทุกท่อนที่การค้นหาเจอ

ระบบจริงจะเพิ่มของเข้าไปในทั้งสองครึ่งของหน้านี้ ฝั่งการค้นหา: ฐานข้อมูลเวกเตอร์เมื่อมีท่อนมากเกินกว่าจะให้คะแนนทีละท่อน วิธีตัดเอกสารที่ประณีตขึ้น การค้นหาด้วยคำควบคู่กับการค้นหาด้วยความหมาย และโมเดลตัวที่สองที่จัดลำดับท่อนที่เจอให้ดีขึ้น ฝั่งตัวอ่าน: โมเดลที่ใหญ่ขึ้น ทุกอย่างในนี้คือวิธีเพิ่มตัวเลขตัวใดตัวหนึ่งในสองตัวของขั้นที่ 7 ดังนั้นให้วัดตัวเลขสองตัวนั้นก่อน แล้วคุณจะรู้ว่าควรลงแรงกับครึ่งไหน

คุณไม่จำเป็นต้องเขียนทั้งหมดด้วยมือ อย่างที่เราทำในหน้านี้เพื่อให้เห็นทุกส่วน หน้า NotebookLM กับการพางานวิจัยกลับบ้าน ของเราสร้างสามขั้นตอนเดียวกันนี้ด้วยไลบรารีชื่อ LlamaIndex กับโมเดลที่ใหญ่กว่าซึ่งรันบนคอมพิวเตอร์ของคุณเอง

🇨🇳 中文

问一问缺的是什么,选择通常就清楚了。

  • 缺的是事实,而它写在某个地方。用 RAG。如果事实会变、不能公开,或者必须有人能对照出处核实答案,就更该用它。
  • 缺的是一种行为方式。模型懂得够多了,可就是不肯按你的格式、你的语气,或者你要的简短程度来回答。先试试更好的提示词。还不够,再微调,先用 LoRA。
  • 模型需要的一切都放得进提示词,回答也来得够快。那就放进提示词,到此为止。既不需要搜索,也不需要训练。第 6 步就我们的手册量过这个选择:效果一样好,花的时间却是 3.0 倍。
  • 模型读得很差。那么 RAG 也好,更好的搜索也好,都救不了它。如果你的电脑带得动,就换一个更大的模型。第 7 步也量过这一点:一个 4.6 倍大的阅读模型,把搜索找到的每个段落都读对了。

真实的系统会给这一页的两半各添些东西。搜索这一半:段落多到没法一个个打分时,用向量数据库;更讲究的切文档的办法;在按意思搜索之外,再加上按词搜索;还有第二个模型,把找到的段落重新排出更好的顺序。阅读模型这一半:换更大的模型。这里的每一样,都是在提高第 7 步那两个数字中的一个。所以先把这两个数字量出来,你就知道该在哪一半下功夫。

你不必像我们在这里这样全部手写,我们这样做是为了让每个部分都看得见。我们的另一页《NotebookLM,把研究带回家》用一个库 LlamaIndex,加上一个在你自己电脑上运行的更大的模型,搭出了同样的三步。

YOUR TURN
  1. Add a passage of your own to the end of handbook.txt, with a title line and an empty line before it. Ask about it with ask.py. Then delete it and ask again.
  2. In answer.py, the function nearest takes three passages. Change the 3 to 1, and then to 5, and run answer.py found each time. Watch three numbers: the right answers, the refusals, and the tokens for one question.
  3. Give the passage DELIVERY a first sentence that a customer might use, such as How far we deliver. Run search.py again and see whether the missed question is found. Remember what the last page said: once you repair what the test showed you, the test is no longer a fair exam.
  4. If your computer has 8 GB of memory to spare, change MODEL in ask.py to "ibm-granite/granite-4.0-1b" and ask Can I pay by card? again.
  5. Write a handbook for something you know well: your school, your club, your family's shop. Write ten questions with the answers you would accept, and two that the handbook cannot answer. Then run answer.py on them.
  1. เพิ่มท่อนของคุณเองต่อท้าย handbook.txt โดยมีบรรทัดชื่อหัวข้อ และมีบรรทัดว่างคั่นไว้ข้างหน้า ถามเรื่องนั้นด้วย ask.py แล้วลบออกและถามอีกครั้ง
  2. ใน answer.py ฟังก์ชัน nearest เอาสามท่อน ลองเปลี่ยน 3 เป็น 1 แล้วเป็น 5 และรัน answer.py found ทุกครั้ง ดูตัวเลขสามตัว คือคำตอบที่ถูก การปฏิเสธ และโทเคนต่อหนึ่งคำถาม
  3. ใส่ประโยคแรกให้ท่อน DELIVERY เป็นประโยคที่ลูกค้าน่าจะใช้ เช่น How far we deliver. แล้วรัน search.py อีกครั้ง ดูว่าคำถามที่เคยพลาดถูกเจอหรือเปล่า อย่าลืมสิ่งที่หน้าที่แล้วบอกไว้: เมื่อคุณซ่อมสิ่งที่ชุดทดสอบชี้ให้เห็นแล้ว ชุดทดสอบก็ไม่ใช่ข้อสอบที่ยุติธรรมอีกต่อไป
  4. ถ้าคอมพิวเตอร์ของคุณมีหน่วยความจำว่าง 8 GB ให้เปลี่ยน MODEL ใน ask.py เป็น "ibm-granite/granite-4.0-1b" แล้วถาม Can I pay by card? อีกครั้ง
  5. เขียนคู่มือของเรื่องที่คุณรู้ดี เช่น โรงเรียนของคุณ ชมรมของคุณ หรือร้านของครอบครัวคุณ เขียนคำถามสิบข้อพร้อมคำตอบที่คุณจะยอมรับ และอีกสองข้อที่คู่มือตอบไม่ได้ แล้วรัน answer.py กับคำถามเหล่านั้น
  1. 在 handbook.txt 的末尾加上你自己写的一个段落,要有一行标题,前面留一个空行。用 ask.py 问一问它。然后把它删掉,再问一次。
  2. 在 answer.py 里,函数 nearest 取三个段落。把那个 3 改成 1,再改成 5,每次都运行 answer.py found。留意三个数字:答对的个数、拒答的个数,以及每个问题的 token 数。
  3. 给 DELIVERY 这一段加一个顾客可能会说的开头句,比如 How far we deliver. 再运行一次 search.py,看看原先漏掉的问题有没有被找到。记住上一页说过的话:一旦你修好了测试指给你看的毛病,这份测试就不再是一场公平的考试了。
  4. 如果你的电脑有 8 GB 的空闲内存,把 ask.py 里的 MODEL 改成 "ibm-granite/granite-4.0-1b",再问一次 Can I pay by card?
  5. 为你熟悉的东西写一本手册:你的学校、你的社团、你家的小店。写十个问题,附上你愿意认可的答案,再写两个手册回答不了的问题。然后用 answer.py 跑一遍。

🇬🇧 English

Next: Fine-tune a language model with Python is the other half of this pair. Meaning, as a row of numbers goes further into embeddings, and NotebookLM, and taking the research home does RAG with a library. To serve a model to a whole classroom, see vLLM instead of Ollama.

The two models have their own pages: huggingface.co/sentence-transformers/all-MiniLM-L6-v2 and huggingface.co/ibm-granite/granite-4.0-350m. The documentation of the two libraries is at sbert.net and huggingface.co/docs/transformers. The name RAG comes from a paper of 2020, Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, by Patrick Lewis and eleven others.

🇹🇭 ไทย

ต่อไป: ปรับจูนโมเดลภาษาด้วย Python คืออีกครึ่งหนึ่งของคู่นี้ ความหมาย ในรูปแถวของตัวเลข ลงลึกเรื่องเอมเบดดิ้งมากกว่านี้ และ NotebookLM กับการพางานวิจัยกลับบ้าน ทำ RAG ด้วยไลบรารี ถ้าอยากเสิร์ฟโมเดลให้ทั้งห้องเรียน ดูที่ ใช้ vLLM แทน Ollama

โมเดลทั้งสองตัวมีหน้าของตัวเอง: huggingface.co/sentence-transformers/all-MiniLM-L6-v2 และ huggingface.co/ibm-granite/granite-4.0-350m เอกสารของไลบรารีสองตัวอยู่ที่ sbert.net และ huggingface.co/docs/transformers ชื่อ RAG มาจากบทความวิจัยปี 2020 ชื่อ Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks โดย Patrick Lewis และผู้เขียนอีกสิบเอ็ดคน

🇨🇳 中文

接下来:《用 Python 微调语言模型》是这一对里的另一半。《意思,就是一排数字》把嵌入讲得更深,《NotebookLM,把研究带回家》用一个库来做 RAG。想给整个教室提供模型服务,可以看《用 vLLM 取代 Ollama》。

两个模型各有自己的页面:huggingface.co/sentence-transformers/all-MiniLM-L6-v2 和 huggingface.co/ibm-granite/granite-4.0-350m。两个库的文档在 sbert.net 和 huggingface.co/docs/transformers。RAG 这个名字出自 2020 年的一篇论文:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks,作者是 Patrick Lewis 和另外十一人。