Ollama API にテキストや PDF を添付できるようにする【Mocolamma 開発日記】

みなさんこんにちは、たいくんです。
ここ数日はClip Holdの開発をお休みして、気分転換がてら私のOllamaマネージャーであるMocolammaのアップデート 1.4.0に取り組んでいました。
そのアップデートで登場予定の新機能であるテキストファイルとPDFファイルの添付機能を実装したときのお話です。

広告

テキストファイルとPDFファイルの添付機能の実装

要望が届いた

4月の終わり頃、ドイツの方から「PDFやMarkdownをアップロードしてモデルを活用できるようにしてほしい」との要望が書かれたApp Storeのレビューを受け取りました。
Mocolammaのチャット機能はモデルをテストするための簡易的なものですが、確かにファイルをアップロードしてその能力をテストできたら良いなと思い、実装してみることにしました。
レビューをいただいた時はバージョン1.3.0をリリースしたばかりだったのでしばらく休憩していましたが、9月にリリースされるOSバージョン27の対応作業と一緒に実装することにしました。

どのようにOllama APIでファイルを送信するか

テキストファイルとPDFファイルの添付機能の実装開始時点では、Ollama APIではファイルの送信に対応しておらず、プロンプトテキストと画像の送信にしか対応していません。そのため、まずはどのようにしてテキストファイルやPDFファイルを添付するかを考える必要がありました。

テキストファイルであれば、内容はテキストだけですのでプロンプトに含めて送信すれば実現できそうです。しかし、問題はPDFファイルです。
PDFファイルは一般的なテキストファイルとは異なり、多種多様なレイアウトが組まれていたり、画像が含まれていたり、書類のスキャンのように全てが画像で構成されていたり…と様々なパターンが考えられます。そこで、次のようにしてPDFファイルを読み込ませることにしました。

  1. PDFKitフレームワークを使ってページごとのテキストを抽出
  2. 1で抽出できなかった場合はVisionフレームワークOCR機能を使ってテキストの抽出を試みる
  3. 抽出したテキストをプロンプトに組み込む
  4. 送信先のモデルがビジョンに対応していれば、各ページを画像化して一緒に送信する

このようにすれば、抽出できたテキストをAIに送信しつつ、ビジョン対応モデルであれば一緒に画像を確認してレイアウトを確認したり、AIモデル自身の能力を使ってOCRの誤検出を訂正したりすることができるのではないかと思ったのです。

しかし、ここで1つの疑問が浮かび上がりました。それは、「AIモデルは何枚までの画像をきちんと認識できるのか?」ということです。

何枚までの画像を認識できるのかテストしてみることに

そこで、ビジョン対応モデルでは何枚まできちんと認識できるのか、APIで送信可能な画像の枚数に制限はあるのかを調査してみることにしました。

ちょうど開発に使用しているMac miniではOllama APIが動いていていくつかのビジョン対応モデルが利用できる状態にしていましたので、開発に使用しているソフトであるGoogle Antigravity IDEを使って、テストの自動化スクリプトを組んでもらってしばらくテストしてみることにしました。
テストの時間があまりかからないように、64 × 64pxの単色ベタ塗り画像を使用して、それぞれの画像の色と枚数をカウントさせるテストを実施してもらいました。

最初のテスト対象モデルは、小型なモデルであるGemma 4 E4Bを使用することにしました。

広告

Gemma 4 E4Bの結果は?

1枚から順に14枚まで増やしていくテストを実行したところ、どうやら5枚目あたりから数え間違いやハルシネーション(嘘・幻覚)が発生することが多いようでした。
これは3枚程度が実用的な範囲なのか…?と思いましたが、今回使用したモデルはたったの45億パラメーターしかない小型なモデルなので、もう少し大きなモデルを使用すれば改善するのかテストしてみることにしました。

次のテスト対象モデルは規模を一気に上げて、Gemma 4 E4B(4.5B)の約6倍のパラメーター数を持つ、家庭用GPU 1枚で動いて性能が高いと噂のQwen3.8-27B(27.8B)のMLXモデルです。

Qwen3.8-27B MLXの結果は?

驚くべきことに15枚までは全く問題なかったので、さらに30枚までのテストを行ってみたところ、なんと全て完璧に認識していました。すごいな、30枚あっても認識できるのか…。一体どこまで認識できるの!?

さらに枚数を増やし、50枚までテストをしましたが、こちらも全て完璧(!)
先ほどGemma 4 E4Bのテストをした時は「画像認識はまだまだだろうな」と思っていたのですが、最新の中型モデルになるととてつもない進化です。ローカルで50ページ以上のPDFファイルを添付する事はほとんどないと思うのでこれだけテストできれば十分ではあるのですが、ここまで来たらどこでエラーやハルシネーションが起きるのか気になってきたのでテストを続行します。

さらに枚数を倍に増やして100枚までテストを行いました。すると、84枚までは1つも落とさず完璧に認識し、85〜100枚まででも時々1つの数え落としが発生しつつも、エラーやハルシネーションが起こることなくほぼ完璧に認識することができました。マジかよ…!

最初に懸念していたOllama APIの枚数制限はなさそうですし、最新のモデルであれば100枚近くに及ぶ大量の画像があっても問題なさそうです。正直ローカルで動く比較的小さなモデルでもここまで大量の画像を認識できると思っておらず、非常に驚きました。
さすがに100枚以上になると一つ一つのテストが完了するまでに時間がかかるので、テストはここで打ち切ることにしました。

画像は1つあたり64 × 64pxの非常に小さな画像で単色しかない非常にシンプルな画像なので、実際のPDFファイルのように複雑で大きめの画像であれば結果は大きく変わる可能性が高いですが、抽出されたテキストはプロンプトにも組み込まれているため、それらを組み合わせればかなり高精度で認識できそうです!

広告

番外編: Gemma 4 26B / 31Bだとどうなる?

これは実装が終わった後に気になったので、Gemma 4ファミリーの中でも大きなモデルではどんな結果になるのか試してみました。

1枚から30枚までのテストを行ってみましたが、Gemma 4 26Bでは残念ながら画像の枚数を正確にカウントする事はほとんどできず、複数の画像を1枚の画像だと認識してしまうことが多いようでした。
一方で、色彩の認識は結構正確なようで、16枚程度まではかなり高精度で認識できていたようです。
ただそれでも、2枚や3枚などの少ない枚数でも無視されている色があったようで、先程のQwen3.8-27B MLXと比べると大きく劣る結果となりました。モデルが大きくても精度はあまり向上していないようです。
ただし、このモデルは、今回テストした中では唯一MoEモデル(26B A4B)で、実際にアクティブになるパラメーター数は38億しかないため、それによって性能が伸びていない可能性があります(ビジョンエンコーダーのパラメーター数は大きくなっていますが)。

続いて、Gemma 4ファミリーの中で最も大きい31Bでテストしてみたところ、26Bのような大きなミスはなくなりましたが、それでも、1、2枚程度の数え間違いは時々起きていたようです。

Gemma 4 31Bよりもわずかに小さいQwen3.8-27B MLXでは圧倒的に多くの画像をきちんと認識できており、たったの4ヶ月程度でここまで大きく進化したわけですから、そう考えるととんでもない進化ですね…!

広告

テキストをプロンプトに組み込む

テストが終わったので、テキストをどのようにプロンプトに組み込むかを考えます。

最初に実装した時は以下のようにプロンプトに組み込んでいました。

ユーザが入力したテキスト

===

Attached File: ファイル名.md

``````````
# ファイル
ファイル内のテキストコンテンツ
``````````

===

Attached File: ...

ユーザがテキストボックスに入力した文字が先頭にあり、その下に添付されたファイルの情報やコンテンツが並ぶような形式でした。

