Skip to content

Structured outputs: JSON schema doesn't respect nullable modifier on numbers #1461

Open
@davidjwiner

Description

@davidjwiner

Confirm this is a Node library issue and not an underlying OpenAI API issue

  • This is an issue with the Node library

Describe the bug

The API doesn't respect the nullable modifier when appended to numbers.

To Reproduce

  1. Try to extract a schema containing nullable numbers from a user's input query, for example:
const schema = z.object({
  lowerBound: z.number().nullable(),
  upperBound: z.number().nullable(),
});
  1. Even if the query clearly doesn't indicate a lower or upper bound (or indicates that the lower / upper bound should be null), the model will still hallucinate a lower / upper bound.

Code snippets

import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";

const schema = z.object({
  lowerBound: z.number().nullable(),
  upperBound: z.number().nullable(),
});

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
  {
    role: "system",
    content: `You are an assistant that extracts headcount ranges. Follow the provided JSON schema precisely. You should take the user's
      query and extract the headcount range for relevant companies based on the user's query.`,
  },
  {
    role: "user",
    content: `
      I'm looking for companies with at least 1000 employees. There should be no upper bound on the number of employees.
      `,
  },
];

async function runRepro() {
  console.log("--- Schema Definition ---");
  console.log(
    JSON.stringify(
      zodResponseFormat(schema, "nestedData").json_schema,
      null,
      2,
    ),
  );
  console.log("\n--- Running OpenAI Call ---");

  try {
    const completion = await openai.beta.chat.completions.parse({
      model: "gpt-4o",
      messages: messages,
      response_format: zodResponseFormat(schema, "nestedData"),
      temperature: 0,
    });

    const result = completion.choices[0]?.message?.parsed;

    console.log("\n--- OpenAI Response (Parsed) ---");
    console.log(JSON.stringify(result, null, 2));

  } catch (error) {
    console.error("\n--- Error during OpenAI call ---");
    console.error(error);
  }
}

runRepro();


// Return value:
// {
//   "lowerBound": 1000,
//   "upperBound": 1000000
// }

OS

macOS

Node version

Node v21.7.1

Library version

openai v4.93.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingopenai apiRelated to underlying OpenAI API

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions