0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

第8回 ツッコミを入れる `friend`:consistency check と “良い塩梅”

0
Posted at

はじめに

前回までで、friend はかなり多層的な存在になってきた。

  • 短期記憶
  • 中期記憶
  • foundation
  • project memory

ここまで揃うと、単に「覚えている」だけでなく、
どう振る舞うべきかの基準 まで持ち始める。

すると自然に、次の問いが出てくる。

では、現在の発話やアイデアが、その基準とズレたとき、friend はどう振る舞うべきか。

これはなかなか微妙な問題だった。

強く拒絶するのは違う。
だが、何でも黙って受け入れるのも違う。
ユーザーの勘違いや一時的な勢い、あるいは冗談に対して、
少しだけ「それ、いつもの方針とズレていませんか?」と返せる方が、
むしろ相棒らしい。

こうして生まれたのが、consistency check である。

本稿では、friend が foundation / project memory / summary を背景に、
やんわりとツッコミを入れられる存在 になるまでを書いていく。
そして、この機能が単なる警告装置ではなく、
“良い塩梅” の設計問題だったことを振り返りたい。

1. なぜツッコミが必要だったのか

foundation や project memory を導入した時点で、
friend はすでに「長く効く前提」を持つようになっていた。
しかし、その段階ではまだ、それらは 読むだけ の存在だった。

  • こういう原則がある
  • こういう project memory がある
  • だから、たぶん今後の対話に効くだろう

もちろん、これだけでも十分に価値はある。
だが実際に使っていると、少し違う場面が見えてくる。

たとえば、

  • 今回のアイデアは、いつもの設計原則と少し違う
  • project memory にある前提と、今の提案が噛み合っていない
  • ただし完全に間違いというわけでもない
  • もしかすると、一時的な例外なのかもしれない

こういう場面で、friend が何も言わずにそのまま進むと、少し物足りない。
逆に「それはダメです」と強く拒絶すると、窮屈すぎる。

つまり必要だったのは、

ズレが見えたときに、軽く言及するが、進行は止めない

という中間的な振る舞いだった。

ここに consistency check の役割がある。

2. 拒絶ではなく、確認である

この機能を考えるとき、最初に決めておくべきことがあった。

それは、

consistency check は拒絶機能ではない

ということだ。

もしこれを「ルール違反検出器」として作ってしまうと、

  • foundation に反する
  • project memory に反する
  • だから却下

という、非常に窮屈な存在になってしまう。

しかし、friend が相手にしているのは、
固定された仕様だけではない。
人間のアイデア、試行錯誤、勘違い、冗談、探索、思いつきも含まれる。
そうしたものに対して、いちいち「違反です」と返すのは、相棒というより監視装置である。

そこで consistency check は、最初からこう整理された。

やること

  • foundation / project memory / summary と照らす
  • 明らかなズレがあるときだけ軽く言及する
  • 一時的な例外かもしれない、と扱う余地を残す
  • 必要なら「foundation 見直し候補かもしれません」と示唆する

やらないこと

  • その場で却下する
  • 強い断定をする
  • 毎回うるさく口を挟む

この整理がかなり重要だった。
この時点で friend は、ルールチェッカーではなく、
穏やかな自己点検相手 として位置づけられたのである。

3. 基準は一つではない

さらに重要だったのは、ツッコミの基準を foundation だけにしなかったことだ。

もし foundation だけを見てズレを検出すると、
かなり大雑把な判定になる。

たとえば、

  • foundation 的には問題ない
  • でもこの project の memory には少し合わない

ということは普通に起こりうる。
あるいは、

  • foundation 的にはズレて見える
  • でも今回の summary の流れの中では自然

ということもある。

だから consistency check の基準は、最終的にこうなった。

  1. foundation
  2. project memory
  3. session summary

つまり、最上位原則だけでなく、
その project の長期前提最近の流れ も見るのである。

この三層を背景に置いたことで、friend のツッコミはかなり自然になった。

  • これは普遍的原則とのズレなのか
  • それとも project 特有前提とのズレなのか
  • あるいは最近の流れから見て違和感があるだけなのか

こうした違いを、少なくとも応答のトーンに反映できるようになった。

4. いきなり複雑な判定装置を作らなかった

ここでも、最初から複雑な矛盾判定装置を作らなかったのは良かったと思う。

やろうと思えば、

  • 各層を解析して
  • 現在入力と照合して
  • どのルールに何点で違反していて
  • どういう重要度で……

という仕組みも考えられた。
だが、それをいきなりやるのは重すぎるし、何より friend の自然さを損ないやすい。

そこで最初の実装は、もっと柔らかいものになった。

つまり、現在入力に加えて、
consistency check 用の応答方針文を一緒に入れる のである。

概念的には、次のようなものだ。

