← Kembali ke Blog

Tool Bawaan Responses API OpenAI: Web Search, File Search, dan Sandbox Python dalam Satu Panggilan

Kalau kamu pernah bangun research agent secara manual, kamu tahu bentuk kodenya. Satu client API buat search, satu vector database buat dokumenmu, satu container buat jalanin Python, plus loop yang mutusin mana yang dipanggil berikutnya. Itu ratusan baris kode lem sebelum agent-nya ngapa-ngapain yang berguna.

Responses API menyediakan tiga bagian itu sebagai tool bawaan: web search, file search, dan Code Interpreter. Kamu cukup daftarkan di array tools, dan model yang memutuskan kapan memanggilnya. Tidak ada loop orkestrasi di sisimu, tidak ada vector DB yang harus dioperasikan, tidak ada container yang perlu dirawat.

Panduan ini membahas tiap tool dengan Python yang bisa langsung dijalankan, cara membaca sitasi dari response, dan kapan pakai solusi sendiri justru lebih masuk akal.

Prasyarat

  • Python 3.9 atau lebih baru, plus SDK-nya: pip install --upgrade openai
  • OPENAI_API_KEY sudah ada di environment
  • Model yang mendukung tool. Contoh memakai nama model dari dokumentasi OpenAI saat ini, jadi sesuaikan dengan akses akunmu.
from openai import OpenAI

MODEL = "gpt-6-astra"  # sesuaikan dengan nama model di dokumentasimu
client = OpenAI()

response = client.responses.create(
    model=MODEL,
    input="Bilang halo dalam satu kalimat singkat.",
)
print(response.output_text)

Satu catatan migrasi. Assistants API sudah dimatikan pada 26 Agustus 2026 dan tidak berfungsi lagi. Kalau kodemu masih mengarah ke /v1/assistants atau thread, migration guide resminya menjelaskan cara pindah dari Threads ke Conversations dan dari Assistants ke prompts.

Web search

Daftarkan tool-nya, lalu tanya hal yang butuh data terbaru.

response = client.responses.create(
    model=MODEL,
    tools=[{"type": "web_search"}],
    input="What is the current recommended way to install Docker Engine on Ubuntu?",
)

print(response.output_text)

Response-nya berisi dua output item. Pertama web_search_call dengan id pemanggilan dan objek action yang type-nya search, open_page, atau find_in_page. Kedua message yang memuat teks jawaban dan annotations.

Item kedua itulah tempat sitasinya. Tiap annotation berbentuk url_citation berisi url sumber, title-nya, dan rentang start_index / end_index dari teks jawaban yang didukungnya.

for item in response.output:
    if item.type != "message":
        continue
    for part in item.content:
        if part.type != "output_text":
            continue
        print(part.text)
        for note in part.annotations or []:
            if note.type == "url_citation":
                print(f"- {note.title}: {note.url} [{note.start_index}:{note.end_index}]")

Ketentuan OpenAI mewajibkan sitasi inline itu tetap terlihat dan bisa diklik saat kamu menampilkan hasil pencarian ke user, jadi jangan dihapus.

Ada tiga knob yang layak kamu tahu. search_context_size menerima low, medium, atau high dan menukar jumlah token konteks dengan kualitas jawaban. user_location menggeser hasil ke arah negara dan kota tertentu. external_web_access: false membatasi pencarian ke indeks milik OpenAI, bukan menarik halaman live, dan ini berguna kalau kamu butuh jawaban yang reprodusibel.

tools=[{
    "type": "web_search",
    "search_context_size": "low",
    "user_location": {"type": "approximate", "country": "ID", "city": "Jakarta"},
}]

File search

File search itu RAG as a service. Kamu upload dokumen ke vector store, pasang store-nya ke request, dan model mengambil chunk-nya sendiri.

# 1. upload dokumen
with open("handbook.pdf", "rb") as f:
    uploaded = client.files.create(file=f, purpose="user_data")

# 2. bikin vector store dan pasang file-nya
store = client.vector_stores.create(name="handbook")
client.vector_stores.files.create(vector_store_id=store.id, file_id=uploaded.id)

# 3. query
response = client.responses.create(
    model=MODEL,
    input="What is the refund window for digital orders?",
    tools=[{
        "type": "file_search",
        "vector_store_ids": [store.id],
        "max_num_results": 5,
    }],
    include=["file_search_call.results"],
)
print(response.output_text)

Proses indexing jalan asinkron. Di service sungguhan, poll status file di vector store sampai berstatus completed sebelum user boleh query, kalau tidak request pertama akan mengenai store kosong dan tidak mengembalikan apa pun yang berguna.

Dua kontrol retrieval yang penting: max_num_results membatasi berapa chunk yang masuk konteks, dan filters menyaring berdasarkan atribut file yang kamu set saat upload.

tools=[{
    "type": "file_search",
    "vector_store_ids": [store.id],
    "filters": {"type": "in", "key": "category", "value": ["policy", "billing"]},
}]

