はじめに ― 「なぜこの配属だったのか」を残したい
こんにちは、TeamPです。
私たちは、アラフィフのベテランエンジニア2人で「AI HACK 2026」に参加しました。
今回作ったのは、配属・異動に関する「なぜそう判断したのか」を組織に残すAIナレッジパートナー、HRper <ハーパー>です。
聞き上手が、組織にひとり増える。
社員情報やスキル表があっても、配属を決めるために本当に必要な情報は、担当者の頭の中や個別の面談に残りがちです。
- 本人は、これからどんな仕事をしたいのか
- 配属先では、実際にどの仕事へ手が回っていないのか
- どんな経験や行動が、その部署で活かせそうなのか
- 受け入れる前に、何を確認し、どんな支援を約束するのか
- 人事は、どの材料を見て最終判断したのか
一次ヒアリングでは、配属後に不満が生じて早期に再異動した事例や、年間約10名から配属への不満が上がっている状況を確認しました。
結果だけが人事システムに残り、理由が残らない。担当者が替われば、本人へ説明することも、次の判断へ活かすことも難しくなります。
HRperが目指すのは、AIが最適な配属先を決めることではありません。
本人・部署長・人事が、それぞれの立場だからこそ話せることを持ち寄り、人が根拠を確認して判断できる状態を作ること。
この記事では、企画の出発点から、完成した業務フロー、AIとコードと人の役割分担、OrcaRouterの使い分け、テスト、そして提出版に残る制約までを、1本にまとめて紹介します。
人がAIに聞くのではなく、AIが人へ聞く
企画会議で最初に考えたのは、「この課題に生成AI(LLM)を使う必然性はどこにあるか」でした。
文章の要約だけなら、既存のチャットAIでもできます。チャット画面を作ってLLMへつなぐだけでは、判断理由が残らないという課題の本質には届きません。
そこで、発想を逆転させました。
人がAIへ質問するのではなく、AIの方から人へ聞きにいけばいい。
暗黙知を持つ人に「判断基準を全部書いてください」と頼んでも、簡単には言葉になりません。一方、具体的な場面について少しずつ聞かれれば、経験に基づく答えを返せます。
HRperでは、組織マスタと蓄積済みの知識を見て、まだ分からない点を選びます。
- 本人には、経験、志向、希望、不安を聞く
- 部署長には、不足している仕事、必要な力、受け入れ条件を聞く
- 人事には、異動案の背景、ねらい、気がかりを聞く
台帳から分かる事項はknownとしてプロンプトへ渡し、聞き返しを抑えています。LLMが判断材料として重要な情報が足りないと判定した場合に、追加質問を最大1問生成します。
HRperの業務フロー
完成した業務フローを1枚にまとめると、次のようになります。
本人・部署長・人事の声をHRperがdraftの判断材料へ整理し、現在のUIでは話した人が確認した内容をconfirmedとして蓄積します。confirmedだけを正式なレポート材料にし、人事の判断と本人向け説明までつなげる流れです。
当初は、対話から知識マップへノードが生まれる体験を中心に考えていました。
しかし、マップが育つだけでは、人事の業務成果にはなりません。そこで実装の途中から、知識を配属根拠レポート、最終判断、本人への説明までつなげることを中心へ置き直しました。
知識マップはゴールではなく、判断材料がどこから生まれ、誰やどの部署に関係しているかを見るための手段です。
佐藤さんを営業部から開発部へ——代表シナリオ
ハッカソンの標準シナリオでは、「営業部の佐藤さんを開発部へ異動させる場合」を扱います。
1. 本人が、自分にしか話せないことを話す
佐藤さんは一般社員としてログインし、これまで手応えを感じた仕事、得意なこと、今後取り組みたい仕事やキャリアについて答えます。
自由入力だけでなく、回答例、音声入力、質問の読み上げ、会話モードも用意しました。「分からない」と答えることもできます。
本人の個人的な希望は、本人と人事だけが見られる情報として扱い、部署長の画面には表示しません。
2. 部署長が、現場にしか分からないことを話す
開発部長は、次のような点を答えます。
- いま手が回っていない仕事
- どんな力を持つ人が必要か
- 現メンバーとの差は何か
- 受け入れ時に気になること
- 最初の数か月に必要な支援
3. AIがdraftの判断材料へ整理し、人が確かめる
HRperは回答を、再利用できる短い判断材料へ言い換えます。
たとえば、
「分からない点を、その日のうちに聞きに来ていました」
という発言は、
疑問の即日解消
のようなdraftの判断材料になります。
ただし、AIの言い換えをそのまま正式記録にはしません。
聞き取りの最後に「今日のまとめ」を表示し、要約、次のアクション、記録するラベルを人が編集します。現在のUIでは、話した人が「ここまでの内容を記録する」を押したものだけがconfirmedになります。
4. 人事が、異動案そのものをレビューする
人事は対象者と配属先を選び、異動案の背景、配属先で期待する役割、現時点の気がかりを整理します。
ここでは、異動の可否を決めません。まず「判断に足りる材料が揃っているか」を確認します。
本人が書いた相談や、部署長が書いた人員要望は、提出後も作成者自身の一覧に残り、人事の提出済み一覧にも届きます。書きかけは作成者だけの下書きで、自分の意思で提出して初めて人事へ見せます。
5. 異動案について、本人と配属先の部署長へ確認する
異動案が登録されると、佐藤さんには、その話をどう受け止めているか、不安や希望、事前に確認したい条件を聞きます。
開発部長には、受け入れ可否、その理由や懸念、条件や必要な支援を確認します。異動案が生まれた後に両者へ聞くことで、一般的なキャリア志向と、具体的な案への受け止めを分けて残します。
6. 確認済みの材料から、引用付きレポートを作る
現在のUIでは、confirmedの判断材料だけを本人側・配属先側の材料として選びます。
本人側
経験・得意分野・取り組みたい仕事・キャリア志向
(異動したいという意向そのものは除外)
配属先側
不足業務・必要な力・受け入れ条件・懸念
HRperは両側を突き合わせ、次を整理します。
- 検討内容の要約
- 両側の材料から言えること
- 配属先側の懸念
- 追加で確認したいこと
- 判断材料の充足度
ここで表示するのは、人物の適合度ではありません。
画面に表示する0〜100の充足度スコアは、材料の件数、観点の広がり、実際に引用された割合から、同じ入力なら同じ値になるようTypeScriptで計算します。これとは別に、LLMにも根拠が成立するかを判定させ、根拠がないレポートは保存しません。AIが人物を点数化することはありません。
7. 人事が決め、本人へ説明する
レポートを読んだ人事は、次のいずれかを選び、その理由を自分で記録します。
- 配属する
- 保留する
- 見送る
配属判断の記録ではLLMを呼びません。判断者は人です。
業務上の推奨順序として、その後に内部レポートを本人向けの次の項目へ整理します。
- 異動を検討した理由
- 期待する役割
- 本人の希望との関係
- 配属前に確認する事項
- 配属後の支援内容
AIが作るのは下書きで、条件や支援内容は人事が編集してからPDFへ出力します。受け入れ側の内部的な懸念や、判断材料の充足度は本人向け文面へ載せません。
現行UIはこの順序を強制しておらず、材料が十分なレポートがあれば、判断を記録する前でも本人向け文面を作れます。ここは正式版でワークフローとして制御すべき点です。
事業として置いた仮説
技術だけでなく、「誰が、何の価値に対して使い続けるのか」も一次ヒアリングから仮説を置きました。
| 項目 | 現時点の仮説 |
|---|---|
| 最初の導入業務 | 社内の配属・異動管理 |
| 導入を決める人 | 人事部長 |
| 価格仮説 | 月額20万円 |
| 成功指標 | 配属への不満を年間約10件から2件以下へ減らす |
| 既存システムとの共存 | 最初はCSV、正式版ではHRIS連携 |
ヒアリング先の代表取締役からは、月額20万円での支払意思も確認しました。
ただし、これは受注や削減効果を示す実績ではなく、今回の限られた一次ヒアリングに基づく仮説です。正式な価値検証は、有償PoCで「判断理由が残ることが、配属後の納得度や再異動の減少につながるか」を測る必要があります。
AIは聞く、コードが守る、人が決める
HRperでは、AIへ任せる処理を意図的に限定しました。
| 担当 | 主な役割 |
|---|---|
| コード | 質問候補、公開範囲、保存先、入力上限、引用検証、充足度計算 |
| AI | 自由回答の構造化、必要時の追加質問、意味的な重複判定、文章の下書き |
| 人 | 内容の確認・修正、知識の確定、配属の最終判断、本人向け説明の編集 |
誰に何を聞くかを、LLMへ丸投げしていません。
usecases.tsとgaps.tsに、役割、対象、組織マスタ、既存知識から質問候補を決めるルールを置きました。LLMは、決められた利用目的の範囲で回答を構造化し、必要な場合だけ追加質問を作ります。
知識の状態と公開範囲も、TypeScriptの型として固定しています。
type KnowledgeStatus = "draft" | "confirmed" | "discarded";
type Visibility =
| "self" // 本人のみ
| "self_hr" // 本人と人事
| "dept" // 対象部署の管理者と人事
| "org"; // 全社共有
生成AIに「この情報を誰へ見せるか」を決めさせず、現在のUIでは業務ルールとしてコード側に持たせています。
本音を集めるために、見せない範囲も設計する
「率直に話してください」と画面へ書くだけでは、人は本音を話せません。
HRperでは、情報の性質を複数の軸へ分けました。
-
visibility: 本人、本人と人事、対象部署と人事、全社 -
sensitive: 対象本人を除く非人事へ出さないための追加条件(本人への表示はsubjectIdとhideFromSubject、人事への表示はvisibilityにも従う) -
hideFromSubject: 受け入れ側の率直な懸念など、対象者本人へ返さない情報 -
subjectId: 誰についての知識か
一般社員には自分を中心とする知識、部署長には担当部署と配下、人事には権限内の全社情報を返します。フロントの表示だけでなく、ログイン時の/stateでもサーバー側の絞り込みを行います。
ただし提出版では、フロントの業務ルールが公開範囲を設定し、サーバーは許可値の検証と閲覧時の絞り込みを行う構成です。認証済み利用者とリクエスト上の社員コードを結びつける正式な認可は、正式版の課題として残っています。
回答原文と構造化した知識も、DynamoDB上で別レコードにしました。
ANSWER#... 発言の原文
NODE#... 再利用する判断材料
SUMMARY#... 聞き取りのまとめ(未確認を含み、confirmedで区別)
REPORT#... レポート、引用元の写し、人事判断
原文は出典を辿るために必要ですが、最も機密性が高い情報でもあります。通常のCloudWatchログには、回答本文やLLM応答本文を出さず、文字数、処理時間、モデル、トークン数などだけを記録します。
LLMへ送る前には、質問と回答に含まれる氏名らしき表現を伏せています。ただし、提出版の氏名マスクは正規表現ベースです。正式版では、社員台帳との照合を使った方式へ置き換える必要があります。
相談提出時のSlack通知には、本文全体や「望む状態」を載せません。宛先はリクエストで指定させず、組織マスタから人事担当者を決め、差出人、分類、件名(未入力なら本文冒頭の短い抜粋)、画面リンクだけを送ります。
LLMが返した「根拠」を、そのまま信用しない
配属根拠レポートでは、現在のUIが選んだ確認済みの本人側・部署側材料へ番号を付けてLLMへ渡します。
P0: 本人側の確認済み知識
P1: 本人側の確認済み知識
D0: 配属先側の確認済み知識
D1: 配属先側の確認済み知識
LLMは文章と一緒に引用番号を返しますが、その番号をそのまま採用しません。
- 範囲外の番号は除外する
- 配属理由には、本人側と部署側の両方の引用を必須にする
- 配属先側の懸念には、部署側の引用を必須にする
- 想定外の分類値は採用しない
作成したレポートには、番号だけでなく、引用元のノードID、当時のラベル、回答ID、確認者、確認日時を写して保存します。
表示順が変わればP0が別の判断材料を指す可能性があるためです。保存時点の材料全体からハッシュも作り、ノードIDやラベルの並びが変われば差分を画面へ表示します。ただし、本人側・部署側の区分だけが変わるケースは既知のtodoです。
「生成された文章」よりも、その文章が現在のUIで選んだどの確認済み材料に基づいているかを残すことを優先しました。
1つのモデルに全部任せず、用途ごとに測る
LLMの呼び出しには、OpenAI互換APIを提供するOrcarouterを使っています。
当初、すべてを自動ルーティングへ任せたところ、1文の追加質問に約2,000トークンを使い、34.5秒かかったケースがありました。
短い質問、JSON構造化、長いレポートでは、求める品質が違います。そこでback/src/orca.tsへタスク別の割り当てを集約しました。
| タスク | モデル | 選定理由 |
|---|---|---|
| 回答の構造化 | gpt-4.1-mini |
短いJSONを安定して返す |
| 追加質問 | claude-haiku-4.5 |
日本語の質問品質を優先 |
| 配属レポート | claude-sonnet-5 |
長文の一貫性を優先 |
| 本人向け文面 | claude-haiku-4.5 |
JSON安定性と出力量の再現性 |
| 聞き取り後の自由会話 | gpt-4.1-mini |
短く自然な会話を返す |
モデルは名前だけで選ばず、速度、出力トークン数、日本語品質、JSONの安定性をbenchModels.tsで比較しました。
レポートを1回の呼び出しで全部書かせたときは、出力が2,200トークンを超え、24秒かかりました。API Gatewayのタイムアウトへ近づき、途中で切れたJSONを再試行すると、さらに時間がかかります。
そこで、
- 本人と部署の材料が噛み合う理由
- 配属先側の懸念と、まだ分からない点
を別の呼び出しへ分け、並列実行しました。本人向け文面も「経緯・期待する役割」と「希望・確認事項・支援」に分けて並列化しています。
すべての呼び出しにはX-Title: HRper/<task>を付け、実際に使われたモデル、入出力トークン、応答時間を記録します。コスト画面では、OrcaRouter側の利用ログ、料金表、累計課金額を取得し、モデル・機能別の実測値を表示します。
システム構成
提出版は、フロントからバックエンドまでTypeScriptで構成しました。
組織・社員マスタは画面とUTF-8 CSVで管理し、DynamoDBへ保存します。既存HRISとのAPI連携は提出範囲から外し、まずはCSVで共存する形にしました。
WebSocket用の実験コードもありますが、提出版ではデプロイせず、画面更新はRESTレスポンスと再読込で行います。
リファクタリングの前に、テストを増やした
短期間で機能を増やした結果、フロントのApp.tsxとバックエンドのquestionHandler.tsへ責務が集まりました。
この状態で先に分割すると、現在の業務ルールまで変えてしまうおそれがあります。そこで、本体コードへ手を入れず、先にテストを追加する方針を取りました。
2026年8月14日時点の結果です。
| 対象 | テストファイル | 成功 | todo |
|---|---|---|---|
| フロント | 6 | 71 | 1 |
| バックエンド | 2 | 31 | 1 |
| 合計 | 8 | 102 | 2 |
フロントでは、ロールと公開範囲、組織CSV、質問候補、マップの絞り込み、レポート材料・充足度、コスト集計といった純粋ロジックを確認しています。
バックエンドでは、APIの入力境界とロール別の閲覧・操作、氏名マスクやSlack本文の秘匿、LLM引用の検証、OrcaRouterのモデル・上限・JSON再試行を確認しています。AWS SDK、OrcaRouter、Slackはモックし、未モックの外部通信が発生したらテストを失敗させています。
あわせて、フロント・バック双方のTypeScript型検査と本番ビルドも成功しています。
2件のtodoは、既知の課題を現在の挙動として固定しないために残しました。
- 不正JSONを、汎用500ではなく適切な4xxで拒否する
- 材料の並びが同じでも、本人側・配属先側の区分変更をハッシュで検出する
現在のテストは、ブラウザE2EやReactコンポーネントテストを含む完全なものではありません。それでも、これから責務を分割するための最初の安全網にはなりました。
提出版は、そのまま本番へ出せるものではない
「本番を見据えて設計したこと」と、「本番運用できること」は分けて説明すべきだと考えています。
現在の提出版には、次の制約があります。
- 社員コードだけの簡易ログインで、CognitoやAPI Gateway Authorizerは未実装
- 単一企業、合成データでのデモを前提としている
- API全体で、認証済み利用者と
employeeCodeを結びつける正式な認可は未実装 -
visibilityなどはUIが設定し、APIは利用者がその値を指定してよいかまでは検証していない -
/reportの材料はUIでconfirmedへ絞っており、サーバー側でDynamoDBから再取得して状態を検証していない - 回答原文の保存期限、同意バージョン、訂正・利用停止の運用は未実装
- 氏名マスクは正規表現ベース
- APIキーはLambda環境変数で、Secrets Managerとローテーションは未実装
- 配属レポートは検討用で、承認・回覧ワークフローではない
- ブラウザE2E、IaC、継続監視は未整備
正式サービス化するなら、最初にCognitoなどの認証を入れ、テナント、利用者、ロールを認証情報から確定します。
あわせて、保存期間、削除・訂正手続き、LLM提供者の保存・学習条件、秘密情報管理、WAF、冪等性を整えます。権限やテナントの境界を越えるアクセスを拒否できるかも、専用のテストで確認する必要があります。
実在社員のデータは、それらを確認するまで投入しません。
おわりに— 会話を、判断と説明につなげる
白紙のホワイトボードから始めた企画は、会話を判断材料へ整理し、人が確かめ、両側の根拠を突き合わせて判断し、本人へ理由を説明するところまで動くようになりました。
生成AIを強い判断者として置くのではなく、立場の違う人の間へ入り、話を聞き、整理し、必要なところを問い返す存在として使う。公開範囲・状態・引用検証はコードが、確認・最終判断は人が引き受ける。
提出版には認証・認可をはじめ未完成の部分があります。それも含めて、これがTeamPのたどり着いた、本番化を見据えたAI Product設計への一つの仮説です。
皆さんの職場にも、結果だけが残り、理由を説明できる人がいなくなる判断はないでしょうか。

