Contract Testing สำหรับ AI Service คืออะไร?

สวัสดีครับ ผมเชื่อว่าหลายคนที่กำลังใช้งาน AI Service คงเคยเจอปัญหาแบบนี้: ส่งข้อความไปหา AI แต่คำตอบที่ได้กลับมาไม่เหมือนเดิม หรือบางทีโค้ดที่เคยทำงานได้ก็อยู่ดีๆ ก็พังขึ้นมา ปัญหาเหล่านี้เกิดจากการที่ AI Service Provider (เช่น OpenAI, Anthropic, หรือ HolySheep AI) มีการอัปเดตโมเดลหรือ API บ่อยครั้ง

Contract Testing ก็เหมือนการทำสัญญาว่า: "ถ้าฉันส่งข้อมูลแบบนี้ไป ฉันจะได้ผลลัพธ์แบบนี้กลับมา" แล้วเราจะทดสอบสัญญานั้นทุกครั้งที่มีการเปลี่ยนแปลง

ทำไมต้องทำ Contract Testing?

เริ่มต้นใช้งาน Contract Testing กับ HolySheep AI

ขั้นตอนที่ 1: สมัครสมาชิกและรับ API Key

ก่อนอื่นให้ไปสมัครที่ สมัครที่นี่ เพื่อรับ API Key ฟรี จากนั้นเก็บ API Key ไว้ในที่ปลอดภัย

ขั้นตอนที่ 2: ติดตั้งโปรแกรมที่จำเป็น

ในการทำ Contract Testing เราจะใช้ Python เป็นภาษาหลัก เพราะอ่านง่ายและเข้าใจได้ไม่ยาก ติดตั้ง Python จาก python.org ก่อน แล้วติดตั้ง library ที่จำเป็น:

pip install requests pytest pytest-httpscheck

ขั้นตอนที่ 3: เขียน Contract Test แรกของเรา

สร้างไฟล์ชื่อ contract_test.py แล้วเขียนโค้ดดังนี้:

import requests
import pytest

ตั้งค่าการเชื่อมต่อกับ HolySheep AI

BASE_URL = "https://api.holysheep.ai/v1" API_KEY = "YOUR_HOLYSHEEP_API_KEY"

ส่วนหัวสำหรับการยืนยันตัวตน

HEADERS = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } def test_ai_response_format(): """ ทดสอบว่าการตอบกลับจาก AI มีรูปแบบที่ถูกต้อง นี่คือ Contract Test ของเรา - ถ้ารูปแบบเปลี่ยน เราจะรู้ทันที """ # ข้อมูลที่จะส่งไปถาม AI payload = { "model": "gpt-4.1", "messages": [ {"role": "user", "content": "ทดสอบการตอบกลับ ตอบว่า 'OK' เท่านั้น"} ], "max_tokens": 50 } # ส่งคำถามไปยัง HolySheep AI response = requests.post( f"{BASE_URL}/chat/completions", headers=HEADERS, json=payload ) # ตรวจสอบว่าได้รับคำตอบสำเร็จ assert response.status_code == 200, f"ได้รับข้อผิดพลาด: {response.status_code}" # แปลงคำตอบเป็นข้อมูลที่อ่านได้ data = response.json() # ตรวจสอบ Contract: คำตอบต้องมีโครงสร้างที่ถูกต้อง assert "choices" in data, "ไม่พบ choices ในคำตอบ" assert len(data["choices"]) > 0, "ไม่มีคำตอบจาก AI" assert "message" in data["choices"][0], "ไม่พบ message ในคำตอบ" assert "content" in data["choices"][0]["message"], "ไม่พบ content ใน message" print(f"✓ Contract Test ผ่าน! รูปแบบคำตอบถูกต้อง") print(f" คำตอบจาก AI: {data['choices'][0]['message']['content']}") if __name__ == "__main__": test_ai_response_format()

ขั้นตอนที่ 4: รัน Contract Test

เปิด Terminal หรือ Command Prompt แล้วพิมพ์:

python contract_test.py

ถ้าทุกอย่างถูกต้อง คุณจะเห็นข้อความว่า "✓ Contract Test ผ่าน!" พร้อมคำตอบจาก AI

สร้าง Contract Test ที่ซับซ้อนขึ้น

