[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-dotnet-technology-selection":3,"mdc--jgrqc0-key":37,"related-org-dotnet-technology-selection":3073,"related-repo-dotnet-technology-selection":3236},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":32,"sourceUrl":35,"mdContent":36},"technology-selection","implement AI features in .NET applications","Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent Framework (MAF), GitHub Copilot SDK, ONNX Runtime, and OllamaSharp. Covers the full spectrum from classic ML through modern LLM orchestration to local inference. Use when adding classification, regression, clustering, anomaly detection, recommendation, LLM integration (text generation, summarization, reasoning), RAG pipelines with vector search, agentic workflows with tool calling, Copilot extensions, or custom model inference via ONNX Runtime to a .NET project. DO NOT USE FOR projects targeting .NET Framework (requires .NET 8+), the task is pure data engineering or ETL with no ML\u002FAI component, or the project needs a custom deep learning training loop (use Python with PyTorch\u002FTensorFlow, then export to ONNX for .NET inference).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"dotnet",".NET (Microsoft)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fdotnet.png",[12,16,19,22],{"name":13,"slug":14,"type":15},"LLM","llm","tag",{"name":17,"slug":18,"type":15},".NET","net",{"name":20,"slug":21,"type":15},"Microsoft","microsoft",{"name":23,"slug":24,"type":15},"AI Infrastructure","ai-infrastructure",4576,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills","2026-07-12T08:24:22.582818","MIT",332,[31],"agent-skills",{"repoUrl":26,"stars":25,"forks":29,"topics":33,"description":34},[31],"Repository for skills to assist AI coding agents with .NET and C#","https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills\u002Ftree\u002FHEAD\u002Fplugins\u002Fdotnet-ai\u002Fskills\u002Ftechnology-selection","---\nname: technology-selection\ndescription: \"Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent Framework (MAF), GitHub Copilot SDK, ONNX Runtime, and OllamaSharp. Covers the full spectrum from classic ML through modern LLM orchestration to local inference. Use when adding classification, regression, clustering, anomaly detection, recommendation, LLM integration (text generation, summarization, reasoning), RAG pipelines with vector search, agentic workflows with tool calling, Copilot extensions, or custom model inference via ONNX Runtime to a .NET project. DO NOT USE FOR projects targeting .NET Framework (requires .NET 8+), the task is pure data engineering or ETL with no ML\u002FAI component, or the project needs a custom deep learning training loop (use Python with PyTorch\u002FTensorFlow, then export to ONNX for .NET inference).\"\nlicense: MIT\n---\n\n# .NET AI and Machine Learning\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Task description | Yes | What the AI\u002FML feature should accomplish (e.g., \"classify support tickets\", \"summarize documents\") |\n| Data description | Yes | Type and shape of input data (structured\u002Ftabular, unstructured text, images, mixed) |\n| Deployment constraints | No | Cloud vs. local, latency SLO, cost budget, offline requirements |\n| Existing project context | No | Current .csproj, existing packages, target framework |\n\n## Workflow\n\n### Step 1: Classify the task using the decision tree\n\nEvaluate the developer's task against this decision tree and select the appropriate technology. State which branch applies and why.\n\n| Task type | Technology | Rationale |\n|-----------|-----------|-----------|\n| Structured\u002Ftabular data: classification, regression, clustering, anomaly detection, recommendation | **ML.NET** (`Microsoft.ML`) | Reproducible (given a fixed seed and dataset), no cloud dependency, purpose-built models for these tasks |\n| Natural language understanding, generation, summarization, reasoning over unstructured text (single prompt → response, no tool calling) | **LLM via Microsoft.Extensions.AI** (`IChatClient`) | Requires language model capabilities beyond pattern matching; no orchestration needed |\n| Agentic workflows: tool\u002Ffunction calling, multi-step reasoning, agent loops, multi-agent collaboration | **Microsoft Agent Framework** (`Microsoft.Agents.AI`) built on top of **Microsoft.Extensions.AI** | Requires orchestration, tool dispatch, iteration control, and guardrails that `IChatClient` alone does not provide |\n| Building GitHub Copilot extensions, custom agents, or developer workflow tools | **GitHub Copilot SDK** (`GitHub.Copilot.SDK`) | Integrates with the Copilot agent runtime for IDE and CLI extensibility |\n| Running a pre-trained or fine-tuned custom model in production | **ONNX Runtime** (`Microsoft.ML.OnnxRuntime`) | Hardware-accelerated inference, model-format agnostic |\n| Local\u002Foffline LLM inference with no cloud dependency | **OllamaSharp** with local [AI models supported by Ollama](https:\u002F\u002Follama.com\u002Fsearch) | Privacy-sensitive, air-gapped, or cost-constrained scenarios |\n| Semantic search, RAG, or embedding storage | **Microsoft.Extensions.VectorData.Abstractions** + a vector database provider (e.g., Azure AI Search, Milvus, MongoDB, pgvector, Pinecone, Qdrant, Redis, SQL) | Provider-agnostic abstractions for vector similarity search; pair with a database-specific connector package (many are moving to community toolkits) |\n| Ingesting, chunking, and loading documents into a vector store | **Microsoft.Extensions.AI.DataIngestion** (preview) + **Microsoft.Extensions.VectorData.Abstractions** (MEVD) | Handles document parsing, text chunking, embedding generation, and upserting into a vector database; pairs with Microsoft.Extensions.VectorData.Abstractions |\n| Both structured ML predictions AND natural language reasoning | **Hybrid**: ML.NET for predictions + LLM for reasoning layer | Keep loosely coupled; ML.NET handles reproducible scoring, LLM adds explanation |\n\n**Critical rule:** Do NOT use an LLM for tasks that ML.NET handles well (classification on tabular data, regression, clustering). LLMs are slower, more expensive, and non-deterministic for these tasks.\n\n### Step 1b: Select the correct library layer\n\nAfter identifying the task type, select the right library layer. These libraries form a stack — each builds on the one below it. Using the wrong layer is a major source of non-deterministic agent behavior.\n\n| Layer | Library | NuGet package | Use when |\n|-------|---------|---------------|----------|\n| **Abstraction** | Microsoft.Extensions.AI (MEAI) | `Microsoft.Extensions.AI` | You need a provider-agnostic interface for chat, embeddings, or tool calling. This is the foundation — always include it. Use `IChatClient` directly **only** for simple prompt-in\u002Fresponse-out scenarios with no tool calling or agentic loops. If the task involves tools, agents, or multi-step reasoning, you must add the Orchestration layer above. |\n| **Provider SDK** | OpenAI, Azure.AI.OpenAI, Azure.AI.Inference, OllamaSharp | `OpenAI`, `Azure.AI.OpenAI`, `Azure.AI.Inference`, `OllamaSharp` | You need a concrete LLM provider implementation. These wire into MEAI via `AddChatClient`. Use `OpenAI` for direct OpenAI access, `Azure.AI.OpenAI` for Azure OpenAI, `Azure.AI.Inference` for Azure AI Foundry \u002F GitHub Models, or `OllamaSharp` for local Ollama. Use directly only if you need provider-specific features not exposed through MEAI. |\n| **Orchestration** | Microsoft Agent Framework | `Microsoft.Agents.AI` (prerelease) | The task involves tool\u002Ffunction calling, agentic loops, multi-step reasoning, multi-agent coordination, durable context, or graph-based workflows. **This is required whenever the scenario involves agents or tools — do not hand-roll tool dispatch loops with `IChatClient`.** Builds on top of MEAI. **Note:** This package is currently prerelease — use `dotnet add package Microsoft.Agents.AI --prerelease` to install it. |\n| **Copilot integration** | GitHub Copilot SDK | `GitHub.Copilot.SDK` | You are building extensions or tools that integrate with the GitHub Copilot runtime — custom agents, IDE extensions, or developer workflow automation that leverages the Copilot agent platform. |\n\n#### Decision rules for library selection\n\n1. **Start with MEAI.** Every AI integration begins with `Microsoft.Extensions.AI` for the `IChatClient` \u002F `IEmbeddingGenerator` abstractions. This ensures provider-swappability and testability.\n\n2. **Add a provider SDK** (`OpenAI`, `Azure.AI.OpenAI`) as the concrete implementation behind MEAI. Do not call the provider SDK directly in business logic — always go through the MEAI abstraction.\n\n3. **Use Agent Framework (`Microsoft.Agents.AI`) for any task that involves tools or agents.** If the task is a single prompt → response with no tool calling, MEAI is sufficient. **You MUST use `Microsoft.Agents.AI`** when any of these apply:\n   - Tool\u002Ffunction calling (agent decides which tools to invoke)\n   - Multi-step reasoning with state carried across turns\n   - Agentic loops that iterate until a goal is met\n   - Multi-agent collaboration with handoff protocols\n   - Graph-based or durable workflows\n\n   Do **not** implement these patterns by hand with `IChatClient` — the Agent Framework provides iteration limits, observability, and tool dispatch that are error-prone to reimplement.\n\n4. **Add Copilot SDK only when building Copilot extensions.** Use `GitHub.Copilot.SDK` when the goal is to build a custom agent or tool that runs inside the GitHub Copilot platform (CLI, IDE, or Copilot Chat). This is not a general-purpose LLM orchestration library — it is specifically for Copilot extensibility.\n\n5. **Never skip layers.** Do not use Agent Framework without MEAI underneath. Do not call `HttpClient` to OpenAI alongside MEAI in the same workflow. Each layer depends on the one below it.\n\n### Step 2: Select packages and set up the project\n\nInstall only the packages needed for the selected technology branch. Do not mix competing abstractions.\n\n#### Classic ML packages\n\n```xml\n\u003CPackageReference Include=\"Microsoft.ML\" Version=\"4.*\" \u002F>\n\u003CPackageReference Include=\"Microsoft.ML.AutoML\" Version=\"0.*\" \u002F>\n\u003C!-- Only if custom numerical work is needed: -->\nPackageReference Include=\"System.Numerics.Tensors\" Version=\"10.*\"\n\u003CPackageReference Include=\"MathNet.Numerics\" Version=\"5.*\" \u002F>\n\u003C!-- Only for data exploration: -->\n\u003CPackageReference Include=\"Microsoft.Data.Analysis\" Version=\"0.*\" \u002F>\n```\n\n> **Do NOT use** Accord.NET — it is archived and unmaintained.\n\n#### Modern AI packages\n\n```xml\n\u003C!-- Always start with the abstraction layer -->\n\u003CPackageReference Include=\"Microsoft.Extensions.AI\" Version=\"9.*\" \u002F>\n\n\u003C!-- Orchestration (agents, workflows, tools, memory) — prerelease; use dotnet add package Microsoft.Agents.AI --prerelease -->\n\u003CPackageReference Include=\"Microsoft.Agents.AI\" Version=\"1.*-*\" \u002F>\n\n\u003C!-- Cloud LLM provider (pick one) -->\n\u003CPackageReference Include=\"Azure.AI.OpenAI\" Version=\"2.*\" \u002F>\n\u003C!-- OR -->\n\u003CPackageReference Include=\"OpenAI\" Version=\"2.*\" \u002F>\n\n\u003C!-- Client-side token counting for cost management -->\n    \u003CPackageReference Include=\"Microsoft.ML.Tokenizers\" Version=\"2.*\" \n\n\u003C!-- Local LLM inference -->\n\u003CPackageReference Include=\"OllamaSharp\" Version=\"5.*\" \u002F>\n\n\u003C!-- Custom model inference -->\n\u003CPackageReference Include=\"Microsoft.ML.OnnxRuntime\" Version=\"1.*\" \u002F>\n\n\u003C!-- Vector store abstraction -->\n\u003CPackageReference Include=\"Microsoft.Extensions.VectorData.Abstractions\" Version=\"9.*\" \u002F>\n\n\u003C!-- Document ingestion, chunking, and vector store loading (preview) -->\n\u003CPackageReference Include=\"Microsoft.Extensions.AI.DataIngestion\" Version=\"9.*-*\" \u002F>\n\n\u003C!-- Copilot platform extensibility -->\n\u003CPackageReference Include=\"GitHub.Copilot.SDK\" Version=\"1.*\" \u002F>\n```\n\n> **Stack coherence rule:** Never mix raw SDK calls (`HttpClient` to OpenAI) with `Microsoft.Extensions.AI`, Microsoft Agent Framework, or Copilot SDK in the same workflow. Pick one abstraction layer per workflow boundary and commit to it. See Step 1b for the layering rules.\n\n#### Register services with dependency injection\n\nAll AI\u002FML services must be registered via DI. Never instantiate clients directly in business logic.\n\n```csharp\n\u002F\u002F Configuration via IOptions\u003CT>\nservices.Configure\u003CAiOptions>(configuration.GetSection(\"AI\"));\n\n\u002F\u002F Register the AI client through the abstraction\nservices.AddChatClient(builder => builder\n    .UseOpenAIChatClient(\"gpt-4o-mini-2024-07-18\"));\n```\n\n### Step 3: Implement with guardrails\n\nApply the guardrails for the selected technology branch. Every generated implementation must follow these rules.\n\n#### Classic ML guardrails\n\n1. **Reproducibility**: Always set a random seed in the ML context:\n   ```csharp\n   var mlContext = new MLContext(seed: 42);\n   ```\n\n2. **Data splitting**: Always split into train\u002Ftest (and optionally validation). Never evaluate on training data:\n   ```csharp\n   var split = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);\n   ```\n\n3. **Metrics logging**: Always compute and log evaluation metrics appropriate to the task:\n   ```csharp\n   var metrics = mlContext.BinaryClassification.Evaluate(predictions);\n   logger.LogInformation(\"AUC: {Auc:F4}, F1: {F1:F4}\", metrics.AreaUnderRocCurve, metrics.F1Score);\n   ```\n\n4. **AutoML first**: Prefer `mlContext.Auto()` for initial model selection, then refine manually.\n\n5. **PredictionEngine pooling**: In ASP.NET Core, always use the pooled prediction engine — never a singleton:\n   ```csharp\n   services.AddPredictionEnginePool\u003CModelInput, ModelOutput>()\n       .FromFile(modelPath);\n   ```\n\n#### LLM integration guardrails\n\n1. **Temperature**: Always set explicitly. Use `0` for factual\u002Fdeterministic tasks:\n   ```csharp\n   var options = new ChatOptions\n   {\n       Temperature = 0f,\n       MaxOutputTokens = 1024,\n   };\n   ```\n\n2. **Structured output**: Always parse LLM output into strongly-typed objects with fallback handling:\n   ```csharp\n   var result = await chatClient.GetResponseAsync\u003CMySchema>(prompt, options, cancellationToken);\n   ```\n\n3. **Retry logic**: Always implement retry with exponential backoff:\n   ```csharp\n   services.AddChatClient(builder => builder\n       .UseOpenAIChatClient(modelId)\n       .Use(new RetryingChatClient(maxRetries: 3)));\n   ```\n\n4. **Cost control**: Always estimate and log token usage. Use Microsoft.ML.Tokenizers to count tokens client-side before sending requests so you can enforce budgets proactively. Choose the smallest model tier that meets quality requirements (e.g., gpt-4o-mini before gpt-4o).\n\n5. **Secret management**: Never hardcode API keys. Use Azure Key Vault, user-secrets, or environment variables:\n   ```csharp\n   var apiKey = configuration[\"AI:ApiKey\"]\n       ?? throw new InvalidOperationException(\"AI:ApiKey not configured\");\n   ```\n\n6. **Model version pinning**: Specify exact model versions to reduce behavioral drift:\n   ```csharp\n   \u002F\u002F Pin to a specific dated version, not just \"gpt-4o\"\n   var modelId = \"gpt-4o-2024-08-06\";\n   ```\n\n#### Agentic workflow guardrails\n\n0. **Use `Microsoft.Agents.AI` for all agentic workflows.** Do not implement tool dispatch loops or multi-step agent reasoning by hand with `IChatClient`. The Agent Framework provides `ChatClientAgent` (or `AgentWorker`) which handles the tool call → result → re-prompt cycle with built-in guardrails. All rules below assume you are using `Microsoft.Agents.AI`.\n\n1. **Iteration limits**: Always cap agentic loops to prevent runaway execution:\n   ```csharp\n   var settings = new AgentInvokeOptions\n   {\n       MaximumIterations = 10,\n   };\n   ```\n\n2. **Cost ceiling**: Implement a token budget per execution and terminate when reached. Use Microsoft.ML.Tokenizers to count prompt and completion tokens locally and compare against the budget before each iteration.\n\n3. **Observability**: Log non-sensitive metadata for every agent step. Never log raw `message.Content` — it may contain user prompts, tool outputs, secrets, or PII that persist in plaintext in central logging systems:\n   ```csharp\n   await foreach (var message in agent.InvokeStreamingAsync(history, settings))\n   {\n       logger.LogDebug(\"Agent step: Role={Role}, ContentLength={Length}\",\n           message.Role, message.Content?.Length ?? 0);\n   }\n   ```\n\n4. **Tool schemas**: Define explicit tool\u002Ffunction schemas with descriptions. Never rely on implicit tool discovery.\n\n5. **Simplicity preference**: Prefer single-agent with tools over multi-agent unless the task genuinely requires agent collaboration.\n\n#### RAG guardrails\n\n1. **Embedding caching**: Never re-embed the same content on every query. Cache embeddings in the vector store.\n\n2. **Chunking strategy**: Use semantic chunking (split on paragraph\u002Fsection boundaries) over fixed-size chunking. Ensure chunks have enough context to be useful on their own.\n\n3. **Relevance thresholds**: Do not inject low-relevance chunks into context. Set a minimum similarity score:\n   ```csharp\n   var results = await vectorStore.SearchAsync(query, new VectorSearchOptions\n   {\n       Top = 5,\n       MinimumScore = 0.75f,\n   });\n   ```\n\n4. **Source attribution**: Track which chunks contributed to the final response. Include source references in the output.\n\n5. **Batch embeddings**: Batch embedding API calls where possible to reduce latency and cost.\n\n### Step 4: Handle non-determinism\n\nWhen the solution involves LLM calls or agentic workflows, explicitly address non-determinism:\n\n1. **Acknowledge it**: Inform the developer that LLM outputs are non-deterministic even at temperature 0 (due to batching, quantization, and model updates).\n\n2. **Validate outputs**: Implement schema validation and content assertion checks on every LLM response.\n\n3. **Graceful degradation**: Design a fallback path for when the LLM returns unexpected, malformed, or empty output:\n   ```csharp\n   var response = await chatClient.GetResponseAsync\u003CClassificationResult>(prompt, options);\n   if (response is null || !response.IsValid())\n   {\n       logger.LogWarning(\"LLM returned invalid response, falling back to rule-based classifier\");\n       return ruleBasedClassifier.Classify(input);\n   }\n   ```\n\n4. **Evaluation harness**: For any prompt that will be iterated on, recommend creating a golden dataset and evaluation scaffold to measure prompt quality over time.\n\n5. **Model version pinning**: Pin to specific dated model versions (e.g., `gpt-4o-2024-08-06`) to reduce drift between deployments.\n\n### Step 5: Apply performance and cost controls\n\n1. **Connection pooling**: Use `IHttpClientFactory` and DI-managed clients for all external services.\n\n2. **Response caching**: Cache repeated or similar queries. Consider semantic caching for LLM responses where appropriate.\n\n3. **Streaming**: Use `IAsyncEnumerable` for LLM responses in user-facing scenarios to reduce time-to-first-token:\n   ```csharp\n   await foreach (var update in chatClient.GetStreamingResponseAsync(prompt, options))\n   {\n       yield return update.Text;\n   }\n   ```\n\n4. **Health checks**: Implement health checks for external AI service dependencies:\n   ```csharp\n   services.AddHealthChecks()\n       .AddCheck\u003COpenAIHealthCheck>(\"openai\");\n   ```\n\n5. **ML.NET prediction pooling**: In web applications, always use `PredictionEnginePool\u003CTIn, TOut>`, never a single `PredictionEngine` instance (it is not thread-safe).\n\n### Step 6: Validate the implementation\n\n1. Build the project and verify no warnings:\n   ```bash\n   dotnet build -c Release -warnaserror\n   ```\n\n2. Run tests, including integration tests that validate AI\u002FML behavior:\n   ```bash\n   dotnet test -c Release\n   ```\n\n3. For ML.NET pipelines, verify that evaluation metrics meet the project's quality bar and that the model can be serialized and loaded correctly.\n\n4. For LLM integrations, verify that structured output parsing handles both valid and malformed responses.\n\n5. For RAG pipelines, verify that retrieval returns relevant results and that irrelevant chunks are filtered out.\n\n## Validation\n\n- [ ] Technology selection follows the decision tree — LLMs are not used for tasks ML.NET handles\n- [ ] All AI\u002FML services are registered via dependency injection\n- [ ] Configuration uses `IOptions\u003CT>` pattern — no hardcoded values\n- [ ] API keys are loaded from secure sources — not in source code or committed config files\n- [ ] ML.NET pipelines set a random seed and split data for evaluation\n- [ ] LLM calls set temperature, max tokens, and retry logic explicitly\n- [ ] Agentic workflows have iteration limits and cost ceilings\n- [ ] RAG pipelines implement chunking, relevance thresholds, and source attribution\n- [ ] Non-deterministic outputs have validation and fallback paths\n- [ ] `dotnet build -c Release -warnaserror` completes cleanly\n\n## Anti-Patterns to Reject\n\nWhen reviewing or generating code, flag and redirect the developer if any of these patterns are detected:\n\n| Anti-pattern | Redirect |\n|-------------|----------|\n| Using an LLM for classification on structured\u002Ftabular data | Use ML.NET instead — it is faster, cheaper, and deterministic |\n| Calling LLM APIs without retry or timeout logic | Add `RetryingChatClient` or Polly-based retry with exponential backoff |\n| Storing API keys in `appsettings.json` committed to source control | Use user-secrets (dev), environment variables, or Azure Key Vault (prod) |\n| Using Accord.NET for new projects | Migrate to ML.NET — Accord.NET is archived and unmaintained |\n| Building custom neural networks in .NET from scratch | Use a pre-trained model via ONNX Runtime or call an LLM API |\n| RAG without chunking strategy or relevance filtering | Implement semantic chunking and set a minimum similarity score threshold |\n| Agentic loops without iteration limits or cost ceilings | Add `MaximumIterations` and a token budget ceiling |\n| Using MEAI `IChatClient` with raw `HttpClient` calls to the same provider | Pick one abstraction layer and commit to it |\n| Implementing tool calling or agentic loops manually with `IChatClient` instead of using `Microsoft.Agents.AI` | Use `Microsoft.Agents.AI` — it provides iteration limits (`MaximumIterations`), built-in tool dispatch, observability hooks, and cost controls. Hand-rolled loops lack these guardrails. |\n| Using Agent Framework for a single prompt→response call | Use MEAI `IChatClient` directly — Agent Framework is for multi-step orchestration |\n| Using Copilot SDK for general-purpose LLM apps | Copilot SDK is for Copilot platform extensions only — use MEAI + Agent Framework for standalone apps |\n| Calling OpenAI SDK directly in business logic instead of through MEAI | Register the provider via `AddChatClient` and depend on `IChatClient` in business code |\n| Using `PredictionEngine` as a singleton in ASP.NET Core | Use `PredictionEnginePool\u003CTIn, TOut>` — `PredictionEngine` is not thread-safe |\n| Using `Func\u003CReadOnlySpan\u003CT>>` for delegates with ref struct parameters | Define a custom delegate type — ref structs cannot be generic type arguments |\n| Using `Microsoft.SemanticKernel` for new projects | Use `Microsoft.Extensions.AI` + `Microsoft.Agents.AI` — Semantic Kernel is superseded by these newer abstractions for LLM orchestration and tool calling |\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Over-engineering with LLMs | Start with the simplest approach (rules, ML.NET) and add LLM capability only when simpler methods fall short |\n| Evaluating ML models on training data | Always use `TrainTestSplit` and report metrics on the held-out test set |\n| LLM output drift between deployments | Pin to specific dated model versions (e.g., `gpt-4o-2024-08-06`) |\n| Token cost surprises | Set `MaxOutputTokens`, use Microsoft.ML.Tokenizers for accurate client-side token counting, log token counts per request, and alert on budget thresholds |\n| Non-reproducible ML training | Set `MLContext(seed: N)` and version your training data alongside the code |\n| RAG returning irrelevant context | Set a minimum similarity score and limit the number of injected chunks |\n| Cold start latency on ML.NET models | Pre-warm the `PredictionEnginePool` during application startup |\n| Microsoft Agent Framework + raw OpenAI SDK in same class | Choose one orchestration layer per workflow boundary |\n",{"data":38,"body":39},{"name":4,"description":6,"license":28},{"type":40,"children":41},"root",[42,51,58,161,167,174,180,476,486,492,497,746,753,925,931,936,942,1018,1032,1038,1284,1311,1317,1322,1378,1384,1389,1395,1530,1536,1744,1750,1941,1947,2046,2052,2057,2170,2176,2320,2326,2420,2426,2540,2546,2551,2898,2904,3067],{"type":43,"tag":44,"props":45,"children":47},"element","h1",{"id":46},"net-ai-and-machine-learning",[48],{"type":49,"value":50},"text",".NET AI and Machine Learning",{"type":43,"tag":52,"props":53,"children":55},"h2",{"id":54},"inputs",[56],{"type":49,"value":57},"Inputs",{"type":43,"tag":59,"props":60,"children":61},"table",{},[62,86],{"type":43,"tag":63,"props":64,"children":65},"thead",{},[66],{"type":43,"tag":67,"props":68,"children":69},"tr",{},[70,76,81],{"type":43,"tag":71,"props":72,"children":73},"th",{},[74],{"type":49,"value":75},"Input",{"type":43,"tag":71,"props":77,"children":78},{},[79],{"type":49,"value":80},"Required",{"type":43,"tag":71,"props":82,"children":83},{},[84],{"type":49,"value":85},"Description",{"type":43,"tag":87,"props":88,"children":89},"tbody",{},[90,109,126,144],{"type":43,"tag":67,"props":91,"children":92},{},[93,99,104],{"type":43,"tag":94,"props":95,"children":96},"td",{},[97],{"type":49,"value":98},"Task description",{"type":43,"tag":94,"props":100,"children":101},{},[102],{"type":49,"value":103},"Yes",{"type":43,"tag":94,"props":105,"children":106},{},[107],{"type":49,"value":108},"What the AI\u002FML feature should accomplish (e.g., \"classify support tickets\", \"summarize documents\")",{"type":43,"tag":67,"props":110,"children":111},{},[112,117,121],{"type":43,"tag":94,"props":113,"children":114},{},[115],{"type":49,"value":116},"Data description",{"type":43,"tag":94,"props":118,"children":119},{},[120],{"type":49,"value":103},{"type":43,"tag":94,"props":122,"children":123},{},[124],{"type":49,"value":125},"Type and shape of input data (structured\u002Ftabular, unstructured text, images, mixed)",{"type":43,"tag":67,"props":127,"children":128},{},[129,134,139],{"type":43,"tag":94,"props":130,"children":131},{},[132],{"type":49,"value":133},"Deployment constraints",{"type":43,"tag":94,"props":135,"children":136},{},[137],{"type":49,"value":138},"No",{"type":43,"tag":94,"props":140,"children":141},{},[142],{"type":49,"value":143},"Cloud vs. local, latency SLO, cost budget, offline requirements",{"type":43,"tag":67,"props":145,"children":146},{},[147,152,156],{"type":43,"tag":94,"props":148,"children":149},{},[150],{"type":49,"value":151},"Existing project context",{"type":43,"tag":94,"props":153,"children":154},{},[155],{"type":49,"value":138},{"type":43,"tag":94,"props":157,"children":158},{},[159],{"type":49,"value":160},"Current .csproj, existing packages, target framework",{"type":43,"tag":52,"props":162,"children":164},{"id":163},"workflow",[165],{"type":49,"value":166},"Workflow",{"type":43,"tag":168,"props":169,"children":171},"h3",{"id":170},"step-1-classify-the-task-using-the-decision-tree",[172],{"type":49,"value":173},"Step 1: Classify the task using the decision tree",{"type":43,"tag":175,"props":176,"children":177},"p",{},[178],{"type":49,"value":179},"Evaluate the developer's task against this decision tree and select the appropriate technology. State which branch applies and why.",{"type":43,"tag":59,"props":181,"children":182},{},[183,204],{"type":43,"tag":63,"props":184,"children":185},{},[186],{"type":43,"tag":67,"props":187,"children":188},{},[189,194,199],{"type":43,"tag":71,"props":190,"children":191},{},[192],{"type":49,"value":193},"Task type",{"type":43,"tag":71,"props":195,"children":196},{},[197],{"type":49,"value":198},"Technology",{"type":43,"tag":71,"props":200,"children":201},{},[202],{"type":49,"value":203},"Rationale",{"type":43,"tag":87,"props":205,"children":206},{},[207,240,269,311,340,369,401,424,453],{"type":43,"tag":67,"props":208,"children":209},{},[210,215,235],{"type":43,"tag":94,"props":211,"children":212},{},[213],{"type":49,"value":214},"Structured\u002Ftabular data: classification, regression, clustering, anomaly detection, recommendation",{"type":43,"tag":94,"props":216,"children":217},{},[218,224,226,233],{"type":43,"tag":219,"props":220,"children":221},"strong",{},[222],{"type":49,"value":223},"ML.NET",{"type":49,"value":225}," (",{"type":43,"tag":227,"props":228,"children":230},"code",{"className":229},[],[231],{"type":49,"value":232},"Microsoft.ML",{"type":49,"value":234},")",{"type":43,"tag":94,"props":236,"children":237},{},[238],{"type":49,"value":239},"Reproducible (given a fixed seed and dataset), no cloud dependency, purpose-built models for these tasks",{"type":43,"tag":67,"props":241,"children":242},{},[243,248,264],{"type":43,"tag":94,"props":244,"children":245},{},[246],{"type":49,"value":247},"Natural language understanding, generation, summarization, reasoning over unstructured text (single prompt → response, no tool calling)",{"type":43,"tag":94,"props":249,"children":250},{},[251,256,257,263],{"type":43,"tag":219,"props":252,"children":253},{},[254],{"type":49,"value":255},"LLM via Microsoft.Extensions.AI",{"type":49,"value":225},{"type":43,"tag":227,"props":258,"children":260},{"className":259},[],[261],{"type":49,"value":262},"IChatClient",{"type":49,"value":234},{"type":43,"tag":94,"props":265,"children":266},{},[267],{"type":49,"value":268},"Requires language model capabilities beyond pattern matching; no orchestration needed",{"type":43,"tag":67,"props":270,"children":271},{},[272,277,299],{"type":43,"tag":94,"props":273,"children":274},{},[275],{"type":49,"value":276},"Agentic workflows: tool\u002Ffunction calling, multi-step reasoning, agent loops, multi-agent collaboration",{"type":43,"tag":94,"props":278,"children":279},{},[280,285,286,292,294],{"type":43,"tag":219,"props":281,"children":282},{},[283],{"type":49,"value":284},"Microsoft Agent Framework",{"type":49,"value":225},{"type":43,"tag":227,"props":287,"children":289},{"className":288},[],[290],{"type":49,"value":291},"Microsoft.Agents.AI",{"type":49,"value":293},") built on top of ",{"type":43,"tag":219,"props":295,"children":296},{},[297],{"type":49,"value":298},"Microsoft.Extensions.AI",{"type":43,"tag":94,"props":300,"children":301},{},[302,304,309],{"type":49,"value":303},"Requires orchestration, tool dispatch, iteration control, and guardrails that ",{"type":43,"tag":227,"props":305,"children":307},{"className":306},[],[308],{"type":49,"value":262},{"type":49,"value":310}," alone does not provide",{"type":43,"tag":67,"props":312,"children":313},{},[314,319,335],{"type":43,"tag":94,"props":315,"children":316},{},[317],{"type":49,"value":318},"Building GitHub Copilot extensions, custom agents, or developer workflow tools",{"type":43,"tag":94,"props":320,"children":321},{},[322,327,328,334],{"type":43,"tag":219,"props":323,"children":324},{},[325],{"type":49,"value":326},"GitHub Copilot SDK",{"type":49,"value":225},{"type":43,"tag":227,"props":329,"children":331},{"className":330},[],[332],{"type":49,"value":333},"GitHub.Copilot.SDK",{"type":49,"value":234},{"type":43,"tag":94,"props":336,"children":337},{},[338],{"type":49,"value":339},"Integrates with the Copilot agent runtime for IDE and CLI extensibility",{"type":43,"tag":67,"props":341,"children":342},{},[343,348,364],{"type":43,"tag":94,"props":344,"children":345},{},[346],{"type":49,"value":347},"Running a pre-trained or fine-tuned custom model in production",{"type":43,"tag":94,"props":349,"children":350},{},[351,356,357,363],{"type":43,"tag":219,"props":352,"children":353},{},[354],{"type":49,"value":355},"ONNX Runtime",{"type":49,"value":225},{"type":43,"tag":227,"props":358,"children":360},{"className":359},[],[361],{"type":49,"value":362},"Microsoft.ML.OnnxRuntime",{"type":49,"value":234},{"type":43,"tag":94,"props":365,"children":366},{},[367],{"type":49,"value":368},"Hardware-accelerated inference, model-format agnostic",{"type":43,"tag":67,"props":370,"children":371},{},[372,377,396],{"type":43,"tag":94,"props":373,"children":374},{},[375],{"type":49,"value":376},"Local\u002Foffline LLM inference with no cloud dependency",{"type":43,"tag":94,"props":378,"children":379},{},[380,385,387],{"type":43,"tag":219,"props":381,"children":382},{},[383],{"type":49,"value":384},"OllamaSharp",{"type":49,"value":386}," with local ",{"type":43,"tag":388,"props":389,"children":393},"a",{"href":390,"rel":391},"https:\u002F\u002Follama.com\u002Fsearch",[392],"nofollow",[394],{"type":49,"value":395},"AI models supported by Ollama",{"type":43,"tag":94,"props":397,"children":398},{},[399],{"type":49,"value":400},"Privacy-sensitive, air-gapped, or cost-constrained scenarios",{"type":43,"tag":67,"props":402,"children":403},{},[404,409,419],{"type":43,"tag":94,"props":405,"children":406},{},[407],{"type":49,"value":408},"Semantic search, RAG, or embedding storage",{"type":43,"tag":94,"props":410,"children":411},{},[412,417],{"type":43,"tag":219,"props":413,"children":414},{},[415],{"type":49,"value":416},"Microsoft.Extensions.VectorData.Abstractions",{"type":49,"value":418}," + a vector database provider (e.g., Azure AI Search, Milvus, MongoDB, pgvector, Pinecone, Qdrant, Redis, SQL)",{"type":43,"tag":94,"props":420,"children":421},{},[422],{"type":49,"value":423},"Provider-agnostic abstractions for vector similarity search; pair with a database-specific connector package (many are moving to community toolkits)",{"type":43,"tag":67,"props":425,"children":426},{},[427,432,448],{"type":43,"tag":94,"props":428,"children":429},{},[430],{"type":49,"value":431},"Ingesting, chunking, and loading documents into a vector store",{"type":43,"tag":94,"props":433,"children":434},{},[435,440,442,446],{"type":43,"tag":219,"props":436,"children":437},{},[438],{"type":49,"value":439},"Microsoft.Extensions.AI.DataIngestion",{"type":49,"value":441}," (preview) + ",{"type":43,"tag":219,"props":443,"children":444},{},[445],{"type":49,"value":416},{"type":49,"value":447}," (MEVD)",{"type":43,"tag":94,"props":449,"children":450},{},[451],{"type":49,"value":452},"Handles document parsing, text chunking, embedding generation, and upserting into a vector database; pairs with Microsoft.Extensions.VectorData.Abstractions",{"type":43,"tag":67,"props":454,"children":455},{},[456,461,471],{"type":43,"tag":94,"props":457,"children":458},{},[459],{"type":49,"value":460},"Both structured ML predictions AND natural language reasoning",{"type":43,"tag":94,"props":462,"children":463},{},[464,469],{"type":43,"tag":219,"props":465,"children":466},{},[467],{"type":49,"value":468},"Hybrid",{"type":49,"value":470},": ML.NET for predictions + LLM for reasoning layer",{"type":43,"tag":94,"props":472,"children":473},{},[474],{"type":49,"value":475},"Keep loosely coupled; ML.NET handles reproducible scoring, LLM adds explanation",{"type":43,"tag":175,"props":477,"children":478},{},[479,484],{"type":43,"tag":219,"props":480,"children":481},{},[482],{"type":49,"value":483},"Critical rule:",{"type":49,"value":485}," Do NOT use an LLM for tasks that ML.NET handles well (classification on tabular data, regression, clustering). LLMs are slower, more expensive, and non-deterministic for these tasks.",{"type":43,"tag":168,"props":487,"children":489},{"id":488},"step-1b-select-the-correct-library-layer",[490],{"type":49,"value":491},"Step 1b: Select the correct library layer",{"type":43,"tag":175,"props":493,"children":494},{},[495],{"type":49,"value":496},"After identifying the task type, select the right library layer. These libraries form a stack — each builds on the one below it. Using the wrong layer is a major source of non-deterministic agent behavior.",{"type":43,"tag":59,"props":498,"children":499},{},[500,526],{"type":43,"tag":63,"props":501,"children":502},{},[503],{"type":43,"tag":67,"props":504,"children":505},{},[506,511,516,521],{"type":43,"tag":71,"props":507,"children":508},{},[509],{"type":49,"value":510},"Layer",{"type":43,"tag":71,"props":512,"children":513},{},[514],{"type":49,"value":515},"Library",{"type":43,"tag":71,"props":517,"children":518},{},[519],{"type":49,"value":520},"NuGet package",{"type":43,"tag":71,"props":522,"children":523},{},[524],{"type":49,"value":525},"Use when",{"type":43,"tag":87,"props":527,"children":528},{},[529,572,659,718],{"type":43,"tag":67,"props":530,"children":531},{},[532,540,545,553],{"type":43,"tag":94,"props":533,"children":534},{},[535],{"type":43,"tag":219,"props":536,"children":537},{},[538],{"type":49,"value":539},"Abstraction",{"type":43,"tag":94,"props":541,"children":542},{},[543],{"type":49,"value":544},"Microsoft.Extensions.AI (MEAI)",{"type":43,"tag":94,"props":546,"children":547},{},[548],{"type":43,"tag":227,"props":549,"children":551},{"className":550},[],[552],{"type":49,"value":298},{"type":43,"tag":94,"props":554,"children":555},{},[556,558,563,565,570],{"type":49,"value":557},"You need a provider-agnostic interface for chat, embeddings, or tool calling. This is the foundation — always include it. Use ",{"type":43,"tag":227,"props":559,"children":561},{"className":560},[],[562],{"type":49,"value":262},{"type":49,"value":564}," directly ",{"type":43,"tag":219,"props":566,"children":567},{},[568],{"type":49,"value":569},"only",{"type":49,"value":571}," for simple prompt-in\u002Fresponse-out scenarios with no tool calling or agentic loops. If the task involves tools, agents, or multi-step reasoning, you must add the Orchestration layer above.",{"type":43,"tag":67,"props":573,"children":574},{},[575,583,588,618],{"type":43,"tag":94,"props":576,"children":577},{},[578],{"type":43,"tag":219,"props":579,"children":580},{},[581],{"type":49,"value":582},"Provider SDK",{"type":43,"tag":94,"props":584,"children":585},{},[586],{"type":49,"value":587},"OpenAI, Azure.AI.OpenAI, Azure.AI.Inference, OllamaSharp",{"type":43,"tag":94,"props":589,"children":590},{},[591,597,599,605,606,612,613],{"type":43,"tag":227,"props":592,"children":594},{"className":593},[],[595],{"type":49,"value":596},"OpenAI",{"type":49,"value":598},", ",{"type":43,"tag":227,"props":600,"children":602},{"className":601},[],[603],{"type":49,"value":604},"Azure.AI.OpenAI",{"type":49,"value":598},{"type":43,"tag":227,"props":607,"children":609},{"className":608},[],[610],{"type":49,"value":611},"Azure.AI.Inference",{"type":49,"value":598},{"type":43,"tag":227,"props":614,"children":616},{"className":615},[],[617],{"type":49,"value":384},{"type":43,"tag":94,"props":619,"children":620},{},[621,623,629,631,636,638,643,645,650,652,657],{"type":49,"value":622},"You need a concrete LLM provider implementation. These wire into MEAI via ",{"type":43,"tag":227,"props":624,"children":626},{"className":625},[],[627],{"type":49,"value":628},"AddChatClient",{"type":49,"value":630},". Use ",{"type":43,"tag":227,"props":632,"children":634},{"className":633},[],[635],{"type":49,"value":596},{"type":49,"value":637}," for direct OpenAI access, ",{"type":43,"tag":227,"props":639,"children":641},{"className":640},[],[642],{"type":49,"value":604},{"type":49,"value":644}," for Azure OpenAI, ",{"type":43,"tag":227,"props":646,"children":648},{"className":647},[],[649],{"type":49,"value":611},{"type":49,"value":651}," for Azure AI Foundry \u002F GitHub Models, or ",{"type":43,"tag":227,"props":653,"children":655},{"className":654},[],[656],{"type":49,"value":384},{"type":49,"value":658}," for local Ollama. Use directly only if you need provider-specific features not exposed through MEAI.",{"type":43,"tag":67,"props":660,"children":661},{},[662,670,674,684],{"type":43,"tag":94,"props":663,"children":664},{},[665],{"type":43,"tag":219,"props":666,"children":667},{},[668],{"type":49,"value":669},"Orchestration",{"type":43,"tag":94,"props":671,"children":672},{},[673],{"type":49,"value":284},{"type":43,"tag":94,"props":675,"children":676},{},[677,682],{"type":43,"tag":227,"props":678,"children":680},{"className":679},[],[681],{"type":49,"value":291},{"type":49,"value":683}," (prerelease)",{"type":43,"tag":94,"props":685,"children":686},{},[687,689,701,703,708,710,716],{"type":49,"value":688},"The task involves tool\u002Ffunction calling, agentic loops, multi-step reasoning, multi-agent coordination, durable context, or graph-based workflows. ",{"type":43,"tag":219,"props":690,"children":691},{},[692,694,699],{"type":49,"value":693},"This is required whenever the scenario involves agents or tools — do not hand-roll tool dispatch loops with ",{"type":43,"tag":227,"props":695,"children":697},{"className":696},[],[698],{"type":49,"value":262},{"type":49,"value":700},".",{"type":49,"value":702}," Builds on top of MEAI. ",{"type":43,"tag":219,"props":704,"children":705},{},[706],{"type":49,"value":707},"Note:",{"type":49,"value":709}," This package is currently prerelease — use ",{"type":43,"tag":227,"props":711,"children":713},{"className":712},[],[714],{"type":49,"value":715},"dotnet add package Microsoft.Agents.AI --prerelease",{"type":49,"value":717}," to install it.",{"type":43,"tag":67,"props":719,"children":720},{},[721,729,733,741],{"type":43,"tag":94,"props":722,"children":723},{},[724],{"type":43,"tag":219,"props":725,"children":726},{},[727],{"type":49,"value":728},"Copilot integration",{"type":43,"tag":94,"props":730,"children":731},{},[732],{"type":49,"value":326},{"type":43,"tag":94,"props":734,"children":735},{},[736],{"type":43,"tag":227,"props":737,"children":739},{"className":738},[],[740],{"type":49,"value":333},{"type":43,"tag":94,"props":742,"children":743},{},[744],{"type":49,"value":745},"You are building extensions or tools that integrate with the GitHub Copilot runtime — custom agents, IDE extensions, or developer workflow automation that leverages the Copilot agent platform.",{"type":43,"tag":747,"props":748,"children":750},"h4",{"id":749},"decision-rules-for-library-selection",[751],{"type":49,"value":752},"Decision rules for library selection",{"type":43,"tag":754,"props":755,"children":756},"ol",{},[757,790,812,890,907],{"type":43,"tag":758,"props":759,"children":760},"li",{},[761,766,768,773,775,780,782,788],{"type":43,"tag":219,"props":762,"children":763},{},[764],{"type":49,"value":765},"Start with MEAI.",{"type":49,"value":767}," Every AI integration begins with ",{"type":43,"tag":227,"props":769,"children":771},{"className":770},[],[772],{"type":49,"value":298},{"type":49,"value":774}," for the ",{"type":43,"tag":227,"props":776,"children":778},{"className":777},[],[779],{"type":49,"value":262},{"type":49,"value":781}," \u002F ",{"type":43,"tag":227,"props":783,"children":785},{"className":784},[],[786],{"type":49,"value":787},"IEmbeddingGenerator",{"type":49,"value":789}," abstractions. This ensures provider-swappability and testability.",{"type":43,"tag":758,"props":791,"children":792},{},[793,798,799,804,805,810],{"type":43,"tag":219,"props":794,"children":795},{},[796],{"type":49,"value":797},"Add a provider SDK",{"type":49,"value":225},{"type":43,"tag":227,"props":800,"children":802},{"className":801},[],[803],{"type":49,"value":596},{"type":49,"value":598},{"type":43,"tag":227,"props":806,"children":808},{"className":807},[],[809],{"type":49,"value":604},{"type":49,"value":811},") as the concrete implementation behind MEAI. Do not call the provider SDK directly in business logic — always go through the MEAI abstraction.",{"type":43,"tag":758,"props":813,"children":814},{},[815,827,829,839,841,870,874,876,881,883,888],{"type":43,"tag":219,"props":816,"children":817},{},[818,820,825],{"type":49,"value":819},"Use Agent Framework (",{"type":43,"tag":227,"props":821,"children":823},{"className":822},[],[824],{"type":49,"value":291},{"type":49,"value":826},") for any task that involves tools or agents.",{"type":49,"value":828}," If the task is a single prompt → response with no tool calling, MEAI is sufficient. ",{"type":43,"tag":219,"props":830,"children":831},{},[832,834],{"type":49,"value":833},"You MUST use ",{"type":43,"tag":227,"props":835,"children":837},{"className":836},[],[838],{"type":49,"value":291},{"type":49,"value":840}," when any of these apply:",{"type":43,"tag":842,"props":843,"children":844},"ul",{},[845,850,855,860,865],{"type":43,"tag":758,"props":846,"children":847},{},[848],{"type":49,"value":849},"Tool\u002Ffunction calling (agent decides which tools to invoke)",{"type":43,"tag":758,"props":851,"children":852},{},[853],{"type":49,"value":854},"Multi-step reasoning with state carried across turns",{"type":43,"tag":758,"props":856,"children":857},{},[858],{"type":49,"value":859},"Agentic loops that iterate until a goal is met",{"type":43,"tag":758,"props":861,"children":862},{},[863],{"type":49,"value":864},"Multi-agent collaboration with handoff protocols",{"type":43,"tag":758,"props":866,"children":867},{},[868],{"type":49,"value":869},"Graph-based or durable workflows",{"type":43,"tag":871,"props":872,"children":873},"br",{},[],{"type":49,"value":875},"Do ",{"type":43,"tag":219,"props":877,"children":878},{},[879],{"type":49,"value":880},"not",{"type":49,"value":882}," implement these patterns by hand with ",{"type":43,"tag":227,"props":884,"children":886},{"className":885},[],[887],{"type":49,"value":262},{"type":49,"value":889}," — the Agent Framework provides iteration limits, observability, and tool dispatch that are error-prone to reimplement.",{"type":43,"tag":758,"props":891,"children":892},{},[893,898,900,905],{"type":43,"tag":219,"props":894,"children":895},{},[896],{"type":49,"value":897},"Add Copilot SDK only when building Copilot extensions.",{"type":49,"value":899}," Use ",{"type":43,"tag":227,"props":901,"children":903},{"className":902},[],[904],{"type":49,"value":333},{"type":49,"value":906}," when the goal is to build a custom agent or tool that runs inside the GitHub Copilot platform (CLI, IDE, or Copilot Chat). This is not a general-purpose LLM orchestration library — it is specifically for Copilot extensibility.",{"type":43,"tag":758,"props":908,"children":909},{},[910,915,917,923],{"type":43,"tag":219,"props":911,"children":912},{},[913],{"type":49,"value":914},"Never skip layers.",{"type":49,"value":916}," Do not use Agent Framework without MEAI underneath. Do not call ",{"type":43,"tag":227,"props":918,"children":920},{"className":919},[],[921],{"type":49,"value":922},"HttpClient",{"type":49,"value":924}," to OpenAI alongside MEAI in the same workflow. Each layer depends on the one below it.",{"type":43,"tag":168,"props":926,"children":928},{"id":927},"step-2-select-packages-and-set-up-the-project",[929],{"type":49,"value":930},"Step 2: Select packages and set up the project",{"type":43,"tag":175,"props":932,"children":933},{},[934],{"type":49,"value":935},"Install only the packages needed for the selected technology branch. Do not mix competing abstractions.",{"type":43,"tag":747,"props":937,"children":939},{"id":938},"classic-ml-packages",[940],{"type":49,"value":941},"Classic ML packages",{"type":43,"tag":943,"props":944,"children":949},"pre",{"className":945,"code":946,"language":947,"meta":948,"style":948},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003CPackageReference Include=\"Microsoft.ML\" Version=\"4.*\" \u002F>\n\u003CPackageReference Include=\"Microsoft.ML.AutoML\" Version=\"0.*\" \u002F>\n\u003C!-- Only if custom numerical work is needed: -->\nPackageReference Include=\"System.Numerics.Tensors\" Version=\"10.*\"\n\u003CPackageReference Include=\"MathNet.Numerics\" Version=\"5.*\" \u002F>\n\u003C!-- Only for data exploration: -->\n\u003CPackageReference Include=\"Microsoft.Data.Analysis\" Version=\"0.*\" \u002F>\n","xml","",[950],{"type":43,"tag":227,"props":951,"children":952},{"__ignoreMap":948},[953,964,973,982,991,1000,1009],{"type":43,"tag":954,"props":955,"children":958},"span",{"class":956,"line":957},"line",1,[959],{"type":43,"tag":954,"props":960,"children":961},{},[962],{"type":49,"value":963},"\u003CPackageReference Include=\"Microsoft.ML\" Version=\"4.*\" \u002F>\n",{"type":43,"tag":954,"props":965,"children":967},{"class":956,"line":966},2,[968],{"type":43,"tag":954,"props":969,"children":970},{},[971],{"type":49,"value":972},"\u003CPackageReference Include=\"Microsoft.ML.AutoML\" Version=\"0.*\" \u002F>\n",{"type":43,"tag":954,"props":974,"children":976},{"class":956,"line":975},3,[977],{"type":43,"tag":954,"props":978,"children":979},{},[980],{"type":49,"value":981},"\u003C!-- Only if custom numerical work is needed: -->\n",{"type":43,"tag":954,"props":983,"children":985},{"class":956,"line":984},4,[986],{"type":43,"tag":954,"props":987,"children":988},{},[989],{"type":49,"value":990},"PackageReference Include=\"System.Numerics.Tensors\" Version=\"10.*\"\n",{"type":43,"tag":954,"props":992,"children":994},{"class":956,"line":993},5,[995],{"type":43,"tag":954,"props":996,"children":997},{},[998],{"type":49,"value":999},"\u003CPackageReference Include=\"MathNet.Numerics\" Version=\"5.*\" \u002F>\n",{"type":43,"tag":954,"props":1001,"children":1003},{"class":956,"line":1002},6,[1004],{"type":43,"tag":954,"props":1005,"children":1006},{},[1007],{"type":49,"value":1008},"\u003C!-- Only for data exploration: -->\n",{"type":43,"tag":954,"props":1010,"children":1012},{"class":956,"line":1011},7,[1013],{"type":43,"tag":954,"props":1014,"children":1015},{},[1016],{"type":49,"value":1017},"\u003CPackageReference Include=\"Microsoft.Data.Analysis\" Version=\"0.*\" \u002F>\n",{"type":43,"tag":1019,"props":1020,"children":1021},"blockquote",{},[1022],{"type":43,"tag":175,"props":1023,"children":1024},{},[1025,1030],{"type":43,"tag":219,"props":1026,"children":1027},{},[1028],{"type":49,"value":1029},"Do NOT use",{"type":49,"value":1031}," Accord.NET — it is archived and unmaintained.",{"type":43,"tag":747,"props":1033,"children":1035},{"id":1034},"modern-ai-packages",[1036],{"type":49,"value":1037},"Modern AI packages",{"type":43,"tag":943,"props":1039,"children":1041},{"className":945,"code":1040,"language":947,"meta":948,"style":948},"\u003C!-- Always start with the abstraction layer -->\n\u003CPackageReference Include=\"Microsoft.Extensions.AI\" Version=\"9.*\" \u002F>\n\n\u003C!-- Orchestration (agents, workflows, tools, memory) — prerelease; use dotnet add package Microsoft.Agents.AI --prerelease -->\n\u003CPackageReference Include=\"Microsoft.Agents.AI\" Version=\"1.*-*\" \u002F>\n\n\u003C!-- Cloud LLM provider (pick one) -->\n\u003CPackageReference Include=\"Azure.AI.OpenAI\" Version=\"2.*\" \u002F>\n\u003C!-- OR -->\n\u003CPackageReference Include=\"OpenAI\" Version=\"2.*\" \u002F>\n\n\u003C!-- Client-side token counting for cost management -->\n    \u003CPackageReference Include=\"Microsoft.ML.Tokenizers\" Version=\"2.*\" \n\n\u003C!-- Local LLM inference -->\n\u003CPackageReference Include=\"OllamaSharp\" Version=\"5.*\" \u002F>\n\n\u003C!-- Custom model inference -->\n\u003CPackageReference Include=\"Microsoft.ML.OnnxRuntime\" Version=\"1.*\" \u002F>\n\n\u003C!-- Vector store abstraction -->\n\u003CPackageReference Include=\"Microsoft.Extensions.VectorData.Abstractions\" Version=\"9.*\" \u002F>\n\n\u003C!-- Document ingestion, chunking, and vector store loading (preview) -->\n\u003CPackageReference Include=\"Microsoft.Extensions.AI.DataIngestion\" Version=\"9.*-*\" \u002F>\n\n\u003C!-- Copilot platform extensibility -->\n\u003CPackageReference Include=\"GitHub.Copilot.SDK\" Version=\"1.*\" \u002F>\n",[1042],{"type":43,"tag":227,"props":1043,"children":1044},{"__ignoreMap":948},[1045,1053,1061,1070,1078,1086,1093,1101,1110,1119,1128,1136,1145,1154,1162,1171,1180,1188,1197,1206,1214,1223,1232,1240,1249,1258,1266,1275],{"type":43,"tag":954,"props":1046,"children":1047},{"class":956,"line":957},[1048],{"type":43,"tag":954,"props":1049,"children":1050},{},[1051],{"type":49,"value":1052},"\u003C!-- Always start with the abstraction layer -->\n",{"type":43,"tag":954,"props":1054,"children":1055},{"class":956,"line":966},[1056],{"type":43,"tag":954,"props":1057,"children":1058},{},[1059],{"type":49,"value":1060},"\u003CPackageReference Include=\"Microsoft.Extensions.AI\" Version=\"9.*\" \u002F>\n",{"type":43,"tag":954,"props":1062,"children":1063},{"class":956,"line":975},[1064],{"type":43,"tag":954,"props":1065,"children":1067},{"emptyLinePlaceholder":1066},true,[1068],{"type":49,"value":1069},"\n",{"type":43,"tag":954,"props":1071,"children":1072},{"class":956,"line":984},[1073],{"type":43,"tag":954,"props":1074,"children":1075},{},[1076],{"type":49,"value":1077},"\u003C!-- Orchestration (agents, workflows, tools, memory) — prerelease; use dotnet add package Microsoft.Agents.AI --prerelease -->\n",{"type":43,"tag":954,"props":1079,"children":1080},{"class":956,"line":993},[1081],{"type":43,"tag":954,"props":1082,"children":1083},{},[1084],{"type":49,"value":1085},"\u003CPackageReference Include=\"Microsoft.Agents.AI\" Version=\"1.*-*\" \u002F>\n",{"type":43,"tag":954,"props":1087,"children":1088},{"class":956,"line":1002},[1089],{"type":43,"tag":954,"props":1090,"children":1091},{"emptyLinePlaceholder":1066},[1092],{"type":49,"value":1069},{"type":43,"tag":954,"props":1094,"children":1095},{"class":956,"line":1011},[1096],{"type":43,"tag":954,"props":1097,"children":1098},{},[1099],{"type":49,"value":1100},"\u003C!-- Cloud LLM provider (pick one) -->\n",{"type":43,"tag":954,"props":1102,"children":1104},{"class":956,"line":1103},8,[1105],{"type":43,"tag":954,"props":1106,"children":1107},{},[1108],{"type":49,"value":1109},"\u003CPackageReference Include=\"Azure.AI.OpenAI\" Version=\"2.*\" \u002F>\n",{"type":43,"tag":954,"props":1111,"children":1113},{"class":956,"line":1112},9,[1114],{"type":43,"tag":954,"props":1115,"children":1116},{},[1117],{"type":49,"value":1118},"\u003C!-- OR -->\n",{"type":43,"tag":954,"props":1120,"children":1122},{"class":956,"line":1121},10,[1123],{"type":43,"tag":954,"props":1124,"children":1125},{},[1126],{"type":49,"value":1127},"\u003CPackageReference Include=\"OpenAI\" Version=\"2.*\" \u002F>\n",{"type":43,"tag":954,"props":1129,"children":1131},{"class":956,"line":1130},11,[1132],{"type":43,"tag":954,"props":1133,"children":1134},{"emptyLinePlaceholder":1066},[1135],{"type":49,"value":1069},{"type":43,"tag":954,"props":1137,"children":1139},{"class":956,"line":1138},12,[1140],{"type":43,"tag":954,"props":1141,"children":1142},{},[1143],{"type":49,"value":1144},"\u003C!-- Client-side token counting for cost management -->\n",{"type":43,"tag":954,"props":1146,"children":1148},{"class":956,"line":1147},13,[1149],{"type":43,"tag":954,"props":1150,"children":1151},{},[1152],{"type":49,"value":1153},"    \u003CPackageReference Include=\"Microsoft.ML.Tokenizers\" Version=\"2.*\" \n",{"type":43,"tag":954,"props":1155,"children":1157},{"class":956,"line":1156},14,[1158],{"type":43,"tag":954,"props":1159,"children":1160},{"emptyLinePlaceholder":1066},[1161],{"type":49,"value":1069},{"type":43,"tag":954,"props":1163,"children":1165},{"class":956,"line":1164},15,[1166],{"type":43,"tag":954,"props":1167,"children":1168},{},[1169],{"type":49,"value":1170},"\u003C!-- Local LLM inference -->\n",{"type":43,"tag":954,"props":1172,"children":1174},{"class":956,"line":1173},16,[1175],{"type":43,"tag":954,"props":1176,"children":1177},{},[1178],{"type":49,"value":1179},"\u003CPackageReference Include=\"OllamaSharp\" Version=\"5.*\" \u002F>\n",{"type":43,"tag":954,"props":1181,"children":1183},{"class":956,"line":1182},17,[1184],{"type":43,"tag":954,"props":1185,"children":1186},{"emptyLinePlaceholder":1066},[1187],{"type":49,"value":1069},{"type":43,"tag":954,"props":1189,"children":1191},{"class":956,"line":1190},18,[1192],{"type":43,"tag":954,"props":1193,"children":1194},{},[1195],{"type":49,"value":1196},"\u003C!-- Custom model inference -->\n",{"type":43,"tag":954,"props":1198,"children":1200},{"class":956,"line":1199},19,[1201],{"type":43,"tag":954,"props":1202,"children":1203},{},[1204],{"type":49,"value":1205},"\u003CPackageReference Include=\"Microsoft.ML.OnnxRuntime\" Version=\"1.*\" \u002F>\n",{"type":43,"tag":954,"props":1207,"children":1209},{"class":956,"line":1208},20,[1210],{"type":43,"tag":954,"props":1211,"children":1212},{"emptyLinePlaceholder":1066},[1213],{"type":49,"value":1069},{"type":43,"tag":954,"props":1215,"children":1217},{"class":956,"line":1216},21,[1218],{"type":43,"tag":954,"props":1219,"children":1220},{},[1221],{"type":49,"value":1222},"\u003C!-- Vector store abstraction -->\n",{"type":43,"tag":954,"props":1224,"children":1226},{"class":956,"line":1225},22,[1227],{"type":43,"tag":954,"props":1228,"children":1229},{},[1230],{"type":49,"value":1231},"\u003CPackageReference Include=\"Microsoft.Extensions.VectorData.Abstractions\" Version=\"9.*\" \u002F>\n",{"type":43,"tag":954,"props":1233,"children":1235},{"class":956,"line":1234},23,[1236],{"type":43,"tag":954,"props":1237,"children":1238},{"emptyLinePlaceholder":1066},[1239],{"type":49,"value":1069},{"type":43,"tag":954,"props":1241,"children":1243},{"class":956,"line":1242},24,[1244],{"type":43,"tag":954,"props":1245,"children":1246},{},[1247],{"type":49,"value":1248},"\u003C!-- Document ingestion, chunking, and vector store loading (preview) -->\n",{"type":43,"tag":954,"props":1250,"children":1252},{"class":956,"line":1251},25,[1253],{"type":43,"tag":954,"props":1254,"children":1255},{},[1256],{"type":49,"value":1257},"\u003CPackageReference Include=\"Microsoft.Extensions.AI.DataIngestion\" Version=\"9.*-*\" \u002F>\n",{"type":43,"tag":954,"props":1259,"children":1261},{"class":956,"line":1260},26,[1262],{"type":43,"tag":954,"props":1263,"children":1264},{"emptyLinePlaceholder":1066},[1265],{"type":49,"value":1069},{"type":43,"tag":954,"props":1267,"children":1269},{"class":956,"line":1268},27,[1270],{"type":43,"tag":954,"props":1271,"children":1272},{},[1273],{"type":49,"value":1274},"\u003C!-- Copilot platform extensibility -->\n",{"type":43,"tag":954,"props":1276,"children":1278},{"class":956,"line":1277},28,[1279],{"type":43,"tag":954,"props":1280,"children":1281},{},[1282],{"type":49,"value":1283},"\u003CPackageReference Include=\"GitHub.Copilot.SDK\" Version=\"1.*\" \u002F>\n",{"type":43,"tag":1019,"props":1285,"children":1286},{},[1287],{"type":43,"tag":175,"props":1288,"children":1289},{},[1290,1295,1297,1302,1304,1309],{"type":43,"tag":219,"props":1291,"children":1292},{},[1293],{"type":49,"value":1294},"Stack coherence rule:",{"type":49,"value":1296}," Never mix raw SDK calls (",{"type":43,"tag":227,"props":1298,"children":1300},{"className":1299},[],[1301],{"type":49,"value":922},{"type":49,"value":1303}," to OpenAI) with ",{"type":43,"tag":227,"props":1305,"children":1307},{"className":1306},[],[1308],{"type":49,"value":298},{"type":49,"value":1310},", Microsoft Agent Framework, or Copilot SDK in the same workflow. Pick one abstraction layer per workflow boundary and commit to it. See Step 1b for the layering rules.",{"type":43,"tag":747,"props":1312,"children":1314},{"id":1313},"register-services-with-dependency-injection",[1315],{"type":49,"value":1316},"Register services with dependency injection",{"type":43,"tag":175,"props":1318,"children":1319},{},[1320],{"type":49,"value":1321},"All AI\u002FML services must be registered via DI. Never instantiate clients directly in business logic.",{"type":43,"tag":943,"props":1323,"children":1327},{"className":1324,"code":1325,"language":1326,"meta":948,"style":948},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Configuration via IOptions\u003CT>\nservices.Configure\u003CAiOptions>(configuration.GetSection(\"AI\"));\n\n\u002F\u002F Register the AI client through the abstraction\nservices.AddChatClient(builder => builder\n    .UseOpenAIChatClient(\"gpt-4o-mini-2024-07-18\"));\n","csharp",[1328],{"type":43,"tag":227,"props":1329,"children":1330},{"__ignoreMap":948},[1331,1339,1347,1354,1362,1370],{"type":43,"tag":954,"props":1332,"children":1333},{"class":956,"line":957},[1334],{"type":43,"tag":954,"props":1335,"children":1336},{},[1337],{"type":49,"value":1338},"\u002F\u002F Configuration via IOptions\u003CT>\n",{"type":43,"tag":954,"props":1340,"children":1341},{"class":956,"line":966},[1342],{"type":43,"tag":954,"props":1343,"children":1344},{},[1345],{"type":49,"value":1346},"services.Configure\u003CAiOptions>(configuration.GetSection(\"AI\"));\n",{"type":43,"tag":954,"props":1348,"children":1349},{"class":956,"line":975},[1350],{"type":43,"tag":954,"props":1351,"children":1352},{"emptyLinePlaceholder":1066},[1353],{"type":49,"value":1069},{"type":43,"tag":954,"props":1355,"children":1356},{"class":956,"line":984},[1357],{"type":43,"tag":954,"props":1358,"children":1359},{},[1360],{"type":49,"value":1361},"\u002F\u002F Register the AI client through the abstraction\n",{"type":43,"tag":954,"props":1363,"children":1364},{"class":956,"line":993},[1365],{"type":43,"tag":954,"props":1366,"children":1367},{},[1368],{"type":49,"value":1369},"services.AddChatClient(builder => builder\n",{"type":43,"tag":954,"props":1371,"children":1372},{"class":956,"line":1002},[1373],{"type":43,"tag":954,"props":1374,"children":1375},{},[1376],{"type":49,"value":1377},"    .UseOpenAIChatClient(\"gpt-4o-mini-2024-07-18\"));\n",{"type":43,"tag":168,"props":1379,"children":1381},{"id":1380},"step-3-implement-with-guardrails",[1382],{"type":49,"value":1383},"Step 3: Implement with guardrails",{"type":43,"tag":175,"props":1385,"children":1386},{},[1387],{"type":49,"value":1388},"Apply the guardrails for the selected technology branch. Every generated implementation must follow these rules.",{"type":43,"tag":747,"props":1390,"children":1392},{"id":1391},"classic-ml-guardrails",[1393],{"type":49,"value":1394},"Classic ML guardrails",{"type":43,"tag":754,"props":1396,"children":1397},{},[1398,1422,1446,1479,1497],{"type":43,"tag":758,"props":1399,"children":1400},{},[1401,1406,1408],{"type":43,"tag":219,"props":1402,"children":1403},{},[1404],{"type":49,"value":1405},"Reproducibility",{"type":49,"value":1407},": Always set a random seed in the ML context:",{"type":43,"tag":943,"props":1409,"children":1411},{"className":1324,"code":1410,"language":1326,"meta":948,"style":948},"var mlContext = new MLContext(seed: 42);\n",[1412],{"type":43,"tag":227,"props":1413,"children":1414},{"__ignoreMap":948},[1415],{"type":43,"tag":954,"props":1416,"children":1417},{"class":956,"line":957},[1418],{"type":43,"tag":954,"props":1419,"children":1420},{},[1421],{"type":49,"value":1410},{"type":43,"tag":758,"props":1423,"children":1424},{},[1425,1430,1432],{"type":43,"tag":219,"props":1426,"children":1427},{},[1428],{"type":49,"value":1429},"Data splitting",{"type":49,"value":1431},": Always split into train\u002Ftest (and optionally validation). Never evaluate on training data:",{"type":43,"tag":943,"props":1433,"children":1435},{"className":1324,"code":1434,"language":1326,"meta":948,"style":948},"var split = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);\n",[1436],{"type":43,"tag":227,"props":1437,"children":1438},{"__ignoreMap":948},[1439],{"type":43,"tag":954,"props":1440,"children":1441},{"class":956,"line":957},[1442],{"type":43,"tag":954,"props":1443,"children":1444},{},[1445],{"type":49,"value":1434},{"type":43,"tag":758,"props":1447,"children":1448},{},[1449,1454,1456],{"type":43,"tag":219,"props":1450,"children":1451},{},[1452],{"type":49,"value":1453},"Metrics logging",{"type":49,"value":1455},": Always compute and log evaluation metrics appropriate to the task:",{"type":43,"tag":943,"props":1457,"children":1459},{"className":1324,"code":1458,"language":1326,"meta":948,"style":948},"var metrics = mlContext.BinaryClassification.Evaluate(predictions);\nlogger.LogInformation(\"AUC: {Auc:F4}, F1: {F1:F4}\", metrics.AreaUnderRocCurve, metrics.F1Score);\n",[1460],{"type":43,"tag":227,"props":1461,"children":1462},{"__ignoreMap":948},[1463,1471],{"type":43,"tag":954,"props":1464,"children":1465},{"class":956,"line":957},[1466],{"type":43,"tag":954,"props":1467,"children":1468},{},[1469],{"type":49,"value":1470},"var metrics = mlContext.BinaryClassification.Evaluate(predictions);\n",{"type":43,"tag":954,"props":1472,"children":1473},{"class":956,"line":966},[1474],{"type":43,"tag":954,"props":1475,"children":1476},{},[1477],{"type":49,"value":1478},"logger.LogInformation(\"AUC: {Auc:F4}, F1: {F1:F4}\", metrics.AreaUnderRocCurve, metrics.F1Score);\n",{"type":43,"tag":758,"props":1480,"children":1481},{},[1482,1487,1489,1495],{"type":43,"tag":219,"props":1483,"children":1484},{},[1485],{"type":49,"value":1486},"AutoML first",{"type":49,"value":1488},": Prefer ",{"type":43,"tag":227,"props":1490,"children":1492},{"className":1491},[],[1493],{"type":49,"value":1494},"mlContext.Auto()",{"type":49,"value":1496}," for initial model selection, then refine manually.",{"type":43,"tag":758,"props":1498,"children":1499},{},[1500,1505,1507],{"type":43,"tag":219,"props":1501,"children":1502},{},[1503],{"type":49,"value":1504},"PredictionEngine pooling",{"type":49,"value":1506},": In ASP.NET Core, always use the pooled prediction engine — never a singleton:",{"type":43,"tag":943,"props":1508,"children":1510},{"className":1324,"code":1509,"language":1326,"meta":948,"style":948},"services.AddPredictionEnginePool\u003CModelInput, ModelOutput>()\n    .FromFile(modelPath);\n",[1511],{"type":43,"tag":227,"props":1512,"children":1513},{"__ignoreMap":948},[1514,1522],{"type":43,"tag":954,"props":1515,"children":1516},{"class":956,"line":957},[1517],{"type":43,"tag":954,"props":1518,"children":1519},{},[1520],{"type":49,"value":1521},"services.AddPredictionEnginePool\u003CModelInput, ModelOutput>()\n",{"type":43,"tag":954,"props":1523,"children":1524},{"class":956,"line":966},[1525],{"type":43,"tag":954,"props":1526,"children":1527},{},[1528],{"type":49,"value":1529},"    .FromFile(modelPath);\n",{"type":43,"tag":747,"props":1531,"children":1533},{"id":1532},"llm-integration-guardrails",[1534],{"type":49,"value":1535},"LLM integration guardrails",{"type":43,"tag":754,"props":1537,"children":1538},{},[1539,1604,1628,1668,1678,1711],{"type":43,"tag":758,"props":1540,"children":1541},{},[1542,1547,1549,1555,1557],{"type":43,"tag":219,"props":1543,"children":1544},{},[1545],{"type":49,"value":1546},"Temperature",{"type":49,"value":1548},": Always set explicitly. Use ",{"type":43,"tag":227,"props":1550,"children":1552},{"className":1551},[],[1553],{"type":49,"value":1554},"0",{"type":49,"value":1556}," for factual\u002Fdeterministic tasks:",{"type":43,"tag":943,"props":1558,"children":1560},{"className":1324,"code":1559,"language":1326,"meta":948,"style":948},"var options = new ChatOptions\n{\n    Temperature = 0f,\n    MaxOutputTokens = 1024,\n};\n",[1561],{"type":43,"tag":227,"props":1562,"children":1563},{"__ignoreMap":948},[1564,1572,1580,1588,1596],{"type":43,"tag":954,"props":1565,"children":1566},{"class":956,"line":957},[1567],{"type":43,"tag":954,"props":1568,"children":1569},{},[1570],{"type":49,"value":1571},"var options = new ChatOptions\n",{"type":43,"tag":954,"props":1573,"children":1574},{"class":956,"line":966},[1575],{"type":43,"tag":954,"props":1576,"children":1577},{},[1578],{"type":49,"value":1579},"{\n",{"type":43,"tag":954,"props":1581,"children":1582},{"class":956,"line":975},[1583],{"type":43,"tag":954,"props":1584,"children":1585},{},[1586],{"type":49,"value":1587},"    Temperature = 0f,\n",{"type":43,"tag":954,"props":1589,"children":1590},{"class":956,"line":984},[1591],{"type":43,"tag":954,"props":1592,"children":1593},{},[1594],{"type":49,"value":1595},"    MaxOutputTokens = 1024,\n",{"type":43,"tag":954,"props":1597,"children":1598},{"class":956,"line":993},[1599],{"type":43,"tag":954,"props":1600,"children":1601},{},[1602],{"type":49,"value":1603},"};\n",{"type":43,"tag":758,"props":1605,"children":1606},{},[1607,1612,1614],{"type":43,"tag":219,"props":1608,"children":1609},{},[1610],{"type":49,"value":1611},"Structured output",{"type":49,"value":1613},": Always parse LLM output into strongly-typed objects with fallback handling:",{"type":43,"tag":943,"props":1615,"children":1617},{"className":1324,"code":1616,"language":1326,"meta":948,"style":948},"var result = await chatClient.GetResponseAsync\u003CMySchema>(prompt, options, cancellationToken);\n",[1618],{"type":43,"tag":227,"props":1619,"children":1620},{"__ignoreMap":948},[1621],{"type":43,"tag":954,"props":1622,"children":1623},{"class":956,"line":957},[1624],{"type":43,"tag":954,"props":1625,"children":1626},{},[1627],{"type":49,"value":1616},{"type":43,"tag":758,"props":1629,"children":1630},{},[1631,1636,1638],{"type":43,"tag":219,"props":1632,"children":1633},{},[1634],{"type":49,"value":1635},"Retry logic",{"type":49,"value":1637},": Always implement retry with exponential backoff:",{"type":43,"tag":943,"props":1639,"children":1641},{"className":1324,"code":1640,"language":1326,"meta":948,"style":948},"services.AddChatClient(builder => builder\n    .UseOpenAIChatClient(modelId)\n    .Use(new RetryingChatClient(maxRetries: 3)));\n",[1642],{"type":43,"tag":227,"props":1643,"children":1644},{"__ignoreMap":948},[1645,1652,1660],{"type":43,"tag":954,"props":1646,"children":1647},{"class":956,"line":957},[1648],{"type":43,"tag":954,"props":1649,"children":1650},{},[1651],{"type":49,"value":1369},{"type":43,"tag":954,"props":1653,"children":1654},{"class":956,"line":966},[1655],{"type":43,"tag":954,"props":1656,"children":1657},{},[1658],{"type":49,"value":1659},"    .UseOpenAIChatClient(modelId)\n",{"type":43,"tag":954,"props":1661,"children":1662},{"class":956,"line":975},[1663],{"type":43,"tag":954,"props":1664,"children":1665},{},[1666],{"type":49,"value":1667},"    .Use(new RetryingChatClient(maxRetries: 3)));\n",{"type":43,"tag":758,"props":1669,"children":1670},{},[1671,1676],{"type":43,"tag":219,"props":1672,"children":1673},{},[1674],{"type":49,"value":1675},"Cost control",{"type":49,"value":1677},": Always estimate and log token usage. Use Microsoft.ML.Tokenizers to count tokens client-side before sending requests so you can enforce budgets proactively. Choose the smallest model tier that meets quality requirements (e.g., gpt-4o-mini before gpt-4o).",{"type":43,"tag":758,"props":1679,"children":1680},{},[1681,1686,1688],{"type":43,"tag":219,"props":1682,"children":1683},{},[1684],{"type":49,"value":1685},"Secret management",{"type":49,"value":1687},": Never hardcode API keys. Use Azure Key Vault, user-secrets, or environment variables:",{"type":43,"tag":943,"props":1689,"children":1691},{"className":1324,"code":1690,"language":1326,"meta":948,"style":948},"var apiKey = configuration[\"AI:ApiKey\"]\n    ?? throw new InvalidOperationException(\"AI:ApiKey not configured\");\n",[1692],{"type":43,"tag":227,"props":1693,"children":1694},{"__ignoreMap":948},[1695,1703],{"type":43,"tag":954,"props":1696,"children":1697},{"class":956,"line":957},[1698],{"type":43,"tag":954,"props":1699,"children":1700},{},[1701],{"type":49,"value":1702},"var apiKey = configuration[\"AI:ApiKey\"]\n",{"type":43,"tag":954,"props":1704,"children":1705},{"class":956,"line":966},[1706],{"type":43,"tag":954,"props":1707,"children":1708},{},[1709],{"type":49,"value":1710},"    ?? throw new InvalidOperationException(\"AI:ApiKey not configured\");\n",{"type":43,"tag":758,"props":1712,"children":1713},{},[1714,1719,1721],{"type":43,"tag":219,"props":1715,"children":1716},{},[1717],{"type":49,"value":1718},"Model version pinning",{"type":49,"value":1720},": Specify exact model versions to reduce behavioral drift:",{"type":43,"tag":943,"props":1722,"children":1724},{"className":1324,"code":1723,"language":1326,"meta":948,"style":948},"\u002F\u002F Pin to a specific dated version, not just \"gpt-4o\"\nvar modelId = \"gpt-4o-2024-08-06\";\n",[1725],{"type":43,"tag":227,"props":1726,"children":1727},{"__ignoreMap":948},[1728,1736],{"type":43,"tag":954,"props":1729,"children":1730},{"class":956,"line":957},[1731],{"type":43,"tag":954,"props":1732,"children":1733},{},[1734],{"type":49,"value":1735},"\u002F\u002F Pin to a specific dated version, not just \"gpt-4o\"\n",{"type":43,"tag":954,"props":1737,"children":1738},{"class":956,"line":966},[1739],{"type":43,"tag":954,"props":1740,"children":1741},{},[1742],{"type":49,"value":1743},"var modelId = \"gpt-4o-2024-08-06\";\n",{"type":43,"tag":747,"props":1745,"children":1747},{"id":1746},"agentic-workflow-guardrails",[1748],{"type":49,"value":1749},"Agentic workflow guardrails",{"type":43,"tag":754,"props":1751,"children":1753},{"start":1752},0,[1754,1800,1847,1857,1921,1931],{"type":43,"tag":758,"props":1755,"children":1756},{},[1757,1769,1771,1776,1778,1784,1786,1792,1794,1799],{"type":43,"tag":219,"props":1758,"children":1759},{},[1760,1762,1767],{"type":49,"value":1761},"Use ",{"type":43,"tag":227,"props":1763,"children":1765},{"className":1764},[],[1766],{"type":49,"value":291},{"type":49,"value":1768}," for all agentic workflows.",{"type":49,"value":1770}," Do not implement tool dispatch loops or multi-step agent reasoning by hand with ",{"type":43,"tag":227,"props":1772,"children":1774},{"className":1773},[],[1775],{"type":49,"value":262},{"type":49,"value":1777},". The Agent Framework provides ",{"type":43,"tag":227,"props":1779,"children":1781},{"className":1780},[],[1782],{"type":49,"value":1783},"ChatClientAgent",{"type":49,"value":1785}," (or ",{"type":43,"tag":227,"props":1787,"children":1789},{"className":1788},[],[1790],{"type":49,"value":1791},"AgentWorker",{"type":49,"value":1793},") which handles the tool call → result → re-prompt cycle with built-in guardrails. All rules below assume you are using ",{"type":43,"tag":227,"props":1795,"children":1797},{"className":1796},[],[1798],{"type":49,"value":291},{"type":49,"value":700},{"type":43,"tag":758,"props":1801,"children":1802},{},[1803,1808,1810],{"type":43,"tag":219,"props":1804,"children":1805},{},[1806],{"type":49,"value":1807},"Iteration limits",{"type":49,"value":1809},": Always cap agentic loops to prevent runaway execution:",{"type":43,"tag":943,"props":1811,"children":1813},{"className":1324,"code":1812,"language":1326,"meta":948,"style":948},"var settings = new AgentInvokeOptions\n{\n    MaximumIterations = 10,\n};\n",[1814],{"type":43,"tag":227,"props":1815,"children":1816},{"__ignoreMap":948},[1817,1825,1832,1840],{"type":43,"tag":954,"props":1818,"children":1819},{"class":956,"line":957},[1820],{"type":43,"tag":954,"props":1821,"children":1822},{},[1823],{"type":49,"value":1824},"var settings = new AgentInvokeOptions\n",{"type":43,"tag":954,"props":1826,"children":1827},{"class":956,"line":966},[1828],{"type":43,"tag":954,"props":1829,"children":1830},{},[1831],{"type":49,"value":1579},{"type":43,"tag":954,"props":1833,"children":1834},{"class":956,"line":975},[1835],{"type":43,"tag":954,"props":1836,"children":1837},{},[1838],{"type":49,"value":1839},"    MaximumIterations = 10,\n",{"type":43,"tag":954,"props":1841,"children":1842},{"class":956,"line":984},[1843],{"type":43,"tag":954,"props":1844,"children":1845},{},[1846],{"type":49,"value":1603},{"type":43,"tag":758,"props":1848,"children":1849},{},[1850,1855],{"type":43,"tag":219,"props":1851,"children":1852},{},[1853],{"type":49,"value":1854},"Cost ceiling",{"type":49,"value":1856},": Implement a token budget per execution and terminate when reached. Use Microsoft.ML.Tokenizers to count prompt and completion tokens locally and compare against the budget before each iteration.",{"type":43,"tag":758,"props":1858,"children":1859},{},[1860,1865,1867,1873,1875],{"type":43,"tag":219,"props":1861,"children":1862},{},[1863],{"type":49,"value":1864},"Observability",{"type":49,"value":1866},": Log non-sensitive metadata for every agent step. Never log raw ",{"type":43,"tag":227,"props":1868,"children":1870},{"className":1869},[],[1871],{"type":49,"value":1872},"message.Content",{"type":49,"value":1874}," — it may contain user prompts, tool outputs, secrets, or PII that persist in plaintext in central logging systems:",{"type":43,"tag":943,"props":1876,"children":1878},{"className":1324,"code":1877,"language":1326,"meta":948,"style":948},"await foreach (var message in agent.InvokeStreamingAsync(history, settings))\n{\n    logger.LogDebug(\"Agent step: Role={Role}, ContentLength={Length}\",\n        message.Role, message.Content?.Length ?? 0);\n}\n",[1879],{"type":43,"tag":227,"props":1880,"children":1881},{"__ignoreMap":948},[1882,1890,1897,1905,1913],{"type":43,"tag":954,"props":1883,"children":1884},{"class":956,"line":957},[1885],{"type":43,"tag":954,"props":1886,"children":1887},{},[1888],{"type":49,"value":1889},"await foreach (var message in agent.InvokeStreamingAsync(history, settings))\n",{"type":43,"tag":954,"props":1891,"children":1892},{"class":956,"line":966},[1893],{"type":43,"tag":954,"props":1894,"children":1895},{},[1896],{"type":49,"value":1579},{"type":43,"tag":954,"props":1898,"children":1899},{"class":956,"line":975},[1900],{"type":43,"tag":954,"props":1901,"children":1902},{},[1903],{"type":49,"value":1904},"    logger.LogDebug(\"Agent step: Role={Role}, ContentLength={Length}\",\n",{"type":43,"tag":954,"props":1906,"children":1907},{"class":956,"line":984},[1908],{"type":43,"tag":954,"props":1909,"children":1910},{},[1911],{"type":49,"value":1912},"        message.Role, message.Content?.Length ?? 0);\n",{"type":43,"tag":954,"props":1914,"children":1915},{"class":956,"line":993},[1916],{"type":43,"tag":954,"props":1917,"children":1918},{},[1919],{"type":49,"value":1920},"}\n",{"type":43,"tag":758,"props":1922,"children":1923},{},[1924,1929],{"type":43,"tag":219,"props":1925,"children":1926},{},[1927],{"type":49,"value":1928},"Tool schemas",{"type":49,"value":1930},": Define explicit tool\u002Ffunction schemas with descriptions. Never rely on implicit tool discovery.",{"type":43,"tag":758,"props":1932,"children":1933},{},[1934,1939],{"type":43,"tag":219,"props":1935,"children":1936},{},[1937],{"type":49,"value":1938},"Simplicity preference",{"type":49,"value":1940},": Prefer single-agent with tools over multi-agent unless the task genuinely requires agent collaboration.",{"type":43,"tag":747,"props":1942,"children":1944},{"id":1943},"rag-guardrails",[1945],{"type":49,"value":1946},"RAG guardrails",{"type":43,"tag":754,"props":1948,"children":1949},{},[1950,1960,1970,2026,2036],{"type":43,"tag":758,"props":1951,"children":1952},{},[1953,1958],{"type":43,"tag":219,"props":1954,"children":1955},{},[1956],{"type":49,"value":1957},"Embedding caching",{"type":49,"value":1959},": Never re-embed the same content on every query. Cache embeddings in the vector store.",{"type":43,"tag":758,"props":1961,"children":1962},{},[1963,1968],{"type":43,"tag":219,"props":1964,"children":1965},{},[1966],{"type":49,"value":1967},"Chunking strategy",{"type":49,"value":1969},": Use semantic chunking (split on paragraph\u002Fsection boundaries) over fixed-size chunking. Ensure chunks have enough context to be useful on their own.",{"type":43,"tag":758,"props":1971,"children":1972},{},[1973,1978,1980],{"type":43,"tag":219,"props":1974,"children":1975},{},[1976],{"type":49,"value":1977},"Relevance thresholds",{"type":49,"value":1979},": Do not inject low-relevance chunks into context. Set a minimum similarity score:",{"type":43,"tag":943,"props":1981,"children":1983},{"className":1324,"code":1982,"language":1326,"meta":948,"style":948},"var results = await vectorStore.SearchAsync(query, new VectorSearchOptions\n{\n    Top = 5,\n    MinimumScore = 0.75f,\n});\n",[1984],{"type":43,"tag":227,"props":1985,"children":1986},{"__ignoreMap":948},[1987,1995,2002,2010,2018],{"type":43,"tag":954,"props":1988,"children":1989},{"class":956,"line":957},[1990],{"type":43,"tag":954,"props":1991,"children":1992},{},[1993],{"type":49,"value":1994},"var results = await vectorStore.SearchAsync(query, new VectorSearchOptions\n",{"type":43,"tag":954,"props":1996,"children":1997},{"class":956,"line":966},[1998],{"type":43,"tag":954,"props":1999,"children":2000},{},[2001],{"type":49,"value":1579},{"type":43,"tag":954,"props":2003,"children":2004},{"class":956,"line":975},[2005],{"type":43,"tag":954,"props":2006,"children":2007},{},[2008],{"type":49,"value":2009},"    Top = 5,\n",{"type":43,"tag":954,"props":2011,"children":2012},{"class":956,"line":984},[2013],{"type":43,"tag":954,"props":2014,"children":2015},{},[2016],{"type":49,"value":2017},"    MinimumScore = 0.75f,\n",{"type":43,"tag":954,"props":2019,"children":2020},{"class":956,"line":993},[2021],{"type":43,"tag":954,"props":2022,"children":2023},{},[2024],{"type":49,"value":2025},"});\n",{"type":43,"tag":758,"props":2027,"children":2028},{},[2029,2034],{"type":43,"tag":219,"props":2030,"children":2031},{},[2032],{"type":49,"value":2033},"Source attribution",{"type":49,"value":2035},": Track which chunks contributed to the final response. Include source references in the output.",{"type":43,"tag":758,"props":2037,"children":2038},{},[2039,2044],{"type":43,"tag":219,"props":2040,"children":2041},{},[2042],{"type":49,"value":2043},"Batch embeddings",{"type":49,"value":2045},": Batch embedding API calls where possible to reduce latency and cost.",{"type":43,"tag":168,"props":2047,"children":2049},{"id":2048},"step-4-handle-non-determinism",[2050],{"type":49,"value":2051},"Step 4: Handle non-determinism",{"type":43,"tag":175,"props":2053,"children":2054},{},[2055],{"type":49,"value":2056},"When the solution involves LLM calls or agentic workflows, explicitly address non-determinism:",{"type":43,"tag":754,"props":2058,"children":2059},{},[2060,2070,2080,2143,2153],{"type":43,"tag":758,"props":2061,"children":2062},{},[2063,2068],{"type":43,"tag":219,"props":2064,"children":2065},{},[2066],{"type":49,"value":2067},"Acknowledge it",{"type":49,"value":2069},": Inform the developer that LLM outputs are non-deterministic even at temperature 0 (due to batching, quantization, and model updates).",{"type":43,"tag":758,"props":2071,"children":2072},{},[2073,2078],{"type":43,"tag":219,"props":2074,"children":2075},{},[2076],{"type":49,"value":2077},"Validate outputs",{"type":49,"value":2079},": Implement schema validation and content assertion checks on every LLM response.",{"type":43,"tag":758,"props":2081,"children":2082},{},[2083,2088,2090],{"type":43,"tag":219,"props":2084,"children":2085},{},[2086],{"type":49,"value":2087},"Graceful degradation",{"type":49,"value":2089},": Design a fallback path for when the LLM returns unexpected, malformed, or empty output:",{"type":43,"tag":943,"props":2091,"children":2093},{"className":1324,"code":2092,"language":1326,"meta":948,"style":948},"var response = await chatClient.GetResponseAsync\u003CClassificationResult>(prompt, options);\nif (response is null || !response.IsValid())\n{\n    logger.LogWarning(\"LLM returned invalid response, falling back to rule-based classifier\");\n    return ruleBasedClassifier.Classify(input);\n}\n",[2094],{"type":43,"tag":227,"props":2095,"children":2096},{"__ignoreMap":948},[2097,2105,2113,2120,2128,2136],{"type":43,"tag":954,"props":2098,"children":2099},{"class":956,"line":957},[2100],{"type":43,"tag":954,"props":2101,"children":2102},{},[2103],{"type":49,"value":2104},"var response = await chatClient.GetResponseAsync\u003CClassificationResult>(prompt, options);\n",{"type":43,"tag":954,"props":2106,"children":2107},{"class":956,"line":966},[2108],{"type":43,"tag":954,"props":2109,"children":2110},{},[2111],{"type":49,"value":2112},"if (response is null || !response.IsValid())\n",{"type":43,"tag":954,"props":2114,"children":2115},{"class":956,"line":975},[2116],{"type":43,"tag":954,"props":2117,"children":2118},{},[2119],{"type":49,"value":1579},{"type":43,"tag":954,"props":2121,"children":2122},{"class":956,"line":984},[2123],{"type":43,"tag":954,"props":2124,"children":2125},{},[2126],{"type":49,"value":2127},"    logger.LogWarning(\"LLM returned invalid response, falling back to rule-based classifier\");\n",{"type":43,"tag":954,"props":2129,"children":2130},{"class":956,"line":993},[2131],{"type":43,"tag":954,"props":2132,"children":2133},{},[2134],{"type":49,"value":2135},"    return ruleBasedClassifier.Classify(input);\n",{"type":43,"tag":954,"props":2137,"children":2138},{"class":956,"line":1002},[2139],{"type":43,"tag":954,"props":2140,"children":2141},{},[2142],{"type":49,"value":1920},{"type":43,"tag":758,"props":2144,"children":2145},{},[2146,2151],{"type":43,"tag":219,"props":2147,"children":2148},{},[2149],{"type":49,"value":2150},"Evaluation harness",{"type":49,"value":2152},": For any prompt that will be iterated on, recommend creating a golden dataset and evaluation scaffold to measure prompt quality over time.",{"type":43,"tag":758,"props":2154,"children":2155},{},[2156,2160,2162,2168],{"type":43,"tag":219,"props":2157,"children":2158},{},[2159],{"type":49,"value":1718},{"type":49,"value":2161},": Pin to specific dated model versions (e.g., ",{"type":43,"tag":227,"props":2163,"children":2165},{"className":2164},[],[2166],{"type":49,"value":2167},"gpt-4o-2024-08-06",{"type":49,"value":2169},") to reduce drift between deployments.",{"type":43,"tag":168,"props":2171,"children":2173},{"id":2172},"step-5-apply-performance-and-cost-controls",[2174],{"type":49,"value":2175},"Step 5: Apply performance and cost controls",{"type":43,"tag":754,"props":2177,"children":2178},{},[2179,2197,2207,2261,2294],{"type":43,"tag":758,"props":2180,"children":2181},{},[2182,2187,2189,2195],{"type":43,"tag":219,"props":2183,"children":2184},{},[2185],{"type":49,"value":2186},"Connection pooling",{"type":49,"value":2188},": Use ",{"type":43,"tag":227,"props":2190,"children":2192},{"className":2191},[],[2193],{"type":49,"value":2194},"IHttpClientFactory",{"type":49,"value":2196}," and DI-managed clients for all external services.",{"type":43,"tag":758,"props":2198,"children":2199},{},[2200,2205],{"type":43,"tag":219,"props":2201,"children":2202},{},[2203],{"type":49,"value":2204},"Response caching",{"type":49,"value":2206},": Cache repeated or similar queries. Consider semantic caching for LLM responses where appropriate.",{"type":43,"tag":758,"props":2208,"children":2209},{},[2210,2215,2216,2222,2224],{"type":43,"tag":219,"props":2211,"children":2212},{},[2213],{"type":49,"value":2214},"Streaming",{"type":49,"value":2188},{"type":43,"tag":227,"props":2217,"children":2219},{"className":2218},[],[2220],{"type":49,"value":2221},"IAsyncEnumerable",{"type":49,"value":2223}," for LLM responses in user-facing scenarios to reduce time-to-first-token:",{"type":43,"tag":943,"props":2225,"children":2227},{"className":1324,"code":2226,"language":1326,"meta":948,"style":948},"await foreach (var update in chatClient.GetStreamingResponseAsync(prompt, options))\n{\n    yield return update.Text;\n}\n",[2228],{"type":43,"tag":227,"props":2229,"children":2230},{"__ignoreMap":948},[2231,2239,2246,2254],{"type":43,"tag":954,"props":2232,"children":2233},{"class":956,"line":957},[2234],{"type":43,"tag":954,"props":2235,"children":2236},{},[2237],{"type":49,"value":2238},"await foreach (var update in chatClient.GetStreamingResponseAsync(prompt, options))\n",{"type":43,"tag":954,"props":2240,"children":2241},{"class":956,"line":966},[2242],{"type":43,"tag":954,"props":2243,"children":2244},{},[2245],{"type":49,"value":1579},{"type":43,"tag":954,"props":2247,"children":2248},{"class":956,"line":975},[2249],{"type":43,"tag":954,"props":2250,"children":2251},{},[2252],{"type":49,"value":2253},"    yield return update.Text;\n",{"type":43,"tag":954,"props":2255,"children":2256},{"class":956,"line":984},[2257],{"type":43,"tag":954,"props":2258,"children":2259},{},[2260],{"type":49,"value":1920},{"type":43,"tag":758,"props":2262,"children":2263},{},[2264,2269,2271],{"type":43,"tag":219,"props":2265,"children":2266},{},[2267],{"type":49,"value":2268},"Health checks",{"type":49,"value":2270},": Implement health checks for external AI service dependencies:",{"type":43,"tag":943,"props":2272,"children":2274},{"className":1324,"code":2273,"language":1326,"meta":948,"style":948},"services.AddHealthChecks()\n    .AddCheck\u003COpenAIHealthCheck>(\"openai\");\n",[2275],{"type":43,"tag":227,"props":2276,"children":2277},{"__ignoreMap":948},[2278,2286],{"type":43,"tag":954,"props":2279,"children":2280},{"class":956,"line":957},[2281],{"type":43,"tag":954,"props":2282,"children":2283},{},[2284],{"type":49,"value":2285},"services.AddHealthChecks()\n",{"type":43,"tag":954,"props":2287,"children":2288},{"class":956,"line":966},[2289],{"type":43,"tag":954,"props":2290,"children":2291},{},[2292],{"type":49,"value":2293},"    .AddCheck\u003COpenAIHealthCheck>(\"openai\");\n",{"type":43,"tag":758,"props":2295,"children":2296},{},[2297,2302,2304,2310,2312,2318],{"type":43,"tag":219,"props":2298,"children":2299},{},[2300],{"type":49,"value":2301},"ML.NET prediction pooling",{"type":49,"value":2303},": In web applications, always use ",{"type":43,"tag":227,"props":2305,"children":2307},{"className":2306},[],[2308],{"type":49,"value":2309},"PredictionEnginePool\u003CTIn, TOut>",{"type":49,"value":2311},", never a single ",{"type":43,"tag":227,"props":2313,"children":2315},{"className":2314},[],[2316],{"type":49,"value":2317},"PredictionEngine",{"type":49,"value":2319}," instance (it is not thread-safe).",{"type":43,"tag":168,"props":2321,"children":2323},{"id":2322},"step-6-validate-the-implementation",[2324],{"type":49,"value":2325},"Step 6: Validate the implementation",{"type":43,"tag":754,"props":2327,"children":2328},{},[2329,2372,2405,2410,2415],{"type":43,"tag":758,"props":2330,"children":2331},{},[2332,2334],{"type":49,"value":2333},"Build the project and verify no warnings:",{"type":43,"tag":943,"props":2335,"children":2339},{"className":2336,"code":2337,"language":2338,"meta":948,"style":948},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dotnet build -c Release -warnaserror\n","bash",[2340],{"type":43,"tag":227,"props":2341,"children":2342},{"__ignoreMap":948},[2343],{"type":43,"tag":954,"props":2344,"children":2345},{"class":956,"line":957},[2346,2351,2357,2362,2367],{"type":43,"tag":954,"props":2347,"children":2349},{"style":2348},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[2350],{"type":49,"value":8},{"type":43,"tag":954,"props":2352,"children":2354},{"style":2353},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[2355],{"type":49,"value":2356}," build",{"type":43,"tag":954,"props":2358,"children":2359},{"style":2353},[2360],{"type":49,"value":2361}," -c",{"type":43,"tag":954,"props":2363,"children":2364},{"style":2353},[2365],{"type":49,"value":2366}," Release",{"type":43,"tag":954,"props":2368,"children":2369},{"style":2353},[2370],{"type":49,"value":2371}," -warnaserror\n",{"type":43,"tag":758,"props":2373,"children":2374},{},[2375,2377],{"type":49,"value":2376},"Run tests, including integration tests that validate AI\u002FML behavior:",{"type":43,"tag":943,"props":2378,"children":2380},{"className":2336,"code":2379,"language":2338,"meta":948,"style":948},"dotnet test -c Release\n",[2381],{"type":43,"tag":227,"props":2382,"children":2383},{"__ignoreMap":948},[2384],{"type":43,"tag":954,"props":2385,"children":2386},{"class":956,"line":957},[2387,2391,2396,2400],{"type":43,"tag":954,"props":2388,"children":2389},{"style":2348},[2390],{"type":49,"value":8},{"type":43,"tag":954,"props":2392,"children":2393},{"style":2353},[2394],{"type":49,"value":2395}," test",{"type":43,"tag":954,"props":2397,"children":2398},{"style":2353},[2399],{"type":49,"value":2361},{"type":43,"tag":954,"props":2401,"children":2402},{"style":2353},[2403],{"type":49,"value":2404}," Release\n",{"type":43,"tag":758,"props":2406,"children":2407},{},[2408],{"type":49,"value":2409},"For ML.NET pipelines, verify that evaluation metrics meet the project's quality bar and that the model can be serialized and loaded correctly.",{"type":43,"tag":758,"props":2411,"children":2412},{},[2413],{"type":49,"value":2414},"For LLM integrations, verify that structured output parsing handles both valid and malformed responses.",{"type":43,"tag":758,"props":2416,"children":2417},{},[2418],{"type":49,"value":2419},"For RAG pipelines, verify that retrieval returns relevant results and that irrelevant chunks are filtered out.",{"type":43,"tag":52,"props":2421,"children":2423},{"id":2422},"validation",[2424],{"type":49,"value":2425},"Validation",{"type":43,"tag":842,"props":2427,"children":2430},{"className":2428},[2429],"contains-task-list",[2431,2443,2452,2469,2478,2487,2496,2505,2514,2523],{"type":43,"tag":758,"props":2432,"children":2435},{"className":2433},[2434],"task-list-item",[2436,2441],{"type":43,"tag":2437,"props":2438,"children":2440},"input",{"disabled":1066,"type":2439},"checkbox",[],{"type":49,"value":2442}," Technology selection follows the decision tree — LLMs are not used for tasks ML.NET handles",{"type":43,"tag":758,"props":2444,"children":2446},{"className":2445},[2434],[2447,2450],{"type":43,"tag":2437,"props":2448,"children":2449},{"disabled":1066,"type":2439},[],{"type":49,"value":2451}," All AI\u002FML services are registered via dependency injection",{"type":43,"tag":758,"props":2453,"children":2455},{"className":2454},[2434],[2456,2459,2461,2467],{"type":43,"tag":2437,"props":2457,"children":2458},{"disabled":1066,"type":2439},[],{"type":49,"value":2460}," Configuration uses ",{"type":43,"tag":227,"props":2462,"children":2464},{"className":2463},[],[2465],{"type":49,"value":2466},"IOptions\u003CT>",{"type":49,"value":2468}," pattern — no hardcoded values",{"type":43,"tag":758,"props":2470,"children":2472},{"className":2471},[2434],[2473,2476],{"type":43,"tag":2437,"props":2474,"children":2475},{"disabled":1066,"type":2439},[],{"type":49,"value":2477}," API keys are loaded from secure sources — not in source code or committed config files",{"type":43,"tag":758,"props":2479,"children":2481},{"className":2480},[2434],[2482,2485],{"type":43,"tag":2437,"props":2483,"children":2484},{"disabled":1066,"type":2439},[],{"type":49,"value":2486}," ML.NET pipelines set a random seed and split data for evaluation",{"type":43,"tag":758,"props":2488,"children":2490},{"className":2489},[2434],[2491,2494],{"type":43,"tag":2437,"props":2492,"children":2493},{"disabled":1066,"type":2439},[],{"type":49,"value":2495}," LLM calls set temperature, max tokens, and retry logic explicitly",{"type":43,"tag":758,"props":2497,"children":2499},{"className":2498},[2434],[2500,2503],{"type":43,"tag":2437,"props":2501,"children":2502},{"disabled":1066,"type":2439},[],{"type":49,"value":2504}," Agentic workflows have iteration limits and cost ceilings",{"type":43,"tag":758,"props":2506,"children":2508},{"className":2507},[2434],[2509,2512],{"type":43,"tag":2437,"props":2510,"children":2511},{"disabled":1066,"type":2439},[],{"type":49,"value":2513}," RAG pipelines implement chunking, relevance thresholds, and source attribution",{"type":43,"tag":758,"props":2515,"children":2517},{"className":2516},[2434],[2518,2521],{"type":43,"tag":2437,"props":2519,"children":2520},{"disabled":1066,"type":2439},[],{"type":49,"value":2522}," Non-deterministic outputs have validation and fallback paths",{"type":43,"tag":758,"props":2524,"children":2526},{"className":2525},[2434],[2527,2530,2532,2538],{"type":43,"tag":2437,"props":2528,"children":2529},{"disabled":1066,"type":2439},[],{"type":49,"value":2531}," ",{"type":43,"tag":227,"props":2533,"children":2535},{"className":2534},[],[2536],{"type":49,"value":2537},"dotnet build -c Release -warnaserror",{"type":49,"value":2539}," completes cleanly",{"type":43,"tag":52,"props":2541,"children":2543},{"id":2542},"anti-patterns-to-reject",[2544],{"type":49,"value":2545},"Anti-Patterns to Reject",{"type":43,"tag":175,"props":2547,"children":2548},{},[2549],{"type":49,"value":2550},"When reviewing or generating code, flag and redirect the developer if any of these patterns are detected:",{"type":43,"tag":59,"props":2552,"children":2553},{},[2554,2570],{"type":43,"tag":63,"props":2555,"children":2556},{},[2557],{"type":43,"tag":67,"props":2558,"children":2559},{},[2560,2565],{"type":43,"tag":71,"props":2561,"children":2562},{},[2563],{"type":49,"value":2564},"Anti-pattern",{"type":43,"tag":71,"props":2566,"children":2567},{},[2568],{"type":49,"value":2569},"Redirect",{"type":43,"tag":87,"props":2571,"children":2572},{},[2573,2586,2607,2628,2641,2654,2667,2687,2714,2752,2772,2785,2812,2845,2865],{"type":43,"tag":67,"props":2574,"children":2575},{},[2576,2581],{"type":43,"tag":94,"props":2577,"children":2578},{},[2579],{"type":49,"value":2580},"Using an LLM for classification on structured\u002Ftabular data",{"type":43,"tag":94,"props":2582,"children":2583},{},[2584],{"type":49,"value":2585},"Use ML.NET instead — it is faster, cheaper, and deterministic",{"type":43,"tag":67,"props":2587,"children":2588},{},[2589,2594],{"type":43,"tag":94,"props":2590,"children":2591},{},[2592],{"type":49,"value":2593},"Calling LLM APIs without retry or timeout logic",{"type":43,"tag":94,"props":2595,"children":2596},{},[2597,2599,2605],{"type":49,"value":2598},"Add ",{"type":43,"tag":227,"props":2600,"children":2602},{"className":2601},[],[2603],{"type":49,"value":2604},"RetryingChatClient",{"type":49,"value":2606}," or Polly-based retry with exponential backoff",{"type":43,"tag":67,"props":2608,"children":2609},{},[2610,2623],{"type":43,"tag":94,"props":2611,"children":2612},{},[2613,2615,2621],{"type":49,"value":2614},"Storing API keys in ",{"type":43,"tag":227,"props":2616,"children":2618},{"className":2617},[],[2619],{"type":49,"value":2620},"appsettings.json",{"type":49,"value":2622}," committed to source control",{"type":43,"tag":94,"props":2624,"children":2625},{},[2626],{"type":49,"value":2627},"Use user-secrets (dev), environment variables, or Azure Key Vault (prod)",{"type":43,"tag":67,"props":2629,"children":2630},{},[2631,2636],{"type":43,"tag":94,"props":2632,"children":2633},{},[2634],{"type":49,"value":2635},"Using Accord.NET for new projects",{"type":43,"tag":94,"props":2637,"children":2638},{},[2639],{"type":49,"value":2640},"Migrate to ML.NET — Accord.NET is archived and unmaintained",{"type":43,"tag":67,"props":2642,"children":2643},{},[2644,2649],{"type":43,"tag":94,"props":2645,"children":2646},{},[2647],{"type":49,"value":2648},"Building custom neural networks in .NET from scratch",{"type":43,"tag":94,"props":2650,"children":2651},{},[2652],{"type":49,"value":2653},"Use a pre-trained model via ONNX Runtime or call an LLM API",{"type":43,"tag":67,"props":2655,"children":2656},{},[2657,2662],{"type":43,"tag":94,"props":2658,"children":2659},{},[2660],{"type":49,"value":2661},"RAG without chunking strategy or relevance filtering",{"type":43,"tag":94,"props":2663,"children":2664},{},[2665],{"type":49,"value":2666},"Implement semantic chunking and set a minimum similarity score threshold",{"type":43,"tag":67,"props":2668,"children":2669},{},[2670,2675],{"type":43,"tag":94,"props":2671,"children":2672},{},[2673],{"type":49,"value":2674},"Agentic loops without iteration limits or cost ceilings",{"type":43,"tag":94,"props":2676,"children":2677},{},[2678,2679,2685],{"type":49,"value":2598},{"type":43,"tag":227,"props":2680,"children":2682},{"className":2681},[],[2683],{"type":49,"value":2684},"MaximumIterations",{"type":49,"value":2686}," and a token budget ceiling",{"type":43,"tag":67,"props":2688,"children":2689},{},[2690,2709],{"type":43,"tag":94,"props":2691,"children":2692},{},[2693,2695,2700,2702,2707],{"type":49,"value":2694},"Using MEAI ",{"type":43,"tag":227,"props":2696,"children":2698},{"className":2697},[],[2699],{"type":49,"value":262},{"type":49,"value":2701}," with raw ",{"type":43,"tag":227,"props":2703,"children":2705},{"className":2704},[],[2706],{"type":49,"value":922},{"type":49,"value":2708}," calls to the same provider",{"type":43,"tag":94,"props":2710,"children":2711},{},[2712],{"type":49,"value":2713},"Pick one abstraction layer and commit to it",{"type":43,"tag":67,"props":2715,"children":2716},{},[2717,2734],{"type":43,"tag":94,"props":2718,"children":2719},{},[2720,2722,2727,2729],{"type":49,"value":2721},"Implementing tool calling or agentic loops manually with ",{"type":43,"tag":227,"props":2723,"children":2725},{"className":2724},[],[2726],{"type":49,"value":262},{"type":49,"value":2728}," instead of using ",{"type":43,"tag":227,"props":2730,"children":2732},{"className":2731},[],[2733],{"type":49,"value":291},{"type":43,"tag":94,"props":2735,"children":2736},{},[2737,2738,2743,2745,2750],{"type":49,"value":1761},{"type":43,"tag":227,"props":2739,"children":2741},{"className":2740},[],[2742],{"type":49,"value":291},{"type":49,"value":2744}," — it provides iteration limits (",{"type":43,"tag":227,"props":2746,"children":2748},{"className":2747},[],[2749],{"type":49,"value":2684},{"type":49,"value":2751},"), built-in tool dispatch, observability hooks, and cost controls. Hand-rolled loops lack these guardrails.",{"type":43,"tag":67,"props":2753,"children":2754},{},[2755,2760],{"type":43,"tag":94,"props":2756,"children":2757},{},[2758],{"type":49,"value":2759},"Using Agent Framework for a single prompt→response call",{"type":43,"tag":94,"props":2761,"children":2762},{},[2763,2765,2770],{"type":49,"value":2764},"Use MEAI ",{"type":43,"tag":227,"props":2766,"children":2768},{"className":2767},[],[2769],{"type":49,"value":262},{"type":49,"value":2771}," directly — Agent Framework is for multi-step orchestration",{"type":43,"tag":67,"props":2773,"children":2774},{},[2775,2780],{"type":43,"tag":94,"props":2776,"children":2777},{},[2778],{"type":49,"value":2779},"Using Copilot SDK for general-purpose LLM apps",{"type":43,"tag":94,"props":2781,"children":2782},{},[2783],{"type":49,"value":2784},"Copilot SDK is for Copilot platform extensions only — use MEAI + Agent Framework for standalone apps",{"type":43,"tag":67,"props":2786,"children":2787},{},[2788,2793],{"type":43,"tag":94,"props":2789,"children":2790},{},[2791],{"type":49,"value":2792},"Calling OpenAI SDK directly in business logic instead of through MEAI",{"type":43,"tag":94,"props":2794,"children":2795},{},[2796,2798,2803,2805,2810],{"type":49,"value":2797},"Register the provider via ",{"type":43,"tag":227,"props":2799,"children":2801},{"className":2800},[],[2802],{"type":49,"value":628},{"type":49,"value":2804}," and depend on ",{"type":43,"tag":227,"props":2806,"children":2808},{"className":2807},[],[2809],{"type":49,"value":262},{"type":49,"value":2811}," in business code",{"type":43,"tag":67,"props":2813,"children":2814},{},[2815,2827],{"type":43,"tag":94,"props":2816,"children":2817},{},[2818,2820,2825],{"type":49,"value":2819},"Using ",{"type":43,"tag":227,"props":2821,"children":2823},{"className":2822},[],[2824],{"type":49,"value":2317},{"type":49,"value":2826}," as a singleton in ASP.NET Core",{"type":43,"tag":94,"props":2828,"children":2829},{},[2830,2831,2836,2838,2843],{"type":49,"value":1761},{"type":43,"tag":227,"props":2832,"children":2834},{"className":2833},[],[2835],{"type":49,"value":2309},{"type":49,"value":2837}," — ",{"type":43,"tag":227,"props":2839,"children":2841},{"className":2840},[],[2842],{"type":49,"value":2317},{"type":49,"value":2844}," is not thread-safe",{"type":43,"tag":67,"props":2846,"children":2847},{},[2848,2860],{"type":43,"tag":94,"props":2849,"children":2850},{},[2851,2852,2858],{"type":49,"value":2819},{"type":43,"tag":227,"props":2853,"children":2855},{"className":2854},[],[2856],{"type":49,"value":2857},"Func\u003CReadOnlySpan\u003CT>>",{"type":49,"value":2859}," for delegates with ref struct parameters",{"type":43,"tag":94,"props":2861,"children":2862},{},[2863],{"type":49,"value":2864},"Define a custom delegate type — ref structs cannot be generic type arguments",{"type":43,"tag":67,"props":2866,"children":2867},{},[2868,2880],{"type":43,"tag":94,"props":2869,"children":2870},{},[2871,2872,2878],{"type":49,"value":2819},{"type":43,"tag":227,"props":2873,"children":2875},{"className":2874},[],[2876],{"type":49,"value":2877},"Microsoft.SemanticKernel",{"type":49,"value":2879}," for new projects",{"type":43,"tag":94,"props":2881,"children":2882},{},[2883,2884,2889,2891,2896],{"type":49,"value":1761},{"type":43,"tag":227,"props":2885,"children":2887},{"className":2886},[],[2888],{"type":49,"value":298},{"type":49,"value":2890}," + ",{"type":43,"tag":227,"props":2892,"children":2894},{"className":2893},[],[2895],{"type":49,"value":291},{"type":49,"value":2897}," — Semantic Kernel is superseded by these newer abstractions for LLM orchestration and tool calling",{"type":43,"tag":52,"props":2899,"children":2901},{"id":2900},"common-pitfalls",[2902],{"type":49,"value":2903},"Common Pitfalls",{"type":43,"tag":59,"props":2905,"children":2906},{},[2907,2923],{"type":43,"tag":63,"props":2908,"children":2909},{},[2910],{"type":43,"tag":67,"props":2911,"children":2912},{},[2913,2918],{"type":43,"tag":71,"props":2914,"children":2915},{},[2916],{"type":49,"value":2917},"Pitfall",{"type":43,"tag":71,"props":2919,"children":2920},{},[2921],{"type":49,"value":2922},"Solution",{"type":43,"tag":87,"props":2924,"children":2925},{},[2926,2939,2960,2979,3000,3020,3033,3054],{"type":43,"tag":67,"props":2927,"children":2928},{},[2929,2934],{"type":43,"tag":94,"props":2930,"children":2931},{},[2932],{"type":49,"value":2933},"Over-engineering with LLMs",{"type":43,"tag":94,"props":2935,"children":2936},{},[2937],{"type":49,"value":2938},"Start with the simplest approach (rules, ML.NET) and add LLM capability only when simpler methods fall short",{"type":43,"tag":67,"props":2940,"children":2941},{},[2942,2947],{"type":43,"tag":94,"props":2943,"children":2944},{},[2945],{"type":49,"value":2946},"Evaluating ML models on training data",{"type":43,"tag":94,"props":2948,"children":2949},{},[2950,2952,2958],{"type":49,"value":2951},"Always use ",{"type":43,"tag":227,"props":2953,"children":2955},{"className":2954},[],[2956],{"type":49,"value":2957},"TrainTestSplit",{"type":49,"value":2959}," and report metrics on the held-out test set",{"type":43,"tag":67,"props":2961,"children":2962},{},[2963,2968],{"type":43,"tag":94,"props":2964,"children":2965},{},[2966],{"type":49,"value":2967},"LLM output drift between deployments",{"type":43,"tag":94,"props":2969,"children":2970},{},[2971,2973,2978],{"type":49,"value":2972},"Pin to specific dated model versions (e.g., ",{"type":43,"tag":227,"props":2974,"children":2976},{"className":2975},[],[2977],{"type":49,"value":2167},{"type":49,"value":234},{"type":43,"tag":67,"props":2980,"children":2981},{},[2982,2987],{"type":43,"tag":94,"props":2983,"children":2984},{},[2985],{"type":49,"value":2986},"Token cost surprises",{"type":43,"tag":94,"props":2988,"children":2989},{},[2990,2992,2998],{"type":49,"value":2991},"Set ",{"type":43,"tag":227,"props":2993,"children":2995},{"className":2994},[],[2996],{"type":49,"value":2997},"MaxOutputTokens",{"type":49,"value":2999},", use Microsoft.ML.Tokenizers for accurate client-side token counting, log token counts per request, and alert on budget thresholds",{"type":43,"tag":67,"props":3001,"children":3002},{},[3003,3008],{"type":43,"tag":94,"props":3004,"children":3005},{},[3006],{"type":49,"value":3007},"Non-reproducible ML training",{"type":43,"tag":94,"props":3009,"children":3010},{},[3011,3012,3018],{"type":49,"value":2991},{"type":43,"tag":227,"props":3013,"children":3015},{"className":3014},[],[3016],{"type":49,"value":3017},"MLContext(seed: N)",{"type":49,"value":3019}," and version your training data alongside the code",{"type":43,"tag":67,"props":3021,"children":3022},{},[3023,3028],{"type":43,"tag":94,"props":3024,"children":3025},{},[3026],{"type":49,"value":3027},"RAG returning irrelevant context",{"type":43,"tag":94,"props":3029,"children":3030},{},[3031],{"type":49,"value":3032},"Set a minimum similarity score and limit the number of injected chunks",{"type":43,"tag":67,"props":3034,"children":3035},{},[3036,3041],{"type":43,"tag":94,"props":3037,"children":3038},{},[3039],{"type":49,"value":3040},"Cold start latency on ML.NET models",{"type":43,"tag":94,"props":3042,"children":3043},{},[3044,3046,3052],{"type":49,"value":3045},"Pre-warm the ",{"type":43,"tag":227,"props":3047,"children":3049},{"className":3048},[],[3050],{"type":49,"value":3051},"PredictionEnginePool",{"type":49,"value":3053}," during application startup",{"type":43,"tag":67,"props":3055,"children":3056},{},[3057,3062],{"type":43,"tag":94,"props":3058,"children":3059},{},[3060],{"type":49,"value":3061},"Microsoft Agent Framework + raw OpenAI SDK in same class",{"type":43,"tag":94,"props":3063,"children":3064},{},[3065],{"type":49,"value":3066},"Choose one orchestration layer per workflow boundary",{"type":43,"tag":3068,"props":3069,"children":3070},"style",{},[3071],{"type":49,"value":3072},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3074,"total":3235},[3075,3091,3106,3119,3136,3150,3169,3179,3191,3201,3214,3225],{"slug":3076,"name":3076,"fn":3077,"description":3078,"org":3079,"tags":3080,"stars":3088,"repoUrl":3089,"updatedAt":3090},"multithreaded-task-migration","migrate MSBuild tasks to multithreaded mode","Guide for migrating MSBuild tasks to multithreaded mode support, including compatibility red-team review. Use this when converting tasks to thread-safe versions, implementing IMultiThreadableTask, adding TaskEnvironment support, or auditing migrations for behavioral compatibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3081,3082,3085],{"name":17,"slug":18,"type":15},{"name":3083,"slug":3084,"type":15},"Engineering","engineering",{"name":3086,"slug":3087,"type":15},"Performance","performance",5535,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fmsbuild","2026-07-22T05:37:33.965588",{"slug":3092,"name":3092,"fn":3093,"description":3094,"org":3095,"tags":3096,"stars":25,"repoUrl":26,"updatedAt":3105},"analyzing-dotnet-performance","analyze .NET code for performance anti-patterns","Scans .NET code for ~50 performance anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I\u002FO with tiered severity classification. Use when analyzing .NET code for optimization opportunities, reviewing hot paths, or auditing allocation-heavy patterns.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3097,3098,3101,3104],{"name":17,"slug":18,"type":15},{"name":3099,"slug":3100,"type":15},"Code Analysis","code-analysis",{"name":3102,"slug":3103,"type":15},"Debugging","debugging",{"name":3086,"slug":3087,"type":15},"2026-07-12T08:23:25.400375",{"slug":3107,"name":3107,"fn":3108,"description":3109,"org":3110,"tags":3111,"stars":25,"repoUrl":26,"updatedAt":3118},"android-tombstone-symbolication","symbolicate .NET runtime frames in Android tombstones","Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java\u002FKotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3112,3113,3116,3117],{"name":17,"slug":18,"type":15},{"name":3114,"slug":3115,"type":15},"Android","android",{"name":3102,"slug":3103,"type":15},{"name":20,"slug":21,"type":15},"2026-07-12T08:23:21.595572",{"slug":3120,"name":3120,"fn":3121,"description":3122,"org":3123,"tags":3124,"stars":25,"repoUrl":26,"updatedAt":3135},"apple-crash-symbolication","symbolicate .NET runtime frames in crash logs","Symbolicate .NET runtime frames in Apple platform .ips crash logs (iOS, tvOS, Mac Catalyst, macOS). Extracts UUIDs and addresses from the native backtrace, locates dSYM debug symbols, and runs atos to produce function names with source file and line numbers. Automatically downloads .dwarf symbols from the Microsoft symbol server using Mach-O UUIDs. USE FOR triaging a .NET MAUI or Mono app crash from an .ips file on any Apple platform, resolving native backtrace frames in libcoreclr or libmonosgen-2.0 to .NET runtime source code, retrieving .ips crash logs from a connected iOS device or iPhone, or investigating EXC_CRASH, EXC_BAD_ACCESS, SIGABRT, or SIGSEGV originating from the .NET runtime. DO NOT USE FOR pure Swift\u002FObjective-C crashes with no .NET components, or Android tombstone files. INVOKES Symbolicate-Crash.ps1 script, atos, dwarfdump, idevicecrashreport.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3125,3126,3127,3130,3133],{"name":17,"slug":18,"type":15},{"name":3102,"slug":3103,"type":15},{"name":3128,"slug":3129,"type":15},"iOS","ios",{"name":3131,"slug":3132,"type":15},"macOS","macos",{"name":1864,"slug":3134,"type":15},"observability","2026-07-12T08:23:20.369986",{"slug":3137,"name":3137,"fn":3138,"description":3139,"org":3140,"tags":3141,"stars":25,"repoUrl":26,"updatedAt":3149},"assertion-quality","evaluate assertion quality in test suites","Analyzes the variety and depth of assertions across test suites in any language. Use when the user asks to evaluate assertion quality, find shallow tests, identify assertion-free tests (no assertions or only trivial ones like Assert.IsNotNull \u002F toBeTruthy()), flag self-referential or tautological assertions, measure assertion diversity, or audit whether tests verify different facets of behavior. Polyglot: .NET, Python, TS\u002FJS, Java, Go, Ruby, Rust, Swift, Kotlin, PowerShell, C++. DO NOT USE FOR: writing new tests (use code-testing-agent \u002F writing-mstest-tests), mutation reasoning about whether tests would catch a bug (use test-gap-analysis), or a general severity-ranked anti-pattern audit (use test-anti-patterns), fixing or rewriting assertions, or writing, fixing, or modernizing MSTest tests, assertions, or attributes (use writing-mstest-tests).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3142,3143,3146],{"name":3099,"slug":3100,"type":15},{"name":3144,"slug":3145,"type":15},"QA","qa",{"name":3147,"slug":3148,"type":15},"Testing","testing","2026-07-12T08:23:51.277743",{"slug":3151,"name":3151,"fn":3152,"description":3153,"org":3154,"tags":3155,"stars":25,"repoUrl":26,"updatedAt":3168},"author-component","create and review Blazor components","Create or review Blazor components (.razor files) with correct architecture. USE FOR: writing new Blazor components that do NOT involve JavaScript interop, implementing parameters and EventCallback, RenderFragment slots, component lifecycle (OnInitializedAsync, OnParametersSet), async patterns, IAsyncDisposable, CancellationToken, CSS isolation, code-behind. DO NOT USE FOR: creating new projects (use create-blazor-project), JavaScript interop or calling browser APIs from Blazor (use use-js-interop), forms and validation (use collect-user-input), prerendering issues (use support-prerendering), HTTP data fetching patterns (use fetch-and-send-data), coordinating state between unrelated components (use coordinate-components).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3156,3157,3160,3162,3165],{"name":17,"slug":18,"type":15},{"name":3158,"slug":3159,"type":15},"Blazor","blazor",{"name":3161,"slug":1326,"type":15},"C#",{"name":3163,"slug":3164,"type":15},"UI Components","ui-components",{"name":3166,"slug":3167,"type":15},"Web Development","web-development","2026-07-15T06:03:29.216359",{"slug":3170,"name":3170,"fn":3171,"description":3172,"org":3173,"tags":3174,"stars":25,"repoUrl":26,"updatedAt":3178},"binlog-failure-analysis","analyze MSBuild binary logs","Analyze MSBuild binary logs to diagnose build failures. USE FOR: build errors that are unclear from console output, diagnosing cascading failures across multi-project builds, tracing MSBuild target execution order, and generally any MSBuild build issues. Requires an existing .binlog file. DO NOT USE FOR: generating binlogs (use binlog-generation), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3175,3176,3177],{"name":3099,"slug":3100,"type":15},{"name":3102,"slug":3103,"type":15},{"name":20,"slug":21,"type":15},"2026-07-12T08:21:34.637923",{"slug":3180,"name":3180,"fn":3181,"description":3182,"org":3183,"tags":3184,"stars":25,"repoUrl":26,"updatedAt":3190},"binlog-generation","generate MSBuild binary logs for diagnostics","Generate MSBuild binary logs (binlogs) for build diagnostics and analysis. USE FOR: adding \u002Fbl:{} to any dotnet build, test, pack, publish, or restore command to capture a full build execution trace, prerequisite for binlog-failure-analysis and build-perf-diagnostics skills, enabling post-build investigation of errors or performance. Requires MSBuild 17.8+ \u002F .NET 8 SDK+ for {} placeholder; PowerShell needs -bl:{{}}. DO NOT USE FOR: non-MSBuild build systems (npm, Maven, CMake), analyzing an existing binlog (use binlog-failure-analysis instead).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3185,3188,3189],{"name":3186,"slug":3187,"type":15},"Build","build",{"name":3102,"slug":3103,"type":15},{"name":3083,"slug":3084,"type":15},"2026-07-19T05:38:19.340791",{"slug":3192,"name":3192,"fn":3193,"description":3194,"org":3195,"tags":3196,"stars":25,"repoUrl":26,"updatedAt":3200},"build-parallelism","optimize MSBuild build parallelism","Diagnose and fix under-parallelized MSBuild builds. USE WHEN a multi-project solution build is slower than expected, doesn't speed up when you add cores, pegs a single core while others idle, or you want to know why `-m` isn't helping. Note: `\u002Fmaxcpucount` default is 1 (sequential) — always pass `-m` for parallel builds. Covers finding the critical path (longest serial ProjectReference chain), graph build (`\u002Fgraph`), BuildInParallel, and solution filters (`.slnf`). DO NOT USE FOR: single-project builds, incremental issues (use incremental-build), compilation slowness inside one project (use build-perf-diagnostics), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3197,3198,3199],{"name":17,"slug":18,"type":15},{"name":3083,"slug":3084,"type":15},{"name":3086,"slug":3087,"type":15},"2026-07-19T05:38:18.364937",{"slug":3202,"name":3202,"fn":3203,"description":3204,"org":3205,"tags":3206,"stars":25,"repoUrl":26,"updatedAt":3213},"build-perf-baseline","establish and optimize build performance baselines","Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before\u002Fafter measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output, and dependency graph trimming. Start here before diving into build-perf-diagnostics, incremental-build, or build-parallelism. DO NOT USE FOR: non-MSBuild build systems, detailed bottleneck analysis (use build-perf-diagnostics after baselining).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3207,3208,3211,3212],{"name":3083,"slug":3084,"type":15},{"name":3209,"slug":3210,"type":15},"Monitoring","monitoring",{"name":3086,"slug":3087,"type":15},{"name":3147,"slug":3148,"type":15},"2026-07-12T08:21:35.865649",{"slug":3215,"name":3215,"fn":3216,"description":3217,"org":3218,"tags":3219,"stars":25,"repoUrl":26,"updatedAt":3224},"build-perf-diagnostics","diagnose MSBuild build performance bottlenecks","Diagnose MSBuild build performance bottlenecks using binary log analysis. USE FOR: identifying why builds are slow by analyzing binlog performance summaries, detecting ResolveAssemblyReference (RAR) taking >5s, Roslyn analyzers consuming >30% of Csc time, single targets dominating >50% of build time, node utilization below 80%, excessive Copy tasks, NuGet restore running every build. Covers timeline analysis, Target\u002FTask Performance Summary interpretation, and 7 common bottleneck categories. Use after build-perf-baseline has established measurements. DO NOT USE FOR: establishing initial baselines (use build-perf-baseline first), fixing incremental build issues (use incremental-build), parallelism tuning (use build-parallelism), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3220,3221,3222,3223],{"name":17,"slug":18,"type":15},{"name":3102,"slug":3103,"type":15},{"name":3083,"slug":3084,"type":15},{"name":3086,"slug":3087,"type":15},"2026-07-12T08:21:40.961722",{"slug":3226,"name":3226,"fn":3227,"description":3228,"org":3229,"tags":3230,"stars":25,"repoUrl":26,"updatedAt":3234},"check-bin-obj-clash","detect MSBuild output path conflicts","Detects MSBuild projects with conflicting OutputPath or IntermediateOutputPath. USE FOR: builds failing with 'Cannot create a file when that file already exists', 'The process cannot access the file because it is being used by another process', intermittent build failures that succeed on retry, or missing\u002Foverwritten outputs in multi-project or multi-targeting builds where bin\u002Fobj (or project.assets.json) collide. Common causes: shared OutputPath, missing AppendTargetFrameworkToOutputPath, extra global properties (e.g. PublishReadyToRun), or SetTargetFramework on a ProjectReference to a single-targeting project. DO NOT USE FOR: file access errors unrelated to MSBuild (OS-level locking), single-project single-TFM builds, non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3231,3232,3233],{"name":3102,"slug":3103,"type":15},{"name":3083,"slug":3084,"type":15},{"name":3144,"slug":3145,"type":15},"2026-07-19T05:38:14.336279",144,{"items":3237,"total":3286},[3238,3245,3252,3260,3266,3274,3280],{"slug":3092,"name":3092,"fn":3093,"description":3094,"org":3239,"tags":3240,"stars":25,"repoUrl":26,"updatedAt":3105},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3241,3242,3243,3244],{"name":17,"slug":18,"type":15},{"name":3099,"slug":3100,"type":15},{"name":3102,"slug":3103,"type":15},{"name":3086,"slug":3087,"type":15},{"slug":3107,"name":3107,"fn":3108,"description":3109,"org":3246,"tags":3247,"stars":25,"repoUrl":26,"updatedAt":3118},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3248,3249,3250,3251],{"name":17,"slug":18,"type":15},{"name":3114,"slug":3115,"type":15},{"name":3102,"slug":3103,"type":15},{"name":20,"slug":21,"type":15},{"slug":3120,"name":3120,"fn":3121,"description":3122,"org":3253,"tags":3254,"stars":25,"repoUrl":26,"updatedAt":3135},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3255,3256,3257,3258,3259],{"name":17,"slug":18,"type":15},{"name":3102,"slug":3103,"type":15},{"name":3128,"slug":3129,"type":15},{"name":3131,"slug":3132,"type":15},{"name":1864,"slug":3134,"type":15},{"slug":3137,"name":3137,"fn":3138,"description":3139,"org":3261,"tags":3262,"stars":25,"repoUrl":26,"updatedAt":3149},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3263,3264,3265],{"name":3099,"slug":3100,"type":15},{"name":3144,"slug":3145,"type":15},{"name":3147,"slug":3148,"type":15},{"slug":3151,"name":3151,"fn":3152,"description":3153,"org":3267,"tags":3268,"stars":25,"repoUrl":26,"updatedAt":3168},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3269,3270,3271,3272,3273],{"name":17,"slug":18,"type":15},{"name":3158,"slug":3159,"type":15},{"name":3161,"slug":1326,"type":15},{"name":3163,"slug":3164,"type":15},{"name":3166,"slug":3167,"type":15},{"slug":3170,"name":3170,"fn":3171,"description":3172,"org":3275,"tags":3276,"stars":25,"repoUrl":26,"updatedAt":3178},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3277,3278,3279],{"name":3099,"slug":3100,"type":15},{"name":3102,"slug":3103,"type":15},{"name":20,"slug":21,"type":15},{"slug":3180,"name":3180,"fn":3181,"description":3182,"org":3281,"tags":3282,"stars":25,"repoUrl":26,"updatedAt":3190},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3283,3284,3285],{"name":3186,"slug":3187,"type":15},{"name":3102,"slug":3103,"type":15},{"name":3083,"slug":3084,"type":15},96]