AizuDemy

Tutorial PydanticAI & Ollama: Bikin Agentic AI Type-Safe di Python

Tutorial PydanticAI & Ollama: Bikin Agentic AI Type-Safe di Python
IKLAN
IDCloudHost
🎧
Dengarkan Artikel Ini
Suara AI Otomatis β€’ 10 mnt baca baca
⚑ TL;DR

Poin Kunci Artikel Ini:

  • Mimpi Buruk JSON Hallucination pada AI AgentPernah kebangun jam dua malam cuma gara-gara server e-commerce mendadak mati total?
  • Kita butuh jaminan tipe data murni langsung di level kode Python.
  • Pastikan komputer kamu sudah terpasang Python versi 3.10 atau yang lebih baru.
πŸ“‹ Daftar Isi Materi Tutup β–΄

Mimpi Buruk JSON Hallucination pada AI Agent

Pernah kebangun jam dua malam cuma gara-gara server e-commerce mendadak mati total? Pas diperiksa sambil merem melek, ternyata pemicunya sepele: LLM yang dipakai buat mengekstrak data pesanan malah mengembalikan string "Rp 50.000" bukannya angka integer 50000 pada field harga. Kode Python yang gak siap langsung nge-throw ValueError dan menghentikan seluruh antrean transaksi saat itu juga.

Respon LLM yang tidak konsisten dan sering halusinasi format memang jadi momok utama buat developer saat membangun AI Agent. Kita minta model mengembalikan format JSON rapi, tapi model malah nambahin teks basa-basi di awal, lupa menutup kurung kurawal }, atau bikin nama key baru yang gak pernah kita minta.

Mengandalkan regex atau string manipulation manual buat membersihkan respon LLM cuma kaya nempel plester di pipa bocorβ€”gampang jebol lagi. Kita butuh jaminan tipe data murni langsung di level kode Python. Kalau data gak sesuai skema, sistem wajib menolaknya atau minta LLM mengoreksinya secara otomatis sebelum masuk ke database.

Di sinilah PydanticAI hadir sebagai penyelamat. Pustaka ini dikembangkan oleh tim di balik Pydantic (library validasi data paling populer di ekosistem Python) untuk membawa konsep type safety ke dunia agentic AI. Kalau dikawinkan dengan Ollama buat menjalankan LLM secara lokal, kita bisa membangun AI Agent yang hemat biaya, menjaga privasi data, dan punya tingkat presisi tinggi buat lingkungan produksi.

Setup Environment: Persiapan Tooling

Mari kita persiapkan environment proyek Python. Pastikan komputer kamu sudah terpasang Python versi 3.10 atau yang lebih baru. Pertama, buat folder proyek baru dan aktifkan virtual environment agar dependensi tidak bentrok dengan proyek lain:

mkdir pydanticai-ollama-demo
cd pydanticai-ollama-demo
python -m venv venv
source venv/bin/activate  # Untuk Linux/macOS
# venv\Scripts\activate   # Untuk Windows

pip install pydantic-ai httpx logfire

Selanjutnya, kita butuh Ollama yang sudah berjalan di background. Jika belum ada, unduh aplikasi Ollama dari situs resminya lalu pilih model LLM yang jago mengikuti instruksi serta paham structured output. Model seperti qwen2.5 atau llama3.2 sangat direkomendasikan untuk tugas ekstraksi ini.

Buka terminal baru lalu tarik model yang ingin digunakan ke komputer lokal kamu:

ollama pull qwen2.5:7b

Secara bawaan, Ollama menyediakan REST API lokal yang kompatibel dengan format OpenAI di http://localhost:11434/v1. Fitur ini memudahkan PydanticAI untuk berkomunikasi langsung dengan model lokal tanpa perlu API key berbayar dari layanan cloud.

Integrasi PydanticAI dengan Provider Ollama

PydanticAI punya arsitektur provider yang sangat rapi. Untuk menyambungkannya ke Ollama, kita cukup memanfaatkan modul OpenAIModel bawaan PydanticAI, lalu melempar alur request-nya ke URL server Ollama lokal.

Buat berkas baru bernama agent_demo.py dan tulis kode sederhana berikut untuk menguji koneksi ke model lokal kita:

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel

# Konfigurasi model Ollama via endpoint OpenAI-compatible
ollama_model = OpenAIModel(
    model_name='qwen2.5:7b',
    base_url='http://localhost:11434/v1',
    api_key='ollama',  # API key dummy dibutuhkan oleh SDK client
)

# Inisialisasi agent dasar
agent = Agent(model=ollama_model)

# Uji coba query sederhana
result = agent.run_sync('Mengapa langit berwarna biru? Jawab singkat saja.')
print(result.data)

Jalankan skrip tersebut lewat terminal dengan perintah python agent_demo.py. Jika balasan teks sudah muncul di terminal, berarti agen AI kamu siap dikembangkan lebih jauh.

Membuat Agent dengan Validasi Skema Pydantic

Sekarang masuk ke fitur paling penting dari PydanticAI: memaksa LLM mengembalikan struktur data yang terverifikasi ketat. Kita akan membuat skema untuk mengekstrak profil pengguna dari teks bebas yang berantakan.

Kita definisikan kelas Pydantic sebagai kontrak bentuk data. PydanticAI secara otomatis mengonversi skema Python ini menjadi JSON Schema standar dan mengirimkannya ke LLM sebagai batas aturan balasan.

from typing import List, Optional
from pydantic import BaseModel, Field
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel

ollama_model = OpenAIModel(
    model_name='qwen2.5:7b',
    base_url='http://localhost:11434/v1',
    api_key='ollama',
)

# Definisi struktur data target
class Skill(BaseModel):
    name: str = Field(description="Nama keahlian atau teknologi")
    level: str = Field(description="Tingkat keahlian: Beginner, Intermediate, atau Expert")

class UserProfile(BaseModel):
    full_name: str = Field(description="Nama lengkap pengguna")
    age: int = Field(description="Usia dalam angka murni")
    email: Optional[str] = Field(default=None, description="Alamat email valid jika ada")
    skills: List[Skill] = Field(description="Daftar keahlian yang dimiliki")
    is_employed: bool = Field(description="Status sedang bekerja atau tidak")

# Buat agent dengan result_type bertipe UserProfile
extractor_agent = Agent(
    model=ollama_model,
    result_type=UserProfile,
    system_prompt=(
        "Anda adalah asisten ekstraksi data yang presisi. "
        "Ekstrak informasi pengguna dari teks input ke dalam format yang diminta."
    ),
)

# Teks input mentah yang acak-acakan
raw_text = """
Halo, nama saya Budi Santoso, umur 28 tahun. Saat ini saya bekerja sebagai 
Backend Developer. Saya menguasai Python di tingkat Expert dan Postgresql 
di tingkat Intermediate. Email kontak saya budi.santoso@example.com.
"""

response = extractor_agent.run_sync(raw_text)
user_data: UserProfile = response.data

print(f"Tipe Data Output: {type(user_data)}")
print(f"Nama: {user_data.full_name}")
print(f"Usia: {user_data.age} tahun (Tipe: {type(user_data.age)})")
print(f"Jumlah Skill: {len(user_data.skills)}")
for s in user_data.skills:
    print(f" - {s.name} ({s.level})")

Saat skrip di atas mengeksekusi data, variabel user_data bukan lagi objek string JSON biasa yang perlu kamu dekode manual menggunakan json.loads(). Variabel itu sudah murni menjadi instansi kelas UserProfile lengkap dengan fitur autocompletion dan tipe data yang dikenali oleh IDE seperti VS Code.

Menambahkan Tool Calling pada Agent

AI Agent masa kini tidak cuma pintar mengolah kata, tapi juga harus bisa mengambil tindakan nyata melalui pemanggilan fungsi (tool calling). PydanticAI menyederhanakan penambahan fungsi eksternal ini lewat dekorator @agent.tool.

Sebagai contoh praktis, mari buat skenario toko komputer di mana agen bisa langsung mengecek stok barang di basis data simulasi saat menjawab pertanyaan pelanggan.

from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
from pydantic_ai.models.openai import OpenAIModel

