คู่มือ LangChain ฉบับเข้าใจง่าย: จากพื้นฐานสู่การสร้าง AI Application
1. Introduction to LangChain — LangChain คืออะไร
ลองนึกภาพว่าคุณอยากสร้างแอปพลิเคชันที่ใช้ AI อย่าง GPT หรือ Claude มาช่วยตอบคำถาม ดึงข้อมูลจากเอกสาร หรือทำงานอัตโนมัติหลายขั้นตอน ถ้าเขียนเองตั้งแต่ศูนย์ คุณจะต้องจัดการเรื่องการเรียก API, การจัดรูปแบบ prompt, การเชื่อมต่อกับฐานข้อมูล, การจัดการ memory ของบทสนทนา ฯลฯ ซึ่งซ้ำซ้อนและเสียเวลามาก
LangChain คือ framework แบบ open-source ที่ถูกออกแบบมาเพื่อลดความยุ่งยากตรงนี้ มันเป็นเหมือน "ชุดเครื่องมือกลาง" ที่ช่วยให้นักพัฒนาต่อประกอบส่วนต่าง ๆ ของแอป AI เข้าด้วยกันได้ง่ายขึ้น เช่น
- เชื่อมต่อกับ LLM (Large Language Model) หลายเจ้า ทั้ง OpenAI, Anthropic, Google, หรือโมเดล open-source โดยใช้ interface เดียวกัน
- จัดการ prompt แบบเป็นระบบ ไม่ต้องเขียน string ต่อกันมั่ว ๆ
- เชื่อมต่อกับแหล่งข้อมูลภายนอก เช่น ฐานข้อมูล, ไฟล์เอกสาร, API อื่น ๆ
- สร้าง "chain" หรือลำดับขั้นตอนการทำงานของ AI ที่ซับซ้อนได้ โดยแยกเป็นชิ้นเล็ก ๆ ที่นำกลับมาใช้ซ้ำได้
พูดง่าย ๆ คือถ้า LLM เป็นเหมือน "สมอง" LangChain ก็เป็นเหมือน "ระบบประสาทและเส้นเอ็น" ที่เชื่อมสมองเข้ากับส่วนอื่น ๆ ของร่างกายแอปพลิเคชัน ทำให้มันทำงานร่วมกับโลกภายนอกได้จริง
ในบทความนี้เราจะพาไปรู้จัก LangChain ตั้งแต่การติดตั้ง ไปจนถึงเทคนิคขั้นสูงอย่าง function calling และการดึงข้อมูลแบบมีโครงสร้าง
2. Environment Setup with Python — เตรียมสภาพแวดล้อมให้พร้อม
ก่อนเริ่มเขียนโค้ด แนะนำให้สร้าง virtual environment แยกต่างหาก เพื่อไม่ให้ library ของโปรเจกต์นี้ไปชนกับโปรเจกต์อื่น
# สร้าง virtual environment
python -m venv langchain-env
# เปิดใช้งาน (macOS/Linux)
source langchain-env/bin/activate
# เปิดใช้งาน (Windows)
langchain-env\Scripts\activate
จากนั้นติดตั้ง package หลัก ๆ ที่จะใช้:
pip install langchain langchain-openai langchain-community python-dotenv
langchain— core frameworklangchain-openai— ตัวเชื่อมต่อสำหรับโมเดลของ OpenAI (แยก package ออกมาตั้งแต่ LangChain เวอร์ชันใหม่ ๆ เพื่อให้ dependency เบาลง)langchain-community— connector และ tool จากชุมชนที่ไม่ได้อยู่ใน corepython-dotenv— ใช้โหลด API key จากไฟล์.envแทนการฝัง key ลงในโค้ดตรง ๆ
สร้างไฟล์ .env เก็บ API key ไว้:
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
แล้วโหลดใน Python:
from dotenv import load_dotenv
load_dotenv()
???? เคล็ดลับ: อย่า commit ไฟล์ .env ขึ้น Git เด็ดขาด ให้เพิ่ม .env ลงใน .gitignore เพื่อป้องกัน API key รั่วไหล
3. Chat Models — โมเดลแชทใน LangChain
LangChain มี abstraction ที่เรียกว่า Chat Model ซึ่งครอบการเรียก LLM แบบ conversational ไว้ ทำให้เราสลับใช้โมเดลจากผู้ให้บริการต่าง ๆ ได้โดยไม่ต้องเขียนโค้ดใหม่มาก
from langchain_openai import ChatOpenAI
chat = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
response = chat.invoke("อธิบายว่า LangChain คืออะไรใน 2 ประโยค")
print(response.content)
จุดสำคัญคือ Chat Model จะทำงานกับ "ข้อความแบบมีบทบาท" (role-based messages) ไม่ใช่ string ธรรมดา เช่น
from langchain_core.messages import HumanMessage, SystemMessage
messages = [
SystemMessage(content="คุณคือผู้ช่วยที่ตอบสั้น กระชับ เข้าใจง่าย"),
HumanMessage(content="แนะนำหนังสือเรียน Python สำหรับมือใหม่หน่อย"),
]
response = chat.invoke(messages)
print(response.content)
การแยกบทบาทแบบนี้ (system / human / ai) ช่วยให้เราควบคุมพฤติกรรมของโมเดลได้ชัดเจนขึ้น เช่น กำหนดโทนเสียง ขอบเขตหัวข้อ หรือ persona ของ AI
4. Streaming Chat Models — การสตรีมคำตอบแบบเรียลไทม์
ถ้าเคยใช้ ChatGPT แล้วเห็นคำตอบทยอยขึ้นทีละคำแบบพิมพ์สด นั่นคือการทำ streaming ซึ่งช่วยให้ผู้ใช้รู้สึกว่าระบบตอบสนองเร็ว ไม่ต้องรอจนจบประโยคทั้งหมด
ใน LangChain ทำได้ง่าย ๆ ด้วยเมธอด .stream():
for chunk in chat.stream("เขียนกลอนสั้น ๆ เกี่ยวกับสายฝนในเดือนสิงหาคม"):
print(chunk.content, end="", flush=True)
แต่ละ chunk คือส่วนเล็ก ๆ ของคำตอบที่โมเดลสร้างออกมาทีละก้อน เหมาะมากสำหรับแอปที่มีหน้าจอแชท เพราะทำให้ประสบการณ์ผู้ใช้ลื่นไหลกว่าการรอคำตอบทั้งก้อนทีเดียว
หากทำงานแบบ asynchronous ก็มี .astream() ให้ใช้คู่กับ async/await เช่นกัน ซึ่งเหมาะกับเว็บแอปที่ต้องรองรับผู้ใช้พร้อมกันหลายคน
5. Creating Multiple LLM Generations — สร้างคำตอบหลายแบบพร้อมกัน
บางครั้งเราอยากให้โมเดลสร้างคำตอบหลาย ๆ แบบจาก prompt เดียวกัน เพื่อนำไปเปรียบเทียบหรือให้ผู้ใช้เลือก เช่น การสร้างพาดหัวข่าวหลายแบบ
result = chat.generate([
["เขียนพาดหัวข่าวเกี่ยวกับเทคโนโลยี AI ในมหาวิทยาลัย"]
] * 3)
for generation in result.generations:
print(generation[0].text)
หรือถ้าอยากได้หลายคำตอบจาก prompt เดียวในการเรียกครั้งเดียว บางโมเดลรองรับพารามิเตอร์ n:
chat = ChatOpenAI(model="gpt-4o-mini", n=3, temperature=0.9)
result = chat.generate([["ตั้งชื่อแอปพลิเคชันจองห้องประชุมออนไลน์"]])
for gen in result.generations[0]:
print(gen.text)
การตั้งค่า temperature สูงขึ้นจะทำให้คำตอบแต่ละแบบมีความหลากหลายมากขึ้น เหมาะกับงาน creative แต่ถ้าต้องการความแม่นยำสม่ำเสมอ (เช่น งานสรุปข้อมูล) ควรตั้ง temperature ต่ำ ๆ
6. LangChain Prompt Templates — แม่แบบ Prompt ที่นำกลับมาใช้ซ้ำได้
การเขียน prompt แบบ hard-code ข้อความลงในโค้ดตรง ๆ จะจัดการยากเมื่อโปรเจกต์โตขึ้น LangChain จึงมี PromptTemplate ให้เราสร้างแม่แบบที่มีตัวแปรใส่เข้าไปได้
from langchain_core.prompts import PromptTemplate
template = PromptTemplate.from_template(
"แปลประโยคต่อไปนี้เป็นภาษา{target_language}: {sentence}"
)
prompt = template.format(target_language="อังกฤษ", sentence="วันนี้อากาศดีมาก")
print(prompt)
ข้อดีของการใช้ template คือ:
- แยกโครงสร้าง prompt ออกจาก logic ของโปรแกรม ทำให้แก้ไขปรับแต่งได้ง่าย โดยไม่ต้องไปยุ่งกับโค้ดส่วนอื่น
- ป้องกันข้อผิดพลาด เพราะ LangChain จะตรวจสอบว่าตัวแปรที่ระบุครบถ้วนหรือไม่
- นำกลับมาใช้ซ้ำได้ เช่น เก็บ template ไว้เป็นไฟล์แยก แล้วโหลดมาใช้ในหลายจุดของแอป
7. LangChain Expression Language (LCEL) — เชื่อมต่อ Component ด้วย Pipe
LCEL เป็นวิธีการเขียนโค้ด LangChain แบบใหม่ที่ทำให้การต่อ component (เช่น prompt → model → output parser) เข้าด้วยกันทำได้ด้วยเครื่องหมาย | (pipe) คล้ายกับการต่อคำสั่งใน Unix
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template("สรุปข้อความนี้ใน 1 ประโยค: {text}")
model = ChatOpenAI(model="gpt-4o-mini")
parser = StrOutputParser()
chain = prompt | model | parser
result = chain.invoke({"text": "LangChain เป็น framework สำหรับสร้างแอปพลิเคชันที่ขับเคลื่อนด้วย LLM..."})
print(result)
จากตัวอย่างนี้ ข้อมูลจะไหลผ่านแต่ละขั้นตอนตามลำดับ: prompt แปลง input เป็นข้อความ → model ประมวลผลแล้วคืนคำตอบ → parser แปลงผลลัพธ์ให้อยู่ในรูปแบบที่ใช้งานง่าย
ข้อดีของ LCEL คือ chain ที่สร้างขึ้นมาจะรองรับ .invoke(), .stream(), และ .batch() โดยอัตโนมัติ โดยไม่ต้องเขียนโค้ดเพิ่มเลย ทำให้ chain เดียวกันนำไปใช้ได้ทั้งแบบเรียกครั้งเดียว แบบสตรีม หรือแบบประมวลผลเป็นชุด (batch)
8. Using PromptTemplate with Chat Models — ผสาน Prompt Template เข้ากับ Chat Model
เมื่อทำงานกับ Chat Model เราจะใช้ ChatPromptTemplate แทน PromptTemplate ธรรมดา เพราะต้องระบุบทบาท (role) ของแต่ละข้อความด้วย
from langchain_core.prompts import ChatPromptTemplate
chat_prompt = ChatPromptTemplate.from_messages([
("system", "คุณคือติวเตอร์สอนคณิตศาสตร์ระดับมัธยม อธิบายให้เข้าใจง่าย"),
("human", "ช่วยอธิบายเรื่อง {topic} หน่อย"),
])
messages = chat_prompt.format_messages(topic="สมการกำลังสอง")
chat = ChatOpenAI(model="gpt-4o-mini")
response = chat.invoke(messages)
print(response.content)
การกำหนด system message แยกจาก human message ช่วยให้เรา "ล็อก" พฤติกรรมของ AI ไว้ล่วงหน้าได้ (เช่น บทบาท โทนเสียง ข้อจำกัด) โดยที่ผู้ใช้ปลายทางกรอกแค่ตัวแปรส่วน human message เท่านั้น ซึ่งเหมาะมากกับการสร้างแชทบอทเฉพาะทาง เช่น บอทตอบคำถามนักศึกษา หรือบอทให้ข้อมูลบริการ IT ภายในองค์กร
9. Output Parsers — แปลงผลลัพธ์ให้อยู่ในรูปแบบที่ใช้งานได้
โดยธรรมชาติ LLM จะคืนค่าเป็นข้อความ (string) เสมอ แต่บ่อยครั้งเราต้องการผลลัพธ์ในรูปแบบที่มีโครงสร้าง เช่น list, JSON หรือ object ที่กำหนดเอง Output Parser จึงเข้ามาช่วยตรงนี้
StrOutputParser — parser พื้นฐานที่สุด
from langchain_core.output_parsers import StrOutputParser
parser = StrOutputParser()
CommaSeparatedListOutputParser — แปลงเป็น list
from langchain_core.output_parsers import CommaSeparatedListOutputParser
parser = CommaSeparatedListOutputParser()
prompt = ChatPromptTemplate.from_template(
"บอกชื่อผลไม้ไทย 5 ชนิด {format_instructions}"
)
chain = prompt | model | parser
result = chain.invoke({"format_instructions": parser.get_format_instructions()})
print(result) # ['มะม่วง', 'ทุเรียน', 'มังคุด', ...]
PydanticOutputParser — แปลงเป็น object ที่มี schema ชัดเจน
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
class StudentInfo(BaseModel):
name: str = Field(description="ชื่อนักศึกษา")
major: str = Field(description="สาขาที่เรียน")
year: int = Field(description="ชั้นปี")
parser = PydanticOutputParser(pydantic_object=StudentInfo)
การใช้ output parser ช่วยลดปัญหา "โมเดลตอบมาไม่ตรงรูปแบบที่โปรแกรมคาดหวัง" เพราะ parser จะแนบคำแนะนำรูปแบบ (format instructions) ไปกับ prompt โดยอัตโนมัติ และช่วยตรวจสอบ/แปลงผลลัพธ์กลับมาให้ตรง schema
10. LangChain Evals — การประเมินผลลัพธ์ของ LLM
เมื่อสร้างแอป AI แล้ว คำถามสำคัญคือ "แล้วเรารู้ได้ยังไงว่าคำตอบของโมเดลดีจริง?" LangChain มีเครื่องมือด้าน evaluation ที่ช่วยตอบคำถามนี้อย่างเป็นระบบ แทนที่จะเดาสุ่มหรือดูด้วยตาเปล่าอย่างเดียว
รูปแบบการประเมินที่ใช้บ่อย ได้แก่:
- Criteria-based evaluation — ประเมินว่าคำตอบตรงตามเกณฑ์ที่กำหนดหรือไม่ เช่น ความกระชับ ความสุภาพ ความถูกต้องตามข้อเท็จจริง
- Comparison evaluation — เปรียบเทียบคำตอบจากสองโมเดล หรือสอง prompt ว่าอันไหนดีกว่ากัน
- String/exact match evaluation — ตรวจสอบว่าคำตอบตรงกับคำตอบที่คาดหวังแบบตรงตัวหรือไม่ เหมาะกับงานที่มีคำตอบชัดเจน
from langchain.evaluation import load_evaluator
evaluator = load_evaluator("criteria", criteria="conciseness")
result = evaluator.evaluate_strings(
prediction="LangChain เป็นเครื่องมือที่ช่วยให้นักพัฒนาสร้างแอปพลิเคชัน AI ได้ง่ายและรวดเร็วขึ้นมาก โดยมีฟีเจอร์เยอะแยะมากมาย",
input="LangChain คืออะไร"
)
print(result)
การมีระบบ eval ที่ดีสำคัญมากในโปรเจกต์จริง เพราะช่วยให้ทีมพัฒนาเปรียบเทียบเวอร์ชัน prompt หรือโมเดลต่าง ๆ ได้อย่างมีหลักฐาน แทนที่จะอาศัยความรู้สึก
11. OpenAI Function Calling — ให้โมเดลเรียกใช้ฟังก์ชันได้
Function Calling คือความสามารถที่ให้โมเดล LLM "ตัดสินใจ" ว่าควรเรียกใช้ฟังก์ชันไหน พร้อมพารามิเตอร์อะไร โดยดูจากคำถามของผู้ใช้ แทนที่จะตอบเป็นข้อความอย่างเดียว
ตัวอย่างเช่น ถ้าผู้ใช้ถามว่า "วันนี้อากาศที่นครศรีธรรมราชเป็นยังไง" โมเดลจะไม่ตอบเดา ๆ แต่จะ "ขอเรียก" ฟังก์ชัน get_weather(location="นครศรีธรรมราช") แล้วเราค่อยเอาผลลัพธ์จริงจากฟังก์ชันไปให้โมเดลสรุปคำตอบอีกที
from langchain_core.tools import tool
@tool
def get_weather(location: str) -> str:
"""ดึงข้อมูลสภาพอากาศปัจจุบันของสถานที่ที่ระบุ"""
# ในการใช้งานจริงจะไปเรียก weather API
return f"อากาศที่ {location} วันนี้ แจ่มใส อุณหภูมิ 32°C"
model_with_tools = chat.bind_tools([get_weather])
response = model_with_tools.invoke("วันนี้อากาศที่นครศรีธรรมราชเป็นยังไง")
print(response.tool_calls)
โมเดลจะคืนค่า tool_calls ที่บอกว่าต้องเรียกฟังก์ชันไหน พร้อม argument ที่ต้องใช้ ซึ่งเราต้องเขียนโค้ดไปเรียกฟังก์ชันจริงเอง แล้วส่งผลลัพธ์กลับไปให้โมเดลสรุปเป็นคำตอบสุดท้ายอีกรอบ
12. Parallel Function Calling — เรียกหลายฟังก์ชันพร้อมกัน
ในบางกรณี คำถามเดียวอาจต้องใช้ข้อมูลจากหลายฟังก์ชันพร้อมกัน เช่น "เปรียบเทียบอากาศที่กรุงเทพกับเชียงใหม่" ซึ่งต้องเรียก get_weather สองครั้งด้วยคนละพารามิเตอร์
โมเดลรุ่นใหม่ ๆ รองรับการคืนค่า tool_calls เป็น list มากกว่าหนึ่งรายการในการตอบครั้งเดียว:
response = model_with_tools.invoke(
"เปรียบเทียบอากาศที่กรุงเทพกับเชียงใหม่หน่อย"
)
for call in response.tool_calls:
print(call["name"], call["args"])
ผลลัพธ์ที่ได้อาจมี tool call สองรายการ เช่น get_weather(location="กรุงเทพ") และ get_weather(location="เชียงใหม่") เราสามารถเขียนโค้ด loop เพื่อเรียกทั้งสองฟังก์ชัน (หรือเรียกแบบขนานด้วย asyncio เพื่อความเร็ว) แล้วรวบรวมผลลัพธ์ส่งกลับไปให้โมเดลสรุปเป็นคำตอบเดียว
ข้อดีของ parallel function calling คือลดจำนวนรอบการสนทนา (round trip) กับโมเดล ทำให้แอปตอบสนองได้เร็วขึ้นเมื่อคำถามซับซ้อนต้องใช้ข้อมูลจากหลายแหล่ง
13. Function Calling in LangChain — ผูก Tool เข้ากับ Chain แบบเต็มรูปแบบ
LangChain ทำให้การสร้างวงจร "โมเดลเรียก tool → รันจริง → ส่งผลกลับ → โมเดลสรุป" เป็นระบบมากขึ้น โดยเฉพาะเมื่อใช้ร่วมกับ Agent
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "คุณเป็นผู้ช่วยที่ตอบคำถามโดยใช้เครื่องมือที่มีให้เมื่อจำเป็น"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(chat, [get_weather], prompt)
executor = AgentExecutor(agent=agent, tools=[get_weather], verbose=True)
result = executor.invoke({"input": "วันนี้อากาศที่ภูเก็ตเป็นยังไงบ้าง"})
print(result["output"])
AgentExecutor จะจัดการวงจรทั้งหมดให้อัตโนมัติ: ส่งคำถามให้โมเดล → ถ้าโมเดลอยากเรียก tool ก็รันให้ → ส่งผลลัพธ์กลับไปให้โมเดล → วนซ้ำจนกว่าโมเดลจะได้คำตอบสุดท้ายที่พร้อมส่งให้ผู้ใช้ ทำให้เราไม่ต้องเขียน loop จัดการเองทุกครั้ง
14. Extracting Data with LangChain — ดึงข้อมูลแบบมีโครงสร้างจากข้อความอิสระ
หนึ่งในการใช้งานที่ได้รับความนิยมมากคือการให้ LLM แปลงข้อความอิสระ (unstructured text) ให้เป็นข้อมูลมีโครงสร้าง (structured data) เช่น ดึงชื่อ วันที่ จำนวนเงิน จากอีเมลหรือใบเสร็จ
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
class ContactInfo(BaseModel):
name: str = Field(description="ชื่อบุคคล")
email: str = Field(description="อีเมล")
phone: str | None = Field(default=None, description="เบอร์โทรศัพท์ ถ้ามี")
structured_model = chat.with_structured_output(ContactInfo)
text = "สวัสดีครับ ผมชื่ออรรถกร ติดต่อได้ที่ atakorn@example.com หรือโทร 081-234-5678"
result = structured_model.invoke(f"ดึงข้อมูลติดต่อจากข้อความนี้: {text}")
print(result)
# name='อรรถกร' email='atakorn@example.com' phone='081-234-5678'
เมธอด .with_structured_output() เป็นวิธีที่สะดวกที่สุดในปัจจุบัน เพราะรวมขั้นตอน function calling + output parsing ไว้ในคำสั่งเดียว ทำให้ได้ผลลัพธ์เป็น Python object ที่พร้อมใช้งานทันที เหมาะมากกับงานอย่างการดึงข้อมูลจากแบบฟอร์ม อีเมลของผู้ใช้ หรือเอกสารราชการที่มีรูปแบบไม่ตายตัว
Summary — สรุปส่งท้าย
จากที่เล่ามาทั้งหมด จะเห็นว่า LangChain ไม่ได้เป็นแค่ "ตัวเรียก API ของ LLM" แต่เป็น framework ที่ช่วยจัดระเบียบทุกส่วนของการสร้างแอปพลิเคชัน AI ตั้งแต่ต้นจนจบ:
- เริ่มจาก Chat Models ที่ให้เราคุยกับ LLM ผ่าน interface เดียวกัน ไม่ว่าจะสลับไปใช้โมเดลค่ายไหน
- Streaming และ multiple generations ช่วยให้ประสบการณ์ผู้ใช้ดีขึ้นและมีความยืดหยุ่นในการสร้างคำตอบ
- Prompt Templates และ LCEL ช่วยให้เราจัดการ prompt และเชื่อมต่อ component ต่าง ๆ เข้าด้วยกันได้อย่างเป็นระบบ อ่านง่าย ดูแลรักษาง่าย
- Output Parsers แปลงคำตอบข้อความอิสระให้กลายเป็นข้อมูลที่โปรแกรมใช้งานต่อได้จริง
- LangChain Evals ช่วยวัดคุณภาพคำตอบอย่างมีหลักฐาน ไม่ใช่แค่ความรู้สึก
- Function Calling ทั้งแบบเดี่ยวและแบบขนาน เปิดทางให้ AI เชื่อมต่อกับโลกจริง เรียกใช้ API หรือฟังก์ชันของเราเองได้
- และสุดท้าย Data Extraction ที่นำทุกอย่างมารวมกัน เพื่อดึงข้อมูลมีโครงสร้างจากข้อความยุ่งเหยิงในชีวิตจริง
โดยรวมแล้ว LangChain เหมาะมากสำหรับใครที่อยากสร้างแอป AI แบบจริงจัง ไม่ว่าจะเป็นแชทบอทตอบคำถามภายในองค์กร ระบบดึงข้อมูลจากเอกสาร หรือ agent ที่ทำงานอัตโนมัติหลายขั้นตอน การเข้าใจ building block เหล่านี้จะเป็นรากฐานสำคัญก่อนไปต่อยอดสู่เรื่องที่ซับซ้อนขึ้น เช่น RAG (Retrieval-Augmented Generation) หรือระบบ multi-agent ในอนาคต