AWS Bedrock with .NET: Converse API with Tools

AWS Bedrock with .NET: Converse API with Tools
Author(s): Ajay Kumar
Last updated: 24 Jan 2026

What is the Converse API with Tools?


AWS Bedrock's Converse API can be supercharged with tools—structured interfaces that let the model call functions, enforce output schemas, or interact with external systems. This enables developers to build AI agents that not only chat, but also return structured data, trigger workflows, or integrate with business logic.

In this article, you'll learn how to use the Converse API with tools to guarantee structured, reliable responses from generative AI models. We'll walk through a real-world example: extracting detailed movie information as JSON using a tool schema.

ℹ️ Why Tools?

Tools let you move beyond plain text. They enable the model to return data in a format your application can consume directly—no more brittle prompt engineering or regex parsing!

When and Why to Use Tools with Converse API


  • Structured Output: Enforce JSON schemas for reliable, machine-readable responses.
  • Function Calling: Let the model trigger business logic, database queries, or API calls.
  • Data Extraction: Extract entities, summaries, or analytics from unstructured text.
  • Workflow Automation: Build agents that can take actions, not just answer questions.

Use tools when you need more than just a chat—you want the AI to work as part of your system.

How: Building a Movie Info Extractor with Converse Tools


1. Prerequisites

  • AWS account with Bedrock access enabled.
  • AWS credentials with permissions for Bedrock Converse API and tools.
  • .NET 8 or later SDK installed.
  • NuGet package: AWSSDK.BedrockRuntime
2. Service Implementation Example

This example shows how to use a tool schema to extract structured movie information from the model. The tool enforces a JSON schema, so the model must return an array of movie objects with required fields.


using Amazon.BedrockRuntime;
using Amazon.BedrockRuntime.Model;
using Amazon.Runtime.Documents;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;

public class BedrockWithConverseToolsService
{
    private readonly AmazonBedrockRuntimeClient _client;
    private const string ModelId = "anthropic.claude-3-haiku-20240307-v1:0";

    public BedrockWithConverseToolsService()
    {
        _client = new AmazonBedrockRuntimeClient(Amazon.RegionEndpoint.USEast1);
    }

    public async Task<string> GetMovieDetailsAsJson(string movieQuery)
    {
        // Build the tool configuration - this GUARANTEES the output structure
        var toolConfig = BuildToolConfiguration();

        // Create the user message
        var userMessage = new Message
        {
            Role = "user",
            Content = new List<ContentBlock>
            {
                new ContentBlock
                {
                    Text = $"Provide detailed information about the movie '{movieQuery}'."
                }
            }
        };

        var converseRequest = new ConverseRequest
        {
            ModelId = ModelId,
            Messages = new List<Message> { userMessage },
            ToolConfig = toolConfig,
            System = new List<SystemContentBlock>
            {
                new SystemContentBlock
                {
                    Text = "You are a movie information expert"
                }
            }
        };

        // Send the request to Bedrock
        var response = await _client.ConverseAsync(converseRequest);

        if (response?.Output?.Message?.Content == null)
        {
            return JsonSerializer.Serialize(new { error = "Invalid response from Bedrock" });
        }

        // Find the tool use response
        var toolUseBlock = response.Output.Message.Content
            .FirstOrDefault(c => c.ToolUse != null);

        if (toolUseBlock?.ToolUse == null)
        {
            return JsonSerializer.Serialize(new { error = "Model did not use the expected tool" });
        }

        // Extract the structured data from the tool input
        return ExtractMovieInfoAsJson(toolUseBlock.ToolUse.Input);
    }

    private ToolConfiguration BuildToolConfiguration()
    {
        // Define the JSON schema for the tool input
        var toolInputSchema = new
        {
            type = "object",
            properties = new
            {
                movies = new
                {
                    type = "array",
                    description = "Array of movie information objects",
                    items = new
                    {
                        type = "object",
                        properties = new
                        {
                            title = new { type = "string", description = "The movie title" },
                            year = new { type = "integer", description = "The release year" },
                            category = new { type = "string", description = "Category to which this title belongs to. Like a TV show or Movie" },
                            directors = new { type = "array", description = "Array of director names", items = new { type = "string", description = "A director name" } },
                            actors = new { type = "array", description = "Array of actor names", items = new { type = "string", description = "An actor name" } },
                            plot = new { type = "string", description = "Brief plot summary" },
                            genre = new { type = "string", description = "Movie genre" },
                            rating = new { type = "string", description = "IMDb rating or similar" }
                        },
                        required = new[] { "title", "year", "category", "directors", "actors", "plot", "genre", "rating" },
                        additionalProperties = false
                    }
                }
            },
            required = new[] { "movies" },
            additionalProperties = false
        };

        var tool = new Tool
        {
            ToolSpec = new ToolSpecification
            {
                Name = "return_movie_info",
                Description = "Return structured movie information as an array to handle multiple matching movies",
                InputSchema = new ToolInputSchema
                {
                    Json = Document.FromObject(toolInputSchema)
                }
            }
        };

        return new ToolConfiguration
        {
            Tools = new List<Tool> { tool },
            ToolChoice = new ToolChoice
            {
                Tool = new SpecificToolChoice
                {
                    Name = "return_movie_info"
                }
            }
        };
    }

    private string ExtractMovieInfoAsJson(Document toolInput)
    {
        try
        {
            var inputDict = toolInput.AsDictionary();
            if (!inputDict.ContainsKey("movies"))
            {
                return JsonSerializer.Serialize(new { error = "Expected 'movies' property in response" });
            }
            var moviesDoc = inputDict["movies"];
            if (!moviesDoc.IsList())
            {
                return JsonSerializer.Serialize(new { error = "Expected 'movies' to be an array" });
            }
            var moviesList = moviesDoc.AsList();
            var movies = new List<object>();
            foreach (var movieDoc in moviesList)
            {
                var movieDict = movieDoc.AsDictionary();
                var directors = new List<string>();
                if (movieDict.ContainsKey("directors") && movieDict["directors"].IsList())
                {
                    directors = movieDict["directors"].AsList().Select(doc => doc.AsString()).ToList();
                }
                var actors = new List<string>();
                if (movieDict.ContainsKey("actors") && movieDict["actors"].IsList())
                {
                    actors = movieDict["actors"].AsList().Select(doc => doc.AsString()).ToList();
                }
                var movieData = new
                {
                    title = movieDict.ContainsKey("title") ? movieDict["title"].AsString() : "",
                    year = movieDict.ContainsKey("year") ? movieDict["year"].AsInt() : 0,
                    category = movieDict.ContainsKey("category") ? movieDict["category"].AsString() : "",
                    directors = directors,
                    actors = actors,
                    plot = movieDict.ContainsKey("plot") ? movieDict["plot"].AsString() : "",
                    genre = movieDict.ContainsKey("genre") ? movieDict["genre"].AsString() : "",
                    rating = movieDict.ContainsKey("rating") ? movieDict["rating"].AsString() : ""
                };
                movies.Add(movieData);
            }
            return JsonSerializer.Serialize(movies, new JsonSerializerOptions { WriteIndented = true });
        }
        catch (Exception ex)
        {
            return JsonSerializer.Serialize(new { error = $"Failed to extract movie info: {ex.Message}" });
        }
    }
}
            

💡 Full Example on GitHub

See the complete implementation and usage in the BedrockWithConverseToolsService.cs file on GitHub.

3. How the Example Works

  • Tool Schema: Defines exactly what fields the model must return for each movie.
  • System Prompt: Sets the AI’s persona as a movie expert.
  • Tool Use: The model is required to use the tool and return structured data.
  • Extraction: The code parses the tool output and returns formatted JSON.
4. Example Use Case: Movie Info Extraction

Suppose a user wants to get details about "Inception". The service will return a structured JSON array with all the required fields, ready for use in your app or workflow.


var service = new BedrockWithConverseToolsService();
string movieJson = await service.GetMovieDetailsAsJson("Inception");
Console.WriteLine(movieJson);
            

The output will be a JSON array of movie objects, each with title, year, category, directors, actors, plot, genre, and rating.

Summary


  • What: Converse API with tools lets you build AI agents that return structured, reliable data—not just text.
  • When: Use tools for data extraction, workflow automation, and any scenario where you need more than chat.
  • How: Define tool schemas, enforce output structure, and integrate with your .NET apps using the AWS SDK.

For more details and the full code, see the GitHub example.

References & Further Reading


For reference, the code repository being discussed is available at github: https://github.com/ajaysskumar/ai-playground/blob/main/AwsBedrockExamples/Services/BedrockWithConverseToolsService.cs

Thanks for reading through. Please share feedback, if any, in comments or on my email ajay.a338@gmail.com

Copyright © 2026 Dev Codex

An unhandled error has occurred. Reload 🗙