openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.0.0-beta.13

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Chat/Example03_FunctionCalling.cs

186lines · 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",
34functionParameters: BinaryData.FromString("""
35{
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}
50""")
51);
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
60List<ChatMessage> messages = [
61new UserChatMessage("What's the weather like today?"),
62];
63
64ChatCompletionOptions options = new()
65{
66Tools = { getCurrentLocationTool, getCurrentWeatherTool },
67};
68#endregion
69
70#region
71bool requiresAction;
72
73do
74{
75requiresAction = false;
76ChatCompletion chatCompletion = client.CompleteChat(messages, options);
77
78switch (chatCompletion.FinishReason)
79{
80case ChatFinishReason.Stop:
81{
82// Add the assistant message to the conversation history.
83messages.Add(new AssistantChatMessage(chatCompletion));
84break;
85}
86
87case ChatFinishReason.ToolCalls:
88{
89// First, add the assistant message with tool calls to the conversation history.
90messages.Add(new AssistantChatMessage(chatCompletion));
91
92// Then, add a new tool message for each tool call that is resolved.
93foreach (ChatToolCall toolCall in chatCompletion.ToolCalls)
94{
95switch (toolCall.FunctionName)
96{
97case nameof(GetCurrentLocation):
98{
99string toolResult = GetCurrentLocation();
100messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
101break;
102}
103
104case nameof(GetCurrentWeather):
105{
106// The arguments that the model wants to use to call the function are specified as a
107// stringified JSON object based on the schema defined in the tool definition. Note that
108// the model may hallucinate arguments too. Consequently, it is important to do the
109// appropriate parsing and validation before calling the function.
110using JsonDocument argumentsJson = JsonDocument.Parse(toolCall.FunctionArguments);
111bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
112bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
113
114if (!hasLocation)
115{
116throw new ArgumentNullException(nameof(location), "The location argument is required.");
117}
118
119string toolResult = hasUnit
120? GetCurrentWeather(location.GetString(), unit.GetString())
121: GetCurrentWeather(location.GetString());
122messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
123break;
124}
125
126default:
127{
128// Handle other unexpected calls.
129throw new NotImplementedException();
130}
131}
132}
133
134requiresAction = true;
135break;
136}
137
138case ChatFinishReason.Length:
139throw new NotImplementedException("Incomplete model output due to MaxTokens parameter or token limit exceeded.");
140
141case ChatFinishReason.ContentFilter:
142throw new NotImplementedException("Omitted content due to a content filter flag.");
143
144case ChatFinishReason.FunctionCall:
145throw new NotImplementedException("Deprecated in favor of tool calls.");
146
147default:
148throw new NotImplementedException(chatCompletion.FinishReason.ToString());
149}
150} while (requiresAction);
151#endregion
152
153#region
7a8bc8beJose Arriaga Maldonado1 years ago154foreach (ChatMessage message in messages)
9f9f2936Jose Arriaga Maldonado2 years ago155{
7a8bc8beJose Arriaga Maldonado1 years ago156switch (message)
9f9f2936Jose Arriaga Maldonado2 years ago157{
158case SystemChatMessage systemMessage:
159Console.WriteLine($"[SYSTEM]:");
160Console.WriteLine($"{systemMessage.Content[0].Text}");
161Console.WriteLine();
162break;
163
164case UserChatMessage userMessage:
165Console.WriteLine($"[USER]:");
166Console.WriteLine($"{userMessage.Content[0].Text}");
167Console.WriteLine();
168break;
169
170case AssistantChatMessage assistantMessage when assistantMessage.Content.Count > 0:
171Console.WriteLine($"[ASSISTANT]:");
172Console.WriteLine($"{assistantMessage.Content[0].Text}");
173Console.WriteLine();
174break;
175
176case ToolChatMessage:
177// Do not print any tool messages; let the assistant summarize the tool results instead.
178break;
179
180default:
181break;
182}
183}
184#endregion
185}
186}