Skip to content

Unable to find a valid Json for Converse Tools

0

Hi, I'm trying to implement the Tool-Use in a Spring boot project. Everything works like a charm except for the Tool schema. The JSON shown in the code below looks like is not valid for AWS and return this error:

Caused by: software.amazon.awssdk.services.bedrockruntime.model.ValidationException: The format of the value at toolConfig.tools.0.toolSpec.inputSchema.jsonSchem is invalid. Provide a json object for the field and try again.

I wasn't able to find ANY documentation regarding ToolUse in Java, only in Python, so my implementation is what I derived from the Python guides.

My bedrock client constructor

    private final BedrockRuntimeClient client;
    private final ToolConfiguration toolConfiguration;

    //Constructor for the client, it will automaticalli inject all class extending "CustomToolSpecification"
    public BedrockClient(AWSConfig config, List<CustomToolSpecification> tools) {
        this.config = config;
        this.client = config.bedrockRuntimeClient();

        List<Tool> toolList = tools.stream()
                .map(CustomToolSpecification::getTool)
                .toList();
        
        //When initilizing the Bean it will populate ToolConfiguration with all the tools annotated with @Component
        this.toolConfiguration = ToolConfiguration.builder().tools(toolList).build();
    }

An example of how a custom tool is declared

@Component
@Data
public class CustomToolDbReader extends CustomToolSpecification {

    public static final String NAME = "CustomToolDbReader";
    public static final String DESCRIPTION = "CustomToolDbReader";
    public static final String SCHEMA = "{\"json\": {\"type\": \"object\",\"properties\": {\"search\": {\"type\": \"string\",\"description\": \"the string to search in the db\"}},\"required\": [\"search\"]}}";

    public CustomToolDbReader(){
        super();

        initializeTool(NAME, DESCRIPTION, SCHEMA);
    }
}

And the abstract class that all tools extends

@NoArgsConstructor
@Getter
public abstract class CustomToolSpecification {

    private ToolSpecification specification;
    private ToolInputSchema inputSchema;
    private Tool tool;

    private void initializeInputSchema(String schema){

        this.inputSchema = ToolInputSchema.builder().json(new StringDocument(schema)).build();
    }

    private void initializeSpecification(String name, String description, String schema){

        initializeInputSchema(schema);

        this.specification =
                ToolSpecification.builder()
                        .name(name)
                        .description(description)
                        .inputSchema(this.inputSchema)
                        .build();
    }

    protected void initializeTool(String name, String description, String schema) {

        initializeSpecification(name, description, schema);

        this.tool =
                Tool.builder()
                    .toolSpec(this.specification).build();


    }

}

The function that use Converse and that receive the final toolConfiguration

    public String converseWithModel(List<Message> messageList, String modelId) {

        try {
            // Ora avvia la conversazione con tutti i messaggi in messageList
            ConverseResponse response = client.converse(request -> request
                    .modelId(modelId)
                    .messages(messageList)
                    .toolConfig(toolConfiguration)
                    .inferenceConfig(config -> config
                            .maxTokens(512)
                            .temperature(0.5F)
                            .topP(0.9F)));

            // Recupera il testo generato dalla risposta di Bedrock
            var responseText = response.output().message().content().get(0).text();
            return responseText;
        } catch (RuntimeException e) {
            throw new RuntimeException(e);
        }
    }
1 Answer
1
Accepted Answer

Found the problem, instead of using a String the schema need to be built using the Document interface like so:

        Document search = Document.mapBuilder()
                .putString("type", "string")
                .putString("description", "the string to search in the db").build();

        Document required = Document.listBuilder()
                .addString("search").build();

        Document properties = Document.mapBuilder()
                .putDocument("search", search).build();

        Document json = Document.mapBuilder()
                .putString("type", "object")
                .putDocument("properties", properties)
                .putDocument("required", required).build();

This code generate a Json schema equivalent to the one i was using but it is built automagically and for some reason this one work. i also had to change the CustomToolSpecification class:

@NoArgsConstructor
@Getter
public abstract class CustomToolSpecification {

    private ToolSpecification specification;
    private ToolInputSchema inputSchema;
    private Tool tool;

    private void initializeInputSchema(Document json){

        this.inputSchema = ToolInputSchema.builder().json(json).build();
    }

    private void initializeSpecification(String name, String description, Document json){

        initializeInputSchema(json);

        this.specification =
                ToolSpecification.builder()
                        .name(name)
                        .description(description)
                        .inputSchema(this.inputSchema)
                        .build();
    }

    protected void initializeTool(String name, String description, Document json) {

        initializeSpecification(name, description, json);

        this.tool =
                Tool.builder()
                    .toolSpec(this.specification).build();


    }

}
answered 2 years ago
EXPERT
reviewed 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.