0Pricing
AI Prompt Engineering · Pelajaran

Pengujian Prompt Berbasis Assertion

Periksa output menggunakan contains(), regex, skema JSON, dan LLM sebagai penilai.

Pengujian Prompt Berbasis Assertion adalah pelajaran AI Prompt Engineering gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Prompt Engineering, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Prompt Engineering mencakup 4 pelajaran total.

Pernyataan untuk Keluaran LLM

Pengujian berbasis pernyataan berlaku untuk LLM dengan prinsip yang sama seperti dalam pengujian unit: buat klaim eksplisit tentang hal yang harus atau tidak boleh terdapat dalam keluaran, lalu segera gagalkan pengujian ketika klaim tersebut dilanggar.

Berbeda dari pengujian unit dengan fungsi deterministik, pernyataan LLM menangani keluaran teks probabilistik — sehingga memerlukan jenis pernyataan yang lebih fleksibel: contains, matches_schema, satisfies_regex, llm_judge_score_above.

Pernyataan Dasar: contains dan not_contains

Pernyataan paling sederhana memeriksa ada atau tidaknya kata kunci. Pernyataan ini cocok untuk tugas klasifikasi, keluaran terstruktur, dan pemeriksaan keamanan.

import openai
client = openai.OpenAI(api_key='sk-...')

def call_prompt(system, user, temperature=0):
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': system},
            {'role': 'user', 'content': user}
        ],
        temperature=temperature
    )
    return resp.choices[0].message.content

# Keyword presence assertion
def assert_contains(output, keyword, case_sensitive=False):
    text = output if case_sensitive else output.lower()
    kw = keyword if case_sensitive else keyword.lower()
    assert kw in text, f'Expected "{keyword}" in output, got: {output[:100]}'

# Keyword absence assertion
def assert_not_contains(output, forbidden, case_sensitive=False):
    text = output if case_sensitive else output.lower()
    kw = forbidden if case_sensitive else forbidden.lower()
    assert kw not in text, f'Forbidden "{forbidden}" found in output: {output[:100]}'

Validasi Skema JSON

Jika prompt Anda seharusnya mengembalikan JSON terstruktur, validasikan keluaran tersebut terhadap sebuah skema. Kegagalan validasi skema berarti terdapat masalah format pada prompt—model mungkin menambahkan prosa, atau struktur JSON-nya salah.

import json
from jsonschema import validate, ValidationError

PRODUCT_SCHEMA = {
    'type': 'object',
    'properties': {
        'name': {'type': 'string'},
        'price': {'type': 'number', 'minimum': 0},
        'available': {'type': 'boolean'}
    },
    'required': ['name', 'price', 'available'],
    'additionalProperties': False
}

def assert_valid_json_schema(output, schema):
    try:
        data = json.loads(output.strip())
    except json.JSONDecodeError as e:
        raise AssertionError(f'Output is not valid JSON: {e}\nOutput: {output[:200]}')
    try:
        validate(instance=data, schema=schema)
    except ValidationError as e:
        raise AssertionError(f'JSON does not match schema: {e.message}\nOutput: {output[:200]}')
    return data

# Test
output = call_prompt(
    'Extract product info as JSON: {"name": ..., "price": ..., "available": ...}',
    'Widget Pro costs $49.99 and is in stock.'
)
product = assert_valid_json_schema(output, PRODUCT_SCHEMA)
print('Parsed product:', product)

Pencocokan Regex

Pernyataan regex memvalidasi format keluaran secara tepat—berguna untuk keluaran yang harus mengikuti pola tertentu, seperti tanggal, nomor telepon, atau kode terstruktur.

import re

def assert_matches_regex(output, pattern, flags=0):
    if not re.search(pattern, output, flags):
        raise AssertionError(
            f'Output does not match pattern /{pattern}/\nOutput: {output[:200]}'
        )

def assert_output_is_label(output, valid_labels):
    cleaned = output.strip().upper()
    assert cleaned in valid_labels, (
        f'Expected one of {valid_labels}, got: {repr(cleaned)}'
    )

# Examples
output = call_prompt('Classify sentiment as POSITIVE, NEGATIVE, or NEUTRAL:', 'Great product!')
assert_output_is_label(output, {'POSITIVE', 'NEGATIVE', 'NEUTRAL'})

date_output = call_prompt('Extract the date in YYYY-MM-DD format:', 'Meeting on November 15, 2024')
assert_matches_regex(date_output, r'^\d{4}-\d{2}-\d{2}$')

Penilaian oleh LLM sebagai Juri

Untuk keluaran terbuka, gunakan panggilan LLM kedua untuk mengevaluasi kualitasnya. Ini disebut LLM-as-judge. Model juri menerima prompt asli, keluaran, dan kriteria evaluasi, lalu mengembalikan skor.

