【第5部】意図理解とスキル選択を担うセマンティックルーター

# 【第5部】意図理解とスキル選択を担うセマンティックルーター
> 連載「Slack AIエージェント基盤を作る」全8部の第5部。
第4部のジョブ化で、Slackの発言は実行基盤へ渡せる形になった。だが、何を実行するかを間違えたら意味がない。第5部では、「これ直して」「前の件まとめて」のような 自然文を、どのスキルへ渡すか判断するセマンティックルーターを扱う。AIエージェント基盤の実用性は、ここでかなり決まる。
前後で読む
- 前回: 第4部 Slack発言をジョブ化する
- 次回: 第6部 記憶を設計する
SlackでAIエージェントに依頼するとき、人間は正確なコマンドを書いてくれない。
「この資料いい感じに直して」「先方への返事を考えて」「このエラー見て」「毎週確認して」くらいの自然な言い方になる。ここで必要になるのが、意図理解とスキル選択を担うセマンティックルーターだ。
セマンティックルーターは、自然文の依頼を読んで、どの処理へ渡すかを決める層だ。キーワードで分岐するだけではなく、文脈、チャンネル、添付ファイル、過去の依頼、ユーザーの役割を合わせて判断する。この基盤では、Slackからの指示をCLI実行、資料作成、記憶更新、定期実行などへ分ける中核になる。
キーワード分岐だけでは足りない
最初の実装では、つい「エラー」という単語があれば調査、 「記事」という単語があれば執筆、といった分岐にしたくなる。小さなBotなら動く。だが、業務で使うAIエージェントではすぐ破綻する。
たとえば「この記事のエラーを直して」は、ブログ原稿の表現ミスかもしれないし、Webページのビルドエラーかもしれない。「先方に返して」は、メールなのかSlack返信なのか、CRMメモなのか分からない。
セマンティックルーターは、単語ではなく依頼の意味を読む必要がある。
そのために、次の情報を使う。
- 投稿されたチャンネルの用途
- スレッドの前後文脈
- 添付ファイルの種類
- メンションされた人やBot
- 直近のジョブ履歴
- ユーザーの明示的な指示
- 利用できるスキル一覧
Slack Bolt for JavaScriptはイベント取得の土台になるが、意味解釈はアプリケーション側の責務だ。Slackイベントを受けた後、実行前にこのルーティング層を挟むことで、誤実行を減らせる。
スキルを宣言的に扱う
AIエージェント基盤では、スキルをコードの関数としてだけでなく、説明可能な部品として扱うと運用しやすい。
スキルには、少なくとも 次の情報を持たせる。
- 何ができるか
- どんな入力を受けるか
- どんな成果物を返すか
- 実行に必要な権限
- 実行にかかる目安時間
- 失敗時の扱い
- 使ってはいけない条件
この情報があると、セマンティックルーターは「どのスキルを使うか」だけでなく、「実行してよいか」「追加確認が必要か」も判断しやすい。自然文からツール呼び出しへ変換する前に、スキルの境界を明文化するのが肝になる。
OpenAIのコード生成ガイドでも、モデルに作業を任せるときはコンテキストと制約が結果を左右する。スキル宣言は、その制約をAIエージェント基盤の部品として持たせる方法だ。
ルーティング結果をSlackで確認できるようにする
セマンティックルーターの判断は、内部だけで完結させないほうがよい。
「資料作成として処理します」「コード調査として実行します」「権限確認が必要です」のように、Slack上で短く見せると、ユーザーが意図のズレに気づける。
特に危険なのは、AIエージェントが自信満々に間違ったスキルを選ぶことだ。たとえば「消しておいて」を単なるメモ削除と判断した が、実際にはクラウド上のデータ削除を指していた、という事故は避けたい。
ルーティング結果を表示し、破壊的な操作では確認を挟む。これだけで、AIエージェントの信頼感はかなり変わる。
記憶とルーターを分ける
過去の依頼を覚えると、セマンティックルーターは賢くなる。
ただし、記憶そのものをルーティングロジックに混ぜると、後から理由を追いにくい。記憶は入力の一部として読み込み、ルーターはその入力を使って判断する。判断結果と理由はログに残す。
この分離があると、誤ルーティングが起きたときに「記憶が悪かったのか」「分類ロジックが悪かったのか」を切り分けられる。
公開用の説明では、実際に保存しているファイル名や社内のナレッジ名は出さない。代わりに「ユーザーの明示的な好み」「プロジェクトのルール」「過去ジョブの要約」のように抽象化して書く。技術的な特異性は伝えつつ、運用情報は守れる。
ルーターの品質は「止まれるか」で決まる
自然文からスキルを選ぶとき、分類精度だけを追うと危ない。業務システムでは、実行してはいけない依頼を止める力のほうが重要になる。情報が足りない、権限が足りない、外部副作用がある、対象が曖昧。このときにclarifyやapprovalへ落とせる設計が必要だ。
そのため、semantic routerの出力は自由文ではなくdecision objectにする。route type、skill name、confidence、evidence、missing fields、approval requirementを持たせる。実行側はそれを検査し、条件を満たすものだけ実行する。
キーワード分岐を超えることと、AIに丸投げすることは違う。ルーターは、自然文の曖昧さを業務上の安全な選択肢へ落とすための制御面だ。
スキル定義(skill manifest)を読んで、LLMの自由判断を狭める
セマンティックルーターの目的は、AIに何でも自由に考えさせることではない。むしろ逆で、使ってよいスキル、使ってはいけない条件、必要な入力シグナルを明示し、危ない経路を閉じることだ。
スキルは、コードだけでなくmanifestとして扱う。たとえば次のような情報を持たせる。
name: proposal_deck
description: 提案資料の構成、本文、画像、PPTXを生成する
when_to_use:
- 提案書、営業資料、プレゼン資料を作る依頼
required_signals:
- 目的
- 想定読者
- 納品形式
do_not_use_when:
- 外部送信や契約確定を求める依頼
- 機密ファイルを未確認で公開する依頼
outputs:
- pptx
- summary
approval:
required_for_external_send: trueルーターは、ユーザーの自然文をこのmanifest群と照合する。単語一致ではなく、中心アクション、添付ファイル、スレッド文脈、ユーザーの権限、過去の実行状態を合わせて判断する。
振り分けはscoreだけで決めない
実装では、候補スキルごとにscoreを出すだけでは弱い。scoreが高くても、required_signalsが足りなければ確認へ回す。do_not_use_whenに当たるなら候補から外す。write操作や外部送信を含む場合は承認routeへ回す。
このrouting logが運用で効く。後から「なぜこのスキルが選ばれたのか」「なぜ聞き返したのか」「どの条件で止めたのか」を追える。AIエージェントの誤動作を直すには、最終出力だけでなく、ルーティング理由が必要になる。
指示型スキルと手続き型スキルを分ける
スキルには大きく2種類ある。script skillは、入力が揃えば決まった処理を実行する。たとえばサムネイル生成、ファイル変換、構文検証のようなものだ。instruction skillは、LLMやCLI agentに渡す手順書に近い。たとえばブログ生成、資料作成、調査レポートのように判断を含むものだ。
この2つを同じ「スキル」と呼んでもよいが、実行時の制御は分けるべきだ。script skillは引数検証と終了コードを重視する。instruction skillは、前提、禁止事項、成果物形式、検証手順を重視する。ここを分けると、AIエージェントの動きが安定する。
分類器を自由回答にしない
セマンティックルーターにLLMを使うとしても、自由作文を返させない。実行系に渡す前段なので、返り値は構造化された判定結果に絞る。コード上ではdecision objectとして扱うが、役割は「実行してよいかを検査できる形にする」ことだ。
{
"decision": "route",
"routeType": "script_skill",
"skillName": "masked-skill",
"confidence": 0.86,
"evidence": ["依頼本文からの短い根拠"],
"missingFields": [],
"approvalRequired": false,
"blockers": []
}この形なら、実行前に止められる。confidenceが低い、missingFieldsがある、approvalRequiredがtrue、blockersがある。どれかに該当すれば、Slackで確認してから進める。AIの判断を信じるのではなく、判断結果を検査できる形にするのが重要だ。
スレッド文脈を考慮した振り分けは必要な時だけ使う
毎回Slackスレッド全体を分類器へ渡すと、コストも誤爆も増える。スレッド文脈を考慮した振り分けは強力だが、常用するものではない。短い依頼、添付ファイル参照、pending approval、直前の成果物再添付のように、文脈が必要なときだけthread historyを読む。
たとえば「これ直して」は単体 では実行できない。直前にPPTXが生成されているのか、ブログ原稿なのか、コード差分なのかでrouteが変わる。この場合はhistoryを取りに行く。一方、「画像を再添付して」はartifact delivery routeへ直接行けることが多い。
ルーターは賢いほどよいのではなく、迷ったら止まれることが大事だ。clarifyを返す設計にしておくと、危ない自動実行をかなり減らせる。
最小構成で始めるなら3つだけ決める
この層を最初から大きく作る必要はない。実装を始めるなら、まず次の3つだけを固定するとよい。
- 使えるスキルの一覧と、それぞれの「使ってよい条件」「使ってはいけない条件」を書く。
- ルーターの返り値を、route type、skill name、根拠、足りない情報、承認要否に絞る。
- 足りない情報があるときは実行せず、Slackで聞き返す条件を決める。
この3つがあるだけで、自然文からいきなり副作用のある処理へ飛ぶ事故を減らせる。高度な分類精度より先に、実行前に止まれる構造を作る。そこが、Slack上のAIエージェントを業務で使うための第一歩になる。
関連記事
連載「Slack AIエージェント基盤を作る」
- 第1部 Slackを業務OSにする
- 第2部 CLIをサーバーに上げる
- 第3部 並行実装を回す
- 第4部 Slack発言をジョブ化する
- 第5部 意図理解で振り分ける
- 第6部 記憶を設計する
- 第7部 定期実行で運用する
- 第8部 安全性と観測性を固める
- まとめ Slack AIエージェント基盤の全体設計