ollama_model = OpenAIModel(
    model_name='qwen2.5:7b',
    base_url='http://localhost:11434/v1',
    api_key='ollama',
)

# Database simulasi
STOCK_DB = {
    "laptop-01": {"name": "Laptop Gaming X", "stock": 5, "price": 15000000},
    "mouse-02": {"name": "Mouse Wireless Y", "stock": 0, "price": 250000},
}

support_agent = Agent(
    model=ollama_model,
    system_prompt=(
        "Anda adalah customer service toko komputer. "
        "Gunakan tool cek_stok untuk memeriksa ketersediaan barang sebelum menjawab."
    ),
)

@support_agent.tool
def cek_stok(ctx: RunContext[None], product_id: str) -> str:
    """Mengecek ketersediaan stok barang berdasarkan ID produk."""
    item = STOCK_DB.get(product_id.lower())
    if not item:
        return f"Produk dengan ID {product_id} tidak ditemukan."
    if item["stock"] > 0:
        return f"{item['name']} tersedia. Stok: {item['stock']} unit. Harga: Rp {item['price']:,}."
    return f"{item['name']} saat ini habis (stok 0)."

# Jalankan agent dengan pertanyaan user
res = support_agent.run_sync("Apakah produk laptop-01 masih ada?")
print(res.data)

PydanticAI secara otomatis membaca tipe parameter dan dokumentasi docstring dari fungsi cek_stok, lalu menerjemahkannya menjadi skema tool yang dimengerti oleh Ollama. Agen akan menentukan secara mandiri kapan waktu yang tepat untuk mengeksekusi fungsi tersebut.

Retry Otomatis Saat Validation Error

Salah satu tantangan memakai LLM ukuran kecil (seperti 3B atau 7B) adalah kecenderungannya menghasilkan format salah secara tak terduga. Untungnya, PydanticAI punya fitur auto-retry loop yang sangat membantu mengatasi kendala ini.

Saat LLM mengembalikan nilai yang gagal divalidasi oleh skema Pydantic, PydanticAI tidak akan langsung mematikan aplikasi kamu. PydanticAI bakal menangkap ValidationError tersebut, lalu secara otomatis mengirimkan pesan kesalahan itu balik ke LLM sebagai instruksi perbaikan tambahan.

Proses perbaikan otomatis ini berjalan dalam alur berikut:

  • Langkah 1: Agen mengirimkan prompt dan JSON Schema target ke server Ollama.
  • Langkah 2: Ollama membalas dengan respon JSON mentah.
  • Langkah 3: PydanticAI melakukan pengecekan validasi tipe data terhadap skema.
  • Langkah 4 (Jika Invalid): PydanticAI menangkap error validasi lalu mengirim balik petunjuk perbaikan ke Ollama.
  • Langkah 5 (Jika Valid): Data dikembalikan sebagai objek Python asli yang siap dipakai aplikasi.

Batas maksimal percobaan ulang bisa kamu atur sesuai kebutuhan lewat parameter max_result_retries:

# Membatasi perbaikan otomatis maksimal hingga 3 kali percobaan
response = extractor_agent.run_sync(raw_text, max_result_retries=3)

Mekanisme ini menaikkan tingkat keberhasilan sistem secara signifikan tanpa perlu mengotori kode utama dengan blok try-except yang rumit.

Optimasi Latensi dan Performa Model Lokal

Menjalankan LLM di komputer sendiri memang gratis dan privat, tapi masalah latensi bisa mengganggu kalau konfigurasi hardware kurang pas. Beberapa trik berikut bisa kamu pakai buat menggenjot kecepatan respon agen AI kamu:

  • Pilih Ukuran Model yang Pas: Manfaatkan model qwen2.5:3b jika kamu mengutamakan kecepatan respon untuk tugas ekstraksi simpel. Pilih varian 7B atau 8B kalau butuh kemampuan penalaran yang lebih kompleks atau pemanggilan tool bertingkat.
  • Set Temperature ke Nol: Selalu atur parameter temperature ke 0.0 saat fokus melakukan ekstraksi data terstruktur. Cara ini menekan kreativitas model agar jawaban yang dihasilkan konsisten dan deterministik.
  • Pastikan Offload ke GPU: Pastikan Ollama sudah menggunakan VRAM GPU secara penuh. Kamu bisa mengecek status penggunaan GPU saat Ollama berjalan memakai perintah nvidia-smi di terminal.
  • Gunakan Async API: PydanticAI dirancang secara native mendukung asyncio di Python. Gunakan metode agent.run() dibanding agent.run_sync() pada aplikasi berbasis web server agar proses I/O tidak mengunci thread utama.