ทดสอบหลายรูปแบบพร้อมกัน

ในโปรเจกต์จริง เราต้องการทดสอบหลายกรณี สร้างไฟล์ test_contracts.py:

import requests
import pytest
import time

BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

class ContractTestSuite:
    """ชุดการทดสอบ Contract สำหรับ AI Service"""
    
    def __init__(self):
        self.results = []
    
    def test_basic_completion(self):
        """ทดสอบ: การตอบคำถามพื้นฐาน"""
        payload = {
            "model": "gpt-4.1",
            "messages": [{"role": "user", "content": "2+2 เท่ากับเท่าไร?"}],
            "max_tokens": 20
        }
        
        response = requests.post(f"{BASE_URL}/chat/completions", headers=HEADERS, json=payload)
        data = response.json()
        
        # Contract: ต้องได้คำตอบที่มีเลข 4
        answer = data["choices"][0]["message"]["content"].lower()
        assert "4" in answer, f"คาดหวังคำตอบที่มี 4 แต่ได้: {answer}"
        
        self.results.append({"test": "basic_completion", "status": "PASS"})
        print(f"✓ ทดสอบพื้นฐาน: ผ่าน")
    
    def test_response_time(self):
        """ทดสอบ: เวลาตอบสนองต้องเร็ว"""
        start = time.time()
        
        payload = {
            "model": "gpt-4.1",
            "messages": [{"role": "user", "content": "ทักทายสั้นๆ"}],
            "max_tokens": 30
        }
        
        response = requests.post(f"{BASE_URL}/chat/completions", headers=HEADERS, json=payload)
        elapsed = (time.time() - start) * 1000  # แปลงเป็นมิลลิวินาที
        
        assert response.status_code == 200
        assert elapsed < 5000, f"ใช้เวลานานเกินไป: {elapsed:.0f}ms"
        
        self.results.append({"test": "response_time", "status": "PASS", "latency": elapsed})
        print(f"✓ ทดสอบความเร็ว: {elapsed:.0f}ms - ผ่าน")
    
    def test_json_format(self):
        """ทดสอบ: รูปแบบ JSON ที่ถูกต้อง"""
        payload = {
            "model": "gpt-4.1",
            "messages": [{"role": "user", "content": "บอกวันที่และเวลาปัจจุบันในรูปแบบ JSON"}],
            "max_tokens": 100
        }
        
        response = requests.post(f"{BASE_URL}/chat/completions", headers=HEADERS, json=payload)
        data = response.json()
        
        # Contract: ต้องมีโครงสร้างครบถ้วน
        required_fields = ["id", "object", "created", "model", "choices", "usage"]
        for field in required_fields:
            assert field in data, f"ไม่พบ {field} ในคำตอบ"
        
        self.results.append({"test": "json_format", "status": "PASS"})
        print(f"✓ ทดสอบรูปแบบ JSON: ผ่าน")
    
    def run_all_tests(self):
        """รันการทดสอบทั้งหมด"""
        print("=" * 50)
        print("เริ่ม Contract Testing Suite")
        print("=" * 50)
        
        try:
            self.test_basic_completion()
        except Exception as e:
            self.results.append({"test": "basic_completion", "status": "FAIL", "error": str(e)})
            print(f"✗ ทดสอบพื้นฐาน: ล้มเหลว - {e}")
        
        try:
            self.test_response_time()
        except Exception as e:
            self.results.append({"test": "response_time", "status": "FAIL", "error": str(e)})
            print(f"✗ ทดสอบความเร็ว: ล้มเหลว - {e}")
        
        try:
            self.test_json_format()
        except Exception as e:
            self.results.append({"test": "json_format", "status": "FAIL", "error": str(e)})
            print(f"✗ ทดสอบรูปแบบ JSON: ล้มเหลว - {e}")
        
        print("=" * 50)
        print("ผลการทดสอบทั้งหมด:")
        passed = sum(1 for r in self.results if r["status"] == "PASS")
        print(f"ผ่าน: {passed}/{len(self.results)}")
        print("=" * 50)

รันการทดสอบ

if __name__ == "__main__": suite = ContractTestSuite() suite.run_all_tests()

ใช้ pytest สำหรับการทดสอบอัตโนมัติ

