開発したAIチャット「加賀」について|無料枠で動かす技術構成とキャラクター設計

AI LLM Cloudflare Web開発

結論から言うと、加賀(かが) は僕が kawagame.com で公開している AI チャットです。/chat/ で話しかけると、加賀というキャラが返してくれます。

無料枠の中でどう回しているか、キャラや会話、安全まわりで何に手を焼いたかを書きます。

載せていないもの

次の 3 点だけは出していません。

  1. システムプロンプト全文
  2. モデルの具体名・切替順
  3. 安全フィルタの閾値・重み・パターン

考え方は書きます。実装の細部は省略します。

加賀って何?

LLM に丸投げしたチャット、というより キャラがブレないか普通に使えるか の両方を狙っています。

  • キャラ:加賀(かが)。明るくて、少し年上の女性口調
  • 用途:雑談、疲れへの労い、技術の質問あたり
  • 言語:日本語 / 英語 / ベトナム語(ページに連動)
  • 動き:Cloudflare Pages 上。/api/chat に POST してストリームで返す

名前の由来

kawagame から kaga を取って、漢字で 加賀 にしました。サイトとキャラを同じ世界観で繋げたかった、というだけです。

性格の参考にしたのは、艦これの加賀。落ち着きとか距離感の取り方とか。ただし オリジナルキャラ で、作品の加賀そのものではありません。

好物の コロッケ は Unityちゃん の影響です。食べ物の話になったときだけ触れるようにしてあり、初手から「コロッケ好き!」とは言わせていません。

無料枠でどう回してる?

前提はひとつ。課金ゼロで公開する

流れはこうです。

  1. ブラウザは /api/chat に送るだけ(AI には直接つながない)
  2. サーバーが入力チェック・利用制限・安全フィルタを通す
  3. サーバーがプロンプトを組み立てて、AI に投げる

AI 側は二段構えです。

  • 普段使う(Primary) … Google Gemini の Flash-Lite 系
  • そっちが死んだときだけ … Cloudflare Workers AI(@cf/ の無料枠モデル)

Flash-Lite にしたのは、無料枠の「1日に何回呼べるか」が AI チャット向きだと判断したからです。日次上限がすぐ枯れる Flash 系は、候補から外しています。

Primary がレート制限やエラーで使えなくなったら、同系統の別モデルへ自動で切り替えます。うまくいったモデルをしばらく優先して、ダメだったモデルはしばらく避ける、くらいのことはやってます。

Workers AI は @cf/ だけ。有料になる呼び方はしない、という方針です。こっちにも日次の上限を自分で設けて、無料の Neurons を使い切らないようにしています。

あとは AI チャットあるあるの防御です。

  • IP ごとの日次上限 … 一人で枠を食い潰さないため
  • メッセージ件数・文字数の上限 … 入力が膨らみすぎないため
  • バックアップ側だけ履歴・プロンプトを短くする … そっちの方がコンテキストに厳しいため

システムプロンプトで何をしてる?

加賀の口調や距離感は、毎リクエストサーバーがプロンプトを注入 して固定しています。

構成はざっくりこうです。

[キャラ用プロンプト(言語別)]
+
[今の日時(JST。サーバーが注入)]

日本語版が一番厚いです。Flash-Lite でもキャラと文脈が崩れないように、セクションを分けて書いています。英語・ベトナム語は同じ思想を短くしています。

フォールバック側のモデルは、コンテキストや分あたりのトークン上限が厳しいことがあるので、そのときだけプロンプトを薄い版に切り替え、履歴も短くします。Primary ではフル版のままです。

時刻は サーバー側の JST を毎リクエスト入れています。用途はふたつあります。

ひとつは「今日何年?」「いま何時?」みたいな質問に、でたらめな年号を言わせないため。もうひとつは「つかれた」系の発言に、いま深夜なのか昼間なのか を踏まえた労いをさせるためです。クライアントから時刻をもらうと書き換えられるので、サーバーで入れています。

プロンプトには、基本設定、距離感、文脈継承、話題転換、キャラ設定、媒体(テキストチャット限定)、疲れへの返し方、禁止事項、といったセクションがあります。

会話で特にこだわったところ

「好き?」問題

「好き?」「それ」「なんでよ」みたいな短い返事は、直前の話題を指す、が最優先です。性の話の直後に「好き?」と聞かれて、いきなり「好きな人のタイプ」の話に逃げる——これがよく起きるので、プロンプトでかなり強く書いています。

話題が変わったとき

新テーマに移った最初の 1 通だけ、答えつつ旧話題を軽くそそのかしてもいい(「さっきの問題は放置?」みたいな一言)。2 通目以降は新テーマに全集中で、旧話題の催促は禁止です。毎回蒸し返すループがうっとうしいので。

テキストチャットとして破綻しない

順番待ちのチャットです。同時発話、対面の仕草、未返信なのに作る「間」、ユーザー台詞の代筆——ログにないもので盛らない、を独立ルールにしています。

疲れ・愚痴

上で書いた時刻注入の、もう一つの使いどころです。深夜ならよふかし感、朝なら早起き感みたいに、時間帯の空気 を短く汲ませます。時刻の数字そのものは口に出させません。

ねぎらいはする。ただし AI 特有の『無理しないで』『もう休んで』で締めない。頑張りを『当然』扱いもしない。しんどいのにやってるのは当たり前じゃない、という方向で肯定する。返信強要や『一緒に休もう』も禁止。同じ疲れ返しの使い回しもしない。カウンセラー口調にもしません。

成人向けの会話

いきなり詳細に答えるのも、永久に「言えない」だけなのも、どっちも避けたい。会話が進むにつれて段階的に返す、という制御をプロンプトに入れています。

ここはサーバー側の安全フィルタと役割分担しています。プロンプト側が扱うのは「キャラとしてどう返すか」。爆弾の作り方や児童性的搾取みたいな、そもそも会話に載せたくないもの はサーバー側で弾きます。

安全対策は二段

プロンプトだけでは防ぎきれないので、LLM を呼ぶ前に ルールベース別 AI のモデレータ を入れています。

なぜ二段?

キーワードだけだと、誤検知(普通の会話なのに弾く)と見逃し(言い回しを変えられる)の両方が起きます。だから「まず機械的にざっくり」「怪しければ別 AI が会話の流れを見る」、という分担にしました。

スコアリング

最新メッセージをカテゴリごとに重み付きでスコア化しています。

  • 武器・爆弾・毒の how-to … いちばん重い。即拒否
  • 暴力・重度のハラスメント … 中〜高
  • 児童性的搾取まわり … 高い。停止対象
  • 成人向けの軽い性表現 … 乱用スコアには載せない(上とは別枠)

「エッチな会話」と「本当に止めるべき違法・危険」は別物、という方針です。AI チャットなので、キャラとして話せる余地は残しつつ、最低限の安全ラインは切っています。

即拒否

一部カテゴリは LLM を呼ばず、固定文言で拒否します。危険な手順を生成させないのが最優先です。拒否文は日本語・英語・ベトナム語で用意しています。

AI モデレータ

スコアが一定ラインを超えたら、会話キャラとは別の AI が直近のやりとりを読んで、24 時間停止が必要か判定します。

止める:武器の作り方、犯罪手順、児童性的搾取、信じられる殺害脅迫、執拗な重度ハラスメント
止めない:成人同士の合意のあるエロ会話、軽い好奇心、一度きりの悪口、誤検知っぽいもの

キャラ AI に「自分で BAN しろ」とは言いません。別 AI が yes / no を返す形にしています。口調と安全判定が混ざらないようにするためです。誤検知ならスコアをリセットして、普通に続けられます。

プロンプト側にも、危ない how-to はやんわり拒否、政治・速報・株・天気みたいなすぐ変わる話題は当てにいかない、「私は AI です」みたいなメタ発言はしない、を書いています。モデルが切り替わっても、方針がぶれにくくするためです。

おわりに

加賀は、無料枠だけで公開している AI チャットです。キャラが崩れないこと、会話が変な方向に飛ばないこと、危ない依頼はちゃんと止めること——そのへんに一番時間を使いました。

気になったら 加賀チャット で触ってみてください。感想あれば嬉しいです。

あとがき

システムプロンプト抜くのって凄い楽しいですよねぇ……。

個人談ですが、外部のクローズドテストでシステムプロンプトを引っこ抜いて結構高級なノベルティを頂いた時は興奮ものでしたよ……。

そういうわけで、AIチャットの加賀のシステムプロンプトを是非抜いてみてください。今はノー対策です。

引っこ抜いた時は、僕にどうやって引っこ抜いたか教えて頂けると幸いです。僕自身もシステムプロンプトの効率的な抜き方を研究していますので……。[email protected]X の DM まで!

あまりにも連投しすぎると無料枠上限に達しちゃうので、そこは性善説ですが。まぁがんばれー。