chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
# Concept samples on how to use AWS Bedrock agents
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
1. You need to have an AWS account and [access to the foundation models](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access-permissions.html)
|
||||
2. [AWS CLI installed](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [configured](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration)
|
||||
|
||||
## Before running the samples
|
||||
|
||||
You need to set up some user secrets to run the samples.
|
||||
|
||||
### `BedrockAgent:AgentResourceRoleArn`
|
||||
|
||||
On your AWS console, go to the IAM service and go to **Roles**. Find the role you want to use and click on it. You will find the ARN in the summary section.
|
||||
|
||||
```
|
||||
dotnet user-secrets set "BedrockAgent:AgentResourceRoleArn" "arn:aws:iam::...:role/..."
|
||||
```
|
||||
|
||||
### `BedrockAgent:FoundationModel`
|
||||
|
||||
You need to make sure you have permission to access the foundation model. You can find the model ID in the [AWS documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html). To see the models you have access to, find the policy attached to your role you should see a list of models you have access to under the `Resource` section.
|
||||
|
||||
```
|
||||
dotnet user-secrets set "BedrockAgent:FoundationModel" "..."
|
||||
```
|
||||
|
||||
### How to add the `bedrock:InvokeModelWithResponseStream` action to an IAM policy
|
||||
|
||||
1. Open the [IAM console](https://console.aws.amazon.com/iam/).
|
||||
2. On the left navigation pane, choose `Roles` under `Access management`.
|
||||
3. Find the role you want to edit and click on it.
|
||||
4. Under the `Permissions policies` tab, click on the policy you want to edit.
|
||||
5. Under the `Permissions defined in this policy` section, click on the service. You should see **Bedrock** if you already have access to the Bedrock agent service.
|
||||
6. Click on the service, and then click `Edit`.
|
||||
7. On the right, you will be able to add an action. Find the service and search for `InvokeModelWithResponseStream`.
|
||||
8. Check the box next to the action and then scroll all the way down and click `Next`.
|
||||
9. Follow the prompts to save the changes.
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to interact with a <see cref="BedrockAgent"/> in the most basic way.
|
||||
/// </summary>
|
||||
public class Step01_BedrockAgent(ITestOutputHelper output) : BaseBedrockAgentTest(output)
|
||||
{
|
||||
private const string UserQuery = "Why is the sky blue in one sentence?";
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> and interact with it.
|
||||
/// The agent will respond to the user query.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseNewAgent()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step01_BedrockAgent");
|
||||
|
||||
// Respond to user input
|
||||
AgentThread bedrockAgentThread = new BedrockAgentThread(this.RuntimeClient);
|
||||
try
|
||||
{
|
||||
var responses = bedrockAgent.InvokeAsync(new ChatMessageContent(AuthorRole.User, UserQuery), bedrockAgentThread, null);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
await bedrockAgentThread.DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to use an existing <see cref="BedrockAgent"/> and interact with it.
|
||||
/// The agent will respond to the user query.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseExistingAgent()
|
||||
{
|
||||
// Retrieve the agent
|
||||
// Replace "bedrock-agent-id" with the ID of the agent you want to use
|
||||
var agentId = "bedrock-agent-id";
|
||||
var getAgentResponse = await this.Client.GetAgentAsync(new() { AgentId = agentId });
|
||||
var bedrockAgent = new BedrockAgent(getAgentResponse.Agent, this.Client, this.RuntimeClient);
|
||||
|
||||
// Respond to user input
|
||||
AgentThread bedrockAgentThread = new BedrockAgentThread(this.RuntimeClient);
|
||||
try
|
||||
{
|
||||
var responses = bedrockAgent.InvokeAsync(new ChatMessageContent(AuthorRole.User, UserQuery), bedrockAgentThread, null);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgentThread.DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> and interact with it using streaming.
|
||||
/// The agent will respond to the user query.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseNewAgentStreaming()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step01_BedrockAgent_Streaming");
|
||||
AgentThread bedrockAgentThread = new BedrockAgentThread(this.RuntimeClient);
|
||||
|
||||
// Respond to user input
|
||||
try
|
||||
{
|
||||
var streamingResponses = bedrockAgent.InvokeStreamingAsync(new ChatMessageContent(AuthorRole.User, UserQuery), bedrockAgentThread, null);
|
||||
await foreach (StreamingChatMessageContent response in streamingResponses)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
await bedrockAgentThread.DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
return new BedrockAgent(agentModel, this.Client, this.RuntimeClient);
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to interact with a <see cref="BedrockAgent"/> with code interpreter enabled.
|
||||
/// </summary>
|
||||
public class Step02_BedrockAgent_CodeInterpreter(ITestOutputHelper output) : BaseBedrockAgentTest(output)
|
||||
{
|
||||
private const string UserQuery = @"Create a bar chart for the following data:
|
||||
Panda 5
|
||||
Tiger 8
|
||||
Lion 3
|
||||
Monkey 6
|
||||
Dolphin 2";
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> with code interpreter enabled and interact with it.
|
||||
/// The agent will respond to the user query by creating a Python code that will be executed by the code interpreter.
|
||||
/// The output of the code interpreter will be a file containing the bar chart, which will be returned to the user.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentWithCodeInterpreter()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step02_BedrockAgent_CodeInterpreter");
|
||||
AgentThread bedrockAgentThread = new BedrockAgentThread(this.RuntimeClient);
|
||||
|
||||
// Respond to user input
|
||||
try
|
||||
{
|
||||
BinaryContent? binaryContent = null;
|
||||
var responses = bedrockAgent.InvokeAsync(new ChatMessageContent(AuthorRole.User, UserQuery), bedrockAgentThread, null);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
if (binaryContent == null && response.Items.Count > 0)
|
||||
{
|
||||
binaryContent = response.Items.OfType<BinaryContent>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
if (binaryContent == null)
|
||||
{
|
||||
throw new InvalidOperationException("No file found in the response.");
|
||||
}
|
||||
|
||||
// Save the file to the same directory as the test assembly
|
||||
var filePath = Path.Combine(
|
||||
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!,
|
||||
binaryContent.Metadata!["Name"]!.ToString()!);
|
||||
this.Output.WriteLine($"Saving file to {filePath}");
|
||||
binaryContent.WriteToFile(filePath, overwrite: true);
|
||||
|
||||
// Expected output:
|
||||
// Here is the bar chart for the given data:
|
||||
// [A bar chart showing the following data:
|
||||
// Panda 5
|
||||
// Tiger 8
|
||||
// Lion 3
|
||||
// Monkey 6
|
||||
// Dolphin 2]
|
||||
// Saving file to ...
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
await bedrockAgentThread.DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient);
|
||||
// Create the code interpreter action group and prepare the agent for interaction
|
||||
await bedrockAgent.CreateCodeInterpreterActionGroupAsync();
|
||||
|
||||
return bedrockAgent;
|
||||
}
|
||||
}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to interact with a <see cref="BedrockAgent"/> with kernel functions.
|
||||
/// </summary>
|
||||
public class Step03_BedrockAgent_Functions(ITestOutputHelper output) : BaseBedrockAgentTest(output)
|
||||
{
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> with kernel functions enabled and interact with it.
|
||||
/// The agent will respond to the user query by calling kernel functions to provide weather information.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentWithFunctions()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step03_BedrockAgent_Functions");
|
||||
|
||||
// Respond to user input
|
||||
try
|
||||
{
|
||||
var responses = bedrockAgent.InvokeAsync(
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather in Seattle?"),
|
||||
null);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> with kernel functions enabled and interact with it.
|
||||
/// The agent will respond to the user query by calling kernel functions that returns complex types to provide
|
||||
/// information about the menu.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentWithFunctionsComplexType()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step03_BedrockAgent_Functions_Complex_Types");
|
||||
|
||||
// Respond to user input
|
||||
try
|
||||
{
|
||||
var responses = bedrockAgent.InvokeAsync(
|
||||
new ChatMessageContent(AuthorRole.User, "What is the special soup and how much does it cost?"),
|
||||
null);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> with kernel functions enabled and interact with it using streaming.
|
||||
/// The agent will respond to the user query by calling kernel functions to provide weather information.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentStreamingWithFunctions()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step03_BedrockAgent_Functions_Streaming");
|
||||
|
||||
// Respond to user input
|
||||
try
|
||||
{
|
||||
var streamingResponses = bedrockAgent.InvokeStreamingAsync(
|
||||
new ChatMessageContent(AuthorRole.User, "What is the weather forecast in Seattle?"),
|
||||
null);
|
||||
await foreach (StreamingChatMessageContent response in streamingResponses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to create a new <see cref="BedrockAgent"/> with kernel functions enabled and interact with it.
|
||||
/// The agent will respond to the user query by calling multiple kernel functions in parallel to provide weather information.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentWithParallelFunctionsAsync()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step03_BedrockAgent_Functions_Parallel");
|
||||
|
||||
// Respond to user input
|
||||
try
|
||||
{
|
||||
var responses = bedrockAgent.InvokeAsync(
|
||||
new ChatMessageContent(AuthorRole.User, "What is the current weather in Seattle and what is the weather forecast in Seattle?"),
|
||||
null);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new kernel with plugins
|
||||
Kernel kernel = new();
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromType<WeatherPlugin>());
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromType<MenuPlugin>());
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient);
|
||||
// Create the kernel function action group and prepare the agent for interaction
|
||||
await bedrockAgent.CreateKernelFunctionActionGroupAsync();
|
||||
|
||||
return bedrockAgent;
|
||||
}
|
||||
|
||||
private sealed class WeatherPlugin
|
||||
{
|
||||
[KernelFunction, Description("Provides real-time weather information.")]
|
||||
public string Current([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
return $"The current weather in {location} is 72 degrees.";
|
||||
}
|
||||
|
||||
[KernelFunction, Description("Forecast weather information.")]
|
||||
public string Forecast([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
return $"The forecast for {location} is 75 degrees tomorrow.";
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class MenuPlugin
|
||||
{
|
||||
[KernelFunction, Description("Get the menu.")]
|
||||
public MenuItem[] GetMenu()
|
||||
{
|
||||
return s_menuItems;
|
||||
}
|
||||
|
||||
[KernelFunction, Description("Provides a list of specials from the menu.")]
|
||||
public MenuItem[] GetSpecials()
|
||||
{
|
||||
return [.. s_menuItems.Where(i => i.IsSpecial)];
|
||||
}
|
||||
|
||||
[KernelFunction, Description("Provides the price of the requested menu item.")]
|
||||
public float? GetItemPrice([Description("The name of the menu item.")] string menuItem)
|
||||
{
|
||||
return s_menuItems.FirstOrDefault(i => i.Name.Equals(menuItem, StringComparison.OrdinalIgnoreCase))?.Price;
|
||||
}
|
||||
|
||||
private static readonly MenuItem[] s_menuItems =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Category = "Soup",
|
||||
Name = "Clam Chowder",
|
||||
Price = 4.95f,
|
||||
IsSpecial = true,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Category = "Soup",
|
||||
Name = "Tomato Soup",
|
||||
Price = 4.95f,
|
||||
IsSpecial = false,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Category = "Salad",
|
||||
Name = "Cobb Salad",
|
||||
Price = 9.99f,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Category = "Drink",
|
||||
Name = "Chai Tea",
|
||||
Price = 2.95f,
|
||||
IsSpecial = true,
|
||||
},
|
||||
];
|
||||
|
||||
public sealed class MenuItem
|
||||
{
|
||||
public string Category { get; init; }
|
||||
public string Name { get; init; }
|
||||
public float Price { get; init; }
|
||||
public bool IsSpecial { get; init; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using Amazon.BedrockAgentRuntime.Model;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to interact with a <see cref="BedrockAgent"/> and inspect the agent's thought process.
|
||||
/// To learn more about different traces available, see:
|
||||
/// https://docs.aws.amazon.com/bedrock/latest/userguide/trace-events.html
|
||||
/// </summary>
|
||||
public class Step04_BedrockAgent_Trace(ITestOutputHelper output) : BaseBedrockAgentTest(output)
|
||||
{
|
||||
/// <summary>
|
||||
/// Demonstrates how to inspect the thought process of a <see cref="BedrockAgent"/> by enabling trace.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentWithTrace()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step04_BedrockAgent_Trace");
|
||||
|
||||
// Respond to user input
|
||||
var userQuery = "What is the current weather in Seattle and what is the weather forecast in Seattle?";
|
||||
try
|
||||
{
|
||||
AgentThread agentThread = new BedrockAgentThread(this.RuntimeClient);
|
||||
BedrockAgentInvokeOptions options = new()
|
||||
{
|
||||
EnableTrace = true,
|
||||
};
|
||||
|
||||
var responses = bedrockAgent.InvokeAsync([new ChatMessageContent(AuthorRole.User, userQuery)], agentThread, options);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
if (response.InnerContent is List<object?> innerContents)
|
||||
{
|
||||
// There could be multiple traces and they are stored in the InnerContent property
|
||||
var traceParts = innerContents.OfType<TracePart>().ToList();
|
||||
if (traceParts is not null)
|
||||
{
|
||||
foreach (var tracePart in traceParts)
|
||||
{
|
||||
this.OutputTrace(tracePart.Trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs the trace information to the console.
|
||||
/// This only outputs the orchestration trace for demonstration purposes.
|
||||
/// To learn more about different traces available, see:
|
||||
/// https://docs.aws.amazon.com/bedrock/latest/userguide/trace-events.html
|
||||
/// </summary>
|
||||
private void OutputTrace(Trace trace)
|
||||
{
|
||||
if (trace.OrchestrationTrace is not null)
|
||||
{
|
||||
if (trace.OrchestrationTrace.ModelInvocationInput is not null)
|
||||
{
|
||||
this.Output.WriteLine("========== Orchestration trace ==========");
|
||||
this.Output.WriteLine("Orchestration input:");
|
||||
this.Output.WriteLine(trace.OrchestrationTrace.ModelInvocationInput.Text);
|
||||
}
|
||||
if (trace.OrchestrationTrace.ModelInvocationOutput is not null)
|
||||
{
|
||||
this.Output.WriteLine("========== Orchestration trace ==========");
|
||||
this.Output.WriteLine("Orchestration output:");
|
||||
this.Output.WriteLine(trace.OrchestrationTrace.ModelInvocationOutput.RawResponse.Content);
|
||||
this.Output.WriteLine("Usage:");
|
||||
this.Output.WriteLine($"Input token: {trace.OrchestrationTrace.ModelInvocationOutput.Metadata.Usage.InputTokens}");
|
||||
this.Output.WriteLine($"Output token: {trace.OrchestrationTrace.ModelInvocationOutput.Metadata.Usage.OutputTokens}");
|
||||
}
|
||||
}
|
||||
// Example output:
|
||||
// ========== Orchestration trace ==========
|
||||
// Orchestration input:
|
||||
// {"system":"You're a helpful assistant who helps users find information.You have been provided with a set of functions to answer ...
|
||||
// ========== Orchestration trace ==========
|
||||
// Orchestration output:
|
||||
// <thinking>
|
||||
// To answer this question, I will need to call the following functions:
|
||||
// 1. Step04_BedrockAgent_Trace_KernelFunctions::Current to get the current weather in Seattle
|
||||
// 2. Step04_BedrockAgent_Trace_KernelFunctions::Forecast to get the weather forecast in Seattle
|
||||
// </thinking>
|
||||
//
|
||||
// <function_calls>
|
||||
// <invoke>
|
||||
// <tool_name>Step04_BedrockAgent_Trace_KernelFunctions::Current</tool_name>
|
||||
// <parameters>
|
||||
// <location>Seattle</location>
|
||||
// </parameters>
|
||||
// Usage:
|
||||
// Input token: 617
|
||||
// Output token: 144
|
||||
// ========== Orchestration trace ==========
|
||||
// Orchestration input:
|
||||
// {"system":"You're a helpful assistant who helps users find information.You have been provided with a set of functions to answer ...
|
||||
// ========== Orchestration trace ==========
|
||||
// Orchestration output:
|
||||
// <thinking>Now that I have the current weather in Seattle, I will call the forecast function to get the weather forecast.</thinking>
|
||||
//
|
||||
// <function_calls>
|
||||
// <invoke>
|
||||
// <tool_name>Step04_BedrockAgent_Trace_KernelFunctions::Forecast</tool_name>
|
||||
// <parameters>
|
||||
// <location>Seattle</location>
|
||||
// </parameters>
|
||||
// Usage:
|
||||
// Input token: 834
|
||||
// Output token: 87
|
||||
// ========== Orchestration trace ==========
|
||||
// Orchestration input:
|
||||
// {"system":"You're a helpful assistant who helps users find information.You have been provided with a set of functions to answer ...
|
||||
// ========== Orchestration trace ==========
|
||||
// Orchestration output:
|
||||
// <answer>
|
||||
// The current weather in Seattle is 72 degrees. The weather forecast for Seattle is 75 degrees tomorrow.
|
||||
// Usage:
|
||||
// Input token: 1003
|
||||
// Output token: 31
|
||||
}
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient);
|
||||
// Initialize kernel with plugins
|
||||
bedrockAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromType<WeatherPlugin>());
|
||||
// Create the kernel function action group and prepare the agent for interaction
|
||||
await bedrockAgent.CreateKernelFunctionActionGroupAsync();
|
||||
|
||||
return bedrockAgent;
|
||||
}
|
||||
|
||||
private sealed class WeatherPlugin
|
||||
{
|
||||
[KernelFunction, Description("Provides realtime weather information.")]
|
||||
public string Current([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
return $"The current weather in {location} is 72 degrees.";
|
||||
}
|
||||
|
||||
[KernelFunction, Description("Forecast weather information.")]
|
||||
public string Forecast([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
return $"The forecast for {location} is 75 degrees tomorrow.";
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to interact with a <see cref="BedrockAgent"/> that is associated with a knowledge base.
|
||||
/// A Bedrock Knowledge Base is a collection of documents that the agent uses to answer user queries.
|
||||
/// To learn more about Bedrock Knowledge Base, see:
|
||||
/// https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base.html
|
||||
/// </summary>
|
||||
public class Step05_BedrockAgent_FileSearch(ITestOutputHelper output) : BaseBedrockAgentTest(output)
|
||||
{
|
||||
// Replace the KnowledgeBaseId with a valid KnowledgeBaseId
|
||||
// To learn how to create a Knowledge Base, see:
|
||||
// https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-create.html
|
||||
private const string KnowledgeBaseId = "[KnowledgeBaseId]";
|
||||
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient);
|
||||
// Associate the agent with a knowledge base and prepare the agent
|
||||
await bedrockAgent.AssociateAgentKnowledgeBaseAsync(
|
||||
KnowledgeBaseId,
|
||||
"You will find information here.");
|
||||
|
||||
return bedrockAgent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to use a <see cref="BedrockAgent"/> with file search.
|
||||
/// </summary>
|
||||
[Fact(Skip = "This test is skipped because it requires a valid KnowledgeBaseId.")]
|
||||
public async Task UseAgentWithFileSearch()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step05_BedrockAgent_FileSearch");
|
||||
|
||||
// Respond to user input
|
||||
// Assuming the knowledge base contains information about Semantic Kernel.
|
||||
// Feel free to modify the user query according to the information in your knowledge base.
|
||||
var userQuery = "What is Semantic Kernel?";
|
||||
try
|
||||
{
|
||||
AgentThread bedrockThread = new BedrockAgentThread(this.RuntimeClient);
|
||||
var responses = bedrockAgent.InvokeAsync(new ChatMessageContent(AuthorRole.User, userQuery), bedrockThread, null, CancellationToken.None);
|
||||
await foreach (ChatMessageContent response in responses)
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine(response.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
using Microsoft.SemanticKernel.Agents.Chat;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how two agents (one of which is a Bedrock agent) can chat with each other.
|
||||
/// </summary>
|
||||
public class Step06_BedrockAgent_AgentChat(ITestOutputHelper output) : BaseBedrockAgentTest(output)
|
||||
{
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
return new BedrockAgent(agentModel, this.Client, this.RuntimeClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates how to put two <see cref="BedrockAgent"/> instances in a chat.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UseAgentWithAgentChat()
|
||||
{
|
||||
// Create the agent
|
||||
var bedrockAgent = await this.CreateAgentAsync("Step06_BedrockAgent_AgentChat");
|
||||
var chatCompletionAgent = new ChatCompletionAgent()
|
||||
{
|
||||
Instructions = "You're a translator who helps users understand the content in Spanish.",
|
||||
Name = "Translator",
|
||||
Kernel = this.CreateKernelWithChatCompletion(),
|
||||
};
|
||||
|
||||
// Create a chat for agent interaction
|
||||
var chat = new AgentGroupChat(bedrockAgent, chatCompletionAgent)
|
||||
{
|
||||
ExecutionSettings = new()
|
||||
{
|
||||
// Terminate after two turns: one from the bedrock agent and one from the chat completion agent.
|
||||
// Note: each invoke will terminate after two turns, and we are invoking the group chat for each user query.
|
||||
TerminationStrategy = new MultiTurnTerminationStrategy(2),
|
||||
}
|
||||
};
|
||||
|
||||
// Respond to user input
|
||||
string[] userQueries = [
|
||||
"Why is the sky blue in one sentence?",
|
||||
"Why do we have seasons in one sentence?"
|
||||
];
|
||||
try
|
||||
{
|
||||
foreach (var userQuery in userQueries)
|
||||
{
|
||||
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, userQuery));
|
||||
await foreach (var response in chat.InvokeAsync())
|
||||
{
|
||||
if (response.Content != null)
|
||||
{
|
||||
this.Output.WriteLine($"[{response.AuthorName}]: {response.Content}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class MultiTurnTerminationStrategy : TerminationStrategy
|
||||
{
|
||||
public MultiTurnTerminationStrategy(int turns)
|
||||
{
|
||||
this.MaximumIterations = turns;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task<bool> ShouldAgentTerminateAsync(
|
||||
Agent agent,
|
||||
IReadOnlyList<ChatMessageContent> history,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
using System.ComponentModel;
|
||||
using Amazon.BedrockAgent;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Agents;
|
||||
using Microsoft.SemanticKernel.Agents.Bedrock;
|
||||
|
||||
namespace GettingStarted.BedrockAgents;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to declaratively create instances of <see cref="BedrockAgent"/>.
|
||||
/// </summary>
|
||||
public class Step07_BedrockAgent_Declarative : BaseBedrockAgentTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Demonstrates creating and using a Bedrock Agent with using configuration settings.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task BedrockAgentWithConfiguration()
|
||||
{
|
||||
var text =
|
||||
"""
|
||||
type: bedrock_agent
|
||||
name: StoryAgent
|
||||
description: Story Telling Agent
|
||||
instructions: Tell a story suitable for children about the topic provided by the user.
|
||||
model:
|
||||
id: ${BedrockAgent:FoundationModel}
|
||||
connection:
|
||||
type: bedrock
|
||||
agent_resource_role_arn: ${BedrockAgent:AgentResourceRoleArn}
|
||||
""";
|
||||
BedrockAgentFactory factory = new();
|
||||
|
||||
var agent = await factory.CreateAgentFromYamlAsync(text, configuration: TestConfiguration.ConfigurationRoot);
|
||||
|
||||
await InvokeAgentAsync(agent!, "Cats and Dogs");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates loading an existing Bedrock Agent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task BedrockAgentWithId()
|
||||
{
|
||||
var text =
|
||||
"""
|
||||
id: ${BedrockAgent:AgentId}
|
||||
type: bedrock_agent
|
||||
""";
|
||||
BedrockAgentFactory factory = new();
|
||||
|
||||
var agent = await factory.CreateAgentFromYamlAsync(text, configuration: TestConfiguration.ConfigurationRoot);
|
||||
|
||||
await InvokeAgentAsync(agent!, "What is Semantic Kernel?", false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates creating and using a Bedrock Agent with a code interpreter.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task BedrockAgentWithCodeInterpreter()
|
||||
{
|
||||
var text =
|
||||
"""
|
||||
type: bedrock_agent
|
||||
name: CodeInterpreterAgent
|
||||
instructions: Use the code interpreter tool to answer questions which require code to be generated and executed.
|
||||
description: Agent with code interpreter tool.
|
||||
model:
|
||||
id: ${BedrockAgent:FoundationModel}
|
||||
connection:
|
||||
type: bedrock
|
||||
agent_resource_role_arn: ${BedrockAgent:AgentResourceRoleArn}
|
||||
tools:
|
||||
- type: code_interpreter
|
||||
""";
|
||||
BedrockAgentFactory factory = new();
|
||||
|
||||
var agent = await factory.CreateAgentFromYamlAsync(text, new() { Kernel = this._kernel }, TestConfiguration.ConfigurationRoot);
|
||||
|
||||
await InvokeAgentAsync(agent!, "Use code to determine the values in the Fibonacci sequence that are less then the value of 101?");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates creating and using a Bedrock Agent with functions.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task BedrockAgentWithFunctions()
|
||||
{
|
||||
var text =
|
||||
"""
|
||||
type: bedrock_agent
|
||||
name: FunctionCallingAgent
|
||||
instructions: Use the provided functions to answer questions about the menu.
|
||||
description: This agent uses the provided functions to answer questions about the menu.
|
||||
model:
|
||||
id: ${BedrockAgent:FoundationModel}
|
||||
connection:
|
||||
type: bedrock
|
||||
agent_resource_role_arn: ${BedrockAgent:AgentResourceRoleArn}
|
||||
tools:
|
||||
- id: Current
|
||||
type: function
|
||||
description: Provides real-time weather information.
|
||||
options:
|
||||
parameters:
|
||||
- name: location
|
||||
type: string
|
||||
required: true
|
||||
description: The location to get the weather for.
|
||||
- id: Forecast
|
||||
type: function
|
||||
description: Forecast weather information.
|
||||
options:
|
||||
parameters:
|
||||
- name: location
|
||||
type: string
|
||||
required: true
|
||||
description: The location to get the weather for.
|
||||
""";
|
||||
BedrockAgentFactory factory = new();
|
||||
|
||||
KernelPlugin plugin = KernelPluginFactory.CreateFromType<WeatherPlugin>();
|
||||
this._kernel.Plugins.Add(plugin);
|
||||
|
||||
var agent = await factory.CreateAgentFromYamlAsync(text, new() { Kernel = this._kernel }, TestConfiguration.ConfigurationRoot);
|
||||
|
||||
await InvokeAgentAsync(agent!, "What is the current weather in Seattle and what is the weather forecast in Seattle?");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates creating and using a Bedrock Agent with a knowledge base.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task BedrockAgentWithKnowledgeBase()
|
||||
{
|
||||
var text =
|
||||
"""
|
||||
type: bedrock_agent
|
||||
name: KnowledgeBaseAgent
|
||||
instructions: Use the provided knowledge base to answer questions.
|
||||
description: This agent uses the provided knowledge base to answer questions.
|
||||
model:
|
||||
id: ${BedrockAgent:FoundationModel}
|
||||
connection:
|
||||
type: bedrock
|
||||
agent_resource_role_arn: ${BedrockAgent:AgentResourceRoleArn}
|
||||
tools:
|
||||
- type: knowledge_base
|
||||
description: You will find information here.
|
||||
options:
|
||||
knowledge_base_id: ${BedrockAgent:KnowledgeBaseId}
|
||||
""";
|
||||
BedrockAgentFactory factory = new();
|
||||
|
||||
var agent = await factory.CreateAgentFromYamlAsync(text, new() { Kernel = this._kernel }, TestConfiguration.ConfigurationRoot);
|
||||
|
||||
await InvokeAgentAsync(agent!, "What is Semantic Kernel?");
|
||||
}
|
||||
|
||||
public Step07_BedrockAgent_Declarative(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
var builder = Kernel.CreateBuilder();
|
||||
builder.Services.AddSingleton<AmazonBedrockAgentClient>(this.Client);
|
||||
this._kernel = builder.Build();
|
||||
}
|
||||
|
||||
protected override async Task<BedrockAgent> CreateAgentAsync(string agentName)
|
||||
{
|
||||
// Create a new agent on the Bedrock Agent service and prepare it for use
|
||||
var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName));
|
||||
// Create a new kernel with plugins
|
||||
Kernel kernel = new();
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromType<WeatherPlugin>());
|
||||
// Create a new BedrockAgent instance with the agent model and the client
|
||||
// so that we can interact with the agent using Semantic Kernel contents.
|
||||
var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient)
|
||||
{
|
||||
Kernel = kernel,
|
||||
};
|
||||
// Create the kernel function action group and prepare the agent for interaction
|
||||
await bedrockAgent.CreateKernelFunctionActionGroupAsync();
|
||||
|
||||
return bedrockAgent;
|
||||
}
|
||||
|
||||
#region private
|
||||
private readonly Kernel _kernel;
|
||||
|
||||
/// <summary>
|
||||
/// Invoke the agent with the user input.
|
||||
/// </summary>
|
||||
private async Task InvokeAgentAsync(Agent agent, string input, bool deleteAgent = true)
|
||||
{
|
||||
AgentThread? agentThread = null;
|
||||
try
|
||||
{
|
||||
await foreach (AgentResponseItem<ChatMessageContent> response in agent.InvokeAsync(input))
|
||||
{
|
||||
agentThread = response.Thread;
|
||||
WriteAgentChatMessage(response);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Error invoking agent: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deleteAgent)
|
||||
{
|
||||
var bedrockAgent = agent as BedrockAgent;
|
||||
await bedrockAgent!.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id });
|
||||
}
|
||||
|
||||
if (agentThread is not null)
|
||||
{
|
||||
await agentThread.DeleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class WeatherPlugin
|
||||
{
|
||||
[KernelFunction, Description("Provides real-time weather information.")]
|
||||
public string Current([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
return $"The current weather in {location} is 72 degrees.";
|
||||
}
|
||||
|
||||
[KernelFunction, Description("Forecast weather information.")]
|
||||
public string Forecast([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
return $"The forecast for {location} is 75 degrees tomorrow.";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user