Agentic កម្រិតស្មុគស្មាញ: ទាប

Prompt Template in Go

Build prompts from versioned, parameterized templates so prompt logic stays separate from agent orchestration code and can be tested, diffed, and swapped independently.

The Problem

Agent prompt strings concatenated inline — "You are a " + role + " assistant. The user asked: " + query — are impossible to review, test independently, or version. A one-character change to a prompt buried in a 500-line agent file can silently break behavior. As prompts grow to hundreds of tokens with multiple sections, inline construction becomes unmanageable.

The Solution

Store each prompt section as a named PromptTemplate with a version string and a text/template body. A Registry compiles templates at registration time — syntax errors surface immediately rather than at runtime. Registry.Render(name, vars) performs substitution with missingkey=error, so a forgotten variable is a compile-time-equivalent panic, not a silent blank. A PromptBuilder assembles multi-section prompts by rendering and concatenating named templates in order.

Structure

Prompt Template Pattern
Step 1 of 3

Registration and Validation

Templates are registered at package init or server startup via MustRegister(). text/template.Parse() runs immediately — a malformed template panics early rather than failing during a live LLM call.

Implementation

package main

// PromptTemplate holds a named, versioned text/template for prompt construction.
type PromptTemplate struct {
	Name    string
	Version string
	Raw     string
}

// RenderedPrompt is the final prompt string after variable substitution.
type RenderedPrompt struct {
	TemplateName string
	Content      string
}

// TemplateVars is a free-form map of variable substitutions.
type TemplateVars map[string]any

Real-World Analogy

Legal document templates: a law firm maintains versioned contract templates with placeholder clauses. The paralegal fills in the blanks (client name, date, jurisdiction) for each engagement. The underlying template is reviewed, approved, and versioned independently from the data that populates it. Changing the indemnification clause means updating one template file, not hunting through every engagement letter.

Pros and Cons

ProsCons
Prompt text is reviewable, diffable, and versionable as plain filestext/template syntax is unfamiliar to non-Go contributors
missingkey=error surfaces missing vars at render time, not silentlyTemplate logic (conditionals, ranges) can grow complex and hard to test
Registry validates syntax at startup, not during a live LLM callEach new section type requires a new template registration
PromptBuilder decouples assembly order from template contentTemplates are strings — IDE support for embedded syntax is limited

Best Practices

  • Version every template (Version: "1.0.0") and log the version alongside every LLM call — prompt regressions are easier to diagnose when you know which version was active.
  • Keep templates as logic-free as possible — use Go code for conditionals, not {{if}} blocks inside templates.
  • Write unit tests that call Registry.Render() with known vars and assert the output string — prompts are testable code.
  • Store template raw strings as .tmpl files in an embed.FS so they can be reviewed in pull requests without touching Go source.
  • Use TemplateVars (a map[string]any alias) consistently — resist the temptation to pass typed structs, which break the uniform Render signature.

When to Use

  • Any agent with more than one prompt section or more than two variable substitutions.
  • Teams where non-engineers need to review or edit prompt content.
  • Systems that run A/B experiments on prompt wording.

When NOT to Use

  • Trivial single-turn agents with a one-sentence system prompt — a string constant is fine.
  • Prompts with no variable substitution at all — just use a const.