AI駆動の業務自動化システムの最小UI|見えない不安を解消する現場ボード

どれだけの画面が必要なのか?」ヘッドレス基幹の開発に着手したときに最初に立てた問いです。一覧・詳細・編集フォームといった CRUD の画面群のほとんどが要りません。データを作り、動かし、繋ぐのはエージェントの仕事だからです。UIは、人が関わらざるを得ない場所——判断する承認画面と、管理するアドミン画面——にだけ残す。これがエージェンティックシステムの「最小UI」の考え方です。

ところが、実際に複数のエージェントを走らせてみると、想定していなかった問題があらわれます。裏で何が、どこまで進んでいるのか、まったく見えないのです。処理は着々と流れているのに、現場からは沈黙しているように見える。自動化がうまくいっているときほど、この「見えない不安」は強くなる。

そこで、操作のためではなくエージェントの仕事を見せるためだけの画面を足しました。それが今回、この記事で紹介する現場ボードです。この記事は、最小UIという設計判断と、その上にあえて足した現場ボードの作り方の記録です。技術的には、少ない画面でも軽量・高速に組めるNext.jsと、LangGraphのノードをそのまま可視化したReact Flowが見どころです。

このシステムの設計に興味がある方は、以下の記事を参照してください。

また、環境構築を含めた実装の部分について知りたい方は、以下の記事をご覧ください。

目次

エージェンティックシステムに与えた3つの画面

今回、制作したエージェンティックシステムに与えた3つの画面を紹介します。

エージェンティックシステムは、AIが複数の工程を続けて進める仕組みの総称です。当社が設計したのは、そのうち業務の流れを人が設計して固定するワークフロー型に当たります。目的だけを渡して進め方まで任せる自律型ではありません。

フロントは「人が関わる場所」にだけ作る

冒頭でも述べたように、ヘッドレス基幹では、SaaSに当たり前のように存在した、一覧画面、詳細画面、編集フォームがありません。データを作り、動かし、繋ぐのはAIエージェントの仕事だからです。

この画面の少なさはアプリケーション開発の高速化に繋がります。Claude Codeを使えばコードはあっという間に書ける時代ですが、それでも要件定義、チケット作成、UIデザイン、共有ミーティングなどの工数はそのまま削減できます。

逆にUIが必要となるのは、人が判断する瞬間(承認画面)。もうひとつは、システムを管理する瞬間(管理画面)。この2つ以外に、汎用の入力画面は作りません。

承認画面 ── human-in-the-loop の窓

承認画面はエージェントが作成した受注書・見積書を承認するための画面です。こういった人間のインタラクションを挟むアプローチはAIエージェントの世界ではhuman-in-the-loopと呼ばれます。

この画面には、承認待ちの受注案件が一覧で表示されます。ここでユーザがおこなうことができる操作は、承認・修正・差し戻しの3つだけです。修正は金額や数量といった意味のある項目だけに限られます。

エージェントを待たせるという部分の詳しい仕組み(interrupt() と再開、検査役)は、別記事で解説しています。

管理画面 ──システムのコックピット

管理画面は、システムのコックピットです。工程ごとの運用モード(自動/人間承認/手動)の切り替え、全体を一手で止める緊急停止、そして表示言語(日英)の切り替えを、1画面に集めました。

言語切替をここに集約したのは、できるだけUIの機能を絞りたかったというのと、英語と日本語を切り替える各画面にバラ撒くと迷子になるからです。モードの状態はデータ(mode_settings)に持たせ、画面はそれを映すだけにしています。

現場ボード ── 「見えない不安」へ回答

承認画面と管理画面。当初、想定したのはこの2つの画面のみです。

ところが、実際に自動で回し始めると、別の問題が出ます。AIエージェントが裏で何をしているのか、まったく見えないと、人は不安になるのです。処理は進んでいるのに、現場からは沈黙しているように見える。この「見えない不安」はAIエージェントは何をしでかすかわからないイメージと合わさると、不気味でしかない。

そこで、操作のためではなく、見せるためだけの画面を足しました。それが現場ボードです。誰も操作しない、ただ流れているのを眺めるための画面。

この現場ボードは3つの異なる情報を数秒ごとに切り替えて映します。それは「進行中の案件」「自動操作ログ」「ワークフロー」の3つです。

フロントエンドの土台 ── Next.js を選んだ理由

画面数は少ないのに、なぜ本格的なフレームワークを使うのか?それは、「軽量に、速く作れる」からです。

少ない画面でも Next.js が速い

画面が少ないならReactでも組めますが、Next.js(App Router)は、ルーティング・メタデータ・多言語・サーバー側のAPIルートといった土台を最初から持っています。npx create-next-app@latest で雛形が一発で立ち、あとは画面を足すだけ。一人で最速に作るには、この土台の部分がそのまま開発速度になります。

画面ページは業務ロジックを持たず、/api/** のAPIルートが薄いプロキシとして実務側(FastAPI)へリクエストを転送します。この薄い層をNext側にまとめて置けるのも、フレームワークを使う利点です。

TypeScript
// apps/web/app/api/system/state/route.ts —— Next 側は薄いプロキシに徹する
const AGENT_URL = process.env.AGENT_URL ?? "http://localhost:8000";

export async function GET() {
  const res = await fetch(`${AGENT_URL}/system/state`, { cache: "no-store" });
  const data = await res.json();
  return NextResponse.json({ halted: !!data.halted }); // 判断は持たず、転送するだけ
}

多言語切替とタブタイトル

言語設定はnext-intlのcookieベースにしました。この実装ならURL に /ja /en を付けないで済みます。ルートレイアウトがロケールを読んでプロバイダを張ります。停止バナーのコンポーネントもここに置きました。

TypeScript
// app/layout.tsx —— ロケールは cookie から、タブ名はテンプレートで統一
export const metadata = { title: { template: "%s | Synaptiq", default: "Synaptiq" } };

export default async function RootLayout({ children }) {
  const locale = await getLocale();
  return (
    <html lang={locale}>
      <body><NextIntlClientProvider><SystemBanner />{children}</NextIntlClientProvider></body>
    </html>
  );
}

タブ名は、各ルートで呼んでいる generateMetadata が返す形に落ち着きました。当然、言語はアドミン画面で設定した言語に追従します。

TypeScript
// app/wall/page.tsx —— タブ名は generateMetadata で
export async function generateMetadata() {
  const t = await getTranslations("wall");
  return { title: t("title") };          // 「現場ボード | Synaptiq」
}

配色はデザイントークンに集約する

色はコンポーネントにはダイレクトに書かず、1つのトークンに集約しました。色を変える場合はここを変えるだけで済みます。承認=濃紺、自動=緑、手動=琥珀、といった具合にここで一元管理しています。

TypeScript
// app/_components/tokens.ts —— 色を変えるならここだけ
export const T = {
  page: "#eef1f5", card: "#ffffff", ink: "#0f1923",
  navy: "#1e3a5f",                                   // 承認・見出し
  green: "#00a87a", greenDeep: "#007d5a", greenTint: "#e6f7f2",  // アクション・自動
  amber: "#c8870c", amberTint: "#fdf3e0",            // 警告・手動
  muted: "#8896aa", sub: "#4a5568", line: "#dde2ea",
};
export const FONT_JP = "'Hiragino Kaku Gothic ProN','Noto Sans JP',Meiryo,sans-serif";

現場ボード ── AIの動きを「見せる」画面

さて、ここからは現場ボードについて見ていきましょう。この画面は操作のためではなく、ユーザの安心のために作った画面です。

壁掛けの制約が設計を決める

まずは現場ボードの要件について簡単にまとめます。

表示専用で操作はさせない
現場ボードは表示専用。ユーザに操作をさせない。3種類の画面は数秒ごとに自動で切り替わる。

リアルタイム更新
内容はリアルタイムに自動で更新される。誰かが受注を承認すればそれが自動で反映されます。

3つのスライドを自動で巡回する

現場ボードは3枚の異なる画面を一定の感覚で自動的に巡回します。

  • 自動操作ログ(AIと人間が何をしたかを簡潔に書く)
  • 進行中の案件(取引先・品目・数量・納期+工程ステッパー)
  • ワークフロー(全体の工程と現在取り組み中の工程を表示する)

切り替えは穏やかに、prefers-reduced-motion を尊重し、文字は遠くから読めるよう vw ベースで特大に。

TypeScript
const ROTATE_MS = 10000;      // スライド切替:10秒
const POLL_MS = 12000;        // ログ・案件の再取得:12秒
const GRAPH_POLL_MS = 3000;   // ワークフローの再取得:3秒

ワークフローを React Flow で描く ── LangGraphノードを可視化

3枚目のワークフロー画面は、LangGraph のグラフ(build.py のノード)をそのままヴィジュアル化しています。structure_orderorder_gateorder_egress… というノードが、実際のエージェントの工程です。ライブラリは @xyflow/react。ドラッグもズームも無効の読み取り専用表示で、いま実行中のノードを塗って発光させます。

ノードが増えると横一列に収まらないので、蛇行レイアウトを自前で組みました。行末で折り返し、奇数行は右→左に流す。座標計算はひとつの関数にまとめてあり、将来ノードが増えたら中身だけ差し替えられます。

TypeScript
const WORKFLOW_COLUMNS = 5;   // 1行あたりのノード数(規模が増えたら 5〜6 に)
// 蛇行:行末で折り返し、奇数行は右→左(大きいノードを保ったまま多数を収める)
function computePositions(ids: string[], cols: number) {
  const pos = new Map<string, { x: number; y: number }>();
  ids.forEach((id, i) => {
    const row = Math.floor(i / cols);
    let col = i % cols;
    if (row % 2 === 1) col = cols - 1 - col;      // 奇数行は逆向き
    pos.set(id, { x: col * (NODE_W + GAP_X), y: row * (NODE_H + GAP_Y) });
  });
  return pos;
}

/api/wall/graph 経由で実際のコンパイル済みグラフからノードとエッジを取得するので、build.py を変えれば壁掛けモニターの図も追随します。「現場で見えるワークフローが、動いているエージェントの構造とズレない」——これは今後のシステム拡張を楽にします。

接続に失敗してもフリーズさせない

つけっぱなしの画面でいちばん怖いのは、データの取得に失敗して真っ白になることです。ポーリングは失敗しても直前の実データを保持し、成否は接続ドットの色(緑=オンライン/琥珀=接続待ち)だけで示します。

TypeScript
// 取得失敗時は前回値を捨てず、online フラグだけ倒す(画面を白くしない)
const loadData = useCallback(async () => {
  let ok = true;
  try { /* /api/audit/recent → setLog / processedToday */ } catch { ok = false; }
  try { /* /api/orders/active → setJobs */ }               catch { ok = false; }
  setOnline(ok);
  if (ok) setLastSync(new Date());
}, []);

