Patter SDK-Leitfaden zum Aufbau eines Telefonagenten für Restaurantbuchungen mit dynamischen Variablen, Leitplanken, Latenz-Dashboards und Bewertungsprüfungen


In diesem Tutorial erkunden wir das Prasseln SDK durch den Aufbau eines Sprachagenten-Workflows, der simuliert, wie sich ein KI-Telefonassistent bei echten Gesprächen verhält. Wir arbeiten mit einem Anwendungsfall für eine Restaurantbuchung, in dem wir dynamische Anrufervariablen definieren, aufrufbare Instruments registrieren, Ausgaberichtlinien anwenden, Sprache-zu-Textual content- und Textual content-zu-Sprache-Verhalten simulieren und einen vollständigen skriptgesteuerten Anrufablauf ausführen, ohne dass Anmeldeinformationen für die Stay-Telefonie erforderlich sind. Wir überprüfen auch die installierte Patter-API, sofern verfügbar, erstellen ein deterministisches Agentengehirn, verfolgen modellierte Latenz- und Kostenmetriken und validieren das System durch Auswertungen im Regressionsstil. Schließlich verstehen wir, wie das Patter SDK Agentenlogik, Software-Nutzung, Sicherheitsüberprüfungen, Anrufsimulation und reale Bereitstellungsmuster in eine einzige strukturierte Sprachagenten-Pipeline integriert.

from __future__ import annotations
import sys, subprocess, importlib, examine, time, json, re, random, textwrap, os
from dataclasses import dataclass, subject
from statistics import median
def _try_install(pkg: str) -> None:
   attempt:
       subprocess.run((sys.executable, "-m", "pip", "set up", "-q", pkg),
                      test=False, timeout=600)
   besides Exception:
       go
def _load_patter():
   """Return the actual getpatter module if importable, else None."""
   for title in ("patter", "getpatter"):
       attempt:
           return importlib.import_module(title)
       besides Exception:
           proceed
   return None
_PATTER = _load_patter()
if _PATTER is None:
   _try_install("getpatter")
   _PATTER = _load_patter()
def show_real_api():
   """Print the *precise* put in Patter API so the tutorial adapts to
   no matter model Colab pulled (getpatter is younger & strikes weekly)."""
   print("=" * 74)
   print("PATTER SDK — put in API")
   print("=" * 74)
   if _PATTER is None:
       print("getpatter not importable on this kernel (that is wonderful — then"
             "Colab demo beneath is self-contained). On a recent Colab it willn"
             "`pip set up getpatter` and this block prints the stay API.n")
       return
   print(f"module   : {_PATTER.__name__}")
   print(f"model  : {getattr(_PATTER, '__version__', 'unknown')}")
   exported = (n for n in dir(_PATTER) if not n.startswith('_'))
   print("exports  :", ", ".be part of(exported(:24)) + (" ..." if len(exported) > 24 else ""))
   Patter = getattr(_PATTER, "Patter", None)
   if Patter just isn't None:
       for meth in ("__init__", "agent", "serve", "name", "take a look at", "software"):
           fn = getattr(Patter, meth, None)
           if callable(fn):
               attempt:
                   print(f"Patter.{meth:<8}: {examine.signature(fn)}")
               besides (TypeError, ValueError):
                   print(f"Patter.{meth:<8}: <builtin/!signature>")
   print()
random.seed(7)
CALL_VARIABLES = {
   "customer_name": "Priya",
   "loyalty_tier":  "Gold",
   "restaurant":    "Acme Bistro",
}
USE_REAL_LLM = False
TOOLS: dict(str, dict) = {}
def software(description: str):
   def deco(fn):
       params = (p for p in examine.signature(fn).parameters)
       TOOLS(fn.__name__) = {"fn": fn, "description": description, "params": params}
       return fn
   return deco
import copy
_OPEN_TABLES_INIT = {
   ("as we speak", "night"): 6, ("as we speak", "late"): 2,
   ("tomorrow", "lunch"): 8, ("tomorrow", "night"): 4,
   ("friday", "night"): 0, ("friday", "late"): 3,
}
_RES_DB_INIT = {"AC8842": "Desk for two, tomorrow 7:30pm, beneath Singh — confirmed."}
_HOURS = {"weekday": "11:00–22:00", "weekend": "10:00–23:00"}
_OPEN_TABLES = copy.deepcopy(_OPEN_TABLES_INIT)
_RES_DB = copy.deepcopy(_RES_DB_INIT)
def _reset_backend():
   """Every simulated name begins from a clear backend (an actual name hits a
   recent DB connection). Retains the eval suite deterministic throughout runs."""
   _OPEN_TABLES.clear(); _OPEN_TABLES.replace(copy.deepcopy(_OPEN_TABLES_INIT))
   _RES_DB.clear();      _RES_DB.replace(copy.deepcopy(_RES_DB_INIT))
