Sortie structurée

Ce chapitre explique comment retourner des fichiers JSON validés par un schéma à partir de flux de travail d’agents en utilisant le schéma JSON : L’agent peut utiliser tous les outils dont il a besoin pour effectuer la tâche. Une fois la validation réussie, le résultat comprend des données structurées correspondant à votre schéma.

Définissez un`schéma JSON <https://json-schema.org/understanding-json-schema/about>`_ pour la structure dont vous avez besoin, et le SDK validera la sortie finale du modèle par rapport à celui-ci.

Pourquoi des sorties structurées ?

Les Agents renvoient du texte libre par défaut, ce qui fonctionne pour les cas d’utilisation conversationnels, mais pas lorsque vous avez besoin d’utiliser la sortie de manière programmatique. Les sorties structurées fournissent des données typées que vous pouvez transmettre directement à votre logique d’application, à votre base de données ou aux composants de l’UI.

Prenons l’exemple d’un agent qui analyse une base de code. Sans sorties structurées, vous obtenez un texte libre que vous devriez analyser vous-même. Les sorties structurées vous permettent de définir la forme que vous voulez obtenir et d’obtenir des données typées que vous pouvez utiliser directement :

Sans sorties structurées

Avec des sorties structurées

This codebase uses Python and
TypeScript. It has 42 files
and the main entry point is...
{ "languages": ["Python", "TypeScript"],
  "file_count": 42,
  "entry_point": "src/main.ts" }

Démarrage rapide

Transmettez un schéma JSON à l’option outputFormat (TypeScript) ou output_format (Python). Lorsque la validation réussit, le message de résultat comprend un champ structured_output avec des données correspondant à votre schéma. Si l’agent ne peut pas satisfaire le schéma après de nouvelles tentatives, le SDK renvoie à la place un résultat erroné.

import { query } from "cortex-code-agent-sdk";

const schema = {
  type: "object",
  properties: {
    company_name: { type: "string" },
    founded_year: { type: "number" },
    headquarters: { type: "string" },
  },
  required: ["company_name"],
};

for await (const message of query({
  prompt: "Research Snowflake and provide key company information",
  options: {
    cwd: process.cwd(),
    outputFormat: { type: "json_schema", schema },
  },
})) {
  if (message.type === "result" && message.structured_output) {
    console.log(message.structured_output);
    // { company_name: "Snowflake", founded_year: 2012, headquarters: "Bozeman, MT" }
  }
}

Schémas de type sécurisé avec Zod et Pydantic

Au lieu d’écrire le schéma JSON à la main, utilisez `Zod<https://zod.dev/>`_ (TypeScript) ou Pydantic (Python) pour définir votre schéma. Ces bibliothèques génèrent le schéma JSON pour vous et vous permettent d’analyser la réponse pour obtenir un objet entièrement typé avec l’autocomplétion et la vérification de types.

import { z } from "zod";
import { query } from "cortex-code-agent-sdk";

const FeaturePlan = z.object({
  feature_name: z.string(),
  summary: z.string(),
  steps: z.array(
    z.object({
      step_number: z.number(),
      description: z.string(),
      estimated_complexity: z.enum(["low", "medium", "high"]),
    })
  ),
  risks: z.array(z.string()),
});

type FeaturePlan = z.infer<typeof FeaturePlan>;

const schema = z.toJSONSchema(FeaturePlan);

for await (const message of query({
  prompt: "Plan how to add dark mode support to a React app.",
  options: {
    cwd: process.cwd(),
    outputFormat: { type: "json_schema", schema },
  },
})) {
  if (message.type === "result" && message.structured_output) {
    const parsed = FeaturePlan.safeParse(message.structured_output);
    if (parsed.success) {
      const plan: FeaturePlan = parsed.data;
      console.log(`Feature: ${plan.feature_name}`);
      plan.steps.forEach((step) => {
        console.log(`${step.step_number}. [${step.estimated_complexity}] ${step.description}`);
      });
    }
  }
}

Exemple : agent de suivi TODO

Cet exemple montre des sorties structurées avec l’utilisation d’outils à plusieurs étapes. L’agent trouve des commentaires TODO dans une base de code à l’aide d’outils intégrés (Grep, Bash), puis renvoie les résultats sous forme de données structurées. Les champs facultatifs comme author traitent les cas où les informations de blname git peuvent ne pas être disponibles.

