Back to chapters

Chapter 3C

Decisions with Reusable Prompts and Native .NET Functions

Workshop (AI Extensions) - Decisions with Reusable Prompts and Native .NET Functions

Decision Intelligence applied in this module:

  • Listing various decision-making frameworks with their descriptions
  • Listing types of decision-making frameworks dynamically based on the decision type
  • Reusing AI Extensions prompt templates with dynamic inputs
  • Selecting a decision-making framework dynamically using native .NET code
  • Decision Scenario: Using a Monte Carlo Simulation to estimate decision uncertainty

AI Extensions prompt templates are reusable instructions that help guide GenAI models toward a specific decision workflow. A prompt template usually has one responsibility: list useful decision frameworks, recommend a reasoning approach for a high-stakes decision, summarize a tradeoff, or personalize a recommendation from structured context.

What makes reusable prompt functions useful? GenAI models can already respond to basic prompts, but decision workflows usually need repeatable instructions, consistent formatting, and dynamic inputs. By combining Microsoft.Extensions.AI with simple C# helper methods, a prompt becomes a reusable part of an AI orchestration flow instead of a one-off string.

For example, imagine you want to prepare a great Thanksgiving dinner and you ask a GenAI cooking application to create a recipe. It may produce a delicious plan, but it may also use ingredients or cooking appliances you do not own. You could keep prompting until it narrows the recipe, but it is better to provide available ingredients, time availability, kitchen appliances, and allergy preferences as dynamic inputs. The same pattern applies to Decision Intelligence: reusable prompt templates let the model consider specific business context, user constraints, and decision criteria each time the prompt runs.


Step 1 - Initialize Configuration Builder & Build the AI Extensions Responses API Orchestration

Execute the next two cells to:

  • Use the Configuration Builder to load the API secrets.
  • Use the API configuration to build a Responses API-backed AI Extensions IChatClient orchestration.
In [1]:
// Import the required NuGet configuration packages
#r "nuget: Microsoft.Extensions.Configuration, 10.0.9"
#r "nuget: Microsoft.Extensions.Configuration.Json, 10.0.9"
#r "nuget: System.Text.Json, 10.0.9"

using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.Configuration;
using System.IO;
using System;

// Load the configuration settings from the local.settings.json and secrets.settings.json files
// The secrets.settings.json file is used to store sensitive information such as API keys
var configurationBuilder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
    .AddJsonFile("secrets.settings.json", optional: true, reloadOnChange: true);
var config = configurationBuilder.Build();

// IMPORTANT: You ONLY NEED either Azure OpenAI or OpenAI connection info, not both.
// Azure OpenAI Connection Info
var azureOpenAIEndpoint = config["AzureOpenAI:Endpoint"];
var azureOpenAIAPIKey = config["AzureOpenAI:APIKey"];
var azureOpenAIModelDeploymentName = config["AzureOpenAI:ModelDeploymentName"];
// OpenAI Connection Info 
var openAIAPIKey = config["OpenAI:APIKey"];
var openAIModelId = config["OpenAI:ModelId"];
// AzureOpenAI or OpenAI selection flag
var useAzureOpenAI = bool.Parse(config["AzureOpenAI:UseAzureOpenAI"] ?? "true");
Installed Packages
  • Microsoft.Extensions.Configuration, 10.0.9
  • Microsoft.Extensions.Configuration.Json, 10.0.9
  • System.Text.Json, 10.0.9
In [23]:
// Import the Microdoft Extensions AI NuGet Packages
#r "nuget: Microsoft.Extensions.AI, 10.7.0"
#r "nuget: Microsoft.Extensions.AI.Abstractions, 10.7.0"
#r "nuget: Microsoft.Extensions.AI.OpenAI, 10.7.0"
// Import Azure & OpenAI NuGet Packages
#r "nuget: Azure.Identity, 1.21.0"
#r "nuget: OpenAI, 2.11.0"

using Azure;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using OpenAI;
using System.ClientModel;
using System.ComponentModel;
using System.Text.Json;


// Create the IChatClient based on the selected service
IChatClient chatClient;