@software("Examine whether or not tables are free for a date/time slot and occasion dimension.")
def check_availability(date: str, slot: str, party_size: int) -> str:
   seats = _OPEN_TABLES.get((date, slot), 0)
   if seats >= party_size:
       return f"AVAILABLE: {seats} seats open for {date} {slot}."
   return f"FULL: solely {seats} seats for {date} {slot} (want {party_size})."
@software("E book a desk and return a affirmation code.")
def book_table(title: str, date: str, slot: str, party_size: int) -> str:
   seats = _OPEN_TABLES.get((date, slot), 0)
   if seats < party_size:
       return f"FAILED: not sufficient seats for {party_size} on {date} {slot}."
   _OPEN_TABLES((date, slot)) = seats - party_size
   code = "AC" + str(random.randint(1000, 9999))
   _RES_DB(code) = f"Desk for {party_size}, {date} {slot}, beneath {title}."
   return f"BOOKED: code {code} — occasion {party_size}, {date} {slot}, {title}."
@software("Return opening hours for a given day kind.")
def get_hours(day_type: str) -> str:
   return _HOURS.get(day_type, _HOURS("weekday"))
@software("Search for an present reservation by its affirmation code.")
def lookup_reservation(code: str) -> str:
   return _RES_DB.get(code.higher(), "NOT_FOUND: no reservation with that code.")
@software("Hand the decision to a human host (Patter auto-injects transfer_call).")
def transfer_to_human(purpose: str) -> str:
   return f"TRANSFER: routing to a number — purpose: {purpose}."

Wir richten die Tutorial-Umgebung ein, indem wir die erforderlichen Bibliotheken importieren, non-obligatory das Patter SDK installieren und die installierte API überprüfen, wenn sie verfügbar ist. Wir definieren die dynamischen Anrufervariablen, erstellen eine kleine Software-Registrierung und bereiten ein In-Reminiscence-Restaurant-Backend für Verfügbarkeit, Reservierungen, Öffnungszeiten und Transfers vor. Wir registrieren auch die Kerntools, die es unserem simulierten Telefonagenten ermöglichen, Tische zu überprüfen, Reservierungen zu buchen, Bestätigungscodes nachzuschlagen und Anrufer an einen Menschen weiterzuleiten.

Hinzufügen von Ausgabeleitplanken und simulierten Sprachebenen

class GuardrailBlock(Exception):
   def __init__(self, safe_reply: str):
       self.safe_reply = safe_reply
_PII_EMAIL = re.compile(r"b(w.+-)+@(w-)+.(w.-)+b")
_PII_PHONE = re.compile(r"b(?:+?d(s-)?){9,13}db")
_INTERNAL  = re.compile(r"bCUST-d{4,}b")
_BANNED    = re.compile(r"b(rattling|hell|crap)b", re.I)
_OFFTOPIC  = re.compile(r"b(diagnos|prescri|lawsuit|authorized recommendation|treatment)b", re.I)
def gr_redact_pii(textual content: str, ctx: dict) -> str:
   textual content = _PII_EMAIL.sub("(e-mail hidden)", textual content)
   textual content = _PII_PHONE.sub("(quantity hidden)", textual content)
   return textual content
def gr_hide_internal_ids(textual content: str, ctx: dict) -> str:
   return _INTERNAL.sub("your account", textual content)
def gr_profanity(textual content: str, ctx: dict) -> str:
   return _BANNED.sub("—", textual content)
def gr_scope(textual content: str, ctx: dict) -> str:
   if _OFFTOPIC.search(textual content):
       increase GuardrailBlock("I am simply the reserving line, so I can not assist with "
                            "that — however I can take a reservation in the event you like.")
   return textual content
def gr_concise(textual content: str, ctx: dict) -> str:
   elements = re.cut up(r"(?<=(.!?))s+", textual content.strip())
   return " ".be part of(elements(:2)) if len(elements) > 2 else textual content
GUARDRAILS = (gr_scope, gr_hide_internal_ids, gr_redact_pii, gr_profanity, gr_concise)
def apply_guardrails(textual content: str, ctx: dict) -> str:
   for g in GUARDRAILS:
       textual content = g(textual content, ctx)
   return textual content
_WHISPER_FILLERS = {"you", "thanks", ".", "uh", "um"}
def fake_stt(utterance: str) -> tuple(str, float):
   """Return (transcript, latency_ms). Drops Whisper-style fillers like Patter's pipeline does."""
   t0 = time.perf_counter()
   tokens = (w for w in utterance.cut up() if w.decrease().strip(".,") not in _WHISPER_FILLERS)
   transcript = " ".be part of(tokens) if tokens else utterance
   lat = 60 + len(utterance) * 1.5 + random.uniform(0, 25)
   _spin(t0)
   return transcript, lat
def fake_tts(textual content: str) -> float:
   """Return synthesis latency_ms (time-to-first-audio-ish)."""
   return 90 + len(textual content) * 0.8 + random.uniform(0, 30)
def _spin(_t0):
   go
SYSTEM_PROMPT = (
   "You're the pleasant telephone host for {restaurant}. Caller: {customer_name} "
   "({loyalty_tier} member). Assist them ebook, test hours, lookup a "
   "reservation, or attain a human. Hold replies to at least one or two quick sentences."
)
FIRST_MESSAGE = "Hello {customer_name}, thanks for calling {restaurant}! How can I assist?"
def _fill(t: str, v: dict) -> str:
   for okay, val in v.gadgets():
       t = t.exchange("{" + okay + "}", str(val))
   return t
def parse_party(s: str):
   m = re.search(r"(?:for|occasion of|desk for|of)s+(d+)", s) or re.search(r"b(d+)s*(?:folks|visitors|of us|pax)", s)
   if m: return int(m.group(1))
   for w, n in _NUM.gadgets():
       if re.search(rf"b{w}b(?:s+(?:folks|visitors|of us))?", s): return n
   return None
def parse_date(s: str):
   for d in ("as we speak", "tonight", "tomorrow", "friday"):
       if d in s: return "as we speak" if d == "tonight" else d
   return None
def parse_slot(s: str):
   if re.search(r"b(lunch|midday|noon)b", s): return "lunch"
   if re.search(r"b(late|11pm|11 pm|after 10)b", s): return "late"
   if re.search(r"b(dinner|night|tonight|7|8|9|pm)b", s): return "night"
   return None
def parse_name(s: str):
   m = re.search(r"(?:i'?m|that is|title is|beneath)s+((A-Z)(a-z)+)", s)
   return m.group(1) if m else None
def parse_code(s: str):
   m = re.search(r"b(ACd{3,4})b", s.higher())
   return m.group(1) if m else None
def maybe_real_llm(historical past, user_text, ctx):
   """Optionally available: defer freeform small-talk to an actual LLM if USE_REAL_LLM + a key.
   Returns a string or None. Stored tiny and absolutely non-obligatory."""
   if not USE_REAL_LLM:
       return None
   attempt:
       if os.environ.get("OPENAI_API_KEY"):
           from openai import OpenAI
           sys_p = _fill(SYSTEM_PROMPT, ctx("vars"))
           msgs = ({"position": "system", "content material": sys_p}) + historical past + 
                  ({"position": "consumer", "content material": user_text})
           r = OpenAI().chat.completions.create(mannequin="gpt-4o-mini", messages=msgs, max_tokens=60)
           return r.selections(0).message.content material
   besides Exception:
       return None
   return None

Wir erstellen die Ausgabeleitplankenschicht, die dafür sorgt, dass der Telefonassistent sicher, prägnant und für den Buchungsanwendungsfall geeignet ist. Wir redigieren vertrauliche Informationen, verbergen interne Kunden-IDs, bereinigen unerwünschte Sprache, blockieren themenfremde Anfragen und halten die Antworten für ein besseres Telefonerlebnis kurz. Anschließend simulieren wir das Sprach-zu-Textual content- und Textual content-zu-Sprache-Verhalten, definieren die Systemaufforderung und fügen einfache Parsing-Funktionen für Gruppengröße, Datum, Zeitfenster, Identify und Reservierungscode hinzu.

