สร้างแชทบ็อตที่ทำงานแบบออฟไลน์และแบบใช้ภายในได้โดยใช้ WebLLM

เผยแพร่เมื่อวันที่ 13 มกราคม 2024

บทความนี้เป็นบทความที่ 2 ในชุดบทความ 3 บทความเกี่ยวกับ LLM กับแชทบ็อต บทความก่อนหน้าได้กล่าวถึงข้อดีและข้อเสียของ LLM ในอุปกรณ์และในเบราว์เซอร์

เมื่อเข้าใจ AI ฝั่งไคลเอ็นต์มากขึ้นแล้ว คุณก็พร้อมที่จะเพิ่ม WebLLM ลงในเว็บแอปพลิเคชันรายการสิ่งที่ต้องทําแล้ว คุณดูโค้ดได้ในสาขา web-llm ของที่เก็บ GitHub

WebLLM เป็นรันไทม์บนเว็บสําหรับ LLM ที่ Machine Learning Compilation ให้บริการ คุณลองใช้ WebLLM เป็นแอปพลิเคชันแบบสแตนด์อโลนได้ แอปพลิเคชันนี้ได้รับแรงบันดาลใจมาจากแอปพลิเคชันแชทที่ทำงานบนระบบคลาวด์ เช่น Gemini แต่ระบบจะเรียกใช้การอนุมาน LLM ในอุปกรณ์แทนระบบคลาวด์ พรอมต์และข้อมูลของคุณจะไม่ออกจากอุปกรณ์ และมั่นใจได้ว่าจะไม่มีการนำข้อมูลดังกล่าวไปใช้ฝึกโมเดล

WebLLM ใช้ WebAssembly และ WebGPU เพื่อทำการอนุมานโมเดลในอุปกรณ์ แม้ว่า WebAssembly จะทําการคํานวณได้อย่างมีประสิทธิภาพในหน่วยประมวลผลกลาง (CPU) แต่ WebGPU จะให้สิทธิ์เข้าถึงระดับล่างแก่นักพัฒนาแอปในหน่วยประมวลผลกราฟิก (GPU) ของอุปกรณ์

Browser Support

  • Chrome: 113.
  • Edge: 113.
  • Firefox Technology Preview: supported.
  • Safari Technology Preview: supported.

Source

ติดตั้ง WebLLM

WebLLM มีให้บริการเป็นแพ็กเกจ npm คุณสามารถเพิ่มแพ็กเกจนี้ลงในแอปพลิเคชันรายการสิ่งที่ต้องทำได้โดยการรัน npm install @mlc-ai/web-llm

เลือกรุ่น

ถัดไป คุณต้องเลือก LLM เพื่อเรียกใช้ในพื้นที่ มีโมเดลต่างๆ ให้เลือก

คุณควรทราบคําศัพท์และตัวเลขสําคัญต่อไปนี้เพื่อตัดสินใจ

  • โทเค็น: หน่วยข้อความที่เล็กที่สุดที่ LLM ประมวลผลได้
  • กรอบบริบท: จำนวนโทเค็นสูงสุดที่โมเดลประมวลผลได้
  • พารามิเตอร์หรือน้ำหนัก: ตัวแปรภายในที่เรียนรู้ระหว่างการฝึก ซึ่งนับเป็นจํานวนพันล้าน
  • การแปลงค่าเป็นจำนวนเต็ม: จำนวนบิตที่แสดงถึงน้ำหนัก ยิ่งบิตมีจำนวนมากขึ้น ความแม่นยำก็จะยิ่งสูงขึ้น แต่การใช้หน่วยความจําก็จะยิ่งมากขึ้นด้วย
  • รูปแบบตัวเลขทศนิยม: ตัวเลขทศนิยม 32 บิต (ความแม่นยำแบบเต็ม, F32) มีความแม่นยำมากกว่า ส่วนตัวเลขทศนิยม 16 บิต (ความแม่นยำแบบครึ่งหนึ่ง, F16) ทำงานได้เร็วกว่าและใช้หน่วยความจำน้อยลง แต่ต้องใช้ฮาร์ดแวร์ที่เข้ากันได้