PDFの場合はファイル名の下、コードブロックの上に「Page: 1 / 2」のようにページ番号が追加されます。
PDFKitでテキストが抽出できたページではそのままページ番号が表示されますが、PDFKitで抽出できずにOCRが使用された場合はページ番号の末尾に「(Extracted by OCR)」が追加されるため、ページごとにOCRによってテキストが抽出されたかどうかがわかるようにしています。
OCRでもテキストが抽出できなかった場合はコンテンツ部分が「[No Text Detected by OCR]」となるため、AIモデルがそれを認識できるようになっています(ビジョン対応モデルでは画像と合わせて認識できるはず)。

簡単にテストしたところ全く問題なさそうに思っていたのですが、ふと「LLMの性質上、ユーザのプロンプトは末尾に配置した方が良いのでは?」という考えが頭をよぎりました。以前、プロンプトは末尾に配置した方が良いという情報を聞いたことがあったためです。
ただそれを聞いたのは何年か前の話ですし、とんでもない速度でAIが進化している現在では話が変わってくると思ったので、どちらの方がきちんと正確に従うことができるのかテストしてみることにしました。

今回のテストもAIに組んでもらった自動化テストを行いました。時間の都合上、各テストは2回しか行っていないため正確ではありませんが、あくまで傾向を見るための簡易的なものですのでご了承ください。

Qwen3.8-27B MLXの場合

Qwen3.8-27B MLXの思考: オフでテストしたところ、予想に反して、プロンプトを先頭に配置した方がより正確に指示に従うことができていました(思考: 低以上だとどちらも完璧だったため)。
その後、AIからの助言により、先頭だけでなく末尾にもプロンプトを配置するサンドウィッチ構成にすればさらに精度が上がる可能性があるとのことで、そちらもテストしてみました。

その結果、サンドウィッチ構成でもきちんと指示に従うことができていました。

広告

Gemma 4 E4Bの場合

次は、Gemma 4 E4Bの思考: オンでテストしてみました(設定は低ですが、思考レベルの設定に対応していないのでオンと同じ)。
思考: オフの場合はどれも成功しなかったためオンにしましたが、このモデルでは末尾に配置した場合とサンドウィッチ構成のパターンだけ全て成功しました。
Gemma 4 E4Bでは意外にも先頭に配置するよりも末尾に配置した方が精度が高いようです。どちらにせよ、サンドウィッチ構成ではさらに成功率が高いようです。
面白いことに、サンドウィッチ構成の方が処理時間が圧倒的に短かった(8倍ほど速かった!)です。前後で指示があることでモデルがスムーズに思考できたのかもしれません。

Gemma 4 12B MLX / 26Bでもテスト

他のGemma 4ファミリー(12B MLXと26B)でも思考: オフでテストをしてみたところ、12B MLXではE4Bとは逆で先頭に配置した方が正確でした。こちらもサンドウィッチ構成では確実・最速なようです(わずかな時間なので実質変わらないレベルですが)。
26Bではどのパターンでも成功しました。処理時間はどのパターンでもほとんど同じ。

これらのテスト結果から、先頭や末尾のどちらかにだけ配置するよりも、上下で挟むサンドウィッチ構成の方が精度が上がり、モデルによっては短い時間で出力できるということがわかりました。

そのため、最終的にはプロンプトは以下のようになりました。

ユーザが入力したテキスト

===

Attached File: ファイル名.md

``````````
# ファイル
ファイル内のテキストコンテンツ
``````````

===

ユーザが入力したテキスト
広告

できたもの

これはログファイルを渡して解析させた時の画面です。きちんとテキストを読み取ってレポートを出力してくれました。
ファイルの中身をプロンプトで渡すだけですので何も特別な事はありません。

こちらはAIにHTMLで作成してもらった、5ページで構成された架空の家具カタログPDFファイルを渡して、要約とレイアウトについて説明させたときの画面です。
渡した実際のPDFファイルはこちらからご確認いただけます。

モデル(Qwen3.8-27B MLX: 低)の出力(クリックで開閉)
思考 ユーザーは5ページ構成の架空家具カタログ(VÄRN FORM)の内容要約とレイアウト解説を求めている。提供されたテキストと画像(5枚のページ画像)を統合して理解する必要がある。