// Create a new MEAI ChatClient instance
if (useAzureOpenAI)
{
    Console.WriteLine("Using Azure OpenAI Service");

    var apiKeyCredential = new ApiKeyCredential(azureOpenAIAPIKey!);

    var azureOpenAIClient = new OpenAIClient(
        apiKeyCredential,
        new OpenAIClientOptions
        {
            Endpoint = new Uri($"{azureOpenAIEndpoint!.TrimEnd('/')}/openai/v1")
        });

    #pragma warning disable OPENAI001
    var responsesClient = azureOpenAIClient.GetResponsesClient();
    chatClient = responsesClient.AsIChatClient(azureOpenAIModelDeploymentName);
}
else
{
    Console.WriteLine("Using OpenAI Service");

    var apiKeyCredential = new ApiKeyCredential(azureOpenAIAPIKey);
    var openAIClient = new OpenAIClient(apiKeyCredential);

    #pragma warning disable OPENAI001
    var responsesClient = openAIClient.GetResponsesClient();
    chatClient = responsesClient.AsIChatClient(defaultModelId: openAIModelId);
}

#pragma warning restore OPENAI001

var decisionIntelligenceSystemPrompt = """
You are a Decision Intelligence assistant.
Help the user explore options, evaluate tradeoffs, reason through uncertainty, solve problems,
and apply systems thinking to personal, professional, strategic, and operational decisions.

Provide responses that are structured, logical, and thorough.
Aim to improve the user's judgment rather than make choices for them.
Be balanced, analytical, and pragmatic.
Adapt depth and complexity to the user's context.
""";

async Task<string> RunPromptAsync(string prompt, ChatOptions? options = null)
{
    ChatResponse response = await chatClient.GetResponseAsync(prompt, options);
    return response.Text ?? string.Empty;
}

async Task<string> RunDecisionPromptAsync(string userPrompt, ChatOptions? options = null)
{
    var chatMessages = new List<ChatMessage>
    {
        new(ChatRole.System, decisionIntelligenceSystemPrompt),
        new(ChatRole.User, userPrompt)
    };

    ChatResponse response = await chatClient.GetResponseAsync(chatMessages, options);
    return response.Text ?? string.Empty;
}

static string GetFunctionResultText(object? result)
{
    if (result is null)
    {
        return string.Empty;
    }

    if (result is JsonElement jsonElement)
    {
        return jsonElement.ValueKind == JsonValueKind.String
            ? jsonElement.GetString() ?? string.Empty
            : jsonElement.ToString();
    }

    return result.ToString() ?? string.Empty;
}
Installed Packages
  • Azure.Identity, 1.21.0
  • Microsoft.Extensions.AI, 10.7.0
  • Microsoft.Extensions.AI.Abstractions, 10.7.0
  • Microsoft.Extensions.AI.OpenAI, 10.7.0
  • OpenAI, 2.11.0
Using Azure OpenAI Service
(60,61): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

(66,73): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

(78,43): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.


Step 2 - Create an AI Extensions Reusable Prompt Function

📜 "Decision frameworks are like maps. Use them to navigate complex decision-making terrain.

-- Unknown

Reusable prompt functions in this notebook are simple C# helper methods that submit prompt templates through IChatClient. This keeps the prompt reusable while using the same AI Extensions API surface shown in the previous workshop notebooks.

In [27]:
// Simple prompt to list some decision frameworks this GenAI LLM is familiar with
var decisionFrameworksPromptTemplate = """
Identify and list various decision-making frameworks that can enhance the quality of decisions. 
Briefly describe how each framework supports better analysis and reasoning in different decision-making scenarios.

Output Format Instructions: 
When generating Markdown, do not use any headings higher than ###. 
Avoid # and ## headers. Use only ###, ####, or lower-level headings if necessary. 
All top-level section headers should start at ### or lower. 
Never use ---, ***, or ___ for horizontal lines. There should be no horizontal lines in the output.
For separation, use extra extra spacing. Do not any render horizontal lines.
Format the response using only a Markdown table. Only return a Markdown table. 
Do not enclose the table in triple backticks.
""";

// Treat the prompt template as a reusable local function that invokes the AI Extensions IChatClient.
async Task<string> RunDecisionFrameworksPromptAsync(ChatOptions? options = null)
{
    return await RunDecisionPromptAsync(decisionFrameworksPromptTemplate, options);
}

