Hoppa till navigering

Workflows som kod

Bygg, redigera och versionshantera agent-workflows med Python- och JavaScript-SDK:erna

Översikt

Ett workflow lagras som en graf med noder och kanter. Om du skriver grafen för hand måste du själv hålla kant-ID:n, edge_order-listor och villkorsobjekt konsekventa. Workflow-byggaren i Python- och JavaScript-SDK:erna låter dig beskriva samma graf med kedjade metodanrop. Den skapar sedan workflow-värdet som agents.create() och agents.update() redan accepterar.

Använd den för att:

  • Bygga ett workflow i kod och granska det som vilken annan kodändring som helst.
  • Läsa in en agents workflow, ändra en nod och skicka tillbaka det utan att påverka resten av grafen.
  • Lagra workflows som JSON i versionshantering och validera dem i CI.

Byggaren körs helt i SDK:n. Den anropar inga nya API-slutpunkter, och allt den bygger kan öppnas och redigeras i dashboardens visuella redigerare.

Krav

  • Python: paketet elevenlabs. Byggaren importeras från elevenlabs.agent_workflows.
  • JavaScript: paketet @elevenlabs/elevenlabs-js. Byggaren exporteras från paketets rot.

Bygg ett workflow

Objektet Workflow representerar startnoden. Varje verb lägger till en nod och returnerar den, så att du kan kedja nästa steg från den:

PythonJavaScriptLägger till
converse(id, prompt, **options)converse(id, prompt, options?)En subagentnod. Agenten håller en konversation med prompt tillagd i sina instruktioner.
tool(id, tool_ids, **options)tool(id, toolIds, options?)En dispatch tool-nod som kör de angivna verktygen.
transfer(id, destination, **options)transfer(id, destination, options?)En överföring till ett telefonnummer, en SIP URI eller en annan agent.
end(id="end")end(options?)En slutnod. Varje end() utan ID delar en och samma "end"-nod.

Routningsmetoderna avgör vilken kant som leder till nästa nod:

PythonJavaScriptSkapar
when(condition)when(condition)En villkorlig kant. En sträng är ett LLM-villkor; en Expr är ett uttryck.
on_success() / on_failure()onSuccess() / onFailure()En kant från en tool-nod, som följs när verktygsanropet lyckas eller misslyckas.
on_result(success=..., failure=...)onResult({ success, failure })Båda kanterna för verktygsresultat på en gång.
go_to(node)goTo(node)En kant till en nod som redan finns, för sammanslagningar och loopar.
up()up()Ingen kant. Returnerar noden som den aktuella kedjades från, så att du kan fortsätta kedja från den. Se Skriv ett workflow som en kedja.

Verb som anropas direkt på workflowet förgrenas från startnoden med en ovillkorlig kant. Det här exemplet dirigerar uppringare till en ordersökning, försöker identifieringen igen om sökningen misslyckas och överför VIP- eller frustrerade uppringare:

from elevenlabs import ElevenLabs
from elevenlabs.agent_workflows import Destination, Expr, Workflow
elevenlabs = ElevenLabs()
wf = Workflow()
triage = wf.converse("triage", "Greet the caller and find out why they're calling")
identify = triage.when("Caller wants to check an order").converse(
"identify", "Ask for the order number and the email on the account"
)
lookup = identify.when("Caller gave an order number").tool("lookup_order", ["tool_get_order"])
lookup.on_result(
success=lambda ok: ok.converse("resolve", "Explain the order status")
.when("Caller is satisfied")
.end(),
failure=lambda failed: failed.go_to(identify),
)
triage.when(Expr.variable("tier").eq("gold")).transfer("vip", Destination.agent("agent_vip"))
triage.when("Caller wants a human").transfer("human", Destination.phone("+15551234567"))
elevenlabs.conversational_ai.agents.update("agent_id", workflow=wf.build())

build() validerar hela grafen och returnerar request-modellen. Den:

  • Ger startnoden ID:t start_node, som API:t kräver.
  • Genererar kant-ID:n i formatet source__target.
  • Fyller i varje nods edge_order i den ordning du lade till kanterna.
  • Positionerar alla noder som saknar position, så att grafen visas från vänster till höger i den visuella redigeraren.

Skriv ett workflow som en kedja

up() returnerar noden som den aktuella kedjades från, så att du kan beskriva ett helt workflow i ett uttryck i stället för att spara varje nod i en variabel. Inom en enda kedja använder du go_to() / goTo() med ett nod-ID, eftersom det inte finns någon variabel att skicka:

wf = Workflow()
(
wf.converse("triage", "Find out why the customer is calling")
.when("Caller gave an order number")
.tool("lookup_order", ["tool_get_order"])
.on_result(
success=lambda ok: ok.converse("resolve", "Explain the order status").when("Customer is satisfied").end(),
failure=lambda failed: failed.go_to("triage"),
)
.up()
.when(Expr.variable("tier").eq("gold"))
.transfer("vip", Destination.agent("agent_vip_desk"))
)
elevenlabs.conversational_ai.agents.update("agent_id", workflow=wf.build())

