跳到正文

04 · 04-dotnet-agent-framework

返回:工具调用 · 不可变原始文件

原课程脚本 · 未联网执行

保留原始框架与完整代码。依赖、变量、入口以脚本及其相邻 README 为准;本页为代码导读,未声称所有外部服务均已验证。

行为约束:instructions 引导模型,不能替代执行器的权限验证、次数限制和结果检查。

csharp
#!/usr/bin/dotnet run

#:package Microsoft.Extensions.AI@10.*
#:package Microsoft.Agents.AI.OpenAI@1.*-*
#:package Azure.AI.OpenAI@2.1.0
#:package Azure.Identity@1.13.1

using System.ComponentModel;
using System.Text.Json;

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

using Azure.AI.OpenAI;
using Azure.Identity;
using OpenAI.Chat;

// ============================================================================
// TOOL USE DESIGN PATTERN DEMONSTRATION
// ============================================================================
// This sample demonstrates the key concepts from the Tool Use lesson:
// 1. FUNCTION SCHEMAS: Clear descriptions and typed parameters
// 2. MULTIPLE TOOLS: Agent selects the right tool for each task
// 3. TOOL COMPOSITION: Tools can work together to solve complex requests
// 4. PARAMETER HANDLING: Functions with different parameter types
// ============================================================================

// ----------------------------------------------------------------------------
// TOOL 1: Random Destination Generator (No Parameters)
// ----------------------------------------------------------------------------
// Demonstrates: Simple tool with no parameters
[Description("Provides a random vacation destination when the user hasn't specified one.")]
static string GetRandomDestination()
{
    var destinations = new List<string>
    {
        "Paris, France",
        "Tokyo, Japan",
        "New York City, USA",
        "Sydney, Australia",
        "Rome, Italy",
        "Barcelona, Spain",
        "Cape Town, South Africa",
        "Rio de Janeiro, Brazil",
        "Bangkok, Thailand",
        "Vancouver, Canada"
    };

    var random = new Random();
    int index = random.Next(destinations.Count);
    
    Console.WriteLine($"\n[Tool Called] GetRandomDestination() -> {destinations[index]}");
    return destinations[index];
}

// ----------------------------------------------------------------------------
// TOOL 2: Weather Lookup (Single Parameter)
// ----------------------------------------------------------------------------
// Demonstrates: Tool with a required parameter - the LLM must extract
// the location from the user's message and pass it to this function
[Description("Gets the current weather conditions for a specified location. Use this when planning activities or packing suggestions.")]
static string GetWeather(
    [Description("The city and country to get weather for, e.g., 'Paris, France'")] string location)
{
    // Simulated weather data for demonstration
    var weatherConditions = new Dictionary<string, (string condition, int tempC, int tempF)>
    {
        { "paris", ("Partly Cloudy", 18, 64) },
        { "tokyo", ("Sunny", 24, 75) },
        { "new york", ("Rainy", 15, 59) },
        { "sydney", ("Sunny", 28, 82) },
        { "rome", ("Clear", 22, 72) },
        { "barcelona", ("Sunny", 26, 79) },
        { "cape town", ("Windy", 19, 66) },
        { "rio", ("Hot and Humid", 32, 90) },
        { "bangkok", ("Tropical", 33, 91) },
        { "vancouver", ("Overcast", 12, 54) }
    };

    var locationLower = location.ToLower();
    foreach (var (key, weather) in weatherConditions)
    {
        if (locationLower.Contains(key))
        {
            var result = $"Weather in {location}: {weather.condition}, {weather.tempC}°C ({weather.tempF}°F)";
            Console.WriteLine($"\n[Tool Called] GetWeather(\"{location}\") -> {result}");
            return result;
        }
    }

    var defaultResult = $"Weather in {location}: Mild conditions, around 20°C (68°F)";
    Console.WriteLine($"\n[Tool Called] GetWeather(\"{location}\") -> {defaultResult}");
    return defaultResult;
}

// ----------------------------------------------------------------------------
// TOOL 3: Destination Information (Multiple Parameters)
// ----------------------------------------------------------------------------
// Demonstrates: Tool with multiple parameters including an enum-like category
[Description("Gets detailed information about a destination including attractions, cuisine, and travel tips. Use this after selecting a destination to provide rich details.")]
static string GetDestinationInfo(
    [Description("The destination city to get information about")] string destination,
    [Description("The category of information: 'attractions', 'cuisine', 'tips', or 'all'")] string category = "all")
{
    Console.WriteLine($"\n[Tool Called] GetDestinationInfo(\"{destination}\", \"{category}\")");
    
    // Simulated destination data
    var info = new Dictionary<string, Dictionary<string, string>>
    {
        { "paris", new() {
            { "attractions", "Eiffel Tower, Louvre Museum, Notre-Dame, Champs-Élysées" },
            { "cuisine", "Croissants, French onion soup, Coq au vin, Macarons" },
            { "tips", "Metro is efficient, book museums in advance, tip 10-15%" }
        }},
        { "tokyo", new() {
            { "attractions", "Senso-ji Temple, Shibuya Crossing, Tokyo Tower, Akihabara" },
            { "cuisine", "Sushi, Ramen, Tempura, Wagyu beef" },
            { "tips", "Get a Suica card, bow when greeting, shoes off indoors" }
        }},
        { "rome", new() {
            { "attractions", "Colosseum, Vatican, Trevi Fountain, Pantheon" },
            { "cuisine", "Pasta Carbonara, Pizza al taglio, Gelato, Tiramisu" },
            { "tips", "Book Vatican early, carry water bottle, siesta 1-4pm" }
        }}
    };

    var destLower = destination.ToLower();
    foreach (var (key, data) in info)
    {
        if (destLower.Contains(key))
        {
            if (category.ToLower() == "all")
            {
                return JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
            }
            if (data.TryGetValue(category.ToLower(), out var value))
            {
                return $"{category} in {destination}: {value}";
            }
        }
    }

    return $"Information about {destination}: A wonderful destination with rich culture and experiences.";
}

