Tools extend agent capabilities by allowing them to execute code, query databases, call APIs, and interact with external systems. The .NET SDK provides AITool and AIFunction abstractions for defining and using tools with agents.
The simplest way to create functions is using AIFunctionFactory.Create():
using System.ComponentModel;using Microsoft.Agents.AI;using Microsoft.Extensions.AI;[Description("Get the weather for a given location.")]static string GetWeather( [Description("The location to get the weather for.")] string location){ return $"The weather in {location} is sunny with a high of 25°C.";}// Create an AIFunction from the methodAIFunction weatherTool = AIFunctionFactory.Create(GetWeather);// Use it with an agentAIAgent agent = chatClient.AsAIAgent( instructions: "You are a helpful assistant.", tools: [weatherTool]);var response = await agent.RunAsync( "What's the weather like in Seattle?");Console.WriteLine(response.Text);
Use [Description] attributes from System.ComponentModel to provide descriptions for the function and parameters. These help the AI model understand when and how to use the function.
[Description("Search for information on the web.")]static async Task<string> SearchWeb( [Description("The search query.")] string query, CancellationToken cancellationToken = default){ using var client = new HttpClient(); var result = await client.GetStringAsync( $"https://api.example.com/search?q={query}", cancellationToken); return result;}AIFunction searchTool = AIFunctionFactory.Create(SearchWeb);
public class SearchParameters{ [Description("The search query")] public string Query { get; set; } = string.Empty; [Description("Maximum number of results")] public int MaxResults { get; set; } = 10; [Description("Filter by date range")] public DateTime? StartDate { get; set; }}[Description("Search with advanced parameters.")]static string AdvancedSearch(SearchParameters parameters){ return $"Searching for '{parameters.Query}' with max {parameters.MaxResults} results";}AIFunction tool = AIFunctionFactory.Create(AdvancedSearch);
Add tools for specific requests using AgentRunOptions:
AIAgent agent = chatClient.AsAIAgent( instructions: "You are a helpful assistant.");// Add tool for this specific requestvar options = new ChatClientAgentRunOptions(new ChatOptions(){ Tools = [AIFunctionFactory.Create(GetWeather)]});var response = await agent.RunAsync( "What's the weather in Paris?", options: options);
By default, when an agent decides to call a function, the framework automatically:
Extracts parameters from the model’s response
Invokes the function with the parameters
Returns the result to the model
Continues the conversation
AIAgent agent = chatClient.AsAIAgent( instructions: "You are a helpful assistant.", tools: [AIFunctionFactory.Create(GetWeather)]);// The agent will automatically call GetWeather if neededvar response = await agent.RunAsync( "What's the weather in Tokyo?");Console.WriteLine(response.Text);// Output: "The weather in Tokyo is sunny with a high of 25°C."
For sensitive operations, require human approval before execution:
public class ApprovalRequiredAIFunction : AIFunction{ private readonly AIFunction _innerFunction; public ApprovalRequiredAIFunction(AIFunction innerFunction) { _innerFunction = innerFunction; } // Implementation that prompts for approval // See middleware documentation for full implementation}// Wrap sensitive functionsvar deleteFunction = AIFunctionFactory.Create(DeleteFile);var approvalTool = new ApprovalRequiredAIFunction(deleteFunction);AIAgent agent = chatClient.AsAIAgent( instructions: "You are a file management assistant.", tools: [approvalTool]);
[Description("Query the customer database by customer ID.")]static async Task<string> GetCustomerInfo( [Description("The customer ID to look up")] int customerId, CancellationToken cancellationToken = default){ await using var connection = new SqlConnection(connectionString); await connection.OpenAsync(cancellationToken); var command = new SqlCommand( "SELECT Name, Email FROM Customers WHERE Id = @Id", connection); command.Parameters.AddWithValue("@Id", customerId); await using var reader = await command.ExecuteReaderAsync(cancellationToken); if (await reader.ReadAsync(cancellationToken)) { return $"Name: {reader.GetString(0)}, Email: {reader.GetString(1)}"; } return "Customer not found.";}AIFunction dbTool = AIFunctionFactory.Create(GetCustomerInfo);
AIAgent agent = chatClient.AsAIAgent( instructions: "You are a helpful assistant.", tools: [AIFunctionFactory.Create(GetWeather)]);await foreach (var update in agent.RunStreamingAsync( "What's the weather in Seattle?")){ if (!string.IsNullOrEmpty(update.Text)) { Console.Write(update.Text); }}
Customize function metadata with AIFunctionFactoryOptions:
var options = new AIFunctionFactoryOptions{ Name = "weather_lookup", Description = "Get current weather conditions for any city worldwide"};AIFunction tool = AIFunctionFactory.Create(GetWeather, options);
Use descriptive [Description] attributes for functions and parameters. This helps the AI model understand when and how to use the function.
[Description("Search the product catalog by name, category, or SKU.")]static string SearchProducts( [Description("Search term (product name, category, or SKU)")] string query, [Description("Maximum number of results to return (1-100)")] int limit = 10){ // ...}
Handle Errors Gracefully
Functions should handle errors and return meaningful messages:
Some models support calling multiple functions in parallel:
// The model may decide to call multiple functions at oncevar response = await agent.RunAsync( "What's the weather in Paris and Tokyo, and what time is it in both cities?");