För ett nodhandtag från wf.node(id) returnerar up() noden som den första inkommande kanten kommer från. För startnoden returnerar den startnoden.

Nodalternativ

Valfria inställningar anges som nyckelordsargument i Python och i ett avslutande alternativobjekt i JavaScript. Namnen motsvarar nodens fält i API:t:

NodPythonJavaScript
converselabel, tool_ids, knowledge_base, conversation_config, entry_behaviorlabel, toolIds, knowledgeBase, conversationConfig, entryBehavior
toolschema_overridesschemaOverrides
transfertransfer_type, custom_sip_headers, post_dial_digits, delay_ms, transfer_message, …transferType, customSipHeaders, postDialDigits, delayMs, transferMessage, …
endidid

Varje verb accepterar också position om du vill placera noden själv. Workflow(prevent_subagent_loops=True) i Python, eller new Workflow({ preventSubagentLoops: true }) i JavaScript, förhindrar att konversationen återvänder till en subagent som den redan har besökt.

triage = wf.converse(
"triage",
"Greet the caller and find out why they're calling",
label="Triage",
tool_ids=["tool_crm_search"],
entry_behavior="generate_immediately",
)
triage.when("Caller is a VIP").transfer(
"vip_desk",
Destination.agent("agent_vip_concierge"),
transfer_message="Connecting you to our VIP team",
delay_ms=500,
)
identify.when("Caller refuses to share details").end(id="abandoned")

Överföringsdestinationer

PythonJavaScriptÖverför till
Destination.phone(number)Destination.phone(number)Ett telefonnummer
Destination.phone_variable(name)Destination.phoneVariable(name)Ett telefonnummer i en dynamisk variabel
Destination.sip(uri)Destination.sip(uri)En SIP URI
Destination.sip_variable(name)Destination.sipVariable(name)En SIP URI i en dynamisk variabel
Destination.agent(agent_id)Destination.agent(agentId)En annan agent

Villkor

when() tar en vanlig sträng, ett Condition eller ett Expr:

  • En sträng är ett LLM-villkor: LLM:en avgör om det uppfylls.
  • Condition.llm(text, label=...) är samma sak, med en etikett som visas på kanten i den visuella redigeraren. Använd Condition.expr(expr, label=...) för att märka ett uttryck.
  • Ett Expr utvärderas mot dynamiska variabler, utan att anropa LLM:en.

Bygg uttryck från Expr.variable(name) och Expr.literal(value). Jämför dem med eq, neq, gt, gte, lt och lte, och utför aritmetik med add, sub, mul och div. Kombinera dem med all_of / allOf, any_of / anyOf och if_else / ifElse. Vanliga värden omsluts automatiskt av Expr.literal(). Expr.llm(description) ber LLM:en att extrahera ett värde ur konversationen; ange type och enum för att få en sträng, ett tal eller ett av en fast uppsättning värden i stället för ett booleskt värde.

from elevenlabs.agent_workflows import Condition, Expr
is_vip = Expr.any_of(
Expr.variable("tier").eq("gold"),
Expr.all_of(Expr.variable("orders").gte(10), Expr.variable("churn_risk").eq(True)),
)
triage.when(Condition.expr(is_vip, label="VIP")).transfer("vip_desk", Destination.agent("agent_vip"))
big_refund = Expr.variable("unit_price").mul(Expr.variable("quantity")).gt(500)
resolve.when(big_refund).transfer("finance", Destination.phone("+15551234567"))
score = Expr.llm("How satisfied the caller sounds, from 1 to 5", type="integer")
resolve.when(score.lte(2)).converse("recovery", "Apologize and offer a discount code")

Loopar och bakåtriktade kanter

API:t tillåter en kant mellan två valfria noder, i båda riktningar. Om du vill att konversationen ska kunna återvända samma väg som den kom, ger du kanten ett bakåtriktat villkor med back:

faq = triage.when("Caller has a general question", back="Question answered").converse(
"faq", "Answer using the FAQ knowledge base"
)

go_to() / goTo() hanterar det vanliga fallet åt dig. När målnoden redan har en kant som leder hit blir den nya kanten den kantens bakåtriktade villkor. I det första exemplet skickas failed.go_to(identify) som det bakåtriktade villkoret för kanten identify → lookup_order. Alla andra kanter mellan samma två noder, och alla kanter från en nod till sig själv, misslyckas vid validering.

Redigera en befintlig agent

Workflow.from_agent() / Workflow.fromAgent() läser in workflowet för en agent som returneras av agents.get(). Nod-ID:n, kant-ID:n, redigerarpositioner och kantordning behålls, så att endast det du ändrade ändras när du skickar tillbaka det.

PythonJavaScriptFunktion
wf.node(id)wf.node(id)Returnerar ett handtag till en befintlig nod, för att redigera eller kedja från den.
node.update(**fields)node.update(fields)Ändrar en nods prompt, verktyg, destination eller alternativ.
wf.insert_between(source, target, fn)wf.insertBetween(source, target, fn)Infogar nya noder i en befintlig kant och behåller dess villkor.
wf.remove(id)wf.remove(id)Tar bort en nod och alla kanter till eller från den.

