<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Loïc Carrère</title>
    <description>The latest articles on Forem by Loïc Carrère (@loc_carrre_0d798813c662).</description>
    <link>https://forem.com/loc_carrre_0d798813c662</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3052497%2F2da60c2c-4f49-4481-90bd-62a1c959ac33.jpg</url>
      <title>Forem: Loïc Carrère</title>
      <link>https://forem.com/loc_carrre_0d798813c662</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/loc_carrre_0d798813c662"/>
    <language>en</language>
    <item>
      <title>Agent Skills Explained: What They Are, What They Aren't, and How to Use Them</title>
      <dc:creator>Loïc Carrère</dc:creator>
      <pubDate>Sat, 07 Feb 2026 17:35:42 +0000</pubDate>
      <link>https://forem.com/loc_carrre_0d798813c662/agent-skills-explained-what-they-are-what-they-arent-and-how-to-use-them-bf9</link>
      <guid>https://forem.com/loc_carrre_0d798813c662/agent-skills-explained-what-they-are-what-they-arent-and-how-to-use-them-bf9</guid>
      <description>&lt;p&gt;&lt;em&gt;A comprehensive guide to the open standard that turns AI agents into on-demand specialists&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Agent Skills is an open standard for packaging reusable AI agent capabilities as plain Markdown files. A skill is a folder with a &lt;code&gt;SKILL.md&lt;/code&gt; file containing metadata and instructions. When an agent activates a skill, it loads the instructions on demand, follows them as an explicit workflow, and produces structured, repeatable output. Skills solve the problem of bloated prompts, inconsistent behavior, and tightly coupled agent logic. They are supported by leading tools including OpenAI Codex, GitHub Copilot, VS Code, Cursor, and LM-Kit.NET.&lt;/p&gt;

&lt;p&gt;This article covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What Agent Skills actually are (and what they are not)&lt;/li&gt;
&lt;li&gt;How they compare to MCP, tool use, system prompts, and subagents&lt;/li&gt;
&lt;li&gt;How progressive disclosure works&lt;/li&gt;
&lt;li&gt;Why skills are particularly well-suited for local inference&lt;/li&gt;
&lt;li&gt;A complete, runnable C# tutorial using LM-Kit.NET&lt;/li&gt;
&lt;li&gt;Best practices for writing your own skills&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Quick start with LM-Kit.NET
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package LM-Kit.NET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Load skills from a folder&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SkillRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./skills"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Activate a skill&lt;/span&gt;
&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryParseSlashCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/explain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Inject instructions into the conversation&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SkillActivator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;activator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FormatForInjection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SkillInjectionMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\n\n---\n\nUser request: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full tutorial in Section 9. Full demo on &lt;a href="https://github.com/LM-Kit/lm-kit-net-samples/tree/main/console_net/agents/skill_based_assistant" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Problem: Why We Need Agent Skills
&lt;/h2&gt;

&lt;p&gt;If you have built an AI agent that does more than one thing, you have probably hit this wall:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your system prompt keeps growing.&lt;/strong&gt; Every new capability means more instructions, more examples, more edge cases. A prompt that started at 200 tokens is now 5,000. The agent gets slower, more expensive, and less reliable because it is trying to juggle everything at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavior is inconsistent.&lt;/strong&gt; Ask the same agent to review code on Monday and again on Friday, and you might get different formats, different levels of detail, different criteria. There is nothing enforcing a consistent process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompts live in code.&lt;/strong&gt; The instructions that define your agent's behavior are buried in C# strings, Python f-strings, or YAML configs. Non-developers cannot review or improve them. Version control is awkward. Deploying a small wording change means a code release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Knowledge is not reusable.&lt;/strong&gt; You build a great code review workflow for Project A. Project B needs the same thing. You copy-paste the prompt, it drifts, and now you maintain two copies.&lt;/p&gt;

&lt;p&gt;These are not edge cases. They are the daily reality of production AI development. Agent Skills were created to solve exactly these problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. What Agent Skills Are
&lt;/h2&gt;

&lt;p&gt;Agent Skills is an &lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;open specification&lt;/a&gt; for defining modular, reusable AI agent capabilities as self-contained directories. It was &lt;a href="https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills" rel="noopener noreferrer"&gt;developed by Anthropic&lt;/a&gt; and introduced publicly on October 16, 2025. On December 18, 2025, the format was &lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;published as an open standard&lt;/a&gt; for cross-platform portability, open to contributions from the broader ecosystem.&lt;/p&gt;

&lt;p&gt;At its core, a skill is a folder containing one required file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;explain/
  SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The &lt;code&gt;SKILL.md&lt;/code&gt; file has two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;YAML frontmatter&lt;/strong&gt; with metadata (name, description, version)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown body&lt;/strong&gt; with the actual instructions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a complete, working skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;explain&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Explains any topic in plain language. Type a word or phrase and get a clear, jargon-free explanation.&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Plain Language Explainer&lt;/span&gt;

You explain topics so anyone can understand them. The user gives you a word,
phrase, or concept. You explain it clearly.

&lt;span class="gu"&gt;## Output Format&lt;/span&gt;

&lt;span class="gu"&gt;## &amp;lt;Topic&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**In one sentence:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;simple&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;one-sentence&lt;/span&gt; &lt;span class="na"&gt;definition&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**How it works:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="na"&gt;-3&lt;/span&gt; &lt;span class="na"&gt;sentences&lt;/span&gt; &lt;span class="na"&gt;explaining&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;mechanism&lt;/span&gt; &lt;span class="na"&gt;or&lt;/span&gt; &lt;span class="na"&gt;idea&lt;/span&gt; &lt;span class="na"&gt;using&lt;/span&gt; &lt;span class="na"&gt;an&lt;/span&gt; &lt;span class="na"&gt;everyday&lt;/span&gt; &lt;span class="na"&gt;analogy&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**Why it matters:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="na"&gt;-2&lt;/span&gt; &lt;span class="na"&gt;sentences&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt; &lt;span class="na"&gt;why&lt;/span&gt; &lt;span class="na"&gt;someone&lt;/span&gt; &lt;span class="na"&gt;should&lt;/span&gt; &lt;span class="na"&gt;care&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**Example:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;one&lt;/span&gt; &lt;span class="na"&gt;concrete&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;real-world&lt;/span&gt; &lt;span class="na"&gt;example&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**No jargon.**&lt;/span&gt; If you must use a technical term, define it in parentheses.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Use analogies.**&lt;/span&gt; Compare unfamiliar concepts to everyday things.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Be concise.**&lt;/span&gt; The entire explanation fits on one screen.
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**Assume zero background knowledge.**&lt;/span&gt;
&lt;span class="p"&gt;5.&lt;/span&gt; Never say "it's complicated" or "it depends." Just explain it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a complete Agent Skill. Save it as &lt;code&gt;explain/SKILL.md&lt;/code&gt;, point your agent at it, and the agent will follow these instructions precisely whenever the skill is activated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional Resources
&lt;/h3&gt;

&lt;p&gt;For more complex skills, the directory can include additional folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code-review/
  SKILL.md                # Required: instructions + metadata
  scripts/                # Optional: executable code
    lint-check.sh
  references/             # Optional: documentation
    coding-standards.md
  assets/                 # Optional: templates, data files
    review-template.json
  examples/               # Optional: sample inputs/outputs
    sample-review.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These resources are loaded lazily: the agent only reads them when it actually needs them, not at startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  YAML Frontmatter Reference
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;Agent Skills specification&lt;/a&gt; defines these frontmatter fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Constraints&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;1-64 chars. Lowercase letters, numbers, and hyphens only. Must match the parent directory name. No consecutive hyphens (&lt;code&gt;--&lt;/code&gt;). Must not start or end with a hyphen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;1-1024 chars. Describes what the skill does and when to use it. Should include keywords that help agents match tasks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;license&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;License name or reference to a bundled license file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;compatibility&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Max 500 chars. Environment requirements (intended product, system packages, network access).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;metadata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Arbitrary key-value mapping. Use this for &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, or any custom properties.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;allowed-tools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Space-delimited list of pre-approved tools the skill may use. (Experimental; support varies by implementation.)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note that &lt;code&gt;version&lt;/code&gt; is not a top-level spec field. Use the &lt;code&gt;metadata&lt;/code&gt; map for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-org&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some implementations (including LM-Kit.NET) also accept &lt;code&gt;version&lt;/code&gt; as a top-level convenience field, but for maximum portability across tools, place it inside &lt;code&gt;metadata&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. What Agent Skills Are NOT
&lt;/h2&gt;

&lt;p&gt;This is just as important as understanding what they are. Misunderstanding the boundaries leads to poor design decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills are not tools.&lt;/strong&gt; A tool (MCP tool, function call, API endpoint) is a deterministic action: call it with inputs, get a structured output. A skill is a set of instructions interpreted by an LLM. Skills describe &lt;em&gt;how&lt;/em&gt; to do something. Tools &lt;em&gt;do&lt;/em&gt; something. They are complementary layers. As the Goose team at Block &lt;a href="https://block.github.io/goose/blog/2025/12/22/agent-skills-vs-mcp/" rel="noopener noreferrer"&gt;put it&lt;/a&gt;: skills describe the workflow, while MCP provides the runner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills are not prompts.&lt;/strong&gt; A prompt is ephemeral, reactive, and typically embedded in code. A skill is a persistent, portable, version-controlled artifact. Skills load dynamically based on context. Prompts are always present.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills are not agents.&lt;/strong&gt; An agent is an execution runtime with its own tools, memory, and decision loop. A skill is a knowledge module that &lt;em&gt;any&lt;/em&gt; agent can load. Think of skills as "apps" and agents as the "operating system."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills are not deterministic.&lt;/strong&gt; Because an LLM interprets the instructions, there is inherent non-determinism. The same skill can produce slightly different outputs. If you need guaranteed structure, combine a skill with structured output constraints (grammar, JSON schema) or use tool calls for the critical parts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills are not a replacement for MCP.&lt;/strong&gt; MCP (Model Context Protocol) provides secure connectivity to external systems: databases, APIs, file systems. Skills provide procedural knowledge for &lt;em&gt;using&lt;/em&gt; those systems. A "Database Query" skill might instruct the agent on how to write safe SQL and handle edge cases, while an MCP server provides the actual database connection. Different layers, same stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Agent Skills vs. MCP vs. Tool Use vs. Prompts
&lt;/h2&gt;

&lt;p&gt;One of the most common confusions in the current AI tooling landscape is understanding where Agent Skills fit relative to MCP, function calling/tool use, system prompts, and subagents. This section lays it out concretely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skills vs. MCP (Model Context Protocol)
&lt;/h3&gt;

&lt;p&gt;MCP and Agent Skills both originated at Anthropic, but they solve different problems at different layers.&lt;/p&gt;

&lt;p&gt;MCP is a &lt;strong&gt;communication protocol&lt;/strong&gt; (&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;spec&lt;/a&gt;). It defines how an agent talks to external systems: databases, APIs, file systems, SaaS applications. An MCP server exposes tools (structured functions with JSON schemas) and resources (data the agent can read). When the agent calls an MCP tool, it sends a JSON-RPC request and gets a deterministic response. MCP runs as a separate process with its own authentication and isolation.&lt;/p&gt;

&lt;p&gt;Agent Skills are &lt;strong&gt;knowledge files&lt;/strong&gt;. A skill tells the agent &lt;em&gt;how&lt;/em&gt; to think about a task: what steps to follow, what output format to use, what constraints to respect. Skills run inside the agent's own context window. There is no separate process, no network call, no schema.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://block.github.io/goose/blog/2025/12/22/agent-skills-vs-mcp/" rel="noopener noreferrer"&gt;Goose team at Block&lt;/a&gt; summarized it well: MCP gives agents abilities; skills teach agents how to use those abilities well. Anthropic product manager Mahesh Murag confirmed in the &lt;a href="https://venturebeat.com/technology/anthropic-launches-enterprise-agent-skills-and-opens-the-standard" rel="noopener noreferrer"&gt;VentureBeat launch coverage&lt;/a&gt; that the two are designed as complementary layers.&lt;/p&gt;

&lt;p&gt;A concrete example: you might have an MCP server that connects to your PostgreSQL database. The MCP server exposes a &lt;code&gt;run_query&lt;/code&gt; tool. But the agent still needs to know &lt;em&gt;how&lt;/em&gt; to write safe, efficient SQL for your specific schema. That is what a &lt;code&gt;database-query&lt;/code&gt; skill provides: the procedural knowledge for using the tool well.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Agent Skills&lt;/th&gt;
&lt;th&gt;MCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Knowledge / procedure&lt;/td&gt;
&lt;td&gt;Connectivity / action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Markdown + YAML file&lt;/td&gt;
&lt;td&gt;JSON-RPC 2.0 protocol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LLM interprets instructions&lt;/td&gt;
&lt;td&gt;Deterministic API call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shares agent's context&lt;/td&gt;
&lt;td&gt;Separate process per server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero (local file read)&lt;/td&gt;
&lt;td&gt;Network round-trip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (trust the file)&lt;/td&gt;
&lt;td&gt;OAuth-native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stateless (text)&lt;/td&gt;
&lt;td&gt;Stateful (running server)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Workflows, expertise, formats&lt;/td&gt;
&lt;td&gt;Data access, external actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Misinterpretation, hallucination&lt;/td&gt;
&lt;td&gt;Tool poisoning, auth leaks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a deeper technical analysis, see the &lt;a href="https://www.llamaindex.ai/blog/skills-vs-mcp-tools-for-agents-when-to-use-what" rel="noopener noreferrer"&gt;LlamaIndex comparison&lt;/a&gt; and &lt;a href="https://www.friedrichs-it.de/blog/agent-skills-vs-model-context-protocol/" rel="noopener noreferrer"&gt;Friedrichs-IT security analysis&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skills vs. Tool Use / Function Calling
&lt;/h3&gt;

&lt;p&gt;Tool use (also called function calling) is the mechanism where an LLM decides to invoke a structured function. The model outputs a JSON object with a function name and arguments; the runtime executes it and returns the result. OpenAI, Anthropic, Google, and most providers support this natively.&lt;/p&gt;

&lt;p&gt;Skills operate at a higher level of abstraction. A single skill might orchestrate multiple tool calls as part of a workflow. For example, a &lt;code&gt;research-report&lt;/code&gt; skill could instruct the agent to: (1) search the web, (2) read the top 5 results, (3) synthesize findings, (4) format them as a report. The skill defines the &lt;em&gt;procedure&lt;/em&gt;; individual tool calls handle the &lt;em&gt;actions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can also combine the two directly. In LM-Kit.NET, a skill can be exposed as a tool via &lt;code&gt;SkillTool&lt;/code&gt;, letting the model decide when to activate a particular skill through the function calling interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skills vs. System Prompts
&lt;/h3&gt;

&lt;p&gt;A system prompt is a block of text prepended to every conversation. It is always present, always consuming tokens, and typically hardcoded in your application.&lt;/p&gt;

&lt;p&gt;A skill is loaded only when needed and unloaded when done. This is the progressive disclosure advantage. But there is a deeper difference: skills are &lt;strong&gt;portable artifacts&lt;/strong&gt; that live outside your code. A system prompt is part of your application. A skill is a file you can share, version, review, and swap without changing a line of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skills vs. Subagents
&lt;/h3&gt;

&lt;p&gt;A subagent is a fully independent agent with its own model, tools, system prompt, and conversation history. Orchestration patterns (pipeline, supervisor, parallel) coordinate multiple subagents.&lt;/p&gt;

