openai/openai-dotnet

Public

mirrored from https://github.com/openai/openai-dotnetAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.1.0-beta.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

examples/Chat/Example03_FunctionCalling.cs

181lines · modeblame

9f9f2936Jose Arriaga Maldonado2 years ago1using NUnit.Framework;
2using OpenAI.Chat;
3using System;
4using System.Collections.Generic;
5using System.Text.Json;
6
8cc6643fJose Arriaga Maldonado2 years ago7namespace OpenAI.Examples;
9f9f2936Jose Arriaga Maldonado2 years ago8
8cc6643fJose Arriaga Maldonado2 years ago9public partial class ChatExamples
9f9f2936Jose Arriaga Maldonado2 years ago10{
11#region
12private static string GetCurrentLocation()
13{
14// Call the location API here.
15return "San Francisco";
16}
17
18private static string GetCurrentWeather(string location, string unit = "celsius")
19{
20// Call the weather API here.
21return $"31 {unit}";
22}
23#endregion
24
25#region
26private static readonly ChatTool getCurrentLocationTool = ChatTool.CreateFunctionTool(
27functionName: nameof(GetCurrentLocation),
28functionDescription: "Get the user's current location"
29);
30
31private static readonly ChatTool getCurrentWeatherTool = ChatTool.CreateFunctionTool(
32functionName: nameof(GetCurrentWeather),
33functionDescription: "Get the current weather in a given location",
e4af1691Jose Arriaga Maldonado1 years ago34functionParameters: BinaryData.FromBytes("""
9f9f2936Jose Arriaga Maldonado2 years ago35{
36"type": "object",
37"properties": {
38"location": {
39"type": "string",
40"description": "The city and state, e.g. Boston, MA"
41},
42"unit": {
43"type": "string",
44"enum": [ "celsius", "fahrenheit" ],
45"description": "The temperature unit to use. Infer this from the specified location."
46}
47},
48"required": [ "location" ]
49}
e4af1691Jose Arriaga Maldonado1 years ago50"""u8.ToArray())
9f9f2936Jose Arriaga Maldonado2 years ago51);
52#endregion
53
54[Test]
8cc6643fJose Arriaga Maldonado2 years ago55public void Example03_FunctionCalling()
9f9f2936Jose Arriaga Maldonado2 years ago56{
8cc6643fJose Arriaga Maldonado2 years ago57ChatClient client = new("gpt-4-turbo", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
9f9f2936Jose Arriaga Maldonado2 years ago58
59#region
b0f9e5c3Jose Arriaga Maldonado1 years ago60List<ChatMessage> messages =
31c2ba63Jose Arriaga Maldonado1 years ago61[
9f9f2936Jose Arriaga Maldonado2 years ago62new UserChatMessage("What's the weather like today?"),
63];
64
65ChatCompletionOptions options = new()
66{
67Tools = { getCurrentLocationTool, getCurrentWeatherTool },
68};
69#endregion
70
71#region
72bool requiresAction;
73
74do
75{
76requiresAction = false;
31c2ba63Jose Arriaga Maldonado1 years ago77ChatCompletion completion = client.CompleteChat(messages, options);
9f9f2936Jose Arriaga Maldonado2 years ago78
31c2ba63Jose Arriaga Maldonado1 years ago79switch (completion.FinishReason)
9f9f2936Jose Arriaga Maldonado2 years ago80{
81case ChatFinishReason.Stop:
82{
83// Add the assistant message to the conversation history.
31c2ba63Jose Arriaga Maldonado1 years ago84messages.Add(new AssistantChatMessage(completion));
9f9f2936Jose Arriaga Maldonado2 years ago85break;
86}
87
88case ChatFinishReason.ToolCalls:
89{
90// First, add the assistant message with tool calls to the conversation history.
31c2ba63Jose Arriaga Maldonado1 years ago91messages.Add(new AssistantChatMessage(completion));
9f9f2936Jose Arriaga Maldonado2 years ago92
93// Then, add a new tool message for each tool call that is resolved.
31c2ba63Jose Arriaga Maldonado1 years ago94foreach (ChatToolCall toolCall in completion.ToolCalls)
9f9f2936Jose Arriaga Maldonado2 years ago95{
96switch (toolCall.FunctionName)
97{
98case nameof(GetCurrentLocation):
99{
100string toolResult = GetCurrentLocation();
101messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
102break;
103}
104
105case nameof(GetCurrentWeather):
106{
107// The arguments that the model wants to use to call the function are specified as a
108// stringified JSON object based on the schema defined in the tool definition. Note that
109// the model may hallucinate arguments too. Consequently, it is important to do the
110// appropriate parsing and validation before calling the function.
111using JsonDocument argumentsJson = JsonDocument.Parse(toolCall.FunctionArguments);
112bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
113bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
114
115if (!hasLocation)
116{
117throw new ArgumentNullException(nameof(location), "The location argument is required.");
118}
119
120string toolResult = hasUnit
121? GetCurrentWeather(location.GetString(), unit.GetString())
122: GetCurrentWeather(location.GetString());
123messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
124break;
125}
126
127default:
128{
129// Handle other unexpected calls.
130throw new NotImplementedException();
131}
132}
133}
134
135requiresAction = true;
136break;
137}
138
139case ChatFinishReason.Length:
140throw new NotImplementedException("Incomplete model output due to MaxTokens parameter or token limit exceeded.");
141
142case ChatFinishReason.ContentFilter:
143throw new NotImplementedException("Omitted content due to a content filter flag.");
144
145case ChatFinishReason.FunctionCall:
146throw new NotImplementedException("Deprecated in favor of tool calls.");
147
148default:
31c2ba63Jose Arriaga Maldonado1 years ago149throw new NotImplementedException(completion.FinishReason.ToString());
9f9f2936Jose Arriaga Maldonado2 years ago150}
151} while (requiresAction);
152#endregion
153
154#region
7a8bc8beJose Arriaga Maldonado1 years ago155foreach (ChatMessage message in messages)
9f9f2936Jose Arriaga Maldonado2 years ago156{
7a8bc8beJose Arriaga Maldonado1 years ago157switch (message)
9f9f2936Jose Arriaga Maldonado2 years ago158{
159case UserChatMessage userMessage:
160Console.WriteLine($"[USER]:");
161Console.WriteLine($"{userMessage.Content[0].Text}");
162Console.WriteLine();
163break;
164
165case AssistantChatMessage assistantMessage when assistantMessage.Content.Count > 0:
166Console.WriteLine($"[ASSISTANT]:");
167Console.WriteLine($"{assistantMessage.Content[0].Text}");
168Console.WriteLine();
169break;
170
171case ToolChatMessage:
172// Do not print any tool messages; let the assistant summarize the tool results instead.
173break;
174
175default:
176break;
177}
178}
179#endregion
180}
181}