この一連の記事では、主軸が移りました。前回の記事 AIによるブログ執筆は、結局エンジニアリングにする必要がある(1):blog-writerがなぜ生まれてきたか では、消費側(コンテンツの利用側)の自動化について取り上げました。この記事からは生産側、つまりスタイルデータがどのように生成され、どのように圧縮され、どうすればトークンを無駄に燃焼させないかという点について語ります。次の記事では AIによるブログ執筆は、結局エンジニアリングにする必要がある(3):ローカルモデル、オンラインモデル、そしてMinimaxの役割分担 を続けます。
最初の一番自然な発想は、過去の記事をそのまま与えることだ
この道筋は本当に自然すぎる。 モデルにあなたの書き方を学ばせたいのなら、最も直感的な方法はもちろん、古い記事を餌として与えることだ。できれば、過去のブログの中で自分自身に一番近いと感じるものを詰め込んで、自分で要約させるのがベストだ。 一度きりのタスクを見る限りでは、これを行っても問題はない。 むしろ多くのケースで効果は良い。コンテキストが十分長く、モデルが十分に強力で、過去の記事が十分にあれば、スタイルを習得することは確かに可能だ。 しかし、問題は「この記事を書き上げられるか」ではなく、「次の記事、その次の記事も、これを繰り返さなければならないのか」ということなのだ。 毎回古い記事のバッチを再投入することは、いくつかの非常に現実的な副作用をもたらす:
- 同じ材料が繰り返しコンテキストを占有する
- トークン消費量が執筆回数にほぼ線形に増加する
- モデルが見るノイズが増えすぎ、真に有用なシグナルが逆に希釈されてしまう
- 執筆という動作とスタイル維持という動作が完全に結びつき、どちらも軽々しくできなくなる つまり、トークンが潤沢な時は、生で与えるのはもちろん可能だ。しかし、工学的な観点から常にこのようにすることはできないのだ。
これがデータモジュールとデータ生成モジュールを分離しなければならない理由です
後になって考えたところ、核心は一言に尽きます。「消費側」と「生産側」を分けることです。
blog-writer が担当しているのは消費側です。これは、すでに公開されたランタイムを読み取り、固定の契約に従って記事を書き出すだけです。
一方、スタイルデータのスキャン、フィルタリング、スコアリング、圧縮、プロバイダー比較などは、別の生産側のパイプラインに置かれるべきでした。つまり、後から作られた blog-style-suite のようなものです。
gitの履歴を見れば、この転換は非常に明確です。
2026年4月1日 21:47 のコミット 84a06b5 で、元の blog-style-maintainer スキルがリポジトリレベルのCLIツールに置き換えられたことが明記されています。この動きは物事を物語っています。なぜなら、scan/build/rebuild があり、出力ディレクトリがあり、リカバリ機構がある時点で、それはもはや単なる「スキル」ではなく、通常のPythonプロジェクトのように見えてくるからです。
さらに2026年4月1日 23:05 のコミット 9e92b8e では、blog-style-suite が scanner.py、builder.py、compressor.py といったモジュールに分割され続けました。この段階に至ると、考え方はすでに非常に工学的なものになっています。
scanner.py: ディスクから記事をスキャンし、構造化された特徴を抽出する役割builder.py: スコアリング、選別、キャッシュ、ランタイムアセンブリの役割compressor.py: モデルが関与するいくつかの圧縮ステップを担当する
これは、単にスーパープロンプトを一段書くというアプローチとは、全く異なる考え方なのです。
トークンを節約するのは、玄学ではなく前処理とバッチ化によるもの
このエンジニアリングセットで真に価値があるのは、2026年4月2日19:41のbc4b950だと思います。
あのコミットは非常に率直なことを述べていました。AIの呼び出し回数が約「2000回」から、各プロバイダーで最大「5回」に直接削減されたのです。
どうやって達成したのか? それは「プロンプトをより賢くする」のではなく、事前に処理すべきものを前もって実行することによるものです。
現在のblog-style-suiteのフローは非常に明確になりました:
scanフェーズは純粋にヒューリスティックであり、AI呼び出しは0回。buildフェーズではまずヒューリスティックなスコアリングを行い、これもAI呼び出しは0回です。- その後、
technical / finance / essay / toolingの4つのレーンそれぞれで1回のバッチ選別とラベリングを行います。 - 最後に作者スタイルの圧縮を1回行います。
これを計算すると、コールドスタートでも最大5回の呼び出しに抑えられます。
さらに重要なのは、この5回が各記事に分散しているのではなく、すでに前処理された高価値な要約材料に集中している点です。
これが前処理が真にトークンを節約する部分です。単に数文字を減らすのではなく、「記事ごとに呼び出す」から「フェーズごとに集中的に呼び出す」というパラダイムシフトなのです。
その後は、キャッシュも整備されました。
builder.pyにはレーンのバッチフィンガープリントがあり、プロバイダーのチェックポイント復元機能があり、さらにローカルモデルのコンテキストのためにreview_pool_per_lane = 12のような縮小化が行われています。少しデータを変更しただけで、パイプライン全体を再実行する必要がありません。
こうした設計は一見派手ではありませんが、一つ一つが非常に実用的です。なぜなら、それらはすべて「同じトークン群を二度と無駄に燃焼させない」という問題を解決しているからです。
現在のデータ構造は、本質的に真に有用なシグナルを圧縮しているものだ
この構造を分解すれば、データ構造も整理されるだろう。 私は今、これを3層として理解する方がより良いと感じている。
第1層:scan.json
これは共有の原料です。
ここには、記事のパス、タイトル、日付、カテゴリ、タグ、冒頭段落、クロージングスタブ、見出し、スクリーニング結果、レーン分類といった構造化されたシグナルが格納されています。
これは blog-writer に直接渡されるものではなく、生産側でさらに加工するためのものです。
第2層:{provider}.source.json
これはプロバイダーレベルのチェックポイントです。 共有された原料に加え、スコアリング結果、レーン選択、フィンガープリント、キャッシュステータスといった中間状態が追加されています。つまり、「加工過程の中間製品」のようなものであり、復元可能、再利用可能、中断して再開できる点が重要です。
第3層:{provider}.runtime.json と published.runtime.json
これが消費側が真に気にする完成品です。 ここには以下のものが保持されています:
author_stylelanessampleswriter_guideつまり、元々大量にあった過去の記事群を、そのまま利用できるランタイムスタイルアセットとして圧縮したものになります。 特にpublished.runtime.jsonという公開用のファイルが重要です。blog-writerはこのファイルのみを読み取り、content/postを再スキャンしたり、suite ディレクトリ内の全プロバイダーの完全なイメージを気にする必要がなくなります。 この境界線が引かれることで、消費側は軽量化します。執筆モデルが見るのは、もはや原始的な古い記事の山ではなく、すでに前処理された高密度のシグナルとなるのです。
すべてのことをモデルにさせるべきではない
最近、このエンジニアリングにおいて最も正しい判断は、「モデルを多く追加すること」ではなく、「モデルに任せるべきでないこともモデルに投げ渡さないこと」だと感じています。
以下のようなことは、ローカルルールで処理する方が適しています:
- frontmatter の解析
- 冒頭段落の抽出
- 見出し(headings)の抽出
- 本人/転載/モデルによる署名の判断
- blockquote の比率チェック
<!--more-->や埋め込みプロンプト、本文の長さといったハードルルールでのフィルタリング
これらの作業をモデルにやらせることは不可能というわけではなく、単に無駄です。
モデルがより適しているのは、曖昧さやトレードオフを含む部分です。例えば、「あるレーンの中でどの記事が現在の論調をよりよく代表しているか」、あるいは「高評価の記事から著者のスタイルタグを抽出する」といった作業です。
そのため、blog-style-suite が真に価値があるのは、「トークンを節約できる」という点だけではなく、人間、ルール、モデルのそれぞれが担当すべき役割を再定義した点にあるのです。
前処理はトークンを節約するためではなく、執筆作業を持続可能にするためである
第2回の結論について、もっと直接的に伝えたい。
トークンが潤沢な時は、過去の記事をそのまま使うのはもちろん問題ない。むしろ、本当に1〜2本だけ書くなら、頭を使う量が少ないかもしれない。
しかし、このことを長期的なワークフローにしたいと思うなら、前処理は選択肢ではなくなる。なぜなら、前処理をしないと、執筆モデルは毎回古い素材を見直さなければならず、スタイルの維持と記事生成が常に混ざり合ってしまうからだ。
blog-style-suite の意味するところは、このごちゃ混ぜになっているものを分解することにある。
システムに見せるためでも、プロジェクト名を増やすためでもなく、blog-writer が軽快に、安定して、「執筆」という一つの動作だけに集中できるようにするためなのだ。
ここまで来ると、次のステップの問題は自然とついてくる。
すでに生成側が独立した以上、このコストをどのモデルに負わせるべきなのか?ローカルモデル、オンラインモデル、Minimax はそれぞれどの工程に立つべきなのか?この件については、次回の記事 AIでブログを書くという行為は、結局エンジニアリングにする必要がある(三):ローカルモデル、オンラインモデル、そして Minimax の役割分担 で触れることにする。
参考資料
- リポジトリコミット:
84a06b5dc743f2e9bc6e788d53496a1261bc63ae - リポジトリコミット:
9e92b8e6a15d03e6392aff7f3b2dcb0992fe5043 - リポジトリコミット:
bc4b950cbb13e37d1fdb16a9d23325cfefa6f90e - リポジトリファイル:
scripts/blog-style-suite/README.md - リポジトリファイル:
scripts/blog-style-suite/style_pipeline/scanner.py - リポジトリファイル:
scripts/blog-style-suite/style_pipeline/builder.py - リポジトリファイル:
scripts/blog-style-suite/style_pipeline/compressor.py - 有効なランタイム:
.agents/data/blog-writing/published.runtime.json
作成上の注記
元のプロンプト
$blog-writer 今回の内容は多いため、シリーズ記事に分割しました。昨年も多くの原稿が大規模言語モデルによって書かれました。その際は、自分でアウトラインや質問リストを作成し、AIに原稿を生成させ、内容をローカルのmdドキュメントにコピーし、ヘッダー情報、タグ情報などを記入して投稿するという流れでした。最近はCodexを多く使用し、Codexのインターネット検索能力が非常に強力だと気づいたため、これらの作業を自動化するskillを作成できないかと考えました。これがskill blog-writerの初稿の誕生につながりました。また、AIに以前の記事のスタイルを学習させたいと考えたため、blog-writerの実行時にトークンを大量に消費するという問題が発生しました。その後、私はblog-writerに対して複数のバージョンの最適化を行いました。データモジュールとデータ生成モジュールに分割したのですが、元々のデータ生成モジュールは独立したskillでした。書き進めるうちに、Pythonプロジェクトとしてまとめた方がより適していることに気づき、それがblog-style-suiteの誕生につながりました。さらに、スタイルデータの学習もトークンを消費することが多いと感じたため、ローカルの大規模言語モデルを使用することにしました。ローカルの大規模言語モデルとオンライン版の違いを比較したいと考え、minimaxを組み込みました。blog-style-suiteとblog-writerの進化の歴史は、gitのコミット履歴から分析できます。ついでに、ローカルのblog-writerやblog-style-suiteのコードを基にして、設計思想(どのようにトークン節約を実現したか、データ構造をどう設計したか、核となる設計思想)について説明することができます。トークンが潤沢であれば過去の記事を丸ごと処理できますし、前処理を行うことで多くのトークンを節約できます。
ライティングの骨子(要約)
- 本稿では、執筆という行為からデータエンジニアリングへと焦点を移し、「なぜモジュール化する必要があるのか」という核心的な問いに答えることを目指した。
- 冒頭で「生きた歴史の記事をそのまま使える」と認めることで、後続の分割理由に説得力を持たせている。
scan.json、source.json、runtime.jsonの三層構造を重点的に展開し、単なるアーキテクチャの説明に留まらないようにした。bc4b950を中間地点の転換点として配置した。なぜなら、「約2000回から5回へ」という変化が前処理の価値を最も明確に示すためである。- 最後に、消費側と生産側を再分離し、次回の記事で扱うモデルの役割分担への布石を打った。