def llm_judge_score(original_prompt, output, criteria, max_score=10):
    judge_prompt = (
        f'Evaluate the following AI response on a scale of 1-{max_score}.\n'
        f'Evaluation criteria: {criteria}\n\n'
        f'Original prompt: {original_prompt}\n\n'
        f'AI response: {output}\n\n'
        f'Return only a number from 1 to {max_score}.'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': judge_prompt}],
        temperature=0
    )
    score_text = resp.choices[0].message.content.strip()
    return int(score_text)

def assert_llm_score_above(original_prompt, output, criteria, min_score=7):
    score = llm_judge_score(original_prompt, output, criteria)
    assert score >= min_score, f'LLM judge score {score} < minimum {min_score}'

Menggunakan pytest untuk Pengujian Prompt

pytest adalah kerangka kerja pengujian Python standar dan cocok untuk pengujian prompt. Setiap fungsi pengujian berhubungan dengan satu kasus pengujian. pytest mengumpulkan, menjalankan, dan melaporkan hasilnya secara otomatis.

# test_sentiment_prompt.py
import pytest
import openai

client = openai.OpenAI(api_key='sk-...')
SYSTEM_PROMPT = 'Classify the sentiment as POSITIVE, NEGATIVE, or NEUTRAL. Return only the label.'

def classify(text):
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': SYSTEM_PROMPT},
            {'role': 'user', 'content': text}
        ],
        temperature=0
    )
    return resp.choices[0].message.content.strip().upper()

# pytest automatically discovers functions starting with test_
def test_positive_sentiment():
    assert classify('I love this product!') == 'POSITIVE'

def test_negative_sentiment():
    assert classify('Terrible experience.') == 'NEGATIVE'

def test_neutral_sentiment():
    assert classify('It arrived on time.') == 'NEUTRAL'

# Run: pytest test_sentiment_prompt.py -v

Pengujian Berparameter dalam pytest

Gunakan @pytest.mark.parametrize untuk menjalankan fungsi pengujian yang sama pada banyak input tanpa mengulang kode. Ini adalah cara paling rapi untuk membangun rangkaian pengujian yang menyeluruh.

# test_sentiment_parametrized.py
import pytest

TEST_CASES = [
    ('I love this!', 'POSITIVE'),
    ('Worst purchase ever.', 'NEGATIVE'),
    ('It works.', 'NEUTRAL'),
    ('Amazing!', 'POSITIVE'),
    ('Terrible!', 'NEGATIVE'),
    ('OK I guess.', 'NEUTRAL'),
]

@pytest.mark.parametrize('text,expected', TEST_CASES)
def test_sentiment_classification(text, expected):
    result = classify(text)
    assert result == expected, f'For "{text}": expected {expected}, got {result}'

# pytest test_sentiment_parametrized.py -v
# Output shows each test case individually:
# PASSED test_sentiment_parametrized.py::test_sentiment_classification[I love this!-POSITIVE]
# PASSED test_sentiment_parametrized.py::test_sentiment_classification[Worst purchase ever.-NEGATIVE]

Fixture untuk Status Prompt Bersama

Gunakan fixture pytest untuk berbagi penyiapan yang mahal di antara berbagai pengujian—misalnya memuat templat prompt atau membuat klien API satu kali untuk setiap sesi pengujian.

# conftest.py — fixtures available to all test files in the directory
import pytest
import openai

@pytest.fixture(scope='session')
def llm_client():
    return openai.OpenAI(api_key='sk-...')

@pytest.fixture(scope='session')
def sentiment_prompt():
    with open('prompts/sentiment_v3.txt') as f:
        return f.read()

# test_sentiment.py
def test_positive_with_fixture(llm_client, sentiment_prompt):
    resp = llm_client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': sentiment_prompt},
            {'role': 'user', 'content': 'I love this!'}
        ],
        temperature=0
    )
    assert 'POSITIVE' in resp.choices[0].message.content.upper()

Menangani Pengujian yang Tidak Stabil

Keluaran LLM bersifat probabilistik—bahkan pada temperature=0, penerapan atau versi model yang berbeda dapat menghasilkan keluaran yang berbeda. Tangani ketidakstabilan dengan logika percobaan ulang dan ambang toleransi.

import pytest

def run_with_retry(fn, n=3):
    '''Run fn up to n times, pass if any run succeeds.'''
    failures = []
    for _ in range(n):
        try:
            fn()
            return  # passed
        except AssertionError as e:
            failures.append(str(e))
    raise AssertionError(f'Failed all {n} attempts. Last: {failures[-1]}')