var decisionFrameworksResponseText = await RunDecisionFrameworksPromptAsync();
decisionFrameworksResponseText.DisplayAs("text/markdown");
Decision-making framework How it supports better analysis and reasoning Useful scenarios
Rational decision-making model Defines the problem, establishes objectives, generates alternatives, evaluates evidence, and selects the option with the greatest expected value. Structured business, operational, and resource-allocation decisions
Cost–benefit analysis Compares the expected costs and benefits of alternatives, often using monetary estimates and time horizons. Investments, projects, public policy, and procurement
Decision matrix Scores options against weighted criteria, making tradeoffs and priorities explicit. Vendor selection, hiring, product choices, and project prioritization
Expected utility theory Weighs possible outcomes by their probability and value, supporting choices under uncertainty. Financial decisions, insurance, strategy, and risk management
Expected value analysis Calculates the probability-weighted average outcome of each option. Repeated decisions involving measurable risks and returns
Decision trees Maps decisions, uncertain events, probabilities, and consequences in sequence. Multi-stage choices, clinical decisions, investments, and contingency planning
Bayesian decision-making Updates beliefs and estimates as new evidence becomes available, rather than treating initial assumptions as fixed. Diagnosis, forecasting, intelligence analysis, and experimentation
Scenario planning Develops multiple plausible futures and tests strategies against each one. Long-term strategy, uncertain markets, climate risks, and geopolitical planning
SWOT analysis Examines strengths, weaknesses, opportunities, and threats to connect internal capabilities with external conditions. Strategic reviews, market entry, organizational planning, and competitive analysis
PESTLE analysis Assesses political, economic, social, technological, legal, and environmental influences. Environmental scanning, policy decisions, and long-range planning
Porter’s Five Forces Evaluates industry attractiveness through rivalry, supplier power, buyer power, substitutes, and new entrants. Competitive strategy, market analysis, and business-model decisions
OODA loop Uses observe, orient, decide, and act cycles to make and revise decisions quickly as conditions change. Operations, crisis response, military contexts, and dynamic competition
Cynefin framework Classifies situations as clear, complicated, complex, chaotic, or disorderly, then matches the response to the type of uncertainty. Ambiguous problems, crisis management, organizational change, and innovation
Six Thinking Hats Separates analysis into perspectives such as facts, risks, benefits, creativity, emotions, and process control. Group decisions, workshops, brainstorming, and conflict reduction
First-principles thinking Breaks a problem into fundamental facts and constraints, then reconstructs solutions from the basics. Innovation, engineering, cost reduction, and challenging industry assumptions
Systems thinking Examines relationships, feedback loops, delays, dependencies, and unintended consequences across a whole system. Public policy, organizational change, sustainability, and complex operations
Pareto analysis Identifies the small number of causes or actions likely to produce most of the impact. Prioritization, quality improvement, troubleshooting, and workload management
Root-cause analysis Investigates underlying causes rather than treating only visible symptoms. Recurring failures, safety incidents, service problems, and process improvement
Pre-mortem analysis Assumes a proposed decision has failed and asks what caused the failure, exposing overlooked risks. Major projects, strategic commitments, product launches, and high-stakes decisions
Red-team analysis Assigns people to challenge assumptions, identify vulnerabilities, and construct opposing arguments. Security, policy, strategy, investment review, and adversarial environments
Devil’s advocacy Deliberately argues against a preferred option to reduce confirmation bias and groupthink. Executive decisions, board reviews, and controversial proposals
Real options analysis Treats flexibility, delay, expansion, or abandonment as valuable options when uncertainty is high. Research and development, staged investments, technology adoption, and exploration
Multi-criteria decision analysis Integrates quantitative and qualitative criteria while making stakeholder preferences and tradeoffs visible. Public policy, infrastructure, sustainability, and complex procurement
Value of information analysis Estimates whether obtaining additional information is worth its cost and delay. Medical testing, market research, due diligence, and uncertain investments
Minimax regret Chooses the option that limits the worst possible feeling of having made the wrong choice. Decisions with ambiguous probabilities or irreversible consequences
Satisficing Selects an option that meets essential requirements rather than optimizing every criterion. Time-constrained decisions, routine management, and situations with limited information
Recognition-primed decision-making Uses experience to recognize patterns and rapidly evaluate a workable course of action. Emergency response, frontline operations, and experienced professional judgment
Delphi method Collects and iteratively refines anonymous expert judgments to build a more informed consensus. Forecasting, technology assessment, policy planning, and expert estimation
Nominal group technique Structures individual idea generation, discussion, and ranking to prevent dominant voices from controlling the decision. Team prioritization, problem solving, and stakeholder workshops
A/B testing and experimentation Compares alternatives under controlled conditions, using observed outcomes rather than assumptions. Product design, marketing, process changes, and digital services
After-action review Evaluates what was expected, what happened, why differences occurred, and what should change next time. Projects, operations, incidents, and continuous improvement
Ethics-based decision framework Tests options against principles such as fairness, rights, duties, harm reduction, and stakeholder impact. Healthcare, AI, public policy, compliance, and people-related decisions
RAPID or RACI decision-rights frameworks Clarifies who recommends, decides, contributes, executes, and is accountable, reducing ambiguity and delay. Cross-functional projects, governance, and organizational decisions
10-10-10 framework Considers how an option may feel or matter in 10 minutes, 10 months, and 10 years. Personal decisions, career choices, and emotionally charged tradeoffs
Reversibility framework Distinguishes easily reversible choices from difficult-to-reverse commitments and adjusts decision speed accordingly. Product experiments, hiring, capital investments, and strategic commitments
(17,64): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.


