All fields are required
Prompting is negotiation. State machines are software. Build voice AI agents with scoped prompts, scoped tools, and enforced transitions.
A 2,000-word system prompt forces the model to decide which instructions apply right now. It guesses wrong. It skips steps. It uses tools from the wrong phase.
The task looks complex because the entire agent lives in one prompt. You pay for GPT-4 when a cheaper model would handle each step on its own.
You cannot unit test a blob of prose. You cannot diff two versions meaningfully. You cannot tell an auditor which instruction applied to a given call.
The greeting step can see the payment tools. The model decides whether to respect boundaries. In production, it sometimes does not.
from signalwire_agents import AgentBase
from signalwire_agents.core.function_result import SwaigFunctionResult
class SupportAgent(AgentBase):
def __init__(self):
super().__init__(name="Support Agent", route="/support")
self.prompt_add_section("Instructions",
body="You are a customer support agent. "
"Greet the caller and resolve their issue.")
self.add_language("English", "en-US", "rime.spore:mistv2")
@AgentBase.tool(name="check_order")
def check_order(self, order_id: str):
"""Check the status of a customer order.
Args:
order_id: The order ID to look up
"""
return SwaigFunctionResult(f"Order {order_id}: shipped, ETA April 2nd")
agent = SupportAgent()
agent.run()
| Concern | Monolithic Prompt | Programmable Agent |
|---|---|---|
| Tool access | All tools visible to all phases | Scoped per step; greeting cannot see payment tools |
| Prompt length | 2,000+ words, conflicting instructions | Short, focused prompt per step |
| Model cost | Expensive model for every turn | Cheap model for greetings, capable model for reasoning |
| Testing | Not possible (probabilistic blob) | Step-level unit tests with defined inputs and outputs |
| Audit trail | Guessing which instruction applied | Structured log: step, tool call, transition, parameters |
| Rollback | Find the old prompt somewhere | git revert |
Each step has its own prompt describing one task. The model sees only what it needs for the current phase. No conflicting instructions, no ambiguity.
Tools are bound per step. The model in the greeting step cannot access payment tools. Those tools do not exist in its context.
The platform validates and executes transitions between steps. The model chooses which allowed path to take; the platform enforces the boundary.
Sensitive data is available to tool functions but invisible to the LLM context window. The model cannot leak what it cannot see.
greeting > identify_patient > check_availability > confirm_booking > farewell
greeting > authenticate > lookup_order > resolve_issue > confirm_action > farewell (with branch to transfer_specialist)
greeting > verify_identity > present_balance > collect_payment > confirm > farewell (with branch to payment_failed > retry_or_transfer)
Yes. The platform integrates with multiple LLM providers. You can assign different models to different steps based on complexity and cost.
Each step sends a short, focused prompt instead of the entire agent definition. Fewer tokens per turn means lower inference cost. You can also use cheaper models for routine steps like greetings.
It cannot. The platform enforces transitions. The model can only move to steps defined as valid transitions from the current step.
Each step is an isolated unit with defined inputs, tools, and transitions. Write unit tests for individual steps and integration tests for the full conversation flow. Deploy through your existing CI/CD pipeline.
Tool functions can access sensitive data (account numbers, balances, PII) without exposing it to the LLM context window. The model requests data through tools; your code decides what to return.
Trusted by 2,000+ companies
Define steps. Scope tools. Enforce transitions. Ship agents you can test and audit.