Skip to content

Commit

Permalink
Add Function Calling support (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcominerva authored Jun 19, 2023
2 parents fa56569 + 6a32ef6 commit b149ec0
Show file tree
Hide file tree
Showing 142 changed files with 3,337 additions and 39 deletions.
7 changes: 7 additions & 0 deletions ChatGptNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatGptStreamConsole", "sam
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatGptBlazor.Wasm", "samples\ChatGptBlazor.Wasm\ChatGptBlazor.Wasm.csproj", "{7C629CAB-98E5-48AF-A884-7662A3D063F7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatGptFunctionCallingConsole", "samples\ChatGptFunctionCallingConsole\ChatGptFunctionCallingConsole.csproj", "{D3A6B4F9-B5D9-4E68-9CEE-96676717B9F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -47,6 +49,10 @@ Global
{7C629CAB-98E5-48AF-A884-7662A3D063F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C629CAB-98E5-48AF-A884-7662A3D063F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C629CAB-98E5-48AF-A884-7662A3D063F7}.Release|Any CPU.Build.0 = Release|Any CPU
{D3A6B4F9-B5D9-4E68-9CEE-96676717B9F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3A6B4F9-B5D9-4E68-9CEE-96676717B9F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3A6B4F9-B5D9-4E68-9CEE-96676717B9F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3A6B4F9-B5D9-4E68-9CEE-96676717B9F8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -56,6 +62,7 @@ Global
{435F71F0-D250-4726-A5C1-EFF5CD3A05F9} = {74E21338-5D64-4CA4-87E9-0621F93FE6A5}
{E8254DE1-D0EC-4858-81BB-656089F287CD} = {74E21338-5D64-4CA4-87E9-0621F93FE6A5}
{7C629CAB-98E5-48AF-A884-7662A3D063F7} = {74E21338-5D64-4CA4-87E9-0621F93FE6A5}
{D3A6B4F9-B5D9-4E68-9CEE-96676717B9F8} = {74E21338-5D64-4CA4-87E9-0621F93FE6A5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C0C7E910-6AB2-450F-8C88-810B320AA514}
Expand Down
104 changes: 103 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ The library is 100% compatible also with Blazor WebAssembly applications:

![](https://raw.githubusercontent.com/marcominerva/ChatGptNet/master/assets/ChatGptBlazor.WasmStreaming.gif)

Check the [Samples folder](https://github.com/marcominerva/ChatGptNet/tree/master/samples) for more information about the different implementations.
Check out the [Samples folder](https://github.com/marcominerva/ChatGptNet/tree/master/samples) for more information about the different implementations.

## Changing the assistant's behavior

Expand Down Expand Up @@ -255,6 +255,108 @@ Conversation history is automatically deleted when expiration time (specified by

The _preserveSetup_ argument allows to decide whether mantain also the _system_ message that has been set with the **SetupAsync** method (default: _false_).

## Function calling

With function calling, we can describe functions and have the model intelligently choose to output a JSON object containing arguments to call those functions. This is a new way to more reliably connect GPT's capabilities with external tools and APIs.

> **Note**
Currently, only OpenAI _gpt-3.5-turbo-0613_ and _gpt-4-0613_ models support function calling.

**ChatGptNet** fully supports function calling by providing an overload of the **AskAsync** method that allows to specify function specifications. If this parameter is supplied, then the model will decide when this it is appropiate to use one the functions. For example:

var functions = new List<ChatGptFunction>
{
new()
{
Name = "GetCurrentWeather",
Description = "Get the current weather",
Parameters = JsonDocument.Parse("""
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and/or the zip code"
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location."
}
},
"required": ["location", "format"]
}
""")
},
new()
{
Name = "GetWeatherForecast",
Description = "Get an N-day weather forecast",
Parameters = JsonDocument.Parse("""
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and/or the zip code"
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location."
},
"daysNumber": {
"type": "integer",
"description": "The number of days to forecast"
}
},
"required": ["location", "format", "daysNumber"]
}
""")
}
};

var functionParameters = new ChatGptFunctionParameters
{
FunctionCall = ChatGptFunctionCalls.Auto, // This is the default if functions are present.
Functions = functions
};

var response = await chatGptClient.AskAsync("What is the weather like in Taggia?", functionParameters);

We can pass an arbitrary number of functions, each one with a name, a description and a JSON schema describing the function parameters, following the [JSON Schema references](https://json-schema.org/understanding-json-schema). Under the hood, functions are injected into the system message in a syntax the model has been trained on. This means functions count against the model's context limit and are billed as input tokens.

The response object returned by the **AskAsync** method provides a property to check if the model has selected a function call:

if (response.IsFunctionCall)
{
Console.WriteLine("I have identified a function to call:");

var functionCall = response.GetFunctionCall()!;

Console.WriteLine(functionCall.Name);
Console.WriteLine(functionCall.Arguments);
}

This code will print something like this:

I have identified a function to call:
GetCurrentWeather
{
"location": "Taggia",
"format": "celsius"
}

Note that the API will not actually execute any function calls. It is up to developers to execute function calls using model outputs.

After the actual execution, we need to call the **AddFunctionResponseAsync** method on the **ChatGptClient** to add the response to the conversation history, just like a standard message, so that it will be automatically used for chat completion:

// Calls the remote function API.
var functionResponse = await GetWeatherAsync(functionCall.Arguments);
await chatGptClient.AddFunctionResponseAsync(conversationId, functionCall.Name, functionResponse);

Check out the [Function calling sample](https://github.com/marcominerva/ChatGptNet/blob/master/samples/ChatGptFunctionCallingConsole/Application.cs#L18) for a complete implementation of this workflow.

## Contribute

The project is constantly evolving. Contributions are welcome. Feel free to file issues and pull requests on the repo and we'll address them as we can.
Expand Down
21 changes: 21 additions & 0 deletions docs/ChatGptNet.Exceptions/ChatGptException.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ChatGptException class

Represents errors that occur during API invocation.

```csharp
public class ChatGptException : HttpRequestException
```

## Public Members

| name | description |
| --- | --- |
| [ChatGptException](ChatGptException/ChatGptException.md)(…) | Initializes a new instance of the [`ChatGptException`](./ChatGptException.md) class with the specified *error* details. |
| [Error](ChatGptException/Error.md) { get; } | Gets the detailed error information. |

## See Also

* namespace [ChatGptNet.Exceptions](../ChatGptNet.md)
* [ChatGptException.cs](https://github.com/marcominerva/ChatGptNet/tree/master/src/ChatGptNet/Exceptions/ChatGptException.cs)
<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
20 changes: 20 additions & 0 deletions docs/ChatGptNet.Exceptions/ChatGptException/ChatGptException.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ChatGptException constructor

Initializes a new instance of the [`ChatGptException`](../ChatGptException.md) class with the specified *error* details.

```csharp
public ChatGptException(ChatGptError? error, HttpStatusCode statusCode)
```

| parameter | description |
| --- | --- |
| error | The detailed error information |
| statusCode | The HTTP status code |

## See Also

* class [ChatGptError](../../ChatGptNet.Models/ChatGptError.md)
* class [ChatGptException](../ChatGptException.md)
* namespace [ChatGptNet.Exceptions](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
15 changes: 15 additions & 0 deletions docs/ChatGptNet.Exceptions/ChatGptException/Error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ChatGptException.Error property

Gets the detailed error information.

```csharp
public ChatGptError Error { get; }
```

## See Also

* class [ChatGptError](../../ChatGptNet.Models/ChatGptError.md)
* class [ChatGptException](../ChatGptException.md)
* namespace [ChatGptNet.Exceptions](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
21 changes: 21 additions & 0 deletions docs/ChatGptNet.Extensions/ChatGptResponseExtensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ChatGptResponseExtensions class

Provides extension methods for the [`ChatGptResponse`](../ChatGptNet.Models/ChatGptResponse.md) class.

```csharp
public static class ChatGptResponseExtensions
```

## Public Members

| name | description |
| --- | --- |
| static [AsDeltas](ChatGptResponseExtensions/AsDeltas.md)(…) | Returns an IAsyncEnumerable that allows to enumerate all the partial message deltas. |

## See Also

* class [ChatGptResponse](../ChatGptNet.Models/ChatGptResponse.md)
* namespace [ChatGptNet.Extensions](../ChatGptNet.md)
* [ChatGptResponseExtensions.cs](https://github.com/marcominerva/ChatGptNet/tree/master/src/ChatGptNet/Extensions/ChatGptResponseExtensions.cs)
<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
23 changes: 23 additions & 0 deletions docs/ChatGptNet.Extensions/ChatGptResponseExtensions/AsDeltas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# ChatGptResponseExtensions.AsDeltas method

Returns an IAsyncEnumerable that allows to enumerate all the partial message deltas.

```csharp
public static IAsyncEnumerable<string> AsDeltas(this IAsyncEnumerable<ChatGptResponse> responses)
```

| parameter | description |
| --- | --- |
| responses | The source IAsyncEnumerable. |

## Return Value

An IAsyncEnumerable that allows to enumerate all the partial message deltas.

## See Also

* class [ChatGptResponse](../../ChatGptNet.Models/ChatGptResponse.md)
* class [ChatGptResponseExtensions](../ChatGptResponseExtensions.md)
* namespace [ChatGptNet.Extensions](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
25 changes: 25 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# ChatGptChoice class

Represent a chat completion choice.

```csharp
public class ChatGptChoice
```

## Public Members

| name | description |
| --- | --- |
| [ChatGptChoice](ChatGptChoice/ChatGptChoice.md)() | The default constructor. |
| [Delta](ChatGptChoice/Delta.md) { get; set; } | When using streaming responses, gets or sets the partial message delta associated with this [`ChatGptChoice`](./ChatGptChoice.md). |
| [FinishReason](ChatGptChoice/FinishReason.md) { getset; } | Gets or sets a value specifying why the choice has been returned. |
| [Index](ChatGptChoice/Index.md) { getset; } | Gets or sets the index of the choice in the list. |
| [IsFunctionCall](ChatGptChoice/IsFunctionCall.md) { get; } | Gets a value indicating whether this choice contains a function call. |
| [Message](ChatGptChoice/Message.md) { getset; } | Gets or sets the message associated with this [`ChatGptChoice`](./ChatGptChoice.md). |

## See Also

* namespace [ChatGptNet.Models](../ChatGptNet.md)
* [ChatGptChoice.cs](https://github.com/marcominerva/ChatGptNet/tree/master/src/ChatGptNet/Models/ChatGptChoice.cs)
<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
14 changes: 14 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice/ChatGptChoice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ChatGptChoice constructor

The default constructor.

```csharp
public ChatGptChoice()
```

## See Also

* class [ChatGptChoice](../ChatGptChoice.md)
* namespace [ChatGptNet.Models](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
15 changes: 15 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice/Delta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ChatGptChoice.Delta property

When using streaming responses, gets or sets the partial message delta associated with this [`ChatGptChoice`](../ChatGptChoice.md).

```csharp
public ChatGptMessage? Delta { get; set; }
```

## See Also

* class [ChatGptMessage](../ChatGptMessage.md)
* class [ChatGptChoice](../ChatGptChoice.md)
* namespace [ChatGptNet.Models](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
24 changes: 24 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice/FinishReason.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# ChatGptChoice.FinishReason property

Gets or sets a value specifying why the choice has been returned.

```csharp
public string FinishReason { get; set; }
```

## Remarks

Possible values are:

* stop: API returned complete model output
* length: incomplete model output due to max_tokens parameter or token limit
* function_call: the model decided to call a function
* content_filter: omitted content due to a flag from content filters
* null: API response still in progress or incomplete

## See Also

* class [ChatGptChoice](../ChatGptChoice.md)
* namespace [ChatGptNet.Models](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
14 changes: 14 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice/Index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ChatGptChoice.Index property

Gets or sets the index of the choice in the list.

```csharp
public int Index { get; set; }
```

## See Also

* class [ChatGptChoice](../ChatGptChoice.md)
* namespace [ChatGptNet.Models](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
14 changes: 14 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice/IsFunctionCall.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ChatGptChoice.IsFunctionCall property

Gets a value indicating whether this choice contains a function call.

```csharp
public bool IsFunctionCall { get; }
```

## See Also

* class [ChatGptChoice](../ChatGptChoice.md)
* namespace [ChatGptNet.Models](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
15 changes: 15 additions & 0 deletions docs/ChatGptNet.Models/ChatGptChoice/Message.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ChatGptChoice.Message property

Gets or sets the message associated with this [`ChatGptChoice`](../ChatGptChoice.md).

```csharp
public ChatGptMessage Message { get; set; }
```

## See Also

* class [ChatGptMessage](../ChatGptMessage.md)
* class [ChatGptChoice](../ChatGptChoice.md)
* namespace [ChatGptNet.Models](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
Loading

0 comments on commit b149ec0

Please sign in to comment.