Passa al contenuto principale

Il tuo primo flow

Un flow writer → reviewer, eseguito dall'inizio alla fine sulla tua macchina, senza nessuna chiave di modello.

Ti serve
  • Python 3.12+ e uv.
  • git.
  • nient'altro: l'esecuzione usa l'harness dry e non serve nessuna chiave di modello.
Alla fine hai
  • una cartella con il flow writer → reviewer dello scenario S1.
  • una configurazione che valida.
  • un ticket finito: il writer scrive, il reviewer controlla, tu approvi.

Passi​

  1. Clona il repository, installa le dipendenze e metti afe nel path:

    git clone <repository-url> afe
    cd afe
    uv sync
    source .venv/bin/activate
  2. Crea una cartella per il tutorial e una cartella config/ dentro:

    mkdir -p afe-first-flow/config/prompts
    cd afe-first-flow
  3. Scrivi il flow, config/flow.yaml. È un ciclo writer → reviewer. Il writer produce il text. Il reviewer risponde ok o ko. Un ko rimanda il testo come feedback, e il nodo umano approve chiude il flow:

    config/flow.yaml
    # yaml-language-server: $schema=../../../../schemas/afe.dev-v1alpha1.json
    apiVersion: afe.dev/v1alpha1
    kind: Flow
    metadata:
    name: writer-reviewer
    annotations:
    afe.dev/description: Scenario S1, a text written, reviewed and approved
    labels:
    scenario: S1
    spec:
    input:
    artifact: text-request
    budget:
    costUsd: 0.5
    wallTime: 30m
    nodes:
    writer:
    type: agent
    agent: writer
    reviewer:
    type: agent
    agent: reviewer
    approve:
    type: human
    actions:
    - approve
    - reject
    requireComment:
    - reject
    writes: decision
    message: Publish "{text.title}"?
    edges:
    - from: START
    to: writer
    - from: writer
    to: reviewer
    - from: reviewer
    when: review.outcome == 'ko'
    to: writer
    feedback: true
    maxRounds: 2
    - from: reviewer
    to: approve
    - from: approve
    when: decision.action == 'reject'
    to: writer
    newRound: true
    maxRounds: 2
    - from: approve
    to: END
  4. Scrivi i due agenti, config/agents.yaml:

    config/agents.yaml
    # yaml-language-server: $schema=../../../../schemas/afe.dev-v1alpha1.json
    apiVersion: afe.dev/v1alpha1
    kind: Agent
    metadata:
    name: writer
    spec:
    model: cheap
    systemPromptFile: prompts/writer.md
    reads:
    - text-request
    - review?
    - decision?
    writes: text
    budget:
    tokens: 20000
    costUsd: 0.1
    wallTime: 5m
    ---
    apiVersion: afe.dev/v1alpha1
    kind: Agent
    metadata:
    name: reviewer
    spec:
    model: cheap
    systemPromptFile: prompts/reviewer.md
    reads:
    - text-request
    - text
    writes: review
    budget:
    tokens: 20000
    toolCalls: 3
    costUsd: 0.1
    wallTime: 5m
    limits:
    maxSubmitRetries: 2
  5. Scrivi gli artefatti, config/schemas.yaml:

    config/schemas.yaml
    # yaml-language-server: $schema=../../../../schemas/afe.dev-v1alpha1.json
    apiVersion: afe.dev/v1alpha1
    kind: Schema
    metadata:
    name: text-request
    spec:
    fields:
    topic:
    type: string
    length:
    type: enum[short|medium|long]
    ---
    apiVersion: afe.dev/v1alpha1
    kind: Schema
    metadata:
    name: text
    spec:
    fields:
    title:
    type: string
    body:
    type: string
    ---
    apiVersion: afe.dev/v1alpha1
    kind: Schema
    metadata:
    name: review
    spec:
    fields:
    outcome:
    type: enum[ok|ko]
    notes:
    type: list[string]
    optional: true
    ---
    apiVersion: afe.dev/v1alpha1
    kind: Schema
    metadata:
    name: decision
    spec:
    fields:
    action:
    type: enum[approve|reject]
    comment:
    type: string
    optional: true
  6. Scrivi l'alias di modello, config/models.yaml. L'harness dry non lo chiama mai, quindi oggi la chiave non serve:

    config/models.yaml
    # yaml-language-server: $schema=../../../../schemas/afe.dev-v1alpha1.json
    apiVersion: afe.dev/v1alpha1
    kind: Model
    metadata:
    name: cheap
    annotations:
    afe.dev/description: A cheap model for drafts and reviews
    spec:
    provider: openrouter
    model: deepseek/deepseek-chat
    apiKeyEnv: OPENROUTER_API_KEY
  7. Scrivi i due prompt, config/prompts/writer.md e config/prompts/reviewer.md:

    config/prompts/writer.md
    Write the text the request asks for. If a review or a rejection is present, address it.
    config/prompts/reviewer.md
    Check the text against the request. Answer ok, or ko with concrete notes.
  8. Scrivi l'input del ticket, request.yaml, accanto a config/:

    request.yaml
    topic: bees
    length: short
  9. Valida la configurazione:

    afe validate -c config/

    Stampa 8 manifests, no errors.

  10. Rompi un riferimento per vedere l'errore, poi correggilo. Cambia agent: reviewer in agent: reviewr in config/flow.yaml e valida di nuovo. Il report nomina l'Agent sconosciuto e il percorso spec.nodes.reviewer.agent. Rimetti reviewer.

  11. Esegui il flow con l'harness dry:

    afe run writer-reviewer -i request.yaml -c config/ --local --dry
  12. Rispondi all'approvazione al prompt: scrivi approve e premi Invio due volte. Gli eventi scorrono e l'esecuzione finisce con T-0001 ticket_done.

Il motore --local non tiene nulla dopo la fine del comando. Gli eventi stampati sono tutto il risultato: dopo non resta nulla da ispezionare.

Ora leggi Nella web UI per eseguire lo stesso flow attraverso il server. Il tutorial successivo, Su un modello reale, chiama un modello vero.

Risoluzione dei problemi​

Sintomo: la shell stampa afe: command not found. Causa: l'ambiente virtuale del passo 1 non è attivo in questa shell. Rimedio: esegui di nuovo source .venv/bin/activate. Non resta attivo in una nuova scheda del terminale.

Sintomo: afe run termina subito con codice 2 e non stampa nessun prompt. Causa: il comando non ha un terminale collegato, per esempio dentro uno script o un job di CI. Rimedio: usa il comando afe resume che stampa, con l'azione che vuoi rispondere.

Vedi anche​