技術約6分で読めます

かなの近況雑談と画像生成をつなぎ、エージェントへのタスク受け渡しも見直した

いけさん目次

自作の会話窓口「かな」(チャットから呼び出すAIアシスタント)に、短い近況の雑談と、それに対応する画像を返す仕組みを追加した。
実際に会話しながら画像との組み合わせを調整し、あわせてBacklogから受けたタスクが調査で止まってしまう問題や、実行エージェントの通信が権限で遮断される問題も見直した。

前回の記事では、常駐サーバー基盤のPiとLLMのQwenを入口にして、タスクの進捗を管理する作業台帳や、Claude・Codexなどの各AI CLIをつなぐ全体像を書いた。
今回はその窓口を使い、返答が出るところから画像や指示した作業の結果が戻るまでを通してみた。

会話の間が空いたときに、かなから近況を送る

こちらから延々と話しかけ続けることもないので、かなの側から話を振る仕組みを考えた。
接続しているサービスの更新を知らせることもできるが、まずは「いまこんなことしてる」という雑談を既存のチャットへ流す形にした。

直前まで会話していたところへ別の話題を差し込まれても困る。
自発的に送る場合は、最後の会話からの経過時間、入力中かどうか、送ってよい時間帯、当日の回数をサーバー側で確認する。今回は期限を決めた試行として、会話が2時間以上空いてから、時間を少しずらして候補を作るようにした。送信は1日1回までに制限している。

かな自身の日常を作るための補足設定も分けた。
20歳くらいで、仕事や勉強をし、IT情報や機械いじり、アニメやゲームの情報に興味がある、といった内容だ。これは近況の雑談や対応画像を作るときに使う設定で、通常の作業報告に毎回プロフィールを混ぜるわけではない。

最初に出てきた文章は、近況を伝えるにしては長かった。
一つの話題を短い1〜2文で返すようにし、長くなった場合もプログラムで末尾を切らないで、Qwen自身に短く書き直させるようにした。

雑談の本文から、対応する画像指示を作る

画像は、文章とは別々に思い付いたものを出すと内容がずれてしまう。
先にQwenで雑談の本文を確定し、その本文から同じQwenが画像生成用の指示と参照素材を指定する。実際の描画は、Codex CLIに備わっている画像生成機能に任せる。

flowchart LR
    A["Qwenで近況の本文を作る"]
    B["本文から画像指示と参照を決める"]
    C["Codexで画像を生成する"]
    D["元の返答へ画像を付ける"]
    A --> B --> C --> D

本文でまだ何をするか考えている段階なのに、絵の中ではもう作業を終えている、といった不整合も避けたい。
行動、場所、服装、表情を確定した本文へ合わせ、本文と矛盾しない範囲で絵の細部を補う。本文を作る段階と画像の指示を作る段階を分けたことで、両者の対応関係を確実に合わせられるようにした。

参照用には、あらかじめ選んであったかなの画像33枚をすべて登録した。
使う画像の候補を絞るのではなく、表情、顔の向き、衣装、用途が名前と一覧から分かるように整理した。Qwenが生成のたびに元画像を開いて分類し直さないで、必要な素材を直接指定できるようにしている。

ただし、使う元画像が合っていても、顔や頭身、服装がそのまま出るとは限らなかった。
背が高すぎたり逆に幼くなったりしたので、元の顔と体型を保つプロンプトを調整した。運動着の全身画像を体型の参照に使う場合も、外出の場面にその服が出ないようにする。衣装を参照するのか、体型だけを参照するのかを指示レベルで分けた。

塗りは、くっきりしたアニメのセル塗りに寄せた。
この画風と元の頭身を保つ指定は、Qwenが毎回生成する指示文に委ねず、画像生成へ送るプロンプトの末尾にサーバー側で固定で付与する。

ソファでスマートフォンを見ているかなの生成画像

