Implementation:Ollama Ollama Thinking Template
| Knowledge Sources | |
|---|---|
| Domains | Thinking, Template Analysis |
| Last Updated | 2025-02-15 00:00 GMT |
Overview
Infers thinking tag delimiters from Go chat templates by analyzing the template AST for .Thinking field references within message range loops.
Description
InferTags walks the parsed template AST using templateVisit, maintaining an ancestor stack. When it finds a FieldNode referencing "Thinking" inside a RangeNode that iterates over "Messages", it navigates to the nearest ListNode ancestor and extracts the first and last TextNode as opening and closing tags. The templateVisit function provides a generic AST walker with enter/exit callbacks, handling all template node types (ListNode, BranchNode, ActionNode, WithNode, RangeNode, IfNode, PipeNode, CommandNode, TemplateNode).
Usage
Called during model initialization to automatically detect thinking tags (e.g., <think>/</think>) from the model's chat template without hardcoding them.
Code Reference
Source Location
- Repository: Ollama
- File: thinking/template.go
- Lines: 1-134
Signature
func templateVisit(n parse.Node, enterFn func(parse.Node) bool, exitFn func(parse.Node))
func InferTags(t *template.Template) (openingTag string, closingTag string)
func rangeUsesField(rangeNode *parse.RangeNode, field string) bool
Import
import "github.com/ollama/ollama/thinking"
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| t | *template.Template | Yes | Parsed Go template from the model's chat template |
Outputs
| Name | Type | Description |
|---|---|---|
| openingTag | string | Detected opening tag (e.g. "<think>") |
| closingTag | string | Detected closing tag (e.g. "</think>") |
Usage Examples
tmpl, _ := template.New("chat").Parse(`
{{range .Messages}}
{{if .Thinking}}<think>{{.Thinking}}</think>{{end}}
{{.Content}}
{{end}}
`)
openTag, closeTag := thinking.InferTags(tmpl)
// openTag: "<think>"
// closeTag: "</think>"