Step 3 - AI Extensions Dynamic Decision Intelligence

📜 "If the only tool you have is a hammer, you tend to see every problem as a nail."

-- Abraham Maslow (Renowned American psychologist)

Prompt templates can be dynamically composed using C# variables and raw string interpolation. This allows the ease of passing in parameters and execution settings into reusable prompt functions. This is not groundbreaking, but it does allow you to dynamically compose AI prompts (context-engineering, prompt-engineering dynamically).

Execute the cell below to view how the prompt can dynamically instruct the LLM to retrieve different types of decision-making frameworks.

In [28]:
// Takes input variables and creates a dynamic prompt that can be used to invoke the GenAI model.
string CreateDecisionFrameworkPrompt(int numberOfFrameworks, string decisionType)
{
    return $"""
        Identify and list {numberOfFrameworks} decision-making frameworks that can enhance the quality of decisions. 
        Briefly describe how each framework supports better analysis and reasoning in {decisionType} decision-making scenarios.

        Output Format Instructions: 
        When generating Markdown, do not use any headings higher than ###. 
        Avoid # and ## headers. Use only ###, ####, or lower-level headings if necessary. 
        All top-level section headers should start at ### or lower. 
        Never use ---, ***, or ___ for horizontal lines. There should be no horizontal lines in the output.
        For separation, use extra extra spacing. Do not any render horizontal lines.
        Format the response using only a Markdown table. Only return a Markdown table. 
        Do not enclose the table in triple backticks.
        """;
}

// Create the chat options. 
//Try changing the settings to see how they affect the quality of generated text.
#pragma warning disable OPENAI001

var decisionFrameworkChatOptions = new ChatOptions
{
    RawRepresentationFactory = _ => new OpenAI.Responses.CreateResponseOptions
    {
        Model = useAzureOpenAI ? azureOpenAIModelDeploymentName : openAIModelId,
        ReasoningOptions = new OpenAI.Responses.ResponseReasoningOptions
        {
            ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.Medium,
            ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
        },
        StoredOutputEnabled = false
    }
};

#pragma warning restore OPENAI001

// Dynamically set the number of frameworks and decision type -> strategic
var strategicDecisionFrameworkPrompt = CreateDecisionFrameworkPrompt(
    numberOfFrameworks: 3,
    decisionType: "Long-Term strategic with probabilistic outcomes");

var strategicDecisionFrameworkResponseText = await RunDecisionPromptAsync(
    strategicDecisionFrameworkPrompt,
    decisionFrameworkChatOptions);

strategicDecisionFrameworkResponseText.DisplayAs("text/markdown");
Decision-making framework How it supports better analysis and reasoning in long-term strategic decisions with probabilistic outcomes
Scenario Planning Develops multiple plausible future scenarios rather than relying on a single forecast. It helps decision-makers test strategies against uncertainty, identify key drivers and early-warning indicators, and build flexible plans that remain effective across different future conditions.
Expected Value and Decision-Tree Analysis Breaks complex choices into alternatives, uncertain events, probabilities, and outcomes. By calculating probability-weighted results and comparing pathways, it clarifies trade-offs, exposes assumptions, and supports disciplined evaluation of risks, benefits, and contingent decisions over time.
Real Options Analysis Treats strategic choices as options that can be expanded, delayed, modified, or abandoned as information emerges. This framework accounts for the value of flexibility and staged commitment, helping organizations manage uncertainty while preserving the ability to benefit from favorable future developments.