「ソファでITニュースを見ている」という近況に対応させた出力例が上の画像だ。
現在は、このようにかなの返答本文と生成画像をひとつのメッセージにまとめて返せる。画像の保存と生成ジョブの完了を確認してから表示へつなぐため、生成要求を受け付けたことと画像が生成完了したことも別の状態として管理している。

「今何してる?」の後に一言続くと通常の会話に流れていた

こちらから近況を尋ねた場合も、短い雑談と画像を返すようにした。
ところが、単独の「今何してる?」なら通るのに、「今何してるの?俺はそろそろ寝る」と送ると画像が付かなかった。近況質問だけの文に完全一致させて判定していたため、後ろに一言続くだけで通常の会話処理へ流れてしまっていた。

文の中に近況を尋ねる意図が含まれているかを拾う判定に改めた。
単独の質問はそのまま処理し、後半にも文がある場合は、入力全体が雑談であることを確認したうえで近況と画像を生成する。別の作業や予約の指示が含まれる場合は、この近況応答で上書きしない。

ブラウザのチャット画面から後半付きの質問を送り、32字の日本語の近況とCodexの生成画像1枚が同じ返答に付くところまで確認できた。
「写真を見せて」と重ねて頼む必要はなくなった。後半の寝るという話題に触れるか、近況の報告に集中するかといった会話の細部はモデルの文脈判断に任せている。

天気情報も、話題に混ぜるなら取得した情報と発言の時刻が合っていなければならない。
現在の気温に日別の最高・最低気温を流用しないようにし、必要なタイミングで現在値を取得する形に改めた。参照する位置情報も取得時刻と照合して扱う。天気を毎回無理に話す設定にはしていない。

なお、日本語を指定していても、簡体字が混じったり一文まるごと中国語になったりする返答が稀に出ることがあった。
日本語の文として最後まで完結させるシステムプロンプトを補強したが、モデル側の語彙選択による混入を完全にゼロにできるかは今後の監視が必要だ。現在の日本時間と発言日時を渡していても、日付をまたいだ直後に前夜の「明日」をそのまま引き継ぐ返答も確認された。

Backlogのチケットを読めても、ファイル取得が進まなかった

外部の課題管理(Backlog)からタスクを受け取って連携する処理も、実際の作業で使ってみると、チケットの本文が取得できるだけでは実用に足りなかった。
必要なファイルを取得してローカルへ保存するタスクを投げたのに、窓口から実行エージェントへ渡るときにタスク種別が「調査」として登録されてしまった事例があった。

「調査」タスクとして渡されると、実行エージェントは読み取り権限を中心に動作する。
資料を読み、ファイルの所在を確認した段階でタスク完了と判断してしまい、実際のダウンロードや保存は行われない。実行結果を確認すると、記録にある保管場所を照会しただけで終わっていた。

指示の内容ワーカーに渡った処理実際に終わっていたこと
必要なファイルを取得して保存する調査(読み取り中心)資料にある保管場所の確認

指示文の中に取得や保存の文言があっても、エージェントへ渡すタスク定義が読み取りに限定されていたら実際の取得まで進まない。
リポジトリ担当エージェントへの引き継ぎ方針を整理し、指示原文、対象、許可する操作(書き込み・保存権限)、実際の終了条件(ファイルの保存完了)を構造化して渡すように改めた。「調べる」と「取得して保存する」を、受付時と完了判定の両方で明確に区別する。

別のテストでは、実行エージェントを動かしても通信が権限で遮断される現象が起きた。
個別に確認したところ、外部サーバーの認証へ到達する前に、ローカル実行環境の通信制限でプロセスが停止していた。接続が必要な登録済みの宛先に限り、タスク実行時に通信を許可する設定を追加した。

変更後はエージェントから既存の検証サーバーへ接続し、権限情報を確認するところまで動作した。
接続できたこと、必要な領域へ書き込めること、取得や転送が完了したことを工程ごとに段階を分けて記録するようにしている。