Tag: LangChain

  • Basic Haystack: วิธีใช้ Haystack 2.0 เพื่อทำงานกับ LLM อย่างง่าย ใน 5 ขั้นตอน—ตัวอย่างการสร้าง AI ตอบคำถามเรื่อง Mental Model

    Basic Haystack: วิธีใช้ Haystack 2.0 เพื่อทำงานกับ LLM อย่างง่าย ใน 5 ขั้นตอน—ตัวอย่างการสร้าง AI ตอบคำถามเรื่อง Mental Model

    ในบทความก่อน ผมพาทุกคนไปรู้จักกับการใช้ LangChain ซึ่งเป็น package ยอดนิยมสำหรับสร้าง LLM (large language model) application อย่าง chatbot

    ในบทความนี้ ผมจะพาทุกคนไปรู้จักกับ Haystack 2.0 ซึ่งเป็นอีกหนึ่ง package ที่ทำงานได้เหมือนกับ LangChain

    แม้ว่า LangChain เป็นที่นิยมและใช้งานง่าย แต่ก็แลกมาด้วยข้อจำกัดใน “การมองเห็น” เพราะ LangChain ซ่อนการทำงานหลาย ๆ อย่างไว้หลัง code ไม่กี่บรรัดเพื่อให้เราใช้งานง่าย เมื่อเกิด bug ขึ้นมา เราจะไม่รู้เลยว่า error อยู่ที่จุดไหน จนกว่าเราจะแกะการทำงานเบื้องหลัง code ที่เราเขียนออกมา

    Haystack เป็น package ที่มี “การมองเห็น” ที่สูงกว่า เพราะมีการทำงานแบบแยกส่วนประกอบ หรือ component เหมือนกับรถยนต์ที่ประกอบขึ้นมาจากหลายชิ้นส่วน อย่างเครื่องยนต์ ถังน้ำมัน ล้อ และพวงมาลัย เราสามารถกำหนดได้ว่า เราอยากได้ชิ้นส่วนไหนแบบไหน และแต่ละชิ้นส่วนจะประกอบกันยังไง เมื่อเป็นเช่นนี้ เราจะรู้ได้ว่าข้อผิดพลาดอยู่ที่ไหน เพราะเราเป็นคนที่ประกอบทุกอย่างขึ้นมาเอง

    ในบทความนี้ ผมจะพาทุกคนไปดูการใช้ Haystack เพื่อเชื่อมต่อกับ LLM ผ่านตัวอย่างการสร้าง AI ตอบคำถามเกี่ยวกับ mental model กัน

    ถ้าพร้อมแล้ว ไปเริ่มกันเลย


    1. ⭐️ High-Level View
    2. 📜 Step 1. Create a Prompt Builder
    3. 🤖 Step 2. Create an LLM Instance
    4. 🪈 Step 3. Create a Pipeline
    5. 🏃 Step 4. Run
    6. 💪 Summary
    7. 😺 GitHub
    8. 📃 References

    ⭐️ High-Level View

    ในการใช้ Haystack เชื่อมต่อกับ LLM เราจะใช้ component 3 อย่าง:

    1. Prompt builder สำหรับเก็บ prompt
    2. LLM instance สำหรับเรียก LLM
    3. Pipeline สำหรับเชื่อมทุก component เข้าด้วยกัน

    โดยเราจะเรียกใช้งาน 3 components นี้ใน 4 ขั้นตอน:

    1. Create a prompt builder
    2. Create an LLM instance
    3. Create a pipeline
    4. Run

    ไปดูตัวอย่างทั้ง 4 ขั้นตอนกัน


    📜 Step 1. Create a Prompt Builder

    ในขั้นแรก เราจะสร้าง prompt builder สำหรับเก็บ prompt กัน

    เราจะเริ่มจากสร้าง system prompt และ user prompt:

    Python
    # System prompt
    system_prompt = """
    You are an expert curator of mental models across science, philosophy, and applied reasoning.
    Your task is to explain mental models clearly and accurately using a fixed schema.
    If the origin of a model is unclear or debated, state that explicitly.
    Do not invent historical sources. Be concise and concrete.
    """
    # User prompt
    user_prompt = "Explain the following mental model: {{model_query}}"

    Note: เราใช้ {{}} ใน user prompt เพื่อที่เราจะสร้างแทนที่ค่าใน user prompt ได้ในภายหลัง เช่น ถ้าเราต้องการถามเกี่ยวกับ “First-Principles Thinking” user prompt ของเราก็จะกลายเป็น:

    "Explain the following mental model: First-Principles Thinking"

    จากนั้น เราจะใส่ prompts ลงใน ChatPromptBuilder():

    Python
    # Import required packages
    from Haystack.components.builders import ChatPromptBuilder
    from Haystack.dataclasses import ChatMessage
    # Create a prompt builder instance
    prompt_builder = ChatPromptBuilder(
    template=[
    ChatMessage.from_system(system_prompt.strip()),
    ChatMessage.from_user(user_prompt)
    ],
    required_variables=["model_query"]
    )

    Note: เรากำหนด required_variables เพื่อกันไม่ให้ {{model_query}} เป็นค่าว่าง


    🤖 Step 2. Create an LLM Instance

    ในขั้นที่ 2 เราจะสร้าง LLM instance สำหรับเชื่อมต่อกับ LLM โดยในตัวอย่าง เราจะใช้ Gemini

    เราจะเริ่มจากดึง API key ที่เก็บไว้ใน .env:

    Python
    # Import required packages
    import os
    # Retrieve the API key
    GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")

    จากนั้น กำหนด structured output หรือหน้าตา output ที่เราต้องการ ด้วย Pydantic:

    Python
    # Import required packages
    from pydantic import BaseModel, Field
    from typing import List, Literal
    # Define the output schema
    class MentalModel(BaseModel):
    # Mental model name
    model_name: str = Field(
    description="The commonly accepted name of the mental model"
    )
    # Origin or source
    origin: str = Field(
    description="Where the model comes from (a person, book, field, or cultural origin)"
    )
    # Brief description
    description: str = Field(
    description="A brief explanation of what the mental model is and why it matters"
    )
    # Example
    example: str = Field(
    description="A concrete real-world example illustrating the mental model"
    )
    # Tags
    tags: List[str] = Field(
    description="Short tags such as decision-making, systems thinking, learning, and philosophy"
    )

    หน้าตา structured output ที่เราจะได้:

    {
    "model_name": "",
    "origin": "",
    "description": "",
    "example": "",
    "tags": []
    }

    สุดท้าย เราจะใส่ API key และ structured output ลงใน LLM instance:

    Python
    # Import required packages
    from Haystack.utils import Secret
    from Haystack_integrations.components.generators.google_genai import GoogleGenAIChatGenerator
    # Create an LLM instance
    llm_with_structured_output = GoogleGenAIChatGenerator(
    model="gemini-2.5-flash",
    api_key=Secret.from_token(GEMINI_API_KEY),
    generation_kwargs={
    "temperature": 0.5,
    "response_format": MentalModel
    }
    )

    🪈 Step 3. Create a Pipeline

    ในขั้นที่ 3 เราจะเชื่อมต่อ prompt builder และ LLM instance เข้าด้วยกัน

    เริ่มจากสร้าง pipeline:

    Python
    # Import the required package
    from Haystack import Pipeline
    # Create a pipeline instance
    chain = Pipeline()

    เพิ่ม prompt builder และ LLM instance ลงใน pipeline:

    Python
    # Add the prompt builder and LLM instances
    chain.add_component(
    "prompt_builder", # Name
    prompt_builder # Instance
    )
    chain.add_component(
    "llm", # Name
    llm_with_structured_output # Instance
    )

    แล้วเชื่อมต่อ prompt builder และ LLM instance เข้าด้วยกัน:

    Python
    # Connect the components
    chain.connect(
    "prompt_builder.prompt", # Sender: prompt from prompt builder
    "llm.messages" # Receiver: message from LLM instance
    )

    Note: เรากำหนดให้ prompt builder ส่ง system และ user prompts ให้เป็น input สำหรับ LLM instance:

    Prompt FROM prompt builder
    Messages TO LLM instance

    🏃 Step 4. Run

    ในขั้นสุดท้าย เราจะรัน pipeline และดึงผลลัพธ์ที่ต้องการออกมา

    ตัวอย่างเช่น ถามเกี่ยวกับ “Compound Interest”:

    Python
    # Run the pipeline with a mental-model query
    raw_result = chain.run(
    data={
    "prompt_builder": {"model_query": "Compound Interest"}
    }
    )

    ดึงผลลัพธ์ที่ต้องการ:

    Python
    # Extract the structured-output text from the raw result
    reply_json = raw_result["llm"]["replies"][0].text
    # Validate the structured output
    result = MentalModel.model_validate_json(reply_json)
    # Print the validated structured output
    print(result.model_dump())

    ผลลัพธ์:

    {
    "model_name": "Compound Interest",
    "origin": (
    "Finance, Mathematics. The concept dates back to ancient Mesopotamia, "
    "with formalization in mathematics and finance over centuries."
    ),
    "description": (
    "Compound interest is the interest on a loan or deposit calculated "
    "based on both the initial principal and the accumulated interest from "
    "previous periods. It matters because it illustrates exponential growth, "
    "where small, consistent gains over time lead to significantly larger "
    "returns, making it a powerful force in finance and many other systems."
    ),
    "example": (
    "If you invest $1,000 at a 5% annual interest rate, after one year "
    "you have $1,050. In the second year, you earn 5% not just on the "
    "initial $1,000, but on the full $1,050, resulting in $1,102.50. "
    "This 'interest on interest' accelerates growth significantly over "
    "decades compared to simple interest."
    ),
    "tags": [
    "Finance",
    "Growth",
    "Long-term thinking",
    "Mathematics",
    "Systems thinking",
    ],
    }

    💪 Summary

    ในบทความนี้ เราได้ทำความรู้จักกับ Haystack ซึ่งเป็น package สำหรับสร้าง LLM application กัน

    เราได้เรียนเกี่ยวกับ 3 components สำหรับเชื่อมต่อกับ LLM:

    1. Prompt builder
    2. LLM instance
    3. Pipeline

    และการเชื่อมต่อกับ LLM ใน 4 ขั้นตอน:

    1. Create a prompt builder
    2. Create an LLM instance
    3. Create a pipeline
    4. Run

    😺 GitHub

    ดูตัวอย่าง code ทั้งหมดได้ที่ GitHub


    📃 References

  • สร้าง RAG pipeline ด้วย LangChain ใน 5 ขั้นตอน–ตัวอย่างการสร้างบอทตอบคำถามเกี่ยวกับนโยบาย HR

    สร้าง RAG pipeline ด้วย LangChain ใน 5 ขั้นตอน–ตัวอย่างการสร้างบอทตอบคำถามเกี่ยวกับนโยบาย HR

    RAG (Retrieval-Augmented Generation) เป็นเทคนิคที่ช่วยให้ LLM (large language model) ตอบคำถามได้แม่นยำขึ้น และไม่ถูกจำกัดด้วย knowledge cutoff หรือความรู้ที่จำกัดจากตอน train model

    RAG ทำงานใน 2 ขั้นตอน:

    1. Retrieve: ดึงเอกสารที่เกี่ยวข้อง
    2. Generate: สร้างคำตอบจากเอกสารที่ได้มา

    RAG มีข้อดี 3 ข้อ:

    1. คำตอบมีความแม่นยำมากขึ้น
    2. คำตอบมีความเกี่ยวข้องกับคำถามมากขึ้น
    3. ช่วยอัปเดตความรู้ให้กับ LLM ได้โดยไม่ต้อง train model ใหม่

    ในบทความนี้ เราจะมาดูวิธีการสร้าง RAG pipeline ด้วย LangChain ซึ่งเป็น framework ในการพัฒนาแอปพลิเคชัน LLM กัน

    ถ้าพร้อมแล้ว ไปเริ่มกันเลย


    1. 🔆 High-Level View
    2. 📑 Step 1. Load Documents
    3. 📚 Step 2. Split Text
    4. 💾 Step 3. Embed & Store Chunks
    5. 🔎 Step 4. Create a Retriever
    6. 🤖 Step 5. Generate a Response
    7. 💪 Summary
    8. 😺 GitHub
    9. 📃 References

    🔆 High-Level View

    เราใช้ LangChain สร้าง RAG pipeline ได้ใน 5 ขั้นตอน

    1. Load documents
    2. Split text
    3. Embed and store chunks
    4. Create a retriever
    5. Generate a response

    เราไปดูการสร้าง RAG pipeline กับตัวอย่างบอทตอบคำถามเกี่ยวกับนโยบาย HR เช่น การลาและสวัสดิ กัน


    📑 Step 1. Load Documents

    ในขั้นแรก เราจะโหลดเอกสารที่เป็นข้อมูลของ RAG pipeline ก่อน

    LangChain มีหลาย functions สำหรับโหลดเอกสาร เช่น:

    FunctionDocument
    TextLoader()Text file
    UnstructuredMarkdownLoader()Markdown file
    CSVLoader()CSV file
    JSONLoader()JSON file
    PyPDFLoader()PDF file
    DirectoryLoader()ไฟล์จากในโฟลเดอร์

    ในตัวอย่าง เราจะใช้ DirectoryLoader() เพราะเราเก็บเอกสารไว้ในโฟลเดอร์ชื่อ documents:

    documents/
    ├── benefits_policy.txt
    ├── compensation_policy.txt
    ├── leave_policy.txt
    └── remote_work_policy.txt

    ตัวอย่างข้อมูลในเอกสาร benefits_policy.txt:

    DataWise Co. Benefits Policy
    Full-time employees receive health insurance after completing probation.
    The company provides annual health checkups once per year.
    Employees can claim up to 2,000 THB per month for wellness activities such as fitness memberships, yoga classes, or mental health support.
    Employees are also eligible for learning support. The company reimburses up to 10,000 THB per year for approved online courses, books, or professional certificates.

    วิธีใช้ DirectoryLoader():

    Python
    # Import packages
    from langchain_community.document_loaders import DirectoryLoader
    from langchain_community.document_loaders import TextLoader
    # Initialise loader
    loader = DirectoryLoader(
    path="documents",
    glob="*.txt",
    loader_cls=TextLoader,
    loader_kwargs={"encoding": "utf-8"}
    )
    # Load documents
    docs = loader.load()

    การใช้งาน DirectoryLoader():

    • path = โฟลเดอร์ที่ต้องการโหลด
    • glob = pattern ชื่อไฟล์ที่ต้องการโหลด (เช่น "*.txt" หมายถึง ไฟล์ที่ลงชื่อด้วย .txt ทั้งหมด)
    • loader_cls = function ที่จะใช้โหลด (เช่น TextLoader())
    • loader_kwargs = argument เพิ่มเติมสำหรับ function ที่จะใช้โหลด

    เราสามารถดูตัวอย่างเอกสารที่โหลดแล้วได้แบบนี้:

    Python
    # View loaded documents
    for doc in docs:
    print("=" * 50)
    print(doc.metadata["source"])
    print("=" * 50)
    print(doc.page_content[:200])

    ผลลัพธ์:

    ==================================================
    documents/remote_work_policy.txt
    ==================================================
    DataWise Co. Remote Work Policy
    Employees may work from home up to 2 days per week.
    Remote work must be approved by the employee's direct manager.
    Employees must be reachable on Slack during core w
    ==================================================
    documents/benefits_policy.txt
    ==================================================
    DataWise Co. Benefits Policy
    Full-time employees receive health insurance after completing probation.
    The company provides annual health checkups once per year.
    Employees can claim up to 2,000 THB
    ==================================================
    documents/compensation_policy.txt
    ==================================================
    DataWise Co. Compensation Policy
    Salary is paid on the last working day of each month.
    Performance bonuses are reviewed once per year in December.
    Employees may receive an annual salary adjustment
    ==================================================
    documents/leave_policy.txt
    ==================================================
    DataWise Co. Leave Policy
    Full-time employees receive 10 days of annual leave per year after completing probation.
    Employees receive 15 days of paid sick leave per year.
    Sick leave of 3 consecutive

    📚 Step 2. Split Text

    ในขั้นที่ 2 เราจะแบ่ง text ในเอกสารออกเป็นก้อน ๆ หรือ chunk เพราะการแบ่ง text จะช่วยให้การค้นหาข้อมูลง่ายขึ้น

    LangChain มี 3 functions หลักในการแบ่ง text:

    FunctionMethod
    CharacterTextSplitter()แบ่งตามจำนวน character ที่กำหนด
    TokenTextSplitter()แบ่งตามจำนวน token ที่กำหนด
    RecursiveCharacterTextSplitter()แบ่งตามย่อหน้า บรรทัด และประโยค

    ในตัวอย่าง เราจะใช้ RecursiveCharacterTextSplitter() เพราะเป็นวิธีที่เก็บรักษาความหมายของ text ได้ดีกว่าวิธีอื่น:

    วิธีใช้ RecursiveCharacterTextSplitter():

    Python
    # Import package
    from langchain_text_splitters import RecursiveCharacterTextSplitter
    # Create splitter
    text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100
    )
    # Split documents
    chunks = text_splitter.split_documents(docs)

    ดูตัวอย่าง text ที่แบ่งแล้วได้ตามนี้:

    Python
    # View results
    for i, chunk in enumerate(chunks[:5]):
    print(f"Chunk {i+1}")
    print("Source:", chunk.metadata["source"])
    print(chunk.page_content)
    print("-" * 50)

    ผลลัพธ์:

    Chunk 1
    Source: documents/remote_work_policy.txt
    DataWise Co. Remote Work Policy
    Employees may work from home up to 2 days per week.
    Remote work must be approved by the employee's direct manager.
    Employees must be reachable on Slack during core working hours from 10:00 AM to 4:00 PM.
    Employees working remotely are responsible for maintaining a stable internet connection and a quiet work environment.
    New employees may request remote work only after completing their first month.
    --------------------------------------------------
    Chunk 2
    Source: documents/benefits_policy.txt
    DataWise Co. Benefits Policy
    Full-time employees receive health insurance after completing probation.
    The company provides annual health checkups once per year.
    Employees can claim up to 2,000 THB per month for wellness activities such as fitness memberships, yoga classes, or mental health support.
    Employees are also eligible for learning support. The company reimburses up to 10,000 THB per year for approved online courses, books, or professional certificates.
    --------------------------------------------------
    Chunk 3
    Source: documents/compensation_policy.txt
    DataWise Co. Compensation Policy
    Salary is paid on the last working day of each month.
    Performance bonuses are reviewed once per year in December.
    Employees may receive an annual salary adjustment based on company performance, individual performance, and market benchmarks.
    Overtime pay is available only for non-managerial employees and must be approved by a manager before the overtime work begins.
    --------------------------------------------------
    Chunk 4
    Source: documents/leave_policy.txt
    DataWise Co. Leave Policy
    Full-time employees receive 10 days of annual leave per year after completing probation.
    Employees receive 15 days of paid sick leave per year.
    Sick leave of 3 consecutive days or more requires a medical certificate.
    Employees should submit annual leave requests at least 7 days in advance through the HR system.
    Unused annual leave can be carried over for up to 5 days into the next calendar year.
    --------------------------------------------------

    สังเกตว่า text ถูกแบ่งย่อหน้า ทำให้ chunk ที่ได้มีความหมายที่ครบถ้วนในตัวเอง


    💾 Step 3. Embed & Store Chunks

    ในขั้นที่ 3 เราจะ embed และเก็บข้อมูลลงใน vector database

    Embedding คือ การแปลง chunk ให้กลายเป็น vector คือ ชุดตัวเลขที่เป็นตัวแทนของ chunk

    ตัวอย่าง chunk:

    "Employees can work from home up to two days per week."

    ตัวอย่าง vector:

    [
    0.021,
    -0.184,
    0.736,
    0.094,
    -0.511,
    0.302,
    0.087,
    -0.624
    ]

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

    ใน LangChain เราสามารถเลือก model ที่จะใช้ embedding ได้ ในตัวอย่าง เราจะใช้ Gemini กัน:

    Python
    # Import packages
    import os
    from langchain_google_genai import GoogleGenerativeAIEmbeddings
    # Get API key
    GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
    # Create embedder
    document_embedder = GoogleGenerativeAIEmbeddings(
    model="gemini-embedding-001",
    task_type="retrieval_document",
    google_api_key=GEMINI_API_KEY
    )

    หลังจากได้ embedding model แล้ว เราจะสร้าง vector database เพื่อเก็บ vector โดยในตัวอย่างเราจะใช้ FAISS database:

    Python
    # Import package
    from langchain_community.vectorstores import FAISS
    # Build vector DB
    vectorstore = FAISS.from_documents(
    documents=chunks,
    embedding=document_embedder
    )

    สังเกตว่า เราใส่ document_embedder ไปใน vector database ด้วย เพื่อแปลง chunk เป็น vector และเก็บลงใน database


    🔎 Step 4. Create a Retriever

    ในขั้นที่ 4 เราจะสร้าง retriever ที่ทำหน้าที่ค้นหา vector โดยใช้ .as_retriever() แบบนี้:

    Python
    # Creater retriever
    retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 2}
    )

    เราสามารถทดสอบ retriever เพื่อดูว่า จะได้เอกสารอะไรกลับมา ได้แบบนี้:

    Python
    # Test retriever
    question = "Do I need a medical certificate for sick leave?"
    relevant_docs = retriever.invoke(question)
    for i, doc in enumerate(relevant_docs, start=1):
    print(f"Retrieved chunk {i}")
    print("Source:", doc.metadata["source"])
    print(doc.page_content)
    print("-" * 60)

    ผลลัพธ์:

    Retrieved chunk 1
    Source: documents/leave_policy.txt
    DataWise Co. Leave Policy
    Full-time employees receive 10 days of annual leave per year after completing probation.
    Employees receive 15 days of paid sick leave per year.
    Sick leave of 3 consecutive days or more requires a medical certificate.
    Employees should submit annual leave requests at least 7 days in advance through the HR system.
    Unused annual leave can be carried over for up to 5 days into the next calendar year.
    ------------------------------------------------------------
    Retrieved chunk 2
    Source: documents/compensation_policy.txt
    DataWise Co. Compensation Policy
    Salary is paid on the last working day of each month.
    Performance bonuses are reviewed once per year in December.
    Employees may receive an annual salary adjustment based on company performance, individual performance, and market benchmarks.
    Overtime pay is available only for non-managerial employees and must be approved by a manager before the overtime work begins.
    ------------------------------------------------------------

    🤖 Step 5. Generate a Response

    ในขั้นสุดท้าย เราจะให้ LLM สร้างคำตอบโดยใช้ข้อมูลใน vector database

    ในตัวอย่างเราจะลองใช้ Gemini ช่วยคิดคำตอบให้กับเรา

    เราจะเริ่มจากเชื่อมต่อกับ Gemini และสร้าง prompt ก่อน:

    Python
    # Import packages
    from langchain_google_genai import ChatGoogleGenerativeAI
    from langchain_core.prompts import ChatPromptTemplate
    # Initialise Gemini
    llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    temperature=0,
    google_api_key=GEMINI_API_KEY
    )
    # Create prompt template
    prompt = ChatPromptTemplate.from_template("""
    You are an HR policy assistant.
    Answer the user's question using only the policy context below.
    Rules:
    - Do not use outside knowledge.
    - If the answer is not in the context, say:
    "I could not find this information in the available company policies."
    - Keep the answer concise.
    - Mention the source policy file when possible.
    Policy context:
    {context}
    User question:
    {question}
    """)

    จากนั้น กำหนดคำถามและดึงเอกสารที่เกี่ยวข้องจาก vector database

    Python
    # Ask a question
    question = "Do I need a medical certificate for sick leave?"
    # Retrieve relevant document chunks
    relevant_docs = retriever.invoke(question)
    # Combine retrieved chunks into one context string
    context = "\n\n".join(
    [
    f"Source: {doc.metadata['source']}\n"
    f"{doc.page_content}"
    for doc in relevant_docs
    ]
    )
    # Inspect retrieved context before sending it to Gemini
    print("Retrieved context:")
    print(context)

    ผลลัพธ์:

    Retrieved context:
    Source: documents/leave_policy.txt
    DataWise Co. Leave Policy
    Full-time employees receive 10 days of annual leave per year after completing probation.
    Employees receive 15 days of paid sick leave per year.
    Sick leave of 3 consecutive days or more requires a medical certificate.
    Employees should submit annual leave requests at least 7 days in advance through the HR system.
    Unused annual leave can be carried over for up to 5 days into the next calendar year.
    Source: documents/compensation_policy.txt
    DataWise Co. Compensation Policy
    Salary is paid on the last working day of each month.
    Performance bonuses are reviewed once per year in December.
    Employees may receive an annual salary adjustment based on company performance, individual performance, and market benchmarks.
    Overtime pay is available only for non-managerial employees and must be approved by a manager before the overtime work begins.

    แล้วส่งข้อมูลคำถามและเอกสารให้กับ Gemini:

    Python
    # Add context and question to prompt template
    messages = prompt.invoke(
    {
    "context": context,
    "question": question
    }
    )
    # Send prompt to Gemini
    response = llm.invoke(messages)
    # Print Gemini's answer
    print(response.content)

    ผลลัพธ์:

    Yes, sick leave of 3 consecutive days or more requires a medical certificate. (Source: documents/leave_policy.txt)

    เพื่อให้เราใช้งาน RAG pipeline ได้ง่าย เราสามารถแปลงโค้ดชุดนี้ให้เป็น function ได้:

    Python
    # Convert to function
    def ask_policy_question(question: str) -> str:
    """
    Retrieve relevant policy chunks, send them to Gemini,
    and return Gemini's answer.
    """
    # Retrieve relevant chunks
    relevant_docs = retriever.invoke(question)
    # Combine retrieved chunks into context
    context = "\n\n".join(
    [
    f"Source: {doc.metadata['source']}\n"
    f"{doc.page_content}"
    for doc in relevant_docs
    ]
    )
    # Add context and question to prompt template
    messages = prompt.invoke(
    {
    "context": context,
    "question": question
    }
    )
    # Send completed prompt to Gemini
    response = llm.invoke(messages)
    # Return answer text
    return response.content

    เพื่อที่เราจะเขียนโค้ดสั้นลงในครั้งถัด ๆ ไป:

    Python
    # Test function
    answer = ask_policy_question("Who is eligible for health insurance?")
    print(answer)

    ผลลัพธ์:

    Full-time employees receive health insurance after completing probation. (Source: documents/benefits_policy.txt)

    💪 Summary

    ในบทความนี้ เราได้เรียนรู้การสร้าง RAG pipeline ด้วย LangChain ใน 5 ขั้นตอน:

    1. Load documents: โหลดเอกสารสำหรับ RAG pipeline
    2. Split text: แบ่ง text ในเอกสารเป็น chunk
    3. Embed and store chunks: แปลง chunk เป็น vector และเก็บลงใน database
    4. Create a retriever: สร้างตัวค้นหาเอกสารจาก vector database
    5. Generate a response: สร้างคำตอบจากเอกสาร

    😺 GitHub

    ดูตัวอย่าง code และเอกสารทั้งหมดได้ที่ GitHub


    📃 References

  • Basic LangChain: วิธีใช้ LangChain เพื่อทำงานกับ LLM อย่างง่าย ใน 5 ขั้นตอน—ตัวอย่างการสร้าง AI ตอบคำถามเรื่อง Mental Model

    Basic LangChain: วิธีใช้ LangChain เพื่อทำงานกับ LLM อย่างง่าย ใน 5 ขั้นตอน—ตัวอย่างการสร้าง AI ตอบคำถามเรื่อง Mental Model

    langchain เป็น framework สำหรับสร้างแอปพลิเคชั่นที่ใช้ large language model (LLM) ที่ช่วยลดความยุ่งยากการเรียกใช้งาน API โดยตรง

    langchain มีข้อดี 3 อย่าง:

    1. Modular: ใช้งานง่าย ด้วยการเขียนเป็นส่วน ๆ หรือ module (เหมือนเลโก้)
    2. Use case: รองรับการใช้งานหลายหลาก เพราะสามารถประกอบ module เข้าด้วยกันได้หลายแบบ (ต่อเลโก้ได้หลายแบบ)
    3. Integration: ใช้งานร่วมเครื่องมือได้กับหลากหลาย เช่น OpenAI, Hugging Face, databricks

    ในบทความนี้ เรามาดูวิธีใช้ langchain เพื่อทำงานกับ LLM อย่างง่ายกัน

    ถ้าพร้อมแล้ว ไปเริ่มกันเลย


    1. 🧠 Mental Model
    2. 🤖 Step 1. Set LLM
    3. 💬 Step 2. Set Prompt
    4. 📦 Step 3. Set Output Structure
    5. ⛓️‍💥 Step 4. Chain
    6. 🏃 Step 5. Run
      1. ☝️ Single Run
      2. 🎳 Batch Run
    7. 💪 Summary
    8. 🫵 Your Turn
    9. 📄 References

    🧠 Mental Model

    การใช้งาน langchain มีอยู่ 5 ขั้นตอน ได้แก่:

    1. Set LLM: เลือก LLM ที่ต้องการ
    2. Set prompt: สร้าง prompt สำหรับคุยกับ LLM
    3. Set output structure: กำหนดหน้าตา output ที่ต้องการ
    4. Chain: เชื่อม LLM และ prompt เข้าด้วยกัน เพื่อสร้าง pipeline ในการเรียกใช้ LLM
    5. Run: เรียกใช้งาน LLM

    เราไปดูการใช้งาน ผ่านการสร้าง chatbot ตอบคำถามเกี่ยวกับ mental model กัน


    🤖 Step 1. Set LLM

    langchain รองรับการใช้งาน LLM หลายเจ้า เช่น:

    ในตัวอย่าง เราจะเลือกใช้ Gemini โดยเริ่มจากโหลด module สำหรับเชื่อมกับ Gemini:

    Python
    # Import package
    from langchain_google_genai import ChatGoogleGenerativeAI

    แล้วสร้าง LLM instance ขึ้นมา:

    Python
    # Create model instance
    llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    temperature=0.5,
    api_key="YOUR_API_KEY"
    )
    • model: ชื่อ LLM ที่เราต้องการใช้งาน
    • temperature: ระดับความสุ่มของคำตอบจาก LLM (ค่ายิ่งสูง คำตอบยิ่งมีความหลากหลาย ส่วนยิ่งค่าน้อย คำตอบจะยิ่งมีความคล้ายคลึงกัน)
    • api_key: API key สำหรับใช้งาน LLM (ดูวิธีการสร้าง Gemini API key ฟรี)

    💬 Step 2. Set Prompt

    ในขั้นที่ 2 เราจะสร้าง prompt สำหรับคุยกับ LLM กัน:

    1. โหลด module
    2. กำหนด prompt

    ขั้นย่อยที่ 1. โหลด module สำหรับสร้าง prompt:

    Python
    # Import package
    from langchain_core.prompts import ChatPromptTemplate

    ขั้นย่อยที่ 2. กำหนด prompt โดยแยกระหว่าง:

    1. System prompt: บทบาทและสไตล์การตอบคำถามของ LLM (เช่น ผู้เชี่ยวชาญด้าน mental model)
    2. User prompt: คำถามที่จะส่งให้ LLM (เช่น บอกให้อธิบาย mental model ที่ต้องการ)

    ตัวอย่าง system และ user prompts:

    Python
    # Define system prompt
    system_prompt = """
    You are an expert curator of mental models across science, philosophy, and applied reasoning.
    Your task is to explain mental models clearly and accurately using a fixed schema.
    If the origin of a model is unclear or debated, state that explicitly.
    Do not invent historical sources. Be concise and concrete.
    """
    # Define user prompt
    user_prompt = "Explain the following mental model: {model_query}"

    จากนั้น ประกอบ prompts เข้าด้วยกัน:

    Python
    # Create prompt template
    prompts = ChatPromptTemplate.from_messages(
    [
    # System prompt
    ("system", system_prompt.strip()),
    # User prompt
    ("human", user_prompt)
    ]
    )

    เราสามารถดูตัวอย่าง prompt ได้ด้วย .format_messages():

    Python
    # Inspect prompt template
    prompts.format_messages(model_query="Pareto Principle")

    ผลลัพธ์:

    [SystemMessage(content='You are an expert curator of mental models across science, philosophy, and applied reasoning.\\n\\nYour task is to explain mental models clearly and accurately using a fixed schema.\\n\\nIf the origin of a model is unclear or debated, state that explicitly.\\n\\nDo not invent historical sources. Be concise and concrete.', additional_kwargs={}, response_metadata={}),
    HumanMessage(content='Explain the following mental model: Pareto Princinple', additional_kwargs={}, response_metadata={})]

    📦 Step 3. Set Output Structure

    ในขั้นที่ 3 เราจะกำหนดหน้าตา output ที่เราต้องการ

    เช่น ถ้าเราต้องการให้คืนค่า JSON แบบนี้:

    {
    "model_name": "",
    "origin": "",
    "description": "",
    "example": "",
    "tags": []
    }

    เรากำหนดได้โดยใช้ pydantic และ typing packages แบบนี้:

    Python
    # Import packages
    from pydantic import BaseModel, Field
    from typing import List, Literal
    # Define output structure
    class MentalModel(BaseModel):
    # Mental model name
    model_name: str = Field(description="The commonly accepted name of the mental model")
    # Source/origin
    origin: str = Field(
    description="Where the model comes from (person, book, field, or cultural origin)"
    )
    # Brief description
    description: str = Field(
    description="A brief explanation of what the mental model is and why it matters"
    )
    # Example
    example: str = Field(
    description="A concrete real-world example illustrating the mental model"
    )
    # Tags
    tags: List[str] = Field(
    description="Short tags such as decision-making, systems thinking, learning, philosophy"
    )

    Note: ดูวิธีใช้ Pydantic

    หลังกำหนดหน้าตา output แล้ว ให้ใส่เข้าไปใน LLM instance แบบนี้:

    Python
    # Add output structure to LLM
    llm_with_structured_output = llm.with_structured_output(MentalModel)

    ⛓️‍💥 Step 4. Chain

    ในขั้นที่ 4 ให้เราสร้าง chain โดยเชื่อม LLM instance เข้ากับ prompts ด้วย pipe operator (|):

    Python
    # Build chain
    chain = prompts | llm_with_structured_output

    Note: ให้มองว่า | เป็นลูกศรชี้ทางขวา (prompt → llm)


    🏃 Step 5. Run

    ในขั้นสุดท้าย เราจะเรียกใช้งาน chain ซึ่งทำได้ 2 แบบ:

    1. Single run: เรียกใช้ครั้งเดียว
    2. Batch run: เรียกใช้หลายครั้งพร้อมกัน

    .

    ☝️ Single Run

    เราเรียกใช้งานครั้งเดียวด้วย .invoke()

    ในตัวอย่าง เราจะถามเกี่ยวกับ “compound interest” กัน:

    Python
    # Run query
    result = chain.invoke({"model_query": "Compound Interest"})

    แสดงผลลัพธ์ใน console:

    Python
    # Import package
    import json
    # Load result
    result_dict = result.model_dump()
    # Print
    print(json.dumps(result_dict, indent=4))

    ผลลัพธ์:

    {
    "model_name": "Compound Interest",
    "origin": "Finance, Mathematics; concept dates back to ancient times, formalized in the Renaissance.",
    "description": "Compound interest is the interest on a loan or deposit calculated based on both the initial principal and the accumulated interest from previous periods. It is often called 'interest on interest' and leads to exponential growth over time, making it a powerful force in finance for both wealth creation and debt accumulation.",
    "example": "If you invest $1,000 at an annual interest rate of 5% compounded annually, after the first year you'll have $1,050. In the second year, the 5% interest is calculated on $1,050, not just the original $1,000, leading to a balance of $1,102.50. This snowball effect accelerates over decades, significantly increasing the total return compared to simple interest.",
    "tags": [
    "Finance",
    "Economics",
    "Wealth Building",
    "Decision-making",
    "Long-term thinking"
    ]
    }

    .

    🎳 Batch Run

    สำหรับการรันหลายครั้งพร้อมกัน เราจะใช้ .batch() แบบนี้:

    Python
    # Create list of mental models
    mental_model_queries = [
    "First Principles Thinking",
    "Occam's Razor",
    "Confirmation Bias"
    ]
    # Create batch inputs
    batch_inputs = [{"model_query": query} for query in mental_model_queries]
    # Run queries
    results = chain.batch(batch_inputs)
    # Instantiate collector
    query_collector = [result.model_dump() for result in results]

    แสดงผลลัพธ์ใน console:

    Python
    # Instantiate counter
    i = 1
    # Loop through elements in collector
    for result in query_collector:
    # Print result
    print(f"👉 Query {i}:")
    print(json.dumps(result, indent=4))
    print("\\n")
    # Add 1 to counter
    i += 1

    ผลลัพธ์:

    👉 Query 1:
    {
    "model_name": "First Principles Thinking",
    "origin": "Often attributed to Aristotle; popularized in modern business by Elon Musk.",
    "description": "First Principles Thinking involves breaking down complex problems into their most basic, fundamental truths or 'first principles,' rather than reasoning by analogy or conventional wisdom. It matters because it allows for innovative solutions by challenging assumptions and building new knowledge from the ground up.",
    "example": "Instead of accepting the high cost of batteries for electric cars, Elon Musk famously broke down a battery into its constituent raw materials (cobalt, nickel, lithium, etc.) to understand their actual cost, then sought ways to procure and assemble them more efficiently, leading to significant cost reductions and innovation.",
    "tags": [
    "Problem-solving",
    "Innovation",
    "Critical Thinking",
    "Decision-making"
    ]
    }
    👉 Query 2:
    {
    "model_name": "Occam's Razor",
    "origin": "William of Ockham (14th-century philosopher and theologian)",
    "description": "Occam's Razor is a problem-solving principle stating that among competing hypotheses that explain an event or phenomenon equally well, the simplest solution is most likely the correct one. It advocates for parsimony, suggesting that one should not multiply entities beyond necessity, thereby favoring theories with fewer assumptions.",
    "example": "If you hear hoofbeats outside, it is more likely to be horses than zebras, assuming you are in a location where horses are common and zebras are not. The 'horse' explanation is simpler and requires fewer extraordinary assumptions.",
    "tags": [
    "Philosophy",
    "Decision-making",
    "Problem-solving",
    "Critical thinking",
    "Science"
    ]
    }
    👉 Query 3:
    {
    "model_name": "Confirmation Bias",
    "origin": "Psychology; early concepts traced to Francis Bacon's Novum Organum (1620)",
    "description": "Confirmation bias is the tendency to search for, interpret, favor, and recall information in a way that confirms one's pre-existing beliefs or hypotheses. It matters because it can lead to flawed reasoning, poor decision-making, and resistance to new or contradictory evidence, hindering objective analysis.",
    "example": "A person who believes a certain stock will perform well might selectively read news articles and analyst reports that support this positive outlook, while ignoring or downplaying any negative news or warnings about the company.",
    "tags": [
    "cognitive bias",
    "decision-making",
    "psychology",
    "critical thinking"
    ]
    }

    💪 Summary

    เราจะได้เห็นได้ว่า langchain เป็น package ที่ใช้ทำงานกับ LLM ได้อย่างง่าย ๆ ใน 5 ขั้นตอน:

    Set LLM: เลือก model
    Set prompt: กำหนด system และ user prompt
    Set output: กำหนด output structure
    Chain: สร้าง pipeline
    Run: เรียกใช้งาน (single & batch)

    🫵 Your Turn

    สำหรับคนที่สนใจศึกษา langchain เพิ่มเติม:


    📄 References