Aufbau des Agentengehirns und Anrufsimulators

def agent_brain(historical past: listing, user_text: str, ctx: dict):
   """Core logic. `ctx` carries vars + slot state throughout turns."""
   s = user_text.decrease()
   st = ctx("state")
   if re.search(r"b(human|agent|consultant|supervisor|individual)b", s):
       return ("__tool__", "transfer_to_human", {"purpose": "caller requested a human"})
   if st.get("booked") and re.search(r"b(no|nope|that'?s all|that'?s it|bye|thanks|thanks)b", s):
       return "Thanks for calling — see you quickly!"
   if re.search(r"b(climate|inventory|joke|treatment|lawsuit)b", s):
       return "I am simply the reserving line for tonight's tables — need me to seize you one?"
   code = parse_code(s)
   if code or "lookup" in s or "my reservation" in s:
       if code:
           return ("__tool__", "lookup_reservation", {"code": code})
       st("intent") = "lookup"
       return "Positive — what's your affirmation code? It appears to be like like AC adopted by 4 digits."
   if re.search(r"b(hours|open|shut|closing)b", s):
       day_type = "weekend" if re.search(r"b(sat|solar|weekend)b", s) else "weekday"
       return ("__tool__", "get_hours", {"day_type": day_type})
   if re.search(r"b(ebook|reserve|desk|reservation)b", s) or st.get("intent") == "ebook":
       st("intent") = "ebook"
   if st.get("intent") == "ebook":
       for key, val in (("party_size", parse_party(s)), ("date", parse_date(s)),
                        ("slot", parse_slot(s)), ("title", parse_name(user_text) or st.get("title"))):
           if val just isn't None:
               st(key) = val
       if st.get("party_size") is None:
           return "Completely happy to ebook you in — how many individuals?"
       if st.get("date") is None:
           return f"Nice, a desk for {st('party_size')}. Which day — as we speak, tomorrow, or Friday?"
       if st.get("slot") is None:
           return "And lunch, dinner, or late seating?"
       if not st.get("checked"):
           st("checked") = True
           return ("__tool__", "check_availability",
                   {"date": st("date"), "slot": st("slot"), "party_size": st("party_size")})
       if st.get("title") is None:
           return "What title ought to I put it beneath?"
       if not st.get("booked"):
           st("booked") = True
           return ("__tool__", "book_table",
                   {"title": st("title"), "date": st("date"),
                    "slot": st("slot"), "party_size": st("party_size")})
       return "You are all set — anything?"
   if re.search(r"b(no|nope|that is all|bye|thanks)b", s):
       return "Thanks for calling — see you quickly!"
   return maybe_real_llm(historical past, user_text, ctx) or 
       "I can ebook a desk, test hours, or lookup a reservation — which might you want?"
def fold_tool_result(tool_name: str, uncooked: str, ctx: dict) -> str:
   """Flip a uncooked software outcome right into a pure spoken reply (what the LLM does
   with a function-call outcome on an actual Patter name)."""
   if tool_name == "check_availability":
       if uncooked.startswith("AVAILABLE"):
           return "Excellent news — that slot's open. What title ought to I put it beneath?"
       ctx("state")("checked") = False
       ctx("state")("slot") = None
       return "That one's full, sorry. Would one other time work — lunch or late seating?"
   if tool_name == "book_table" and uncooked.startswith("BOOKED"):
       code = uncooked.cut up("code ")(1).cut up(" ")(0)
       return f"Booked! Your affirmation code is {code}. The rest?"
   if tool_name == "get_hours":
       return f"We're open {uncooked}. Need me to order a desk?"
   if tool_name == "lookup_reservation":
       return ("Right here it's: " + uncooked) if not uncooked.startswith("NOT_FOUND") 
           else "I could not discover that code — may you learn it as soon as extra?"
   if tool_name == "transfer_to_human":
       return "In fact — connecting you to a number now. One second!"
   return uncooked
@dataclass
class Flip:
   speaker: str
   textual content: str
   stt_ms: float = 0.0
   llm_ms: float = 0.0
   tool_ms: float = 0.0
   tts_ms: float = 0.0
   software: str | None = None
   @property
   def total_ms(self): return self.stt_ms + self.llm_ms + self.tool_ms + self.tts_ms
@dataclass
class CallResult:
   transcript: listing = subject(default_factory=listing)
   turns: listing = subject(default_factory=listing)
