A custom LLM agent hands every conversational decision to a server you run. Tried still handles the phone line, speech recognition, turn-taking, interruptions, text to speech, recording and post-call analysis. Your server receives the live transcript over a WebSocket and streams back the words the agent should say.
The protocol is wire-compatible with Retell's custom LLM WebSocket. A server written for Retell works against Tried without code changes.
When to use a custom LLM#
Use a custom LLM when the built-in engines do not give you enough control:
- You already have an agent framework (LangChain, your own orchestration, a fine-tuned model) and want to put a phone line in front of it.
- Your replies depend on systems that are easier to reach from your own network than from a tool call.
- You need full control of prompts, retrieval, memory and tool execution per turn.
- You want to use a model Tried does not offer in its model list.
If a prompt plus functions is enough, a single or multi-prompt agent built in the dashboard is simpler to run, and you get the Test LLM playground and simulation tests with it. Custom LLM agents do not use those (see Testing a custom LLM).
How a call works#
The call starts#
A phone or web call is created for an agent whose response_engine.type is custom-llm. The voice worker opens a WebSocket to {llm_websocket_url}/{call_id}.
Your server configures the session#
Within half a second your server can send a config frame. It turns on auto_reconnect (pings every 2 seconds) and call_details (the worker then sends you the call object).
The agent speaks first, or waits#
If your server sends a response with response_id: 0 before the first request, the agent says it as the opening line. Otherwise the agent waits for the caller.
Every turn#
Each time a user or agent utterance is final, the worker sends update_only with the full transcript. When the caller finishes a turn, it sends response_required with a new response_id. Your server streams response frames for that id until content_complete: true.
Actions#
A response can set end_call, transfer_number or digit_to_press. Your server can also push agent_interrupt (speak without being asked), update_agent and tool call events at any time.
The call ends#
The socket closes when the call ends. If the socket fails, the call ends with one of the error_llm_websocket_* disconnection reasons.
Create a custom LLM agent#
In the dashboard#
Open Create an Agent#
On Agents, open the Create an Agent menu and choose Custom LLM agent. The Create agent modal opens with the Custom LLM type ("Your own LLM server over WebSocket.") selected.
Enter the WebSocket URL#
Fill in LLM WebSocket URL. It must start with ws:// or wss://. Do not add the call id: Tried appends /{call_id} for every call.
Configure the rest of the agent#
The custom LLM builder shows the LLM WebSocket card, a Protocol card you can copy, the voice and language pickers, and the usual settings panel (speech, call handling, analysis). The Functions, Knowledge Base and dynamic variable sections are hidden, because your server owns those.
Test the connection and publish#
Use Test connection (see Testing a custom LLM), then Publish and attach the agent to a number.
With the API#
Create an agent with a custom-llm response engine:
curl -X POST https://api.tried.com.au/create-agent \
-H "Authorization: Bearer $TRIED_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_name": "Own LLM (WebSocket)",
"voice_id": "11labs-Adrian",
"response_engine": {
"type": "custom-llm",
"llm_websocket_url": "wss://llm.example.com/llm-websocket"
}
}'| Field | Type | Description |
|---|---|---|
response_engine.type |
"custom-llm" |
Selects the WebSocket engine. |
response_engine.llm_websocket_url |
string | Base URL of your server. The worker connects to {llm_websocket_url}/{call_id}. |
All other agent fields (voice, language, responsiveness, interruption_sensitivity, reminder_trigger_ms, reminder_max_count, post-call analysis, webhooks) behave as they do for any agent. Use the voice id of a voice in your workspace.
What Tried does and what your server does#
| Tried | Your server |
|---|---|
| Telephony, SIP, web calls, recording | Prompting and model choice |
| Speech recognition and end-of-turn detection | Deciding what to say each turn |
| Interruption handling and barge-in | Calling your own tools and APIs |
| Text to speech and voice settings | Retrieval and memory |
Reminders after silence (asks your server via reminder_required) |
The wording of reminders |
Executing end_call, transfer_number, digit_to_press |
Deciding when to end, transfer or press digits |
| Transcript, latency, post-call analysis, webhooks | Optional tool call events for the transcript |
Limits and defaults#
| Item | Value |
|---|---|
Ping interval (with auto_reconnect) |
2 seconds |
| Reconnect when no ping arrives for | 5 seconds |
| Reconnect attempts per call | 2 |
Wait for your config frame after connecting |
0.5 seconds |
| Wait between frames of one response before the call fails | 30 seconds |
| Frame format | JSON text frames |