Featured Teardown · Automation Signature № 02 · STEADY-PULSE

把 Gemma 4 e2b 接成 Obsidian 的本地 Helper:摘要、翻譯、Tag 建議Wire gemma4:e2b Into Obsidian as a Local Daily Helper

Obsidian 我用了三年,筆記累積到一定數量後,三件事每天都會發生:寫太長想看摘要、英文資料想翻成繁中、文章寫完忘記加 tag。這三件以前我打開 Claude 處理,現在改成 Gemma 4 e2b 在本機,不裝 plugin、不寫 Python。

I've used Obsidian for three years. Past a certain note count, three things happen daily: a note grows too long and I want a summary, an English source needs Traditional Chinese translation, or I finish writing and forget to add tags. I used to open Claude for these. Now they go to gemma4:e2b on the local machine — no plugin, no Python.


為什麼不用現成的 Obsidian plugin?

社群有幾個 Ollama integration plugin,我試過兩個。問題不在功能,在「邊界控制」:

  • 多數 plugin 是把整篇筆記丟進 prompt,無法精準選取「我只要摘要這三段」。
  • prompt 是寫死在 plugin 設定裡,要改 prompt 就要進設定介面,動線不順。
  • 多數 plugin 為了通用性會引入 model selector、temperature slider,這些對日常使用是雜訊。

我要的是:選一段文字 → 跑某個固定任務 → 結果貼回筆記。三件任務各自就是一個 shortcut,不需要選單。

Why not an existing Obsidian plugin?

The community has several Ollama integration plugins. I tried two. The issue isn't features, it's boundary control:

  • Most ship "send the whole note as prompt" — no precise selection like "summarize just these three paragraphs."
  • Prompts live in plugin settings; tweaking one means digging through a UI.
  • Many add a model picker and temperature slider in the name of generality. For daily use that's noise.

What I want: select text → run one fixed task → paste result back. Three tasks, three shortcuts. No menus.


架構:60 行 shell + macOS Shortcuts

Obsidian 選取文字
   ↓ ⌘⌥1 / ⌘⌥2 / ⌘⌥3
macOS Shortcuts(接住選取的文字)
   ↓ Run Shell Script
~/bin/llm-helper.sh {task} {selection}
   ↓ curl
Ollama HTTP API (localhost:11434)
   ↓ JSON response
回貼到 Obsidian(蓋掉原本的選取)

三個任務(summary / translate / tag)共用一支 shell script,靠第一個參數切分支。macOS Shortcuts 負責「截取選取 → 餵給 script → 把 stdout 蓋回去」。

Architecture: 60 lines of shell + macOS Shortcuts

Obsidian: select text
   ↓ ⌘⌥1 / ⌘⌥2 / ⌘⌥3
macOS Shortcuts (captures the selection)
   ↓ Run Shell Script
~/bin/llm-helper.sh {task} {selection}
   ↓ curl
Ollama HTTP API (localhost:11434)
   ↓ JSON response
Paste back into Obsidian (replaces the selection)

Three tasks (summary / translate / tag) share one script, branched on the first argument. macOS Shortcuts handles "capture selection → pipe to script → replace selection with stdout."


Shell script

~/bin/llm-helper.sh:

#!/bin/bash
set -euo pipefail

TASK="${1:-}"
INPUT="${2:-}"
MODEL="gemma4:e2b"
ENDPOINT="http://localhost:11434/api/generate"

if [[ -z "$TASK" || -z "$INPUT" ]]; then
  echo "usage: llm-helper.sh {summary|translate|tag} <text>" >&2
  exit 1
fi

case "$TASK" in
  summary)
    PROMPT="請務必使用繁體中文台灣用語回答。請用三句話以內摘要下面這段文字,
直接回摘要本體,不要前綴、不要解釋:

---
$INPUT
---"
    ;;
  translate)
    PROMPT="請務必使用繁體中文台灣用語翻譯下面這段英文,
