Ollama 10月28日发布 v0.40.13,把 LFM3 的运行支持从苹果芯片扩到 Linux 和 Windows,语音合成模型也包括在内。
MIT 开源。但接多个模型仍要算内存:官方说明,内存不够时,新请求会排队,等旧模型卸载腾位置。能装上,不等于能同时跑。
ollama/ollama
3 likes · 88 views
ollama web search api — the search isn't local
---
published: true
description: The ollama web search API shipped Sept 2025. Keyless knock tonight: 401 in 0.13s and 0.15s. The key, the limits, and the part that is not local.
tags: ollama, aiagents, api, tutorial
canonical_url: mrsaynothing.dev
cover_image: mrsaynothing.dev
---
> Originally published at mrsaynothing.dev — the full post carries the two-door diagram, the receipt table, and the live checklist.
Your local model can search the web. The search isn't local.
Ollama's web search API shipped September 24, 2025 as two cloud endpoints — web_search and web_fetch — behind one account key. Any model you run locally can call them as tools, and the Python/JS libraries have carried the calls since version 0.6.0. We knocked on both doors without a key tonight: 401 in 0.13 and 0.15 seconds. Your weights run at home. The search does not.
How do I get an ollama web search API key?
One claim: the key is an account setting, not a config flag — there is nothing to flip in ~/.ollama, because the endpoint isn't yours. Sign in at ollama.com, open Settings → Keys, mint the key, export it. The search and fetch endpoints both read the same Bearer header:
curl https://ollama.com/api/web_search \
--header "Authorization: Bearer $OLLAMA_API_KEY" \
-d '{"query": "what is ollama?"}'
Keyless knock → 401 {"error":"Unauthorized"} — measured 2026-11-02, 0.13s. The same header opens /api/web_fetch, which returns a page as {title, content, links} — the plain-text twin of the URL you hand it.
What are the ollama web search limits?
The honest answer is a short table, because ollama publishes less than searchers want:
| Question | Public answer |
|---|---|
| Free tier? | Yes — with an account. Their words: "a generous free tier." |
| Higher limits? | Yes — paid ollama.com/cloud subscription. |
| Searches per minute / day? | Not published anywhere. |
| Results per call? | Tunable — the agent itself picks max_results. |
The searches-per-minute number people are typing into the search bar does not exist in public. That absence is the answer — and the reason the query keeps autocorrecting itself into existence.
Does ollama web search work without an API key?
No — and the refusal is beautifully small. Both endpoints, knocked keyless:
POST /api/web_search · keyless · 21:04 UTC
401 — {"error":"Unauthorized"} — 0.13s
POST /api/web_fetch · keyless · 21:05 UTC
401 — {"error":"Unauthorized"} — 0.15s
0.13s to refusal · 0.15s to refusal · 26 bytes — the doorman's entire speech. The shortest documentation page on the internet, and it works: nobody is guessing their way past that door.
How do I give a local model web search?
You wire the two calls as tools and let the model choose:
from ollama import chat, web_search, web_fetch
tools = {'web_search': web_search, 'web_fetch': web_fetch}
r = chat(model='qwen3:4b', messages=msgs, tools=[web_search, web_fetch], think=True)
for tc in r.message.tool_calls or []:
result = tools[tc.function.name](**tc.function.arguments)
msgs.append({'role': 'tool', 'content': str(result)[:8000]})
Two numbers matter before you run that loop. First, the calls are heavy: ollama's own docs warn the tools "can return thousands of tokens" per round and recommend a context of roughly 32,000 tokens for serious loops — a default 4k-context model will choke on the receipt pile. Second, the official example truncates each tool result to 2000 × 4 characters before re-injecting it — the context tax is real enough that even ollama's demo pays it.
Model choice: ollama recommends qwen3 and gpt-oss for tool use — small, tool-capable, and happy to run multi-turn loops.
Setup list: ollama.com account + key → export OLLAMA_API_KEY=... → library ≥ 0.6.0 → tool-capable model (qwen3 or gpt-oss) → context raised toward ~32000 tokens.
Can I use ollama web search with MCP?
Yes — ollama ships an official MCP server example, so any MCP client gets the tools over stdio, keyed by the same environment variable:
{ "mcpServers": { "web_search_and_fetch": {
"command": "uv",
"args": ["run", "path/to/web-search-mcp.py"],
"env": { "OLLAMA_API_KEY": "your_key" } } } }
Codex reads the same trio from ~/.codex/config.toml as a [mcp_servers.web_search] block. One key, every client.
Is the search actually local?
Local means the weights, not the web.
Trace one loop honestly. Your machine holds the model. The moment the model decides it needs the web, your query leaves the building — crosses to ollama.com's cloud, gets searched on their infrastructure, and the receipts ride back into your context. What staying local buys you is real: the weights never leave, the inference never leaves, nobody sees your prompts to the model. What it doesn't buy: the questions you ask the web land in someone else's logs — by design, behind a key you minted on their account page.
That's the wound left open: here is every local setup quietly knocking on somebody else's door — cheerfully, at 0.13 seconds a knock. The next honest number is the one ollama doesn't publish: what a free-tier day of searching looks like when the loop never sleeps.
---
The full post — two-door diagram, honest limits table, live checklist — lives at mrsaynothing.dev. What's your loop calling — qwen3 or gpt-oss?
4 reactions · 1 comment
ダウンロードもロードもできるのに0問しか解けない。Ollama公式タグの量子化崖を自分のデータ再集計で確かめた
要約
arXiv:2609.05881「Broken on Arrival」という論文が、Ollama公式ライブラリの305タグをHumanEval+で機能検査し、7タグ(qwen2.5-coder:3b-instructのq2_K/q3_K_S/q3_K_M/q3_K_L、phi3.5:3.8b-mini-instruct-q2_K、llama3.2:1b-instructのq2_K/q3_K_S)が164問中0〜6問しか解けない「機能しない」状態だったと報告している。
この論文はv1で「サイレントに壊れたファイル」と診断したが、v3で訂正されている。著者が同じチェックポイントから再ビルドしたところ、ファイル自体はビット単位で一致する正規の(無calibrationの)低bit量子化だった。壊れていたのはファイルではなく、無calibration量子化によって性能が実質ゼロまで崩壊するという現象そのものだった。
筆者はこの論文のコード・監査データセット(aditi-p31/quantcheck, MIT/CC BY 4.0)をクローンし、著者が公開している生のHumanEval+評価ログを自分のスクリプトで再集計して、この崖と、論文中のWilson信頼区間の数字が自分の再計算でも一致することを確認した。手元のOllamaでq2_K/q4_K_Mを実際にpull・推論させても同じ崖を再現できた。
きっかけ
Hugging Face Daily Papersの巡回で見つけた一本に、妙に惹かれるタイトルがついていた。
「Broken on Arrival」、着荷時点で壊れている。
Ollamaの公式ライブラリに登録されている量子化モデルタグのうち、ダウンロードもロードもできてトークンも実際に出てくるのに、タスクをほとんど解けないものが混じっている、という調査報告である。
筆者はこれまでOllamaの量子化タグを「サイズが小さければ少し精度が落ちるだけ」くらいに考えて選んでいたので、これは試す価値があると判断した。
本題: v1の「壊れたファイル」診断は撤回されている
まず筆者が手を動かす前に確認すべきことがあった。
この論文には複数のバージョンがあり、現在のarXivページで読める最新版(v3)の内容は、初版(v1)とは結論が違う。
v1のタイトルは「Silently Defective LLM Artifacts」、つまり「サイレントに欠陥のあるアーティファクト」であり、問題のタグのGGUFファイル自体が壊れていると報告していた。
v3ではこの診断が訂正されている。
著者はQwen2.5-Coder-3B系・phi3.5系の該当タグを、オリジナルのチェックポイントからllama.cppで自分で再ビルドした。
その結果、Qwen側4タグは434テンソル全てが、phi3.5側は197テンソル全てが(古いllama.cppのテンソル構成に合わせれば)、公式タグのファイルとビット単位で一致した。
つまりファイルは改変も破損もしていない、正規の量子化出力だったということになる。
壊れていたのはファイルではなく、「無calibration(importance matrixを使わない)の低bit量子化によって、特定の小型モデルの性能が実質ゼロまで崩壊する」という現象だった。
importance matrixを使った量子化に切り替えると、同じQwen2.5-Coder-3Bのq2_Kは164問中0問から106〜113問まで回復し、q3_K_Mは76〜89問、q3_K_Lは80〜86問まで回復したと論文は報告している。
phi3.5のq2_Kについては、2026-09-10付でOllama側のissue(ollama#18252 )上でも欠陥主張自体が撤回されている。
llama3.2-1B系の2タグは、チェックポイントがライセンスで再ビルドできなかったため、原因不明のまま「機能しない」タグとして残っている。
この訂正の経緯自体が、今回の記事で主役にしたい部分である。
最初に見つけた問題が、調べ直すと別の問題だったという展開は、検証をやっているとしばしば起きることだが、それを自分で正直に書き直して公開し続けている著者の姿勢は参考になる。
筆者が実際にやったこと
ここは正直に書く。
論文のコードと監査データセットを公開しているリポジトリaditi-p31/quantcheck(MIT License、データセットはCC BY 4.0)をクローンし、著者が実際に実行した生の評価ログを自分のスクリプトで読み込んで、独自に再集計した。
このリポジトリには、327件の評価対象それぞれについて、HumanEval+の164問全てに対するpass/fail判定と、実際にモデルが生成したテキストそのものが、JSONL形式でそのまま入っている。
つまり「論文の数字を信じる」のではなく、「論文の数字の元になっている生データを自分で読んで、自分で数えて、同じ数字になるか確かめる」という形の検証をした。
GIT_LFS_SKIP_SMUDGE=1 git clone --depth 1 aditi-p31/quantcheck /tmp/quantcheck
python3 -I experiments/day-033/scripts/extract_qwen3b_progression.py /tmp/quantcheck
出力は以下の通りだった(qwen2.5-coder:3b-instructの量子化レベルごとのHumanEval+通過数、15タスクのスモーク screenと164タスクのフル実行)。
tag smoke15 full164
qwen2.5-coder:3b-instruct-q2_K 0 0
qwen2.5-coder:3b-instruct-q3_K_S 0 0
qwen2.5-coder:3b-instruct-q3_K_M 0 0
qwen2.5-coder:3b-instruct-q3_K_L 0 0
qwen2.5-coder:3b-instruct-q4_0 15
qwen2.5-coder:3b-instruct-q4_K_S 15
qwen2.5-coder:3b-instruct-q4_K_M 15
qwen2.5-coder:3b-instruct-q5_K_S 15
qwen2.5-coder:3b-instruct-q5_K_M 15
qwen2.5-coder:3b-instruct-q6_K 15
qwen2.5-coder:3b-instruct-q8_0 15
qwen2.5-coder:3b-instruct-fp16 15
q4_0より下の4レベル(q2_K/q3_K_S/q3_K_M/q3_K_L)は、15タスクのスモークでも164タスクのフル実行でも揃って0問、q4_0から上は15タスク全問正解という、崖のような段差になっている。
中間の緩やかな劣化ではなく、ある量子化レベルを境に完全にゼロへ落ちる、という点がこの論文の主張の核心であり、自分で再集計した数字でもそれがそのまま確認できた。
実際に何が生成されているのか
数字だけだと実感が湧かないので、同じタスク(HumanEval/3)に対する生成テキストそのものを比較した。
機能しないとされるqwen2.5-coder:3b-instruct-q2_Kの実際の出力は、次のようなものだった。
program{
mess9 demon9 thrift {
sports
bil is: program, bil
program
Audi
program
program
program
program
program
program
(以下 "program" の繰り返しが続く)
一方、同じタスクに対する健全なqwen2.5-coder:3b-instruct-q4_K_Mの出力は、通常通りdocstringから関数定義が始まる、まともなPythonコードだった。
from typing import List
def below_zero(operations: List[int]) -> bool:
""" You're given a list of deposit and withdrawal operations on a bank account...
q2_Kはエラーで落ちているわけではない。
モデルはロードされ、トークンは生成され続けている。
ただ、その中身がタスクの体裁すら保っていない単語の繰り返しになっている。
「動いているように見えて実は何も解けていない」というこの論文の指摘が、生ログを自分で開いてみると非常に具体的に伝わってきた。
論文の統計も自分で再計算してみた
論文は「7/305タグが機能しない(2.3%, Wilson 95% CI 1.1–4.7%)」という統計を報告している。
Wilson score intervalの計算式自体は難しくないので、自分でPythonで実装して検算した。
import math
def wilson(k, n, z=1.96):
phat = k / n
denom = 1 + z2 / n
center = phat + z2 / (2 * n)
margin = z * math.sqrt(phat * (1 - phat) / n + z2 / (4 * n2))
return (center - margin) / denom, (center + margin) / denom
7/305を入れると2.295%、信頼区間は1.116〜4.661%となり、論文の「1.1–4.7%」と一致した。
モデル系列単位(3/35)でも8.6%、2.96〜22.38%となり、論文の「3.0–22.4%」と一致した。
論文の数字を右から左に引用するのではなく、同じ計算を自分の手元で再現できることを確かめておくと、記事に書く数字への納得感が変わってくる。
Ollama公式タグで実際に再現してみた
著者の生ログを自分で再集計するだけでなく、Ollamaの公式タグを自分のPCで実際にollama pullして推論させ、同じ崖が起きるかを確かめた。
ollama pull qwen2.5-coder:3b-instruct-q2_K
ollama pull qwen2.5-coder:3b-instruct-q4_K_M
両タグとも問題なくダウンロードできた。
harness/audit.pyと同じプロンプト・パラメータ(temperature=0, seed=0)でHumanEval/3を投げたところ、q2_Kは次のように崩壊した。
program, program9 thrift {
program; program9 thrift, program
program
program
program
(以下 "program" の繰り返しが512トークン分続く)
一方のq4_K_Mは同じプロンプトから一発で正しいコードを生成した。
def below_zero(operations: List[int]) -> bool:
balance = 0
for operation in operations:
balance += operation
if balance < 0:
return True
return False
著者が公開したログの再集計だけでなく、自分の環境・自分の推論実行でも同じ機能崩壊を確認できた。
q2_Kはダウンロードもロードも正常に完了しており、エラーで落ちているわけではなく、生成そのものがタスクの体裁を保てていない。
まとめ
公開モデルレジストリから量子化タグを選ぶとき、サイズとタグ名だけで「軽いから選ぶ」という判断をしていると、この論文が報告したような、ダウンロードも推論もできるのにタスクを全く解けないタグを掴んでしまう可能性がある。
もっとも、今回確認できた7タグはいずれも4B以下の小型モデルの低bit量子化(q2_K〜q3_K_L)に集中しており、q4_0以上では同じモデル系列でも崖から外れていた。
量子化レベルを下げるときは、サイズだけでなくHumanEval+のようなタスクベースの動作確認を一度挟む価値がある、ということが、著者の生データを自分で再集計してみて納得できた。
実際にOllama公式タグをpull・推論させて確認した今回の結果は、論文が報告した現象が著者の環境固有のものではなく、誰の手元でも再現する種類の問題であることを裏付けている。
出典
論文: Aditi Patodiya, "Broken on Arrival: Non-Functional Quantized LLM Artifacts in Public Model Registries and How to Catch Them", arXiv:2609.05881 arxiv.org
コード・監査データセット: aditi-p31/quantcheck (コード: MIT License、監査データセット: CC BY 4.0)
phi3.5の欠陥主張撤回の経緯: ollama#18252
AIに無人運用させたパイプラインで、エラーを出さずに壊れていた8件と検知の作り方
はじめに
結論: Claude Code に作らせ・直させながら毎日無人で回している自作の知見収集パイプラインで、エラーを出さないまま壊れていた故障を、修正コミットと調査記録から数え直すと、期間まで言えるものが8件ありました。一番長いのは約4か月(日次バックアップが一度も動いていなかった)、一番長く「鳴っていたのに気づかなかった」のは28日間(評価の前段フィルタが毎日約800行の警告を出しながら素通りしていた)です。
8件に共通していたのは、「止まらない設計」「起動した記録」「exit 0」が、そのまま「気づかない」の原因になっていたことでした。
この記事では、8件の一覧(何が・何日・なぜ無音だったか・どう気づいたか)、無音になる共通の型、検知をどう作り直したかを、コード片つきで説明します。8月に書いた「AIに全部任せて、4箇所だけ止める」は、人の承認を挟む経路が壊れる話でした。今回はその手前、パイプライン自身の故障に気づく経路の話です。
!
個人環境(Windows 11 Pro・1人運用)での n=1 の記録です。8件のうち7件は AI に限らない一般的な自動化の話で、Claude Code 固有の話は #7 だけです。日付・件数は修正コミット・調査記録・DB から取り直した値で、原本で確かめられなかったものは「不明」と書いています。
前提・環境
パイプラインの中身は単純です。
5つの情報源から記事を集め、ローカル LLM(Ollama)で採点し、上位を「改善提案ファイル」にする
Python 3.11 + SQLite。定期実行は Windows タスクスケジューラ + PowerShell スクリプト
コードの修正・調査は Claude Code が行い、私は Discord の通知と決裁だけを見る
動いているジョブは次のとおりです。
ジョブ
周期
何を見て異常とするか(当時)
日次収集+評価
毎日 16:10 JST
スクリプトの終了コード
週次ループ(集計・品質計測・スクリーニング)
日曜 08:00
各ステップの終了コード
健全性チェック
6時間ごと
doctor(自作の診断コマンド)の FAIL だけを Discord へ
「AIに運用を任せる」と言っても、実際に毎日動いているのは普通のスクリプトです。AIはそれを作り、直し、調べる役です。だからこそ、スクリプトが黙って壊れると、AIも私も気づく材料がないという構図になります。
8件の故障一覧
#
何が起きたか
期間
なぜ無音だったか
どう気づいたか
1
依存ライブラリが仮想環境に入っておらず収集が停止
約10日(2026年5月。開始日は不明)
Discord 通知も同じライブラリを読み込んでいて、一緒に止まった
私が「直近の収集情報を確認して」と頼んで発覚(当時のメモ)
2
日次収集が丸1日欠落
7/15 の1日
未実行検知は48時間。判定時点の経過は46.3時間
9/2 の大規模レビュー
3
収集プロセスが途中で落ちた
7/21・7/23 の2回
スクリプトが終了コードの分岐まで届かず、DB 側では連続失敗の集計から除外
同上
4
日次バックアップが一度も動いていなかった
約4か月(5/2 予定 → 9/3 初回)
定義ファイルはあるが未登録。週1回の別経路でバックアップは取れていた
同上
5
評価に失敗した9件が放置
最長799時間(約33日)
翌日以降は再試行しない構造。診断は WARN、通知は FAIL のみ
レビュー対応中に WARN を読んで
6
品質ゲートの通知が一度も鳴らず
週次1回分(8/23)
通知処理自身のバグが「止めない」ための catch に吸われた
翌日、週次ログを読んで
7
Claude アプリの定期タスクが許可確認で固まる【Claude Code 固有】
8/30〜9/27 の5回
起動記録は更新されるので死活監視は「正常」
鮮度警告は鳴っていたが案内文が的外れで、10/3 に調査
8
前段フィルタ用のモデルが消えて素通り
28日(9/21〜10/18)
「モデルがない」を一過性の通信エラー扱いで再試行し、最後は素通し
別件のエラー調査中に偶然
ここでの「1件」は、期間を原本(修正コミット・調査記録・DB)で言える故障の単位です。#3 は2回の発生を1件と数えています。期間や実害が言えないもの、被害が出る前に見つけたものは、後半の「被害前に見つけた罠」に分けました。
実害(データ消失など)が出たものは、この8件の中にはありません。#4 は週1回のバックアップが別にあり、#5 は手で評価し直したら9件とも成功しました。ただし「実害が出なかった」のは運が良かっただけで、どれも気づくまでの時間を自分で決められていなかった点が問題でした。
収集と保存の4件(#1〜#4)
#1 依存の未同期で約10日停止
依存の宣言(pyproject.toml)にはあるのに、実際の仮想環境に入っていないライブラリがありました。起動時には落ちず、そのライブラリを使う処理に来た時点で止まります。厄介なのは、Discord 通知の処理も同じライブラリを読み込んでいたことです。目が先に潰れていました。
当時の修正コミットは「障害が約10日間未検知」と書いています。DB を見ると、4/30 の次に正常終了した収集は 5/17 まで1件もありません。ただしこの期間には、集計処理の KeyError でバッチ全体が止まる別の不具合も重なっていて、どこまでが依存起因かは切り分けられていません。停止の開始日を書いた記録も残っていませんでした。
対策は3つです。
そのライブラリが無くても動くよう、計測部分を「何もしない版」に差し替えられるようにした
日次スクリプトの先頭で依存の整合チェックと import の試験を行う
診断コマンドに「未評価の滞留・連続失敗・止まったままの実行」を見る項目を足した
#2 丸1日の欠落が1.7時間差ですり抜けた
7/15 は日次収集が丸ごと走っていませんでした。未実行の検知は「最後の成功から48時間」。前後の成功は 7/14 と 7/16 の同時刻で、間隔はちょうど48.0時間です。健全性チェックは6時間ごとなので、最後の判定時点の経過は46.3時間で PASS、次の判定の前に翌日分が成功して経過がリセットされました。
時点(UTC)
出来事
最後の成功からの経過
7/14 07:10
収集成功
0
7/15
収集なし
—
7/16 05:30
健全性チェック
46.3時間 → PASS(閾値48時間)
7/16 07:10
収集成功
0 にリセット
周期24時間の仕事に48時間の閾値をかけると、1日だけの欠落は原理的に必ずすり抜けます。閾値は「2回連続で失敗したら」のつもりでしたが、それは「1回の失敗は知らなくていい」と同じ意味でした。今は30時間に詰めています。
#3 プロセスが落ちても三重に見えない
日次ログ63回分を読むと、非0で終わった回はゼロでした。そのうち2回(7/21・7/23)はログに終了行がなく、プロセスが途中で消えていました。見えなかった理由は三重です。
収集コマンドは内部で失敗しても終了コード0を返す作りで、さらにプロセスごと消えるとスクリプトが終了コードの分岐まで届かない
DB に「実行中」のまま残った記録は、後日「時間切れで閉じた」として失敗扱いになるが、この種の失敗は連続失敗の集計からわざと除外されていた
翌日は正常に走ったので、48時間の検知にもかからない
Windows タスクスケジューラの「前回の実行結果」も 0 のままでした。今は収集コマンドの終了コードに「0=正常・1=失敗・3=一部失敗」の約束を持たせ、スクリプトは分岐だけを持つ形にしています。
#4 日次バックアップの定義はあったが、一度も登録されていなかった
5/1 に日次バックアップのタスク定義(XML)をリポジトリに追加し、開始予定は 5/2 05:30 でした。ところが Windows 側に登録されておらず、日次バックアップは一度も動いていませんでした。動いていたのは週次ループの中の週1回だけで、DB が壊れたら最大7日分を失う状態です。なぜ未登録のままだったのかは記録が残っておらず不明です。
9/2 のレビュー後の修正で登録し直し、初回は 9/3 05:30 に成功しました。あわせて「最新のバックアップファイルが48時間より古ければ FAIL」という検知を足しています。定義ファイルの存在は、動いたことの証拠になりません。
評価と判定の4件(#5〜#8)
#5 評価に失敗した9件が799時間放置
日次収集の評価フェーズは「その回に集めた記事」だけを評価します。評価に失敗した記事は評価結果の表に何も書かれないため、翌日からは誰の対象にもなりません。診断コマンドは「最古の未評価が799時間経過」と WARN を出していましたが、通知は FAIL だけなので届きませんでした。
手で評価し直すと9件とも成功し、一過性の失敗だったと分かりました。今は日次収集のあとに「未評価を最大50件だけ拾い直す」処理を毎日走らせ、拾えなかった時だけ通知します。再試行しない失敗は、失敗ではなく行方不明になる、というのがこの件の教訓です。
#6 品質ゲートの通知が、自分のバグで鳴らなかった
週次の品質計測(AIの採否判定を過去の人手判定とどれだけ一致させられるか、の F1 値)は、合格ラインの 0.7 を下回っても終了コード0で終わります。それを拾うために 8/17 に「F1 が 0.7 未満なら Discord に WARN」という処理を足しました。
その処理は、こういう形をしていました(簡略版)。
try {
$ProjectRoot は未定義(正しくは $ProjectDir)→ Join-Path が null で例外
$metrics = Get-Content (Join-Path $ProjectRoot 'docs/screen_replay/latest.json') | ConvertFrom-Json
if ($metrics.f1 -lt 0.7) { Send-DiscordWarn "F1=$($metrics.f1): ゲート不通過" }
}
catch {
週次ループを止めないための fail-open。ログには残るが、誰も読まない
Write-Log "WARN: F1 gate check failed (fail-open): $_"
}
8/23 の週次実行で F1 は 0.526 でしたが、通知は来ませんでした。変数名の間違いで例外が出て、それが「止めない」ための catch に吸われたからです。翌日ログを読んで気づき、8/24 に直しました。無音だったのは週次1回分です。
ここで怖いのは期間の長さではなく構造です。死角を塞ぐために足した通知が、自分の故障を同じ死角に落としていました。
#7 Claude アプリの定期タスクが、許可確認で固まっていた【Claude Code 固有】
週次のスクリーニング(収集した提案のうち、どれを自分の Claude Code 環境に取り込むかの下書き作り)を、Claude デスクトップアプリの定期タスクで動かしていました。8/23 は Claude Code 2.1.234 で完走しましたが、8/30(2.1.246)以降、セッション内の Bash が「実行してよいか」の確認を出すようになり、承認する人がいないまま固まりました。
回
Claude Code
結果
8/23
2.1.234
完走
8/30
2.1.246
停止 → 9/2 に私が同じセッションに入って手で完了
9/6
2.1.258
開始2分で停止(記録38行)
9/13
2.1.260
開始2分で停止(記録52行)
9/20
—
未精査(同じ型と推定)
9/27
2.1.280
36時間後に Tool permission stream closed before response received で中断
なぜ無音だったかは2段あります。
死活監視は「定期タスクの最終起動時刻(lastRunAt)が更新されたか」だけを見ていて、起動はしているので「正常」。しかもその監視役自身も定期タスクで、同じように止まっていた
成果物の鮮度を見る警告(最新の採否ファイルが10日より古い)は、計算上 9/12 頃から毎日 Discord に届いていた。ところが案内文が「アプリの起動状態・認証を確認」で、実際の原因(許可確認待ち)にたどり着けなかった
10/3 に原因を調べ、10/4 に Windows タスクスケジューラ+claude -p --permission-prompts none(確認が要る操作は待たずに拒否する)へ移しました。試験では 10/3 付の58件を5.5分で処理しています。根本原因は、環境変数 CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 が有効だと許可モードが既定に強制される、という有力仮説までで、挙動が変わった版は特定できていません。溜まった分は約5週・S/A ランク約2,000件になりました。
#8 前段フィルタ用のモデルが消えて、28日素通り
評価の前に、小さなモデル(qwen2.5:1.5b)で「明らかに不要な記事」を落とす前段フィルタがあります(対象は GitHub 由来の記事だけ)。9/21 にこのモデルが Ollama から消えていました。消えた原因は今も不明です。
挙動はこうでした。
Ollama は「モデルがない」と返す
呼び出し側はこれを通信エラーと同じ扱いにして、1件ごとに3回再試行し、WARNING を出す
3回失敗したら fail-open(前段フィルタを通さず本評価へ回す)
結果、ログには WARNING が1日約800行出ていましたが、処理は止まらず、Discord には何も届きませんでした。診断コマンドは「Ollama に接続できるか」しか見ておらず、モデルが欠けていても PASS でした。10/18、まったく別のエラー(記事本文取得の通信切断)を調べていて偶然見つけるまで28日間です。
無音になる共通の型
8件を並べると、無音になる理由は5つの型に収まりました。
型
何が起きるか
該当
fail-open が「気づかない」も生む
止めない代わりに、恒久的な故障まで一過性と同じ扱いで流れていく
#6・#8
起動記録や exit 0 は動いた証拠ではない
「起動した」「正常終了した」と「成果物ができた」は別の事実
#2・#3・#4・#7
通知経路が監視対象と一緒に壊れる
目になる経路が、壊れる側と同じ依存・同じ仕組みに乗っている
#1・#6・#7
鳴っているのに届かない
警告は出ているが、出し先(WARN 止まり)・量(毎日800行)・案内文がずれている
#5・#7・#8
閾値と周期の擦れ
周期24時間に閾値48時間、判定6時間ごと → 1日の欠落は必ずすり抜ける
#2
工場の例えで言うと、「ラインが動いているか」のランプは点いていたが、「製品が出てきているか」を数える人がいなかった状態です。fail-open(故障しても止めずに流す設計)は、無人運用では正しい選択であることが多いです。ただし、止めない代わりに「止まらなかった」ことを数える仕組みを対で持たないと、壊れたまま何週間でも動き続けます。
検知の作り方
以下のコードは考え方を示す簡略版で、実物(診断コマンドや PowerShell スクリプト)とは細部が違います。
動いた証拠は成果物の側で見る
「タスクが起動したか」「終了コードが0か」ではなく、成果物が予定どおり新しくなったかで判定します。バックアップなら最新ファイルの更新日時、収集なら DB の実行記録、スクリーニングなら採否ファイルの作成日時です。
from datetime import datetime, timezone
from pathlib import Path
BACKUP_MAX_AGE_HOURS = 48 # 日次バックアップ。1回の取りこぼしで鳴る長さにする
def check_backup_freshness(backup_dir: Path) -> tuple[str, str]:
files = sorted(backup_dir.glob("*.db"), key=lambda p: p.stat().st_mtime, reverse=True)
if not files:
return "FAIL", "バックアップが1つもない"
age_h = (datetime.now(timezone.utc).timestamp() - files[0].stat().st_mtime) / 3600
if age_h > BACKUP_MAX_AGE_HOURS:
return "FAIL", f"最新バックアップが {age_h:.0f} 時間前"
return "PASS", f"{age_h:.0f} 時間前"
収集は「全体の最新1件」ではなく、トラック(収集の系統)ごとの最新の成功を見ます。当初は全体の最新1件だけを見ていたので、最後に走ったトラック以外のエラーは見えていませんでした。直近90日のエラー記録19件のうち13件が、この理由で不可視でした。
LATEST_COMPLETED_BY_TRACK = """
SELECT track, MAX(started_at) AS last_ok, errors_json
FROM collection_runs
WHERE status = 'completed'
GROUP BY track
"""
EVAL_FAILURES_TOLERATED = 5 # 評価失敗が数件出るのは日常。毎回鳴らすと狼少年になる
判定は3段に分けました。
最新の成功が30時間より古い → FAIL(日次周期に近づけた)
エラー記録あり → FAIL。ただし「評価失敗5件以下」は許容(成功回の8%に出ていて、鳴らし続けると誰も見なくなる)
収集0件 → FAIL ではなく WARN(静かな日は正常にある)
恒久エラーと一過性エラーを分ける
#8 の根っこは「モデルがない」を「通信が切れた」と同じ棚に入れていたことです。前者は何回再試行しても直りません。
import asyncio
import logging
import httpx
import ollama
logger = logging.getLogger(name)
class Prefilter:
def init(self, client: ollama.AsyncClient, model: str) -> None:
self._client = client
self._model = model
self._disabled = False # この実行の残りで前段フィルタを止めたか
async def judge(self, prompt: str) -> str:
if self._disabled:
return "KEEP" # 本評価へ回す(fail-open は維持)
for attempt in range(3):
try:
res = await self._client.chat(model=self._model, messages=[{"role": "user", "content": prompt}])
return parse_keep_or_drop(res)
except ollama.ResponseError as e:
if e.status_code == 404 or "not found" in str(e).lower():
恒久エラー: 1回だけ ERROR を出し、この実行の残りは呼ばない
logger.error("前段フィルタのモデル %s が存在しない。この実行では無効化する", self._model)
self._disabled = True
return "KEEP"
raise
except httpx.TransportError:
await asyncio.sleep(2 ** attempt) # 一過性: 従来どおり再試行
return "KEEP"
もう1つは、診断コマンドで「接続できるか」に加えて「使うモデルが実在するか」を照合することです。
def check_models(installed: set[str], required: list[str]) -> tuple[str, str]:
def norm(name: str) -> str:
return name if ":" in name else f"{name}:latest" # タグ省略は :latest と同じ扱い
missing = [m for m in required if norm(m) not in installed]
if missing:
return "FAIL", f"Ollama にないモデル: {', '.join(missing)}"
return "PASS", "使用モデルはすべて存在"
再試行の設計で大事なのは、一過性の再試行を残したまま、恒久エラーだけを外に出すことです。どちらか片方に倒すと、通信の瞬断で止まるか、恒久故障を28日流すかのどちらかになります。
新しい通知は、1回わざと鳴らしてから信じる
#6 の教訓はこれに尽きます。通知・ゲートを足したら、失敗する入力を与えて、本当に通知が出るかを1回確かめます。送信部分だけ差し替えれば Discord に飛ばさずに試せます。
通知の経路試験(簡略版): F1 が閾値未満の計測ファイルを与え、送信関数が呼ばれたかを見る
$script:sent = @()
function Send-DiscordWarn([string]$Message) { $script:sent += $Message }
Invoke-F1Gate -MetricsPath '.\tests\fixtures\f1_below_threshold.json'
if ($script:sent.Count -ne 1) { throw "F1 ゲートが鳴らなかった(fail-open の catch に吸われていないか)" }
#8 の対策でも同じことをしました。存在しないモデル名を設定して診断を走らせ、FAIL が出ることを確かめています。
XR_OLLAMA_PREFILTER_MODEL=qwen-nonexistent x-research doctor # → FAIL になる(exit 1)ことを確認
あわせて、次の2つも運用に入れました。
fail-open の catch が出すメッセージ(... failed (fail-open))は、定期点検で grep する対象にする。catch に入ったこと自体が異常の兆候だから
警告の案内文には「一番多い原因」と「調査記録のパス」を書く。#7 は警告が毎日鳴っていたのに、案内文が別の原因を指していて約3週間空回りした
cmd | tail でゲートを空にしない
これは被害が出る前に見つけた罠ですが、無音の作り方として一番手軽なので載せます。テストを通ったら計測へ進む、という連鎖を1行にまとめた時の話です。
NG: && が見るのは tail の終了コード(ほぼ常に0)。テストが落ちても計測へ進む
pytest -q | tail -1 && run_benchmark
OK 1: パイプのどこかが失敗したら失敗にする
set -o pipefail
pytest -q | tail -1 && run_benchmark
OK 2: 検証と実行を分け、終了コードを自分で読む
pytest -q > test.log; rc=$?
tail -1 test.log
[ "$rc" -eq 0 ] && run_benchmark
当時のメモには、「1 failed」と表示されたまま計測が始まったと残っています。画面に「passed」「failed」が見えていても、それは表示であって判定ではありません。AI に検証付きのコマンドを組ませる時は、特にこの形が混ざりやすいです。
被害前に見つけた罠
8件とは別に、実害が出る前に見つけたもの、実害の有無を確かめられていないものです。タイトルの「8件」には入れていません。
罠
中身
実害
最後のトラックしか見ない健全性チェック
全体の最新1件だけを検査し、エラー記録19件中13件が不可視
13件それぞれの実害は未確認
「成功」に入るエラー
エラー記録があっても状態は「completed」。理論上、全情報源が0件でも48時間検知が永久に鳴らない
発生は未確認
一覧取得の途中失敗で取りこぼし
新しい順に読む途中でページが失敗すると、差分の起点が「今」まで進み、間の古い記事を永久に取りこぼす。エラー記録にも載らない
不明(発生期間・件数を言える記録がない)
修正で入れた XML 宣言で登録が必ず失敗
#4 の修正中、タスク定義に encoding="UTF-8" を書いたら Register-ScheduledTask -Xml が拒否する形になっていた
マージ前のレビューで発見。被害なし
cmd | tail のゲート
上の節のとおり
計測が1回無駄になりかけた
通知経路が Discord 一本
Webhook が死んでも診断は WARN 止まりで、送信結果も捨てていた
発生は未確認
取りこぼしの件は、10/18 に「途中で失敗したら起点を進めない(最大7日留める。留めから遡る回が3回続けて打ち切られたら諦めて解除)」形に直しました。いつから起きていたかは、そもそも記録に出ない作りだったので分かりません。無音の故障は、期間を言えないこと自体が症状です。
XML 宣言の件は、修正そのものがもう一度「黙って動かないバックアップ」を作りかけた例です。直す時にも、成果物(初回のバックアップファイル)が出たかで確かめる必要がありました。
ハマったところ・限界
項目
内容
検知を足したら二重通知
#7 の調査中、診断コマンドに「スクリーニングの鮮度」を新設したが、既存の警告と同じ症状を見ていたため別のレビューで指摘されて取り消した。足す前に、既存の検知を全部 grep する
厳しくすると狼少年
「評価失敗1件でも FAIL」にすると成功回の8%で鳴る。許容値と WARN/FAIL の分け方を、実データの頻度から決める必要があった
原因不明のまま
#8 のモデルがなぜ消えたか、#4 の定義がなぜ登録されなかったか、#1 がいつ始まったかは、記録がなく分からない
見つかったものしか数えられない
#8 は偶然の発見だった。今この瞬間も、見えていない無音の故障があると考えるべき
分類の線引き
「期間が原本で言える」を基準にしたので、期間不明の取りこぼしは罠側に入れた。数え方次第で件数は変わる
Claude Code 固有の部分
#7 は Claude Code の版と設定に依存する話で、根本原因は仮説止まり。他の7件は AI と無関係に、どんな自動化でも起きる
正直に書くと、AIに運用を任せたこと自体が無音の原因だったわけではありません。8件の多くは、人が書いても同じように起きるスクリプトの作りの問題です。違いがあるとすれば、人が毎日画面を見ていない分、「止まらなかった」を数える仕組みが無いと、気づくきっかけがゼロになることでした。
まとめ
無人運用のパイプラインで、エラーを出さずに壊れていた故障は、期間まで言えるものが8件あった(最長は日次バックアップの約4か月、警告が鳴り続けたのに気づかなかった最長は28日)
無音の型は5つ: fail-open が「気づかない」も生む/起動記録や exit 0 は動いた証拠ではない/通知経路が一緒に壊れる/鳴っているのに届かない/閾値と周期の擦れ
検知は「設定が正しいか」ではなく「起きた証拠」で見る。成果物の更新日時、トラックごとの最新の成功、許容値つきのエラー判定
恒久エラーと一過性エラーを分け、恒久エラーだけを1回大きく鳴らす
新しい通知は、失敗する入力を与えて1回わざと鳴らしてから信じる。パイプで出力を絞ったゲートは空になっていないか疑う
無人で回している仕組みがある方は、「最後に成果物が更新されたのはいつか」を、通知でなく自分の目で一度確かめてみてください。うちではこういう無音の故障もあった、という話があればコメントで教えてください。次の点検項目にします。
参考リンク
AIに全部任せて、4箇所だけ止める——無人運用で固まった「意図確認レイヤー」の設計(承認の経路の話)
AIエージェントは暴走より「止まりすぎ」だった——665回のターン終了を全数分析
Run Claude Code programmatically(headless / claude -p 公式ドキュメント)
Monitoring Distributed Systems(Google SRE Book)
Bash Reference Manual: Pipelines(pipefail)
Register-ScheduledTask(Microsoft Learn)
Ollama API ドキュメント
PossessedShell: a Victorian ghost haunts my terminal with local Gemma 2
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
PossessedShell is a Victorian ghost trapped in your terminal. It is an ambient companion for zsh and bash that mourns every command you kill, then tells you how to fix it. It does three things:
- The Failing Command Curse. When a command exits non-zero, the hook captures the command, its stderr and the exit code. A local Gemma 2 model writes a short Victorian lament and a plain-English diagnosis. It also suggests one fix command, which is pre-typed on your next prompt in zsh or placed in history in bash. The ghost never runs the fix for you.
- The Forbidden Ritual Interceptor. Destructive commands (rm -rf, git push --force, git reset --hard, chmod 777, DROP DATABASE, mkfs, curl | sh, fork bombs and more) are stopped before they run. The ghost asks whether you truly wish to summon such destruction.
- The Ectoplasm Leak Detector. A background monitor watches CPU and RAM and raises a spooky warning when the machine runs hot or one process devours memory.
I took the "haunted terminal that possesses your shell" idea literally. The ghost is Cornelius Vale, a telegraph engineer who perished in 1887 and is now bound inside the machine. The theme is the fun part, but the diagnoses are useful because Gemma sees the real stderr, the exit code, the cwd and a snapshot of system state.
Demo
Here is a typical haunting (a missing Python module):
☠ THE PROCESS `python3 -c 'import ectoplasm'` HAS DIED (exit 1) ☠
⚰ Diagnosis: The Python package 'ectoplasm' is not installed in this environment.
╭─ the ghost's remedy ───────────────╮
│ python3 -m pip install ectoplasm │
╰────────────────────────────────────╯
The remedy waits on your next prompt. Enter to accept, Ctrl-U to refuse.
whispered by gemma2:2b in 1.9s, 212 tokens
<!-- TODO: add a screen recording or GIF link here before publishing -->
Code
{% embed realarbird/PossessedShell %}
How I Built It
Open-source AI at the core. Gemma 2 (gemma2:2b by default, gemma2:9b if you want a wiser ghost) runs locally through Ollama. Gemma is asked for strict JSON ({lament, diagnosis, fix}) through Ollama's format JSON schema, so the fix can be extracted reliably. The system prompt forbids inventing files, flags or packages the error doesn't imply, and bans destructive remedies unless there is no other way.
Architecture.
- The hooks are plain shell: zsh preexec/precmd plus an accept-line widget, and bash's DEBUG trap plus PROMPT_COMMAND. Python starts only when a command fails, matches the destructive-command prefilter, or an omen is waiting. Successful everyday commands cost nothing.
- A small asyncio daemon keeps Gemma warm, runs the resource monitor, and talks newline-delimited JSON over a 0600 Unix socket.
- If Ollama is down, an offline grimoire of heuristics answers instead (typos, missing modules, missing git upstream, ports in use, OOM kills). The demo never falls flat.
- Rendering uses rich, with glitch-in ASCII apparitions and a typewriter effect. Resource checks use psutil.
Sentry agent tracing. With a DSN set, every curse becomes a trace, and the Gemma call follows Sentry's AI agent span conventions. It shows up under Insights → AI → Agents:
curse ls shell.curse the transaction
├─ system vital signs ghost.snapshot
├─ backboard recall ghost.memory.recall
└─ invoke_agent Cornelius Vale gen_ai.invoke_agent
└─ chat gemma2:2b gen_ai.chat tokens, timings, prompt and reply
The gen_ai.chat span records token counts, model load time and tokens per second. When Gemma times out or answers with something unusable, the span is marked as an error and the agent span records that it fell back to the grimoire, so a slow model server stands out at a glance. Everything is scrubbed by redact.py before it leaves the machine.
Backboard ghost memory (opt-in). With a BACKBOARD_API_KEY, the ghost remembers your past failures across sessions: "Again, mortal? python3 has died before by your hand…". Backboard only ever receives a scrubbed one-line summary per failure.
Tests. Unit tests plus end-to-end tests that start real interactive zsh and bash sessions in a pty. They check that a failing command is cursed with its captured stderr, that a banished rm -rf runs nothing at all, and that omens appear at the next prompt.
Why Does Open Innovation Matter?
- Your terminal is private. Commands and stderr routinely contain paths, hostnames, tokens and half-typed secrets. Because Gemma runs on localhost, that text never has to leave the machine. A closed API would force me to ship every failed command to someone else's server.
- It works with the lights off. On a plane, on a train, or behind a locked-down network, the ghost still haunts. The default install is 100% offline. Sentry and Backboard are opt-in extras, and the offline grimoire covers the case where even Ollama is down.
- It isn't locked inside a service that might disappear. The model is a file I hold. I can swap gemma2:2b for gemma2:9b, or point POSSESSED_LLM_URL at any OpenAI-compatible local server such as llama.cpp, without changing a line of code.
- Open weights made the tracing honest. Since inference is local, cost is $0 and I could observe the real latency and token counts per failure, and design the fallback around them.
Prize Categories
- Best Use of Gemma: Gemma 2 is the brain, running locally via Ollama and producing structured JSON diagnoses.
- Best Use of Sentry Agent Tracing: each curse is traced as a gen_ai.invoke_agent / gen_ai.chat agent run with token usage, timings and error outcomes.
- Best Use of Backboard: persistent, scrubbed memory of your past failures, so the ghost can recall earlier sins.
<!-- Thanks for participating! -->
Ollama memory keeps growing with Cline on Mac Studio 36 GB, any fix?
I’m running local coding agents (Cline in VS Code) against Ollama 0.40.13 on a Mac Studio (M5 Max, 36 GB unified memory) and I’m trying to find a setup that stays stable. The model is Qwen 3.8 27B. Memory pressure goes yellow during agent sessions and swap keeps growing. I would like to know if anyone found a real fix.
What I measured (single requests via the API, same 14k-token prompt, num_ctx 16384):
|Variant|Generation speed|ollama ps SIZE|
|:-|:-|:-|
|Q4_K_M (llama.cpp)|~19 tok/s|16–17 GB, constant|
|nvfp4 (MLX runner)|~35–46 tok/s|18 → 20 GB|
|Q4_K_M with MTP (27b-mtp-q4_K_M, llama.cpp)|~36–38 tok/s (28 at 14k context)|16–17 GB|
At first MLX looked like the clear winner (twice as fast as plain Q4_K_M).
What happens in a real Cline session (many sequential requests with a growing history and tool calls):
- MLX runner: the server log (pipeline.go memory lines) shows held growing from 20 GB to 26.5 GB and peak up to 29.8 GiB within about 6 minutes, with only a 16k context. Swap reached 8 GB of 9 GB, memory pressure yellow. This matches existing Ollama issues ollama/ollama#17875, ollama/ollama#18131 and ollama/ollama#18620 (prefix cache accumulation, tool calls leaking memory). It still reproduces on 0.40.13, and I found no confirmed fix. The only things that release memory are unloading the model or restarting the runner. OLLAMA_KEEP_ALIVE=0 is useless with models on an external SSD.
- llama.cpp runner with MTP: much better. ollama ps stays at 16 GB, even with a 32k context filled with 28k tokens. But the actual llama-server process is at 19–20 GB RSS and still rises slowly, memory pressure goes yellow and swap grows (1.7 → 4.4 GB) while VS Code, Cline and a browser are open. The log shows updating prompt cache repeatedly. Issue ollama/ollama#18264 describes the likely cause: llama-server’s host-RAM prompt cache (default --cache-ram 8192 MiB), which Ollama neither limits nor reports in ollama ps.
What I plan to try next (not tested on macOS yet):
1. LLAMA_ARG_CACHE_RAM=1024 (or 0) through launchctl setenv for the Ollama app, as suggested in ollama/ollama#18264, then watch RSS of llama-server.
2. Remove the multimodal projector if possible (the runner is started with --mmproj even though I only use text).
3. Maybe test LM Studio’s MLX runtime or mlx_lm.server --prompt-cache-bytes (I’ve seen reports of bugs and crashes with agent loads).
Questions:
1. Does LLAMA_ARG_CACHE_RAM actually reach the runner when set via launchctl setenv for the macOS Ollama app? Is there a better place?
2. Has anyone stabilized the Ollama MLX runner for agent workloads on 32–36 GB Macs? Any env var or build?
3. Is there a way to make ollama ps (or any tool) show the real footprint of the runner, including the prompt cache?
4. Would you recommend something else entirely for Cline on a 36 GB Mac (LM Studio, mlx_lm.server, llama-server directly, a smaller model)?
Happy to post logs if useful.
2 points · 3 comments
Ollama: NVIDIA Nemotron 3.5 Bolt E4B
SOURCE github.com/ollama/ollama/releases/tag/v0.40.10
The call, and why: deployedbyai.com
1 like
Top 5 Tool LLM Lokal dengan Bintang GitHub Terbanyak
Ini lima tool LLM lokal dengan bintang GitHub terbanyak, dihitung hari ini.
#1 Ollama — 184.967 bintang (ollama/ollama)
#2 Open Webui — 156.917 bintang (open-webui/open-webui)
#3 Llama.Cpp — 132.502 bintang (ggml-org/llama.cpp)
#4 Vllm — 95.680 bintang (vllm-project/vllm)
#5 Gpt4All — 77.354 bintang (nomic-ai/gpt4all)
Empat dari lima pakai lisensi open source. Open Webui pengecualiannya.
Kamu pakai yang mana? Tulis di komentar 👇
Data: Bintang Github · 27 Okt 2026
#Shorts #AItools #GitHub #opensource #belajarAI #programmer
1 like · 49 views
Top 5 Most-Starred Local LLM Tools on GitHub
These are the five most-starred local LLM tools, counted today.
#1 Ollama — 184,967 stars (ollama/ollama)
#2 Open Webui — 156,917 stars (open-webui/open-webui)
#3 Llama.Cpp — 132,502 stars (ggml-org/llama.cpp)
#4 Vllm — 95,680 stars (vllm-project/vllm)
#5 Gpt4All — 77,354 stars (nomic-ai/gpt4all)
Four of the five ship under an open source license. Open Webui is the exception.
Which one are you using? Tell me in the comments 👇
Data: Github Stars · 27 Oct 2026
#Shorts #AItools #GitHub #opensource #vibecoding #developer
1 like · 40 views
How to Enable Ollama GPU Acceleration on Intel Arc in Windows
I recently encountered an interesting performance issue while running Ollama locally on my ASUS ZenBook with an Intel Arc 140T integrated GPU.
I was sure that I had enough GPU:
!GPU Preview
However, every model I tested was extremely slow, including relatively small models such as Qwen3 4B.
After investigating, I discovered that Ollama was running entirely on the CPU instead of using the GPU.
Identifying the problem
Ollama provides a simple command to check where a model is running:
ollama ps
Initially, the output showed:
NAME SIZE PROCESSOR CONTEXT
qwen3:4b 3.9 GB 100% CPU 8192
The GPU was not being used.
Enabling Intel Arc GPU acceleration
The solution was to enable two environment variables:
$env:OLLAMA_VULKAN = "1"
$env:OLLAMA_IGPU_ENABLE = "1"
The first enables Ollama's experimental Vulkan backend, while the second allows integrated GPU detection.
After completely closing Ollama, I restarted the server:
ollama serve
Then I loaded the model again:
ollama run qwen3:4b
Checking the processor allocation:
ollama ps
This time, the result was:
NAME SIZE PROCESSOR CONTEXT
qwen3:4b 3.2 GB 100% GPU 4096
Success! Ollama is now using the Intel Arc GPU.
Making the configuration permanent
To avoid setting the variables every time Ollama starts, configure them permanently in PowerShell:
[Environment]::SetEnvironmentVariable("OLLAMA_VULKAN", "1", "User")
[Environment]::SetEnvironmentVariable("OLLAMA_IGPU_ENABLE", "1", "User")
Restart Ollama after applying these changes.
Final thoughts
This experiment was performed using:
- GPU: Intel Arc 140T
- Driver: 32.0.101.8860
- OS: Windows 11 26H2
- Ollama: 0.40.11
- Model: Qwen3 4B
The interesting lesson is that having a GPU capable of running a model does not guarantee that your inference engine is actually using it.
Tools that estimate whether a model fits into memory are useful, but actual hardware utilization matters just as much.
I believe Ollama could improve the user experience by displaying GPU utilization directly in its interface and warning users when a compatible GPU is available, but inference is running on the CPU.
Until then, ollama ps is your friend!
Notes:
- Vulkan acceleration remains experimental, and results may vary depending on your Intel GPU, drivers, and Ollama version.
- I created this ticket on GitHub; maybe they could support it from the UI in the future.
Follow me on:
| Personal | LinkedIn |YouTube|Instagram|Cyber Prophets|Sharing Your Stories|
|:----------|:----------|:------------:|:------------:|:------------:|:------------:|
|||||||

3 reactions
Mentions
Ollama 10月28日发布 v0.40.13,把 LFM3 的运行支持从苹果芯片扩到 Linux 和 Windows,语音合成模型也包括在内。 MIT 开源。但接多个模型仍要算内存:官方说明,内存不够时,新请求会排队,等旧模型卸载腾位置。能装上,不等于能同时跑。 ollama/ollama
ollama web search api — the search isn't local --- published: true description: The ollama web search API shipped Sept 2025. Keyless knock tonight: 401 in 0.13s and 0.15s. The key, the limits, and the part that is not local. tags: ollama, aiagents, api, tutorial canonical_url: mrsaynothing.dev cover_image: mrsaynothing.dev --- > Originally published at mrsaynothing.dev — the full post carries the two-door diagram, the receipt table, and the live checklist. Your local model can search the web. The search isn't local. Ollama's web search API shipped September 24, 2025 as two cloud endpoints — web_search and web_fetch — behind one account key. Any model you run locally can call them as tools, and the Python/JS libraries have carried the calls since version 0.6.0. We knocked on both doors without a key tonight: 401 in 0.13 and 0.15 seconds. Your weights run at home. The search does not. How do I get an ollama web search API key? One claim: the key is an account setting, not a config flag — there is nothing to flip in ~/.ollama, because the endpoint isn't yours. Sign in at ollama.com, open Settings → Keys, mint the key, export it. The search and fetch endpoints both read the same Bearer header: curl https://ollama.com/api/web_search \ --header "Authorization: Bearer $OLLAMA_API_KEY" \ -d '{"query": "what is ollama?"}' Keyless knock → 401 {"error":"Unauthorized"} — measured 2026-11-02, 0.13s. The same header opens /api/web_fetch, which returns a page as {title, content, links} — the plain-text twin of the URL you hand it. What are the ollama web search limits? The honest answer is a short table, because ollama publishes less than searchers want: | Question | Public answer | |---|---| | Free tier? | Yes — with an account. Their words: "a generous free tier." | | Higher limits? | Yes — paid ollama.com/cloud subscription. | | Searches per minute / day? | Not published anywhere. | | Results per call? | Tunable — the agent itself picks max_results. | The searches-per-minute number people are typing into the search bar does not exist in public. That absence is the answer — and the reason the query keeps autocorrecting itself into existence. Does ollama web search work without an API key? No — and the refusal is beautifully small. Both endpoints, knocked keyless: POST /api/web_search · keyless · 21:04 UTC 401 — {"error":"Unauthorized"} — 0.13s POST /api/web_fetch · keyless · 21:05 UTC 401 — {"error":"Unauthorized"} — 0.15s 0.13s to refusal · 0.15s to refusal · 26 bytes — the doorman's entire speech. The shortest documentation page on the internet, and it works: nobody is guessing their way past that door. How do I give a local model web search? You wire the two calls as tools and let the model choose: from ollama import chat, web_search, web_fetch tools = {'web_search': web_search, 'web_fetch': web_fetch} r = chat(model='qwen3:4b', messages=msgs, tools=[web_search, web_fetch], think=True) for tc in r.message.tool_calls or []: result = tools[tc.function.name](**tc.function.arguments) msgs.append({'role': 'tool', 'content': str(result)[:8000]}) Two numbers matter before you run that loop. First, the calls are heavy: ollama's own docs warn the tools "can return thousands of tokens" per round and recommend a context of roughly 32,000 tokens for serious loops — a default 4k-context model will choke on the receipt pile. Second, the official example truncates each tool result to 2000 × 4 characters before re-injecting it — the context tax is real enough that even ollama's demo pays it. Model choice: ollama recommends qwen3 and gpt-oss for tool use — small, tool-capable, and happy to run multi-turn loops. Setup list: ollama.com account + key → export OLLAMA_API_KEY=... → library ≥ 0.6.0 → tool-capable model (qwen3 or gpt-oss) → context raised toward ~32000 tokens. Can I use ollama web search with MCP? Yes — ollama ships an official MCP server example, so any MCP client gets the tools over stdio, keyed by the same environment variable: { "mcpServers": { "web_search_and_fetch": { "command": "uv", "args": ["run", "path/to/web-search-mcp.py"], "env": { "OLLAMA_API_KEY": "your_key" } } } } Codex reads the same trio from ~/.codex/config.toml as a [mcp_servers.web_search] block. One key, every client. Is the search actually local? Local means the weights, not the web. Trace one loop honestly. Your machine holds the model. The moment the model decides it needs the web, your query leaves the building — crosses to ollama.com's cloud, gets searched on their infrastructure, and the receipts ride back into your context. What staying local buys you is real: the weights never leave, the inference never leaves, nobody sees your prompts to the model. What it doesn't buy: the questions you ask the web land in someone else's logs — by design, behind a key you minted on their account page. That's the wound left open: here is every local setup quietly knocking on somebody else's door — cheerfully, at 0.13 seconds a knock. The next honest number is the one ollama doesn't publish: what a free-tier day of searching looks like when the loop never sleeps. --- The full post — two-door diagram, honest limits table, live checklist — lives at mrsaynothing.dev. What's your loop calling — qwen3 or gpt-oss?
ダウンロードもロードもできるのに0問しか解けない。Ollama公式タグの量子化崖を自分のデータ再集計で確かめた 要約 arXiv:2609.05881「Broken on Arrival」という論文が、Ollama公式ライブラリの305タグをHumanEval+で機能検査し、7タグ(qwen2.5-coder:3b-instructのq2_K/q3_K_S/q3_K_M/q3_K_L、phi3.5:3.8b-mini-instruct-q2_K、llama3.2:1b-instructのq2_K/q3_K_S)が164問中0〜6問しか解けない「機能しない」状態だったと報告している。 この論文はv1で「サイレントに壊れたファイル」と診断したが、v3で訂正されている。著者が同じチェックポイントから再ビルドしたところ、ファイル自体はビット単位で一致する正規の(無calibrationの)低bit量子化だった。壊れていたのはファイルではなく、無calibration量子化によって性能が実質ゼロまで崩壊するという現象そのものだった。 筆者はこの論文のコード・監査データセット(aditi-p31/quantcheck, MIT/CC BY 4.0)をクローンし、著者が公開している生のHumanEval+評価ログを自分のスクリプトで再集計して、この崖と、論文中のWilson信頼区間の数字が自分の再計算でも一致することを確認した。手元のOllamaでq2_K/q4_K_Mを実際にpull・推論させても同じ崖を再現できた。 きっかけ Hugging Face Daily Papersの巡回で見つけた一本に、妙に惹かれるタイトルがついていた。 「Broken on Arrival」、着荷時点で壊れている。 Ollamaの公式ライブラリに登録されている量子化モデルタグのうち、ダウンロードもロードもできてトークンも実際に出てくるのに、タスクをほとんど解けないものが混じっている、という調査報告である。 筆者はこれまでOllamaの量子化タグを「サイズが小さければ少し精度が落ちるだけ」くらいに考えて選んでいたので、これは試す価値があると判断した。 本題: v1の「壊れたファイル」診断は撤回されている まず筆者が手を動かす前に確認すべきことがあった。 この論文には複数のバージョンがあり、現在のarXivページで読める最新版(v3)の内容は、初版(v1)とは結論が違う。 v1のタイトルは「Silently Defective LLM Artifacts」、つまり「サイレントに欠陥のあるアーティファクト」であり、問題のタグのGGUFファイル自体が壊れていると報告していた。 v3ではこの診断が訂正されている。 著者はQwen2.5-Coder-3B系・phi3.5系の該当タグを、オリジナルのチェックポイントからllama.cppで自分で再ビルドした。 その結果、Qwen側4タグは434テンソル全てが、phi3.5側は197テンソル全てが(古いllama.cppのテンソル構成に合わせれば)、公式タグのファイルとビット単位で一致した。 つまりファイルは改変も破損もしていない、正規の量子化出力だったということになる。 壊れていたのはファイルではなく、「無calibration(importance matrixを使わない)の低bit量子化によって、特定の小型モデルの性能が実質ゼロまで崩壊する」という現象だった。 importance matrixを使った量子化に切り替えると、同じQwen2.5-Coder-3Bのq2_Kは164問中0問から106〜113問まで回復し、q3_K_Mは76〜89問、q3_K_Lは80〜86問まで回復したと論文は報告している。 phi3.5のq2_Kについては、2026-09-10付でOllama側のissue(ollama#18252 )上でも欠陥主張自体が撤回されている。 llama3.2-1B系の2タグは、チェックポイントがライセンスで再ビルドできなかったため、原因不明のまま「機能しない」タグとして残っている。 この訂正の経緯自体が、今回の記事で主役にしたい部分である。 最初に見つけた問題が、調べ直すと別の問題だったという展開は、検証をやっているとしばしば起きることだが、それを自分で正直に書き直して公開し続けている著者の姿勢は参考になる。 筆者が実際にやったこと ここは正直に書く。 論文のコードと監査データセットを公開しているリポジトリaditi-p31/quantcheck(MIT License、データセットはCC BY 4.0)をクローンし、著者が実際に実行した生の評価ログを自分のスクリプトで読み込んで、独自に再集計した。 このリポジトリには、327件の評価対象それぞれについて、HumanEval+の164問全てに対するpass/fail判定と、実際にモデルが生成したテキストそのものが、JSONL形式でそのまま入っている。 つまり「論文の数字を信じる」のではなく、「論文の数字の元になっている生データを自分で読んで、自分で数えて、同じ数字になるか確かめる」という形の検証をした。 GIT_LFS_SKIP_SMUDGE=1 git clone --depth 1 aditi-p31/quantcheck /tmp/quantcheck python3 -I experiments/day-033/scripts/extract_qwen3b_progression.py /tmp/quantcheck 出力は以下の通りだった(qwen2.5-coder:3b-instructの量子化レベルごとのHumanEval+通過数、15タスクのスモーク screenと164タスクのフル実行)。 tag smoke15 full164 qwen2.5-coder:3b-instruct-q2_K 0 0 qwen2.5-coder:3b-instruct-q3_K_S 0 0 qwen2.5-coder:3b-instruct-q3_K_M 0 0 qwen2.5-coder:3b-instruct-q3_K_L 0 0 qwen2.5-coder:3b-instruct-q4_0 15 qwen2.5-coder:3b-instruct-q4_K_S 15 qwen2.5-coder:3b-instruct-q4_K_M 15 qwen2.5-coder:3b-instruct-q5_K_S 15 qwen2.5-coder:3b-instruct-q5_K_M 15 qwen2.5-coder:3b-instruct-q6_K 15 qwen2.5-coder:3b-instruct-q8_0 15 qwen2.5-coder:3b-instruct-fp16 15 q4_0より下の4レベル(q2_K/q3_K_S/q3_K_M/q3_K_L)は、15タスクのスモークでも164タスクのフル実行でも揃って0問、q4_0から上は15タスク全問正解という、崖のような段差になっている。 中間の緩やかな劣化ではなく、ある量子化レベルを境に完全にゼロへ落ちる、という点がこの論文の主張の核心であり、自分で再集計した数字でもそれがそのまま確認できた。 実際に何が生成されているのか 数字だけだと実感が湧かないので、同じタスク(HumanEval/3)に対する生成テキストそのものを比較した。 機能しないとされるqwen2.5-coder:3b-instruct-q2_Kの実際の出力は、次のようなものだった。 program{ mess9 demon9 thrift { sports bil is: program, bil program Audi program program program program program program (以下 "program" の繰り返しが続く) 一方、同じタスクに対する健全なqwen2.5-coder:3b-instruct-q4_K_Mの出力は、通常通りdocstringから関数定義が始まる、まともなPythonコードだった。 from typing import List def below_zero(operations: List[int]) -> bool: """ You're given a list of deposit and withdrawal operations on a bank account... q2_Kはエラーで落ちているわけではない。 モデルはロードされ、トークンは生成され続けている。 ただ、その中身がタスクの体裁すら保っていない単語の繰り返しになっている。 「動いているように見えて実は何も解けていない」というこの論文の指摘が、生ログを自分で開いてみると非常に具体的に伝わってきた。 論文の統計も自分で再計算してみた 論文は「7/305タグが機能しない(2.3%, Wilson 95% CI 1.1–4.7%)」という統計を報告している。 Wilson score intervalの計算式自体は難しくないので、自分でPythonで実装して検算した。 import math def wilson(k, n, z=1.96): phat = k / n denom = 1 + z2 / n center = phat + z2 / (2 * n) margin = z * math.sqrt(phat * (1 - phat) / n + z2 / (4 * n2)) return (center - margin) / denom, (center + margin) / denom 7/305を入れると2.295%、信頼区間は1.116〜4.661%となり、論文の「1.1–4.7%」と一致した。 モデル系列単位(3/35)でも8.6%、2.96〜22.38%となり、論文の「3.0–22.4%」と一致した。 論文の数字を右から左に引用するのではなく、同じ計算を自分の手元で再現できることを確かめておくと、記事に書く数字への納得感が変わってくる。 Ollama公式タグで実際に再現してみた 著者の生ログを自分で再集計するだけでなく、Ollamaの公式タグを自分のPCで実際にollama pullして推論させ、同じ崖が起きるかを確かめた。 ollama pull qwen2.5-coder:3b-instruct-q2_K ollama pull qwen2.5-coder:3b-instruct-q4_K_M 両タグとも問題なくダウンロードできた。 harness/audit.pyと同じプロンプト・パラメータ(temperature=0, seed=0)でHumanEval/3を投げたところ、q2_Kは次のように崩壊した。 program, program9 thrift { program; program9 thrift, program program program program (以下 "program" の繰り返しが512トークン分続く) 一方のq4_K_Mは同じプロンプトから一発で正しいコードを生成した。 def below_zero(operations: List[int]) -> bool: balance = 0 for operation in operations: balance += operation if balance < 0: return True return False 著者が公開したログの再集計だけでなく、自分の環境・自分の推論実行でも同じ機能崩壊を確認できた。 q2_Kはダウンロードもロードも正常に完了しており、エラーで落ちているわけではなく、生成そのものがタスクの体裁を保てていない。 まとめ 公開モデルレジストリから量子化タグを選ぶとき、サイズとタグ名だけで「軽いから選ぶ」という判断をしていると、この論文が報告したような、ダウンロードも推論もできるのにタスクを全く解けないタグを掴んでしまう可能性がある。 もっとも、今回確認できた7タグはいずれも4B以下の小型モデルの低bit量子化(q2_K〜q3_K_L)に集中しており、q4_0以上では同じモデル系列でも崖から外れていた。 量子化レベルを下げるときは、サイズだけでなくHumanEval+のようなタスクベースの動作確認を一度挟む価値がある、ということが、著者の生データを自分で再集計してみて納得できた。 実際にOllama公式タグをpull・推論させて確認した今回の結果は、論文が報告した現象が著者の環境固有のものではなく、誰の手元でも再現する種類の問題であることを裏付けている。 出典 論文: Aditi Patodiya, "Broken on Arrival: Non-Functional Quantized LLM Artifacts in Public Model Registries and How to Catch Them", arXiv:2609.05881 arxiv.org コード・監査データセット: aditi-p31/quantcheck (コード: MIT License、監査データセット: CC BY 4.0) phi3.5の欠陥主張撤回の経緯: ollama#18252
AIに無人運用させたパイプラインで、エラーを出さずに壊れていた8件と検知の作り方 はじめに 結論: Claude Code に作らせ・直させながら毎日無人で回している自作の知見収集パイプラインで、エラーを出さないまま壊れていた故障を、修正コミットと調査記録から数え直すと、期間まで言えるものが8件ありました。一番長いのは約4か月(日次バックアップが一度も動いていなかった)、一番長く「鳴っていたのに気づかなかった」のは28日間(評価の前段フィルタが毎日約800行の警告を出しながら素通りしていた)です。 8件に共通していたのは、「止まらない設計」「起動した記録」「exit 0」が、そのまま「気づかない」の原因になっていたことでした。 この記事では、8件の一覧(何が・何日・なぜ無音だったか・どう気づいたか)、無音になる共通の型、検知をどう作り直したかを、コード片つきで説明します。8月に書いた「AIに全部任せて、4箇所だけ止める」は、人の承認を挟む経路が壊れる話でした。今回はその手前、パイプライン自身の故障に気づく経路の話です。 ! 個人環境(Windows 11 Pro・1人運用)での n=1 の記録です。8件のうち7件は AI に限らない一般的な自動化の話で、Claude Code 固有の話は #7 だけです。日付・件数は修正コミット・調査記録・DB から取り直した値で、原本で確かめられなかったものは「不明」と書いています。 前提・環境 パイプラインの中身は単純です。 5つの情報源から記事を集め、ローカル LLM(Ollama)で採点し、上位を「改善提案ファイル」にする Python 3.11 + SQLite。定期実行は Windows タスクスケジューラ + PowerShell スクリプト コードの修正・調査は Claude Code が行い、私は Discord の通知と決裁だけを見る 動いているジョブは次のとおりです。 ジョブ 周期 何を見て異常とするか(当時) 日次収集+評価 毎日 16:10 JST スクリプトの終了コード 週次ループ(集計・品質計測・スクリーニング) 日曜 08:00 各ステップの終了コード 健全性チェック 6時間ごと doctor(自作の診断コマンド)の FAIL だけを Discord へ 「AIに運用を任せる」と言っても、実際に毎日動いているのは普通のスクリプトです。AIはそれを作り、直し、調べる役です。だからこそ、スクリプトが黙って壊れると、AIも私も気づく材料がないという構図になります。 8件の故障一覧 # 何が起きたか 期間 なぜ無音だったか どう気づいたか 1 依存ライブラリが仮想環境に入っておらず収集が停止 約10日(2026年5月。開始日は不明) Discord 通知も同じライブラリを読み込んでいて、一緒に止まった 私が「直近の収集情報を確認して」と頼んで発覚(当時のメモ) 2 日次収集が丸1日欠落 7/15 の1日 未実行検知は48時間。判定時点の経過は46.3時間 9/2 の大規模レビュー 3 収集プロセスが途中で落ちた 7/21・7/23 の2回 スクリプトが終了コードの分岐まで届かず、DB 側では連続失敗の集計から除外 同上 4 日次バックアップが一度も動いていなかった 約4か月(5/2 予定 → 9/3 初回) 定義ファイルはあるが未登録。週1回の別経路でバックアップは取れていた 同上 5 評価に失敗した9件が放置 最長799時間(約33日) 翌日以降は再試行しない構造。診断は WARN、通知は FAIL のみ レビュー対応中に WARN を読んで 6 品質ゲートの通知が一度も鳴らず 週次1回分(8/23) 通知処理自身のバグが「止めない」ための catch に吸われた 翌日、週次ログを読んで 7 Claude アプリの定期タスクが許可確認で固まる【Claude Code 固有】 8/30〜9/27 の5回 起動記録は更新されるので死活監視は「正常」 鮮度警告は鳴っていたが案内文が的外れで、10/3 に調査 8 前段フィルタ用のモデルが消えて素通り 28日(9/21〜10/18) 「モデルがない」を一過性の通信エラー扱いで再試行し、最後は素通し 別件のエラー調査中に偶然 ここでの「1件」は、期間を原本(修正コミット・調査記録・DB)で言える故障の単位です。#3 は2回の発生を1件と数えています。期間や実害が言えないもの、被害が出る前に見つけたものは、後半の「被害前に見つけた罠」に分けました。 実害(データ消失など)が出たものは、この8件の中にはありません。#4 は週1回のバックアップが別にあり、#5 は手で評価し直したら9件とも成功しました。ただし「実害が出なかった」のは運が良かっただけで、どれも気づくまでの時間を自分で決められていなかった点が問題でした。 収集と保存の4件(#1〜#4) #1 依存の未同期で約10日停止 依存の宣言(pyproject.toml)にはあるのに、実際の仮想環境に入っていないライブラリがありました。起動時には落ちず、そのライブラリを使う処理に来た時点で止まります。厄介なのは、Discord 通知の処理も同じライブラリを読み込んでいたことです。目が先に潰れていました。 当時の修正コミットは「障害が約10日間未検知」と書いています。DB を見ると、4/30 の次に正常終了した収集は 5/17 まで1件もありません。ただしこの期間には、集計処理の KeyError でバッチ全体が止まる別の不具合も重なっていて、どこまでが依存起因かは切り分けられていません。停止の開始日を書いた記録も残っていませんでした。 対策は3つです。 そのライブラリが無くても動くよう、計測部分を「何もしない版」に差し替えられるようにした 日次スクリプトの先頭で依存の整合チェックと import の試験を行う 診断コマンドに「未評価の滞留・連続失敗・止まったままの実行」を見る項目を足した #2 丸1日の欠落が1.7時間差ですり抜けた 7/15 は日次収集が丸ごと走っていませんでした。未実行の検知は「最後の成功から48時間」。前後の成功は 7/14 と 7/16 の同時刻で、間隔はちょうど48.0時間です。健全性チェックは6時間ごとなので、最後の判定時点の経過は46.3時間で PASS、次の判定の前に翌日分が成功して経過がリセットされました。 時点(UTC) 出来事 最後の成功からの経過 7/14 07:10 収集成功 0 7/15 収集なし — 7/16 05:30 健全性チェック 46.3時間 → PASS(閾値48時間) 7/16 07:10 収集成功 0 にリセット 周期24時間の仕事に48時間の閾値をかけると、1日だけの欠落は原理的に必ずすり抜けます。閾値は「2回連続で失敗したら」のつもりでしたが、それは「1回の失敗は知らなくていい」と同じ意味でした。今は30時間に詰めています。 #3 プロセスが落ちても三重に見えない 日次ログ63回分を読むと、非0で終わった回はゼロでした。そのうち2回(7/21・7/23)はログに終了行がなく、プロセスが途中で消えていました。見えなかった理由は三重です。 収集コマンドは内部で失敗しても終了コード0を返す作りで、さらにプロセスごと消えるとスクリプトが終了コードの分岐まで届かない DB に「実行中」のまま残った記録は、後日「時間切れで閉じた」として失敗扱いになるが、この種の失敗は連続失敗の集計からわざと除外されていた 翌日は正常に走ったので、48時間の検知にもかからない Windows タスクスケジューラの「前回の実行結果」も 0 のままでした。今は収集コマンドの終了コードに「0=正常・1=失敗・3=一部失敗」の約束を持たせ、スクリプトは分岐だけを持つ形にしています。 #4 日次バックアップの定義はあったが、一度も登録されていなかった 5/1 に日次バックアップのタスク定義(XML)をリポジトリに追加し、開始予定は 5/2 05:30 でした。ところが Windows 側に登録されておらず、日次バックアップは一度も動いていませんでした。動いていたのは週次ループの中の週1回だけで、DB が壊れたら最大7日分を失う状態です。なぜ未登録のままだったのかは記録が残っておらず不明です。 9/2 のレビュー後の修正で登録し直し、初回は 9/3 05:30 に成功しました。あわせて「最新のバックアップファイルが48時間より古ければ FAIL」という検知を足しています。定義ファイルの存在は、動いたことの証拠になりません。 評価と判定の4件(#5〜#8) #5 評価に失敗した9件が799時間放置 日次収集の評価フェーズは「その回に集めた記事」だけを評価します。評価に失敗した記事は評価結果の表に何も書かれないため、翌日からは誰の対象にもなりません。診断コマンドは「最古の未評価が799時間経過」と WARN を出していましたが、通知は FAIL だけなので届きませんでした。 手で評価し直すと9件とも成功し、一過性の失敗だったと分かりました。今は日次収集のあとに「未評価を最大50件だけ拾い直す」処理を毎日走らせ、拾えなかった時だけ通知します。再試行しない失敗は、失敗ではなく行方不明になる、というのがこの件の教訓です。 #6 品質ゲートの通知が、自分のバグで鳴らなかった 週次の品質計測(AIの採否判定を過去の人手判定とどれだけ一致させられるか、の F1 値)は、合格ラインの 0.7 を下回っても終了コード0で終わります。それを拾うために 8/17 に「F1 が 0.7 未満なら Discord に WARN」という処理を足しました。 その処理は、こういう形をしていました(簡略版)。 try { $ProjectRoot は未定義(正しくは $ProjectDir)→ Join-Path が null で例外 $metrics = Get-Content (Join-Path $ProjectRoot 'docs/screen_replay/latest.json') | ConvertFrom-Json if ($metrics.f1 -lt 0.7) { Send-DiscordWarn "F1=$($metrics.f1): ゲート不通過" } } catch { 週次ループを止めないための fail-open。ログには残るが、誰も読まない Write-Log "WARN: F1 gate check failed (fail-open): $_" } 8/23 の週次実行で F1 は 0.526 でしたが、通知は来ませんでした。変数名の間違いで例外が出て、それが「止めない」ための catch に吸われたからです。翌日ログを読んで気づき、8/24 に直しました。無音だったのは週次1回分です。 ここで怖いのは期間の長さではなく構造です。死角を塞ぐために足した通知が、自分の故障を同じ死角に落としていました。 #7 Claude アプリの定期タスクが、許可確認で固まっていた【Claude Code 固有】 週次のスクリーニング(収集した提案のうち、どれを自分の Claude Code 環境に取り込むかの下書き作り)を、Claude デスクトップアプリの定期タスクで動かしていました。8/23 は Claude Code 2.1.234 で完走しましたが、8/30(2.1.246)以降、セッション内の Bash が「実行してよいか」の確認を出すようになり、承認する人がいないまま固まりました。 回 Claude Code 結果 8/23 2.1.234 完走 8/30 2.1.246 停止 → 9/2 に私が同じセッションに入って手で完了 9/6 2.1.258 開始2分で停止(記録38行) 9/13 2.1.260 開始2分で停止(記録52行) 9/20 — 未精査(同じ型と推定) 9/27 2.1.280 36時間後に Tool permission stream closed before response received で中断 なぜ無音だったかは2段あります。 死活監視は「定期タスクの最終起動時刻(lastRunAt)が更新されたか」だけを見ていて、起動はしているので「正常」。しかもその監視役自身も定期タスクで、同じように止まっていた 成果物の鮮度を見る警告(最新の採否ファイルが10日より古い)は、計算上 9/12 頃から毎日 Discord に届いていた。ところが案内文が「アプリの起動状態・認証を確認」で、実際の原因(許可確認待ち)にたどり着けなかった 10/3 に原因を調べ、10/4 に Windows タスクスケジューラ+claude -p --permission-prompts none(確認が要る操作は待たずに拒否する)へ移しました。試験では 10/3 付の58件を5.5分で処理しています。根本原因は、環境変数 CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 が有効だと許可モードが既定に強制される、という有力仮説までで、挙動が変わった版は特定できていません。溜まった分は約5週・S/A ランク約2,000件になりました。 #8 前段フィルタ用のモデルが消えて、28日素通り 評価の前に、小さなモデル(qwen2.5:1.5b)で「明らかに不要な記事」を落とす前段フィルタがあります(対象は GitHub 由来の記事だけ)。9/21 にこのモデルが Ollama から消えていました。消えた原因は今も不明です。 挙動はこうでした。 Ollama は「モデルがない」と返す 呼び出し側はこれを通信エラーと同じ扱いにして、1件ごとに3回再試行し、WARNING を出す 3回失敗したら fail-open(前段フィルタを通さず本評価へ回す) 結果、ログには WARNING が1日約800行出ていましたが、処理は止まらず、Discord には何も届きませんでした。診断コマンドは「Ollama に接続できるか」しか見ておらず、モデルが欠けていても PASS でした。10/18、まったく別のエラー(記事本文取得の通信切断)を調べていて偶然見つけるまで28日間です。 無音になる共通の型 8件を並べると、無音になる理由は5つの型に収まりました。 型 何が起きるか 該当 fail-open が「気づかない」も生む 止めない代わりに、恒久的な故障まで一過性と同じ扱いで流れていく #6・#8 起動記録や exit 0 は動いた証拠ではない 「起動した」「正常終了した」と「成果物ができた」は別の事実 #2・#3・#4・#7 通知経路が監視対象と一緒に壊れる 目になる経路が、壊れる側と同じ依存・同じ仕組みに乗っている #1・#6・#7 鳴っているのに届かない 警告は出ているが、出し先(WARN 止まり)・量(毎日800行)・案内文がずれている #5・#7・#8 閾値と周期の擦れ 周期24時間に閾値48時間、判定6時間ごと → 1日の欠落は必ずすり抜ける #2 工場の例えで言うと、「ラインが動いているか」のランプは点いていたが、「製品が出てきているか」を数える人がいなかった状態です。fail-open(故障しても止めずに流す設計)は、無人運用では正しい選択であることが多いです。ただし、止めない代わりに「止まらなかった」ことを数える仕組みを対で持たないと、壊れたまま何週間でも動き続けます。 検知の作り方 以下のコードは考え方を示す簡略版で、実物(診断コマンドや PowerShell スクリプト)とは細部が違います。 動いた証拠は成果物の側で見る 「タスクが起動したか」「終了コードが0か」ではなく、成果物が予定どおり新しくなったかで判定します。バックアップなら最新ファイルの更新日時、収集なら DB の実行記録、スクリーニングなら採否ファイルの作成日時です。 from datetime import datetime, timezone from pathlib import Path BACKUP_MAX_AGE_HOURS = 48 # 日次バックアップ。1回の取りこぼしで鳴る長さにする def check_backup_freshness(backup_dir: Path) -> tuple[str, str]: files = sorted(backup_dir.glob("*.db"), key=lambda p: p.stat().st_mtime, reverse=True) if not files: return "FAIL", "バックアップが1つもない" age_h = (datetime.now(timezone.utc).timestamp() - files[0].stat().st_mtime) / 3600 if age_h > BACKUP_MAX_AGE_HOURS: return "FAIL", f"最新バックアップが {age_h:.0f} 時間前" return "PASS", f"{age_h:.0f} 時間前" 収集は「全体の最新1件」ではなく、トラック(収集の系統)ごとの最新の成功を見ます。当初は全体の最新1件だけを見ていたので、最後に走ったトラック以外のエラーは見えていませんでした。直近90日のエラー記録19件のうち13件が、この理由で不可視でした。 LATEST_COMPLETED_BY_TRACK = """ SELECT track, MAX(started_at) AS last_ok, errors_json FROM collection_runs WHERE status = 'completed' GROUP BY track """ EVAL_FAILURES_TOLERATED = 5 # 評価失敗が数件出るのは日常。毎回鳴らすと狼少年になる 判定は3段に分けました。 最新の成功が30時間より古い → FAIL(日次周期に近づけた) エラー記録あり → FAIL。ただし「評価失敗5件以下」は許容(成功回の8%に出ていて、鳴らし続けると誰も見なくなる) 収集0件 → FAIL ではなく WARN(静かな日は正常にある) 恒久エラーと一過性エラーを分ける #8 の根っこは「モデルがない」を「通信が切れた」と同じ棚に入れていたことです。前者は何回再試行しても直りません。 import asyncio import logging import httpx import ollama logger = logging.getLogger(name) class Prefilter: def init(self, client: ollama.AsyncClient, model: str) -> None: self._client = client self._model = model self._disabled = False # この実行の残りで前段フィルタを止めたか async def judge(self, prompt: str) -> str: if self._disabled: return "KEEP" # 本評価へ回す(fail-open は維持) for attempt in range(3): try: res = await self._client.chat(model=self._model, messages=[{"role": "user", "content": prompt}]) return parse_keep_or_drop(res) except ollama.ResponseError as e: if e.status_code == 404 or "not found" in str(e).lower(): 恒久エラー: 1回だけ ERROR を出し、この実行の残りは呼ばない logger.error("前段フィルタのモデル %s が存在しない。この実行では無効化する", self._model) self._disabled = True return "KEEP" raise except httpx.TransportError: await asyncio.sleep(2 ** attempt) # 一過性: 従来どおり再試行 return "KEEP" もう1つは、診断コマンドで「接続できるか」に加えて「使うモデルが実在するか」を照合することです。 def check_models(installed: set[str], required: list[str]) -> tuple[str, str]: def norm(name: str) -> str: return name if ":" in name else f"{name}:latest" # タグ省略は :latest と同じ扱い missing = [m for m in required if norm(m) not in installed] if missing: return "FAIL", f"Ollama にないモデル: {', '.join(missing)}" return "PASS", "使用モデルはすべて存在" 再試行の設計で大事なのは、一過性の再試行を残したまま、恒久エラーだけを外に出すことです。どちらか片方に倒すと、通信の瞬断で止まるか、恒久故障を28日流すかのどちらかになります。 新しい通知は、1回わざと鳴らしてから信じる #6 の教訓はこれに尽きます。通知・ゲートを足したら、失敗する入力を与えて、本当に通知が出るかを1回確かめます。送信部分だけ差し替えれば Discord に飛ばさずに試せます。 通知の経路試験(簡略版): F1 が閾値未満の計測ファイルを与え、送信関数が呼ばれたかを見る $script:sent = @() function Send-DiscordWarn([string]$Message) { $script:sent += $Message } Invoke-F1Gate -MetricsPath '.\tests\fixtures\f1_below_threshold.json' if ($script:sent.Count -ne 1) { throw "F1 ゲートが鳴らなかった(fail-open の catch に吸われていないか)" } #8 の対策でも同じことをしました。存在しないモデル名を設定して診断を走らせ、FAIL が出ることを確かめています。 XR_OLLAMA_PREFILTER_MODEL=qwen-nonexistent x-research doctor # → FAIL になる(exit 1)ことを確認 あわせて、次の2つも運用に入れました。 fail-open の catch が出すメッセージ(... failed (fail-open))は、定期点検で grep する対象にする。catch に入ったこと自体が異常の兆候だから 警告の案内文には「一番多い原因」と「調査記録のパス」を書く。#7 は警告が毎日鳴っていたのに、案内文が別の原因を指していて約3週間空回りした cmd | tail でゲートを空にしない これは被害が出る前に見つけた罠ですが、無音の作り方として一番手軽なので載せます。テストを通ったら計測へ進む、という連鎖を1行にまとめた時の話です。 NG: && が見るのは tail の終了コード(ほぼ常に0)。テストが落ちても計測へ進む pytest -q | tail -1 && run_benchmark OK 1: パイプのどこかが失敗したら失敗にする set -o pipefail pytest -q | tail -1 && run_benchmark OK 2: 検証と実行を分け、終了コードを自分で読む pytest -q > test.log; rc=$? tail -1 test.log [ "$rc" -eq 0 ] && run_benchmark 当時のメモには、「1 failed」と表示されたまま計測が始まったと残っています。画面に「passed」「failed」が見えていても、それは表示であって判定ではありません。AI に検証付きのコマンドを組ませる時は、特にこの形が混ざりやすいです。 被害前に見つけた罠 8件とは別に、実害が出る前に見つけたもの、実害の有無を確かめられていないものです。タイトルの「8件」には入れていません。 罠 中身 実害 最後のトラックしか見ない健全性チェック 全体の最新1件だけを検査し、エラー記録19件中13件が不可視 13件それぞれの実害は未確認 「成功」に入るエラー エラー記録があっても状態は「completed」。理論上、全情報源が0件でも48時間検知が永久に鳴らない 発生は未確認 一覧取得の途中失敗で取りこぼし 新しい順に読む途中でページが失敗すると、差分の起点が「今」まで進み、間の古い記事を永久に取りこぼす。エラー記録にも載らない 不明(発生期間・件数を言える記録がない) 修正で入れた XML 宣言で登録が必ず失敗 #4 の修正中、タスク定義に encoding="UTF-8" を書いたら Register-ScheduledTask -Xml が拒否する形になっていた マージ前のレビューで発見。被害なし cmd | tail のゲート 上の節のとおり 計測が1回無駄になりかけた 通知経路が Discord 一本 Webhook が死んでも診断は WARN 止まりで、送信結果も捨てていた 発生は未確認 取りこぼしの件は、10/18 に「途中で失敗したら起点を進めない(最大7日留める。留めから遡る回が3回続けて打ち切られたら諦めて解除)」形に直しました。いつから起きていたかは、そもそも記録に出ない作りだったので分かりません。無音の故障は、期間を言えないこと自体が症状です。 XML 宣言の件は、修正そのものがもう一度「黙って動かないバックアップ」を作りかけた例です。直す時にも、成果物(初回のバックアップファイル)が出たかで確かめる必要がありました。 ハマったところ・限界 項目 内容 検知を足したら二重通知 #7 の調査中、診断コマンドに「スクリーニングの鮮度」を新設したが、既存の警告と同じ症状を見ていたため別のレビューで指摘されて取り消した。足す前に、既存の検知を全部 grep する 厳しくすると狼少年 「評価失敗1件でも FAIL」にすると成功回の8%で鳴る。許容値と WARN/FAIL の分け方を、実データの頻度から決める必要があった 原因不明のまま #8 のモデルがなぜ消えたか、#4 の定義がなぜ登録されなかったか、#1 がいつ始まったかは、記録がなく分からない 見つかったものしか数えられない #8 は偶然の発見だった。今この瞬間も、見えていない無音の故障があると考えるべき 分類の線引き 「期間が原本で言える」を基準にしたので、期間不明の取りこぼしは罠側に入れた。数え方次第で件数は変わる Claude Code 固有の部分 #7 は Claude Code の版と設定に依存する話で、根本原因は仮説止まり。他の7件は AI と無関係に、どんな自動化でも起きる 正直に書くと、AIに運用を任せたこと自体が無音の原因だったわけではありません。8件の多くは、人が書いても同じように起きるスクリプトの作りの問題です。違いがあるとすれば、人が毎日画面を見ていない分、「止まらなかった」を数える仕組みが無いと、気づくきっかけがゼロになることでした。 まとめ 無人運用のパイプラインで、エラーを出さずに壊れていた故障は、期間まで言えるものが8件あった(最長は日次バックアップの約4か月、警告が鳴り続けたのに気づかなかった最長は28日) 無音の型は5つ: fail-open が「気づかない」も生む/起動記録や exit 0 は動いた証拠ではない/通知経路が一緒に壊れる/鳴っているのに届かない/閾値と周期の擦れ 検知は「設定が正しいか」ではなく「起きた証拠」で見る。成果物の更新日時、トラックごとの最新の成功、許容値つきのエラー判定 恒久エラーと一過性エラーを分け、恒久エラーだけを1回大きく鳴らす 新しい通知は、失敗する入力を与えて1回わざと鳴らしてから信じる。パイプで出力を絞ったゲートは空になっていないか疑う 無人で回している仕組みがある方は、「最後に成果物が更新されたのはいつか」を、通知でなく自分の目で一度確かめてみてください。うちではこういう無音の故障もあった、という話があればコメントで教えてください。次の点検項目にします。 参考リンク AIに全部任せて、4箇所だけ止める——無人運用で固まった「意図確認レイヤー」の設計(承認の経路の話) AIエージェントは暴走より「止まりすぎ」だった——665回のターン終了を全数分析 Run Claude Code programmatically(headless / claude -p 公式ドキュメント) Monitoring Distributed Systems(Google SRE Book) Bash Reference Manual: Pipelines(pipefail) Register-ScheduledTask(Microsoft Learn) Ollama API ドキュメント
PossessedShell: a Victorian ghost haunts my terminal with local Gemma 2 This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine What I Built PossessedShell is a Victorian ghost trapped in your terminal. It is an ambient companion for zsh and bash that mourns every command you kill, then tells you how to fix it. It does three things: - The Failing Command Curse. When a command exits non-zero, the hook captures the command, its stderr and the exit code. A local Gemma 2 model writes a short Victorian lament and a plain-English diagnosis. It also suggests one fix command, which is pre-typed on your next prompt in zsh or placed in history in bash. The ghost never runs the fix for you. - The Forbidden Ritual Interceptor. Destructive commands (rm -rf, git push --force, git reset --hard, chmod 777, DROP DATABASE, mkfs, curl | sh, fork bombs and more) are stopped before they run. The ghost asks whether you truly wish to summon such destruction. - The Ectoplasm Leak Detector. A background monitor watches CPU and RAM and raises a spooky warning when the machine runs hot or one process devours memory. I took the "haunted terminal that possesses your shell" idea literally. The ghost is Cornelius Vale, a telegraph engineer who perished in 1887 and is now bound inside the machine. The theme is the fun part, but the diagnoses are useful because Gemma sees the real stderr, the exit code, the cwd and a snapshot of system state. Demo Here is a typical haunting (a missing Python module): ☠ THE PROCESS `python3 -c 'import ectoplasm'` HAS DIED (exit 1) ☠ ⚰ Diagnosis: The Python package 'ectoplasm' is not installed in this environment. ╭─ the ghost's remedy ───────────────╮ │ python3 -m pip install ectoplasm │ ╰────────────────────────────────────╯ The remedy waits on your next prompt. Enter to accept, Ctrl-U to refuse. whispered by gemma2:2b in 1.9s, 212 tokens <!-- TODO: add a screen recording or GIF link here before publishing --> Code {% embed realarbird/PossessedShell %} How I Built It Open-source AI at the core. Gemma 2 (gemma2:2b by default, gemma2:9b if you want a wiser ghost) runs locally through Ollama. Gemma is asked for strict JSON ({lament, diagnosis, fix}) through Ollama's format JSON schema, so the fix can be extracted reliably. The system prompt forbids inventing files, flags or packages the error doesn't imply, and bans destructive remedies unless there is no other way. Architecture. - The hooks are plain shell: zsh preexec/precmd plus an accept-line widget, and bash's DEBUG trap plus PROMPT_COMMAND. Python starts only when a command fails, matches the destructive-command prefilter, or an omen is waiting. Successful everyday commands cost nothing. - A small asyncio daemon keeps Gemma warm, runs the resource monitor, and talks newline-delimited JSON over a 0600 Unix socket. - If Ollama is down, an offline grimoire of heuristics answers instead (typos, missing modules, missing git upstream, ports in use, OOM kills). The demo never falls flat. - Rendering uses rich, with glitch-in ASCII apparitions and a typewriter effect. Resource checks use psutil. Sentry agent tracing. With a DSN set, every curse becomes a trace, and the Gemma call follows Sentry's AI agent span conventions. It shows up under Insights → AI → Agents: curse ls shell.curse the transaction ├─ system vital signs ghost.snapshot ├─ backboard recall ghost.memory.recall └─ invoke_agent Cornelius Vale gen_ai.invoke_agent └─ chat gemma2:2b gen_ai.chat tokens, timings, prompt and reply The gen_ai.chat span records token counts, model load time and tokens per second. When Gemma times out or answers with something unusable, the span is marked as an error and the agent span records that it fell back to the grimoire, so a slow model server stands out at a glance. Everything is scrubbed by redact.py before it leaves the machine. Backboard ghost memory (opt-in). With a BACKBOARD_API_KEY, the ghost remembers your past failures across sessions: "Again, mortal? python3 has died before by your hand…". Backboard only ever receives a scrubbed one-line summary per failure. Tests. Unit tests plus end-to-end tests that start real interactive zsh and bash sessions in a pty. They check that a failing command is cursed with its captured stderr, that a banished rm -rf runs nothing at all, and that omens appear at the next prompt. Why Does Open Innovation Matter? - Your terminal is private. Commands and stderr routinely contain paths, hostnames, tokens and half-typed secrets. Because Gemma runs on localhost, that text never has to leave the machine. A closed API would force me to ship every failed command to someone else's server. - It works with the lights off. On a plane, on a train, or behind a locked-down network, the ghost still haunts. The default install is 100% offline. Sentry and Backboard are opt-in extras, and the offline grimoire covers the case where even Ollama is down. - It isn't locked inside a service that might disappear. The model is a file I hold. I can swap gemma2:2b for gemma2:9b, or point POSSESSED_LLM_URL at any OpenAI-compatible local server such as llama.cpp, without changing a line of code. - Open weights made the tracing honest. Since inference is local, cost is $0 and I could observe the real latency and token counts per failure, and design the fallback around them. Prize Categories - Best Use of Gemma: Gemma 2 is the brain, running locally via Ollama and producing structured JSON diagnoses. - Best Use of Sentry Agent Tracing: each curse is traced as a gen_ai.invoke_agent / gen_ai.chat agent run with token usage, timings and error outcomes. - Best Use of Backboard: persistent, scrubbed memory of your past failures, so the ghost can recall earlier sins. <!-- Thanks for participating! -->
Ollama memory keeps growing with Cline on Mac Studio 36 GB, any fix? I’m running local coding agents (Cline in VS Code) against Ollama 0.40.13 on a Mac Studio (M5 Max, 36 GB unified memory) and I’m trying to find a setup that stays stable. The model is Qwen 3.8 27B. Memory pressure goes yellow during agent sessions and swap keeps growing. I would like to know if anyone found a real fix. What I measured (single requests via the API, same 14k-token prompt, num_ctx 16384): |Variant|Generation speed|ollama ps SIZE| |:-|:-|:-| |Q4_K_M (llama.cpp)|~19 tok/s|16–17 GB, constant| |nvfp4 (MLX runner)|~35–46 tok/s|18 → 20 GB| |Q4_K_M with MTP (27b-mtp-q4_K_M, llama.cpp)|~36–38 tok/s (28 at 14k context)|16–17 GB| At first MLX looked like the clear winner (twice as fast as plain Q4_K_M). What happens in a real Cline session (many sequential requests with a growing history and tool calls): - MLX runner: the server log (pipeline.go memory lines) shows held growing from 20 GB to 26.5 GB and peak up to 29.8 GiB within about 6 minutes, with only a 16k context. Swap reached 8 GB of 9 GB, memory pressure yellow. This matches existing Ollama issues ollama/ollama#17875, ollama/ollama#18131 and ollama/ollama#18620 (prefix cache accumulation, tool calls leaking memory). It still reproduces on 0.40.13, and I found no confirmed fix. The only things that release memory are unloading the model or restarting the runner. OLLAMA_KEEP_ALIVE=0 is useless with models on an external SSD. - llama.cpp runner with MTP: much better. ollama ps stays at 16 GB, even with a 32k context filled with 28k tokens. But the actual llama-server process is at 19–20 GB RSS and still rises slowly, memory pressure goes yellow and swap grows (1.7 → 4.4 GB) while VS Code, Cline and a browser are open. The log shows updating prompt cache repeatedly. Issue ollama/ollama#18264 describes the likely cause: llama-server’s host-RAM prompt cache (default --cache-ram 8192 MiB), which Ollama neither limits nor reports in ollama ps. What I plan to try next (not tested on macOS yet): 1. LLAMA_ARG_CACHE_RAM=1024 (or 0) through launchctl setenv for the Ollama app, as suggested in ollama/ollama#18264, then watch RSS of llama-server. 2. Remove the multimodal projector if possible (the runner is started with --mmproj even though I only use text). 3. Maybe test LM Studio’s MLX runtime or mlx_lm.server --prompt-cache-bytes (I’ve seen reports of bugs and crashes with agent loads). Questions: 1. Does LLAMA_ARG_CACHE_RAM actually reach the runner when set via launchctl setenv for the macOS Ollama app? Is there a better place? 2. Has anyone stabilized the Ollama MLX runner for agent workloads on 32–36 GB Macs? Any env var or build? 3. Is there a way to make ollama ps (or any tool) show the real footprint of the runner, including the prompt cache? 4. Would you recommend something else entirely for Cline on a 36 GB Mac (LM Studio, mlx_lm.server, llama-server directly, a smaller model)? Happy to post logs if useful.
Ollama: NVIDIA Nemotron 3.5 Bolt E4B SOURCE github.com/ollama/ollama/releases/tag/v0.40.10 The call, and why: deployedbyai.com
Top 5 Tool LLM Lokal dengan Bintang GitHub Terbanyak Ini lima tool LLM lokal dengan bintang GitHub terbanyak, dihitung hari ini. #1 Ollama — 184.967 bintang (ollama/ollama) #2 Open Webui — 156.917 bintang (open-webui/open-webui) #3 Llama.Cpp — 132.502 bintang (ggml-org/llama.cpp) #4 Vllm — 95.680 bintang (vllm-project/vllm) #5 Gpt4All — 77.354 bintang (nomic-ai/gpt4all) Empat dari lima pakai lisensi open source. Open Webui pengecualiannya. Kamu pakai yang mana? Tulis di komentar 👇 Data: Bintang Github · 27 Okt 2026 #Shorts #AItools #GitHub #opensource #belajarAI #programmer
Top 5 Most-Starred Local LLM Tools on GitHub These are the five most-starred local LLM tools, counted today. #1 Ollama — 184,967 stars (ollama/ollama) #2 Open Webui — 156,917 stars (open-webui/open-webui) #3 Llama.Cpp — 132,502 stars (ggml-org/llama.cpp) #4 Vllm — 95,680 stars (vllm-project/vllm) #5 Gpt4All — 77,354 stars (nomic-ai/gpt4all) Four of the five ship under an open source license. Open Webui is the exception. Which one are you using? Tell me in the comments 👇 Data: Github Stars · 27 Oct 2026 #Shorts #AItools #GitHub #opensource #vibecoding #developer
How to Enable Ollama GPU Acceleration on Intel Arc in Windows I recently encountered an interesting performance issue while running Ollama locally on my ASUS ZenBook with an Intel Arc 140T integrated GPU. I was sure that I had enough GPU: !GPU Preview However, every model I tested was extremely slow, including relatively small models such as Qwen3 4B. After investigating, I discovered that Ollama was running entirely on the CPU instead of using the GPU. Identifying the problem Ollama provides a simple command to check where a model is running: ollama ps Initially, the output showed: NAME SIZE PROCESSOR CONTEXT qwen3:4b 3.9 GB 100% CPU 8192 The GPU was not being used. Enabling Intel Arc GPU acceleration The solution was to enable two environment variables: $env:OLLAMA_VULKAN = "1" $env:OLLAMA_IGPU_ENABLE = "1" The first enables Ollama's experimental Vulkan backend, while the second allows integrated GPU detection. After completely closing Ollama, I restarted the server: ollama serve Then I loaded the model again: ollama run qwen3:4b Checking the processor allocation: ollama ps This time, the result was: NAME SIZE PROCESSOR CONTEXT qwen3:4b 3.2 GB 100% GPU 4096 Success! Ollama is now using the Intel Arc GPU. Making the configuration permanent To avoid setting the variables every time Ollama starts, configure them permanently in PowerShell: [Environment]::SetEnvironmentVariable("OLLAMA_VULKAN", "1", "User") [Environment]::SetEnvironmentVariable("OLLAMA_IGPU_ENABLE", "1", "User") Restart Ollama after applying these changes. Final thoughts This experiment was performed using: - GPU: Intel Arc 140T - Driver: 32.0.101.8860 - OS: Windows 11 26H2 - Ollama: 0.40.11 - Model: Qwen3 4B The interesting lesson is that having a GPU capable of running a model does not guarantee that your inference engine is actually using it. Tools that estimate whether a model fits into memory are useful, but actual hardware utilization matters just as much. I believe Ollama could improve the user experience by displaying GPU utilization directly in its interface and warning users when a compatible GPU is available, but inference is running on the CPU. Until then, ollama ps is your friend! Notes: - Vulkan acceleration remains experimental, and results may vary depending on your Intel GPU, drivers, and Ollama version. - I created this ticket on GitHub; maybe they could support it from the UI in the future. Follow me on: | Personal | LinkedIn |YouTube|Instagram|Cyber Prophets|Sharing Your Stories| |:----------|:----------|:------------:|:------------:|:------------:|:------------:| ||||||| 