โดยคีย์เวิร์ดเหล่านี้มักจะเป็นส่วนหนึ่งของชื่อรุ่น ตัวอย่างเช่น Llama-3.2-3B-Instruct-q4f32_1-MLC มีข้อมูลต่อไปนี้

  • โมเดลคือ LLaMa 3.2
  • โมเดลมีพารามิเตอร์ 3 พันล้านรายการ
  • รูปแบบนี้ปรับแต่งมาเพื่อผู้ช่วยแบบคำสั่งและพรอมต์ (Instruct)
  • โดยใช้การแปลงค่าแบบเป็นระเบียบ (_1) 4 บิต (q4)
  • โดยจะมีตัวเลขทศนิยม 32 บิตที่มีความแม่นยำเต็มรูปแบบ
  • ซึ่งเป็นเวอร์ชันพิเศษที่สร้างขึ้นโดย Machine Learning Compilation

คุณอาจต้องทดสอบรูปแบบต่างๆ เพื่อดูว่ารูปแบบใดเหมาะกับ Use Case ของคุณ

โมเดลที่มีพารามิเตอร์ 3, 000 ล้านรายการและ 4 บิตต่อพารามิเตอร์อาจมีไฟล์ขนาดใหญ่ถึง 1.4 GB ณ เวลาที่เขียนบทความนี้ ซึ่งแอปพลิเคชันจะต้องดาวน์โหลดลงในอุปกรณ์ของผู้ใช้ก่อนใช้งานครั้งแรก คุณอาจใช้โมเดล 3B ได้ แต่โมเดล 7B จะให้ผลลัพธ์ที่ดีกว่าในด้านความสามารถด้านการแปลหรือความรู้รอบตัว แต่ไฟล์ที่มีขนาด 3.3 GB ขึ้นไปจะมีขนาดใหญ่กว่ามาก

หากต้องการสร้างเครื่องมือ WebLLM และเริ่มการดาวน์โหลดโมเดลสำหรับแชทบ็อตรายการสิ่งที่ต้องทำ ให้เพิ่มโค้ดต่อไปนี้ลงในแอปพลิเคชัน

import {CreateMLCEngine} from '@mlc-ai/web-llm';
const engine = await CreateMLCEngine('Llama-3.2-3B-Instruct-q4f32_1-MLC', {
  initProgressCallback: ({progress}) =>  console.log(progress);
});

เมธอด CreateMLCEngine จะรับสตริงโมเดลและออบเจ็กต์การกําหนดค่า (ไม่บังคับ) เมื่อใช้เมธอด initProgressCallback คุณจะค้นหาความคืบหน้าในการดาวน์โหลดโมเดลเพื่อแสดงให้ผู้ใช้ทราบขณะรอได้

Cache API: ทําให้ LLM ทํางานแบบออฟไลน์

ระบบจะดาวน์โหลดโมเดลลงในพื้นที่เก็บข้อมูลแคชของเว็บไซต์ Cache API เปิดตัวพร้อมกับ Service Worker เพื่อให้เว็บไซต์หรือเว็บแอปพลิเคชันทำงานแบบออฟไลน์ได้ ซึ่งเป็นกลไกพื้นที่เก็บข้อมูลที่ดีที่สุดในการแคชโมเดล AI Cache API เป็นแคชที่ตั้งโปรแกรมได้ซึ่งอยู่ภายใต้การควบคุมของนักพัฒนาซอฟต์แวร์โดยสมบูรณ์ ซึ่งแตกต่างจากแคช HTTP

เมื่อดาวน์โหลดแล้ว WebLLM จะอ่านไฟล์โมเดลจาก Cache API แทนที่จะขอไฟล์ผ่านเครือข่าย ซึ่งทำให้ WebLLM ทำงานแบบออฟไลน์ได้อย่างเต็มที่

แคชจะแยกตามต้นทางเช่นเดียวกับพื้นที่เก็บข้อมูลเว็บไซต์ทั้งหมด ซึ่งหมายความว่าต้นทาง 2 รายการ ได้แก่ example.com และ example.net จะแชร์พื้นที่เก็บข้อมูลเดียวกันไม่ได้ หากเว็บไซต์ทั้ง 2 ต้องการใช้โมเดลเดียวกัน จะต้องดาวน์โหลดโมเดลแยกกัน

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

ตั้งค่าการสนทนา

โมเดลสามารถเริ่มต้นด้วยชุดพรอมต์เริ่มต้น โดยปกติแล้ว บทบาทของข้อความมี 3 บทบาท ดังนี้

  • พรอมต์ของระบบ: พรอมต์นี้จะกำหนดลักษณะการทำงาน บทบาท และบุคลิกของโมเดล นอกจากนี้ยังใช้เพื่อกราวด์ได้อีกด้วย ซึ่งก็คือการให้ข้อมูลที่กำหนดเองแก่โมเดลที่ไม่ได้อยู่ในชุดการฝึก (เช่น ข้อมูลเฉพาะโดเมน) คุณระบุพรอมต์ของระบบได้เพียงรายการเดียว
  • พรอมต์ของผู้ใช้: พรอมต์ที่ผู้ใช้ป้อน
  • พรอมต์ของ Assistant: คำตอบจาก Assistant (ไม่บังคับ)