In the example below, the number of frameworks to return has been changed and the type has been changed to Quick to Implement for rapid Decision-Making.

In [29]:
// Dynamically set the number of frameworks and decision type -> requiring fast action
var rapidDecisionFrameworkPrompt = CreateDecisionFrameworkPrompt(
    numberOfFrameworks: 5,
    decisionType: "Quick to Implement for rapid Decision-Making");

// Note: The invocation has NOT changed, only the dynamic prompt inputs have changed.
var rapidDecisionFrameworkResponseText = await RunDecisionPromptAsync(
    rapidDecisionFrameworkPrompt,
    decisionFrameworkChatOptions);

rapidDecisionFrameworkResponseText.DisplayAs("text/markdown");
Decision-making framework How it supports better analysis and reasoning Quick implementation for rapid decisions
OODA Loop — Observe, Orient, Decide, Act Creates a fast feedback cycle, helping decision-makers update their view as new information appears rather than relying on a one-time judgment. Spend a few minutes identifying current facts, interpreting their meaning, selecting an action, and defining what signal will trigger the next review.
80/20 Rule (Pareto Principle) Focuses attention on the small number of factors likely to produce most of the impact, reducing analysis of low-value details. Ask: “Which two or three factors will most influence the outcome?” Prioritize those before deciding.
Expected Value Analysis Compares options by weighing potential benefits, costs, and probabilities, making uncertainty explicit instead of relying only on intuition. Estimate the likely outcome of each option, multiply impact by probability, and choose the option with the strongest risk-adjusted value.
Satisficing Prevents analysis paralysis by defining what “good enough” means and selecting the first option that meets essential requirements. Set three to five non-negotiable criteria, reject options that fail them, and stop searching once a viable option meets the threshold.
Pre-mortem Analysis Challenges overconfidence by imagining that a decision failed and identifying plausible causes before action is taken. Ask the team, “Assume this decision went badly—what caused the failure?” Address the top one or two risks with safeguards or contingency plans.

Step 4 - Decision Scenario with Dynamic Decision Intelligence

In the below code a decision-analysis scenario is introduced that uses dynamic inputs to personalize the decision recommendation dynamically. The more specific information that provides contextual information to the Generative AI model can greatly improve the specific recommendations.

Decision Scenario: Michael is a 35-year-old professional chef who is considering opening his own restaurant. This is a significant life decision that could greatly impact his career and personal life. Michael is looking for a recommendation for an approach (decision) for this potentially life-changing decision.

Three factors will be considered for this decision scenario that the user will be prompted for:

  1. Michael's Total Net Worth in dollars (enter number)
  2. Level of competition with other restaurants (low, medium, high)
  3. Level of support from Michael's friends and family (low, medium, high)

Various Decision Inputs: You can simulate different What-If scenarios by varying the input of net worth, restaurant competition and level of family support. Note the different decision recommendations based on this provided by Artificial Intelligence. The recommendations in this example are quite simple, but even on the extreme inputs Generative AI has a concept of understanding the quality of inputs.

In [30]:
// Import the Microsoft.DotNet.Interactive namespace for user input
using Microsoft.DotNet.Interactive;

var totalNetWorth = await Microsoft.DotNet.Interactive.Kernel.GetInputAsync("Michael's total net worth in dollars: ");
var levelOfCompetition = await Microsoft.DotNet.Interactive.Kernel.GetInputAsync("Level of competition with other restaurants (Low, Medium, High): ");
var levelOfFamilySupport = await Microsoft.DotNet.Interactive.Kernel.GetInputAsync("Level of support from Michael's friends and family (Low, Medium, High): ");

Console.WriteLine($"Michael's Net Worth: {totalNetWorth}");
Console.WriteLine($"Level of Restaurant Competition: {levelOfCompetition}");
Console.WriteLine($"Michael's level of Family Support: {levelOfFamilySupport}");
Console.WriteLine();

