openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
jsquire-patch-1

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Chat/Example03_FunctionCallingAsync.cs

141lines · modecode

1using NUnit.Framework;
2using OpenAI.Chat;
3using System;
4using System.Collections.Generic;
5using System.Text.Json;
6using System.Threading.Tasks;
7
8namespace OpenAI.Examples;
9
10public partial class ChatExamples
11{
12 // See Example03_FunctionCalling.cs for the tool and function definitions.
13
14 [Test]
15 public async Task Example03_FunctionCallingAsync()
16 {
17 ChatClient client = new("gpt-4-turbo", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
18
19 #region
20 List<ChatMessage> messages =
21 [
22 new UserChatMessage("What's the weather like today?"),
23 ];
24
25 ChatCompletionOptions options = new()
26 {
27 Tools = { getCurrentLocationTool, getCurrentWeatherTool },
28 };
29 #endregion
30
31 #region
32 bool requiresAction;
33
34 do
35 {
36 requiresAction = false;
37 ChatCompletion completion = await client.CompleteChatAsync(messages, options);
38
39 switch (completion.FinishReason)
40 {
41 case ChatFinishReason.Stop:
42 {
43 // Add the assistant message to the conversation history.
44 messages.Add(new AssistantChatMessage(completion));
45 break;
46 }
47
48 case ChatFinishReason.ToolCalls:
49 {
50 // First, add the assistant message with tool calls to the conversation history.
51 messages.Add(new AssistantChatMessage(completion));
52
53 // Then, add a new tool message for each tool call that is resolved.
54 foreach (ChatToolCall toolCall in completion.ToolCalls)
55 {
56 switch (toolCall.FunctionName)
57 {
58 case nameof(GetCurrentLocation):
59 {
60 string toolResult = GetCurrentLocation();
61 messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
62 break;
63 }
64
65 case nameof(GetCurrentWeather):
66 {
67 // The arguments that the model wants to use to call the function are specified as a
68 // stringified JSON object based on the schema defined in the tool definition. Note that
69 // the model may hallucinate arguments too. Consequently, it is important to do the
70 // appropriate parsing and validation before calling the function.
71 using JsonDocument argumentsJson = JsonDocument.Parse(toolCall.FunctionArguments);
72 bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
73 bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
74
75 if (!hasLocation)
76 {
77 throw new ArgumentNullException(nameof(location), "The location argument is required.");
78 }
79
80 string toolResult = hasUnit
81 ? GetCurrentWeather(location.GetString(), unit.GetString())
82 : GetCurrentWeather(location.GetString());
83 messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
84 break;
85 }
86
87 default:
88 {
89 // Handle other unexpected calls.
90 throw new NotImplementedException();
91 }
92 }
93 }
94
95 requiresAction = true;
96 break;
97 }
98
99 case ChatFinishReason.Length:
100 throw new NotImplementedException("Incomplete model output due to MaxTokens parameter or token limit exceeded.");
101
102 case ChatFinishReason.ContentFilter:
103 throw new NotImplementedException("Omitted content due to a content filter flag.");
104
105 case ChatFinishReason.FunctionCall:
106 throw new NotImplementedException("Deprecated in favor of tool calls.");
107
108 default:
109 throw new NotImplementedException(completion.FinishReason.ToString());
110 }
111 } while (requiresAction);
112 #endregion
113
114 #region
115 foreach (ChatMessage message in messages)
116 {
117 switch (message)
118 {
119 case UserChatMessage userMessage:
120 Console.WriteLine($"[USER]:");
121 Console.WriteLine($"{userMessage.Content[0].Text}");
122 Console.WriteLine();
123 break;
124
125 case AssistantChatMessage assistantMessage when assistantMessage.Content.Count > 0:
126 Console.WriteLine($"[ASSISTANT]:");
127 Console.WriteLine($"{assistantMessage.Content[0].Text}");
128 Console.WriteLine();
129 break;
130
131 case ToolChatMessage:
132 // Do not print any tool messages; let the assistant summarize the tool results instead.
133 break;
134
135 default:
136 break;
137 }
138 }
139 #endregion
140 }
141}
142