カゴシマニアックスでこれまで書いてきた記事を使って、「僕っぽい記事を書いてくれるAI」を作ってみています。名前は僕氏LLMです。
最初はわりと単純に考えていました。過去記事をたくさん読ませれば、取材メモを渡したときに、僕の代わりにそれっぽい文章を書いてくれるのではないか、と。
結論からいうと、まだ全然そこには届いていません。
下書きは出ます。寿司を食べたというメモを渡せば、寿司の記事らしいものは返ってきます。でも、文章が普通すぎたり、メモにない「食べ比べた」という行動を足してきたりします。過去記事の言い回しを混ぜれば僕らしくなると思ったのですが、実際には「過去記事の一部を組み合わせた文章」になりがちでした。
これは失敗の記録であり、LLMをほぼ知らない人間が、どこまでできてどこで詰まったかのメモでもあります。
そもそも何を作ろうとしたのか
やりたかったのは、記事を自動公開する仕組みではありません。
取材して残したメモを渡すと、過去に自分が書いた記事を参考にして、記事の最初の下書きを作ってくれるものです。最終的には僕が直して公開します。
「僕の仕事をなくすAI」ではなく、「白紙から書き始めるしんどさを減らす道具」にしたいと思っています。
ただ、最初はそこを少し勘違いしていました。自分の過去記事を4,000本近く読ませれば、AIの中に僕ができるのではないか、と期待していたのです。
実際に作ったものは、そんなに魔法ではありません。
| 最初に期待していたこと | 実際にできたこと |
|---|---|
| 過去記事を読めば、僕の代わりに自然に書ける | 関連する過去記事を探し、下書きの材料にできる |
| 僕らしい文体は自動で再現される | 文体見本を選んで渡しても、口調はまだ揺れる |
| 取材メモから完成稿まで作れる | もっともらしいが、メモにない事実を足すことがある |
| 4,000本を読ませれば「僕」ができる | 1回の生成では、数個の断片をカンペとして渡している |
どういう流れで動いているか
なるべく難しい言葉を使わずに書くと、流れはこうです。
WordPressの過去記事
↓
僕の記事だけをMarkdownファイルとして保存
↓
検索しやすい形にしてローカルDBへ入れる
↓
取材メモに近い過去記事を数個だけ探す
↓
書き方のお手本を別に数個だけ探す
↓
取材メモ + 過去の事実 + 書き方のお手本
↓
ローカルで動かしているLLMが下書きを作る
図にすると、実際にLLMへ渡している量はかなり少ないです。
ポイントは、4,000記事を毎回まとめてLLMへ渡しているわけではないことです。
記事は全部で3,967本ありますが、実際に文章を作るときに渡すのは、関連しそうな過去記事の数チャンクと、文体用に選んだ数記事だけです。全部入れると長すぎますし、何を大事にすればいいのかモデルも分からなくなるからです。
この「探してから少しだけ渡す」方式は、RAG(検索拡張生成)と呼ばれるそうです。僕はまだLLMに詳しくないので、まずは「必要そうなメモを検索して、AIにカンペとして渡す仕組み」と理解しています。
作ったファイルと役割
中身は意外と地味です。
corpus/kagoshimaniax/active/
過去記事のMarkdown。ここが正本。
data/gemmaniax.sqlite
検索用のデータベース。壊れてもMarkdownから作り直せる。
prompts/writer.md
「何を事実として使ってよいか」「どういう文章にしないか」を書いた指示書。
src/gemmaniax/
WordPress同期、検索、LLM呼び出しなどのプログラム。
config.example.yaml
使用するモデル名や、検索で何件取るかを書く設定ファイル。
記事はWordPressから取ってきますが、誰の記事でも入れるわけではありません。僕自身の記事に絞り、PRカテゴリなどは機械的に外しています。
さらに、過去記事には二つの役割を分けました。
- Knowledge: 店、場所、過去に食べたものなどの「事実の記憶」
- Style: 僕らしい口調やリズムの「書き方のお手本」
この二つを混ぜると困ります。たとえば、文体のお手本として渡したカレーの記事に出てくる店名や料理を、新しい寿司の記事の事実として使われたら困るからです。
使ったモデル
文章を作るモデルには、LM Studioでローカル実行した google/gemma-4-e4b を使っています。外部の有料APIではなく、自分のMacで動かす選択です。
過去記事を検索するための埋め込みモデルには cl-nagoya/ruri-v3-30m を使いました。こちらは文章を生成するモデルではなく、「このメモと、どの記事が近そうか」を探すためのものです。
検索結果はSQLiteとsqlite-vecに保存しています。名前は難しいですが、小さめのデータベースに「記事の断片」と「文章の近さ」を入れておく仕組みです。今回、3,967記事を17,263チャンクに分けて検索できるようにしました。
何がうまくいかなかったか
一番大きかったのは、「過去記事を読ませる」と「僕になって書ける」は別の話だったことです。
初期の下書きには、取材メモにない「新鮮な海の幸」「サービスが素晴らしい」といった、もっともらしい感想が混ざりました。「会計は現金」とメモしただけなのに、「現金のみの店」と一般化したこともあります。
文章として自然でも、取材記事としてはダメです。
文体も難しいところでした。最初は、寿司の取材メモなら寿司の過去記事を「書き方のお手本」にしていました。でも、それだと同じ説明調の記事ばかりが参照され、僕らしい短いリズムや導入が出ませんでした。
そこで、事実を探す検索と、口調を探す検索を分けました。文体用には「どうも、僕です◯┓」のような書き出しがある承認済み記事を優先して渡すようにしました。
少しは寄りました。でも今度は、口調を真似しようとしてタメ口が強すぎたり、文章が普通の旅行ブログのようになったりします。長文を頼むと、事実を増やさずに書ける分量には限界もありました。
要するに、モデルに「僕らしさ」という曖昧な注文を一発で理解してもらうのは無理でした。禁止事項を増やすだけでも解決しませんでした。
それでも続けたい
ここまで書くと失敗っぽいのですが、やめる理由にもなっていません。
過去記事を自分で検索できるようになったこと自体は便利です。3,967本の中から、ある店や場所について何を書いていたかを探せます。下書きも、完全に使えなくても「ここは違う」と直す材料にはなります。
次は、どの記事を文体のお手本にするかをもう少し丁寧に選ぶこと、取材メモにない事実を足していないかをチェックすること、そして短い下書きで安定してから長文へ進むことをやりたいです。
SEOリライトのような次の機能も考えていますが、まずは新しい記事の下書きが本当に役立つかを確認してからにします。
そもそも僕はLLMについてまだ詳しくありません。だからこそ、分かったふりをせず、小さく作って、失敗したら理由を残して、少しずつ直していくつもりです。
「過去記事を全部読ませたら自分の分身ができる」と思って始めた僕氏LLMは、いまのところ分身ではありません。
でも、過去の自分の文章を探して、一緒に下書きを考える相棒くらいにはなりそうです。もう少し続けてみます。