langchainlangchain-js

How can I get LLM to only respond in JSON strings?


This is how I am defining the executor

const executor = await initializeAgentExecutorWithOptions(tools, model, {
  agentType: 'chat-conversational-react-description',
  verbose: false,
});

Whenever I prompt the AI I have this statement at the end.

type SomeObject = {
  field1: number,
  field2: number,
}

- It is very critical that you answer only as the above object and JSON stringify it as a single string.
  Don't include any other verbose explanatiouns and don't include the markdown syntax anywhere.

The SomeObject is just an example. Usually it will have a proper object type. When I use the executor to get a response from the AI, half the time I get the proper JSON string, but the other half the times are the AI completely ignoring my instructions and gives me a long verbose answer in just plain English...

How can I make sure I always get the structured data answer I want? Maybe using the agentType: 'chat-conversational-react-description' isn't the right approach here?


Solution

  • Update Nov. 6, 2023

    OpenAI announced today a new “JSON Mode” at the DevDay Keynote. When activated the model will only generate responses using the JSON format.

    You can refer to the official docs here.

    Original Answer

    That's a great question and LangChain provides an easy solution. Look at LangChain's Output Parsers if you want a quick answer. It is the recommended way to process LLM output into a specified format.

    Here's the official link from the docs:


    Side note: I wrote an introductory tutorial about this particular issue but for Python, so if anyone else is interested in more details you can check it out here.

    The example below does not use initializeAgentExecutorWithOptions, but will ensure that the output is processed as JSON without specifying this explicitly in your system prompt.

    How it works

    In order to tell LangChain that we'll need to convert the LLM response to a JSON output, we'll need to define a StructuredOutputParser and pass it to our chain.

    Defining our parser:

    Here's an example:

    // Let's define our parser
    const parser = StructuredOutputParser.fromZodSchema(
      z.object({
        field1: z.string().describe("first field"),
        field2: z.string().describe("second field")
      })
    );
    

    Adding it to our Chain:

    // We can then add it to our chain
    const chain = RunnableSequence.from([
      PromptTemplate.fromTemplate(...),
      new OpenAI({ temperature: 0 }),
      parser, // <-- this line
    ]);
    

    Invoking our chain with format_instructions:

    // Finally, we'll pass the format instructions to the invoke method
    const response = await chain.invoke({
      question: "What is the capital of France?",
      format_instructions: parser.getFormatInstructions(), // <-- this line
    });
    

    Go ahead and log the parser.getFormatInstructions() method before you call invoke if you'd like to see the output.

    When we pass parser.getFormatInstructions() to the format_instructions property, this lets LangChain append the desired JSON schema that we defined in step 1 to our prompt before sending it to the large language model.

    As a final point, it is absolutely critical to make sure your query/prompt is relevant and produces values that could be interpreted as the properties in your object SomeObject that are defined in the parser.

    Please give this a try, and let me know if you're able to consistently output JSON.