そして緊急停止中は、上部に赤いバナーを出し、ステータスも赤に。「止まっている」という状態そのものを可視化します。動いていないのに動いて見えるのは望ましくない状態だからです。

バックエンドは「文字列」でなく「コード」を返す

多言語ボードの設計で重要なポイントがあります。

それは表示する日本語や英語の文字列を直接返さずにコードで返すという点です。状態コードとイベント種別を返し、翻訳はフロントエンドに任せます。

フロントエンドは order_approved のようなキーに {partner} を差し込んで文面を組み立てます。日英の切替も文面の修正も、フロントエンド一箇所で完結します。

Python
# api/wall.py:監査ログを (状態, イベントキー) に変換して返す(表示文字列・金額は返さない)
def _audit_event(row):
    at, tgt = row.get("action_type"), row.get("target_table")
    if at == "approve" and tgt == "orders": return ("approved", "order_approved")
    if at == "approve" and tgt == "quotes": return ("approved", "quote_approved")
    if at == "edit":                        return ("edited", "edited")
    return None

まとめ

エージェンティックシステムのUIは、従来の業務アプリとはまったく違う発想が求められます。

人が関わる場所——判断する承認画面と、管理するアドミン画面だけを作る。これが出発点でした。ただし、それだけだとAIの動きが見えず、人は不安になる。だからもうひとつ、操作のためでなく見せるための現場ボードを用意しました。

技術的には、少ない画面でも Next.js が軽量・高速に土台を与えてくれ、現場ボードではReact Flowが LangGraphのノードをそのまま可視化してくれました。UIを極限まで絞ったうえで必要なだけ足す。これこそがAI時代のシステム設計の在り方です。

【中部地方】製造業向けAI自動化ツール 実地検証パートナー募集

株式会社ニューロシンクでは、製造業のバックオフィス業務を自動化するツール「Synaptiq」の開発に伴い、実際の現場で効果を検証していただける企業様を募集しています。 受注・見積もり・請求書の作成から工程管理までをシステムが自動処理し、人間は「内容の承認」を行うだけの環境を目指す取り組みです。

現在は本格提供前の開発段階のため、導入の義務は一切ございません。まずは貴社の業務課題をお伺いし、どこから自動化できるかを無料で一緒に整理させていただきます。

  • 対象エリア: 名古屋駅から2時間圏内の製造業様
  • ご協力内容: 現行業務のヒアリングと検証(費用負担・導入義務なし)

Synaptiqの詳しい内容を見る
相談を申し込む(15分・オンライン)

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

1981年生まれ、名古屋出身。

2008年よりドイツ・ベルリンに在住。
ドイツの国家資格である職業訓練プログラム「アプリケーション開発専門IT技術者」を修了後、医療系自社開発企業にてデスクトップ・Webアプリケーションの開発に4年間従事。
2022年よりドイツの大手SIer「Adesso SE」にて、フルスタックエンジニアとしてリードポジションを務める。

2027年に日本へ帰国し、日本の中小企業へのAI導入支援を本格的に開始予定。

著書「AI時代の海外移住戦略

コメント

コメントする

目次