保留原文的技術名詞(用括號註原文),直接回譯文,不要解釋:

---
$INPUT
---"
    ;;
  tag)
    PROMPT="請務必使用繁體中文台灣用語回答。請為下面這段筆記建議 3-5 個
Obsidian tag(kebab-case,不含 # 字元,用逗號分隔),
不要解釋、不要其他文字、只回 tag 清單:

---
$INPUT
---"
    ;;
  *)
    echo "unknown task: $TASK" >&2
    exit 2
    ;;
esac

curl -s "$ENDPOINT" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc \
        --arg model "$MODEL" \
        --arg prompt "$PROMPT" \
        '{model: $model, prompt: $prompt, stream: false, think: false, options: {temperature: 0.2}}')" \
  | jq -r '.response' \
  | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

五件事值得指出:

  1. prompt 都繁中前綴——gemma4:e2b 預設英文,這句不能省(來源)。
  2. stream: false——shortcut 需要一次拿到完整回應,不需要 streaming。
  3. temperature: 0.2——摘要、翻譯、tag 都要穩定,不要創意。
  4. think: false——gemma4:e2b 是 thinking 模型,沒有這個 flag,num_predict 配額會先被內部推理過程吃掉,response 欄位回傳空字串。這個坑踩過一次就不會忘。
  5. jq -nc 組 JSON——避免 shell 變數插值踩到引號跳脫。

Shell script

~/bin/llm-helper.sh:

#!/bin/bash
set -euo pipefail

TASK="${1:-}"
INPUT="${2:-}"
MODEL="gemma4:e2b"
ENDPOINT="http://localhost:11434/api/generate"

if [[ -z "$TASK" || -z "$INPUT" ]]; then
  echo "usage: llm-helper.sh {summary|translate|tag} <text>" >&2
  exit 1
fi

case "$TASK" in
  summary)
    PROMPT="請務必使用繁體中文台灣用語回答。請用三句話以內摘要下面這段文字,
直接回摘要本體,不要前綴、不要解釋:

---
$INPUT
---"
    ;;
  translate)
    PROMPT="請務必使用繁體中文台灣用語翻譯下面這段英文,
保留原文的技術名詞(用括號註原文),直接回譯文,不要解釋:

---
$INPUT
---"
    ;;
  tag)
    PROMPT="請務必使用繁體中文台灣用語回答。請為下面這段筆記建議 3-5 個
Obsidian tag(kebab-case,不含 # 字元,用逗號分隔),
不要解釋、不要其他文字、只回 tag 清單:

---
$INPUT
---"
    ;;
  *)
    echo "unknown task: $TASK" >&2
    exit 2
    ;;
esac

curl -s "$ENDPOINT" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc \
        --arg model "$MODEL" \
        --arg prompt "$PROMPT" \
        '{model: $model, prompt: $prompt, stream: false, think: false, options: {temperature: 0.2}}')" \
  | jq -r '.response' \
  | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Five things worth pointing out:

  1. All prompts have the Chinese prefix. gemma4:e2b defaults to English (prior article). Don't drop the line.
  2. stream: false — the Shortcut needs a complete response in one shot.
  3. temperature: 0.2 — summary, translation, tags all want stability, not creativity.
  4. think: false — gemma4:e2b is a thinking model. Without this flag, the num_predict budget gets eaten by the internal reasoning pass first, and response comes back empty. A lesson you only need to learn once.
  5. jq -nc to build the JSON — avoids shell-variable quoting hell.

macOS Shortcuts 設定

三個 shortcut,邏輯相同,差別只在參數:

  1. 新建 Shortcut:「Quick Action」類型
  2. 接收:在 Obsidian 中接收「Text」
  3. 動作 1:Get Text from Shortcut Input
  4. 動作 2:Run Shell Script

- Shell: /bin/zsh - Pass input: as arguments - Script: $HOME/bin/llm-helper.sh summary "$1"

  1. 動作 3:Replace Selection(用 stdout 蓋回去)