Jawabannya membawa annotation file_citation berisi file_id, filename, dan pointer index, jadi kamu bisa menautkan satu kalimat ke dokumen yang mendasarinya.

Code interpreter

Code Interpreter memberi model lingkungan Python yang ter-sandbox. Model menulis kode, menjalankannya, membaca output, dan mencoba ulang saat percobaan pertama gagal.

response = client.responses.create(
    model=MODEL,
    tools=[{
        "type": "code_interpreter",
        "container": {"type": "auto", "memory_limit": "4g"},
    }],
    instructions="Run Python for every calculation and show the numbers you used.",
    input="Build a 12-month compound growth table for a 2% monthly rate starting at 10,000, then save it as CSV.",
)

for item in response.output:
    if item.type == "code_interpreter_call":
        print(item.code)
        for out in item.outputs or []:
            print(out)

container: {"type": "auto"} membuat container saat dipakai pertama kali dan memakai ulang container aktif dari item code_interpreter_call sebelumnya di konteks yang sama, sehingga file dan variabel tetap ada antar turn. Tier memori ada 1g (default), 4g, 16g, dan 64g. Untuk lingkungan bersama antar request, buat eksplisit dengan client.containers.create(name=..., memory_limit="4g") lalu pakai id cntr_... yang dikembalikan.

File hasil generate direferensikan sebagai path sandbox:/mnt/data/.... Kamu ambil isinya lewat endpoint konten file container lalu menyajikannya dari route milikmu sendiri, karena sandbox: tidak berarti apa-apa di browser.

Gabungkan ketiganya dalam satu panggilan

response = client.responses.create(
    model=MODEL,
    tools=[
        {"type": "web_search"},
        {"type": "file_search", "vector_store_ids": [store.id]},
        {"type": "code_interpreter", "container": {"type": "auto"}},
    ],
    input="Compare our internal refund policy with current industry benchmarks and chart the difference.",
)

Model memilih tool yang dibutuhkannya dan kamu membaca satu objek response di akhir. Kamu bisa mengarahkan pilihan itu lewat tool_choice, dari auto (default) sampai required, atau membatasinya ke subset tertentu dengan allowed_tools.

Kapan tool bawaan bukan pilihan yang tepat

Tiap tool bawaan dihargai terpisah, dan angkanya dipublikasikan di halaman pricing.

Tool bawaan Harga Pakai saat
Web search $10 per 1.000 panggilan plus token konten pencarian sesuai tarif model Kamu mau tanpa infrastruktur search dan sitasi langsung tersedia
File search Storage $0,10 per GB per hari (1 GB pertama gratis), $2,50 per 1.000 panggilan Korpusmu kecil sampai sedang dan kamu ogah menjalankan vector DB sendiri
Code interpreter $0,03 (1 GB) sampai $1,92 (64 GB) per container per sesi 20 menit Kamu butuh sandbox Python sekali pakai tanpa mengurus container

Pertukarannya lebih banyak soal kontrol.

  • Dibanding API search khusus seperti Tavily, Brave, atau Exa: tool bawaan lebih cepat dimulai dan mengembalikan sitasi di response yang sama. API khusus menang saat kamu butuh indeks tertentu, allowlist sumber, atau biaya per query yang bisa diprediksi. Satu hal yang perlu kamu tahu: untuk gpt-4o-mini dan gpt-4.1-mini pada tool web search non-preview, token konten pencarian ditagih sebagai blok tetap 8.000 input token per panggilan.
  • Dibanding RAG self-hosted di pgvector atau Qdrant: file search bawaan menghilangkan kode chunking, embedding, dan retrieval dari piringmu. Self-host menang saat korpusnya cukup besar sehingga tagihan storage harian melewati biaya infrastrukturmu, saat kamu butuh reranking atau chunking khusus, atau saat dokumen tidak boleh keluar dari jaringanmu.
  • Dibanding sandbox Docker milikmu sendiri: Code Interpreter tanpa maintenance dan tanpa urusan network policy. Sandbox sendiri menang di volume panggilan tinggi, saat kamu butuh bahasa atau paket yang tidak disediakan OpenAI, atau saat kamu butuh kontrol jaringan keluar.

Dua default yang perlu diawasi. Response disimpan secara default, jadi kirim store=False kalau tidak ingin disimpan. Dan set search_context_size ke low saat kamu hanya butuh satu fakta; default-nya menarik konteks lebih banyak, dan semua token itu kamu bayar.

Langkah lanjut

Aktifkan streaming supaya user melihat apa yang dikerjakan agent sambil berjalan, lalu tampilkan item pemanggilan tool saat muncul. Tambahkan remote MCP server ke array tools yang sama supaya layanan eksternal bisa ikut masuk tanpa kode lem tambahan. Dan saat orkestrasinya sudah melewati satu panggilan, Agents SDK dibangun di atas item dan tool yang sama.

Referensi

Butuh Bantuan Implementasi?

Saya membantu tim mendesain dan membangun infrastruktur cloud scalable, pipeline DevOps, dan sistem production-grade.

Konsultasi Gratis