Create an agent and start a session

Updated

Define an agent in your project, then start and stop sessions that run it in an RTC channel or in telephony.

Preview documentation

You're reading the Conversational AI Platform (Preview) docs. Switch to Main.

On the Conversational AI Platform, you create an agent once and save it in your project. For each conversation, you start a session that runs the agent in an RTC channel or in telephony, and you stop the session when the conversation ends. This page shows the code for each step. In a production environment, run this code on your business server.

Understand the tech

An agent is a saved configuration. A session is a single conversation that runs it. The workflow is as follows:

  1. Your server creates an agent and stores the agent ID that the Platform returns. You do this once, not for every conversation.
  2. Your server starts a session with the agent ID, the channel name, and the user's UID. The agent and the user, through your app, join the same RTC channel. The agent talks to the user, using the agent's ASR, LLM, and TTS models and Agora's low-latency Software-Defined Real-Time Network (SDRTN®).
  3. When the conversation ends, your server stops the session, and the agent leaves the channel.

Prerequisites

Use the Agora CLI to create or select an Agora project, verify project readiness, and export local credentials:

agora login
agora project create conv-ai-tutorial
agora project use conv-ai-tutorial
agora project doctor
agora project env --format shell --with-secrets

You also need:

Install the SDK preview in your project's virtual environment. You need Python 3.8 or later. Specify the version, because the default agora-agents release doesn't support the Platform API.

pip install agora-agents==3.0.0a3

Create a client with your App ID and App Certificate. The SDK uses them to generate a token for each request. The Python examples on this page use this client:

import os
from agora_agent import Agora, Area

client = Agora(
    area=Area.US,
    app_id=os.environ["AGORA_APP_ID"],
    app_certificate=os.environ["AGORA_APP_CERTIFICATE"],
)

Install the SDK preview in your project. You need Node.js 18 or later. Specify the version, because the default agora-agents release doesn't support the Platform API.

cd <your_project_folder>
npm install agora-agents@3.0.0-alpha.3

Create a client with your App ID and App Certificate. The SDK uses them to generate a token for each request. The TypeScript examples on this page use this client:

import { AgoraClient, Area } from 'agora-agents';

const client = new AgoraClient({
  area: Area.US,
  appId: process.env.AGORA_APP_ID!,
  appCertificate: process.env.AGORA_APP_CERTIFICATE!,
});

Add the SDK to your Go module. You need Go 1.21 or later.

cd <your_project_folder>
go get github.com/AgoraIO/agora-agents-go/v2@v2.14.0-alpha.3
go mod tidy

Create a client with your App ID and App Certificate. The SDK uses them to generate a token for each request. The Go examples on this page use this client and ctx, and these imports:

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/AgoraIO/agora-agents-go/v2/agentkit"
	"github.com/AgoraIO/agora-agents-go/v2/agentkit/vendors"
	"github.com/AgoraIO/agora-agents-go/v2/option"
)

ctx := context.Background()
client := agentkit.NewAgoraClient(agentkit.AgoraClientOptions{
	Area:           option.AreaUS,
	AppID:          os.Getenv("AGORA_APP_ID"),
	AppCertificate: os.Getenv("AGORA_APP_CERTIFICATE"),
})

Get REST API credentials for the Platform. For details, see Authentication.

Create an agent

Create an agent with its name, instructions, greeting, and models. This example declares a customer_name variable and uses it in the instructions and the greeting. You pass its value when you start a session.

from agora_agent import Agent, DeepgramSTT, OpenAI, OpenAITTS

agent = (
    Agent(client=client)
    .with_stt(DeepgramSTT(model="nova-3", language="en-US"))
    .with_llm(
        OpenAI(
            model="gpt-4.1-mini",
            system_messages=[
                {
                    "role": "system",
                    "content": "You are a friendly support agent for Acme. Address the user as {{customer_name}}. Keep your answers short.",
                }
            ],
            greeting_message="Hi {{customer_name}}, how can I help you today?",
            greeting_configs={"on": "each_join"},
        )
    )
    .with_tts(OpenAITTS(model="tts-1", voice="alloy"))
    .with_variable("customer_name", type="str", required=True)
)

