Llama 3.2 LINE Chatbot for Master's Curriculum

บทความโดย บทความโดย บทความโดย ผศ.ดร.ณัฐโชติ พรหมฤทธิ์ และ อ.ดร.สัจจาภรณ์ ไวจรรยา
ภาควิชาคอมพิวเตอร์
คณะวิทยาศาสตร์
มหาวิทยาลัยศิลปากร

ภาควิชาคอมพิวเตอร์

ด้วยความก้าวหน้าของเทคโนโลยีปัญญาประดิษฐ์ (AI) และการประมวลผลภาษาธรรมชาติ (NLP) เราจะได้เห็นการเปลี่ยนแปลงครั้งใหญ่ในวิธีการพัฒนาระบบ Question and Answeringคณะวิทยาศาสตร์

บทความนี้จะพาผู้อ่านไปสำรวจการประยุกต์ใช้ LINE Chatbot เพื่อตอบคำถามที่เกี่ยวกับหลักสูตรปริญญาโท สาขาเทคโนโลยีสารสนเทศและนวัตกรรมดิจิทัล ของ ม.ศิลปากร ด้วยโมเดล Llama 3.2 ซึ่งเป็น Large Language Model แบบ Open Source ที่ได้รับการฝึกฝนด้วยข้อมูลขนาดใหญ่ ทำหน้าที่เป็นแกนหลักของ Chatbot ช่วยให้มันสามารถเข้าใจและตอบสนองต่อคำถามได้อย่างแม่นยำและเป็นธรรมชาติ รวมทั้งการใช้ Platform การส่งข้อความยอดนิยมอย่างเช่น LINE Chatbot จึงมั่นใจได้ในเรื่องของการเข้าถึงและความสะดวกสบายในการใช้งาน

การทำ Indexing และค้นหาข้อมูล

ปัญหาอย่างหนึ่งของ LLM คือพวกมันรู้เฉพาะสิ่งที่ได้เรียนรู้ระหว่างการ Train เท่านั้น เพื่อจะทําให้มันใช้ Private Data ได้ วิธีหนึ่งคือการ Convert ข้อมูล Private Data ทั้งหมดให้เป็น Semantic Vector (Embeddings) แล้วจัดเก็บไว้ใน Vector Database

bytebytego.com

โดย Private Data จะถูกแบ่งออกเป็นชิ้นเล็ก ๆ (Data Chunks) และส่งข้อมูลนั้นผ่าน LLM ผลลัพธ์จาก Layer สุดท้ายของ Model คือ Semantic Vector นำ Vector เก็บใน Vector Database ที่เราจะใช้ในการรกู้คืนข้อมูลชิ้นนั้น (Data Chunks)

คําถามที่ผู้ใช้ Chatbot ถามจะถูกแปลงเป็น Embeddings จากนั้นเราสามารถค้นหาชิ้นส่วนของข้อมูลที่อยู่ใกล้กับมันใน Embedding Space และป้อนเอกสารที่เกี่ยวข้องไปยัง LLM เพื่อดึงคําตอบออกมา

bytebytego.com

เพื่อแสดงตัวอย่างการสร้าง Line Chatbot โดยใช้ Llama 3.2 เราจะทดลองโดยการรัน Webhook บน Google Colab โดยจะต้องติดตั้ง Library ต่างๆ ดังนี้

!pip install colab-xterm
pip install --upgrade langchain langchain-ollama langchain-community chromadb
!pip install fastapi nest-asyncio pyngrok uvicorn line-bot-sdk

Import Library ที่จำเป็น

from langchain_ollama import OllamaLLM
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from langchain_ollama import OllamaEmbeddings
from langchain.vectorstores import Chroma
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os

import nest_asyncio
from pyngrok import ngrok
import uvicorn
from fastapi import FastAPI, Request, HTTPException
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage

เตรียม Data เป็น Text File

Download ข้อมูลหลักสูตร เป็น Text File และ Upload ขึ้น Google Colab

def load_documents(directory):
    documents = []
    for filename in os.listdir(directory):
        if filename.endswith(".txt"):
            file_path = os.path.join(directory, filename)
            loader = TextLoader(file_path, encoding='utf-8')
            documents.extend(loader.load())
    return documents
docs = load_documents("./")

สมัคร Line Messaging API (ฟรี)

แพ็กเกจราคา

ก่อนสมัคร Line Messaging API จะต้องมี Line Office Account ก่อน

ไปที่ Line Office Account เพื่อสมัคร Line Office Account (สำหรับคนที่ยังไม่ได้สมัคร)

ไปยัง Account (Provider) ที่สร้าง

แล้วกด Setting

ไปที่ Menu Messaging API แล้ว Enable Messaging API

Copy Channel secret เก็บไว้ แล้วไปที่ Line Developer

กด Console

สร้าง Channels ใน Provider ที่สมัคร

เข้าไปยัง Channel ที่สร้าง ที่หน้า Messaging API ให้ ขอ Access Token แล้ว Copy ไว้