まず内容を把握する:ブランド「VÄRN FORM」はスキャナビアン建築的家具のコンセプトカタログ。ページ1は表紙、2は序論・ブランド哲学・目次、3はSTRÖM LOUNGEチェアの製品ページ、4はAURAペンダントランプとKILENモジュールソファ、5は素材アーカイブ・ショールーム情報・AI生成免責事項。価格や仕様は日本語+英語で併記。全体に「静寂」「オーク」「ブークレ」「真鍮」の素材テーマ。

レイアウト解説については、各ページの構造的特徴を整理する:グリッド背景、大きな見出しタイポグラフィ、オレンジ(okara/ochre)と黒、白のコントラスト、影付きボックス、左寄りの画像+右寄りのテキストという非対称配置、バーコード、座標表記、付箋風のタグラベルなど。デザイン言語の一貫性(モジュラー、幾何的、余白重視)も触れる。

回答は日本語で、まず内容要約、次にレイアウト解説の2ブロックで構成。過度に長くならず、かつ各ページを網羅する程度にする。箇条書きと見出しを使って読みやすくする。自己完結させる。

内容の要約

本ファイルは、架空の北欧(スキャナビアン)建築的家具ブランド 「VÄRN FORM(ヴァーン・フォーム)」 の2026/27年版カタログ(VOL.08、コペンハーゲン版、カタログNo. VF-2026-CAT-01)で、全5ページから成るコンセプトドキュメントです。最終ページに記載の通り、ブランド・製品・仕様・価格・画像のすべてがAIにより生成された架空のコンセプトデザインであり、実在の企業・人物・商品とは無関係です。

各ページの内容は次のとおりです。

  • P1(表紙):ブランド名「VÄRN.FORM」と副題「SCANDINAVIAN ARCHITECTURAL FURNITURE」。テーマは「SCULPTED SILENCE(彫られた静寂)」で、無垢オークと有機的フォルムの対話、静寂と構造美を標榜。中央にアームチェアのヒーロー画像を配置し、コペンハーゲン座標(55°40′34″N 12°34′06″E)やバーコードなどで建築図面のような演出。
  • P2(序論・プロローグ):ブランド哲学「WHERE TIMBER MEETS SILENCE」。デンマークの機能主義と北欧ミニマリズムを基盤に、「過剰な装飾を排し、余白を調律する彫刻として家具を捉える」設計思想を宣言。FSC認証オーク、デンマーク製への言及があり、下部に4章の目次(01 STRÖM SEATING / 02 KILEN LIVING / 03 AURA LIGHT / 04 MATERIALITY)を配置。
  • P3(STRÖM LOUNGE):旗艦製品であるアームチェア(モデルNo. STR-01、デザイナー Kaj Lindqvist 2026年)。無垢ホワイトオークの三次元蒸気曲げフレーム+高密度ウレタン&イタリア製立体ブークレ(アイボリィ)のクッションが特徴。仕様は W820×D860×H740mm、座高410mm、傾斜108°、18.5kg。価格は税込み ¥420,000(Made to Order)
  • P4(AURA & KILEN):照明とモジュールソファ。セラミック&真鍮のペンダントランプ「AURA PENDANT」(LED/CRI98、2700K、¥148,000)と、3シーター+シェーズロングのモジュールソファ「KILEN」(W2800×D1650×H680mm、テキスチャードオーツミール、¥780,000)を特集。素材パレット(Cool Mist / Warm Ochre / Natural Oak / Slate Black)も提示。
  • P5(素材・店舗・免責事項):素材アーカイブ(①北欧産ホワイトオーク/ソープフィニッシュ、②耐摩耗性50,000回マーチンデールの高耐久ブークレ、③削り出し無垢真鍮)と、コペンハーゲン(旗艦)・ストックホルム・東京(青山、アポイント制)のショールーム情報。最後にAI生成概念ドキュメントであることを明示する免責事項を掲載。