saved_agent = agent.save(name="Support agent")
print(saved_agent.id)  # The agent ID
import { Agent, DeepgramSTT, OpenAI, OpenAITTS } from 'agora-agents';

const agent = new Agent({ client })
  .withStt(new DeepgramSTT({ model: 'nova-3', language: 'en-US' }))
  .withLlm(
    new OpenAI({
      model: 'gpt-4.1-mini',
      systemMessages: [
        {
          role: 'system',
          content:
            'You are a friendly support agent for Acme. Address the user as {{customer_name}}. Keep your answers short.',
        },
      ],
      greetingMessage: 'Hi {{customer_name}}, how can I help you today?',
      greetingConfigs: { on: 'each_join' },
    }),
  )
  .withTts(new OpenAITTS({ model: 'tts-1', voice: 'alloy' }))
  .withVariable('customer_name', { type: 'str', required: true });

const savedAgent = await agent.save({ name: 'Support agent' });
console.log(savedAgent.id); // The agent ID
agent := agentkit.NewAgent(client).
	WithStt(vendors.NewDeepgramSTT(vendors.DeepgramSTTOptions{Model: "nova-3", Language: "en-US"})).
	WithLlm(vendors.NewOpenAI(vendors.OpenAIOptions{
		Model: "gpt-4.1-mini",
		SystemMessages: []map[string]interface{}{
			{
				"role":    "system",
				"content": "You are a friendly support agent for Acme. Address the user as {{customer_name}}. Keep your answers short.",
			},
		},
		GreetingMessage: "Hi {{customer_name}}, how can I help you today?",
		GreetingConfigs: map[string]interface{}{"on": "each_join"},
	})).
	WithTts(vendors.NewOpenAITTS(vendors.OpenAITTSOptions{Model: "tts-1", Voice: "alloy"})).
	WithVariable("customer_name", agentkit.VariableDefinition{Type: "str", Required: true})

savedAgent, err := agent.Save(ctx, agentkit.SaveOptions{Name: "Support agent"})
if err != nil {
	log.Fatal(err)
}
fmt.Println(savedAgent.ID) // The agent ID

Send a request to Create an agent. The pipeline sets the agent's ASR, LLM, and TTS models.

curl --request POST \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/agents \
  --header 'Authorization: Basic <your_base64_encoded_credentials>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "agent_name": "Support agent",
  "instructions": "You are a friendly support agent for Acme. Address the user as {{customer_name}}. Keep your answers short.",
  "variables": {
    "customer_name": {
      "type": "str",
      "required": true
    }
  },
  "greeting": {
    "mode": "text",
    "on": "each_join",
    "text": "Hi {{customer_name}}, how can I help you today?"
  },
  "pipeline": {
    "mode": "cascaded",
    "asr": {
      "credential": { "mode": "managed" },
      "vendor": "deepgram",
      "model": "nova-3",
      "language": "en-US"
    },
    "llm": {
      "credential": { "mode": "managed" },
      "vendor": "openai",
      "style": "openai",
      "model": "gpt-4.1-mini"
    },
    "tts": {
      "credential": { "mode": "managed" },
      "vendor": "minimax",
      "params": {
        "model": "speech-2.6-turbo",
        "voice_setting": {
          "voice_id": "English_captivating_female1",
          "speed": 1
        }
      }
    }
  }
}'

If the request is successful, the response contains the agent ID and the saved configuration:

