Skip to content

Structured outputs ​

Un structured output transformă o conversație într-o înregistrare: o schemă JSON pe care o definești tu, completată din ce s-a spus. Așa devine un apel o programare, un lead, un tichet de suport sau un scor de calificare, în loc de un paragraf pe care trebuie să îl citească cineva.

Cum definești unul ​

GET    /api/v1/structured-outputs
POST   /api/v1/structured-outputs
GET    /api/v1/structured-outputs/templates
GET    /api/v1/structured-outputs/{structuredOutput}
PATCH  /api/v1/structured-outputs/{structuredOutput}
DELETE /api/v1/structured-outputs/{structuredOutput}
POST   /api/v1/structured-outputs/{structuredOutput}/publish
bash
curl -X POST "$CALLAGENT_API_URL/structured-outputs" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "appointment",
    "name": "Cerere de programare",
    "prompt": "Extrage programarea cerută de apelant. Lasă un câmp null dacă nu a fost menționat; nu ghici niciodată o dată.",
    "schema": {
      "type": "object",
      "properties": {
        "service":    { "type": "string", "description": "Ce vrea să i se facă." },
        "preferred_date": { "type": "string", "format": "date" },
        "urgency":    { "type": "string", "enum": ["routine", "soon", "emergency"] },
        "callback_number": { "type": "string" }
      },
      "required": ["service"],
      "additionalProperties": false
    }
  }'
ts
const output = await fetch(`${process.env.CALLAGENT_API_URL}/structured-outputs`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    key: 'appointment',
    name: 'Cerere de programare',
    prompt: 'Extrage programarea cerută de apelant. Lasă un câmp null dacă nu a fost menționat.',
    schema: {
      type: 'object',
      properties: {
        service: { type: 'string' },
        preferred_date: { type: 'string', format: 'date' },
        urgency: { type: 'string', enum: ['routine', 'soon', 'emergency'] },
      },
      required: ['service'],
      additionalProperties: false,
    },
  }),
}).then((response) => response.json());

Schema e validată structural când o salvezi, deci o schemă stricată e respinsă la definire, nu descoperită pe un apel viu.

GET /structured-outputs/templates întoarce puncte de plecare pentru formele obișnuite.

Câmpuri ​

CâmpObservații
keyIdentificator stabil, unic per organizație. Ăsta e cel după care cauți în rezultat.
nameEtichetă pentru oameni.
schemaSchemă JSON. Ține-o plată și ține additionalProperties: false.
promptInstrucțiunea de extragere. Spune explicit ce să facă atunci când un câmp nu a fost menționat.
targetCe citește extragerea.
model{ provider, model } — extragerea poate folosi un model mai ieftin decât conversația.
enabled

Ca asistenții și tools-urile, structured outputs sunt versionate: publish îngheață definiția curentă, deci schimbarea unei scheme nu modifică retroactiv felul în care au fost parsate apelurile de luna trecută.

Cum îl atașezi unui asistent ​

Fie prin pivotul expus de API, fie în analysis_plan al asistentului:

yaml
analysisPlan:
  summaryEnabled: true
  structuredOutputs:
    - name: appointment
      schema: { … }

Cum scrii o schemă care supraviețuiește contactului cu vorbirea ​

Patru reguli, învățate scump:

  1. Fă aproape totul opțional. Un apelant care nu a menționat o dată nu ți-a dat o dată. Un câmp required pe care modelul nu îl poate completa e un câmp pe care modelul îl va inventa.
  2. Folosește enum-uri pentru orice e categorial. urgency ca șir liber produce „destul de urgent", „cât mai repede", „nu foarte urgent, cred". Ca enum produce una din trei valori pe care poți ramifica.
  3. Spune în prompt cum arată „necunoscut". „Lasă un câmp null dacă nu a fost menționat; nu ghici niciodată o dată" valorează mai mult decât orice constrângere de schemă.
  4. Ține-o plată. Obiectele imbricate extrase din vorbire sunt locul unde moare acuratețea. Două structured outputs bat unul cu un sub-obiect.

Cum citești rezultatul ​

Extragerea unui apel ajunge pe înregistrarea apelului și apare în tab-ul structured-outputs din dashboard, în GET /calls/{call} și în evenimentul analysis.completed.

Extragerea nu e rulată în momentul de față de control plane

Definițiile, versionarea, publicarea, atașarea la un asistent și coloanele care stochează un rezultat sunt toate implementate. Ce lipsește e declanșatorul: pipeline-ul de analiză de după apel, care ar face extragerea, nu e dispecerizat după terminarea apelului.

Deci un structured output pe care îl definești azi nu va fi completat de control plane. E populat doar dacă gateway-ul îl furnizează în payload-ul de finalizare. Vezi Analytics și costuri și Stadiul implementării.

Mai departe ​

Scrisă după cod. Ce nu este încă implementat este marcat ca atare, niciodată descris ca funcțional.