Skip to content

Commit ee9de83

Browse files
committed
✨ Introduce BedrockWithConverseTools and update sitemap
- Added BedrockWithConverseTools component for enhanced AI features. - Updated sitemap.xml for better navigation and SEO. - Improved structure and organization of the project files. Generated by Copilot
1 parent 205359f commit ee9de83

File tree

3 files changed

+293
-0
lines changed

3 files changed

+293
-0
lines changed
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
@page "/blog/ai/bedrock/converse-tools"
2+
@using TestArena.Blog.Common
3+
@using TestArena.Blog
4+
@using System.Linq
5+
@using TestArena.Blog.Common.NavigationUtils
6+
7+
@code{
8+
PageInfo currentPage = SiteMap.Pages.FirstOrDefault(x => x.RelativePath == "/blog/ai/bedrock/converse-tools")!;
9+
}
10+
11+
<BlogContainer>
12+
<Header Title="@currentPage.Header"
13+
Image="@currentPage.ArticleImage"
14+
PublishedOn="@currentPage.PublishedOn"
15+
Authors="Ajay Kumar"
16+
isOlderThumbnailFormat="@currentPage.IsOlderThumbnailFormat">
17+
</Header>
18+
19+
<Section Heading="What is the Converse API with Tools?" Level="4">
20+
<p>
21+
AWS Bedrock's <b>Converse API</b> can be supercharged with <b>tools</b>—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.
22+
</p>
23+
<p>
24+
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.
25+
</p>
26+
<CalloutBox Type="info" Title="Why Tools?">
27+
<p>
28+
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!
29+
</p>
30+
</CalloutBox>
31+
</Section>
32+
33+
<Section Heading="When and Why to Use Tools with Converse API" Level="4">
34+
<ul>
35+
<li><b>Structured Output:</b> Enforce JSON schemas for reliable, machine-readable responses.</li>
36+
<li><b>Function Calling:</b> Let the model trigger business logic, database queries, or API calls.</li>
37+
<li><b>Data Extraction:</b> Extract entities, summaries, or analytics from unstructured text.</li>
38+
<li><b>Workflow Automation:</b> Build agents that can take actions, not just answer questions.</li>
39+
</ul>
40+
<p>
41+
Use tools when you need more than just a chat—you want the AI to work as part of your system.
42+
</p>
43+
</Section>
44+
45+
<Section Heading="How: Building a Movie Info Extractor with Converse Tools" Level="4">
46+
<Section Heading="1. Prerequisites" Level="5">
47+
<ul>
48+
<li>AWS account with Bedrock access enabled.</li>
49+
<li>AWS credentials with permissions for Bedrock Converse API and tools.</li>
50+
<li>.NET 8 or later SDK installed.</li>
51+
<li>NuGet package: <b>AWSSDK.BedrockRuntime</b></li>
52+
</ul>
53+
</Section>
54+
<Section Heading="2. Service Implementation Example" Level="5">
55+
<p>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.</p>
56+
<CodeSnippet Language="csharp">
57+
using Amazon.BedrockRuntime;
58+
using Amazon.BedrockRuntime.Model;
59+
using Amazon.Runtime.Documents;
60+
using System.Collections.Generic;
61+
using System.Text.Json;
62+
using System.Threading.Tasks;
63+
64+
public class BedrockWithConverseToolsService
65+
{
66+
private readonly AmazonBedrockRuntimeClient _client;
67+
private const string ModelId = "anthropic.claude-3-haiku-20240307-v1:0";
68+
69+
public BedrockWithConverseToolsService()
70+
{
71+
_client = new AmazonBedrockRuntimeClient(Amazon.RegionEndpoint.USEast1);
72+
}
73+
74+
public async Task&lt;string&gt; GetMovieDetailsAsJson(string movieQuery)
75+
{
76+
// Build the tool configuration - this GUARANTEES the output structure
77+
var toolConfig = BuildToolConfiguration();
78+
79+
// Create the user message
80+
var userMessage = new Message
81+
{
82+
Role = "user",
83+
Content = new List&lt;ContentBlock&gt;
84+
{
85+
new ContentBlock
86+
{
87+
Text = $"Provide detailed information about the movie '{movieQuery}'."
88+
}
89+
}
90+
};
91+
92+
var converseRequest = new ConverseRequest
93+
{
94+
ModelId = ModelId,
95+
Messages = new List&lt;Message&gt; { userMessage },
96+
ToolConfig = toolConfig,
97+
System = new List&lt;SystemContentBlock&gt;
98+
{
99+
new SystemContentBlock
100+
{
101+
Text = "You are a movie information expert"
102+
}
103+
}
104+
};
105+
106+
// Send the request to Bedrock
107+
var response = await _client.ConverseAsync(converseRequest);
108+
109+
if (response?.Output?.Message?.Content == null)
110+
{
111+
return JsonSerializer.Serialize(new { error = "Invalid response from Bedrock" });
112+
}
113+
114+
// Find the tool use response
115+
var toolUseBlock = response.Output.Message.Content
116+
.FirstOrDefault(c =&gt; c.ToolUse != null);
117+
118+
if (toolUseBlock?.ToolUse == null)
119+
{
120+
return JsonSerializer.Serialize(new { error = "Model did not use the expected tool" });
121+
}
122+
123+
// Extract the structured data from the tool input
124+
return ExtractMovieInfoAsJson(toolUseBlock.ToolUse.Input);
125+
}
126+
127+
private ToolConfiguration BuildToolConfiguration()
128+
{
129+
// Define the JSON schema for the tool input
130+
var toolInputSchema = new
131+
{
132+
type = "object",
133+
properties = new
134+
{
135+
movies = new
136+
{
137+
type = "array",
138+
description = "Array of movie information objects",
139+
items = new
140+
{
141+
type = "object",
142+
properties = new
143+
{
144+
title = new { type = "string", description = "The movie title" },
145+
year = new { type = "integer", description = "The release year" },
146+
category = new { type = "string", description = "Category to which this title belongs to. Like a TV show or Movie" },
147+
directors = new { type = "array", description = "Array of director names", items = new { type = "string", description = "A director name" } },
148+
actors = new { type = "array", description = "Array of actor names", items = new { type = "string", description = "An actor name" } },
149+
plot = new { type = "string", description = "Brief plot summary" },
150+
genre = new { type = "string", description = "Movie genre" },
151+
rating = new { type = "string", description = "IMDb rating or similar" }
152+
},
153+
required = new[] { "title", "year", "category", "directors", "actors", "plot", "genre", "rating" },
154+
additionalProperties = false
155+
}
156+
}
157+
},
158+
required = new[] { "movies" },
159+
additionalProperties = false
160+
};
161+
162+
var tool = new Tool
163+
{
164+
ToolSpec = new ToolSpecification
165+
{
166+
Name = "return_movie_info",
167+
Description = "Return structured movie information as an array to handle multiple matching movies",
168+
InputSchema = new ToolInputSchema
169+
{
170+
Json = Document.FromObject(toolInputSchema)
171+
}
172+
}
173+
};
174+
175+
return new ToolConfiguration
176+
{
177+
Tools = new List&lt;Tool&gt; { tool },
178+
ToolChoice = new ToolChoice
179+
{
180+
Tool = new SpecificToolChoice
181+
{
182+
Name = "return_movie_info"
183+
}
184+
}
185+
};
186+
}
187+
188+
private string ExtractMovieInfoAsJson(Document toolInput)
189+
{
190+
try
191+
{
192+
var inputDict = toolInput.AsDictionary();
193+
if (!inputDict.ContainsKey("movies"))
194+
{
195+
return JsonSerializer.Serialize(new { error = "Expected 'movies' property in response" });
196+
}
197+
var moviesDoc = inputDict["movies"];
198+
if (!moviesDoc.IsList())
199+
{
200+
return JsonSerializer.Serialize(new { error = "Expected 'movies' to be an array" });
201+
}
202+
var moviesList = moviesDoc.AsList();
203+
var movies = new List&lt;object&gt;();
204+
foreach (var movieDoc in moviesList)
205+
{
206+
var movieDict = movieDoc.AsDictionary();
207+
var directors = new List&lt;string&gt;();
208+
if (movieDict.ContainsKey("directors") && movieDict["directors"].IsList())
209+
{
210+
directors = movieDict["directors"].AsList().Select(doc =&gt; doc.AsString()).ToList();
211+
}
212+
var actors = new List&lt;string&gt;();
213+
if (movieDict.ContainsKey("actors") && movieDict["actors"].IsList())
214+
{
215+
actors = movieDict["actors"].AsList().Select(doc =&gt; doc.AsString()).ToList();
216+
}
217+
var movieData = new
218+
{
219+
title = movieDict.ContainsKey("title") ? movieDict["title"].AsString() : "",
220+
year = movieDict.ContainsKey("year") ? movieDict["year"].AsInt() : 0,
221+
category = movieDict.ContainsKey("category") ? movieDict["category"].AsString() : "",
222+
directors = directors,
223+
actors = actors,
224+
plot = movieDict.ContainsKey("plot") ? movieDict["plot"].AsString() : "",
225+
genre = movieDict.ContainsKey("genre") ? movieDict["genre"].AsString() : "",
226+
rating = movieDict.ContainsKey("rating") ? movieDict["rating"].AsString() : ""
227+
};
228+
movies.Add(movieData);
229+
}
230+
return JsonSerializer.Serialize(movies, new JsonSerializerOptions { WriteIndented = true });
231+
}
232+
catch (Exception ex)
233+
{
234+
return JsonSerializer.Serialize(new { error = $"Failed to extract movie info: {ex.Message}" });
235+
}
236+
}
237+
}
238+
</CodeSnippet>
239+
<CalloutBox Type="tip" Title="Full Example on GitHub">
240+
<p>See the complete implementation and usage in the <a href="https://github.com/ajaysskumar/ai-playground/blob/main/AwsBedrockExamples/Services/BedrockWithConverseToolsService.cs" target="_blank">BedrockWithConverseToolsService.cs</a> file on GitHub.</p>
241+
</CalloutBox>
242+
</Section>
243+
<Section Heading="3. How the Example Works" Level="5">
244+
<ul>
245+
<li><b>Tool Schema:</b> Defines exactly what fields the model must return for each movie.</li>
246+
<li><b>System Prompt:</b> Sets the AI’s persona as a movie expert.</li>
247+
<li><b>Tool Use:</b> The model is required to use the tool and return structured data.</li>
248+
<li><b>Extraction:</b> The code parses the tool output and returns formatted JSON.</li>
249+
</ul>
250+
</Section>
251+
<Section Heading="4. Example Use Case: Movie Info Extraction" Level="5">
252+
<p>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.</p>
253+
<CodeSnippet Language="csharp">
254+
var service = new BedrockWithConverseToolsService();
255+
string movieJson = await service.GetMovieDetailsAsJson("Inception");
256+
Console.WriteLine(movieJson);
257+
</CodeSnippet>
258+
<p>The output will be a JSON array of movie objects, each with title, year, category, directors, actors, plot, genre, and rating.</p>
259+
</Section>
260+
</Section>
261+
262+
<Section Heading="Summary" Level="4">
263+
<ul>
264+
<li><b>What:</b> Converse API with tools lets you build AI agents that return structured, reliable data—not just text.</li>
265+
<li><b>When:</b> Use tools for data extraction, workflow automation, and any scenario where you need more than chat.</li>
266+
<li><b>How:</b> Define tool schemas, enforce output structure, and integrate with your .NET apps using the AWS SDK.</li>
267+
</ul>
268+
<p>
269+
For more details and the full code, see the <a href="https://github.com/ajaysskumar/ai-playground/blob/main/AwsBedrockExamples/Services/BedrockWithConverseToolsService.cs" target="_blank">GitHub example</a>.
270+
</p>
271+
</Section>
272+
273+
<Section Heading="References & Further Reading" Level="4">
274+
<ul>
275+
<li><a href="https://docs.aws.amazon.com/bedrock/latest/userguide/converse-api.html" target="_blank">AWS Bedrock Converse API Documentation</a></li>
276+
<li><a href="https://github.com/ajaysskumar/ai-playground/blob/main/AwsBedrockExamples/Services/BedrockWithConverseToolsService.cs" target="_blank">BedrockWithConverseToolsService.cs on GitHub</a></li>
277+
</ul>
278+
</Section>
279+
280+
<EndNotes RepositoryLink="https://github.com/ajaysskumar/ai-playground/blob/main/AwsBedrockExamples/Services/BedrockWithConverseToolsService.cs" />
281+
</BlogContainer>

TestArena/Blog/Common/NavigationUtils/SiteMap.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ public static class SiteMap
202202
["AI", "AWS Bedrock", "Converse API", ".NET", "C#", "Chatbot"],
203203
isPublished: true,
204204
isOlderThumbnailFormat: false),
205+
new("AWS Bedrock with .NET: Converse API with Tools",
206+
"/blog/ai/bedrock/converse-tools",
207+
new DateTime(2026, 1, 24),
208+
"images/blog/ai/bedrock/banner.svg",
209+
["AI", "AWS Bedrock", "Converse API", "Tools", ".NET", "C#", "Structured Output"],
210+
isPublished: true,
211+
isOlderThumbnailFormat: false),
205212
];
206213

207214
public static IEnumerable<PageInfo> PublishedArticles => Pages.Where(p => p.IsPublished && p.PublishedOn <= DateTime.UtcNow);

TestArena/wwwroot/sitemap.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,9 @@
170170
<lastmod>2026-01-31</lastmod>
171171
<changefreq>weekly</changefreq>
172172
</url>
173+
<url>
174+
<loc>https://devcodex.in/blog/ai/bedrock/converse-tools</loc>
175+
<lastmod>2026-01-31</lastmod>
176+
<changefreq>weekly</changefreq>
177+
</url>
173178
</urlset>

0 commit comments

Comments
 (0)