Ollama 모델 템플릿
Ollama 모델 템플릿(template)은 서버 측 추론 파이프라인에서 시스템/도구 지시, 사용자 메시지, 생각(thinking) 블록 등을 렌더링하는 규칙을 정의합니다. Hugging Face의 chat_template와 달리 토크나이저 단계가 아닌 서버 메시지 포맷과 연동되므로 별도로 이해해야 합니다.
Ollama 템플릿과 Hugging Face 템플릿 차이¶
적용 위치: Hugging Face는 토크나이저/파이프라인 레벨, Ollama는 서버 런타임 메시지 렌더링.
구문/변수: HF는 Jinja 스타일 변수(
{{ user }}등), Ollama는 서버 전용 변수와 블록(system,tools,thinking,prompt등).툴/시스템 지시: Ollama 템플릿은 도구 호출 스키마와 시스템 프롬프트를 한꺼번에 포함할 수 있음.
템플릿 구조 개요¶
시스템 메시지 블록: 모델 동작 지침.
사용자/어시스턴트 메시지 영역: 대화 기록을 포함.
선택적 thinking 블록: 추론 과정 노출 여부 제어.
도구 호출 섹션: tool schema, 호출 결과 등의 삽입 위치.
변수 예시:
{{ currentDate }},{{ .Tools }},{{ .ThinkLevel }}등.
/show template로 확인하기¶
ollama run <model>, 대화 프롬프트에서/show template입력.출력 텍스트를 복사해 템플릿 변수와 블록을 확인.
템플릿 수정 전 백업: 동일 모델을 복사(
ollama cp) 후 편집.
커스터마이징 팁¶
시스템 지시를 템플릿에 직접 넣기보다, 모델 호출 시 동적으로 설정(추론 옵션)하는 방식을 우선 고려.
도구 호출이 필요 없으면 tool 섹션을 제거하거나 비활성화해 토큰 낭비 감소.
컨텍스트 길이가 짧은 모델에서는 불필요한 상단 지시를 최소화.
/show template 출력 예시와 해설¶
>>> /show template
<|start|>system<|message|>You are ChatGPT, a large language model trained by OpenAI.
Knowledge cutoff: 2024-06
Current date: {{ currentDate }}
{{- if and .IsThinkSet .Think (ne .ThinkLevel "") }}
Reasoning: {{ .ThinkLevel }}
{{- else if or (not .IsThinkSet) (and .IsThinkSet .Think) }}
Reasoning: medium
{{- end }}
{{- $hasNonBuiltinTools := false }}
{{- if .Tools -}}
{{- $hasBrowserSearch := false }}
{{- $hasBrowserOpen := false }}
{{- $hasBrowserFind := false }}
{{- $hasPython := false }}
{{- range .Tools }}
{{- if eq .Function.Name "browser.search" -}}{{- $hasBrowserSearch = true -}}
{{- else if eq .Function.Name "browser.open" -}}{{- $hasBrowserOpen = true -}}
{{- else if eq .Function.Name "browser.find" -}}{{- $hasBrowserFind = true -}}
{{- else if eq .Function.Name "python" -}}{{- $hasPython = true -}}
{{- else }}{{ $hasNonBuiltinTools = true -}}
{{- end }}
{{- end }}
{{- if or $hasBrowserSearch $hasBrowserOpen $hasBrowserFind $hasPython }}
# Tools
{{- if or $hasBrowserSearch $hasBrowserOpen $hasBrowserFind }}
## browser
// Tool for browsing.
// The `cursor` appears in brackets before each browsing display: `[{cursor}]`.
// Cite information from the tool using the following format:
// `【{cursor}†L{line_start}(-L{line_end})?】`, for example: `` or ``.
// Do not quote more than 10 words directly from the tool output.
// sources=web (default: web)
namespace browser {
{{- if $hasBrowserSearch }}
// Searches for information related to `query` and displays `topn` results.
type search = (_: {
query: string,
topn?: number, // default: 10
source?: string,
}) => any;
{{- end }}
{{- if $hasBrowserOpen }}
// Opens the link `id` from the page indicated by `cursor` starting at line number `loc`, showing `num_lines` lines.
// Valid link ids are displayed with the formatting: `【{id}†.*】`.
// If `cursor` is not provided, the most recent page is implied.
// If `id` is a string, it is treated as a fully qualified URL associated with `source`.
// If `loc` is not provided, the viewport will be positioned at the beginning of the document or centered on the most relevant passage, if available.
// Use this function without `id` to scroll to a new location of an opened page.
type open = (_: {
id?: number | string, // default: -1
cursor?: number, // default: -1
loc?: number, // default: -1
num_lines?: number, // default: -1
view_source?: boolean, // default: false
source?: string,
}) => any;
{{- end }}
{{- if $hasBrowserFind }}
// Finds exact matches of `pattern` in the current page, or the page given by `cursor`.
type find = (_: {
pattern: string,
cursor?: number, // default: -1
}) => any;
{{- end }}
} // namespace browser
{{- end }}{{/* end if has browser tools */}}
{{- if $hasPython }}
## python
Use this tool to execute Python code in your chain of thought. The code will not be shown to the user. This tool should be used for internal reasoning, but not for code that is intended to be visible to the user (e.g. when creating plots, tables, or files).
When you send a message containing Python code to python, it will be executed in a stateful Jupyter notebook environment. python will respond with the output of the execution or time out after 120.0 seconds. The drive at '/mnt/data' can be used to save and persist user files. Internet access for this session is UNKNOWN. Depends on the cluster.
{{- end }}{{/* end if hasPython */}}
{{- end }}{{/* end if has any built-in tools */}}
{{- end }}{{/* end if .Tools */}}
# Valid channels: analysis, commentary, final. Channel must be included for every message.{{ if $hasNonBuiltinTools }}
Calls to these tools must go to the commentary channel: 'functions'.
{{- end -}}<|end|>{{/* end of system */ -}}
{{- if or $hasNonBuiltinTools .System -}}
<|start|>developer<|message|>{{- if $hasNonBuiltinTools }}# Tools
## functions
namespace functions {
{{- range .Tools }}
{{- if not (or (eq .Function.Name "browser.search") (eq .Function.Name "browser.open") (eq .Function.Name "browser.find") (eq .Function.Name "python")) }}
{{if .Function.Description }}
// {{ .Function.Description }}
{{- end }}
{{- if and .Function.Parameters.Properties (gt (len .Function.Parameters.Properties) 0) }}
type {{ .Function.Name }} = (_: {
{{- range $name, $prop := .Function.Parameters.Properties }}
{{- if $prop.Description }}
// {{ $prop.Description }}
{{- end }}
{{ $name }}: {{ $prop | toTypeScriptType }},
{{- end }}
}) => any;
{{- else }}
type {{ .Function.Name }} = () => any;
{{- end }}
{{- end }}{{/* end if not browser tool */}}
{{- end }}{{/* end of range .Tools */}}
} // namespace functions
{{- end }}{{/* end if hasNonBuiltinTools */}}
{{- if .System}}
# Instructions
{{ .System }}
{{- end -}}
<|end|>
{{- end -}}
{{- /* Find the index of the last user message */ -}}
{{- $lastUserIdx := -1 }}
{{- $prefillingContent := false }}
{{- $prefillingThinkingOnly := false }}
{{- range $i, $msg := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
{{- if eq $msg.Role "user" }}
{{- $lastUserIdx = $i }}
{{- end -}}
{{- if and $last (eq $msg.Role "assistant") (gt (len $msg.Content) 0) }}
{{- $prefillingContent = true }}
{{- else if and $last (eq $msg.Role "assistant") (gt (len $msg.Thinking) 0) }}
{{- $prefillingThinkingOnly = true }}
{{- end }}
{{- end -}}
{{- /* Now render messages */ -}}
{{- range $i, $msg := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
{{- if (ne $msg.Role "system") -}}
{{- if eq $msg.Role "tool" -}}
{{- if or (eq $msg.ToolName "python") (eq $msg.ToolName "browser.search") (eq $msg.ToolName "browser.open") (eq $msg.ToolName "browser.find") -}}
<|start|>{{ $msg.ToolName }} to=assistant<|message|>{{ $msg.Content }}<|end|>
{{- else -}}
<|start|>functions.{{ $msg.ToolName }} to=assistant<|message|>{{ $msg.Content }}<|end|>
{{- end -}}
{{- else if eq $msg.Role "assistant" -}}
{{- if and $msg.Thinking (gt $i $lastUserIdx) -}}{{- /* Show thinking only after last user message */ -}}
<|start|>assistant<|channel|>analysis<|message|>{{ $msg.Thinking }}{{- if not $prefillingThinkingOnly -}}<|end|>{{- end -}}
{{- end -}}
{{- if gt (len $msg.Content) 0 -}}
<|start|>assistant<|channel|>final<|message|>{{ $msg.Content }}{{- if not $prefillingContent -}}<|end|>{{- end -}}
{{- end -}}
{{- if gt (len $msg.ToolCalls) 0 -}}
{{- range $j, $toolCall := $msg.ToolCalls -}}
{{- $isBuiltin := or (eq $toolCall.Function.Name "python") (eq $toolCall.Function.Name "browser.search") (eq $toolCall.Function.Name "browser.open") (eq $toolCall.Function.Name "browser.find") -}}
<|start|>assistant<|channel|>{{ if $isBuiltin }}analysis{{ else }}commentary{{ end }} to={{ if not $isBuiltin}}functions.{{end}}{{ $toolCall.Function.Name }} <|constrain|>json<|message|>{{ $toolCall.Function.Arguments }}<|call|>
{{- end -}}
{{- end -}}
{{- else if eq $msg.Role "user" -}}
<|start|>{{ $msg.Role }}<|message|>{{ $msg.Content }}<|end|>
{{- end }}
{{- else }}
{{- end }}
{{- end -}}
{{- if not (or $prefillingContent $prefillingThinkingOnly) -}}
<|start|>assistant
{{- end -}}Program 1:gpt-oss ollama 템플릿 (ollama 0.13)
해설 포인트¶
시스템 블록: 모델 동작 규칙, 날짜 삽입(
{{ currentDate }}) 등 상단 지시가 포함됩니다.추론 수준 제어:
Reasoning: {{ .ThinkLevel }}/medium분기 로직은 thinking 모드 표시 여부를 결정합니다.도구 섹션 조건부 렌더링:
.Tools존재 여부에 따라 browser/python 서브블록을 추가합니다. 도구가 없으면 이 블록을 제거하거나 조건을 조정해 불필요한 토큰을 줄일 수 있습니다.함수 시그니처 블록:
functions네임스페이스 부분은 도구 스키마를 나열합니다. 도구 정의가 길면 모델 컨텍스트를 차지하므로 필요한 항목만 남기는 것이 좋습니다.
빠른 체크리스트¶
템플릿 수정 전
ollama cp 원본모델 새이름으로 백업.도구가 없으면 tool 관련 조건문/블록을 정리.
날짜나 버전 정보가 필요 없으면 상단 메타 필드 간소화.
컨텍스트 길이가 짧은 모델은 시스템 지시와 기능 설명을 압축해 토큰을 확보.
흔한 오류와 점검¶
Hugging Face
chat_template를 그대로 붙여넣어 변수명이 맞지 않는 경우: Ollama 변수/블록 이름으로 교체.날짜/버전 등 동적 필드가 없으면
{{ currentDate }}등이 빈 값으로 나올 수 있음.도구 목록이 없을 때 tool 섹션 조건문을 제거하지 않으면 빈 블록이 남을 수 있음.
더 알아보기¶
Ollama 공식 문서: https://
docs .ollama .com 템플릿 출력 명령:
ollama run <model>후/show template