// ----------------------------------------------------------------------------
// TOOL 4: Trip Cost Estimator (Numeric Parameters)
// ----------------------------------------------------------------------------
// Demonstrates: Tool with numeric parameters for calculations
[Description("Estimates the total trip cost based on destination, duration, and budget level. Returns a cost breakdown.")]
static string EstimateTripCost(
    [Description("The destination city")] string destination,
    [Description("Number of days for the trip")] int days,
    [Description("Budget level: 'budget', 'moderate', or 'luxury'")] string budgetLevel = "moderate")
{
    Console.WriteLine($"\n[Tool Called] EstimateTripCost(\"{destination}\", {days}, \"{budgetLevel}\")");
    
    var dailyRates = new Dictionary<string, int>
    {
        { "budget", 100 },
        { "moderate", 250 },
        { "luxury", 500 }
    };

    var rate = dailyRates.GetValueOrDefault(budgetLevel.ToLower(), 250);
    var accommodation = rate * days;
    var food = (rate / 2) * days;
    var activities = (rate / 3) * days;
    var total = accommodation + food + activities;

    return $"""
        Trip Cost Estimate for {destination} ({days} days, {budgetLevel}):
        - Accommodation: ${accommodation}
        - Food & Dining: ${food}
        - Activities: ${activities}
        - Estimated Total: ${total}
        """;
}

// Azure OpenAI with the Responses API (stable v1 endpoint). Sign in with `az login`.
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
    ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deployment = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT") ?? "gpt-5-mini";

var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential());

// Agent Identity
var AGENT_NAME = "TravelAgent";

// ============================================================================
// AGENT INSTRUCTIONS - Tool Use Expert
// ============================================================================
var AGENT_INSTRUCTIONS = """
You are a travel planning AI Agent with access to multiple specialized tools.

## Available Tools

You have access to these tools - use them appropriately:

1. **GetRandomDestination**: Suggests a random destination (no parameters needed)
2. **GetWeather**: Gets weather for a location (requires: location)
3. **GetDestinationInfo**: Gets attraction/cuisine/tips (requires: destination, optional: category)
4. **EstimateTripCost**: Calculates costs (requires: destination, days; optional: budgetLevel)

## Tool Usage Guidelines

- **Chain tools together** for comprehensive responses (e.g., destination → weather → info → cost)
- **Extract parameters** from the user's message to pass to tools
- **Choose the right tool** based on what the user is asking
- When the user asks for a "complete trip plan", use multiple tools

## Response Format

After using tools, synthesize the information into a helpful, well-organized response.
Always mention which tools you used so users understand the agent's capabilities.
""";

// Create AI Agent with Multiple Tools
// This demonstrates the Tool Use Design Pattern with a variety of tool types
AIAgent agent = azureClient
    .GetChatClient(deployment)
    .AsAIAgent(
        name: AGENT_NAME,
        instructions: AGENT_INSTRUCTIONS,
        tools: [
            AIFunctionFactory.Create(GetRandomDestination),
            AIFunctionFactory.Create(GetWeather),
            AIFunctionFactory.Create(GetDestinationInfo),
            AIFunctionFactory.Create(EstimateTripCost)
        ]
    );

// Create Conversation Session
AgentSession session = await agent.CreateSessionAsync();


// ============================================================================
// DEMONSTRATION 1: Tool Selection - Agent picks the right tool
// ============================================================================
Console.WriteLine("=== Tool Use Design Pattern Demonstration ===\n");
Console.WriteLine("--- Demo 1: Tool Selection ---");
Console.WriteLine("User: What's the weather like in Tokyo?\n");
Console.WriteLine("Agent Response:");

await foreach (var update in agent.RunStreamingAsync("What's the weather like in Tokyo?", session))
{
    await Task.Delay(10);
    Console.Write(update);
}

Console.WriteLine("\n");

// ============================================================================
// DEMONSTRATION 2: Parameterized Tool Calling
// ============================================================================
Console.WriteLine("--- Demo 2: Parameterized Tool with Multiple Parameters ---");
Console.WriteLine("User: How much would a 5-day luxury trip to Rome cost?\n");
Console.WriteLine("Agent Response:");

await foreach (var update in agent.RunStreamingAsync("How much would a 5-day luxury trip to Rome cost?", session))
{
    await Task.Delay(10);
    Console.Write(update);
}

Console.WriteLine("\n");

// ============================================================================
// DEMONSTRATION 3: Tool Composition - Multiple tools for complex requests
// ============================================================================
Console.WriteLine("--- Demo 3: Tool Composition ---");
Console.WriteLine("User: Plan me a complete trip - suggest a destination and give me all the details including weather and costs for a 3-day moderate budget trip.\n");
Console.WriteLine("Agent Response:");

await foreach (var update in agent.RunStreamingAsync(
    "Plan me a complete trip - suggest a destination and give me all the details including weather and costs for a 3-day moderate budget trip.", 
    session))
{
    await Task.Delay(10);
    Console.Write(update);
}

基于 Microsoft AI Agents for Beginners · 非官方中文学习版

100%