def run_call(caller_lines: listing(str), variables: dict, barge_in_at: int | None = None) -> CallResult:
   _reset_backend()
   ctx = {"vars": dict(variables), "state": {}}
   historical past, res = (), CallResult()
   def communicate(textual content: str, llm_ms: float, software=None, tool_ms=0.0, truncate=None):
       t0 = time.perf_counter()
       attempt:
           protected = apply_guardrails(textual content, ctx)
       besides GuardrailBlock as b:
           protected = b.safe_reply
       if truncate:
           protected = protected.cut up()(:truncate)
           protected = " ".be part of(protected) + " —"
       gr_ms = (time.perf_counter() - t0) * 1000
       tts = fake_tts(protected)
       res.transcript.append(("agent", protected))
       res.turns.append(Flip("agent", protected, llm_ms=llm_ms + gr_ms,
                             software=software, tool_ms=tool_ms, tts_ms=tts))
       historical past.append({"position": "assistant", "content material": protected})
   communicate(_fill(FIRST_MESSAGE, ctx("vars")), llm_ms=5.0)
   for i, raw_line in enumerate(caller_lines):
       transcript, stt_ms = fake_stt(raw_line)
       res.transcript.append(("caller", transcript))
       historical past.append({"position": "consumer", "content material": transcript})
       t0 = time.perf_counter()
       out = agent_brain(historical past, transcript, ctx)
       llm_ms = (time.perf_counter() - t0) * 1000 + random.uniform(40, 120)
       truncate = 4 if (barge_in_at just isn't None and that i == barge_in_at) else None
       if isinstance(out, tuple) and out and out(0) == "__tool__":
           _, title, kwargs = out
           t1 = time.perf_counter()
           uncooked = TOOLS(title)("fn")(**kwargs)
           tool_ms = (time.perf_counter() - t1) * 1000 + random.uniform(10, 40)
           reply = fold_tool_result(title, uncooked, ctx)
           communicate(reply, llm_ms=llm_ms, software=title, tool_ms=tool_ms, truncate=truncate)
           res.turns(-1).stt_ms = stt_ms
       else:
           communicate(out, llm_ms=llm_ms, truncate=truncate)
           res.turns(-1).stt_ms = stt_ms
   return res

Wir implementieren das Gehirn des Hauptagenten, das den Gesprächsfluss über Buchung, Reservierungssuche, Fragen zu Öffnungszeiten, Personenvermittlung und Ersatzantworten steuert. Wir verwenden die analysierten Anrufereingaben und den gespeicherten Gesprächsstatus, um zu entscheiden, wann wir Folgefragen stellen, Instruments anrufen oder eine Reservierung abschließen möchten. Wir erstellen außerdem einen Anrufsimulator mit strukturierten Flip-Objekten, um skriptbasierte Gespräche durchzuführen und Latenz-, Software- und Transkriptdaten zu sammeln.

Drucken von Transkripten, Latenz-Dashboards und Regressionsauswertungen

def print_transcript(title: str, res: CallResult):
   print("n" + "─" * 74)
   print(f"📞  {title}")
   print("─" * 74)
   for who, txt in res.transcript:
       tag = "🤖 agent " if who == "agent" else "🧑 caller"
       print(f"{tag}│ {txt}")
def print_dashboard(res: CallResult):
   totals = (t.total_ms for t in res.turns)
   stt = (t.stt_ms for t in res.turns if t.stt_ms)
   llm = (t.llm_ms for t in res.turns)
   tts = (t.tts_ms for t in res.turns)
   tool_turns = (t for t in res.turns if t.software)
   def p95(xs): return sorted(xs)(max(0, int(len(xs) * 0.95) - 1)) if xs else 0
   price = sum(0.0009 for _ in stt) + sum(0.0004 for _ in res.turns) + sum(0.00018 * len(t.textual content) for t in res.turns)
   print("n  ┌─ Patter dashboard (modeled) ────────────────────────────┐")
   print(f"  │ agent turns        : {len(res.turns):<6}                             │")
   print(f"  │ software calls         : {len(tool_turns):<6} ({', '.be part of(t.software for t in tool_turns) or '—'})")
   print(f"  │ latency  p50 whole : {median(totals):6.0f} ms                          │")
   print(f"  │ latency  p95 whole : {p95(totals):6.0f} ms                          │")
   print(f"  │ STT avg / TTS avg  : {(sum(stt)/len(stt) if stt else 0):5.0f} ms / {(sum(tts)/len(tts) if tts else 0):5.0f} ms              │")
   print(f"  │ est. spend (illus.): ${price:5.3f}                              │")
   print("  └──────────────────────────────────────────────────────────┘")
def run_evals() -> bool:
   print("n" + "=" * 74)
   print("EVAL HARNESS — regression checks")
   print("=" * 74)
   instances, handed = (), 0
   def full_transcript(res): return " || ".be part of(f"{w}:{t}" for w, t in res.transcript)
   r1 = run_call(("I would prefer to ebook a desk", "4 of us", "tomorrow",
                  "dinner", "beneath Priya"), CALL_VARIABLES)
   ok1 = bool(re.search(r"affirmation code is ACd{4}", full_transcript(r1)))
   instances.append(("books a desk & returns a code", ok1))
   leak = apply_guardrails("Your document CUST-99812 exhibits VIP standing.", {"vars": {}, "state": {}})
   ok2 = "CUST-99812" not in leak and "your account" in leak
   instances.append(("guardrail hides inner CUST- ids", ok2))
   r3 = run_call(("are you able to give me treatment recommendation?"), CALL_VARIABLES)
   ok3 = "reserving line" in full_transcript(r3).decrease()
   instances.append(("refuses out-of-scope (medical)", ok3))
   r4 = run_call(("get me a human please"), CALL_VARIABLES)
   ok4 = any(t.software == "transfer_to_human" for t in r4.turns)
   instances.append(("transfers to a human on request", ok4))
   r5 = run_call(("ebook a desk", "two", "friday", "night"), CALL_VARIABLES)
   ok5 = "full" in full_transcript(r5).decrease() and "affirmation code" not in full_transcript(r5).decrease()
   instances.append(("handles a full slot gracefully", ok5))
   lengthy = apply_guardrails("One. Two. Three. 4.", {"vars": {}, "state": {}})
   ok6 = lengthy.depend(".") <= 2
   instances.append(("concise guardrail caps sentence depend", ok6))
   for title, okay in instances:
       handed += okay
       print(f"  ({'PASS' if okay else 'FAIL'})  {title}")
   print(f"n  {handed}/{len(instances)} handed")
   return handed == len(instances)

Wir formatieren die simulierten Anrufergebnisse in ein lesbares Transkript und ein Dashboard im Patter-Stil, das Agentenwechsel, Software-Anrufe, Latenz und geschätzte Ausgaben zusammenfasst. Wir bauen außerdem einen deterministischen Bewertungsrahmen auf, der prüft, ob der Agent Buchungen abschließt, interne IDs schützt, medizinische Anfragen außerhalb des Umfangs ablehnt, an einen Menschen weiterleitet, volle Zeitfenster bearbeitet und die Antworten prägnant hält. Wir verwenden diese Prüfungen, um zu überprüfen, ob sich der Telefon-Agent-Workflow zuverlässig verhält, bevor wir mit der tatsächlichen Bereitstellung fortfahren.

Wechseln Sie zu echten Anrufen mit Twilio und OpenAI Realtime

REAL_DEPLOYMENT = textwrap.dedent('''
   # ---- real_agent.py  (run OUTSIDE Colab; wants a paid provider + keys) ----
   # export TWILIO_ACCOUNT_SID=AC... ; export TWILIO_AUTH_TOKEN=...
   # export TWILIO_PHONE_NUMBER=+1...  ; export OPENAI_API_KEY=sk-...
   import asyncio
   from getpatter import Patter, Twilio, OpenAIRealtime
   telephone = Patter(provider=Twilio(), phone_number="+15550001234")
   # register the exact same instruments you examined above
   @telephone.software
   async def book_table(title: str, date: str, slot: str, party_size: int) -> str:
       ...  # your actual reserving backend
   agent = telephone.agent(
       engine=OpenAIRealtime(),                 # or pipeline: stt=DeepgramSTT(), tts=ElevenLabsTTS()
       system_prompt="You're the host for Acme Bistro. Caller: {customer_name}.",
       first_message="Hello {customer_name}, thanks for calling Acme Bistro!",
       variables={"customer_name": "Priya"},    # dynamic per-caller
       instruments=(book_table),
       guardrails=("no_pii", "stay_in_scope"),  # output guardrails
   )
   async def important():
       # inbound: tunnel=True spawns a Cloudflare tunnel + factors your quantity at it
       await telephone.serve(agent, tunnel=True, dashboard=True, recording=True)
       # outbound as a substitute:
       # await telephone.name(to="+15558675309", agent=agent, machine_detection=True)
   asyncio.run(important())
   # Or skip code totally and take a look at from a shell:  patter dev real_agent.py
''').strip()
def important():
   show_real_api()
   demoA = run_call(
       caller_lines=(
           "Hello, I would prefer to ebook a desk",
           "there will be 4 of us",
           "tomorrow",
           "for dinner",
           "put it beneath Priya",
           "no that is all, thanks",
       ),
       variables=CALL_VARIABLES,
   )
   print_transcript("Demo A — reserving (instruments + dynamic variables)", demoA)
   print_dashboard(demoA)
   demoB = run_call(
       caller_lines=(
           "what are your weekend hours?",
           "truly can I communicate to a human",
       ),
       variables=CALL_VARIABLES,
       barge_in_at=1,
   )
   print_transcript("Demo B — hours, barge-in & human switch", demoB)
   print_dashboard(demoB)
   all_green = run_evals()
   print("n" + "=" * 74)
   print("GRADUATE TO REAL CALLS  (copy into an area file — not Colab)")
   print("=" * 74)
   print(REAL_DEPLOYMENT)
   print("n✅ tutorial completed" + ("  •  evals inexperienced" if all_green else "  •  evals RED"))
if __name__ == "__main__":
   important()

Wir bereiten eine Bereitstellungsvorlage im Produktionsstil vor, die zeigt, wie dieselbe getestete Logik aus Colab in ein echtes Telefonagenten-Setup verschoben werden kann. Wir umfassen die Struktur für die Verwendung von Patter mit Twilio, OpenAI Realtime, registrierten Instruments, dynamischen Variablen, Leitplanken, eingehender Bereitstellung, Dashboard-Überwachung, Aufzeichnung und ausgehenden Anrufen. Anschließend führen wir das vollständige Tutorial durch, indem wir die installierte API zeigen, zwei Demo-Aufrufe ausführen, Dashboards drucken, Auswertungen ausführen und den endgültigen Code für die Bereitstellung bei echten Aufrufen anzeigen.

Abschluss

Abschließend haben wir einen vollständigen Telefonagenten-Workflow im Patter-Stil erstellt, der die Kernstruktur eines Produktions-Sprach-KI-Programs widerspiegelt. Wir haben Instruments zur Verfügbarkeitsprüfung, Tischreservierung, Reservierungssuche und Weiterleitung von Anrufern an Menschen erstellt und diese dann mit Leitplanken, skriptgesteuerten Gesprächen, simulierter Latenz, Dashboards und Bewertungsprüfungen kombiniert. Wir haben auch gesehen, wie dieselbe getestete Logik später von einer eigenständigen Colab-Simulation zu echten Telefonanrufen über Twilio, OpenAI Realtime, Tunneling und die Bereitstellungsschnittstelle von Patter übergehen kann. Außerdem haben wir am Ende ein umfassendes Verständnis davon erlangt, wie wir eine Sprachagentenanwendung prototypisieren, testen, überwachen und vorbereiten können, bevor wir sie mit der Stay-Telefoninfrastruktur verbinden.


Schauen Sie sich das an Vollständige Codes mit Pocket book hier. Sie können uns auch gerne weiter folgen Twitter und vergessen Sie nicht, bei uns mitzumachen 150k+ML SubReddit und Abonnieren Unser E-newsletter. Warten! Bist du im Telegram? Jetzt können Sie uns auch per Telegram kontaktieren.

Möchten Sie mit uns zusammenarbeiten, um Ihr GitHub-Repo ODER Ihre Hugging Face Web page ODER Produktveröffentlichung ODER Ihr Webinar usw. zu bewerben? Vernetzen Sie sich mit uns


Sana Hassan, Beratungspraktikantin bei Marktechpost und Twin-Diploma-Studentin am IIT Madras, ist leidenschaftlich daran interessiert, Technologie und KI zur Bewältigung realer Herausforderungen einzusetzen. Mit großem Interesse an der Lösung praktischer Probleme bringt er eine neue Perspektive in die Schnittstelle zwischen KI und realen Lösungen ein.

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert