6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

仕様書駆動教材開発へ向けて(AIフレンドリーなドキュメントとしての Mermaid記法)

Last updated at Posted at 2025-12-06

はじめに

この記事は、GLOBIS アドベントカレンダーシリーズ1の7日目の記事となります。

自己紹介

業務委託で「グロービスAI経営教育研究所(GAiMERi)」をお手伝いしている imunew です。

GAiMERi でどんなことをしているかについて詳しくは、こちらを参照いただければと思います。

仕様書駆動教材開発とは

ソフトウェア開発の世界では「仕様書駆動開発(Spec-Driven Development)」というアプローチがにわかに注目を集めています。

仕様書駆動開発では、コーディングエージェント(生成AI)に仕様書や計画書を書かせてから、その仕様・計画にしたがって実装(コーディング)を進めていくのが特徴となっています。

これにヒントを得て、生成AIに演習問題を作成させるのが、仕様書駆動教材開発(造語)です。

GAiChaL-2.0のシナリオ作成を生成AIで半自動化する

GAiMERi で開発・運用しているサービスに、GAiChaL-2.0 という受講生向けの復習ツールがあります。

この1つ1つの演習は、以下のようにフローチャートのような構造を持っています。
(以下は、管理画面のスクリーンショットです。)

image.png

ちなみに、このフローチャートのUIには、Sequential Workflow Designer を使っています。

リリースから1年以上経過して、受講生から「演習数が少ない」「もっと演習を解きたい」といった声をいただきます。

リリース当初からこの演習の量産という課題に、GAiMERiの 健太さん は取り組んできました。

試行錯誤の末、以下の要領で生成AIに、(いい感じに)演習を作らせることができました。

プロンプト概要

下記のプロンプトをベースに、作りたい演習のテーマに沿って「ラーニングポイント」を記述します。

あなたはビジネススクールの教員です。
チャットボットによる演習問題を作成するため、演習問題用のフローチャートの概要を作成しようとしています。
下記のラーニングポイントに関して、フローチャートの概要を番号付きリストを使って作成してください。

# 条件
- 番号付きリストのラベルは4つの種類のみです
    1. ボット(問い)
    2. ボット(判定)
    3. ボット(解説)
    4. 学習者
- 番号付きリストは少なくとも13以上、多くても18以内です
- 最初の「ボット(問い)」ではラーニングポイントに出てくる単語を使わないでください
- 出力は番号付きリストの内容だけにしてください。内容に関する説明は一切不要です

# ラーニングポイント
(省略)

# フローチャートの概要例
## 例1
1. ボット(問い)
    - 将来、グローバルで活躍するため、英語力を強化したい。どんな打ち手があるか3つ挙げさせる
2. 学習者
    - (回答させる)

(以下、番号付きリストが続く)

## 例2
(番号付きリスト)

## 例3
(番号付きリスト)

あとは、生成AIに投げてみて、修正が必要であれば、修正箇所とどのように修正してほしいか、生成AIに追加で指示します。

番号付きリストができたら、あとは、以下のプロンプトを投げて、Mermaid 記法に変換してもらいます。

下記の条件に従って、フローチャートの概要をMermaid記法に変換してください。

# 条件
- 最初は「開始」で始まり、最後は「終了」で終わってください
- 「開始」「終了」はsquareノードを使ってください
- 「ボット(判定)」はdiamondノードを使ってください
- 「ボット(問い)」「学習者」「ボット(解説)」はroundノードを使ってください
- 「ボット(解説)」が正解の場合、不正解の場合に分かれる場合、分岐するようにしてください
- ノード内に問いや解説などのテキストを記述するようにしてください
- ノード内のテキストでは「1. 」のような番号付きリストの表記は使用しないでください
- 出力はMermaidの内容だけにしてください。内容に関する説明は一切不要です

このアプローチのポイントは以下のとおりです。

  • フローチャートを番号付きリストにすることで、生成AIにお手本を示す(Few-shot learning)ことができるようになった
  • 番号付きリストを Mermaid 記法に変換することで
    • フローチャートを人間が目視で確認できる
    • Mermaid 記法はプレーンテキストなので、ソフトウェア上で再利用しやすい
  • ラーニングポイントをどうするかに集中でき、それ以外の工程は生成AIがやってくれる

GAiChaL-2.0のシナリオとの互換性

Mermaid 記法で表現できるデータには限界があり、GAiChaL-2.0のシナリオを完全に網羅することはできません。

なのですが、用途は十分にありそうです。

  • Mermaid 記法から GAiChaL-2.0 にインポート
    • 新規作成のテンプレートとして使う
  • GAiChaL-2.0 から Mermaid 記法にエクスポート
    • プロンプトに渡す Few-shot learning として入力する

既存のシナリオを Mermaid 記法に変換、フローチャートを表示してみた

GAiChaL-2.0のシナリオデータを、Mermaid 記法に変換する部分の実装は Claude にやってもらいました。

管理画面からシナリオデータをJSON形式でエクスポートし、それをMermaid記法へ変換してほしい、と指示しました。

特にこちらからデータ構造の解説はしていないにもかかわらず、いい感じにコードを書いてくれました。

image.png

(Claude には演習のことをより一般的な「クイズ」と言い換えて指示しました)

UI部分の実装は自分でやって、最終的には以下のような画面を実装してみました。

左側には Mermaid 記法のソース、右側にはフローチャートを表示しています。

image.png

ページ右側のチャート表示部分は以下のような実装になっています。
mermaid.jsReact 用のコンポーネントを用意してくれてないので、mermaid.render したSVG要素をHTMLに埋め込んでいます。
おまけ的に、HTMLファイルのダウンロード機能も実装しました。

import { PropsWithChildren, useCallback, useEffect, useId, useRef, useState } from 'react'
import mermaid from 'mermaid'
import { Button, Flex } from 'antd'
import { DownloadOutlined } from '@ant-design/icons'

export default function MermaidDiagram({ code }: PropsWithChildren<{ code: string }>) {
  const outputRef = useRef<HTMLDivElement>(null)
  const [svg, setSvg] = useState<string>()

  const render = useCallback(async () => {
    if (outputRef.current && code) {
      try {
        const { svg } = await mermaid.render('mermaid-flowchart', code)
        outputRef.current.innerHTML = svg
        setSvg(svg)
      } catch (error) {
        console.error(error)
        outputRef.current.innerHTML = 'Invalid syntax'
      }
    }
  }, [code])

  useEffect(() => {
    mermaid.initialize({
      startOnLoad: true,
      theme: 'default',
      flowchart: {
        useMaxWidth: true,
        htmlLabels: true,
        curve: 'basis',
        padding: 20,
        nodeSpacing: 100,
        rankSpacing: 80,
      },
    })
    render()
  }, [render])

  if (!code) {
    return
  }

  const onDownloadButtonClick = () => {
    if (!svg) {
      return
    }
    const a = document.createElement('a')
    a.download = 'mermaid_flowchart.html'
    const blob = new Blob([`<html lang="ja"><body>${svg}</body></html>`], { type: 'text/html' })
    a.href = URL.createObjectURL(blob)
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  }

  return (
    <div className={'mermaid-container'}>
      <Flex>
        <div style={{ marginLeft: 'auto' }}>
          <Button onClick={onDownloadButtonClick}>
            <DownloadOutlined />
            HTMLファイルをダウンロード
          </Button>
        </div>
      </Flex>
      <div className={'mermaid'} ref={outputRef} />
    </div>
  )
}

おわりに

まだまだ始まったばかりの取り組みですが、演習を量産し、受講者が納得いくまで復習できるようにしていきたいです。

お知らせ

グロービスでは継続的にエンジニアを募集しています。
興味のある方は下記のリンクをご覧になってください。

ではでは。

6
1
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
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?