Strategi Unit Testing pada Agentic AI

Menguji (testing) aplikasi AI sering kali lambat kalau setiap skenario pengujian harus memanggil LLM sungguhan. PydanticAI menyediakan mekanisme bawaan untuk membuat simulasi respon AI menggunakan TestModel.

Dengan TestModel, kamu bisa menguji seluruh alur logika aplikasi Python tanpa harus menyalakan server Ollama atau menunggu generasi teks yang memakan waktu.

Berikut contoh penulisan unit test ringkas menggunakan pytest:

import pytest
from pydantic_ai.models.test import TestModel
from agent_demo import extractor_agent, UserProfile

def test_extractor_agent():
    # Ganti model asli dengan TestModel untuk testing instan
    test_payload = UserProfile(
        full_name="Test User",
        age=30,
        email="test@test.com",
        skills=[],
        is_employed=True
    )
    
    with extractor_agent.override(model=TestModel(custom_result_args=test_payload)):
        result = extractor_agent.run_sync("Sembarang teks input")
        assert result.data.full_name == "Test User"
        assert result.data.age == 30
        assert isinstance(result.data, UserProfile)

Pendekatan ini bikin rangkaian pengujian otomatis di pipeline CI/CD kamu bisa selesai dalam hitungan milidetik tanpa bergantung pada koneksi model LLM.

Integrasi AI Agent ke FastAPI

Langkah paling praktis untuk menyajikan AI Agent ini ke lingkungan produksi adalah membungkusnya menjadi endpoint REST API menggunakan FastAPI.

Karena FastAPI dan PydanticAI sama-sama mengandalkan Pydantic untuk urusan data, integrasi keduanya terasa sangat natural. Pasang dependensinya lewat pip install fastapi uvicorn dan buat berkas main.py:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel

app = FastAPI(title="Type-Safe AI Agent Service")

ollama_model = OpenAIModel(
    model_name='qwen2.5:7b',
    base_url='http://localhost:11434/v1',
    api_key='ollama',
)

class SentimentRequest(BaseModel):
    text: str

class SentimentResponse(BaseModel):
    sentiment: str
    confidence: float
    key_keywords: list[str]

sentiment_agent = Agent(
    model=ollama_model,
    result_type=SentimentResponse,
    system_prompt="Analisis sentimen dari teks input yang diberikan."
)

@app.post("/analyze", response_model=SentimentResponse)
async def analyze_sentiment(payload: SentimentRequest):
    try:
        res = await sentiment_agent.run(payload.text)
        return res.data
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# Jalankan aplikasi server dengan perintah:
# uvicorn main:app --reload

Endpoint /analyze ini siap menerima data JSON dari klien, mengolahnya lewat Ollama lokal dengan validasi tipe data PydanticAI, dan langsung mengembalikan hasil analisis yang rapi serta terstruktur.

Kesimpulan

Membangun AI Agent tidak perlu terasa seperti menebak-nebak hasil undian. Kombinasi PydanticAI dan Ollama memberikan kita kendali penuh: biaya operasional nol, privasi data terjaga di server sendiri, kemampuan tool calling yang fleksibel, dan kepastian validasi tipe data ala Python.

Sekarang saatnya kamu mencoba: ambil satu modul parsing data manual atau skrip prompt di proyek kamu saat ini, lalu refaktor menggunakan Agent(result_type=...) dari PydanticAI. Kamu akan langsung merasakan bedanya bekerja dengan AI yang konsisten, deterministik, dan siap untuk lingkungan produksi.

A
Aizu Dev

Tim penulis AizuDemy yang menyajikan tutorial teknologi, cloud, dan pengembangan perangkat lunak dalam Bahasa Indonesia.

πŸ“– Artikel Terkait