pytest เป็นเครื่องมือที่ช่วยรันการทดสอบหลายตัวพร้อมกันและสร้างรายงาน สร้างไฟล์ test_ai_contract.py:

import pytest
import requests

BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

@pytest.fixture
def ai_client():
    """ Fixture สำหรับสร้าง client สำหรับทดสอบ """
    return {"base_url": BASE_URL, "headers": HEADERS}

def test_contract_response_has_required_fields(ai_client):
    """
    Contract Test: ตรวจสอบว่าคำตอบมีฟิลด์ที่จำเป็นทั้งหมด
    ถ้า AI Provider เปลี่ยนรูปแบบคำตอบ Test นี้จะล้มเหลวทันที
    """
    payload = {
        "model": "gpt-4.1",
        "messages": [{"role": "user", "content": "สวัสดี"}],
        "max_tokens": 10
    }
    
    response = requests.post(
        f"{ai_client['base_url']}/chat/completions",
        headers=ai_client["headers"],
        json=payload
    )
    
    data = response.json()
    
    # Contract ที่ต้องมี: คำตอบต้องมีโครงสร้างนี้
    assert "id" in data, "Contract Violation: ไม่มี id"
    assert "object" in data, "Contract Violation: ไม่มี object"
    assert "choices" in data, "Contract Violation: ไม่มี choices"
    assert "usage" in data, "Contract Violation: ไม่มี usage"

def test_contract_message_content_exists(ai_client):
    """Contract Test: ตรวจสอบว่ามี content ใน message"""
    payload = {
        "model": "gpt-4.1",
        "messages": [{"role": "user", "content": "บอกคำว่า test"}],
        "max_tokens": 20
    }
    
    response = requests.post(
        f"{ai_client['base_url']}/chat/completions",
        headers=ai_client["headers"],
        json=payload
    )
    
    data = response.json()
    message = data["choices"][0]["message"]
    
    assert "content" in message, "Contract Violation: ไม่มี content"
    assert len(message["content"]) > 0, "Contract Violation: content ว่างเปล่า"

def test_contract_usage_information(ai_client):
    """Contract Test: ตรวจสอบว่ามีข้อมูลการใช้งาน"""
    payload = {
        "model": "gpt-4.1",
        "messages": [{"role": "user", "content": "ทดสอบ"}],
        "max_tokens": 10
    }
    
    response = requests.post(
        f"{ai_client['base_url']}/chat/completions",
        headers=ai_client["headers"],
        json=payload
    )
    
    data = response.json()
    usage = data["usage"]
    
    # Contract: ต้องมีข้อมูล token ที่ใช้
    assert "prompt_tokens" in usage, "Contract Violation: ไม่มี prompt_tokens"
    assert "completion_tokens" in usage, "Contract Violation: ไม่มี completion_tokens"
    assert "total_tokens" in usage, "Contract Violation: ไม่มี total_tokens"

def test_contract_status_code_success(ai_client):
    """Contract Test: ตรวจสอบว่าได้รับสถานะสำเร็จ"""
    payload = {
        "model": "gpt-4.1",
        "messages": [{"role": "user", "content": "ทดสอบ"}],
        "max_tokens": 10
    }
    
    response = requests.post(
        f"{ai_client['base_url']}/chat/completions",
        headers=ai_client["headers"],
        json=payload
    )
    
    assert response.status_code == 200, f"Contract Violation: ได้ status {response.status_code}"

if __name__ == "__main__":
    pytest.main([__file__, "-v"])

รันการทดสอบด้วยคำสั่ง:

pytest test_ai_contract.py -v

ตั้งเวลาทดสอบอัตโนมัติด้วย GitHub Actions

เมื่อเรามี Contract Test แล้ว ควรตั้งให้รันอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลง สร้างไฟล์ .github/workflows/contract-test.yml:

name: AI Contract Testing

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 */6 * * *'  # รันทุก 6 ชั่วโมง

jobs:
  contract-test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.10'
    
    - name: Install dependencies
      run: |
        pip install requests pytest
    
    - name: Run Contract Tests
      env:
        HOLYSHEEP_API_KEY: ${{ secrets.HOLYSHEEP_API_KEY }}
      run: |
        pytest test_ai_contract.py -v --tb=short
    
    - name: Report Results
      if: always()
      run: |
        echo "Contract Test สิ้นสุด ดูผลลัพธ์ข้างบน"

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