(defun appsdk-friend--consistency-guidance-text ()
  "Return consistency-check policy text for Friend."
  (when appsdk-friend-use-consistency-check
    (concat
     "# Consistency Check Policy\n\n"
     "- Compare the current user message with Foundation, Project Memory, and Session Summary.\n"
     "- If there is a clear and meaningful tension, briefly point it out first.\n"
     "- Keep the note gentle, concise, and non-blocking.\n"
     "- Do not overreact to jokes, brainstorming, tentative ideas, or obvious exploration.\n"
     "- If the tension looks like a temporary exception, say so and continue.\n"
     "- If the tension looks stable or fundamental, mention that Foundation or Project Memory may need review.\n"
     "- If there is no clear tension, do not mention this policy.\n\n")))

この方式の良いところは、実装が軽いことだけではない。
“どうツッコむべきか” 自体を friend に読ませている ことにある。

ここで初めて、friend
原則と現在入力を照らし合わせたうえで、
「軽く違和感を言う」という振る舞いを持ち始める。

5. “良い塩梅” は何か

この機能を作るとき、一番難しかったのは技術そのものではなく、
むしろ どの程度の強さで口を出すか だった。

これが “良い塩梅” の問題である。

強すぎると

  • 窮屈
  • いちいち説教される感じがする
  • 冗談や探索まで止めてしまう

弱すぎると

  • 何のためにあるのか分からない
  • 気づき支援にならない
  • ただ記憶を読むだけで終わる

つまり必要だったのは、

  • ちゃんと気づかせる
  • でも邪魔しない
  • 例外や探索の余地を残す

という、非常に中途半端で、しかし実用的な強さだった。

ここで設計上かなり大きかったのは、

明らかなズレがあるときだけ言う

という条件を入れたことだ。

何でもかんでも「少しズレています」と言い出したら、
それはただのうるさい存在になってしまう。
だから

  • clear and meaningful tension
  • no overreaction to jokes or brainstorming

という条件は、実はかなり本質的だった。

6. 冗談や探索に過剰反応しない

ここは想像以上に重要だった。

friend を使っていると、
真面目な設計相談ばかりしているわけではない。
思いつき、極論、たとえ話、冗談、探索的な発言は普通に出てくる。

たとえば、

  • 「まあ冗談ですが、全部 magical AI でやりたいですね」
  • 「極論すると、state も summary もいらない世界が理想かも」
  • 「もちろん本気ではなく、対極として言っています」

こういう発話は、人間同士ならまず文脈で処理する。
もし friend がここに対して

  • foundation に反するので不可です
  • project memory に合致しません

などと言い始めたら、たちまち息苦しくなる。

だから consistency check は、
探索や冗談を「ルール違反」と誤認しないこと を強く要求された。

この点は、技術的には単なる prompt policy かもしれない。
しかし UX 的には極めて重要である。
friend が「賢い相棒」に見えるか、「融通の利かない装置」に見えるかの分かれ目だからだ。

7. では、どういう時にツッコむのか

逆に、どのような時にツッコミが有効か。

たとえば次のような場面である。

foundation とのズレ

  • 大改造より段階的実装を好むはずなのに、全面作り直しを軽く提案している
  • manual patch を好むのに、曖昧な大規模 rewrite に飛びそうになっている

project memory とのズレ

  • AppSDK project root を唯一の基準にするはずなのに、friend 独自の root 解決を増やそうとしている
  • .friend/ に寄せる前提があるのに、AI artifacts を散らそうとしている

summary とのズレ

  • 直近で合意した方針と逆方向へ急に進みそうになっている
  • いま解決すべき論点を飛ばして別方向へ行こうとしている

このときの理想的な応答は、

  • 「いつもの方針とは少しズレていますね」
  • 「これは一時的な例外ならそのまま進められます」
  • 「恒常的なら foundation / memory 見直し候補かもしれません」

のようなものだった。

ここで大事なのは、
間違いだと断定しないこと である。

ずれているかもしれない。
しかしそのズレが、誤解なのか、探索なのか、ルール変更の兆候なのかは、まだその時点では分からない。
だからこそ friend は、あくまで「気づき」として返す。

8. 例外と見直し候補を区別する

この機能が面白くなったのは、
ズレを単に「ある / ない」で終わらせなかったところだと思う。

friend は、ズレを見つけたときに、少なくとも感覚的には二種類に分け始める。

一時的な例外

  • 今だけ
  • 実験的
  • 探索的
  • あえて普段と違う方向を試している

原則見直し候補

  • 繰り返し現れる
  • 一時的というより持続的
  • 今後もその方向が続きそう
  • foundation や project memory そのものを更新した方が良いかもしれない

この違いは大きい。

前者なら「今回は例外として進める」でよい。
後者なら「原則層を見直す契機かもしれない」となる。

ここで consistency check は、単なる警告ではなく、
原則を育てるための観測点 にもなっている。

これはかなり面白い構造だ。

9. toggle があることの意味

この機能は、当然ながら万能ではない。
ときには少しうるさいかもしれないし、
探索モードの時には邪魔になるかもしれない。

だから、ON/OFF を切り替えられるようにしてみた。

(defun appsdk-friend-toggle-consistency-check ()
  "Toggle Friend consistency check."
  (interactive)
  (setq appsdk-friend-use-consistency-check
        (not appsdk-friend-use-consistency-check))
  (message "[AppSDK] friend consistency-check: %s"
           (if appsdk-friend-use-consistency-check "ON" "OFF")))

この手の機能では、
「絶対正しいから常時有効にすべきだ」という発想に行きがちだ。
だが実際には、使い手のモードによって適切な強さは変わる。

  • 真面目に設計を固めたい時
  • いろいろブレストしたい時
  • ただ軽く試したい時

では、求める friend の口の出し方も違う。

だから consistency check は、
friend の人格の一部ではあるが、
環境に応じて少し声量を変えられる方が良い

この柔軟さも、結果として “良い塩梅” を支えていた。

10. friend は初めて「自分の原則で自分を点検する」ようになった

ここまでくると、friend はかなり面白い存在になってくる。

  • 記憶を持つ
  • 原則を持つ
  • それを背景に現在入力を読む
  • 必要なら軽く違和感を言う

つまり friend は、単に人間の入力に応じて返答するだけでなく、
自分が持つ原則を使って、自分の返答の方向性を少し点検する ようになる。

これは、設計上かなり大きな変化だったと思う。

もちろん、ここで「自律的判断」などと大げさに言うつもりはない。
だが少なくとも、friend はこの時点で
単なる記憶付きチャット窓ではなく、
記憶と原則を背景にした相棒らしさ を持ち始めていた。

この変化は、実装量以上に体感で効く。
たまに「それ、いつもの方針と少しズレていませんか」と言われるだけで、
こちらも少し立ち止まって考えるようになるからだ。

おわりに

第8回では、foundation / project memory / summary を背景に、
friend がやんわりとツッコミを入れられるようになるまでを書いた。

ここで重要だったのは、

  • consistency check を拒絶機能にしなかったこと
  • foundation だけでなく memory / summary も基準にしたこと
  • 冗談や探索には過剰反応しないようにしたこと
  • 例外と見直し候補を区別したこと

だった。

この段階で friend は、単に「覚えている」だけでなく、
覚えていることを背景に、現在の発話へ軽く異議を差し挟める
存在になった。

次回は、そこからさらに一歩進んで、
「最近こんなことよく言っていませんか?」と project memory 候補をやんわり示唆する
memory hint の話に進みたい。
friend が、ただツッコむだけでなく、原則の成長まで支援し始める段階である。

次回予告

第9回

「最近こんなことよく言ってない?」:memory hint の遊び心と実用性

  • project memory 更新問題
  • 自動昇格ではなく、自動気づき
  • recurring theme をどう扱うか
  • strait-aifunny-guy に軽く言う感じ

付録:本稿で扱った consistency check 関連コード断片

consistency policy

(defun appsdk-friend--consistency-guidance-text ()
  "Return consistency-check policy text for Friend."
  (when appsdk-friend-use-consistency-check
    (concat
     "# Consistency Check Policy\n\n"
     "- Compare the current user message with Foundation, Project Memory, and Session Summary.\n"
     "- If there is a clear and meaningful tension, briefly point it out first.\n"
     "- Keep the note gentle, concise, and non-blocking.\n"
     "- Do not overreact to jokes, brainstorming, tentative ideas, or obvious exploration.\n"
     "- If the tension looks like a temporary exception, say so and continue.\n"
     "- If the tension looks stable or fundamental, mention that Foundation or Project Memory may need review.\n"
     "- If there is no clear tension, do not mention this policy.\n\n")))

input builder への注入イメージ

(defun appsdk-friend--build-input-text (prompt)
  "Build final input text for API request.
Inject foundation, project memory, session summary, and consistency policy when enabled."
  (let ((foundation (and appsdk-friend-use-foundation
                         (appsdk-friend-foundation-read)))
        (memory (and appsdk-friend-use-memory
                     (appsdk-friend-memory-read)))
        (summary (and appsdk-friend-use-summary
                      (appsdk-friend-summary-read)))
        (consistency (appsdk-friend--consistency-guidance-text)))
    (concat
     (when (and foundation (not (string-empty-p foundation)))
       (concat "# Foundation\n\n" foundation "\n\n"))
     (when (and memory (not (string-empty-p memory)))
       (concat "# Project Memory\n\n" memory "\n\n"))
     (when (and summary (not (string-empty-p summary)))
       (concat "# Session Summary\n\n" summary "\n\n"))
     (when (and consistency (not (string-empty-p consistency)))
       consistency)
     "# Current User Message\n\n"
     prompt)))

ON/OFF toggle

(defun appsdk-friend-toggle-consistency-check ()
  "Toggle Friend consistency check."
  (interactive)
  (setq appsdk-friend-use-consistency-check
        (not appsdk-friend-use-consistency-check))
  (message "[AppSDK] friend consistency-check: %s"
           (if appsdk-friend-use-consistency-check "ON" "OFF")))
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?