พรอมต์ของผู้ใช้และพรอมต์ของผู้ช่วยสามารถใช้สำหรับการพรอมต์แบบ N-shot ได้โดยการให้ตัวอย่างภาษาที่เป็นธรรมชาติแก่ LLM เกี่ยวกับลักษณะการทำงานหรือการตอบกลับ

ต่อไปนี้เป็นตัวอย่างการตั้งค่าการสนทนาสำหรับแอปรายการสิ่งที่ต้องทำแบบย่อ

const messages = [
  { role: "system",
    content: `You are a helpful assistant. You will answer questions related to
    the user's to-do list. Decline all other requests not related to the user's
    todos. This is the to-do list in JSON: ${JSON.stringify(todos)}`
  },
  {role: "user", content: "How many open todos do I have?"}
];

ตอบคำถามแรก

ความสามารถของฟีเจอร์เติมข้อความในแชทจะแสดงเป็นพร็อพเพอร์ตี้ในเครื่องมือ WebLLM ที่สร้างขึ้นก่อนหน้านี้ (engine.chat.completions) หลังจากดาวน์โหลดโมเดลแล้ว คุณจะเรียกใช้การอนุมานโมเดลได้โดยเรียกใช้เมธอด create() ในพร็อพเพอร์ตี้นี้ สำหรับ Use Case ของคุณ คุณต้องการสตรีมคำตอบเพื่อให้ผู้ใช้เริ่มอ่านได้ในขณะที่ระบบกำลังสร้างคำตอบอยู่ ซึ่งจะช่วยลดเวลาที่ผู้ใช้รู้สึกว่าต้องรอ

const chunks = await engine.chat.completions.create({  messages,  stream: true, });

เมธอดนี้จะแสดงผล AsyncGenerator ซึ่งเป็นคลาสย่อยของคลาส AsyncIterator ที่ซ่อนอยู่ ใช้ลูป for await...of เพื่อรอข้อมูลที่จะเข้ามา อย่างไรก็ตาม การตอบกลับจะมีเฉพาะโทเค็นใหม่ (delta) เท่านั้น คุณจึงต้องรวบรวมการตอบกลับแบบเต็มด้วยตนเอง

let reply = '';

for await (const chunk of chunks) {
  reply += chunk.choices[0]?.delta.content ?? '';
  console.log(reply);
}

ปรากฏว่าเว็บต้องจัดการกับการตอบสนองแบบสตรีมอยู่เสมอ คุณสามารถใช้ API เช่น DOMImplementation เพื่อดำเนินการกับคำตอบแบบสตรีมเหล่านี้และอัปเดต HTML ได้อย่างมีประสิทธิภาพ

ผลลัพธ์จะอิงตามสตริงเท่านั้น คุณต้องแยกวิเคราะห์ก่อนหากต้องการตีความเป็น JSON หรือรูปแบบไฟล์อื่นๆ

อย่างไรก็ตาม WebLLM มีข้อจํากัดบางอย่าง แอปพลิเคชันต้องดาวน์โหลดรูปแบบขนาดใหญ่ก่อนใช้งานครั้งแรก ซึ่งแชร์ข้ามต้นทางไม่ได้ แอปเว็บอื่นจึงอาจต้องดาวน์โหลดรูปแบบเดียวกันอีกครั้ง แม้ว่า WebGPU จะมีประสิทธิภาพการอนุมานใกล้เคียงกับเนทีฟ แต่ก็ไม่ได้มีประสิทธิภาพถึงระดับเนทีฟอย่างเต็มรูปแบบ

สาธิต

ข้อเสียเหล่านี้ได้รับการแก้ไขโดย Prompt API ซึ่งเป็น API สําหรับการสํารวจที่ Google เสนอให้ใช้งาน ซึ่งทำงานฝั่งไคลเอ็นต์ด้วยเช่นกัน แต่ใช้โมเดลกลางที่ดาวน์โหลดลงใน Chrome ซึ่งหมายความว่าแอปพลิเคชันหลายรายการสามารถใช้โมเดลเดียวกันที่ความเร็วในการดำเนินการสูงสุดได้

อ่านเพิ่มเติมเกี่ยวกับการเพิ่มความสามารถของแชทบ็อตโดยใช้ Prompt API ในบทความถัดไป