จาก 0 ถึง AI Agent — บันทึกการเรียนรู้ผ่านโปรเจกต์จริง
ตอนที่ 5: Pydantic กับ Structured Output
ตอนนี้เราเกือบครบแล้ว เหลือแค่ส่วนสุดท้าย — Pydantic และ entry point ของโปรแกรม
ฟังดูน่ากลัว แต่จริงๆ ไม่ยากเลย มาดูกัน
ปัญหาของการรับข้อมูลจาก AI
สมมติ Claude ส่งคำตอบกลับมา แต่ดันส่งผิด เช่น:
confidence ควรเป็น "high", "medium", หรือ "low" แต่ Claude ส่ง "very high" มาfound_in_docs ควรเป็น true/false แต่ส่งมาเป็น "yes" แทนถ้าไม่มีอะไรตรวจสอบ โปรแกรมอาจทำงานผิดพลาดโดยที่เราไม่รู้
Pydantic: ผู้ตรวจสอบข้อมูล
Pydantic คือ library ที่ช่วยตรวจสอบว่าข้อมูลถูกต้องตามที่เรากำหนดหรือเปล่า — ถ้าผิดจะ error ทันที แทนที่จะเงียบแล้วทำงานผิดพลาด
ใน ask.py เรานิยาม model ไว้ตรงนี้:
from pydantic import BaseModel
from typing import List
class DocAnswer(BaseModel):
answer: str
source_files: List[str]
confidence: str # "high" | "medium" | "low"
found_in_docs: boolแค่นี้เลย — บอกว่า DocAnswer ต้องมี 4 field และแต่ละ field เป็น type อะไร
ตอนที่ Claude เรียก return_answer เราก็แปลงข้อมูลมันเป็น DocAnswer ด้วยบรรทัดนี้:
return DocAnswer(**block.input)**block.input คือการแกะ dictionary แล้วส่งเป็น argument เข้า DocAnswer — ถ้า field ไหนผิด type หรือขาดหายไป Pydantic จะ raise error ทันที
Entry Point: โค้ดที่รันเมื่อเปิดโปรแกรม
ส่วนสุดท้ายคือ if __name__ == "__main__" — โค้ดในนี้จะรันเฉพาะตอนที่เราสั่ง python ask.py โดยตรง:
if __name__ == "__main__":
print(f"Docs folder: {DOCS_FOLDER.resolve()}")
print("Type 'quit' to exit\n")
while True:
question = input("You: ").strip()
if question.lower() in ("quit", "exit"):
break
if not question:
continue
print("\nThinking...")
result = ask(question)
if isinstance(result, DocAnswer):
print(f"\nClaude: {result.answer}")
print(f"Sources: {result.source_files}")
print(f"Confidence: {result.confidence}")
print(f"In docs: {result.found_in_docs}\n")
else:
print(f"\nClaude: {result}\n")ทำงานอย่างนี้:
1. วน loop รอรับคำถามจากผู้ใช้
2. ถ้าพิมพ์ quit หรือ exit ก็หยุด
3. ส่งคำถามไปที่ ask() แล้วรอผล
4. ถ้าผลเป็น DocAnswer แสดงแบบ structured, ถ้าเป็น text ธรรมดาก็แสดงตรงๆ
isinstance() คืออะไร?
if isinstance(result, DocAnswer):isinstance() ตรวจสอบว่า result เป็น object ประเภท DocAnswer ไหม — ถ้าใช่แสดงแบบมีหัวข้อ ถ้าไม่ใช่ก็แสดงเป็น text ธรรมดา
ทำไมต้องเช็ค? เพราะในบางกรณีที่ agent วน loop แล้วออกมาด้วย end_turn (แทนที่จะเรียก return_answer) ผลที่ได้จะเป็น string ธรรมดา ไม่ใช่ DocAnswer
ภาพรวมโค้ดทั้งหมดใน ask.py
imports + load_dotenv
↓
DocAnswer (Pydantic model)
↓
client + DOCS_FOLDER + SYSTEM_PROMPT
↓
tools = [list_files, read_file, return_answer]
↓
run_tool() — Python รัน tool จริง
↓
ask() — Agent Loop
↓
if __name__ == "__main__" — CLIแค่นี้เอง ทั้งโปรเจกต์อยู่ในไฟล์เดียว ไม่ถึง 100 บรรทัด
สรุปตอนที่ 5
Pydantic ช่วยให้เรามั่นใจว่าข้อมูลที่ได้จาก Claude ถูกต้องตาม format ที่กำหนด และ entry point ก็เป็นแค่ while loop ธรรมดาที่รอรับคำถาม
ตอนหน้าเป็นตอนสุดท้าย — เราจะรันโปรแกรมจริง และสรุปสิ่งที่ได้เรียนรู้จากโปรเจกต์นี้
📚 Series: จาก 0 ถึง AI Agent — บันทึกการเรียนรู้ผ่านโปรเจกต์จริง
- ตอนที่ 1: เริ่มต้นกับ Anthropic API
- ตอนที่ 2: Tool Calling คืออะไร
- ตอนที่ 3: นิยาม Tools ให้ Claude ใช้
- ตอนที่ 4: Agent Loop — วนจนกว่าจะได้คำตอบ
- ตอนที่ 5: Pydantic กับ Structured Output ← คุณอยู่ที่นี่
- ตอนที่ 6: รันจริง และสิ่งที่ได้เรียนรู้
Source code ทั้งหมดอยู่ที่ github.com/nipitpongpan/ask-my-docs
Leave a Reply