// 201 Created
{
  "agent_id": "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10",
  "agent_name": "Support agent",
  "instructions": "You are a friendly support agent for Acme. Address the user as {{customer_name}}. Keep your answers short.",
  "variables": {
    "customer_name": {
      "type": "str",
      "required": true
    }
  },
  "greeting": {
    "mode": "text",
    "on": "each_join",
    "text": "Hi {{customer_name}}, how can I help you today?"
  },
  "pipeline": { ... },  // The pipeline you set in the request.
  "create_ts": 1786543331,
  "update_ts": 1786543331
}

Store the agent ID. You use it to start every session that runs this agent.

This agent uses managed mode for its ASR, LLM, and TTS models. Agora provides access to the models, and you don't need provider API keys. To use other models or your own provider accounts, see Use managed mode and Use your own provider keys.

Start a session

To start a conversation, start a session with the agent ID and the following details:

  • The RTC channel for the conversation.
  • The RTC token for the agent's UID.
  • The UID the agent uses in the channel. It must be different from the user's UID.
  • The UID of the user the agent talks to.
  • A value for each required variable that you defined when you created the agent, such as customer_name.

Load the saved agent and call create_session().

from agora_agent import SavedAgent

saved_agent = SavedAgent.get(client, "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10")
session = saved_agent.create_session(
    channel="<your_channel_name>",
    token="<your_rtc_token>",
    agent_uid="1002",
    remote_uids=["1001"],
    values={"customer_name": "Ada"},
)

session_id = session.start()
print(session_id)  # The agent_session_id

Load the saved agent and call createSession().

import { SavedAgent } from 'agora-agents';

const savedAgent = await SavedAgent.get(client, '3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10');
const session = savedAgent.createSession({
  channel: '<your_channel_name>',
  token: '<your_rtc_token>',
  agentUid: '1002',
  remoteUids: ['1001'],
  values: { customer_name: 'Ada' },
});

const sessionId = await session.start();
console.log(sessionId); // The agent_session_id

Load the saved agent and call CreateSession().

savedAgent, err := agentkit.GetSavedAgent(ctx, client, "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10")
if err != nil {
	log.Fatal(err)
}
session := savedAgent.CreateSession(agentkit.CreateSessionOptions{
	Channel:    "<your_channel_name>",
	Token:      "<your_rtc_token>",
	AgentUID:   "1002",
	RemoteUIDs: []string{"1001"},
	Values:     map[string]any{"customer_name": "Ada"},
})

sessionID, err := session.Start(ctx)
if err != nil {
	log.Fatal(err)
}
fmt.Println(sessionID) // The agent_session_id

Send a request to Start a session. In transport, set:

  • type: rtc, to run the session in an RTC channel. To run the session in a phone call, you use telephony instead. For details, see Make outbound calls and run campaigns.
  • channel: The RTC channel for the conversation.
  • token: The RTC token for the agent's UID.
  • uid: The UID the agent uses in the channel, as a string or an integer. It must be different from the user's UID. If you omit it, Agora assigns one.
  • subscribe_uids: The UID of the user the agent talks to, as a string or an integer.

In values, pass the variable values.

In the Idempotency-Key header, pass a unique value for each session you start. If a request times out, retry it with the same key and the same body. If the first request already started the session, the retry fails with 409 IdempotencyKeyConflict instead of starting a second one. To get the session ID, list sessions filtered by your channel.

curl --request POST \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/sessions \
  --header 'Authorization: Basic <your_base64_encoded_credentials>' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: <your_unique_key>' \
  --data '
{
  "agent_id": "3f6c2a9e-8d1b-4e7a-9c55-0b2f7d1e4a10",
  "values": {
    "customer_name": "Ada"
  },
  "transport": {
    "type": "rtc",
    "channel": "<your_channel_name>",
    "token": "<your_rtc_token>",
    "uid": "1002",
    "subscribe_uids": ["1001"]
  }
}'

If the request is successful, the response contains the session ID and its status:

// 200 OK
{
  "agent_session_id": "a42ac95tp25py49fc37hp94vm67ht52h",
  "create_ts": 1737111452,
  "status": "RUNNING"
}

