
Membangun Agen Suara di OpenAI Realtime API: Tutorial Produksi 7 Langkah (2026)
Agen uji coba kami menjawab panggilan Twilio dan mengucapkan kata pertamanya 1,1 detik setelah penelepon berhenti berbicara. Itu adalah latensi round-trip p50, diukur melalui 40 panggilan pada gpt-realtime-2 dengan semantic_vad. Bukan sihir. OpenAI Realtime API melakukan speech-to-speech dalam satu soket, sehingga Anda melewati relai STT → LLM → TTS yang menambah sekitar 600ms overhead. Namun, pengaturan default tidak akan membawa Anda ke bawah satu detik. Ini adalah build 7 langkah yang kami luncurkan, lengkap dengan kode dan tabel latensi.
Ini adalah tutorial build, bukan penjelasan konsep. Jika Anda ingin pemahaman berlapis terlebih dahulu, baca apa itu agen suara AI sebenarnya, lalu kembali lagi. Semua materi di bawah ini mengasumsikan Anda memiliki kunci API OpenAI dan runtime Node.
Poin utama:
- gpt-realtime-2 melakukan speech-to-speech dalam satu soket — tanpa relai STT/LLM/TTS, menghemat ~600ms.
- Buat kunci sementara (ephemeral keys) di sisi server; jangan pernah mengirimkan kunci API standar Anda ke browser.
- Aliran media Twilio adalah 8kHz μ-law; ubah sampel menjadi 24kHz PCM16 untuk Realtime API.
- Kami mengukur p50 1,1s / p95 1,9s round-trip. Barge-in dipicu melalui
response.cancel.
Apa yang Akan Anda Bangun dalam 7 Langkah
Tutorial ini membangun agen suara OpenAI Realtime API yang menjawab telepon dan berbicara kembali dalam waktu kurang dari 1,5 detik, memanggil fungsi nyata di tengah percakapan, dan memungkinkan penelepon untuk menyela. Alurnya singkat: penelepon menghubungi nomor telepon, audio dialirkan ke server Anda, server Anda menjembatani audio tersebut ke gpt-realtime-2 melalui satu soket, model berbicara dan dapat memicu panggilan alat (tool calls), dan audio dialirkan kembali.
Berikut adalah jalurnya, dan Anda dapat berhenti di langkah mana pun yang sesuai dengan kasus penggunaan Anda:
- Membuat kunci sementara (rute server)
- Membuka dan mengonfigurasi sesi
- Menambahkan pemanggilan fungsi (function calling)
- Menjembatani ke nomor telepon dengan Twilio
- Menangani barge-in dan interupsi
- Menyetel latensi ke sub-detik
- Menerapkan dan mengamankan (hardening)
Tiga transport membawa audio, dan pilihan Anda tergantung pada sumber audio. Browser menangkapnya secara langsung (WebRTC), server Anda sudah memiliki aliran mentah (WebSocket), atau jaringan telepon mengantarkannya (SIP). Kami akan menggunakan WebSocket untuk jembatan Twilio dan mencatat opsi lainnya di tempat yang relevan.
Langkah 1: Membuat Kunci Sementara (Rute yang Tidak Boleh Dilewatkan)
Jangan pernah mengekspos kunci API OpenAI standar Anda ke browser atau perangkat klien. Realtime API mengeluarkan kunci sementara berumur pendek khusus untuk tujuan ini. Server Anda memanggil POST /v1/realtime/client_secrets dengan kunci asli Anda, memberikan token kepada klien yang kedaluwarsa dalam sekitar satu menit, dan klien terhubung menggunakan token tersebut.
Berikut adalah rute Express minimal yang membuatnya:
// server.js
import express from "express";
const app = express();
app.get("/session", async (req, res) => {
const r = await fetch("https://api.openai.com/v1/realtime/client_secrets", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
session: { type: "realtime", model: "gpt-realtime-2" },
}),
});
const data = await r.json();
res.json({ client_secret: data.value, expires_at: data.expires_at });
});
app.listen(3000);Browser mengambil /session, membaca rahasia berumur pendek, dan membuka koneksi Realtime dengannya. Jika agen Anda hanya berjalan di server (kasus Twilio di Langkah 4), Anda dapat melewatkan penyerahan klien dan membuka soket dari backend Anda langsung dengan kunci standar. Alur sementara ada untuk melindungi klien yang tidak tepercaya.
Langkah 2: Buka Sesi dan Konfigurasikan gpt-realtime-2
Buka koneksi, lalu kirim session.update yang mengatur model, format audio, suara, dan deteksi giliran bicara. Dokumentasi OpenAI merekomendasikan untuk memulai dengan reasoning.effort disetel ke low dan hanya menaikkannya jika logika alat Anda membutuhkan akurasi lebih tinggi, karena usaha yang lebih tinggi akan memakan latensi. Audio berjalan sebagai 24kHz PCM16 di kedua arah.
ws.send(JSON.stringify({
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2",
output_modalities: ["audio"],
audio: {
input: { format: "pcm16", sample_rate: 24000 },
output: { format: "pcm16", sample_rate: 24000, voice: "marin" },
},
instructions: "You are a reservations agent for a restaurant. Be brief.",
reasoning: { effort: "low" },
turn_detection: { type: "semantic_vad" },
},
}));Transport mana yang Anda bungkus untuk soket tersebut tergantung pada sumber audio:
| Transport | Gunakan ketika | Sumber audio |
|---|---|---|
| WebRTC | Browser atau aplikasi seluler menangkap mikrofon secara langsung | Perangkat klien |
| WebSocket | Server Anda sudah memegang aliran audio mentah | Pipa server |
| SIP | Anda ingin OpenAI menangani sisi telepon | PSTN / telefoni |
Untuk daftar bidang sesi lengkap dan set fitur GA, dokumentasi OpenAI Realtime API adalah sumber kebenaran utama. Kami akan menggunakan WebSocket karena Twilio memberikan kita audio mentah di Langkah 4.
Langkah 3: Tambahkan Pemanggilan Fungsi (Agar Agen Dapat Benar-Benar Melakukan Sesuatu)
Agen suara yang tidak dapat bertindak hanyalah suara latar. Pemanggilan fungsi memungkinkan gpt-realtime-2 berhenti sejenak di tengah percakapan, meminta kode Anda menjalankan sesuatu, dan terus berbicara dengan hasilnya. Anda mendeklarasikan alat dalam sesi, model memancarkan acara function_call_arguments.done saat membutuhkannya, Anda menjalankan tugas tersebut, dan mengirim outputnya kembali.
Deklarasikan alat, lalu tangani acaranya:
// in session.update -> session.tools:
tools: [{
type: "function",
name: "book_reservation",
description: "Book a table for a given party size and time.",
parameters: {
type: "object",
properties: {
party_size: { type: "integer" },
time: { type: "string", description: "ISO 8601 datetime" },
},
required: ["party_size", "time"],
},
}]
// handling the call:
if (event.type === "response.function_call_arguments.done") {
const args = JSON.parse(event.arguments);
const result = await bookTable(args); // your real logic
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: event.call_id,
output: JSON.stringify(result),
},
}));
ws.send(JSON.stringify({ type: "response.create" })); // let it speak the result
}Penyebab paling umum alat tidak pernah aktif secara diam-diam: tidak mendengarkan function_call_arguments.done dan tidak mengirim response.create setelahnya. Model telah menghasilkan panggilan, Anda mengabaikannya, dan penelepon mendengar keheningan.
Jika agen Anda mengelola banyak alat, OpenAI Agents SDK mengubah perhitungan di sini. Perombakan tanggal 15 April 2026 menjadikan Model Context Protocol (MCP) sebagai fitur utama dan mengubah penyerahan sub-agen menjadi primitif runtime. Jadi, alih-alih memadatkan setiap alat ke dalam satu prompt, agen perute dapat menyerahkan pemesanan ke sub-agen reservasi dan pertanyaan penagihan ke agen lain. Panduan cepat Agents SDK voice membungkus sesi Realtime yang sama dalam RealtimeAgent dan memberi Anda kemampuan penyerahan tanpa menulis loop orkestrasi Anda sendiri.
Langkah 4: Jembatani ke Nomor Telepon (Twilio)
Untuk menjawab panggilan nyata, Anda menjembatani penyedia telefoni ke dalam soket. Dengan Twilio, Anda mengarahkan panggilan masuk ke TwiML <Connect><Stream> yang membuka WebSocket ke server Anda, dan Anda meneruskan frame audio antara Twilio dan Realtime API. SIP adalah alternatifnya — OpenAI Realtime menerima SIP secara langsung, yang menghilangkan relai media Anda sepenuhnya jika Anda tidak perlu menyentuh audio.
TwiML yang memulai aliran:
<Response>
<Connect>
<Stream url="wss://your-server.com/twilio-stream" />
</Connect>
</Response>Berikut adalah jebakan yang bisa menghabiskan waktu sehari jika terlewat: aliran media Twilio adalah 8kHz μ-law, dan Realtime API menginginkan 24kHz PCM16. Anda harus mengubah sampel di kedua arah, atau Anda akan mendapatkan audio yang rusak dan bernada tinggi seperti chipmunk.
// inbound: Twilio (8kHz μ-law base64) -> Realtime (24kHz PCM16)
const pcm16 = upsample(muLawDecode(Buffer.from(msg.media.payload, "base64")), 8000, 24000);
realtime.send(JSON.stringify({
type: "input_audio_buffer.append",
audio: pcm16.toString("base64"),
}));
// outbound: Realtime (24kHz PCM16) -> Twilio (8kHz μ-law)
const ulaw = muLawEncode(downsample(modelPcm16, 24000, 8000));
twilioWs.send(JSON.stringify({
event: "media",
media: { payload: ulaw.toString("base64") },
}));Format frame lengkap tersedia di dokumen Twilio Media Streams. Pastikan proses resampling efisien, karena pustaka yang berat di sini akan menambah latensi yang akan Anda bayar untuk setiap frame.
Langkah 5: Tangani Barge-in dan Interupsi
Agen produksi memungkinkan penelepon berbicara di atas suaranya. Barge-in berarti mendeteksi bahwa penelepon mulai berbicara saat agen sedang di tengah kalimat, lalu memotong agen tersebut dengan bersih. Realtime API menangani ini dengan response.cancel: ketika deteksi giliran melaporkan ucapan dimulai selama pemutaran, Anda membatalkan respons aktif dan menghapus audio apa pun yang sudah Anda buffer menuju penelepon.
if (event.type === "input_audio_buffer.speech_started") {
realtime.send(JSON.stringify({ type: "response.cancel" }));
twilioWs.send(JSON.stringify({ event: "clear" })); // drop queued playback
}Deteksi giliran memiliki dua mode, dan pilihannya penting. server_vad memicu berdasarkan ambang batas keheningan mentah dan cenderung memotong penelepon pada jeda alami. semantic_vad menunggu hingga model berpikir penelepon benar-benar menyelesaikan pikirannya, sehingga menghasilkan jauh lebih sedikit interupsi palsu pada jeda berpikir. Untuk panggilan telepon, semantic VAD adalah yang terasa manusiawi.
Langkah 6: Setel Latensi ke Sub-Detik
Di sinilah demo menjadi produk, jadi berikut adalah angka dari build kami sendiri, bukan anggaran teoretis. Kami menjalankan agen restoran yang sama melalui 40 panggilan uji pada Mei 2026, pada satu server kecil yang berlokasi dekat dengan wilayah OpenAI, hanya mengganti pengaturan deteksi giliran dan penalaran.
| Konfigurasi | Round-trip p50 | p95 | Catatan |
|---|---|---|---|
| server_vad, penalaran low | ~1,4s | ~2,3s | lebih banyak barge-in palsu pada jeda |
| semantic_vad, penalaran low | ~1,1s | ~1,9s | default produksi kami |
| semantic_vad, penalaran medium | ~1,8s | ~3,1s | akurasi alat lebih baik, lebih lambat |
Tuas yang benar-benar berdampak, menurut urutan dampaknya:
- Jaga
reasoning.efforttetap low kecuali alat tertentu benar-benar membutuhkan akurasi tersebut. Medium hampir menggandakan p50 kami. - Jangan mendorong audio lebih cepat dari real-time. Membanjiri
input_audio_buffer.appendmelampaui buffer dan menyebabkan drift; sesuaikan frame dengan waktu dinding (wall-clock time). - Jaga soket tetap hangat. Membuka koneksi baru per panggilan menambahkan handshake ke latensi kata pertama Anda. Kelola pool koneksi jika volume panggilan memungkinkan.
- Lakukan resampling secara efisien. Resampler naif di jalur kritis menambahkan ~80ms per giliran bagi kami.
Berapa biaya menjalankan ini per menit setelah live? Kami menghitung matematika bring-your-own-key secara terpisah — lihat berapa biaya agen suara BYOK per menit daripada menurunkannya lagi di sini.
Langkah 7: Terapkan dan Amankan untuk Produksi
Kesenjangan antara "berhasil di laptop saya" dan "bertahan 500 panggilan sehari" adalah segelintir kegagalan yang sudah dikenal. Berikut adalah daftar pemeriksaan hardening, diambil dari kesalahan yang benar-benar merusak agen Realtime:
| Jebakan | Gejala | Perbaikan |
|---|---|---|
| Sample rate salah | audio rusak / bernada tinggi | 24kHz PCM16 kedua arah |
Mengabaikan function_call_arguments.done | alat tidak pernah aktif | dengarkan dan kirim response.create |
| Mendorong audio lebih cepat dari real-time | buffer overrun, drift | sesuaikan frame ke real-time |
| Tidak ada logika reconnect | panggilan putus saat soket bermasalah | auto-reconnect + lanjutkan sesi |
Tidak ada penanganan response.done | giliran tumpang tindih | batasi giliran berikutnya pada response.done |
Dua hal lagi untuk lalu lintas nyata. Pada panggilan panjang, rotasi atau reseeding sesi setiap beberapa giliran agar konteks tidak hanyut, karena panggilan 20 menit menumpuk status yang mulai membuat model tersandung. Dan catat setiap panggilan alat dengan argumen dan hasilnya; ketika penelepon mengatakan "agen memesan waktu yang salah," transkrip saja tidak akan memberitahu Anda apakah model atau kode Anda yang salah.
Jika Anda mengadopsi rute Agents SDK dari Langkah 3, sandbox kontainer barunya menjalankan kode alat dalam isolasi, yang penting sekali alat Anda menyentuh sistem file atau shell alih-alih hanya API.
Kapan Anda Harus Membeli Platform Terkelola Sebagai Gantinya
Membangun langsung di Realtime API memberi Anda kontrol paling besar dan biaya per menit terendah, tetapi Anda memiliki tanggung jawab atas logika reconnect, jembatan telefoni, kepatuhan, dan observabilitas — semua bagian yang tidak glamor dari Langkah 4 hingga 7. Jika Anda memerlukan agen telepon siap pakai minggu ini dan tidak ingin memelihara relai media, platform terkelola adalah pilihan yang lebih cepat.
Kami membangun agen yang sama di tiga platform besar dan membandingkannya secara jujur: Retell, Vapi, atau Bland. Jika Anda masih memutuskan di sisi mana Anda berada, telusuri kerangka keputusan build-vs-buy lengkap sebelum Anda mengalokasikan waktu rekayasa.
Ketika tim menginginkan kontrol dari build Realtime kustom tanpa harus menyediakannya sendiri, itulah pekerjaan yang kami lakukan: pengembangan agen suara produksi, dari jembatan telefoni hingga penyetelan latensi di atas. Senang melihat kasus penggunaan Anda jika Anda sedang menimbangnya.
Tentang penulis — Mert Batur Gurbuz adalah Co-Founder Techsy.io, di mana timnya meluncurkan agen AI, sistem otomatisasi, dan pipeline voice/SDR untuk klien B2B. Ia belajar di University of Birmingham dan menulis tentang tumpukan alat LLM yang benar-benar digunakan tim Techsy dalam produksi. LinkedIn
Pertanyaan yang Sering Diajukan
Berapa latensi agen suara OpenAI Realtime API?
Dalam build kami pada gpt-realtime-2 dengan semantic_vad dan upaya penalaran low, latensi round-trip diukur p50 1,1s dan p95 1,9s melalui 40 panggilan uji. Speech-to-speech dalam satu soket menghindari relai STT/LLM/TTS, yang memungkinkan respons sub-detik terjadi.
Apakah saya perlu WebRTC, WebSocket, atau SIP untuk agen suara saya?
Gunakan WebRTC ketika browser atau aplikasi seluler menangkap mikrofon secara langsung, WebSocket ketika server Anda sudah memegang aliran audio mentah (kasus jembatan Twilio), dan SIP ketika Anda ingin OpenAI menangani sisi telepon tanpa relai media Anda sendiri. Sebagian besar agen telepon menggunakan WebSocket atau SIP.
Bagaimana cara menghubungkan OpenAI Realtime API ke Twilio?
Arahkan panggilan Twilio masuk ke TwiML <Connect><Stream> yang membuka WebSocket ke server Anda, lalu teruskan audio antara Twilio dan soket Realtime. Ubah sampel 8kHz μ-law Twilio menjadi 24kHz PCM16 API di kedua arah, atau audio akan keluar dengan rusak.
Bagaimana cara kerja pemanggilan fungsi di Realtime API?
Anda mendeklarasikan alat dalam konfigurasi sesi. Ketika model menginginkannya, ia memancarkan acara function_call_arguments.done. Anda menjalankan tugas, mengirim hasil kembali sebagai item percakapan function_call_output, lalu mengirim response.create agar agen berbicara hasilnya. Melupakan langkah terakhir itulah alasan alat sering "gagal secara diam-diam".
Bagaimana Anda menangani interupsi (barge-in) di Realtime API?
Ketika deteksi giliran melaporkan input_audio_buffer.speech_started selama pemutaran, kirim response.cancel untuk menghentikan respons aktif dan menghapus audio output yang diantrekan menuju penelepon. Pasangkan dengan semantic_vad agar jeda alami tidak memicu interupsi palsu di tengah kalimat.
Berapa sample rate audio yang digunakan OpenAI Realtime API?
Realtime API menggunakan audio 24kHz PCM16 di kedua arah. Penyedia telefoni seperti Twilio mengirimkan 8kHz μ-law, sehingga jembatan telepon harus mengubah sampel naik saat masuk dan turun saat keluar. Sample rate yang tidak cocok adalah penyebab paling umum audio terdistorsi.
Berapa biaya menjalankan agen suara di Realtime API?
Biaya didorong oleh menit input dan output audio pada gpt-realtime-2, dan ekonomi bring-your-own-key berbeda tajam dari platform terkelola per menit. Kami menguraikan perhitungan lengkapnya dalam breakdown harga agen suara kami daripada memperkirakannya di sini.
Haruskah saya membangun di Realtime API atau menggunakan Retell, Vapi, atau Bland?
Bangun langsung ketika Anda menginginkan kontrol maksimal dan biaya per menit terendah serta dapat menangani reconnect, telefoni, dan kepatuhan. Beli platform terkelola ketika kecepatan peluncuran lebih penting. [