1. ได้รับข้อผิดพลาด 401 Unauthorized

# ❌ วิธีที่ผิด - API Key ไม่ถูกต้องหรือหมดอายุ
response = requests.post(url, headers={"Authorization": "Bearer wrong_key"})

✅ วิธีที่ถูก - ตรวจสอบ API Key

API_KEY = "YOUR_HOLYSHEEP_API_KEY" # ใส่ Key ที่ถูกต้องจาก HolySheep

หรือใช้ Environment Variable เพื่อความปลอดภัย

import os API_KEY = os.environ.get("HOLYSHEEP_API_KEY") if not API_KEY: raise ValueError("กรุณาตั้งค่า HOLYSHEEP_API_KEY") headers = {"Authorization": f"Bearer {API_KEY}"} response = requests.post(url, headers=headers)

2. ได้รับข้อผิดพลาด 429 Rate Limit Exceeded

# ❌ วิธีที่ผิด - ส่งคำขอมากเกินไป
for i in range(100):
    send_request()

✅ วิธีที่ถูก - เพิ่ม delay ระหว่างคำขอ และใช้ retry

import time from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.retry import Retry def create_session_with_retry(): session = requests.Session() retry = Retry( total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504] ) adapter = HTTPAdapter(max_retries=retry) session.mount('https://', adapter) return session

ใช้งาน

session = create_session_with_retry() for i in range(10): response = session.post(url, headers=headers, json=payload) time.sleep(2) # รอ 2 วินาทีระหว่างคำขอ print(f"คำขอที่ {i+1}/10: {response.status_code}")

3. ข้อมูลในคำตอบเปลี่ยนรูปแบบ ทำให้ Test ล้มเหลว

# ❌ วิธีที่ผิด - Hardcode คาดหวังค่าเฉพาะเจาะจง
assert data["choices"][0]["message"]["content"] == "สวัสดี"

✅ วิธีที่ถูก - ตรวจสอบเฉพาะ Contract ไม่ใช่ค่าที่แน่นอน

def validate_contract(data): """ตรวจสอบเฉพาะ Contract ที่สำคัญ""" errors = [] # ตรวจสอบโครงสร้าง if "choices" not in data: errors.append("ไม่พบ choices") # ตรวจสอบว่ามีอย่างน้อย 1 คำตอบ if len(data.get("choices", [])) == 0: errors.append("ไม่มีคำตอบ") # ตรวจสอบว่ามี message และ content if data.get("choices"): choice = data["choices"][0] if "message" not in choice: errors.append("ไม่พบ message") elif "content" not in choice["message"]: errors.append("ไม่พบ content") if errors: raise AssertionError(f"Contract Violation: {', '.join(errors)}") return True

ใช้งาน

data = response.json() validate_contract(data) # จะล้มเหลวถ้า Contract เปลี่ยน

4. Timeout เกิดขณะรอคำตอบจาก AI

# ❌ วิธีที่ผิด - ไม่มี timeout
response = requests.post(url, headers=headers, json=payload)

✅ วิธีที่ถูก - กำหนด timeout ที่เหมาะสม

response = requests.post( url, headers=headers, json=payload, timeout=(10, 60) # 10 วินาทีสำหรับเชื่อมต่อ, 60 วินาทีสำหรับรอคำตอบ )

หรือใช้ try-except เพื่อจัดการ Timeout

try: response = requests.post(url, headers=headers, json=payload, timeout=30) print("ได้รับคำตอบสำเร็จ") except requests.Timeout: print("คำขอใช้เวลานานเกินไป ลองใหม่อีกครั้ง") except requests.RequestException as e: print(f"เกิดข้อผิดพลาด: {e}")

สรุป

การทำ Contract Testing สำหรับ AI Service เป็นสิ่งสำคัญมากในการพัฒนาซอฟต์แวร์ที่ใช้ AI เพราะช่วยให้เรา:

เริ่มต้นทำ Contract Testing วันนี้ จะช่วยให้แอปพลิเคชันของคุณเสถียรและน่าเชื่อถือมากขึ้น!

👉 สมัคร HolySheep AI — รับเครดิตฟรีเมื่อลงทะเบียน