// Takes dynamic inputs and creates a personalized prompt that can be used to invoke the model.
var restaurantDecisionRecommendationPrompt = $"""
Michael is a 35-year-old professional chef who is considering opening his own restaurant. 
This is a significant life decision that could greatly impact his career and personal life. 
Michael is looking for a recommendation on how to approach this.
Some key information about Michael:
- Michael's total net worth is (in US dollars) ${totalNetWorth}.
- The level of competition with other restaurants is {levelOfCompetition}.
- The level of support from Michael's friends and family is {levelOfFamilySupport}.

Based on this information, what recommendation would you give to Michael regarding opening his own restaurant?

Output Format Instructions: 
When generating Markdown, do not use any headings higher than ###. 
Avoid # and ## headers. Use only ###, ####, or lower-level headings if necessary. 
All top-level section headers should start at ### or lower. 
Never use ---, ***, or ___ for horizontal lines. There should be no horizontal lines in the output.
For separation, use extra extra spacing. Do not any render horizontal lines.
Format the response using only a Markdown table. Only return a Markdown table. 
Do not enclose the table in triple backticks.
Provide a small Decision Summary of the recommendation below the table.
""";


#pragma warning disable OPENAI001

// Create the chat options. Try changing the settings to see how they affect the quality of generated text.
var restaurantDecisionChatOptions = new ChatOptions
{
    RawRepresentationFactory = _ => new OpenAI.Responses.CreateResponseOptions
    {
        Model = useAzureOpenAI ? azureOpenAIModelDeploymentName : openAIModelId,
        ReasoningOptions = new OpenAI.Responses.ResponseReasoningOptions
        {
            ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.Medium,
            ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
        },
        StoredOutputEnabled = false
    }
};

var restaurantDecisionRecommendationResponseText = await RunDecisionPromptAsync(
    restaurantDecisionRecommendationPrompt,
    restaurantDecisionChatOptions);

restaurantDecisionRecommendationResponseText.DisplayAs("text/markdown");

#pragma warning restore OPENAI001
Michael's Net Worth: 1000000000000
Level of Restaurant Competition: High
Michael's level of Family Support: Low

Decision factor Assessment Implication for Michael
Financial capacity Extremely strong, with a net worth of $1 trillion He can fund a high-quality concept, absorb losses, and hire experienced operators without putting his personal security at risk.
Market competition High Opening a generic restaurant would be risky. He needs a clearly differentiated concept, compelling location, strong branding, and a defensible customer experience.
Friends and family support Low He should not rely on informal emotional, operational, or financial support. He should build a professional support network, including an experienced restaurant operator, financial controller, legal adviser, and trusted mentors.
Personal readiness Michael has professional culinary experience, but running a restaurant also requires expertise in staffing, marketing, purchasing, compliance, cash-flow management, and operations He should assess whether he wants to be an owner-operator or primarily a chef. If he lacks business experience, he should partner with or hire someone strong in restaurant management.
Recommended approach Proceed, but through a staged and disciplined launch Start with market research, customer testing, a pop-up, catering operation, or smaller pilot concept before committing to a permanent flagship location.
Financial discipline Wealth reduces personal financial risk but does not eliminate business risk Set a defined investment limit, require milestone-based funding, and establish clear criteria for continuing, changing, or closing the venture.
Overall recommendation Open a restaurant only if the concept demonstrates genuine market demand and Michael assembles a capable operating team His financial position makes this a reasonable opportunity to explore, but money alone cannot overcome weak differentiation, poor execution, or lack of support.
Decision Summary
Michael should move forward cautiously rather than immediately opening a full-scale restaurant. His extraordinary financial resources make the downside manageable, but high competition and low personal support increase execution risk. The best path is to validate a distinctive concept through a smaller pilot, recruit experienced business and operations partners, and expand only after the pilot demonstrates strong demand, reliable unit economics, and operational readiness.

Step 5 - Create a Simple Native .NET Function with AI Extensions

Execute the cell below to create a very simple native .NET function using a C# inline method. Notice the function takes no parameters. It retrieves the name of a productivity decision framework to use. In this case, that return name is hard-coded to "Price's Law".

The function returns instantly because it is not calling a GenAI service. The point is to show how Microsoft.Extensions.AI can wrap deterministic .NET logic as a first-class AIFunction.

In [31]:
// Create an AIFunction from an inline C# method.
var nameOfProductivityFramework = AIFunctionFactory.Create(
    (Func<string>)(() => "Price's Law"),
    new AIFunctionFactoryOptions
    {
        Name = "GetNameOfProductivityFramework",
        Description = "Retrieves the name of the Productivity Framework to use."
    });

// Invoke the function directly with AI Extensions.
var response = await nameOfProductivityFramework.InvokeAsync(new AIFunctionArguments());
Console.WriteLine(GetFunctionResultText(response));
Price's Law

Step 6 - Create a Native .NET Function with Dynamic Parameters

Execute the cell below to create a native .NET function that takes a parameter as input. This shows that C# native functions can have different execution paths. The execution paths can obviously be quite complex. Basically, any C# logic flow will work.

In [32]:
// Create an AIFunction from an inline C# method with parameters.
var nameOfProductivityFrameworkByType = AIFunctionFactory.Create(
    (Func<string, string>)(typeOfProductivity => typeOfProductivity == "Sales" ? "Price's Law" : "Pareto Principle"),
    new AIFunctionFactoryOptions
    {
        Name = "GetNameOfProductivityFramework",
        Description = "Retrieves the name of the Productivity Framework to use."
    });

// Pass the "Sales" parameter to the function.
var salesResponse = await nameOfProductivityFrameworkByType.InvokeAsync(new AIFunctionArguments
{
    ["typeOfProductivity"] = "Sales"
});
Console.WriteLine(GetFunctionResultText(salesResponse));

// Pass the "Other" parameter to the function.
var otherResponse = await nameOfProductivityFrameworkByType.InvokeAsync(new AIFunctionArguments
{
    ["typeOfProductivity"] = "Other"
});
Console.WriteLine(GetFunctionResultText(otherResponse));
Price's Law
Pareto Principle

Step 7 - Use Native .NET Functions To Simulate the Uncertainty of a Decision

📜 "The best way to predict the future is to simulate it. And the best way to simulate it is with Monte Carlo."

-- Nassim Nicholas Taleb (Lebanese-American essayist, scholar, best known for his work on probability)

For more complex decisions, native .NET functions can use statistics, advanced probabilistic algorithms, analytics, machine learning, AI, and other approaches that have been relied on in software for decades. One such method is Monte Carlo Simulation. These powerful Monte Carlo simulation techniques are used everywhere: risk management, sports gambling, medical decision-making, game theory, energy market forecasting, and more. In simple terms, a Monte Carlo simulation is a series of many runs testing different plausible parameters.

A simple use case for a Monte Carlo simulation is to visualize the distribution of possible outcomes for an average probability. Imagine you want to illustrate the uncertainty of a decision that you have calculated to be 70% successful. On "average" the probability of success can be interpreted as 70%. However, if that 70% decision model is run 100 times, the actual number of successful outcomes will vary. A Monte Carlo simulation can show that variation as a distribution.

Run the cell below to create a native .NET function that takes the confidence parameter and returns a Markdown distribution. The output uses a simple horizontal bar chart so the likely outcomes can be scanned quickly, similar to a compact sales distribution chart.