全体として、「静寂」「天然オーク」「有機的フォルム」「サステナビリティ」「職人技」という価値観を一貫して貫いた、建築的ミニマリズムの家具カタログです。

レイアウトの解説

本カタログは、北欧モダン/建築製図の文法をグラフィック化した、非常に規律のある編集デザインです。主な特徴は以下のとおりです。

  1. グリッド背景とモジュラー構成
    全ページに薄い方眼(罫線)の背景を用い、図面・設計資料のような精密さ・理性的な印象を与えています。要素は矩形のモジュールに分割され、非対称ながらも厳密にアラインされています。
  2. 大胆なタイポグラフィと階層の明確化
    超極太のサンセリフで大きく打ち出した見出し(「VÄRN.FORM」「SCULPTED SILENCE」「WHERE TIMBER MEETS SILENCE」「SHAPING SILENCE, ELEVATING EVERYDAY」等)が各ページの主役。さらに小文字の英字キャプション、日本語の説明文、コード風のモノスペース表記(モデルNo.、座標、バーコード数字)を組み合わせ、情報に明確な階層を作っています。
  3. 限定されたカラーパレット
    白・黒(炭色)を基調とし、アクセントにオレンジ(ウォーム・オッフル/okara) を一点集中で配置。オレンジは強調ボックス、見出しの下書き、タグ、価格帯などに使い、視線誘導とブランドの識別色として機能しています。
  4. 影付きボックスと付箋ラベル
    本文ブロックや画像は、右・下にオフセットした硬いドロップシャドウ(硬質の影)で浮き上がらせ、紙を貼ったような立体的・図感的な処理。さらに「[01] SCULPTED OAK FRAME」のように丸印付きの付箋風タグを画像上に重ね、製品の特徴を注釈(キャプション)として提示しています。
  5. 左画像/右テキストの非対称配置
    製品ページ(P3・P4)では、左側に大きな製品写真、右側に仕様表・価格・説明文を置く二カラム構成。仕様は破線区切りの表形式(DIMENSIONS / FRAME / UPHOLSTERY 等)で整理され、技術仕様書としての信頼性を演出します。
  6. 建築製図的ディテール
    表紙の地理座標表記、バーコード、ページ番号(PAGE 02–05)と章番号(01 / PROLOGUE 等)のヘッダー、枠線で区切られたセクションタイトルなど、カタログ全体が「設計アーカイブ資料」のように統一されています。
  7. ビリンガル(英+和)の並行表記
    説明文は英語と日本語を対で配置し、国際的なブランド感と日本市場への配慮を両立。素材名や価格も税込み表記・単位を明示する等、実用カタログとしての体裁を備えています。

総じて、本レイアウトは「静的・幾何的・余白重視」というブランドの理念そのものを、グリッド、限定的な配色、硬質の影、図面的ディテールという視覚言語で体現した、概念上の一貫した編集デザインといえます。

Qwen3.8-27B MLX

きちんと抽出されたテキストと画像を参照して、レイアウトやデザインについても正しく認識してくれていますね。

バージョン1.4.0は開発中です

今回紹介した内容は、Mocolammaの次期バージョンである1.4.0に搭載される予定です。なお、1.4.0は開発中であり、この記事で紹介した内容は1.4.0の正式リリースまでに変更される可能性があります。

Mocolammaのアップデート情報のお知らせは私のXアカウント(@i_am_taikun)で行いますので、ぜひフォローしていただけると幸いです。

最後まで読んでくださりありがとうございました。それでは、また!

広告

コメントはこちらから!

記事について気になるところや質問、ご指摘など、以下のコメント欄から気軽にコメントしていただけるとうれしいです!

※コメントの投稿には、無料で作成できるGitHubアカウントが必要です。コメント欄が表示されない場合はページを再読み込みしてみてください。

コメント欄ではMarkdown記法が使用でき、画像を挿入することもできます。ここで使用できるMarkdown記法の詳しい使い方は、入力欄の右下にあるアイコンをクリックすることで確認することができます。