Skip to content

Commit 484d8f0

Browse files
authored
Add article about accessing data in AI functions (#49944)
1 parent 6fdceba commit 484d8f0

File tree

10 files changed

+198
-34
lines changed

10 files changed

+198
-34
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
title: Access data in AI functions
3+
description: Learn how to pass data to AIFunction objects and how to access the data within the function delegate.
4+
ms.date: 11/17/2025
5+
---
6+
7+
# Access data in AI functions
8+
9+
When you create AI functions, you might need to access contextual data beyond the parameters provided by the AI model. The `Microsoft.Extensions.AI` library provides several mechanisms to pass data to function delegates.
10+
11+
## `AIFunction` class
12+
13+
The <xref:Microsoft.Extensions.AI.AIFunction> type represents a function that can be described to an AI service and invoked. You can create `AIFunction` objects by calling one of the <xref:Microsoft.Extensions.AI.AIFunctionFactory.Create*?displayProperty=nameWithType> overloads. But <xref:Microsoft.Extensions.AI.AIFunction> is also a base class, and you can derive from it and implement your own AI function type. <xref:Microsoft.Extensions.AI.DelegatingAIFunction> provides an easy way to wrap an existing `AIFunction` and layer in additional functionality, including capturing additional data to be used.
14+
15+
## Pass data
16+
17+
You can associate data with the function at the time it's created, either via closure or via <xref:Microsoft.Extensions.AI.ChatOptions.AdditionalProperties>. If you're creating your own function, you can populate `AdditionalProperties` however you want. If you use <xref:Microsoft.Extensions.AI.AIFunctionFactory> to create the function, you can populate data using <xref:Microsoft.Extensions.AI.AIFunctionFactoryOptions.AdditionalProperties?displayProperty=nameWithType>.
18+
19+
You can also capture any references to data as part of the delegate provided to `AIFunctionFactory`. That is, you can bake in whatever you want to reference as part of the `AIFunction` itself.
20+
21+
## Access data in function delegates
22+
23+
You might call your `AIFunction` directly, or you might call it indirectly by using <xref:Microsoft.Extensions.AI.FunctionInvokingChatClient>. The following sections describe how to access argument data using either approach.
24+
25+
### Manual function invocation
26+
27+
If you manually invoke an <xref:Microsoft.Extensions.AI.AIFunction> by calling <xref:Microsoft.Extensions.AI.AIFunction.InvokeAsync(Microsoft.Extensions.AI.AIFunctionArguments,System.Threading.CancellationToken)?displayProperty=nameWithType>, you pass in <xref:Microsoft.Extensions.AI.AIFunctionArguments>. The <xref:Microsoft.Extensions.AI.AIFunctionArguments> type includes:
28+
29+
- A dictionary of named arguments.
30+
- <xref:Microsoft.Extensions.AI.AIFunctionArguments.Context>: An arbitrary `IDictionary<object, object>` for passing additional ambient data into the function.
31+
- <xref:Microsoft.Extensions.AI.AIFunctionArguments.Services>: An <xref:System.IServiceProvider> that lets the `AIFunction` resolve arbitrary state from a [dependency injection (DI)](../../core/extensions/dependency-injection.md) container.
32+
33+
If you want to access either the `AIFunctionArguments` or the `IServiceProvider` from within your <xref:Microsoft.Extensions.AI.AIFunctionFactory.Create*?displayProperty=nameWithType> delegate, create a parameter typed as `IServiceProvider` or `AIFunctionArguments`. That parameter will be bound to the relevant data from the `AIFunctionArguments` passed to `AIFunction.InvokeAsync()`.
34+
35+
The following code shows an example:
36+
37+
:::code language="csharp" source="snippets/access-data/ArgumentsExample.cs" id="UseAIFunctionArguments":::
38+
39+
<xref:System.Threading.CancellationToken> is also special-cased: if the `AIFunctionFactory.Create` delegate or lambda has a `CancellationToken` parameter, it will be bound to the `CancellationToken` that was passed to `AIFunction.InvokeAsync()`.
40+
41+
### Invocation through `FunctionInvokingChatClient`
42+
43+
<xref:Microsoft.Extensions.AI.FunctionInvokingChatClient> publishes state about the current invocation to <xref:Microsoft.Extensions.AI.FunctionInvokingChatClient.CurrentContext?displayProperty=nameWithType>, including not only the arguments, but all of the input `ChatMessage` objects, the <xref:Microsoft.Extensions.AI.ChatOptions>, and details on which function is being invoked (out of how many). You can add any data you want into <xref:Microsoft.Extensions.AI.ChatOptions.AdditionalProperties?displayProperty=nameWithType> and extract that inside of your `AIFunction` from `FunctionInvokingChatClient.CurrentContext.Options.AdditionalProperties`.
44+
45+
The following code shows an example:
46+
47+
:::code language="csharp" source="snippets/access-data/ArgumentsExample.cs" id="UseAdditionalProperties":::
48+
49+
#### Dependency injection
50+
51+
If you use <xref:Microsoft.Extensions.AI.FunctionInvokingChatClient> to invoke functions automatically, that client configures an <xref:Microsoft.Extensions.AI.AIFunctionArguments> object that it passes into the `AIFunction`. Because `AIFunctionArguments` includes the `IServiceProvider` that the `FunctionInvokingChatClient` was itself provided with, if you construct your client using standard DI means, that `IServiceProvider` is passed all the way into your `AIFunction`. At that point, you can query it for anything you want from DI.
52+
53+
## Advanced techniques
54+
55+
If you want more fine-grained control over how parameters are bound, you can use <xref:Microsoft.Extensions.AI.AIFunctionFactoryOptions.ConfigureParameterBinding?displayProperty=nameWithType>, which puts you in control over how each parameter is populated. For example, the [MCP C# SDK uses this technique](https://github.com/modelcontextprotocol/csharp-sdk/blob/d344c651203841ec1c9e828736d234a6e4aebd07/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs#L83-L107) to automatically bind parameters from DI.
56+
57+
If you use the <xref:Microsoft.Extensions.AI.AIFunctionFactory.Create(System.Reflection.MethodInfo,System.Func{Microsoft.Extensions.AI.AIFunctionArguments,System.Object},Microsoft.Extensions.AI.AIFunctionFactoryOptions)?displayProperty=nameWithType> overload, you can also run your own arbitrary logic when you create the target object that the instance method will be called on, each time. And you can do whatever you want to configure that instance.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// <SnippetGetChatClient>
2+
using Azure;
3+
using Azure.AI.OpenAI;
4+
using Microsoft.Extensions.AI;
5+
using Microsoft.Extensions.Configuration;
6+
7+
class ArgumentsExample
8+
{
9+
public static async Task RunManual()
10+
{
11+
// <SnippetUseAIFunctionArguments>
12+
Delegate getWeatherDelegate = (AIFunctionArguments args) =>
13+
{
14+
// Access named parameters from the arguments dictionary.
15+
string? location = args.TryGetValue("location", out object? loc) ? loc.ToString() : "Unknown";
16+
string? units = args.TryGetValue("units", out object? u) ? u.ToString() : "celsius";
17+
18+
return $"Weather in {location}: 35°{units}";
19+
};
20+
21+
// Create the AIFunction.
22+
AIFunction getWeather = AIFunctionFactory.Create(getWeatherDelegate);
23+
24+
// Call the function manually.
25+
var result = await getWeather.InvokeAsync(new AIFunctionArguments
26+
{
27+
{ "location", "Seattle" },
28+
{ "units", "F" }
29+
});
30+
Console.WriteLine($"Function result: {result}");
31+
// </SnippetUseAIFunctionArguments>
32+
}
33+
public static async Task UseFICC()
34+
{
35+
IConfigurationRoot config = new ConfigurationBuilder()
36+
.AddUserSecrets<Program>()
37+
.Build();
38+
39+
string endpoint = config["AZURE_OPENAI_ENDPOINT"];
40+
string apiKey = config["AZURE_OPENAI_API_KEY"];
41+
string model = config["AZURE_OPENAI_GPT_NAME"];
42+
43+
// <SnippetUseAdditionalProperties>
44+
FunctionInvokingChatClient client = new FunctionInvokingChatClient(
45+
new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey))
46+
.GetChatClient(model).AsIChatClient());
47+
48+
AIFunction getWeather = AIFunctionFactory.Create(() =>
49+
{
50+
// Access named parameters from the arguments dictionary.
51+
AdditionalPropertiesDictionary props =
52+
FunctionInvokingChatClient.CurrentContext.Options.AdditionalProperties;
53+
54+
string location = props["location"].ToString();
55+
string units = props["units"].ToString();
56+
57+
return $"Weather in {location}: 35°{units}";
58+
});
59+
60+
var chatOptions = new ChatOptions
61+
{
62+
Tools = [getWeather],
63+
AdditionalProperties = new AdditionalPropertiesDictionary {
64+
["location"] = "Seattle",
65+
["units"] = "F"
66+
},
67+
};
68+
69+
List<ChatMessage> chatHistory = [
70+
new(ChatRole.System, "You're a helpful weather assistant.")
71+
];
72+
chatHistory.Add(new ChatMessage(ChatRole.User, "What's the weather like?"));
73+
74+
ChatResponse response = await client.GetResponseAsync(chatHistory, chatOptions);
75+
Console.WriteLine($"Response: {response.Text}");
76+
// </SnippetUseAdditionalProperties>
77+
}
78+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
//await ArgumentsExample.RunManual();
2+
await ArgumentsExample.UseFICC();
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<UserSecretsId>4d162886-0da5-4b62-a4db-d09780d06911</UserSecretsId>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Azure.Identity" Version="1.17.0" />
13+
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
14+
<PackageReference Include="Microsoft.Extensions.AI" Version="10.0.0" />
15+
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.4.0-preview.1.25207.5" />
16+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.10" />
17+
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.10" />
18+
19+
</ItemGroup>
20+
21+
</Project>

docs/ai/quickstarts/includes/create-ai-service.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
dotnet user-secrets init
1111
dotnet user-secrets set AZURE_OPENAI_ENDPOINT <your-Azure-OpenAI-endpoint>
1212
dotnet user-secrets set AZURE_OPENAI_GPT_NAME <your-Azure-OpenAI-model-name>
13+
dotnet user-secrets set AZURE_OPENAI_API_KEY <your-Azure-OpenAI-key>
1314
```

docs/ai/quickstarts/snippets/function-calling/azure-openai/FunctionCallingAI.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net9.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
<UserSecretsId>4d162886-0da5-4b62-a4db-d09780d06911</UserSecretsId>
@@ -11,7 +11,7 @@
1111
<ItemGroup>
1212
<PackageReference Include="Azure.Identity" Version="1.17.0" />
1313
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
14-
<PackageReference Include="Microsoft.Extensions.AI" Version="9.10.1" />
14+
<PackageReference Include="Microsoft.Extensions.AI" Version="10.0.0" />
1515
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.4.0-preview.1.25207.5" />
1616
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.10" />
1717
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.10" />

docs/ai/quickstarts/snippets/function-calling/azure-openai/Program.cs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,42 @@
1-
// <SnippetGetChatClient>
2-
using Microsoft.Extensions.Configuration;
3-
using Microsoft.Extensions.AI;
1+
using Azure;
42
using Azure.AI.OpenAI;
5-
using Azure.Identity;
3+
using Microsoft.Extensions.AI;
4+
using Microsoft.Extensions.Configuration;
65

7-
var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
6+
// <SnippetGetChatClient>
7+
IConfigurationRoot config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
88
string endpoint = config["AZURE_OPENAI_ENDPOINT"];
99
string deployment = config["AZURE_OPENAI_GPT_NAME"];
10+
string apiKey = config["AZURE_OPENAI_API_KEY"];
1011

1112
IChatClient client =
1213
new ChatClientBuilder(
13-
new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
14+
new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey))
1415
.GetChatClient(deployment).AsIChatClient())
1516
.UseFunctionInvocation()
1617
.Build();
1718
// </SnippetGetChatClient>
1819

19-
// Add a new plugin with a local .NET function that should be available to the AI model
20+
// Add a new plugin with a local .NET function
21+
// that should be available to the AI model.
2022
var chatOptions = new ChatOptions
2123
{
2224
Tools = [AIFunctionFactory.Create((string location, string unit) =>
23-
{
24-
// Here you would call a weather API to get the weather for the location
25-
return "Periods of rain or drizzle, 15 C";
26-
},
27-
"get_current_weather",
28-
"Get the current weather in a given location")]
25+
{
26+
// Here you would call a weather API to
27+
// get the weather for the location.
28+
return "Periods of rain or drizzle, 15 C";
29+
},
30+
"get_current_weather",
31+
"Get the current weather in a given location")]
2932
};
3033

31-
// System prompt to provide context
34+
// System prompt to provide context.
3235
List<ChatMessage> chatHistory = [new(ChatRole.System, """
33-
You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly.
34-
""")];
36+
You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly.
37+
""")];
3538

36-
// Weather conversation relevant to the registered function
39+
// Weather conversation relevant to the registered function.
3740
chatHistory.Add(new ChatMessage(ChatRole.User,
3841
"I live in Montreal and I'm looking for a moderate intensity hike. What's the current weather like? "));
3942
Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last()}");

docs/ai/quickstarts/snippets/function-calling/openai/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
return "Periods of rain or drizzle, 15 C";
2626
},
2727
"get_current_weather",
28-
"Get the current weather in a given location")]
28+
"Gets the current weather in a given location")]
2929
};
3030
// </SnippetAddOptions>
3131

docs/ai/quickstarts/use-function-calling.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
---
22
title: Quickstart - Extend OpenAI using Tools and execute a local Function with .NET
33
description: Create a simple chat app using OpenAI and extend the model to execute a local function.
4-
ms.date: 03/13/2025
4+
ms.date: 11/13/2025
55
ms.topic: quickstart
66
zone_pivot_groups: openai-library
77
# CustomerIntent: As a .NET developer new to OpenAI, I want deploy and use sample code to interact to learn from the sample code how to extend the model using Tools.
88
---
99

1010
# Invoke .NET functions using an AI model
1111

12-
In this quickstart, you create a .NET console AI chat app to connect to an AI model with local function calling enabled. The app uses the <xref:Microsoft.Extensions.AI> library so you can write code using AI abstractions rather than a specific SDK. AI abstractions enable you to change the underlying AI model with minimal code changes.
12+
In this quickstart, you create a .NET console AI chat app that connects to an AI model with local function calling enabled. The app uses the <xref:Microsoft.Extensions.AI> library so you can write code using AI abstractions rather than a specific SDK. AI abstractions enable you to change the underlying AI model with minimal code changes.
1313

1414
:::zone target="docs" pivot="openai"
1515

@@ -23,8 +23,6 @@ In this quickstart, you create a .NET console AI chat app to connect to an AI mo
2323

2424
:::zone-end
2525

26-
[!INCLUDE [semantic-kernel](includes/semantic-kernel.md)]
27-
2826
## Create the app
2927

3028
Complete the following steps to create a .NET console app to connect to an AI model.
@@ -103,10 +101,7 @@ The app uses the [`Microsoft.Extensions.AI`](https://www.nuget.org/packages/Micr
103101
104102
:::zone target="docs" pivot="azure-openai"
105103
106-
:::code language="csharp" source="snippets/function-calling/azure-openai/program.cs" id="GetChatClient":::
107-
108-
> [!NOTE]
109-
> <xref:Azure.Identity.DefaultAzureCredential> searches for authentication credentials from your local tooling. If you aren't using the `azd` template to provision the Azure OpenAI resource, you'll need to assign the `Azure AI Developer` role to the account you used to sign in to Visual Studio or the Azure CLI. For more information, see [Authenticate to Azure AI services with .NET](../azure-ai-services-authentication.md).
104+
:::code language="csharp" source="snippets/function-calling/azure-openai/Program.cs" id="GetChatClient":::
110105
111106
:::zone-end
112107
@@ -145,5 +140,6 @@ If you no longer need them, delete the Azure OpenAI resource and GPT-4 model dep
145140
146141
## Next steps
147142
143+
- [Access data in AI functions](../how-to/access-data-in-functions.md)
148144
- [Quickstart - Build an AI chat app with .NET](build-chat-app.md)
149145
- [Generate text and conversations with .NET and Azure OpenAI Completions](/training/modules/open-ai-dotnet-text-completions/)

docs/ai/toc.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ items:
5454
href: conceptual/rag.md
5555
- name: OpenAI function calling
5656
href: conceptual/understanding-openai-functions.md
57+
- name: Call functions
58+
items:
59+
- name: "Quickstart: Execute a local function"
60+
href: quickstarts/use-function-calling.md
61+
- name: Access data in AI functions
62+
href: how-to/access-data-in-functions.md
63+
- name: Text to image
64+
items:
65+
- name: Generate images using MEAI
66+
href: quickstarts/text-to-image.md
67+
- name: Generate images using OpenAI.Images.ImageClient
68+
href: quickstarts/generate-images.md
5769
- name: Chat with your data (RAG)
5870
items:
5971
- name: Get started with the RAG sample
@@ -68,12 +80,6 @@ items:
6880
href: quickstarts/build-mcp-server.md
6981
- name: Build a minimal MCP client
7082
href: quickstarts/build-mcp-client.md
71-
- name: Text to image
72-
items:
73-
- name: Generate images using MEAI
74-
href: quickstarts/text-to-image.md
75-
- name: Generate images using OpenAI.Images.ImageClient
76-
href: quickstarts/generate-images.md
7783
- name: Security and content safety
7884
items:
7985
- name: Authentication for Azure-hosted apps and services

0 commit comments

Comments
 (0)