In [33]:
string RetrieveMonteCarloDistributionMarkdown(
    [Description("Claimed Probability Percentage")] int probability)
{
    if (probability < 0 || probability > 100)
    {
        throw new ArgumentOutOfRangeException(nameof(probability), "Probability must be between 0 and 100.");
    }

    const int NUMBEROFSIMULATIONS = 100000; // 100,000 simulations, make this smaller for faster results
    const int NUMBEROFDECISIONS = 100;
    const int MAXIMUMBARWIDTH = 24;

    var random = new Random(42); // Fixed seed keeps notebook output reproducible
    var successfulOutcomesPerSimulation = new List<int>();
    var outcomeDistribution = new Dictionary<int, int>();

    for (int i = 0; i != NUMBEROFSIMULATIONS; i++) // Bootstrap Simulations (bootstrap estimates)
    {
        var successfulDecisions = 0;
        for (int j = 0; j != NUMBEROFDECISIONS; j++)
        {
            var randomIndex = random.Next(0, 100);

            if (randomIndex < probability)
            {
                successfulDecisions++;
            }
        }

        successfulOutcomesPerSimulation.Add(successfulDecisions);

        if (!outcomeDistribution.ContainsKey(successfulDecisions))
        {
            outcomeDistribution[successfulDecisions] = 0;
        }

        outcomeDistribution[successfulDecisions]++;
    }

    // Sort the success counts to calculate the central 95% simulated range.
    var successfulOutcomesSorted = successfulOutcomesPerSimulation.OrderBy(a => a).ToList();
    var lowerPercentileIndex = Convert.ToInt32(0.025 * NUMBEROFSIMULATIONS);
    var topPercentileIndex = Convert.ToInt32(0.975 * NUMBEROFSIMULATIONS);
    var lowerPercentile = successfulOutcomesSorted[lowerPercentileIndex];
    var upperPercentile = successfulOutcomesSorted[topPercentileIndex];

    var visibleOutcomes = Enumerable.Range(lowerPercentile, upperPercentile - lowerPercentile + 1).ToList();
    var maximumOutcomeCount = visibleOutcomes.Max(outcome =>
        outcomeDistribution.ContainsKey(outcome) ? outcomeDistribution[outcome] : 0);

    var distributionMarkdown = new System.Text.StringBuilder();
    distributionMarkdown.AppendLine($"### Monte Carlo Distribution ({probability}% Success Model)");
    distributionMarkdown.AppendLine();
    distributionMarkdown.AppendLine("```text");
    distributionMarkdown.AppendLine($"{NUMBEROFSIMULATIONS:n0} simulations, {NUMBEROFDECISIONS} decisions per simulation");
    distributionMarkdown.AppendLine($"Showing central 95% simulated range: {lowerPercentile} to {upperPercentile} successful outcomes");
    distributionMarkdown.AppendLine();

    foreach (var outcome in visibleOutcomes)
    {
        var simulationsAtOutcome = outcomeDistribution.ContainsKey(outcome) ? outcomeDistribution[outcome] : 0;
        var barWidth = simulationsAtOutcome == 0
            ? 0
            : Math.Max(1, Convert.ToInt32(Math.Round((double)simulationsAtOutcome / maximumOutcomeCount * MAXIMUMBARWIDTH)));
        var bar = new string('█', barWidth).PadRight(MAXIMUMBARWIDTH);
        distributionMarkdown.AppendLine($"{outcome,3} successes | {bar} {simulationsAtOutcome:n0}");
    }

    distributionMarkdown.AppendLine("```");
    return distributionMarkdown.ToString();
}

Run the cell below to wrap the native .NET method as an AIFunction and invoke it directly. This will run a Monte Carlo Simulation with 100,000 simulations of a decision with a confidence (probability) of 70% being run 100 times. The result is displayed as a Markdown distribution so the uncertainty pattern is easier to scan than a single interval sentence.

In [34]:
var retrieveMonteCarloDistribution = AIFunctionFactory.Create(
    (Func<int, string>)RetrieveMonteCarloDistributionMarkdown,
    new AIFunctionFactoryOptions
    {
        Name = "RetrieveMonteCarloDistributionMarkdown",
        Description = "Generates a Markdown distribution from a Monte Carlo simulation."
    });

// Change the probability to another integer and invoke the function to see other outcome distributions.
var monteCarloDistribution70 = await retrieveMonteCarloDistribution.InvokeAsync(new AIFunctionArguments
{
    ["probability"] = 70
});

var monteCarloDistributionMarkdown70 = GetFunctionResultText(monteCarloDistribution70);
monteCarloDistributionMarkdown70.DisplayAs("text/markdown");

Monte Carlo Distribution (70% Success Model)

100,000 simulations, 100 decisions per simulation
Showing central 95% simulated range: 61 to 79 successful outcomes

 61 successes | ████                     1,343
 62 successes | █████                    1,955
 63 successes | ███████                  2,653
 64 successes | ██████████               3,516
 65 successes | █████████████            4,655
 66 successes | ████████████████         5,713
 67 successes | ██████████████████       6,654
 68 successes | █████████████████████    7,764
 69 successes | ███████████████████████  8,301
 70 successes | ████████████████████████ 8,717
 71 successes | ███████████████████████  8,480
 72 successes | ██████████████████████   7,969
 73 successes | ████████████████████     7,311
 74 successes | █████████████████        6,184
 75 successes | ██████████████           5,016
 76 successes | ███████████              3,919
 77 successes | ████████                 2,891
 78 successes | █████                    1,911
 79 successes | ████                     1,275