Store the session ID. You use it to check and stop the session.

Check the session status

A session starts asynchronously. Starting a session successfully confirms that the session exists, not that the agent has joined the channel. To follow the session, retrieve it with its session ID:

info = client.v3.sessions.get(agent_session_id="<agent_session_id>")
print(info["status"])

If you still have the session object from Start a session, you can call session.get_info() instead.

const info = await client.v3.sessions.get({ agentSessionId: '<agent_session_id>' });
console.log(info.status);

If you still have the session object from Start a session, you can call await session.getInfo() instead.

info, err := client.V3.Sessions.Get(ctx, "<agent_session_id>")
if err != nil {
	log.Fatal(err)
}
fmt.Println(info.Body.Status)

If you still have the session object from Start a session, you can call session.GetInfo(ctx) instead.

Send a request to Retrieve a session:

curl --request GET \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/sessions/<agent_session_id> \
  --header 'Authorization: Basic <your_base64_encoded_credentials>'

When the agent is in the channel, the response looks like this:

// 200 OK
{
  "agent_session_id": "a42ac95tp25py49fc37hp94vm67ht52h",
  "status": "RUNNING",
  "start_ts": 1735035893,
  "message": "ok"
}

When the agent is in the channel, status is RUNNING. A session has one of the following statuses:

StatusDescription
IDLEThe session is idle.
STARTINGThe session is starting, and the agent hasn't joined the channel yet.
RUNNINGThe agent is in the channel.
STOPPINGThe session is stopping.
STOPPEDThe session has ended, and the agent has left the channel.
FAILEDThe session failed. Check message for the reason.

Stop the session

When the conversation ends, stop the session with its session ID. The agent leaves the channel.

client.v3.sessions.stop(agent_session_id="<agent_session_id>")

If you still have the session object from Start a session, you can call session.stop() instead.

await client.v3.sessions.stop({ agentSessionId: '<agent_session_id>' });

If you still have the session object from Start a session, you can call await session.stop() instead.

if _, err := client.V3.Sessions.Stop(ctx, "<agent_session_id>"); err != nil {
	log.Fatal(err)
}

If you still have the session object from Start a session, you can call session.Stop(ctx) instead.

Send a request to Stop a session without a body:

curl --request POST \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/sessions/<agent_session_id>/stop \
  --header 'Authorization: Basic <your_base64_encoded_credentials>'

If the request is successful, the response is an empty JSON object:

// 200 OK
{}

A session also stops asynchronously. To confirm that the session has ended, retrieve it and check that status is STOPPED. If you don't stop a session, it ends when it reaches a lifecycle limit. By default, a session ends 30 seconds after no participant is present, or 5 minutes after it starts. You can set lifecycle.max_duration_ms up to 1 hour when you start the session.

Test a configuration without saving an agent

To try a configuration before you save it, start an ephemeral session. You pass the agent configuration instead of an agent ID, and the Platform doesn't save the configuration.

Call create_session() on an Agent instead of a saved agent. The SDK starts an ephemeral session when you set a Platform session option, such as max_duration in seconds.

from agora_agent import Agent, DeepgramSTT, OpenAI, OpenAITTS

test_agent = (
    Agent(client=client)
    .with_stt(DeepgramSTT(model="nova-3", language="en-US"))
    .with_llm(
        OpenAI(
            model="gpt-4.1-mini",
            system_messages=[
                {"role": "system", "content": "You are a friendly support agent for Acme. Keep your answers short."}
            ],
            greeting_message="Hi, how can I help you today?",
            greeting_configs={"on": "each_join"},
        )
    )
    .with_tts(OpenAITTS(model="tts-1", voice="alloy"))
)

session = test_agent.create_session(
    channel="<your_channel_name>",
    token="<your_rtc_token>",
    agent_uid="1002",
    remote_uids=["1001"],
    max_duration=600,
)
session_id = session.start()