รวมทั้งกดเลือกใช้ Webhook (เราจะนำ URL มาจาก Ngrok) แล้ว Disable Auto-reply messages และ Greeting messages

Load Model Llama 3.2

เปิดการใช้งาน Terminal บน Google Colab

%load_ext colabxterm

รัน Terminal

%xterm

ติดตั้ง ollama ใน Terminal ด้วยคำสั่ง

curl -fsSL https://ollama.com/install.sh | sh

 รัน ollama ใน Terminal และ Load Llama 3.2

ollama serve &
ollama pull llama3.2

ไปยัง Cell ของ Google Colab นอก Terminal ตรวจสอบ Model ที่ Load ด้วยคำสั่ง

!ollama list
c

สร้าง Vector จาก Document

llm = OllamaLLM(
    model="llama3.2",
    temperature=0.3,
)

# สร้าง embeddings
embeddings = OllamaEmbeddings(
    model="llama3.2"
)

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,
    chunk_overlap=200,
    separators=["\n\n", "\n", " ", ""]
)

split_docs = text_splitter.split_documents(docs)

# สร้าง vectorstore จาก documents
vectorstore = Chroma.from_documents(
    documents=split_docs,
    embedding=embeddings,
    collection_metadata={"hnsw:space": "cosine"}  # ใช้ cosine similarity
)

สร้าง Chatbot ด้วย LangChain

# กำหนด prompt template
prompt_template = """
คุณเป็นผู้ช่วย AI ที่มีความรู้ความเข้าใจลึกซึ้งในเรื่องของหลักสูตรปริญญาโท
ตอบคำถามต่อไปนี้โดยยึดตามข้อมูลที่ให้มาเท่านั้น และควรแน่ใจว่าคำตอบถูกต้องตามหลักสูตรการศึกษานี้
ถ้าไม่มั้นใจว่ามีข้อมูลก็ควรบอกว่าไม่ทราบครับ ผมไม่พบข้อมูลที่คุณถามในระบบ
และตอบด้วยความชัดเจน กระชับ ในภาษาไทย

บริบท: {context}

คำถาม: {question}

คำตอบ:
"""

โบนัส prompt template วันลอยกระทง

PROMPT = PromptTemplate(
    template=prompt_template, input_variables=["context", "question"]
)

# สร้าง RetrievalQA chain

retriever = vectorstore.as_retriever(
    search_type="mmr",  # ใช้ Maximum Marginal Relevance
    search_kwargs={
        "k": 4,  # จำนวนเอกสารที่จะดึงมา
        "fetch_k": 12,  # จำนวนเอกสารที่จะพิจารณาก่อนคัดเลือก
        "lambda_mult": 0.7  # ค่าถ่วงน้ำหนักระหว่างความเกี่ยวข้องและความหลากหลาย
    }
)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True,
    chain_type_kwargs={"prompt": PROMPT}
)

def ask_question(question: str) -> str:
    try:
        result = qa_chain({"query": question})
        return result["result"]
    except Exception as e:
        print(f"เกิดข้อผิดพลาด: {e}")
        return "ขออภัย, มีบางอย่างผิดพลาดในการประมวลผลคำถามของคุณ"

ทดสอบการใช้งาน

question = "ชื่อหลักสูตรภาษาไทย คือ"
answer = ask_question(question)
print(f"คำถาม: {question}")
print(f"คำตอบ: {answer}")

คำถาม: ชื่อหลักสูตรภาษาไทย คือ
คำตอบ: ชื่อหลักสูตรภาษาไทยคือ "วิทยาศาสตรมหาบัณฑิต (เทคโนโลยีสารสนเทศและนวัตกรรมดิจิทัล)"

ไปยัง https://dashboard.ngrok.com แล้วนำคำสั่ง Config Token มาวางใน Google Colab

!ngrok config add-authtoken xxxx

Authtoken saved to configuration file: /root/.config/ngrok/ngrok.yml

Config Channel Access Token และ Channel secret

app = FastAPI()

line_bot_api = LineBotApi('Channel_Access_Token')
handler = WebhookHandler('Channel_Secret')

รัน Line Webhook

@app.post("/callback")
async def callback(request: Request):
    signature = request.headers['X-Line-Signature']
    body = await request.body()

    try:
        handler.handle(body.decode("utf-8"), signature)
    except InvalidSignatureError:
        raise HTTPException(status_code=400, detail="Invalid signature")

    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    text = event.message.text
    reply_text = ask_question(text)

    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=reply_text)
    )

# สร้าง ngrok tunnel
ngrok_tunnel = ngrok.connect(8000)
print('Webhook URL:', ngrok_tunnel.public_url + '/callback')

nest_asyncio.apply()

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Copy Webhook URL ไปวางที่ Line Developer แล้วกด Verify

Add Line Chatbot ด้วย QR Code แล้วทดลองใช้งาน

มหาวิทยาลัยศิลปากร