import { query } from "cortex-code-agent-sdk";

const todoSchema = {
  type: "object",
  properties: {
    todos: {
      type: "array",
      items: {
        type: "object",
        properties: {
          text: { type: "string" },
          file: { type: "string" },
          line: { type: "number" },
          author: { type: "string" },
          date: { type: "string" },
        },
        required: ["text", "file", "line"],
      },
    },
    total_count: { type: "number" },
  },
  required: ["todos", "total_count"],
};

for await (const message of query({
  prompt: "Find all TODO comments in this codebase and identify who added them",
  options: {
    cwd: process.cwd(),
    outputFormat: { type: "json_schema", schema: todoSchema },
  },
})) {
  if (message.type === "result" && message.structured_output) {
    const data = message.structured_output;
    console.log(`Found ${data.total_count} TODOs`);
    data.todos.forEach((todo) => {
      console.log(`${todo.file}:${todo.line} - ${todo.text}`);
      if (todo.author) {
        console.log(`  Added by ${todo.author} on ${todo.date}`);
      }
    });
  }
}

Exemple : résultats de requête SQL

Cortex Code a des outils SQL Snowflake intégrés. Vous pouvez les combiner avec une sortie structurée pour obtenir des résultats de requêtes typées :

import { query } from "cortex-code-agent-sdk";

const schema = {
  type: "object",
  properties: {
    top_customers: {
      type: "array",
      items: {
        type: "object",
        properties: {
          name: { type: "string" },
          total_revenue: { type: "number" },
          order_count: { type: "number" },
        },
        required: ["name", "total_revenue", "order_count"],
      },
    },
    query_used: { type: "string" },
  },
  required: ["top_customers", "query_used"],
};

for await (const message of query({
  prompt: "Find the top 5 customers by revenue from the ORDERS table",
  options: {
    cwd: process.cwd(),
    connection: "my-connection",
    outputFormat: { type: "json_schema", schema },
  },
})) {
  if (message.type === "result" && message.structured_output) {
    const { top_customers, query_used } = message.structured_output;
    console.log(`Query: ${query_used}`);
    top_customers.forEach((c) => {
      console.log(`${c.name}: $${c.total_revenue} (${c.order_count} orders)`);
    });
  }
}

Configuration du format de sortie

L’option outputFormat (TypeScript ) ou``output_format`` (Python) accepte un objet avec les champs suivants :

Champ

Valeur

Description

type

"json_schema"

Requis. Seul json_schema est pris en charge.

schema

Objet du schéma JSON

Définit la structure de sortie. Générer à partir de Zod avec z.toJSONSchema() ou Pydantic avec .model_json_schema().

Les fonctionnalités de schéma JSON standard sont prises en charge : tous les types de base (object, array, string, number, boolean, null), enum, const, required, objets imbriqués et définitions $ref.

Traitement des erreurs

La génération de sorties structurées peut échouer lorsque l’agent ne peut pas produire de fichier JSON valide correspondant à votre schéma. Lorsque cela se produit, le message de résultat comporte un subtype indiquant le problème qui s’est produit :

Sous-type

Signification

success

La sortie a été générée et validée.

error_max_structured_output_retries

L’agent n’a pas pu produire une sortie valide après plusieurs tentatives.

for await (const msg of query({
  prompt: "Extract contact info from the document",
  options: {
    cwd: process.cwd(),
    outputFormat: { type: "json_schema", schema: contactSchema },
  },
})) {
  if (msg.type === "result") {
    if (msg.subtype === "success" && msg.structured_output) {
      console.log(msg.structured_output);
    } else if (msg.subtype === "error_max_structured_output_retries") {
      console.error("Could not produce valid output");
    }
  }
}

Astuce

Conseils pour éviter les erreurs :

  • Les schémas doivent être ciblés. Les schémas imbriqués profondément avec de nombreux champs obligatoires sont plus difficiles à satisfaire. Commencez simplement et ajoutez de la complexité selon vos besoins.

  • ** Faites correspondre le schéma à la tâche.** Si la tâche ne contient peut-être pas toutes les informations requises par votre schéma, rendez ces champs facultatifs.

  • Utilisez des invites claires. Les invites ambiguës rendent plus difficile pour l’agent de savoir quelle sortie produire.