def test_positive_with_retry():
    def check():
        result = classify('I love this!')
        assert result == 'POSITIVE'
    run_with_retry(check, n=3)

# Or use pytest-retry plugin:
# @pytest.mark.flaky(reruns=3)
# def test_positive_sentiment():
#     assert classify('I love this!') == 'POSITIVE'

Kinerja dan Biaya Pengujian

Setiap kasus pengujian adalah panggilan API—untuk 100 kasus pengujian dengan biaya $0.005/panggilan = $0.50 per proses pengujian lengkap. Strategi untuk mengelola biaya:

  • Simpan respons dalam cache untuk input pengujian statis dan jalankan dari cache di CI
  • Jalankan seluruh rangkaian pengujian setiap malam; jalankan hanya subset pengujian cepat (10 kasus) pada setiap PR
  • Gunakan model yang lebih murah (gpt-4o-mini) untuk sebagian besar pengujian; gunakan gpt-4o hanya untuk rangkaian regresi
import hashlib, json

RESPONSE_CACHE = {}

def cached_classify(text, use_cache=True):
    key = hashlib.md5(text.encode()).hexdigest()
    if use_cache and key in RESPONSE_CACHE:
        return RESPONSE_CACHE[key]
    result = classify(text)
    RESPONSE_CACHE[key] = result
    return result

# Persist cache to disk for CI
def load_cache(path='test_cache.json'):
    global RESPONSE_CACHE
    try:
        with open(path) as f:
            RESPONSE_CACHE = json.load(f)
    except FileNotFoundError:
        RESPONSE_CACHE = {}

def save_cache(path='test_cache.json'):
    with open(path, 'w') as f:
        json.dump(RESPONSE_CACHE, f, indent=2)

Laporan Keluaran Pengujian

pytest menghasilkan laporan terperinci yang menyoroti kasus pengujian mana yang gagal dan alasannya. Gunakan pytest --tb=short -v untuk pesan kegagalan yang ringkas. Untuk CI, gunakan --junitxml untuk menghasilkan laporan XML JUnit yang kompatibel dengan GitHub Actions, GitLab CI, dan Jenkins.

# Run test suite and generate reports
# In terminal:
# pytest tests/prompt/ -v --tb=short --junitxml=test_results.xml

# In Python (for programmatic use):
import subprocess

def run_prompt_tests(test_dir='tests/prompt'):
    result = subprocess.run(
        ['pytest', test_dir, '-v', '--tb=short', '--junitxml=test_results.xml'],
        capture_output=True, text=True
    )
    print(result.stdout)
    if result.returncode != 0:
        print('TESTS FAILED')
        print(result.stderr)
    return result.returncode == 0

passed = run_prompt_tests()

Pemeriksaan Pengetahuan

Kapan Anda akan menggunakan penilaian LLM sebagai juri, bukan pernyataan pencocokan tepat dalam pengujian prompt?

Rangkuman: Pengujian Prompt Berbasis Pernyataan

Jenis pernyataan utama untuk keluaran LLM:

  • contains / not_contains: keberadaan kata kunci—cocok untuk label dan pemeriksaan keamanan
  • validasi skema JSON: memvalidasi format keluaran terstruktur
  • pencocokan regex: memvalidasi pola tertentu (tanggal, kode)
  • LLM sebagai juri: mengevaluasi kualitas prosa terbuka

Gunakan pytest dengan @pytest.mark.parametrize untuk rangkaian pengujian yang rapi dan mudah diskalakan. Simpan respons dalam cache untuk mengelola biaya. Jalankan subset pengujian cepat pada setiap PR; seluruh rangkaian setiap malam. Pelajaran berikutnya: pengujian regresi di antara pembaruan model.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Pengujian Prompt Berbasis Assertion” gratis?

Ya — teks lengkap “Pengujian Prompt Berbasis Assertion” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Prompt Engineering, upgrade ke CoddyKit PRO. Kursus AI Prompt Engineering mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Pengujian Prompt Berbasis Assertion”?

Periksa output menggunakan contains(), regex, skema JSON, dan LLM sebagai penilai. Kamu berlatih AI Prompt Engineering dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai AI Prompt Engineering?

Tidak diperlukan pengalaman sebelumnya. AI Prompt Engineering di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Pengujian Prompt Berbasis Assertion” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Prompt Engineering ini?

Ya. Setiap pelajaran AI Prompt Engineering menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Menulis Kasus Uji Prompt
  2. Pengujian Prompt Berbasis Assertion
  3. Pengujian Regresi pada Pembaruan Model
  4. Membangun Rangkaian Pengujian Prompt
← Kembali ke AI Prompt Engineering