insert_between() / insertBetween() skickar en gren till din funktion som bär det ersatta kantvillkoret. Funktionen returnerar den sista nod den lade till, som sedan ansluts till det ursprungliga målet. Metoden returnerar den noden, eller None / undefined om det inte finns någon kant mellan de två noderna.

agent = elevenlabs.conversational_ai.agents.get("agent_id")
wf = Workflow.from_agent(agent)
wf.node("resolve").update(prompt="Explain the status, then offer a discount code")
verify = wf.insert_between(
"identify",
"lookup_order",
lambda start: start.converse("verify", "Verify the caller's identity with a one-time code"),
)
if verify is not None:
verify.when("Caller can't verify").end(id="unverified")
wf.remove("vip")
elevenlabs.conversational_ai.agents.update("agent_id", workflow=wf.build())

Lagra workflows i versionshantering

to_json_string() / toJSONString() skriver workflowet i API:ts wire-format: snake_case-nycklar, sorterade på varje nivå, med indrag på 2 mellanslag. Det har samma struktur som REST API:t och CLI använder, och båda SDK:erna skriver byte-identiska filer för samma workflow, så skillnaderna blir små. Workflow.from_json() / Workflow.fromJSON() läser in det igen och accepterar även en fullständig agentkonfiguration med en workflow-nyckel, till exempel en fil i CLI:ts katalog agent_configs/.

from pathlib import Path
from elevenlabs.agent_workflows import Workflow
Path("workflows/support.json").write_text(wf.to_json_string())
stored = Workflow.from_json(Path("workflows/support.json").read_text())
from_cli = Workflow.from_json(Path("agent_configs/support.json").read_text())

En typisk konfiguration:

1

Skapa filen

Läs in agenten med from_agent() / fromAgent() och skriv ut den, eller hämta den med elevenlabs agents pull.

2

Redigera

Ändra JSON direkt, eller läs in den med from_json() / fromJSON() och redigera den med byggaren i ett skript.

3

Validera i CI

Kör Workflow.from_json(file).build() / Workflow.fromJSON(file).build() för varje pull request och lägg upp elevenlabs agents workflow diagram <file> --format mermaid-md som en kommentar så att granskare kan se grafen.

4

Distribuera vid sammanslagning

Skicka det byggda workflowet med agents.update().

Visualisera ett workflow

CLI ritar en workflowfil som ett flödesschema, så att du kan kontrollera vad din kod byggde utan att öppna dashboarden. Den accepterar en fristående workflowfil skriven av to_json_string() / toJSONString(), eller en agentkonfiguration med en workflow-nyckel:

elevenlabs agents workflow diagram workflows/support.json

Som standard ritar den rutor och pilar i terminalen, med varje kantvillkor numrerat på sin kant och utskrivet i en förklarande lista under. Använd --format mermaid för att skriva ut Mermaid-källkod i stället, eller --format mermaid-md för att omsluta den i ett inhägnat kodblock som GitHub återger, till exempel i en pull request-kommentar:

elevenlabs agents workflow diagram workflows/support.json --format mermaid-md

Kommandot läser endast lokala filer, så det behöver ingen API-nyckel och kan köras i CI.

Validering

Kedjade anrop misslyckas aldrig på egen hand. build(), to_json() / toJSON() och to_json_string() / toJSONString() kontrollerar hela grafen och reser eller kastar ett enda WorkflowValidationError, vars issues-lista innehåller varje problem, med en code, ett message och det berörda node_id / nodeId.

from elevenlabs.agent_workflows import WorkflowValidationError
try:
workflow = wf.build(on_warning=lambda issue: print("warning:", issue.message))
except WorkflowValidationError as err:
for issue in err.issues:
print(issue.code, issue.message)

Fel omfattar:

  • Två kanter mellan samma par av noder, eller en kant från en nod till sig själv.
  • En kant in till startnoden, eller ut från en slutnod.
  • En kant från en tool-nod som inte är en lyckad eller misslyckad kant, eller en lyckad eller misslyckad kant från någon annan typ av nod.
  • Två noder med samma ID, eller en kant till en nod som inte finns.

Noder som inte kan nås från startnoden rapporteras som varningar via on_warning / onWarning och stoppar inte bygget.

Nodtyper som är nyare än din SDK

Ett workflow som lästs in från API:t eller från en fil kan innehålla nodtyper som din SDK-version ännu inte känner till. De skickas oförändrade fram och tillbaka genom from_json() / fromJSON() och to_json_string() / toJSONString(), och build() rapporterar var och en som en varning. Den typade request-modellen kan inte bära dem, så uppgradera SDK:n eller skicka wire-formatet direkt:

elevenlabs.conversational_ai.agents.update(
"agent_id",
request_options={"additional_body_parameters": {"workflow": wf.to_json()}},
)