The workflow as an API#
A product of yours sends a question and waits for the answer, in one HTTP
request: the workflow checks the input, a model answers it as JSON, and
the call gets the workflow's outputs as its response body. No server of
yours, no queue to poll — the trigger's mode: sync waits for the
execution to end.
This is the Workflow as an API recipe of the console.
sequenceDiagram
participant P as Your product
participant A as The address
participant W as answer-api
P->>A: POST {"question": "…"} + Bearer
A->>W: start, event = the body
W->>W: check (condition) → answer (model, JSON)
W-->>A: outputs
A-->>P: 200 {"answer", "confidence", "input"}
Before you begin#
- A deployment or an
assistant that is up: a call waits at
most 90 s, and waking a deployment at zero can take longer. Below,
<deployment>stands for its name (for an assistant, writeassistant:instead ofdeployment:). - The editor role, and
astrasigned in and pointed at the workspace.
1. Write the workflow#
answer-api.yaml
apiVersion: anemoi.astralyx/v1
kind: Flow
metadata:
name: answer-api
spec:
description: A question in, a checked answer out, in the same request.
triggers:
- {id: api, kind: http, mode: sync, wait_seconds: 60, auth: bearer}
steps:
- id: check
kind: switch
cases:
- {name: ok, when: "event.question != null && event.question != ''"}
default: empty
- id: answer
kind: model
needs: [check]
when: steps.check.outputs.branch == 'ok'
deployment: <deployment>
system: "You answer for an API: short and exact, no greetings."
format: json
prompt: "Answer with JSON: answer (text), confidence (0 to 1).\n\nQuestion: ${{ event.question }}"
outputs:
answer: "${{ steps.answer.outputs.answer }}"
confidence: "${{ steps.answer.outputs.confidence }}"
input: "${{ steps.check.outputs.branch }}"
mode: sync: the call waits for the end, at mostwait_seconds(60 s; at most 90). Past it, the call gets202with the execution's name, and the execution goes on.auth: bearer: the caller sendsAuthorization: Bearer <secret>; the address alone starts nothing.checkis a condition on the event: without aquestion, it takesempty,answeris skipped, and the call is answered at once.- The outputs are the response. Each output is a field of the JSON body.
2. Make its address#
Iris → Workflows → answer-api → Triggers → Make the address. Copy the
URL and the Bearer token: the token is shown once. Below, they are
<address> and <secret>.
3. Call it#
$ curl -sS -X POST '<address>' -H 'Authorization: Bearer <secret>' \
-H 'Content-Type: application/json' \
-d '{"question": "At what temperature does water boil at sea level, in Celsius?"}'
{"answer":"100 °C","confidence":"0.98","input":"ok"}
The answer is 200, and its header Astralyx-Execution names the
execution. Outputs are text unless their text is a JSON object or list:
confidence is "0.98", a string. Without a question:
$ curl -sS -X POST '<address>' -H 'Authorization: Bearer <secret>' \
-H 'Content-Type: application/json' -d '{}'
{"answer":"","confidence":"","input":"empty"}
| Your product gets | When |
|---|---|
200 and the outputs |
The execution succeeded. |
202 and {"execution", "state", "deduplicated"} |
It had not ended within wait_seconds. Read it later: GET $ASTRALYX_API/anemoi/flow-executions/<execution> with a token of the workspace. |
502 and {"code": "WORKFLOW_FAILED", "message", "execution"} |
It failed: the message is its reason (Step answer failed: the model did not answer with a JSON object…). |
401 HOOK_UNAUTHORIZED |
No bearer token, or a wrong one. |
429 HOOK_RATE_LIMITED |
More than 60 calls in a minute (per_minute; at most 600). |
Make it yours#
- Return one object. An output whose value is a model's whole JSON
(
${{ steps.answer.outputs.json }}) is sent as an object, not as text. - Check more. Put a Function box before the model to validate or enrich the input; its fields are outputs the model's prompt reads.
- Limit the load.
concurrency: {max: 4, when_full: drop}answers429 FLOW_BUSYpast four calls at once, instead of queueing them past their wait.