macOS Shortcuts 設定畫面:summary 任務的三個動作

三個 shortcut 分別命名 Obsidian Summary、Obsidian Translate、Obsidian Tag,到「System Settings → Keyboard → Keyboard Shortcuts → Services」綁 ⌘⌥1 / ⌘⌥2 / ⌘⌥3。

macOS Shortcuts setup

Three Shortcuts, same shape, different argument:

  1. New Shortcut → Quick Action
  2. Receives: Text from Obsidian
  3. Action 1: Get Text from Shortcut Input
  4. Action 2: Run Shell Script

- Shell: /bin/zsh - Pass input: as arguments - Script: $HOME/bin/llm-helper.sh summary "$1"

  1. Action 3: Replace Selection (with stdout)
macOS Shortcuts config screen: summary action chain

Name them Obsidian Summary, Obsidian Translate, Obsidian Tag, then bind ⌘⌥1 / ⌘⌥2 / ⌘⌥3 under System Settings → Keyboard → Keyboard Shortcuts → Services.


三個任務實測

我從自己的 Obsidian vault(這個 repo 的 content/ 資料夾本身就兼作 vault)為每個任務挑了三種不同類型的輸入,各跑 10 次取平均,三個任務共 90 次真實 Ollama 呼叫,零空回應。原始記錄在 tests/outputs/functional_test_results.jsonl,彙總在 tests/outputs/functional_test_summary.json。

任務平均推論時間平均 tokens主觀品質 (1-5)我會不會用
Summary1.6 秒61
Translate1.5 秒56
Tag1.1 秒34

推論時間比原本預估的 8–20 秒快很多——gemma4:e2b 只有 5.1B,這三個任務的輸出也都不長。倒是 tag 任務格式穩定度不如預期:90 次裡有好幾次吐出 # 開頭或英文詞,跟下面「限制與下一步」段的觀察一致。

Summary 樣本

輸入(節錄自我自己的 ARCHITECTURE.md 一段):

此監看倉並非強迫所有站點使用同一個 SSG、theme 或 deploy 目標。
每個站點保留最適合自身內容的技術棧。共享的是 knowledge/ skills/
pipeline/ metrics/ n8n-workflows/;不共享 SSG 選擇、視覺識別、
部署目標、是否雙語。

輸出(Gemma 4 e2b):

各站點可根據自身內容選擇最適合的技術棧,不強制使用統一的SSG、theme或部署目標。
僅共享知識、技能、管道、指標等資訊。SSG選擇、視覺識別、部署目標及雙語選項不共享。

Translate 樣本

輸入:The unified memory architecture on Apple Silicon allows large models to run without dedicated VRAM, but inference throughput remains bound by memory bandwidth, not compute.

輸出:

Apple Silicon 上的統一記憶體架構 (unified memory architecture) 允許大型模型在沒有專用
VRAM 的情況下運行,但推論吞吐量 (inference throughput) 仍然受限於記憶體頻寬
(memory bandwidth),而非運算能力 (compute)。

Tag 樣本

輸入(一段關於 RAG chatbot embedding retrieval 的筆記):

今天研究了怎麼幫 RAG chatbot 做 embedding retrieval。用 nomic-embed-text 把每篇文件
切成 300-500 字的 chunk,算 cosine similarity 找出最相關的前 5 段,再把這些段落塞進
prompt context 讓 LLM 生成回答。測試發現 chunk 太短會失去上下文,chunk 太長又容易稀
釋掉關鍵句子的權重,抓 top-k 的 k 值也要跟 chunk 大小一起調。晚點想試試看 hybrid
search,把關鍵字比對(BM25)跟向量相似度加權混合,看看能不能提升召回率。

輸出:

obsidian tag:
RAG
embedding retrieval
nomic-embed-text
chunking
context window
hybrid search
bm25

這次輸出正好示範了 tag 任務的問題——prompt 明明要求「不要解釋、不要其他文字、只回 tag 清單」,模型還是加了 obsidian tag: 前綴,而且是換行列點而不是逗號分隔,也沒有轉成 kebab-case。90 次功能測試裡這種格式偏移不是單一個案。

Three tasks, measured

I picked three different input types per task from my own Obsidian vault (this repo's content/ folder doubles as the vault), ran 10 trials per type — 90 real Ollama calls across the three tasks, zero empty responses. Raw records: tests/outputs/functional_test_results.jsonl; aggregates: tests/outputs/functional_test_summary.json.

TaskAvg inference timeAvg tokensSubjective quality (1-5)Do I keep using it?
Summary1.6s61
Translate1.5s56
Tag1.1s34

Much faster than the 8–20s I'd originally guessed — gemma4:e2b is only 5.1B and none of these three tasks need a long output. Tag format compliance was the shakier one: several of the 90 runs came back with a leading # or a stray English word, matching the observation in "Limits and what's next" below.

Summary sample

Input (excerpt from my own ARCHITECTURE.md):

此監看倉並非強迫所有站點使用同一個 SSG、theme 或 deploy 目標。
每個站點保留最適合自身內容的技術棧。共享的是 knowledge/ skills/
pipeline/ metrics/ n8n-workflows/;不共享 SSG 選擇、視覺識別、
部署目標、是否雙語。

Output (gemma4:e2b):

各站點可根據自身內容選擇最適合的技術棧,不強制使用統一的SSG、theme或部署目標。
僅共享知識、技能、管道、指標等資訊。SSG選擇、視覺識別、部署目標及雙語選項不共享。

Translate sample

Input: The unified memory architecture on Apple Silicon allows large models to run without dedicated VRAM, but inference throughput remains bound by memory bandwidth, not compute.

Output:

Apple Silicon 上的統一記憶體架構 (unified memory architecture) 允許大型模型在沒有專用
VRAM 的情況下運行,但推論吞吐量 (inference throughput) 仍然受限於記憶體頻寬
(memory bandwidth),而非運算能力 (compute)。

Tag sample

Input (a note on RAG chatbot embedding retrieval):

今天研究了怎麼幫 RAG chatbot 做 embedding retrieval。用 nomic-embed-text 把每篇文件
切成 300-500 字的 chunk,算 cosine similarity 找出最相關的前 5 段,再把這些段落塞進
prompt context 讓 LLM 生成回答。測試發現 chunk 太短會失去上下文,chunk 太長又容易稀
釋掉關鍵句子的權重,抓 top-k 的 k 值也要跟 chunk 大小一起調。晚點想試試看 hybrid
search,把關鍵字比對(BM25)跟向量相似度加權混合,看看能不能提升召回率。

Output:

obsidian tag:
RAG
embedding retrieval
nomic-embed-text
chunking
context window
hybrid search
bm25

This run is a good demonstration of the tag task's problem — the prompt explicitly says "no explanation, no other text, just the tag list," and the model still prepended obsidian tag:, one-per-line instead of comma-separated, and never converted to kebab-case. This format drift wasn't a one-off across the 90 functional-test runs.


跟原本用 Claude 比

指標Claude(之前)Gemma 4 e2b(現在)
每天 prompt 數~30
每次延遲1-3 秒
摘要品質5/5
翻譯品質5/5
Tag 品質4/5(有時太發散)
月成本(推估)Claude Pro 部分使用量NT$ 電費
私隱上雲本機

我的判斷不是「Gemma e2b 全面取代 Claude」,是把這三個重複任務從 frontier 模型卸下來——Claude 額度留給真的需要它的事(例如寫這篇文章的英文版)。

Compared to my previous Claude flow

MetricClaude (before)gemma4:e2b (now)
Daily prompts~30
Per-prompt latency1-3 s
Summary quality5/5
Translation quality5/5
Tag quality4/5 (sometimes too broad)
Monthly cost (est.)portion of Claude ProNT$ electricity
Privacycloudlocal

The point isn't "Gemma e2b replaces Claude." It's offloading these three repeated chores so frontier-model budget goes to work that actually needs it (like writing the English version of this article).


限制與下一步

  • 長文輸入:超過 ~3K token 的筆記,summary 開始忽略後半段。要靠先手動分段。
  • Tag 中英混雜:偶爾會吐出英文 tag。在 prompt 加「只用繁中名詞」之後改善但沒完全解決。
  • macOS Shortcuts 偶爾搶不到選取:Obsidian 的 markdown 預覽模式選取行為跟原始模式不同,這個我還在繞。

下一步打算把這套擴成第四個任務:「給定一段筆記,找出 vault 內可能相關的其他筆記」——這要接 embedding,會比現在這套複雜,會單獨寫一篇。

Limits and what's next

  • Long input: past ~3K tokens, summary starts dropping the back half. Manual chunking is the current workaround.
  • Mixed-language tags: occasional English tag slips in. The "Chinese nouns only" instruction helps, doesn't fully fix.
  • Shortcut selection misses: Obsidian's preview-mode selection behaves differently from source mode. Still working around this.

Next: extending this to a fourth task — "given this note, find related notes in the vault." That needs embeddings and gets meaningfully more complex; it'll be its own article.


常見問題

Q:為什麼不用 e2b 直接接 Obsidian 的 Smart Connections plugin? A:Smart Connections 是 embedding 為主,這篇做的是 generation。兩件事互補,不互斥。

Q:可以用更大的模型換掉 e2b 嗎? A:架構上完全可以——llm-helper.sh 的 MODEL 那一行改掉就好,其他都不用動。這台機器目前只裝了 gemma4:e2b(5.1B),沒有裝更大量級的版本,所以沒辦法在這裡給你「換更大模型後 tag 一次過率會不會提高」的實測數字。這是誠實的空白,不是我懶得測。

Q:Windows / Linux 怎麼複製這套? A:Shell script 直接通用。macOS Shortcuts 在 Windows 上對應 AutoHotkey、Linux 對應 xdotool + keybinding。邏輯相同。

FAQ

Q: Why not use Obsidian's Smart Connections plugin with e2b? A: Smart Connections is embedding-based. This article is generation. Complementary, not competing.

Q: Can I swap in a bigger model? A: Architecturally, yes — just change the MODEL line in llm-helper.sh. This machine only has gemma4:e2b (5.1B) installed; I haven't run a larger size, so I can't hand you real numbers on whether tag compliance improves with more parameters. That's an honest gap, not something I'm skipping out of laziness.

Q: Windows / Linux? A: The shell script ports directly. Replace macOS Shortcuts with AutoHotkey (Windows) or xdotool + a keybinding (Linux). Same shape.


共振站結論

波形評級:STEADY_PULSE

適合你,如果:

  • 用 Obsidian 寫筆記,且筆記量到了一定規模
  • 已經有 ollama 在跑、或願意花 30 分鐘設好
  • 想把 frontier 模型額度省給真正需要的事
  • 在意私隱:筆記內容不上雲

暫不適合,如果:

  • 你的筆記長度普遍超過 5K token(要等 streaming / 分段方案)
  • 不想碰 shell script 與 macOS Shortcuts

在 Ollama Library 看 gemma4:e2b →

Verdict

Waveform: STEADY_PULSE

Good fit if you:

  • Use Obsidian and have enough notes for the chores to recur daily
  • Have ollama already running, or are willing to spend 30 minutes setting it up
  • Want to free frontier-model budget for work that actually needs it
  • Care about privacy: notes never leave the machine

Skip if you:

  • Notes routinely exceed 5K tokens (wait for the streaming/chunking version)
  • Don't want to touch shell scripts or macOS Shortcuts

See gemma4:e2b on Ollama Library →