Skip to content

New JSON schema generation includes ToolContext, while old implementation skips it. #2366

Closed
@DamonBao

Description

@DamonBao

The old implementation (MethodInvokingFunctionCallback) skips ToolContext when generating JSON schemas for method inputs, but the new implementation (JsonSchemaGenerator) does not.

Old implementation:

protected String generateJsonSchema(Map<String, Class<?>> namedClasses) {
    try {
        JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(this.mapper);
        ObjectNode rootNode = this.mapper.createObjectNode();
        rootNode.put("$schema", "https://json-schema.org/draft/2020-12/schema");
        rootNode.put("type", "object");
        ObjectNode propertiesNode = rootNode.putObject("properties");
        for (Map.Entry<String, Class<?>> entry : namedClasses.entrySet()) {
            String className = entry.getKey();
            Class<?> clazz = entry.getValue();
            if (ClassUtils.isAssignable(clazz, ToolContext.class)) {
                this.isToolContextMethod = true;
                continue;
            }
            JsonSchema schema = schemaGen.generateSchema(/clazz);
            JsonNode schemaNode = this.mapper.valueToTree(schema);
            propertiesNode.set(className, schemaNode);
        }
        return this.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

New implementation:

public static String generateForMethodInput(Method method, SchemaOption... schemaOptions) {
    ObjectNode schema = JsonParser.getObjectMapper().createObjectNode();
    schema.put("$schema", SchemaVersion.DRAFT_2020_12.getIdentifier());
    schema.put("type", "object");
    ObjectNode properties = schema.putObject("properties");
    List<String> required = new ArrayList<>();
    for (int i = 0; i < method.getParameterCount(); i++) {
        String parameterName = method.getParameters()[i].getName();
        Type parameterType = method.getGenericParameterTypes()[i];
        if (isMethodParameterRequired(method, i)) {
            required.add(parameterName);
        }
        ObjectNode parameterNode = SUBTYPE_SCHEMA_GENERATOR.generateSchema(parameterType);
        String parameterDescription = getMethodParameterDescription(method, i);
        if (StringUtils.hasText(parameterDescription)) {
            parameterNode.put("description", parameterDescription);
        }
        properties.set(parameterName, parameterNode);
    }
    var requiredArray = schema.putArray("required");
    required.forEach(requiredArray::add);
    processSchemaOptions(schemaOptions, schema);
    return schema.toPrettyString();
}

Refer to the documentation (Spring AI ToolContext Documentation), which shows ToolContext is meant for passing user-provided or framework-managed context to tools, not as part of the input schema for the AI model. Including it might mislead users into thinking they need to provide it, potentially causing errors or confusion.

This change could lead to inconsistent behavior compared to previous versions, confuse users who expect ToolContext to be handled externally, or cause errors if users don't provide it when it's included in the schema.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions