Skip to content

Instantly share code, notes, and snippets.

@td2sk
Last active June 1, 2025 02:44
Show Gist options
  • Save td2sk/71bc73523796f12af1d18e41d344e9cc to your computer and use it in GitHub Desktop.
Save td2sk/71bc73523796f12af1d18e41d344e9cc to your computer and use it in GitHub Desktop.

Ollama Thinking 対応 コードリーディングメモ

  • 作成日: 2025/06/01
  • 最終更新日: 2025/06/01

概要

前提: Thinking

  • 回答の前に検討過程を出力すること、またはそう訓練されたモデルの機能
  • 推論性能が向上する
  • Reasoning とも呼ぶ

ollama では v0.9 からサポート(think の有効/無効切り替えオプション追加、ハイライト表示)を追加

処理

概要

  • 前処理
    • thinking サポートモデルかどうかをプロンプトテンプレートから判定
  • リクエスト
    • プロンプトテンプレートに thinking 追加
  • レスポンス
    • 愚直にパースして分解

サポート判定

ollama/server/images.go at 5c42800fca4da07d1c362c0f190429993e53c3b5 · ollama/ollama

  • モデルテンプレートに Think 関連の属性があれば Capability に追加される
  • より正確には、Thinking の開始・終了タグがあるかを判定

ollama/server/thinking.go at v0.9.0 · ollama/ollama

  • {{ .Thinking }} のようなテンプレートを探し、その前後の値を切り出すことで、開始・終了タグを特定
<think>{{ .Thinking }}</think>

リクエスト

ollama/template/template.go at 5c42800fca4da07d1c362c0f190429993e53c3b5 · ollama/ollama

  • テンプレート置換に Think、IsThinkSet を追加
    • Think(boolean): Think 機能が有効かどうか。モデルがサポートしていればデフォルト true
    • IsThinkSet(boolean): ユーザーが明示的に Think 機能を設定したかどうか
      • 主にプロンプトテンプレートにおいて、明示的な指定時のみ置換が行われる箇所があるため

テンプレート側にも対応が追加されている

qwen3/template より抜粋

{{- if and $.IsThinkSet (eq $i $lastUserIdx) }}
{{- if $.Think -}}
{{- " "}}/think
{{- else -}}
{{- " "}}/no_think
{{- end -}}
{{- end }}<|im_end|>
{{ else if eq .Role "assistant" }}<|im_start|>assistant
{{ if (and $.IsThinkSet (and .Thinking (or $last (gt $i $lastUserIdx)))) -}}
<think>{{ .Thinking }}</think>
{{ end -}}

(中略)

{{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
{{ if and $.IsThinkSet (not $.Think) -}}
<think>

</think>

{{ end -}}
{{ end }}

レスポンス処理

ollama/server/routes.go at 5c42800fca4da07d1c362c0f190429993e53c3b5 · ollama/ollama

  • think サポートなら addContent に渡す

addContent

ollama/server/thinking.go at v0.9.0 · ollama/ollama

  • eat 関数による愚直なステートパーサーで <think> </think> 部分とそれ以外に分割

ollama/server/thinking.go at v0.9.0 · ollama/ollama

  • eat の結果を受けて、think 部分と残りのレスポンスに分割して返す

表示

ollama/cmd/cmd.go at 5c42800fca4da07d1c362c0f190429993e53c3b5 · ollama/ollama

  • response に thinking が含まれていればそれを表示

ollama/cmd/cmd.go at 5c42800fca4da07d1c362c0f190429993e53c3b5 · ollama/ollama

  • think 部分を出力
  • plainText でなければ(ターミナル上なら)色をグレーにする

nothink 時

/set nothink した際、旧バージョンでは表示されていた空の <think></think> が出ないよう改善されている

GsUnMyZaMAApn2Q

これは不思議

  • 実装では /set nothink のときはそもそもレスポンスのパーサーが実行されない
  • じゃあどうやって<think>を特定して消してるの?

実は ollama のソースコード上では処理していない

モデルのテンプレートにあらかじめ、/set nothinkのときだけ空の<think></think>をプロンプトに埋め込むよう指示がある

{{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
{{ if and $.IsThinkSet (not $.Think) -}}
<think>

</think>

{{ end -}}
{{ end }}

これによりLLMは<think>を生成しない

∵ LLM の立場では <think></think>までは生成済みで、その後を考えるタスクになる

実際にモデルのプロンプトから上記の対応部分を削除すると、空の <think></think>が出力されるようになる

→ Ollama のソースコードで処理しているわけではないとわかる

GsUoxX4aEAAAbNT

変更履歴

  • 2025/06/01 公開
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment