Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structured output improvements (continuation of PR 5522) #5560

Merged
merged 14 commits into from
Oct 24, 2024
Prev Previous commit
Next Next commit
Better solution
  • Loading branch information
SteveSandersonMS committed Oct 24, 2024
commit 52f0b99b2ce06536e6d2752b4831118728843c14
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.ComponentModel;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Shared.Diagnostics;
Expand Down Expand Up @@ -127,25 +128,23 @@ public static async Task<ChatCompletion<T>> CompleteAsync<T>(
inferenceOptions: _inferenceOptions);

var isWrappedInObject = false;
var schema = JsonSerializer.Serialize(schemaElement, AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(JsonElement)));
if (!SchemaRepresentsObject(schemaElement))
{
// For non-object-representing schemas, we wrap them in an object schema, because all
// the real LLM providers today require an object schema as the root. This is currently
// true even for providers that support native structured output.
isWrappedInObject = true;
schema = $$"""
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {{schema}}
},
"additionalProperties": false
}
""";
schemaElement = JsonSerializer.SerializeToElement(new JsonObject
SteveSandersonMS marked this conversation as resolved.
Show resolved Hide resolved
eiriktsarpalis marked this conversation as resolved.
Show resolved Hide resolved
{
{ "$schema", "https://json-schema.org/draft/2020-12/schema" },
{ "type", "object" },
{ "properties", new JsonObject { { "data", JsonElementToJsonNode(schemaElement) } } },
{ "additionalProperties", false },
}, AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(JsonObject)))!;
}

var schema = JsonSerializer.Serialize(schemaElement, AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(JsonElement)));

ChatMessage? promptAugmentation = null;
options = (options ?? new()).Clone();

Expand Down Expand Up @@ -208,4 +207,14 @@ private static bool SchemaRepresentsObject(JsonElement schemaElement)

return false;
}

private static JsonNode? JsonElementToJsonNode(JsonElement element)
{
return element.ValueKind switch
{
JsonValueKind.Array => JsonArray.Create(element),
SteveSandersonMS marked this conversation as resolved.
Show resolved Hide resolved
JsonValueKind.Object => JsonObject.Create(element),
_ => JsonValue.Create(element)
};
}
}