Skip to content

Commit 915b5dc

Browse files
Add new Tool sample (04-HikerAIPro) (#19)
* New sample that call a function --------- Co-authored-by: Jake <[email protected]>
1 parent 04dd71a commit 915b5dc

File tree

9 files changed

+213
-12
lines changed

9 files changed

+213
-12
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Welcome to the official home for .NET samples demonstrating how to use AI in you
2323
| 1 | Text Summary | [Hike Benefits Summary Project](./src/getting-started/azure-openai-sdk/01-HikeBenefitsSummary/README.md)
2424
| 2 | Hiker AI | [Hiker AI Project](./src/getting-started/azure-openai-sdk/02-HikerAI/README.md)
2525
| 3 | Chat Context/Data | [Chatting About my Previous Hikes Project](./src/getting-started/azure-openai-sdk/03-ChattingAboutMyHikes/README.md)
26-
| 4 | Adding Tools (Functions) | [Coming Soon](.)
26+
| 4 | Hiker AI Pro (Tool extension) | [Hiker AI Pro](./src/getting-started/azure-openai-sdk/04-HikerAIPro/README.md)
2727
| 5 | Generating images | [Hike Images Project](./src/getting-started/azure-openai-sdk/05-HikeImages/README.md)
2828

2929

src/getting-started/README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,25 @@ Ensure that you follow the [Prerequisites](#prerequisites) to have access to Azu
2929
> 💡 If you already have an Azure OpenAI service available, you can skip the deployment and use hardcoded value in the `program.cs`.
3030

3131

32-
## Trying the samples
32+
## Azure OpenAI SDK (SDK)
33+
34+
The [Azure OpenAI client library for .NET](https://learn.microsoft.com/en-us/azure/ai-services/openai/) is an adaptation of OpenAI's REST APIs that provides an idiomatic interface and rich integration with the rest of the Azure SDK ecosystem. It can connect to Azure OpenAI resources or to the non-Azure OpenAI inference endpoint, making it a great choice for even non-Azure OpenAI development.
35+
36+
## Semantic Kernel (SK)
3337

34-
Now that your Azure OpenAI Service is deployed, It's time to select one of our sample to experiment different scenarios:
38+
[Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/overview/) is an open-source SDK that lets you easily build agents that can call your existing code. As a highly extensible SDK, you can use Semantic Kernel with models from OpenAI, Azure OpenAI, Hugging Face, and more!
3539

36-
- [Hike Benefits Summary](01-HikeBenefitsSummary/README.md): Summarize long text to a few words.
37-
- [Hiker AI](02-HikerAI/README.md): Chat with the AI and get hike recommendation.
38-
- [Chatting About my Previous Hikes](03-ChattingAboutMyHikes/README.md): Chat with the AI about your previous hikes.
39-
- [AI and Native .NET](04-AiAndNative/README.md): TBD
40-
- [Hike Images](05-HikeImages/README.md): Generate postal card images to invite your friends for a hike.
40+
## Trying the samples
41+
42+
Now that your Azure OpenAI Service is deployed, It's time to select one of our sample to experiment different scenarios.
4143

44+
| Sample | Description | Semantic Kernel | Azure OpenAI SDK |
45+
|-----------------------|------------- |-----------------|------------------|
46+
| Hike Benefits Summary | Summarize long text to a few words. | [SK](semantic-kernel/01-HikeBenefitsSummary/README.md) | [SDK](azure-openai-sdk/01-HikeBenefitsSummary/README.md) |
47+
| Hiker AI | Chat with the AI and get hike recommendation. | [SK](semantic-kernel/02-HikerAI/README.md) | [SDK](azure-openai-sdk/02-HikerAI/README.md) |
48+
| Chatting About my Previous Hikes | Chat with the AI about your previous hikes. | [SK](semantic-kernel/03-ChattingAboutMyHikes/README.md) | [SDK](azure-openai-sdk/03-ChattingAboutMyHikes/README.md) |
49+
| Hiker AI Pro | Extending the AI model with a local function using Function Tool. | [SK](semantic-kernel/04-AiAndNative/README.md) | [SDK](azure-openai-sdk/04-HikerAIPro/README.md) |
50+
| Hike Images | Generate postal card images to invite your friends for a hike. | [SK](semantic-kernel/05-HikeImages/README.md) | [SDK](azure-openai-sdk/05-HikeImages/README.md) |
4251

4352
## Clean up resources
4453

@@ -48,7 +57,6 @@ When you are done experimenting with the samples, you can delete the Azure resou
4857
azd down
4958
```
5059

51-
5260
## Troubleshooting
5361

5462
On Windows, you may get an error message: "*postprovision.ps1 is not digitally signed. The script will not execute on the system*" after the deployment. This is cause by the script "postprovision" being executed locally after the deployment to create .NET secret that will be used in the application. To avoid this error, execute the command `Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass`. And re-run the `azd up` command.

src/getting-started/azure-openai-sdk/04-AiAndNative/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<UserSecretsId>3fa4fd42-c2d0-493f-984d-f23accaecdfe</UserSecretsId>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.13" />
12+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
13+
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
14+
<PackageReference Include="System.Text.Json" Version="8.0.2" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Azure;
2+
using Azure.AI.OpenAI;
3+
using Microsoft.Extensions.Configuration;
4+
using System.Text.Json;
5+
6+
// == Retrieve the local secrets saved during the Azure deployment ==========
7+
var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
8+
string openAIEndpoint = config["AZURE_OPENAI_ENDPOINT"];
9+
string openAIDeploymentName = config["AZURE_OPENAI_GPT_NAME"];
10+
string openAiKey = config["AZURE_OPENAI_KEY"];
11+
12+
// == Creating the AIClient ==========
13+
var endpoint = new Uri(openAIEndpoint);
14+
var credentials = new AzureKeyCredential(openAiKey);
15+
var openAIClient = new OpenAIClient(endpoint, credentials);
16+
17+
18+
// == Defining a Tool to extend the AI model ==========
19+
var getWeather = new ChatCompletionsFunctionToolDefinition()
20+
{
21+
Name = "get_current_weather",
22+
Description = "Get the current weather in a given location",
23+
Parameters = BinaryData.FromObjectAsJson(
24+
new
25+
{
26+
Type = "object",
27+
Properties = new
28+
{
29+
Location = new
30+
{
31+
Type = "string",
32+
Description = "The city, e.g. Montreal, Sidney",
33+
},
34+
Unit = new
35+
{
36+
Type = "string",
37+
Enum = new[] { "celsius", "fahrenheit" },
38+
}
39+
},
40+
Required = new[] { "location" },
41+
},
42+
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }),
43+
};
44+
45+
// == Purely for convenience and clarity, this standalone local method handles tool call responses. ==========
46+
ChatRequestToolMessage GetToolCallResponseMessage(ChatCompletionsToolCall toolCall)
47+
{
48+
var functionToolCall = toolCall as ChatCompletionsFunctionToolCall;
49+
if (functionToolCall?.Name == getWeather.Name)
50+
{
51+
string unvalidatedArguments = functionToolCall.Arguments;
52+
var functionResultData = (object)null;
53+
54+
// == Here you would call a weather API to get the weather for the location ==========
55+
functionResultData = "Periods of rain or drizzle, 15 C";
56+
57+
return new ChatRequestToolMessage(functionResultData.ToString(), toolCall.Id);
58+
}
59+
else
60+
{
61+
throw new NotImplementedException();
62+
}
63+
}
64+
65+
66+
var completionOptions = new ChatCompletionsOptions
67+
{
68+
MaxTokens = 400,
69+
Temperature = 1f,
70+
FrequencyPenalty = 0.0f,
71+
PresencePenalty = 0.0f,
72+
NucleusSamplingFactor = 0.95f, // Top P
73+
DeploymentName = openAIDeploymentName,
74+
Tools = { getWeather }
75+
};
76+
completionOptions.ToolChoice = ChatCompletionsToolChoice.Auto;
77+
78+
79+
// == Providing context for the AI model ==========
80+
var systemPrompt =
81+
"""
82+
You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly.
83+
A good weather is important for a good hike. Only make recommendations if the weather is good or if people insist.
84+
You introduce yourself when first saying hello. When helping people out, you always ask them
85+
for this information to inform the hiking recommendation you provide:
86+
87+
1. Where they are located
88+
2. What hiking intensity they are looking for
89+
90+
You will then provide three suggestions for nearby hikes that vary in length after you get that information.
91+
You will also share an interesting fact about the local nature on the hikes when making a recommendation.
92+
""";
93+
94+
completionOptions.Messages.Add(new ChatRequestSystemMessage(systemPrompt));
95+
96+
97+
// == Starting the conversation ==========
98+
string userGreeting = """
99+
Hi!
100+
""";
101+
102+
completionOptions.Messages.Add(new ChatRequestUserMessage(userGreeting));
103+
Console.WriteLine($"\n\nUser >>> {userGreeting}");
104+
105+
106+
ChatCompletions response = await openAIClient.GetChatCompletionsAsync(completionOptions);
107+
ChatResponseMessage assistantResponse = response.Choices[0].Message;
108+
Console.WriteLine($"\n\nAssistant >>> {assistantResponse.Content}");
109+
completionOptions.Messages.Add(new ChatRequestSystemMessage(assistantResponse.Content));
110+
111+
112+
// == Providing the user's request ==========
113+
var hikeRequest =
114+
"""
115+
Is the weather is good today for a hike?
116+
If yes, I live in the greater Montreal area and would like an easy hike. I don't mind driving a bit to get there.
117+
I don't want the hike to be over 10 miles round trip. I'd consider a point-to-point hike.
118+
I want the hike to be as isolated as possible. I don't want to see many people.
119+
I would like it to be as bug free as possible.
120+
""";
121+
122+
Console.WriteLine($"\n\nUser >>> {hikeRequest}");
123+
completionOptions.Messages.Add(new ChatRequestUserMessage(hikeRequest));
124+
125+
// == Retrieve the answer from HikeAI ==========
126+
response = await openAIClient.GetChatCompletionsAsync(completionOptions);
127+
128+
// == If the response includes a tool call, handle it and continue the conversation ==========
129+
ChatChoice responseChoice = response.Choices[0];
130+
if (responseChoice.FinishReason == CompletionsFinishReason.ToolCalls)
131+
{
132+
// == Include the FunctionCall message in the conversation history ==========
133+
completionOptions.Messages.Add(new ChatRequestAssistantMessage(responseChoice.Message));
134+
135+
// == Add a new tool message for each tool call that is resolved ==========
136+
foreach (ChatCompletionsToolCall toolCall in responseChoice.Message.ToolCalls)
137+
{
138+
var ToolCallMsg = GetToolCallResponseMessage(toolCall);
139+
completionOptions.Messages.Add(ToolCallMsg);
140+
}
141+
142+
// == Retrieve the answer from HikeAI Pro ==========
143+
response = await openAIClient.GetChatCompletionsAsync(completionOptions);
144+
}
145+
146+
assistantResponse = response.Choices[0].Message;
147+
Console.WriteLine($"\n\nAssistant >>> {assistantResponse.Content}");
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# HikerAI Pro
2+
3+
This sample demonstrates how to extend the Azure OpenAI with a `gpt-35-turbo` model to use local functionalities, from a .NET 8.0 console application. Get a hiking recommendation, based on the weather condition from the AI model. It consists of a console application, running locally, that will send request to an Azure OpenAI Service deployed in your Azure subscription.
4+
5+
## Deploying the Azure resources
6+
7+
If it's not already done, follow the [Getting-started: Deploying the Azure resources](../../README.md#deploying-the-azure-resources) to deploy the Azure OpenAI Service with the models.
8+
9+
## Trying HikerAI Pro
10+
11+
1. From a terminal or command prompt, navigate to the `04-HikerAIPro` directory.
12+
13+
2. It's now time to try the console application. Depending on your Azure subscription it's possible that a few minutes more minute are required before the model deployed in Azure OpenAI is available. If you get an error message about this, wait a few (~5) minutes and try again.
14+
```bash
15+
dotnet run
16+
```
17+
18+
3. (Optional) Try changing the weather condition from `functionResultData`, or the type of weather you prefer for hiking to see the differences in the responses.
19+
20+
4. (Optional) Try another samples from the [Getting-started: Trying the samples](../../README.md#trying-the-samples) to experiment different scenarios.
21+
22+
## Clean up resources
23+
24+
Once you are done experimenting with the samples, follow the instructions from the [Getting-started: Clean up resources](../../README.md#clean-up-resources) to delete the Azure resources created using the Azure Developer CLI.

src/getting-started/azure-openai-sdk/getting-started-azure-openai-sdk.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-ChattingAboutMyHikes", "
1111
EndProject
1212
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "05-HikeImages", "05-HikeImages\05-HikeImages.csproj", "{AEDE95A2-2723-41B2-9DC7-9EFBD3CD24C8}"
1313
EndProject
14+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-HikerAIPro", "04-HikerAIPro\04-HikerAIPro.csproj", "{9122744F-C81C-4403-9C02-F371369262C6}"
15+
EndProject
1416
Global
1517
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1618
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +35,10 @@ Global
3335
{AEDE95A2-2723-41B2-9DC7-9EFBD3CD24C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
3436
{AEDE95A2-2723-41B2-9DC7-9EFBD3CD24C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
3537
{AEDE95A2-2723-41B2-9DC7-9EFBD3CD24C8}.Release|Any CPU.Build.0 = Release|Any CPU
38+
{9122744F-C81C-4403-9C02-F371369262C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39+
{9122744F-C81C-4403-9C02-F371369262C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
40+
{9122744F-C81C-4403-9C02-F371369262C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
41+
{9122744F-C81C-4403-9C02-F371369262C6}.Release|Any CPU.Build.0 = Release|Any CPU
3642
EndGlobalSection
3743
GlobalSection(SolutionProperties) = preSolution
3844
HideSolutionNode = FALSE

src/getting-started/infra/post-script/postprovision.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ $lines = (azd env get-values) -split "`n"
1919
Set-DotnetUserSecrets -path "./azure-openai-sdk/01-HikeBenefitsSummary/" -lines $lines
2020
Set-DotnetUserSecrets -path "./azure-openai-sdk/02-HikerAI/" -lines $lines
2121
Set-DotnetUserSecrets -path "./azure-openai-sdk/03-ChattingAboutMyHikes/" -lines $lines
22-
# Set-DotnetUserSecrets -path "./azure-openai-sdk/04-HikeTracker/" -lines $lines
22+
Set-DotnetUserSecrets -path "./azure-openai-sdk/04-HikerAIPro/" -lines $lines
2323
Set-DotnetUserSecrets -path "./azure-openai-sdk/05-HikeImages/" -lines $lines
2424

2525

src/getting-started/infra/post-script/postprovision.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ lines=$(azd env get-values)
2626
set_dotnet_user_secrets "./azure-openai-sdk/01-HikeBenefitsSummary/" "$lines"
2727
set_dotnet_user_secrets "./azure-openai-sdk/02-HikerAI/" "$lines"
2828
set_dotnet_user_secrets "./azure-openai-sdk/03-ChattingAboutMyHikes/" "$lines"
29-
# set_dotnet_user_secrets "./azure-openai-sdk/04-HikeTracker/" "$lines"
29+
set_dotnet_user_secrets "./azure-openai-sdk/04-HikerAIPro/" "$lines"
3030
set_dotnet_user_secrets "./azure-openai-sdk/05-HikeImages/" "$lines"
3131

3232
set_dotnet_user_secrets "./semantic-kernel/01-HikeBenefitsSummary/" "$lines"

0 commit comments

Comments
 (0)