&lt;p&gt;A skill is lighter. It does not create a new execution context. It augments an &lt;em&gt;existing&lt;/em&gt; agent's behavior. You can think of subagents as "hiring a specialist contractor" and skills as "reading the specialist's playbook yourself." Both are valid; the choice depends on whether you need autonomous execution (subagent) or guided behavior within the current conversation (skill).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Full Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Agent Skills&lt;/th&gt;
&lt;th&gt;MCP Tools&lt;/th&gt;
&lt;th&gt;Function Calling&lt;/th&gt;
&lt;th&gt;System Prompts&lt;/th&gt;
&lt;th&gt;Subagents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it is&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Portable knowledge module&lt;/td&gt;
&lt;td&gt;External connectivity&lt;/td&gt;
&lt;td&gt;Structured action invocation&lt;/td&gt;
&lt;td&gt;Static instruction text&lt;/td&gt;
&lt;td&gt;Independent execution context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SKILL.md (Markdown)&lt;/td&gt;
&lt;td&gt;JSON-RPC server&lt;/td&gt;
&lt;td&gt;JSON schema&lt;/td&gt;
&lt;td&gt;String in code&lt;/td&gt;
&lt;td&gt;Agent with own config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Non-deterministic (LLM)&lt;/td&gt;
&lt;td&gt;Deterministic (API)&lt;/td&gt;
&lt;td&gt;Deterministic (API)&lt;/td&gt;
&lt;td&gt;Non-deterministic (LLM)&lt;/td&gt;
&lt;td&gt;Non-deterministic (LLM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Loading&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;On-demand&lt;/td&gt;
&lt;td&gt;Always connected&lt;/td&gt;
&lt;td&gt;Always available&lt;/td&gt;
&lt;td&gt;Always in context&lt;/td&gt;
&lt;td&gt;On-demand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only when active&lt;/td&gt;
&lt;td&gt;Schema always present&lt;/td&gt;
&lt;td&gt;Schema always present&lt;/td&gt;
&lt;td&gt;Always present&lt;/td&gt;
&lt;td&gt;Separate context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Versioned file&lt;/td&gt;
&lt;td&gt;Running process&lt;/td&gt;
&lt;td&gt;Code definition&lt;/td&gt;
&lt;td&gt;Embedded in code&lt;/td&gt;
&lt;td&gt;Running process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cross-platform standard&lt;/td&gt;
&lt;td&gt;Cross-platform standard&lt;/td&gt;
&lt;td&gt;Provider-specific schema&lt;/td&gt;
&lt;td&gt;Vendor-specific&lt;/td&gt;
&lt;td&gt;Framework-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Workflows, expertise, roles&lt;/td&gt;
&lt;td&gt;Data access, external APIs&lt;/td&gt;
&lt;td&gt;Single actions&lt;/td&gt;
&lt;td&gt;Baseline behavior&lt;/td&gt;
&lt;td&gt;Complex autonomous work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  When to Use What
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;Agent Skills&lt;/strong&gt; when you need the agent to follow a specific workflow, produce a specific output format, or behave with domain expertise. Skills are the right choice when behavior should be portable, reviewable, and swappable without code changes.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;MCP&lt;/strong&gt; when the agent needs to interact with external systems: read a database, call a REST API, access a file system on a remote server.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;function calling / tool use&lt;/strong&gt; when you need the agent to perform a specific, well-defined action with structured inputs and outputs.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;system prompts&lt;/strong&gt; for baseline personality, safety constraints, and always-on behavior that applies to every conversation regardless of task.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;subagents&lt;/strong&gt; when a task requires autonomous multi-step reasoning with its own dedicated tools and context, especially in orchestration patterns (pipelines, parallel work, supervisor delegation).&lt;/p&gt;

&lt;p&gt;In practice, production agents combine all of these. A typical architecture: system prompt for baseline behavior, skills for task-specific expertise, MCP for external data, function calling for actions, and subagents for complex orchestration.&lt;/p&gt;

&lt;p&gt;For the authoritative comparison, see the &lt;a href="https://claude.com/blog/skills-explained" rel="noopener noreferrer"&gt;Claude blog on Skills&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. How Progressive Disclosure Works
&lt;/h2&gt;

&lt;p&gt;The key architectural innovation of Agent Skills is &lt;strong&gt;progressive disclosure&lt;/strong&gt;: a three-tier loading strategy that keeps context efficient.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;th&gt;What loads&lt;/th&gt;
&lt;th&gt;Token cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At startup&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; from YAML frontmatter only&lt;/td&gt;
&lt;td&gt;~50 tokens per skill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Activation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When the skill is triggered&lt;/td&gt;
&lt;td&gt;Full SKILL.md body: instructions, output format, rules, examples&lt;/td&gt;
&lt;td&gt;~500 to 5,000 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When the agent actually needs them&lt;/td&gt;
&lt;td&gt;Files in &lt;code&gt;references/&lt;/code&gt;, &lt;code&gt;scripts/&lt;/code&gt;, &lt;code&gt;assets/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~2,000+ tokens per resource&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;At startup&lt;/strong&gt;, the agent loads only names and descriptions of all available skills. If you have 20 skills, that is roughly 1,000 tokens of metadata. The agent knows &lt;em&gt;what&lt;/em&gt; it can do, but carries none of the detailed instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When a skill is activated&lt;/strong&gt; (by user command or automatic matching), the full SKILL.md body is loaded into context. The agent now has the detailed instructions, output format, and rules for that specific task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;During execution&lt;/strong&gt;, if the skill references a file in &lt;code&gt;references/&lt;/code&gt; or &lt;code&gt;scripts/&lt;/code&gt;, that content is loaded only when the agent actually needs it.&lt;/p&gt;

&lt;p&gt;This means you can give an agent access to a large library of capabilities without paying the token cost for all of them at once. The context window stays clean, the agent stays focused, and you only pay for what you use.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. What Problems Do Agent Skills Solve in Practice?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Context efficiency
&lt;/h3&gt;

&lt;p&gt;Without skills, a multi-capability agent needs all instructions loaded simultaneously. With 10 workflows averaging 500 tokens each, that is 5,000 tokens of permanent context overhead. With skills, the overhead is ~500 tokens for the catalog plus ~500 tokens for whichever skill is currently active. A 10x reduction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistent, repeatable output
&lt;/h3&gt;

&lt;p&gt;A skill specifies an exact output format, a set of rules, and optionally examples. Every time the agent runs that skill, it follows the same structure. This is the difference between "review this code" (unpredictable) and "review this code using the code-review skill" (structured checklist, consistent format, every time).&lt;/p&gt;

&lt;h3&gt;
  
  
  Modularity
&lt;/h3&gt;

&lt;p&gt;Add a new capability? Drop a folder. Remove one? Delete the folder. Update a workflow? Edit the Markdown. No code changes, no redeployment, no risk of breaking unrelated features. Skills decouple &lt;em&gt;what the agent knows&lt;/em&gt; from &lt;em&gt;how the agent runs&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version control and governance
&lt;/h3&gt;

&lt;p&gt;Skills are plain text files. They live in your Git repository. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review changes in pull requests&lt;/li&gt;
&lt;li&gt;Track the history of every instruction change&lt;/li&gt;
&lt;li&gt;Roll back to a previous version if a new one underperforms&lt;/li&gt;
&lt;li&gt;Require approval before behavior changes go live&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters enormously in regulated industries (finance, healthcare, legal) where AI behavior must be auditable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Portability
&lt;/h3&gt;

&lt;p&gt;Agent Skills is an open standard adopted by a &lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;growing number of agent products&lt;/a&gt;, including OpenAI Codex (&lt;a href="https://developers.openai.com/codex/skills" rel="noopener noreferrer"&gt;docs&lt;/a&gt;), GitHub Copilot (&lt;a href="https://docs.github.com/en/copilot/concepts/agents/about-agent-skills" rel="noopener noreferrer"&gt;docs&lt;/a&gt;), VS Code (&lt;a href="https://code.visualstudio.com/docs/copilot/customization/agent-skills" rel="noopener noreferrer"&gt;docs&lt;/a&gt;), Cursor (&lt;a href="https://cursor.com/docs/context/skills" rel="noopener noreferrer"&gt;docs&lt;/a&gt;), Block's Goose, and LM-Kit.NET. A skill you write once works across all of them. No vendor lock-in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Team collaboration
&lt;/h3&gt;

&lt;p&gt;Because skills are Markdown, anyone can write or improve them. A domain expert (lawyer, compliance officer, product manager) can author a skill without touching code. Developers review and deploy it. This separates "what the AI should do" (domain knowledge) from "how the AI works" (infrastructure). Both teams contribute to what they know best.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Why Agent Skills Make Even More Sense for Local Inference
&lt;/h2&gt;

&lt;p&gt;Most of the discussion around Agent Skills focuses on cloud-hosted models: Claude, GPT-4, Gemini. But there is an argument to be made that skills become &lt;em&gt;even more&lt;/em&gt; valuable when you run models locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smaller models need more guidance
&lt;/h3&gt;

&lt;p&gt;Cloud models like GPT-4o or Claude Sonnet have been trained on enormous corpora and can often figure out a reasonable output format on their own. A 4B or 8B parameter model running on your GPU does not have the same capacity to guess your intent. It needs explicit instructions: what format to follow, what constraints to respect, what to include and what to skip. This is exactly what a well-written SKILL.md provides. Skills compensate for a smaller model's weaker instruction-following by giving it the specific, structured guidance it needs.&lt;/p&gt;

&lt;p&gt;In our own testing with LM-Kit.NET, the difference is striking. Ask a 4B model to "review this code" with no skill, and you get a generic response that varies every time. Activate a &lt;code&gt;code-review&lt;/code&gt; skill with a clear checklist and output template, and the same 4B model produces structured, consistent reviews. The skill effectively narrows the solution space, which is precisely what a smaller model needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context windows are tighter
&lt;/h3&gt;

&lt;p&gt;Cloud models now offer 128K to 1M token context windows. Local models typically run with 4K to 32K contexts, sometimes up to 128K but at a real performance cost (memory, speed). Every token matters more.&lt;/p&gt;

&lt;p&gt;This is where progressive disclosure goes from "nice optimization" to "architectural necessity." With a local model, you simply cannot afford to load all possible instructions at once. You need the skill system: load only metadata at startup (~50 tokens per skill), activate the relevant skill on demand (~500 to 2,000 tokens), keep the rest of the context free for the actual user data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Every token costs compute, not dollars
&lt;/h3&gt;

&lt;p&gt;With a cloud API, the cost of extra context tokens is measured in money. With local inference, it is measured in latency and memory. Stuffing a 5,000-token system prompt into every request to a local model directly impacts response time, especially on consumer hardware. Skills let you keep prompts lean for the common case and only expand them when the specific expertise is actually needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  No network dependency
&lt;/h3&gt;

&lt;p&gt;Skills are local files. The model is local. The entire skill activation pipeline (read file, inject into prompt, generate response) happens in-process with zero network calls. This makes the architecture simpler, faster, and fully offline-capable. For edge deployments, air-gapped environments, or embedded applications, this matters. You ship the model and the skills folder together, and the system works with no external dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Privacy and control
&lt;/h3&gt;

&lt;p&gt;When skills run locally, the instructions themselves never leave your machine. If you have a skill encoding proprietary compliance rules, internal procedures, or sensitive domain knowledge, that content stays in your process memory. It is never sent to a third-party API. This is a significant advantage for healthcare, finance, legal, defense, and any industry with data residency requirements.&lt;/p&gt;

&lt;p&gt;In short: skills make large cloud models more organized. They make small local models actually capable. The smaller the model, the more it benefits from well-structured skill instructions.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Before and After: What a Skill Actually Changes
&lt;/h2&gt;

&lt;p&gt;The concept is clearest with a concrete example. Here is the same 4B model, the same user question, with and without a skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without a skill&lt;/strong&gt; (bare prompt: "Review this function for issues"):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The function looks okay but you might want to add some error handling. Also the variable names could be more descriptive. Overall it seems fine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Generic, unstructured, inconsistent. Ask again tomorrow, you will get a different format and different level of detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With a &lt;code&gt;code-review&lt;/code&gt; skill active&lt;/strong&gt; (which defines a checklist, output format, and severity levels):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Code Review&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Line&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Unchecked null dereference on &lt;code&gt;user.Email&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;SQL string concatenation (injection risk)&lt;/td&gt;
&lt;td&gt;Critical&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Magic number &lt;code&gt;86400&lt;/code&gt; should be a named constant&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; 2 issues require fixing before merge. The SQL injection on line 18 is the priority.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Same model, same weights, same temperature. The only difference is 800 tokens of skill instructions loaded into the context. The skill provides the structure the model cannot invent on its own.&lt;/p&gt;

&lt;p&gt;This pattern applies across domains:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;What changes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customer support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;support-playbook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Agent follows a triage checklist instead of guessing what to ask&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Report generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;weekly-report&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output always has the same sections (summary, metrics, action items)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gdpr-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Agent checks a specific list of requirements instead of improvising&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Email writing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;email-writer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Produces subject line, greeting, body, sign-off in consistent format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-mode assistant&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multiple skills&lt;/td&gt;
&lt;td&gt;Same chatbot switches between explainer, analyst, and writer on command&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  9. Implementing Agent Skills with LM-Kit.NET
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/" rel="noopener noreferrer"&gt;LM-Kit.NET&lt;/a&gt; provides a complete, production-ready implementation of the Agent Skills specification. Let's build a working skill-based assistant from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.1 Create the Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new console &lt;span class="nt"&gt;-n&lt;/span&gt; SkillAssistant
&lt;span class="nb"&gt;cd &lt;/span&gt;SkillAssistant
dotnet add package LM-Kit.NET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.2 Create Your Skills
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;skills/&lt;/code&gt; directory with two skills:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;skills/explain/SKILL.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;explain&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Explains any topic in plain language. Type a word or phrase and get a clear, jargon-free explanation.&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Plain Language Explainer&lt;/span&gt;

You explain topics so anyone can understand them. The user gives you a word,
phrase, or concept. You explain it clearly.

&lt;span class="gu"&gt;## Output Format&lt;/span&gt;

&lt;span class="gu"&gt;## &amp;lt;Topic&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**In one sentence:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;simple&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;one-sentence&lt;/span&gt; &lt;span class="na"&gt;definition&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**How it works:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="na"&gt;-3&lt;/span&gt; &lt;span class="na"&gt;sentences&lt;/span&gt; &lt;span class="na"&gt;explaining&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;mechanism&lt;/span&gt; &lt;span class="na"&gt;or&lt;/span&gt; &lt;span class="na"&gt;idea&lt;/span&gt; &lt;span class="na"&gt;using&lt;/span&gt; &lt;span class="na"&gt;an&lt;/span&gt; &lt;span class="na"&gt;everyday&lt;/span&gt; &lt;span class="na"&gt;analogy&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**Why it matters:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="na"&gt;-2&lt;/span&gt; &lt;span class="na"&gt;sentences&lt;/span&gt; &lt;span class="na"&gt;on&lt;/span&gt; &lt;span class="na"&gt;why&lt;/span&gt; &lt;span class="na"&gt;someone&lt;/span&gt; &lt;span class="na"&gt;should&lt;/span&gt; &lt;span class="na"&gt;care&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**Example:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;one&lt;/span&gt; &lt;span class="na"&gt;concrete&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;real-world&lt;/span&gt; &lt;span class="na"&gt;example&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**No jargon.**&lt;/span&gt; If you must use a technical term, define it in parentheses.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Use analogies.**&lt;/span&gt; Compare unfamiliar concepts to everyday things.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Be concise.**&lt;/span&gt; The entire explanation fits on one screen.
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**Assume zero background knowledge.**&lt;/span&gt;
&lt;span class="p"&gt;5.&lt;/span&gt; Never say "it's complicated" or "it depends." Just explain it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;skills/email-writer/SKILL.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email-writer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Writes a professional email from a short description. Type what you need and get a ready-to-send email.&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Professional Email Writer&lt;/span&gt;

You write complete, professional emails from a short description. The user
types one line describing the situation. You produce a full email.

&lt;span class="gu"&gt;## Output Format&lt;/span&gt;

Subject: &lt;span class="nt"&gt;&amp;lt;concise&lt;/span&gt; &lt;span class="na"&gt;subject&lt;/span&gt; &lt;span class="na"&gt;line&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;greeting&amp;gt;&lt;/span&gt;,

&lt;span class="nt"&gt;&amp;lt;body:&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="na"&gt;-3&lt;/span&gt; &lt;span class="na"&gt;short&lt;/span&gt; &lt;span class="na"&gt;paragraphs&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;sign-off&amp;gt;&lt;/span&gt;,
[Your Name]

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Never ask for more details.**&lt;/span&gt; If information is missing, make reasonable assumptions.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Be concise.**&lt;/span&gt; No paragraph longer than 3 sentences.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Start with the purpose.**&lt;/span&gt; The first sentence states why the sender is writing.
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**End with a next step.**&lt;/span&gt; The last paragraph includes a specific action or timeline.
&lt;span class="p"&gt;5.&lt;/span&gt; &lt;span class="gs"&gt;**Use [Name] placeholders**&lt;/span&gt; for any names you do not know.
&lt;span class="p"&gt;6.&lt;/span&gt; &lt;span class="gs"&gt;**Default to professional tone.**&lt;/span&gt; No slang, no emojis, no exclamation marks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.3 Copy Skills to Output
&lt;/h3&gt;

&lt;p&gt;Add this to your &lt;code&gt;.csproj&lt;/code&gt; so the skills folder ships with your binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;None&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"skills\**\*"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CopyToOutputDirectory&amp;gt;&lt;/span&gt;PreserveNewest&lt;span class="nt"&gt;&amp;lt;/CopyToOutputDirectory&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Link&amp;gt;&lt;/span&gt;skills\%(RecursiveDir)%(Filename)%(Extension)&lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/None&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.4 Write the Application
&lt;/h3&gt;

&lt;p&gt;Here is a complete, minimal &lt;code&gt;Program.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.Agents.Skills&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.TextGeneration.Chat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.TextGeneration.Sampling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InputEncoding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutputEncoding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Step 1: Load all skills from the skills/ folder&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SkillRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SkillActivator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;skillsPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skillsPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skillsPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"  Warning: could not load &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFileName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Loaded &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; skill(s).\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Step 2: Load a model&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Loading model..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gemma3:4b"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 3: Set up conversation&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MultiTurnConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaximumCompletionTokens&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SamplingMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RandomSampling&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Temperature&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.7f&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Stream tokens to the console as they are generated.&lt;/span&gt;
&lt;span class="c1"&gt;// LM-Kit.NET fires this event for each chunk of text the model produces,&lt;/span&gt;
&lt;span class="c1"&gt;// so the user sees output appear word by word instead of waiting for the full response.&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AfterTextCompletion&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;AgentSkill&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;activeSkill&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Step 4: Show available skills&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Available skills:"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skill&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Skills&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"  /&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  /off - Deactivate the current skill\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 5: Chat loop&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nYou: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Handle slash commands&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"/off"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;activeSkill&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Skill deactivated."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryParseSlashCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;activeSkill&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Skill activated: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unknown command."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Build the prompt: inject skill instructions when one is active&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activeSkill&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;activator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FormatForInjection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;activeSkill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;SkillInjectionMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\n\n---\n\nUser request: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Submit and stream the response&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nAssistant: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.5 Run It
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical session looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Loaded 2 skill(s).

Available skills:
  /explain - Explains any topic in plain language.
  /email-writer - Writes a professional email from a short description.
  /off - Deactivate the current skill

You: /explain
Skill activated: explain

You: blockchain

Assistant:

## Blockchain

**In one sentence:** A blockchain is a shared digital ledger where every
entry is verified by a network of computers instead of a single authority.

**How it works:** Imagine a notebook that thousands of people hold copies of.
Whenever someone writes a new line, everyone checks it matches and updates
their copy. Because no single person controls the notebook, nobody can
secretly alter past entries.

**Why it matters:** It enables trust between strangers without a middleman,
which is useful for sending money, proving ownership, and recording agreements.

**Example:** Bitcoin uses a blockchain to track who owns which coins, so two
people anywhere in the world can exchange value without a bank in between.

You: /email-writer
Skill activated: email-writer

You: thank a vendor for fast delivery

Assistant:

Subject: Thank You for the Quick Delivery

Dear [Name],

I am writing to thank you for the prompt delivery of our recent order. The
shipment arrived ahead of schedule, which allowed our team to stay on track
with our project timeline.

We appreciate the care taken in packaging and the clear communication
throughout the process. This level of service reinforces our confidence in
your team.

We look forward to continuing our partnership. Please let us know if there
is anything we can do to support future orders.

Best regards,
[Your Name]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the same model produces completely different output formats depending on which skill is active. Without any code change, just by switching the active skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.6 What Just Happened (Under the Hood)
&lt;/h3&gt;

&lt;p&gt;Here is the flow for each user message when a skill is active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User types: "blockchain"

2. SkillActivator.FormatForInjection() reads the full SKILL.md
   and formats it for injection

3. The prompt becomes:
   "[skill instructions]\n\n---\n\nUser request: blockchain"

4. MultiTurnConversation.Submit() sends this to the model

5. The model follows the skill's output format and rules

6. Result: structured, consistent output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill instructions are injected as a user message (via &lt;code&gt;SkillInjectionMode.UserMessage&lt;/code&gt;). LM-Kit.NET also supports &lt;code&gt;SystemPrompt&lt;/code&gt; (prepend to system prompt) and &lt;code&gt;ToolResult&lt;/code&gt; (return as tool output) injection modes.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Production Features in LM-Kit.NET
&lt;/h2&gt;

&lt;p&gt;The tutorial above covers the core workflow. LM-Kit.NET provides several additional capabilities for production deployments. This section gives a brief overview of each; see the &lt;a href="https://docs.lm-kit.com/lm-kit-net/" rel="noopener noreferrer"&gt;full API documentation&lt;/a&gt; for details and code samples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatic skill matching.&lt;/strong&gt; Instead of explicit slash commands, &lt;code&gt;SkillRegistry&lt;/code&gt; can match a user's natural-language request to the best skill using keyword scoring or embedding-based semantic search via &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Skills.SkillRegistry.html" rel="noopener noreferrer"&gt;&lt;code&gt;FindMatches&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;FindMatchesWithEmbeddings&lt;/code&gt;. This lets you build assistants that route to the right skill automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remote skill loading.&lt;/strong&gt; Skills do not have to live on the local file system. &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Skills.SkillRegistry.LoadFromUrlAsync.html" rel="noopener noreferrer"&gt;&lt;code&gt;SkillRegistry.LoadFromUrlAsync&lt;/code&gt;&lt;/a&gt; fetches skills from URLs, ZIP archives, or GitHub repositories. This enables enterprise distribution: host a skill library centrally and have agents pull the latest versions at startup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hot reload.&lt;/strong&gt; During development, &lt;code&gt;SkillWatcher&lt;/code&gt; monitors the skills directory and automatically reloads any SKILL.md that changes. Edit the file, save, and the agent picks up the new instructions without restarting. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;watcher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SkillWatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skillsPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Edit any SKILL.md and the registry updates automatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Programmatic skill creation.&lt;/strong&gt; &lt;code&gt;SkillBuilder&lt;/code&gt; provides a fluent API for constructing skills in code rather than from files. This is useful when skill content comes from a database, a UI, or is generated dynamically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills as tools.&lt;/strong&gt; &lt;code&gt;SkillTool&lt;/code&gt; wraps the skill registry as an &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Tools.ITool.html" rel="noopener noreferrer"&gt;&lt;code&gt;ITool&lt;/code&gt;&lt;/a&gt;, letting the model decide which skill to activate through the function calling interface. Register it with an &lt;code&gt;Agent&lt;/code&gt; and the model can self-select skills based on the conversation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validation.&lt;/strong&gt; &lt;code&gt;SkillRegistry.ValidateAll()&lt;/code&gt; checks all loaded skills against the spec (name format, required fields, directory structure). Run this in CI to catch errors before deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  LM-Kit.NET Agent Skills API at a Glance
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Skills.AgentSkill.html" rel="noopener noreferrer"&gt;&lt;code&gt;AgentSkill&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;A loaded skill: name, description, instructions, resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Skills.SkillRegistry.html" rel="noopener noreferrer"&gt;&lt;code&gt;SkillRegistry&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Discovers, loads, stores, and searches skills&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Skills.SkillActivator.html" rel="noopener noreferrer"&gt;&lt;code&gt;SkillActivator&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Formats skill instructions for injection into conversations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillParser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reads and parses SKILL.md files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillBuilder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fluent API for creating skills in code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillTool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exposes skills as tools for LLM function calling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillWatcher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Monitors files and hot-reloads on change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillRemoteLoader&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetches skills from URLs, ZIPs, and GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Enum&lt;/th&gt;
&lt;th&gt;Values&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillInjectionMode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SystemPrompt&lt;/code&gt;, &lt;code&gt;UserMessage&lt;/code&gt;, &lt;code&gt;ToolResult&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillResourceType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Reference&lt;/code&gt;, &lt;code&gt;Script&lt;/code&gt;, &lt;code&gt;Asset&lt;/code&gt;, &lt;code&gt;Example&lt;/code&gt;, &lt;code&gt;Other&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the full API reference with all classes, methods, and examples, see &lt;a href="https://docs.lm-kit.com/lm-kit-net/" rel="noopener noreferrer"&gt;docs.lm-kit.com&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Best Practices for Writing Great Skills
&lt;/h2&gt;

&lt;p&gt;Writing a SKILL.md is easy. Writing a &lt;em&gt;good&lt;/em&gt; one takes craft. Here are guidelines based on what works in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Naming
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use lowercase with hyphens: &lt;code&gt;code-review&lt;/code&gt;, &lt;code&gt;email-writer&lt;/code&gt;, &lt;code&gt;weekly-report&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Keep it short and descriptive (max 64 characters)&lt;/li&gt;
&lt;li&gt;Avoid generic names like &lt;code&gt;helper&lt;/code&gt; or &lt;code&gt;assistant&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Write it as a one-sentence action statement: "Reviews code for bugs, security issues, and style violations"&lt;/li&gt;
&lt;li&gt;Include keywords that help with automatic matching&lt;/li&gt;
&lt;li&gt;Keep it under 1024 characters&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Instructions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Put the most important constraints first.&lt;/strong&gt; LLMs pay more attention to the beginning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specify the exact output format.&lt;/strong&gt; Show a template with placeholders. The more specific, the more consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write explicit rules.&lt;/strong&gt; Number them. State what the model should and should not do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include at least one example.&lt;/strong&gt; Show a sample input and the expected output. This is the single most effective technique for consistent behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it concise.&lt;/strong&gt; Move lengthy reference material to &lt;code&gt;references/&lt;/code&gt; and load it on demand. The instructions themselves should fit in ~500 to 2,000 tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Structure Template
&lt;/h3&gt;

&lt;p&gt;Every SKILL.md should follow this pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-skill-name&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;One sentence explaining when to use this skill.&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Role Title&lt;/span&gt;

One paragraph defining the agent's role and what it does.

&lt;span class="gu"&gt;## Output Format&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;exact&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt; &lt;span class="na"&gt;with&lt;/span&gt; &lt;span class="na"&gt;placeholders&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Rule one.**&lt;/span&gt; Short explanation.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Rule two.**&lt;/span&gt; Short explanation.
&lt;span class="p"&gt;3.&lt;/span&gt; ...

&lt;span class="gu"&gt;## Example&lt;/span&gt;

&lt;span class="gs"&gt;**Input:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;sample&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gs"&gt;**Output:**&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;sample&lt;/span&gt; &lt;span class="na"&gt;output&lt;/span&gt; &lt;span class="na"&gt;following&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt; &lt;span class="na"&gt;above&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Skill Authoring Checklist
&lt;/h3&gt;

&lt;p&gt;Before shipping a skill, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Name is lowercase, hyphenated, and descriptive&lt;/li&gt;
&lt;li&gt;[ ] Description clearly states when to use the skill&lt;/li&gt;
&lt;li&gt;[ ] Version is set (start with &lt;code&gt;1.0.0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Output format is explicitly defined with a template&lt;/li&gt;
&lt;li&gt;[ ] At least 3 clear rules constrain behavior&lt;/li&gt;
&lt;li&gt;[ ] At least 1 example input/output is included&lt;/li&gt;
&lt;li&gt;[ ] Instructions fit within ~2,000 tokens (move long references to &lt;code&gt;references/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Skill validates without errors (&lt;code&gt;AgentSkill.Validate()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Tested with at least 2 different models&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  12. Security Considerations
&lt;/h2&gt;

&lt;p&gt;Agent Skills are powerful, and that power requires care. Cisco's AI Defense team &lt;a href="https://blogs.cisco.com/ai/personal-ai-agents-like-openclaw-are-a-security-nightmare" rel="noopener noreferrer"&gt;found&lt;/a&gt; that a significant number of publicly shared skills contained vulnerabilities, including prompt injection and credential exfiltration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best practices for skill security:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Review all skills before deployment.&lt;/strong&gt; Treat SKILL.md files like code: review them in pull requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be cautious with &lt;code&gt;scripts/&lt;/code&gt;.&lt;/strong&gt; Scripts execute on the host machine. Only include scripts from trusted sources. Consider sandboxing execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the &lt;code&gt;allowed-tools&lt;/code&gt; field.&lt;/strong&gt; Explicitly declare which system tools a skill can invoke. This helps runtime environments enforce boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never put secrets in skills.&lt;/strong&gt; No API keys, passwords, or tokens in SKILL.md files or their resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate inputs.&lt;/strong&gt; If a skill processes user-provided data, ensure your agent validates that data before acting on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin versions.&lt;/strong&gt; When loading remote skills, pin to specific versions or commit hashes rather than tracking &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  13. Industry Adoption
&lt;/h2&gt;

&lt;p&gt;Agent Skills is not a theoretical standard. It has been adopted by the major players in the AI ecosystem:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;How It Uses Agent Skills&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAI Codex&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reads skills from &lt;code&gt;.agents/skills&lt;/code&gt; directories (&lt;a href="https://developers.openai.com/codex/skills" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Loads skills from &lt;code&gt;.github/skills/&lt;/code&gt; in repositories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VS Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native agent skills support in Copilot (&lt;a href="https://code.visualstudio.com/docs/copilot/customization/agent-skills" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports SKILL.md for workspace-level agent customization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Block (Goose)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open-source agent with full skills support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LM-Kit.NET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complete implementation with registry, activator, hot reload, remote loading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spring AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Java/Spring implementation (&lt;a href="https://spring.io/blog/2026/01/13/spring-ai-generic-agent-skills/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mintlify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-generates skills from documentation sites (&lt;a href="https://www.mintlify.com/blog/skill-md" rel="noopener noreferrer"&gt;blog&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The standard was developed by Anthropic and published as open source. The broader agentic AI ecosystem, including related standards like MCP and AGENTS.md, is coordinated through the &lt;a href="https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation" rel="noopener noreferrer"&gt;Agentic AI Foundation&lt;/a&gt; under the Linux Foundation, whose platinum members include AWS, Anthropic, Block, Google, Microsoft, and OpenAI.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Conclusion
&lt;/h2&gt;

&lt;p&gt;Agent Skills solve a real, specific problem: how to give AI agents specialized, reusable expertise without overwhelming their context windows. The solution is elegant in its simplicity. A skill is a Markdown file in a folder. The agent loads it on demand. The output becomes consistent.&lt;/p&gt;

&lt;p&gt;Here is what to remember:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A skill is a folder with a SKILL.md file.&lt;/strong&gt; YAML frontmatter for metadata, Markdown body for instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive disclosure keeps context efficient.&lt;/strong&gt; Metadata at startup, instructions on activation, resources on execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills are not tools, not prompts, not agents.&lt;/strong&gt; They are portable knowledge modules that complement all three.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The standard is open and widely adopted.&lt;/strong&gt; OpenAI, Microsoft, Anthropic, and a growing number of platforms support it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LM-Kit.NET provides a complete implementation.&lt;/strong&gt; Registry, activator, hot reload, remote loading, validation, tool integration.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try the demo:&lt;/strong&gt; &lt;a href="https://github.com/LM-Kit/lm-kit-net-samples/tree/main/console_net/agents/skill_based_assistant" rel="noopener noreferrer"&gt;Skill-Based Assistant on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the how-to guide:&lt;/strong&gt; &lt;a href="https://docs.lm-kit.com/lm-kit-net/guides/how-to/add-skills-to-assistant.html" rel="noopener noreferrer"&gt;Add Skills to Your AI Assistant&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install LM-Kit.NET:&lt;/strong&gt; &lt;a href="https://www.nuget.org/packages/LM-Kit.NET" rel="noopener noreferrer"&gt;NuGet package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the specification:&lt;/strong&gt; &lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;agentskills.io/specification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore the API docs:&lt;/strong&gt; &lt;a href="https://docs.lm-kit.com/lm-kit-net/" rel="noopener noreferrer"&gt;docs.lm-kit.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with one skill. Get it working. Then build a library your whole team can reuse.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;Agent Skills Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://claude.com/blog/skills-explained" rel="noopener noreferrer"&gt;Claude Blog: Skills Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/codex/skills" rel="noopener noreferrer"&gt;OpenAI Codex Skills Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/copilot/customization/agent-skills" rel="noopener noreferrer"&gt;VS Code Agent Skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://block.github.io/goose/blog/2025/12/22/agent-skills-vs-mcp/" rel="noopener noreferrer"&gt;Goose Blog: "Did Skills Kill MCP?"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.llamaindex.ai/blog/skills-vs-mcp-tools-for-agents-when-to-use-what" rel="noopener noreferrer"&gt;LlamaIndex: Skills vs MCP Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thenewstack.io/agent-skills-anthropics-next-bid-to-define-ai-standards/" rel="noopener noreferrer"&gt;The New Stack: Agent Skills Analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2025/Dec/19/agent-skills/" rel="noopener noreferrer"&gt;Simon Willison on Agent Skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/blog/2026/01/13/spring-ai-generic-agent-skills/" rel="noopener noreferrer"&gt;Spring AI: Agent Skills in Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.cisco.com/ai/personal-ai-agents-like-openclaw-are-a-security-nightmare" rel="noopener noreferrer"&gt;Cisco: Agent Skills Security Research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/" rel="noopener noreferrer"&gt;LM-Kit.NET Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/guides/glossary/agent-skills.html" rel="noopener noreferrer"&gt;LM-Kit.NET Agent Skills Glossary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/LM-Kit/lm-kit-net-samples" rel="noopener noreferrer"&gt;LM-Kit.NET Samples Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🧰 Meet LM-Kit Tool Calling for Local Agents</title>
      <dc:creator>Loïc Carrère</dc:creator>
      <pubDate>Fri, 17 Oct 2025 11:14:01 +0000</pubDate>
      <link>https://forem.com/loc_carrre_0d798813c662/meet-lm-kit-tool-calling-for-local-agents-1ae9</link>
      <guid>https://forem.com/loc_carrre_0d798813c662/meet-lm-kit-tool-calling-for-local-agents-1ae9</guid>
      <description>&lt;h2&gt;
  
  
  LM-Kit Tool Calling: Build Reliable Local AI Agents
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; LM-Kit .NET SDK now supports state-of-the-art tool calling for building AI agents in C#. Create on-device agents that discover, invoke, and chain tools with structured JSON schemas, safety policies, and human-in-the-loop controls, all running locally with full privacy. Works with thousands of local models from Mistral, LLaMA, Qwen, Granite, GPT-OSS, and more. Supports all tool calling modes: simple function, multiple function, parallel function, and parallel multiple function. No cloud dependencies, no API costs, complete control over your agent workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Tools in Agentic AI?
&lt;/h2&gt;

&lt;p&gt;Tools are a fundamental part of agentic AI, alongside these core capabilities:&lt;/p&gt;

&lt;p&gt;While language models excel at understanding and generating text, tools extend their abilities by letting them interact with the real world: searching the web for current information, executing code for calculations, accessing databases, reading files, or connecting to external services through APIs. Think of tools as the hands and eyes of an AI agent. They transform a conversational system into an agent that can accomplish tasks by bridging the gap between reasoning and action. When an agent needs to check the weather, analyze a spreadsheet, or send an email, it invokes the appropriate tool, receives the result, and incorporates that information into its response. This moves AI beyond pure text generation toward practical, real-world problem solving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interested in how agents retain and use context over time?&lt;/strong&gt; Explore our deep dive on &lt;a href="https://lm-kit.com/blog/introducing-agent-memory/" rel="noopener noreferrer"&gt;agent memory&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Local Agents Have Been Hard
&lt;/h2&gt;

&lt;p&gt;Building AI agents that can actually do things locally has been surprisingly hard. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Models that understand when and how to call external functions&lt;/li&gt;
&lt;li&gt;Privacy without sending data to the cloud&lt;/li&gt;
&lt;li&gt;A runtime that can parse tool calls, validate arguments, and inject results&lt;/li&gt;
&lt;li&gt;Model-specific flows because each model has different tool calling formats and interaction patterns, requiring custom logic for interception, result injection, and action ordering&lt;/li&gt;
&lt;li&gt;Safety controls to prevent infinite loops and runaway costs&lt;/li&gt;
&lt;li&gt;Clear observability so you know what your agent is doing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Until now, most agentic frameworks forced a choice: powerful cloud-based agents with latency and privacy concerns, or limited local models without proper tool support. Today, that changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Tool Calling Changes Everything
&lt;/h2&gt;

&lt;p&gt;With LM-Kit's new tool calling capabilities, your local agents can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ground answers in real data.&lt;/strong&gt; No more hallucinated weather forecasts or exchange rates. Agents fetch actual API responses and can cite sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chain complex workflows.&lt;/strong&gt; For example: check the weather, convert temperature to the user's preferred units, then suggest activities. All in one conversational turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintain full privacy.&lt;/strong&gt; Everything runs on-device. Your users' queries, tool arguments, and results never leave their machines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stay deterministic and safe.&lt;/strong&gt; Typed schemas, validated inputs, policy controls, and approval hooks prevent agents from going rogue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale with your domain.&lt;/strong&gt; Add business APIs, internal databases, or external &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Mcp.Client.McpClient.html" rel="noopener noreferrer"&gt;MCP catalogs&lt;/a&gt; as tools. The model learns to use them from descriptions and schemas alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbol6tmvlf78vslidygag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbol6tmvlf78vslidygag.png" alt="Tabbycat empowered with Tools" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's New at a Glance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State-of-the-art tool calling&lt;/strong&gt;, right in chatbot flows. Models decide when to call tools, pass structured JSON args, and use results to answer users accurately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated flow support&lt;/strong&gt; across model families like Mistral, GPT-OSS, Qwen, Granite, LLaMA, and more — all via one runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three ways to add tools:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Implement &lt;code&gt;ITool&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Annotate methods with &lt;code&gt;[LMFunction]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Import catalogs from &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Mcp.Client.McpClient.html" rel="noopener noreferrer"&gt;MCP servers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Unified API&lt;/strong&gt; that runs local SLMs with per-turn policy, guardrails, and events for human-in-the-loop and observability at every stage.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;All function calling modes supported.&lt;/strong&gt; Simple Function, Multiple Function, Parallel Function, and Parallel Multiple Function — choose strict sequencing or safe parallelism.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Model-aware tool call flow.&lt;/strong&gt; Modern SLMs emit structured tool calls. LM-Kit parses calls, routes them to your tools, and feeds results back with correlation and clear result types for a reliable inference path.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works: Getting Started
&lt;/h2&gt;

&lt;p&gt;Here's a complete working example in under 20 lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.TextGeneration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.Agents.Tools&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text.Json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1) Load a local model from the catalog&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gptoss:20b"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// OpenAI GPT-OSS 20B&lt;/span&gt;

&lt;span class="c1"&gt;// Optional: confirm tool-calling capability&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasToolCalls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* choose a different model or fallback */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 2) Create a multi-turn conversation&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MultiTurnConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3) Register tools (see three options below)&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WeatherTool&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// 4) Shape the behavior per turn&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Choice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ToolChoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// let the model decide&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxCallsPerTurn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// guard against loops&lt;/span&gt;

&lt;span class="c1"&gt;// 5) Ask a question&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Plan my weekend and check the weather in Toulouse."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model catalog includes GPT-OSS and many other families. &lt;code&gt;LM.LoadFromModelID&lt;/code&gt; lets you pull a named card like &lt;code&gt;gptoss:20b&lt;/code&gt;. You can also check &lt;code&gt;HasToolCalls&lt;/code&gt; before you rely on tools.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://docs.lm-kit.com/lm-kit-net/guides/getting-started/model-catalog.html" rel="noopener noreferrer"&gt;Model Catalog documentation&lt;/a&gt; for details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it now — GitHub sample
&lt;/h3&gt;

&lt;p&gt;A production-ready console sample demonstrates multi-turn chat with tool calling (currency, weather, unit conversion), per-turn policies, progress feedback, and special commands. Jump to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/LM-Kit/lm-kit-net-samples/tree/main/console_net/multi_turn_chat_with_tools" rel="noopener noreferrer"&gt;Create Multi-Turn Chatbot with Tools in .NET Applications&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Ways to Add Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Implement ITool (Full Control)
&lt;/h3&gt;

&lt;p&gt;Best when you need clear contracts and custom validation.&lt;/p&gt;

&lt;p&gt;This snippet demonstrates implementing the &lt;code&gt;ITool&lt;/code&gt; interface so an LLM can call your tool directly. It declares the tool contract (&lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt;, &lt;code&gt;InputSchema&lt;/code&gt;), parses JSON args, runs your logic, and returns structured JSON to the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeatherTool&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ITool&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Get current weather for a city. Returns temperature, conditions, and optional hourly forecast."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// JSON Schema defines expected arguments&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;InputSchema&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"""
&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"City name (e.g., 'Paris' or 'New York')"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s"&gt;""";
&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;InvokeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Parse the model's JSON arguments&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;RootElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Call your weather API&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;weatherData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;FetchWeatherAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Return structured JSON the model can understand&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp_c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weatherData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conditions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weatherData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conditions&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register it&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WeatherTool&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why use ITool?&lt;/strong&gt; Complete control over validation, async execution, error handling, and result formatting.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Annotate Methods with &lt;a href="https://dev.toQuick%20Binding"&gt;LMFunction&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Best for rapid prototyping and simple synchronous tools.&lt;/p&gt;

&lt;p&gt;What it does: Add &lt;code&gt;[LMFunction(name, description)]&lt;/code&gt; to public instance methods. LM-Kit discovers them and exposes each as an &lt;code&gt;ITool&lt;/code&gt;, generating a JSON schema from method parameters.&lt;/p&gt;

&lt;p&gt;How it's wired: Reflect and bind with &lt;code&gt;LMFunctionToolBinder.FromType&amp;lt;MyDomainTools&amp;gt;()&lt;/code&gt; (or &lt;code&gt;FromInstance&lt;/code&gt;/&lt;code&gt;FromAssembly&lt;/code&gt;), then register the resulting tools via &lt;code&gt;chat.Tools.Register(...)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDomainTools&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;LMFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"search_docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Search internal documentation by keyword. Returns top 5 matches."&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;SearchDocs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_documentIndex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;LMFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get_user_info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Retrieve user profile and preferences."&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetUserInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Automatically scan and register all annotated methods&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LMFunctionToolBinder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDomainTools&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why use [LMFunction]?&lt;/strong&gt; Less boilerplate. The &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Tools.LMFunctionToolBinder.html" rel="noopener noreferrer"&gt;binder&lt;/a&gt; generates schemas from parameter types and registers everything in one line.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Import MCP Catalogs (External Services)
&lt;/h3&gt;

&lt;p&gt;Best for connecting to third-party tool ecosystems via the Model Context Protocol.&lt;/p&gt;

&lt;p&gt;What it does: Uses &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Mcp.Client.McpClient.html" rel="noopener noreferrer"&gt;McpClient&lt;/a&gt; to establish a JSON-RPC session with an MCP server, fetch its tool catalog, and adapt those tools so your agent can call them.&lt;/p&gt;

&lt;p&gt;How it's wired: Create &lt;code&gt;new McpClient(uri, httpClient)&lt;/code&gt; (optionally set a bearer token), then &lt;code&gt;chat.Tools.Register(mcp, overwrite: false)&lt;/code&gt; to import the catalog; LM-Kit manages &lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;tools/call&lt;/code&gt;, retries, and session persistence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;LMKit.Mcp.Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to an MCP server&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;McpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://mcp.example.com/api"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Import all available tools from the server&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;toolCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Imported &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;toolCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tools from MCP server"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why use MCP?&lt;/strong&gt; Instant access to curated tool catalogs. The server handles &lt;code&gt;tools/list&lt;/code&gt; and &lt;code&gt;tools/call&lt;/code&gt; over JSON-RPC; LM-Kit validates schemas locally.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Mcp.Client.McpClient.html" rel="noopener noreferrer"&gt;McpClient documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execution Modes That Match Your Workflow
&lt;/h2&gt;

&lt;p&gt;Choose the right policy for each conversational turn:&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Function
&lt;/h3&gt;

&lt;p&gt;One tool, one answer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxCallsPerTurn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Choice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ToolChoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Required&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// force at least one call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "What is the weather in Tokyo?" → calls &lt;code&gt;get_weather&lt;/code&gt; once → answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Function
&lt;/h3&gt;

&lt;p&gt;Chain tools sequentially.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxCallsPerTurn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Choice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ToolChoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "Convert 75°F to Celsius, then tell me if I need a jacket."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;convert_temperature(75, "F", "C")&lt;/code&gt; → gets 23.9°C&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;get_weather("current_location")&lt;/code&gt; → gets conditions&lt;/li&gt;
&lt;li&gt;Synthesizes answer → "It is 24°C and sunny. A light jacket should be fine."&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Parallel Function
&lt;/h3&gt;

&lt;p&gt;Execute multiple tools concurrently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowParallelCalls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxCallsPerTurn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "Compare weather in Paris, London, and Berlin."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calls &lt;code&gt;get_weather("Paris")&lt;/code&gt;, &lt;code&gt;get_weather("London")&lt;/code&gt;, &lt;code&gt;get_weather("Berlin")&lt;/code&gt; simultaneously&lt;/li&gt;
&lt;li&gt;Waits for all results → compares → answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only enable if your tools are idempotent and thread-safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel Multiple Function
&lt;/h3&gt;

&lt;p&gt;Combine chaining and parallelism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "Check weather in 3 cities, convert all temps to Fahrenheit, and recommend which to visit."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parallel → fetches weather for 3 cities&lt;/li&gt;
&lt;li&gt;Parallel → converts all temperatures&lt;/li&gt;
&lt;li&gt;Sequential → recommends based on results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Tools.ToolCallPolicy.html" rel="noopener noreferrer"&gt;ToolCallPolicy documentation&lt;/a&gt; for all options including &lt;code&gt;ToolChoice.Specific&lt;/code&gt; and &lt;code&gt;ForcedToolName&lt;/code&gt;. Defaults are conservative: parallel off, max calls capped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety, Control, and Observability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Policy Controls
&lt;/h3&gt;

&lt;p&gt;Configure safe defaults and per-turn limits. See &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Agents.Tools.ToolCallPolicy.html" rel="noopener noreferrer"&gt;ToolCallPolicy documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ToolCallPolicy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Choice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ToolChoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// let model decide&lt;/span&gt;
    &lt;span class="n"&gt;MaxCallsPerTurn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// prevent runaway loops&lt;/span&gt;
    &lt;span class="n"&gt;AllowParallelCalls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// safe default: sequential only&lt;/span&gt;

    &lt;span class="c1"&gt;// Optional: force a specific tool first&lt;/span&gt;
    &lt;span class="c1"&gt;// Choice = ToolChoice.Specific,&lt;/span&gt;
    &lt;span class="c1"&gt;// ForcedToolName = "authenticate_user"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Human in the Loop
&lt;/h3&gt;

&lt;p&gt;Review, approve, or block tool execution. Hooks: &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.TextGeneration.MultiTurnConversation.BeforeToolInvocation.html" rel="noopener noreferrer"&gt;BeforeToolInvocation&lt;/a&gt;, &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.TextGeneration.MultiTurnConversation.AfterToolInvocation.html" rel="noopener noreferrer"&gt;AfterToolInvocation&lt;/a&gt;, &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.TextGeneration.MultiTurnConversation.BeforeTokenSampling.html" rel="noopener noreferrer"&gt;BeforeTokenSampling&lt;/a&gt;, &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.TextGeneration.MultiTurnConversation.MemoryRecall.html" rel="noopener noreferrer"&gt;MemoryRecall&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Approve tool calls before execution&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeforeToolInvocation&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"🔔 About to call: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"   Arguments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentsJson&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Block sensitive operations&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"delete_user"&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;UserHasApproved&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cancel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"   ❌ Blocked by policy"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Audit results after execution&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AfterToolInvocation&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolCallResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"✅ &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; completed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"   Status: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"   Result: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResultJson&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;_telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogToolCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// send to monitoring&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Override token sampling in real time&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeforeTokenSampling&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_needsDeterministicOutput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sampling&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Temperature&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.1f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Control memory injection&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MemoryRecall&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"💭 Injecting memory: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// e.Cancel = true; // optionally cancel&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Structured Data Flow
&lt;/h3&gt;

&lt;p&gt;Every call flows through a typed pipeline for reproducibility and clear logs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;→ Incoming:&lt;/strong&gt; &lt;code&gt;ToolCall&lt;/code&gt; with stable &lt;code&gt;Id&lt;/code&gt; and &lt;code&gt;ArgumentsJson&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;← Outgoing:&lt;/strong&gt; &lt;code&gt;ToolCallResult&lt;/code&gt; with &lt;code&gt;ToolCallId&lt;/code&gt;, &lt;code&gt;ToolName&lt;/code&gt;, &lt;code&gt;ResultJson&lt;/code&gt;, and &lt;code&gt;Type&lt;/code&gt; (Success or Error).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It: Multi-Turn Chat Sample
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create Multi-Turn Chatbot with Tools in .NET Applications
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Demonstrates LM-Kit.NET's agentic tool-calling: during a conversation, the model can decide to call one or multiple tools to fetch data or run computations, pass JSON arguments that match each tool's &lt;code&gt;InputSchema&lt;/code&gt;, and use each tool's JSON result to produce a grounded reply—while preserving full multi-turn context. Tools implement &lt;code&gt;ITool&lt;/code&gt; and are managed by a registry; per-turn behavior is shaped via &lt;code&gt;ToolChoice&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why tools in chatbots?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reliable, source-backed answers (weather, FX, conversions, business APIs).&lt;/li&gt;
&lt;li&gt;Agentic chaining: call several tools in one turn and combine results.&lt;/li&gt;
&lt;li&gt;Determinism &amp;amp; safety: typed schemas, clear failure modes, policy control.&lt;/li&gt;
&lt;li&gt;Extensibility: implement &lt;code&gt;ITool&lt;/code&gt; for domain logic; keep code auditable.&lt;/li&gt;
&lt;li&gt;Efficiency: offload math/lookup to tools; keep the model focused on reasoning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Target audience:&lt;/strong&gt; Product &amp;amp; platform teams; DevOps &amp;amp; internal tools; B2B apps; educators &amp;amp; demos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem solved:&lt;/strong&gt; Actionable answers, deterministic conversions/quotes, multi-turn memory, easy extensibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lets you choose a local model (or a custom URI)&lt;/li&gt;
&lt;li&gt;Registers three tools (currency, weather, unit conversion)&lt;/li&gt;
&lt;li&gt;Runs a multi-turn chat where the model decides when to call tools&lt;/li&gt;
&lt;li&gt;Prints generation stats (tokens, stop reason, speed, context usage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tool calling via JSON arguments&lt;/li&gt;
&lt;li&gt;Full dialogue memory&lt;/li&gt;
&lt;li&gt;Progress feedback (download/load bars)&lt;/li&gt;
&lt;li&gt;Special commands: &lt;code&gt;/reset&lt;/code&gt;, &lt;code&gt;/continue&lt;/code&gt;, &lt;code&gt;/regenerate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Multiple tool calls per turn (and across turns)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Built-in Tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool name&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Online?&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;convert_currency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ECB rates via Frankfurter (latest or historical) + optional trend&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No API key; business days; rounding &amp;amp; date support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_weather&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open-Meteo current weather + optional short hourly forecast&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No API key; geocoding + metric/us/si&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;convert_units&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Offline conversions (length, mass, temperature, speed, etc.)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Temperature is non-linear; can list supported units&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tools implement &lt;code&gt;ITool&lt;/code&gt;: &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt;, &lt;code&gt;InputSchema&lt;/code&gt; (JSON Schema), and &lt;code&gt;InvokeAsync(string json)&lt;/code&gt; returning JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extend with your own tool:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MyCustomTool&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// implements ITool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use unique, stable, lowercase &lt;code&gt;snake_case&lt;/code&gt; names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supported Models (Pick per Hardware)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mistral Nemo 2407 12.2B (~7.7 GB VRAM)&lt;/li&gt;
&lt;li&gt;Meta Llama 3.1 8B (~6 GB VRAM)&lt;/li&gt;
&lt;li&gt;Google Gemma 3 4B Medium (~4 GB VRAM)&lt;/li&gt;
&lt;li&gt;Microsoft Phi-4 Mini 3.82B (~3.3 GB VRAM)&lt;/li&gt;
&lt;li&gt;Alibaba Qwen-3 8B (~5.6 GB VRAM)&lt;/li&gt;
&lt;li&gt;Microsoft Phi-4 14.7B (~11 GB VRAM)&lt;/li&gt;
&lt;li&gt;IBM Granite 4 7B (~6 GB VRAM)&lt;/li&gt;
&lt;li&gt;Open-AI GPT-OSS 20B (~16 GB VRAM)&lt;/li&gt;
&lt;li&gt;Or provide a custom model URI (GGUF/LMK)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/reset&lt;/code&gt; — clear conversation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/continue&lt;/code&gt; — continue last assistant message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/regenerate&lt;/code&gt; — new answer for last user input&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Prompts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"Convert 125 USD to EUR and show a 7-day trend."&lt;/li&gt;
&lt;li&gt;"Weather in Toulouse next 6 hours (metric)."&lt;/li&gt;
&lt;li&gt;"Convert 65 mph to km/h." / "List pressure units."&lt;/li&gt;
&lt;li&gt;"Now 75 °F to °C, then 2 km to miles."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Behavior &amp;amp; Policies (Quick Reference)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool selection policy:&lt;/strong&gt; By default the sample lets the model decide (&lt;code&gt;ToolChoice.Auto&lt;/code&gt;). You can Require / Forbid / Force a specific tool per turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple tool calls:&lt;/strong&gt; Supports several tool invocations per turn; outputs are injected back into context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schemas matter:&lt;/strong&gt; Precise &lt;code&gt;InputSchema&lt;/code&gt; + concise &lt;code&gt;Description&lt;/code&gt; improve argument construction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking:&lt;/strong&gt; Currency &amp;amp; weather require internet; unit conversion is offline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors:&lt;/strong&gt; Clear exceptions for invalid inputs (units, dates, locations).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; .NET Framework 4.6.2 or .NET 6.0&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LM-Kit/lm-kit-net-samples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;lm-kit-net-samples/console_net/multi_turn_chat_with_tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet build
dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then pick a model or paste a custom URI. Chat naturally; the assistant will call one or multiple tools as needed. Use &lt;code&gt;/reset&lt;/code&gt;, &lt;code&gt;/continue&lt;/code&gt;, &lt;code&gt;/regenerate&lt;/code&gt; anytime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project link:&lt;/strong&gt; &lt;a href="https://github.com/LM-Kit/lm-kit-net-samples" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Example: All Three Integration Paths
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load a capable local model&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gptoss:20b"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MultiTurnConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 1) ITool implementation&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WeatherTool&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// 2) LMFunctionAttribute methods&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LMFunctionToolBinder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDomainTools&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3) MCP import&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;McpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://mcp.example/api"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Safety and behavior&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ToolCallPolicy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Choice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ToolChoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MaxCallsPerTurn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// AllowParallelCalls = true // enable only if tools are idempotent&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Human-in-the-loop&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeforeToolInvocation&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* approve or cancel */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AfterToolInvocation&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* log results */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Run&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"Find 3 relevant docs for 'safety policy' and summarize."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Go Local with LM-Kit?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  vs. Cloud Agent Frameworks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero API costs:&lt;/strong&gt; No per-token charges. Run unlimited conversations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete privacy:&lt;/strong&gt; User data never leaves the device. GDPR/HIPAA friendly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-100ms latency:&lt;/strong&gt; Local inference eliminates network roundtrips entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline:&lt;/strong&gt; Agents function without internet connectivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No rate limits:&lt;/strong&gt; Scale to millions of requests without throttling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full control:&lt;/strong&gt; Own the stack. No vendor lock-in or API deprecations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  vs. Basic Prompt Engineering
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type-safe schemas:&lt;/strong&gt; JSON Schema validation catches bad arguments before execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic results:&lt;/strong&gt; Clear success/error states, not fragile regex parsing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel execution:&lt;/strong&gt; Run multiple tools concurrently when safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full observability:&lt;/strong&gt; Structured events at every stage, not log archaeology.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testable contracts:&lt;/strong&gt; Mock tools, inject results, replay conversations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error boundaries:&lt;/strong&gt; Graceful failures with retry logic and fallbacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  vs. Manual Function Calling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model decides:&lt;/strong&gt; Agent autonomously picks tools and arguments—no brittle if/else chains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-chaining:&lt;/strong&gt; Multiple tool calls per turn, results fed back automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;90% less boilerplate:&lt;/strong&gt; Register tools once, not per-model or per-prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in safety:&lt;/strong&gt; Loop prevention, max-calls limits, approval hooks out of the box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model-agnostic API:&lt;/strong&gt; Same code works across Mistral, LLaMA, Qwen, Granite, GPT-OSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive enhancement:&lt;/strong&gt; Add tools without refactoring conversation logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance and Limitations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance Expectations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool invocation overhead:&lt;/strong&gt; ~2–5 ms per call (parsing + validation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network tools:&lt;/strong&gt; 50–500 ms depending on API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local tools:&lt;/strong&gt; &amp;lt;1 ms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model inference remains the primary latency factor.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Models must support tool calling (check &lt;code&gt;HasToolCalls&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Network-dependent tools require internet connectivity.&lt;/li&gt;
&lt;li&gt;Parallel execution requires thread-safe, idempotent tools.&lt;/li&gt;
&lt;li&gt;Recommended GPU memory: 6–16 GB VRAM depending on model size.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Known Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tool selection quality depends on clear descriptions and schemas.&lt;/li&gt;
&lt;li&gt;Complex nested objects in arguments may confuse smaller models.&lt;/li&gt;
&lt;li&gt;Very long tool chains (&amp;gt;10 calls) may exceed context windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ready to Build?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clone the sample&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/LM-Kit/lm-kit-net-samples.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;lm-kit-net-samples/console_net/multi_turn_chat_with_tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pick your integration approach&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need full control? Use &lt;code&gt;ITool&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Prototyping quickly? Use &lt;code&gt;[LMFunction]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Using external catalogs? Use &lt;code&gt;McpClient&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add your domain logic&lt;/strong&gt;&lt;br&gt;
Replace demo tools with your APIs, databases, or business logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set policies that fit your use case&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple lookups: &lt;code&gt;MaxCallsPerTurn = 1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Complex workflows: &lt;code&gt;MaxCallsPerTurn = 10&lt;/code&gt; with approval hooks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ship agents that actually work&lt;/strong&gt;&lt;br&gt;
On-device. Private. Reliable. Observable.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start building agentic workflows that respect user privacy, run anywhere, and stay under your control.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dotnet</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>🧬 Four Local Vector Storage Patterns for C# Developers</title>
      <dc:creator>Loïc Carrère</dc:creator>
      <pubDate>Thu, 24 Apr 2025 09:13:23 +0000</pubDate>
      <link>https://forem.com/loc_carrre_0d798813c662/four-local-vector-storage-patterns-for-c-developers-1gno</link>
      <guid>https://forem.com/loc_carrre_0d798813c662/four-local-vector-storage-patterns-for-c-developers-1gno</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this post, we'll break down four vector storage patterns supported by LM-Kit.&lt;/p&gt;

&lt;p&gt;LM-Kit simplifies the complexity of embedding storage by offering a unified, developer-friendly interface that supports both instant prototyping and scalable deployment.&lt;/p&gt;

&lt;p&gt;It supports four storage patterns, each tailored to different stages of your project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory:&lt;/strong&gt; Ideal for fast prototyping and low-volume tasks with zero setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-In Vector DB:&lt;/strong&gt; Self-contained file-based storage for local tools or offline apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qdrant Vector Store:&lt;/strong&gt; External high-performance DB for cloud or large-scale deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom IVectorStore:&lt;/strong&gt; Build your own backend to integrate with proprietary systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All methods use the same &lt;code&gt;DataSource&lt;/code&gt; abstraction, so you can switch storage backends without changing your code logic.&lt;/p&gt;

&lt;p&gt;Modern AI apps, from semantic search to retrieval-augmented generation, rely on embeddings to turn text or images into dense vectors. LM-Kit gives you a few ways to handle those vectors: you can compute them in memory when needed or store them for the long haul. Each approach has tradeoffs in speed, complexity, and cost.&lt;/p&gt;

&lt;p&gt;If you're new to embeddings, check out our &lt;a href="https://lm-kit.com/glossary/" rel="noopener noreferrer"&gt;Embeddings Glossary&lt;/a&gt;. Or better yet, talk to LM-Kit Maestro, our free chatbot generator: &lt;a href="https://github.com/LM-Kit/Maestro" rel="noopener noreferrer"&gt;GitHub: LM-Kit/Maestro&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Patterns
&lt;/h2&gt;

&lt;p&gt;LM-Kit supports four main embedding storage patterns, ranging from ephemeral in-memory use to persistent vector databases, so you can match your infrastructure to the needs of your app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;On-the-Fly (In-Memory) Embeddings&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Storage with an External Vector Database&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Prebuilt Qdrant Vector Store&lt;/li&gt;
&lt;li&gt;Custom Vector Store via &lt;code&gt;IVectorStore&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistent Storage with LM-Kit's Built-In Vector DB&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;LM-Kit uses a &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.html" rel="noopener noreferrer"&gt;DataSource&lt;/a&gt; class to manage all of this. It's your main tool for embedding storage, representing a collection that can handle anything from text and documents to images or web pages. A &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.html" rel="noopener noreferrer"&gt;DataSource&lt;/a&gt; element contains multiple &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Section.html" rel="noopener noreferrer"&gt;Section&lt;/a&gt; elements, and each section holds &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.TextPartition.html" rel="noopener noreferrer"&gt;TextPartition&lt;/a&gt;¹ objects (basically embedding vectors). &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Metadata.html" rel="noopener noreferrer"&gt;Metadata&lt;/a&gt; can be associated to &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.html" rel="noopener noreferrer"&gt;DataSource&lt;/a&gt; and to &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Section.html" rel="noopener noreferrer"&gt;Section&lt;/a&gt; structures.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DataSource&lt;/strong&gt; (can include metadata)

&lt;ul&gt;
&lt;li&gt;→ &lt;strong&gt;Sections&lt;/strong&gt; (can include metadata)&lt;/li&gt;
&lt;li&gt;→ &lt;strong&gt;TextPartitions&lt;/strong&gt; (stores dense vectors)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;¹ &lt;em&gt;The "Text" in TextPartition is a bit misleading now. These partitions can handle images too.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjhik894lakpi7cwlb4z.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjhik894lakpi7cwlb4z.webp" alt="LM-Kit Vector Storage Architecture" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On-the-Fly Embeddings (In-Memory)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;When you need an embedding, LM-Kit calls the model, gets the vector, and keeps it in RAM for immediate use. Nothing is written to disk. No external service needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;

&lt;p&gt;Create an in-memory vector database and perform retrieval:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define some strings from which we want to generate embeddings&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"How do I bake a chocolate cake?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"What is the recipe for chocolate cake?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"I want to make a chocolate cake."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Chocolate cake is delicious."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"How do I cook pasta?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"I need instructions to bake a cake."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Baking requires precise measurements."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"I like vanilla ice cream."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"The weather is sunny today."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"What is the capital of France?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Paris is a beautiful city."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"How can I improve my coding skills?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Programming requires practice."&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Load the embedding model&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nomic-embed-text"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Specify optional metadata to attach to the new collection (a.k.a. DataSource)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collectionMetadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my description"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"another-pair-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"another-pair-value"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Create a new in-memory vector database&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateInMemoryDataSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"my-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;collectionMetadata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Compute embeddings to insert into the collection&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;embedder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Embedder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VectorEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vectorEntries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VectorEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Run multithreaded embedding on the list of examples&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;vectorEntries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;VectorEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SectionIdentifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-section-identifier"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Specify optional metadata to attach to the new section.&lt;/span&gt;
&lt;span class="c1"&gt;// Note: a single collection can contain multiple sections.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sectionMetadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my description"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"another-pair-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"another-pair-value"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Add the computed embedding vectors to the collection&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;SectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vectorEntries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sectionMetadata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Now perform search&lt;/span&gt;
&lt;span class="c1"&gt;// Build the query vector&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"How do I bake a chocolate cake?"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;queryVector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Embedder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Search for similar vectors across partitions&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;similarPartitions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorSearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindMatchingPartitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;queryVector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Do something with the search results...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example demonstrated how to set up an in-memory vector store using &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.CreateInMemoryDataSource.html" rel="noopener noreferrer"&gt;DataSource.CreateInMemoryDataSource&lt;/a&gt;, generate embeddings with a model, and organize them into a section with optional metadata. It finishes by performing a semantic search using a query vector. Everything runs locally in RAM, making it ideal for fast prototyping, real-time classification, or experimentation without persistent storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  In-Memory Embeddings: When and Why to Use Them
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best When&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Rapid prototyping or experimentation&lt;br&gt;• One-shot queries (no need to reuse later)&lt;br&gt;• Small datasets that fit in memory&lt;br&gt;• Real-time classification/semantic search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Upsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Zero infrastructure or setup&lt;br&gt;• Instant start&lt;br&gt;• No file I/O overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Downsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Lost on restart&lt;br&gt;• Not suitable for large collections&lt;br&gt;• No sharing across processes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Serialization Note
&lt;/h3&gt;

&lt;p&gt;Although referred to as "in-memory", any &lt;code&gt;DataSource&lt;/code&gt; instance can be serialized to a file or stream using the &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.Serialize.html" rel="noopener noreferrer"&gt;Serialize()&lt;/a&gt; method. It can then be fully restored into memory with the &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.Deserialize.html" rel="noopener noreferrer"&gt;Deserialize()&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;This provides flexibility to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save your in-memory collections between sessions&lt;/li&gt;
&lt;li&gt;Store intermediate states during experimentation&lt;/li&gt;
&lt;li&gt;Transfer embeddings across environments without requiring an external vector database&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Persistent Storage with an External Vector DB
&lt;/h2&gt;

&lt;p&gt;For production use or anything large-scale, you'll want to persist your vectors in a proper database. LM-Kit supports this through the &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Storage.IVectorStore.html" rel="noopener noreferrer"&gt;IVectorStore&lt;/a&gt; abstraction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qdrant Vector Store (Prebuilt)
&lt;/h3&gt;

&lt;p&gt;LM-Kit offers an out-of-the-box integration with &lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;Qdrant&lt;/a&gt; via the &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Storage.Qdrant.QdrantEmbeddingStore.html" rel="noopener noreferrer"&gt;QdrantEmbeddingStore&lt;/a&gt; class. Qdrant is an open-source, high-performance vector database that supports HNSW indexing and advanced payload filtering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Storage.Qdrant.QdrantEmbeddingStore.html" rel="noopener noreferrer"&gt;QdrantEmbeddingStore&lt;/a&gt; is a simple implementation of the &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Storage.IVectorStore.html" rel="noopener noreferrer"&gt;IVectorStore&lt;/a&gt; interface. It has been open-sourced and is available as part of the dedicated &lt;a href="https://www.nuget.org/packages/LM-Kit.NET.Data.Connectors.Qdrant" rel="noopener noreferrer"&gt;LM-Kit.NET.Data.Connectors.Qdrant package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The source code for this package is hosted in the &lt;a href="https://github.com/LM-Kit/lm-kit-net-data-connectors" rel="noopener noreferrer"&gt;LM-Kit.NET Data Connectors GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additional prebuilt vector store integrations will be added progressively to the same repository. If you require a specific implementation on a short timeline, feel free to &lt;a href="https://lm-kit.com/contact/" rel="noopener noreferrer"&gt;reach out to our team&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initializing store&lt;/span&gt;
&lt;span class="c1"&gt;// We're using local environment that we've started with: docker run -p 6333:6333 -p 6334:6334&lt;/span&gt;
&lt;span class="c1"&gt;// Check this tutorial to setup qdrant local environment: https://qdrant.tech/documentation/quickstart/&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;QdrantEmbeddingStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:6334"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nomic-embed-text"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateVectorStoreDataSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Qdrant Vector Store: When and Why to Use it
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best When&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Production-scale semantic search&lt;br&gt;• Cloud or distributed deployments&lt;br&gt;• Need advanced filtering by metadata&lt;br&gt;• Sharing embeddings across multiple services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Upsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Battle-tested, open-source vector DB&lt;br&gt;• High performance (HNSW indexing)&lt;br&gt;• Powerful metadata filtering&lt;br&gt;• Scales horizontally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Downsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Requires standing up a Qdrant instance&lt;br&gt;• Network latency vs local&lt;br&gt;• Additional operational overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Custom Vector Store with IVectorStore
&lt;/h3&gt;

&lt;p&gt;If you're building your own backend or want to hook into existing systems, just implement the &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.Storage.IVectorStore.html" rel="noopener noreferrer"&gt;IVectorStore&lt;/a&gt; interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IVectorStore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CollectionExistsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;CreateCollectionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;vectorSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DeleteCollectionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;UpsertAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DeleteFromMetadataAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;UpdateMetadataAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;clearFirst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MetadataCollection&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetMetadataAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VectorRecord&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;RetrieveFromMetadataAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;getVector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;getMetadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VectorRecord&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchSimilarVectorsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;collectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;getVector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;getMetadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom Vector Store: When and Why to Build Your Own
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best When&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Integrating with proprietary systems&lt;br&gt;• Using an existing vector DB not yet supported by LM-Kit&lt;br&gt;• Need custom indexing or sharding logic&lt;br&gt;• Full control over storage/retrieval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Upsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Total flexibility&lt;br&gt;• Can leverage existing infrastructure&lt;br&gt;• Tailored to your exact requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Downsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• You own the implementation and maintenance&lt;br&gt;• More upfront development effort&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Persistent Storage with LM-Kit's Built-In Vector DB
&lt;/h2&gt;

&lt;p&gt;When you need durable embedding storage without deploying an external service, LM-Kit's built-in vector database is your go-to solution. Think of it as a SQLite for dense vectors: a self-contained, file-based engine optimized for storing and querying embeddings at scale. Designed to handle millions of vectors on a single node, it delivers low-latency insertions, deletions and searches even as your dataset grows.&lt;/p&gt;

&lt;p&gt;Under the hood, it stores vectors and metadata in an optimized file format and provides two clear APIs for managing and querying the data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DataSource.CreateFileDataSource(path, name, model, metadata, overwrite: true)&lt;/code&gt; - Initialize or overwrite a local vector store at the specified file path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DataSource.LoadFromFile(path, model, readOnly: true)&lt;/code&gt; - Reopen an existing store for querying or modification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These methods let you insert, delete, and search embeddings entirely on disk. This makes the built-in store ideal for rapid prototyping, desktop tools, or any scenario where you want portable, versionable vector storage without standing up a full vector-DB cluster.&lt;/p&gt;

&lt;p&gt;Now, let's dive into some source code to see how LM-Kit's built-in vector storage works in practice, from creating a local database to querying it later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating and Populating a Local Vector Database
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define some strings from which we want to generate embeddings&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"How do I bake a chocolate cake?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"What is the recipe for chocolate cake?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"I want to make a chocolate cake."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Chocolate cake is delicious."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"How do I cook pasta?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"I need instructions to bake a cake."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Baking requires precise measurements."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"I like vanilla ice cream."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"The weather is sunny today."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"What is the capital of France?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Paris is a beautiful city."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"How can I improve my coding skills?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Programming requires practice."&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Load the embedding model&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nomic-embed-text"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Specify optional metadata to attach to the new collection (a.k.a. DataSource)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collectionMetadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my description"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"another-pair-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"another-pair-value"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Create a new local vector database (overwriting if it already exists)&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CollectionPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"d:\\collection.ds"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateFileDataSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CollectionPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"my-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;collectionMetadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Compute embeddings to insert into the collection&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;embedder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Embedder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VectorEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vectorEntries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VectorEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Run multithreaded embedding on the list of examples&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;vectorEntries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;VectorEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SectionIdentifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-section-identifier"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Specify optional metadata to attach to the new section.&lt;/span&gt;
&lt;span class="c1"&gt;// Note: a single collection can contain multiple sections.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sectionMetadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MetadataCollection&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my description"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"another-pair-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"another-pair-value"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Add the computed embedding vectors to the collection&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;SectionIdentifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vectorEntries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sectionMetadata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Close the database&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loading and Querying an Existing Database
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load the embedding model&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromModelID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nomic-embed-text"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CollectionPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"d:\\collection.ds"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Load our previously created database in read-only mode (sufficient for querying)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CollectionPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Build the query vector&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"How do I bake a chocolate cake?"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;queryVector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Embedder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Search for similar vectors across partitions&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;similarPartitions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorSearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindMatchingPartitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;queryVector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Do something with the search results...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Together, these two snippets show the full lifecycle of LM-Kit's built-in vector storage: how to create, populate, persist, and later reload your embedding collection for querying, all without relying on external infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎁 A CEO's Modest Proposal for the Brave
&lt;/h3&gt;

&lt;p&gt;I'm offering a gift to anyone who manages to implement a faster .NET version of the 2 scripts above, without using LM-Kit.&lt;/p&gt;

&lt;h3&gt;
  
  
  LM-Kit's Built-In Vector DB: The Unsung Hero
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best When&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Desktop or local applications&lt;br&gt;• Offline-first tools&lt;br&gt;• Medium-scale datasets (up to millions of vectors)&lt;br&gt;• No external database infrastructure available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Upsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Zero external dependencies&lt;br&gt;• File-based portability&lt;br&gt;• Fast local queries&lt;br&gt;• Version control friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Downsides&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;• Single-machine scale&lt;br&gt;• Not designed for distributed queries&lt;br&gt;• Limited compared to specialized vector DBs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Embedding Storage Methods Compared
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;🔧 Method&lt;/th&gt;
&lt;th&gt;✅ Best For&lt;/th&gt;
&lt;th&gt;💾 Persistence&lt;/th&gt;
&lt;th&gt;📈 Scale&lt;/th&gt;
&lt;th&gt;🌐 Infra Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;In-Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quick tests, small-scale prototyping&lt;/td&gt;
&lt;td&gt;Temporary (can serialize manually)&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-In Vector DB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Local apps, offline tools, medium-scale use&lt;/td&gt;
&lt;td&gt;Yes (file-based)&lt;/td&gt;
&lt;td&gt;Medium (single machine)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qdrant Vector Store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High-scale, distributed or cloud deployments&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Qdrant instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom via IVectorStore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom backends, proprietary infra&lt;/td&gt;
&lt;td&gt;Yes (you implement it)&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Your own infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each method serves a purpose. Use in-memory embeddings for quick tests or when you're feeding results into something immediately. If you need persistence but want to keep things simple and local, go with LM-Kit's built-in vector DB. For large-scale or distributed systems, Qdrant is a solid external option. And if your stack is special, you can always bring your own vector store.&lt;/p&gt;

&lt;p&gt;The best part? &lt;a href="https://docs.lm-kit.com/lm-kit-net/api/LMKit.Data.DataSource.html" rel="noopener noreferrer"&gt;DataSource&lt;/a&gt; is unified. You can switch between these options without rewriting your code, just plug in a different backend and you're set.&lt;/p&gt;

&lt;p&gt;Let us know what you're building. And if you're doing something wild with embeddings, we want to hear about it. ✨&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dotnet</category>
      <category>embeddings</category>
      <category>vectordb</category>
    </item>
  </channel>
</rss>
