Skip to content

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, write assistant: instead of deployment:).
  • The editor role, and astra signed 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 most wait_seconds (60 s; at most 90). Past it, the call gets 202 with the execution's name, and the execution goes on.
  • auth: bearer: the caller sends Authorization: Bearer <secret>; the address alone starts nothing.
  • check is a condition on the event: without a question, it takes empty, answer is skipped, and the call is answered at once.
  • The outputs are the response. Each output is a field of the JSON body.
$ astra iris workflows apply -f answer-api.yaml
flow answer-api: version 1 written, now current

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} answers 429 FLOW_BUSY past four calls at once, instead of queueing them past their wait.