Call createSession() on an Agent instead of a saved agent. The SDK starts an ephemeral session when you set a Platform session option, such as maxDuration in seconds.

import { Agent, DeepgramSTT, OpenAI, OpenAITTS } from 'agora-agents';

const testAgent = new Agent({ client })
  .withStt(new DeepgramSTT({ model: 'nova-3', language: 'en-US' }))
  .withLlm(
    new OpenAI({
      model: 'gpt-4.1-mini',
      systemMessages: [
        { role: 'system', content: 'You are a friendly support agent for Acme. Keep your answers short.' },
      ],
      greetingMessage: 'Hi, how can I help you today?',
      greetingConfigs: { on: 'each_join' },
    }),
  )
  .withTts(new OpenAITTS({ model: 'tts-1', voice: 'alloy' }));

const session = testAgent.createSession({
  channel: '<your_channel_name>',
  token: '<your_rtc_token>',
  agentUid: '1002',
  remoteUids: ['1001'],
  maxDuration: 600,
});
const sessionId = await session.start();

Call CreateSession() on an Agent instead of a saved agent. The SDK starts an ephemeral session when you set a Platform session option, such as MaxDuration in seconds.

testAgent := agentkit.NewAgent(client).
	WithStt(vendors.NewDeepgramSTT(vendors.DeepgramSTTOptions{Model: "nova-3", Language: "en-US"})).
	WithLlm(vendors.NewOpenAI(vendors.OpenAIOptions{
		Model: "gpt-4.1-mini",
		SystemMessages: []map[string]interface{}{
			{"role": "system", "content": "You are a friendly support agent for Acme. Keep your answers short."},
		},
		GreetingMessage: "Hi, how can I help you today?",
		GreetingConfigs: map[string]interface{}{"on": "each_join"},
	})).
	WithTts(vendors.NewOpenAITTS(vendors.OpenAITTSOptions{Model: "tts-1", Voice: "alloy"}))

maxDuration := 600
session := testAgent.CreateSession(agentkit.CreateSessionOptions{
	Channel:     "<your_channel_name>",
	Token:       "<your_rtc_token>",
	AgentUID:    "1002",
	RemoteUIDs:  []string{"1001"},
	MaxDuration: &maxDuration,
})
sessionID, err := session.Start(ctx)
if err != nil {
	log.Fatal(err)
}

Send a request to Start an ephemeral session. The request is the same as Start a session, but you pass the agent configuration in agent instead of agent_id.

curl --request POST \
  --url https://preview.ai.agora.io/conversational-ai/v1/projects/<your_app_id>/sessions/ephemeral \
  --header 'Authorization: Basic <your_base64_encoded_credentials>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "agent": {
    "instructions": "You are a friendly support agent for Acme. Keep your answers short.",
    "greeting": {
      "mode": "text",
      "on": "each_join",
      "text": "Hi, how can I help you today?"
    },
    "pipeline": {
      "mode": "cascaded",
      "asr": { "credential": { "mode": "managed" }, "vendor": "deepgram", "model": "nova-3", "language": "en-US" },
      "llm": { "credential": { "mode": "managed" }, "vendor": "openai", "style": "openai", "model": "gpt-4.1-mini" },
      "tts": {
        "credential": { "mode": "managed" },
        "vendor": "minimax",
        "params": { "model": "speech-2.6-turbo", "voice_setting": { "voice_id": "English_captivating_female1", "speed": 1 } }
      }
    }
  },
  "transport": {
    "type": "rtc",
    "channel": "<your_channel_name>",
    "token": "<your_rtc_token>",
    "uid": "1002",
    "subscribe_uids": ["1001"]
  }
}'

The response has the same format as Start a session.

Check and stop an ephemeral session the same way as any other session.

When the configuration works as you want, save it with Create an agent, or apply it to an existing agent with Update an agent.

Reference

For more information, see the following pages:

API reference