
Δημιουργία Voice Agent στο OpenAI Realtime API: Οδηγός Παραγωγής σε 7 Βήματα (2026)
Ο δοκιμαστικός μας agent απάντησε σε μια κλήση Twilio και είπε την πρώτη του λέξη 1,1 δευτερόλεπτα αφότου ο καλών σταμάτησε να μιλά. Αυτή είναι η median τιμή (p50) για τον γύρο μετάδοσης, μετρημένη σε 40 κλήσεις στο gpt-realtime-2 με semantic_vad. Δεν είναι μαγεία. Το OpenAI Realtime API εκτελεί τη διαδικασία speech-to-speech μέσα σε μία μόνο socket σύνδεση, έτσι παρακάμπτετε τη relay αλυσίδα STT → LLM → TTS που προσθέτει περίπου 600ms επιπλέον καθυστέρηση. Ωστόσο, οι προεπιλεγμένες ρυθμίσεις δεν θα σας οδηγήσουν σε χρόνο κάτω του ενός δευτερολέπτου. Αυτή είναι η υλοποίηση 7 βημάτων που κυκλοφορήσαμε, μαζί με τον κώδικα και τον πίνακα λανθάνουσας καθυστέρησης.
Αυτός είναι ένας οδηγός υλοποίησης, όχι μια επεξήγηση εννοιών. Αν θέλετε πρώτα την αναλυτική θεωρητική ανάλυση, διαβάστε τι είναι πραγματικά ένας AI voice agent και μετά επιστρέψτε εδώ. Όλα τα παρακάτω προϋποθέτουν ότι διαθέτετε ένα κλειδί API του OpenAI και ένα περιβάλλον Node runtime.
Βασικά συμπεράσματα:
- Το gpt-realtime-2 εκτελεί speech-to-speech σε μία socket — χωρίς relay STT/LLM/TTS, εξοικονόμηση ~600ms.
- Δημιουργείτε εφήμερα κλειδιά στην πλευρά του server· μην στέλνετε ποτέ το κανονικό σας κλειδί API σε browser.
- Η ροή πολυμέσων του Twilio είναι 8kHz μ-law· κάνετε resample σε 24kHz PCM16 για το Realtime API.
- Μετρήσαμε p50 1,1s / p95 1,9s για τον γύρο μετάδοσης. Η διακοπή (barge-in) ενεργοποιείται μέσω του
response.cancel.
Τι Θα Φτιάξετε σε 7 Βήματα
Αυτό το σεμινάριο δημιουργεί έναν voice agent του OpenAI Realtime API που απαντά σε τηλεφωνικές κλήσεις σε λιγότερο από 1,5 δευτερόλεπτο, καλεί μια πραγματική συνάρτηση στη μέση της συνομιλίας και επιτρέπει στον καλούντα να τον διακόψει. Η ροή είναι σύντομη: ένας καλών χτυπά έναν τηλεφωνικό αριθμό, ο ήχος ρέει στον server σας, ο server σας τον γεφυρώνει στο gpt-realtime-2 μέσω μιας μοναδικής socket, το μοντέλο μιλά και μπορεί να πυροδοτήσει κλήσεις εργαλείων, και ο ήχος επιστρέφει πίσω.
Εδώ είναι η διαδρομή, και μπορείτε να σταματήσετε σε οποιοδήποτε βήμα ταιριάζει στην περίπτωση χρήσης σας:
- Δημιουργία εφήμερου κλειδιού (διαδρομή server)
- Άνοιγμα και διαμόρφωση της συνεδρίας
- Προσθήκη κλήσης συναρτήσεων (function calling)
- Γέφυρα με τηλεφωνικό αριθμό μέσω Twilio
- Διαχείριση διακοπών (barge-in)
- Ρύθμιση λανθάνουσας καθυστέρησης σε υποδευτερόλεπτο
- Ανάπτυξη και ασφάλιση για παραγωγή
Τρεις τύποι μεταφοράς δεδομένων μεταφέρουν τον ήχο, και η επιλογή σας εξαρτάται από την πηγή του ήχου. Ένα browser τον καταγράφει απευθείας (WebRTC), ο server σας έχει ήδη μια raw ροή ήχου (WebSocket), ή το τηλεφωνικό δίκτυο τον παραδίδει (SIP). Θα χρησιμοποιήσουμε WebSocket για τη γέφυρα Twilio και θα αναφέρουμε τις άλλες όπου ταιριάζουν.
Βήμα 1: Δημιουργία Εφήμερου Κλειδιού (η διαδρομή που δεν πρέπει να παραλείψετε)
Μην εκθέτετε ποτέ το κανονικό σας κλειδί API του OpenAI σε browser ή σε συσκευή πελάτη. Το Realtime API εκδίδει βραχύβια εφήμερα κλειδιά ακριβώς για αυτόν τον σκοπό. Ο server σας καλεί το POST /v1/realtime/client_secrets με το πραγματικό σας κλειδί, παραδίδει στον πελάτη ένα token που λήγει σε περίπου ένα λεπτό, και ο πελάτης συνδέεται με αυτό αντί για το κύριο κλειδί.
Εδώ είναι μια ελάχιστη διαδρομή Express που δημιουργεί ένα τέτοιο κλειδί:
// 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 κάνει fetch στο /session, διαβάζει το βραχύβιο secret και ανοίγει τη σύνδεση Realtime με αυτό. Αν ο agent σας λειτουργεί μόνο στον server (η περίπτωση Twilio στο Βήμα 4), μπορείτε να παραλείψετε την παράδοση στον πελάτη και να ανοίξετε την socket απευθείας από το backend σας με το κανονικό κλειδί. Η ροή με εφήμερα κλειδιά υπάρχει για να προστατεύει μη αξιόπιστους πελάτες.
Βήμα 2: Άνοιγμα Συνεδρίας και Διαμόρφωση του gpt-realtime-2
Ανοίξτε μια σύνδεση και στη συνέχεια στείλτε ένα session.update που ορίζει το μοντέλο, τη μορφή ήχου, τη φωνή και την ανίχνευση αλλαγής σειράς ομιλίας (turn detection). Τα έγγραφα του OpenAI προτείνουν να ξεκινήσετε με το reasoning.effort ρυθμισμένο σε low και να το αυξήσετε μόνο εάν η λογική των εργαλείων σας χρειάζεται μεγαλύτερη ακρίβεια, καθώς higher effort κοστίζει σε λανθάνουσα καθυστέρηση. Ο ήχος τρέχει ως 24kHz PCM16 και προς τις δύο κατευθύνσεις.
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" },
},
}));Ποια μεταφορά δεδομένων θα τυλίξετε γύρω από αυτή την socket εξαρτάται από την πηγή του ήχου:
| Μεταφορά Δεδομένων | Χρήση όταν | Πηγή Ήχου |
|---|---|---|
| WebRTC | Browser ή mobile app καταγράφει απευθείας το μικρόφωνο | Συσκευή πελάτη |
| WebSocket | Ο server σας κατέχει ήδη μια raw ροή ήχου | Pipeline server |
| SIP | Θέλετε το OpenAI να διαχειριστεί το τηλεφωνικό σκέλος | PSTN / τηλεφωνία |
Για την πλήρη λίστα πεδίων συνεδρίας και το σύνολο δυνατοτήτων GA, τα έγγραφα του OpenAI Realtime API είναι η αυθεντική πηγή. Θα χρησιμοποιήσουμε WebSocket επειδή το Twilio μας παραδίδει raw ήχο στο Βήμα 4.
Βήμα 3: Προσθήκη Κλήσης Συναρτήσεων (για να μπορεί ο agent να κάνει πράγματα)
Ένας voice agent που δεν μπορεί να δράσει είναι απλώς voice-over. Η κλήση συναρτήσεων (function calling) επιτρέπει στο gpt-realtime-2 να暂停 τη συνομιλία στη μέση, να ζητήσει από τον κώδικά σας να εκτελέσει κάτι και να συνεχίσει να μιλά με το αποτέλεσμα. Δηλώνετε ένα εργαλείο στη συνεδρία, το μοντέλο εκπέμπει ένα γεγονός function_call_arguments.done όταν το θέλει, εσείς εκτελείτε την εργασία και στέλνετε την έξοδο πίσω.
Δηλώστε το εργαλείο και στη συνέχεια χειριστείτε το γεγονός:
// 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
}Ο πιο συνηθισμένος λόγος που τα εργαλεία δεν πυροδοτούνται ποτέ σιωπηλά: δεν ακούτε για το function_call_arguments.done και δεν στέλνετε response.create afterward. Το μοντέλο παρήγαγε την κλήση, εσείς την αγνοήσατε, ο καλών ακούει νεκρή σιωπή.
Αν ο agent σας διαχειρίζεται πολλά εργαλεία, το OpenAI Agents SDK άλλαξε τα δεδομένα εδώ. Η αναθεώρηση της 15ης Απριλίου 2026 έκανε το Model Context Protocol (MCP) first-class και μετέτρεψε τις handoffs σε sub-agents σε primitive του runtime. Έτσι, αντί να στριμώχνετε κάθε εργαλείο σε ένα prompt, ένας agent router μπορεί να αναθέσει μια κράτηση σε έναν sub-agent κρατήσεων και μια ερώτηση χρέωσης σε έναν άλλον. Το Agents SDK voice quickstart τυλίγει την ίδια συνεδρία Realtime σε ένα RealtimeAgent και σας προσφέρει handoffs χωρίς να γράφετε τον δικό σας βρόχο orchestration.
Βήμα 4: Γέφυρα με Τηλεφωνικό Αριθμό (Twilio)
Για να απαντάτε σε πραγματικές κλήσεις, γεφυρώνετε έναν πάροχο τηλεφωνίας στη socket. Με το Twilio, κατευθύνετε μια εισερχόμενη κλήση σε ένα TwiML <Connect><Stream> που ανοίγει μια WebSocket στον server σας, και αναμεταδίδετε frames ήχου μεταξύ του Twilio και του Realtime API. Το SIP είναι η εναλλακτική — το OpenAI Realtime δέχεται SIP απευθείας, κάτι που αφαιρεί entirely το media relay σας αν δεν χρειάζεται να αγγίξετε τον ήχο.
Το TwiML που ξεκινά τη ροή:
<Response>
<Connect>
<Stream url="wss://your-server.com/twilio-stream" />
</Connect>
</Response>Εδώ είναι η παγίδα που σας κοστίζει μια μέρα αν την χάσετε: η ροή πολυμέσων του Twilio είναι 8kHz μ-law, και το Realtime API θέλει 24kHz PCM16. Κάνετε resample και προς τις δύο κατευθύνσεις, διαφορετικά θα έχετε παραμορφωμένο ήχο με υψηλό τόνο (chipmunk audio).
// 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") },
}));Η πλήρης μορφή frame βρίσκεται στα έγγραφα Twilio Media Streams. Keep the resampling cheap, because a heavy library here adds latency you'll pay for on every frame.
Βήμα 5: Διαχείριση Διακοπών (Barge-In)
Ένας agent παραγωγής επιτρέπει στον καλούντα να μιλά πάνω από αυτόν. Το Barge-in σημαίνει την ανίχνευση ότι ο καλών άρχισε να μιλά ενώ ο agent βρίσκεται στη μέση μιας πρότασης, και στη συνέχεια τη διακοπή του agent καθαρά. Το Realtime API το χειρίζεται με το response.cancel: όταν η ανίχνευση turn reports ότι ξεκίνησε ομιλία κατά την αναπαραγωγή, ακυρώνετε την ενεργή απόκριση και flush whatever audio you've already buffered toward the caller.
if (event.type === "input_audio_buffer.speech_started") {
realtime.send(JSON.stringify({ type: "response.cancel" }));
twilioWs.send(JSON.stringify({ event: "clear" })); // drop queued playback
}Η ανίχνευση Turn έχει δύο modes, και η επιλογή matters. Το server_vad triggers σε raw thresholds σιωπής και tends to cut the caller off on natural pauses. Το semantic_vad waits until the model thinks the caller actually finished a thought, so it produces far fewer false interruptions on a thinking pause. For phone calls, semantic VAD is the one that feels human.
Βήμα 6: Ρύθμιση Λανθάνουσας Καθυστέρησης σε Υποδευτερόλεπτο
Εδώ είναι που ένα demo γίνεται προϊόν, οπότε εδώ είναι οι αριθμοί από τη δική μας υλοποίηση, όχι ένας θεωρητικός προϋπολογισμός. Τρέξαμε τον ίδιο agent εστιατορίου σε 40 δοκιμαστικές κλήσεις τον Μάιο του 2026, σε έναν μικρό server colocated near the OpenAI region, swapping only the turn-detection and reasoning settings.
| Διαμόρφωση | p50 round-trip | p95 | Σημειώσεις |
|---|---|---|---|
| server_vad, reasoning low | ~1,4s | ~2,3s | περισσότερες ψευδείς διακοπές στις παύσεις |
| semantic_vad, reasoning low | ~1,1s | ~1,9s | η προεπιλογή παραγωγής μας |
| semantic_vad, reasoning medium | ~1,8s | ~3,1s | καλύτερη ακρίβεια εργαλείων, πιο αργό |
Οι lever που actually moved the needle, με σειρά impact:
- Κρατήστε το
reasoning.effortlow εκτός αν ένα specific tool genuinely needs the accuracy. Το Medium nearly doubled our p50. - Μην pushάρετε ήχο faster than realtime. Flooding
input_audio_buffer.appendoverruns the buffer and causes drift; pace frames to wall-clock time. - Κρατήστε την socket warm. Cold-opening a connection per call adds the handshake to your first-word latency. Pool connections where call volume allows.
- Resample efficiently. A naive resampler in the hot path added ~80ms per turn for us.
Πόσο κοστίζει η运行 αυτού ανά λεπτό μόλις γίνει live? Worked the bring-your-own-key math separately — see what a BYOK voice agent costs per minute instead of re-deriving it here.
Βήμα 7: Ανάπτυξη και Ασφάλιση για Παραγωγή
Το gap between "it worked on my laptop" and "it survives 500 calls a day" is a handful of well-known failures. Here's the hardening checklist, drawn from the mistakes that actually break Realtime agents:
| Παγίδα | Σύμπτωμα | Λύση |
|---|---|---|
| Λανθασμένος sample rate | παραμορφωμένος / chipmunk ήχος | 24kHz PCM16 και προς τις δύο κατευθύνσεις |
Αγνόηση του function_call_arguments.done | τα εργαλεία δεν πυροδοτούνται ποτέ | listen και send response.create |
| Push ήχου faster than realtime | buffer overrun, drift | pace frames to realtime |
| Χωρίς λογική επανασύνδεσης | οι κλήσεις drop σε ένα socket blip | auto-reconnect + resume the session |
Χωρίς handling του response.done | overlapping turns | gate the next turn on response.done |
Two more things for real traffic. On long calls, rotate or reseed the session every several turns so context doesn't drift, because a 20-minute call accumulates state the model starts tripping over. And log every tool call with its arguments and result; when a caller says "the agent booked the wrong time," the transcript alone won't tell you whether the model or your code was wrong.
If you adopt the Agents SDK route from Step 3, its new container sandbox runs tool code in isolation, which matters once your tools touch a filesystem or shell instead of just an API.
Πότε Να Αγοράσετε Ένα Managed Platform Αντί Να Φτιάξετε
Building directly on the Realtime API gives you the most control and the lowest per-minute cost, but you own the reconnect logic, the telephony bridge, compliance, and observability — all the unglamorous parts of Steps 4 through 7. If you need a phone agent live this week and don't want to maintain a media relay, a managed platform is the faster call.
We built the same agent on the three big ones and compared them honestly: Retell, Vapi, or Bland. If you're still deciding which side of the line you're on, walk through the full build-vs-buy decision framework before you commit engineering time.
When teams want the control of a custom Realtime build without staffing it, that's the work we do: production voice agent development, from the telephony bridge to the latency tuning above. Happy to look at your use case if you're weighing it.
Σχετικά με τον συγγραφέα — Ο Mert Batur Gurbuz είναι Συνιδρυτής της Techsy.io, όπου η ομάδα υλοποιεί AI agents, συστήματα αυτοματοποίησης και pipelines voice/SDR για B2B πελάτες. Σπουδάζει στο Πανεπιστήμιο του Birmingham και γράφει για το LLM tooling stack που χρησιμοποιεί πραγματικά η ομάδα της Techsy σε παραγωγή. LinkedIn
Συχνές Ερωτήσεις
Ποια είναι η λανθάνουσα καθυστέρηση του voice agent στο OpenAI Realtime API;
Στην υλοποίησή μας στο gpt-realtime-2 με semantic_vad και low reasoning effort, η λανθάνουσα καθυστέρηση round-trip μετρήθηκε p50 1,1s και p95 1,9s σε 40 δοκιμαστικές κλήσεις. Το speech-to-speech σε μία socket αποφεύγει το relay STT/LLM/TTS, κάτι που καθιστά δυνατές τις αποκρίσεις υποδευτερολέπτου.
Χρειάζομαι WebRTC, WebSocket ή SIP για τον voice agent μου;
Χρησιμοποιήστε WebRTC όταν ένα browser ή mobile app καταγράφει απευθείας το μικρόφωνο, WebSocket όταν ο server σας κατέχει ήδη μια raw ροή ήχου (η περίπτωση γέφυρας Twilio), και SIP όταν θέλετε το OpenAI να διαχειριστεί το τηλεφωνικό σκέλος χωρίς δικό σας media relay. Οι περισσότεροι phone agents χρησιμοποιούν WebSocket ή SIP.
Πώς συνδέω το OpenAI Realtime API με το Twilio;
Κατευθύνετε μια εισερχόμενη κλήση Twilio σε ένα TwiML <Connect><Stream> που ανοίγει μια WebSocket στον server σας, και στη συνέχεια αναμεταδίδετε ήχο μεταξύ του Twilio και της socket Realtime. Κάνετε resample του 8kHz μ-law του Twilio στο 24kHz PCM16 του API και προς τις δύο κατευθύνσεις, διαφορετικά ο ήχος θα βγει παραμορφωμένος.
Πώς λειτουργεί η κλήση συναρτήσεων (function calling) στο Realtime API;
Δηλώνετε εργαλεία στη διαμόρφωση της συνεδρίας. Όταν το μοντέλο θέλει ένα, εκπέμπει ένα γεγονός function_call_arguments.done. Εκτελείτε την εργασία, στέλνετε το αποτέλεσμα πίσω ως ένα conversation item function_call_output, και στη συνέχεια στέλνετε response.create ώστε ο agent να εκφωνήσει το αποτέλεσμα. Η забывание того последнего шага является причиной того, почему инструменты часто «молча» выходят из строя.
Πώς διαχειρίζεστε τις διακοπές (barge-in) στο Realtime API;
Όταν η ανίχνευση turn reports input_audio_buffer.speech_started during playback, send response.cancel to stop the active response and clear any queued output audio toward the caller. Pair it with semantic_vad so natural pauses don't trigger false interruptions mid-sentence.
Ποιος είναι ο sample rate ήχου που χρησιμοποιεί το OpenAI Realtime API;
Το Realtime API χρησιμοποιεί ήχο 24kHz PCM16 και προς τις δύο κατευθύνσεις. Οι πάροχοι τηλεφωνίας όπως το Twilio παραδίδουν 8kHz μ-law, so a phone bridge has to resample up on the way in and down on the way out. Mismatched sample rates are the single most common cause of distorted audio.
Πόσο κοστίζει η运行 ενός voice agent στο Realtime API;
Το κόστος καθορίζεται από τα λεπτά εισόδου και εξόδου ήχου στο gpt-realtime-2, και η οικονομία bring-your-own-key differs sharply from a managed per-minute platform. We worked the full math in our voice agent pricing breakdown rather than estimating it here.
Πρέπει να χτίσω στο Realtime API ή να χρησιμοποιήσω τα Retell, Vapi ή Bland;
Χτίστε απευθείας όταν θέλετε maximum control and the lowest per-minute cost and can own reconnects, telephony, and compliance. Buy a managed platform when speed-to-launch matters more. Our Retell vs Vapi vs Bland comparison and build-vs-buy framework cover the trade-offs.
Τι άλλαξε η ενημέρωση του OpenAI Agents SDK τον Απρίλιο του 2026 για τους voice agents;
Η αναθεώρηση της 15ης Απριλίου 2026 έκανε το Model Context Protocol first-class, added a container sandbox for tool code, and turned sub-agent handoffs into a runtime primitive. For voice agents, that means a router agent can hand off to specialist sub-agents instead of stuffing every tool into one prompt.