Table of Contents

👉 Try the demo: https://github.com/LM-Kit/lm-kit-net-samples/tree/main/console_net/prompt_templates

Prompt Templates with Logic for C# .NET Applications


🎯 Purpose of the Demo

The Prompt Templates demo shows how to use LM-Kit.NET's PromptTemplate engine to build dynamic, reusable prompts with variable substitution, conditionals, loops, filters, scoping, and custom helpers. It demonstrates a parse-once, render-many pattern that separates prompt structure from runtime data.


👥 Who Should Use This Demo

  • Application developers who build prompts from configuration, user input, or database records and need a clean separation between template structure and runtime values.
  • Agent framework builders who configure system prompts dynamically based on available tools, user roles, or domain context.
  • Platform teams who maintain prompt libraries and want versioned, testable templates instead of string concatenation.
  • Localization engineers who swap languages, personas, or constraints at runtime without rewriting prompt logic.

🚀 What Problem It Solves

Hard-coded string concatenation for prompts is fragile, hard to test, and mixes logic with content. PromptTemplate solves this by providing a lightweight template language with:

  • Variables for injecting runtime values
  • Conditionals (if/else/unless) for toggling prompt sections
  • Loops (each) for listing tools, constraints, or examples
  • Filters (trim, upper, truncate, json, etc.) for transforming values inline
  • Scoping (with) for cleanly accessing nested object properties
  • Custom helpers for injecting computed values like dates or formatted strings

Templates compile to an AST once and render many times with different contexts, making them efficient for high-throughput systems.


💻 Demo Application Overview

The demo is a console application with two parts:

  1. Template Feature Showcase (no model required): walks through each template construct, printing the template source and rendered output side by side.
  2. Dynamic Chat: asks the user to configure an assistant (domain, language, verbosity) and builds a system prompt from a template at runtime. The assistant then runs as a live multi-turn chat.

✨ Key Features

  • 9 interactive examples covering variables, filters, defaults, conditionals, loops, scoping, custom helpers, variable introspection, and alternative syntaxes
  • Real-world agent prompt combining all constructs into a single production-quality system prompt
  • Live multi-turn chat where the system prompt is generated dynamically from user input via a template
  • Three syntax styles: Mustache ({{var}}), Dollar (${var}), and Percent (%var%)
  • Filter chaining: {{name|trim|upper|truncate:20}}
  • Inline defaults: {{language:English}}

🏗️ Architecture

┌───────────────────────────────────────────────────────┐
│              Prompt Template Pipeline                  │
├───────────────────────────────────────────────────────┤
│                                                       │
│  Template String ──► Parse() ──► Compiled AST         │
│                                      │                │
│                         ┌────────────┼────────────┐   │
│                         ▼            ▼            ▼   │
│                    Render(ctx1)  Render(ctx2)  Render  │
│                         │            │            │   │
│                         ▼            ▼            ▼   │
│                    "prompt A"   "prompt B"   "prompt C"│
│                                                       │
│  Parse once, render many ─ efficient for production   │
└───────────────────────────────────────────────────────┘

⚙️ Getting Started

📋 Prerequisites

  • .NET 8.0 or later
  • LM-Kit.NET SDK
  • 4 to 18 GB VRAM (depending on model choice, only needed for Part 2)

📥 Download the Project

▶️ Running the Application

cd console_net/prompt_templates
dotnet run

The template showcase runs immediately (no model needed). When you reach Part 2, select a model to start the live chat.


💡 Example Usage

Basic Variable Substitution

var template = PromptTemplate.Parse("You are {{role}}. Help with {{topic}}.");
string prompt = template.Render(new PromptTemplateContext
{
    ["role"] = "a senior C# developer",
    ["topic"] = "async programming"
});
// "You are a senior C# developer. Help with async programming."

Conditionals and Loops for Agent Prompts

var template = PromptTemplate.Parse(@"You are {{persona}}.
{{#if tools}}Available tools:
{{#each tools}}- {{name}}: {{description}}
{{/each}}{{/if}}
Always respond in {{language:English}}.");

string prompt = template.Render(new PromptTemplateContext
{
    ["persona"] = "Aria",
    ["tools"] = new[]
    {
        new { name = "web_search", description = "Search the internet" },
        new { name = "calculator", description = "Math operations" }
    }
});

Filters and Defaults

var template = PromptTemplate.Parse(
    "Welcome, {{name|trim|capitalize}}! Role: {{role:user}}."
);
string result = template.Render(new PromptTemplateContext
{
    ["name"] = "  alice  "
});
// "Welcome, Alice! Role: user."

🔧 Troubleshooting

Issue Solution
PromptTemplateException on parse Check for unclosed {{ tags or mismatched block constructs ({{#if}} without {{/if}})
Missing variable renders blank This is default behavior. Use StrictVariables = true to throw instead, or provide inline defaults with {{var:fallback}}
Filters not applying Verify pipe syntax with no spaces: {{name\|upper}} not {{name \| upper}}

🚀 Extend the Demo

  • Register custom global filters via PromptTemplateFilters.Register() for domain-specific transformations
  • Use TryParse for user-supplied templates that may contain syntax errors
  • Combine with AgentBuilder to build fully dynamic agent configurations
  • Use variable introspection (template.Variables) to auto-generate UI forms for template parameters