Siv3D でもバイブコーディング!!!

本記事は Siv3D – Qiita Advent Calendar 2025 – Qiita https://qiita.com/advent-calendar/2025/siv3d の 3日目の記事です。

ChatGPTが一般的に使われ始めて2年ほど経ち、今度は AI エージェントというのが今年の4月頃から流行りはじめました。ChatGPT を使って、プログラミングのコードを教えて教えて貰うのはいいのですが、いちいちコードをコピペしないとイケなかったり、そもそも大量のコードをを ChatGPT に貼り付けないと文脈をうまく読み取ってくれないという問題がありました。が、これを Visual Studio Code 上なので直接ファイルを弄ってくれるのが AI エージェントの役割です。ちょっと危険な気もする(まあ、実際のところ MCP あたりが暴走すると危険なんですが)けれども、うまく使いこなせればこその「道具」なので、その道具を使いこなしていきましょう、というのがこの記事の主旨です。

バイブコーディング(vibe coding)とは?

ChatGPT にちまちまと関数のコードを貼り付けていたのととは違って、生成 AI を使って一気にコードを作成してしまおうというのが「バイブコーディング」の主な特徴です。いわゆる、AI にコードを書かせてしまって、コードを書く楽しみが…とも言えるのですが、職業プログラマとしては、

  • テストツールなどのたいくつなツールは AI に書かせた方が早い
  • 使い捨てツール=治具などは、AI に書かせたほうが早い
  • 最初のひな形は、AI にやってもらってたたき台にすることができる

という形で、使い捨てであったり最初のアイデアを実現するツールにバイブコーディングを使うのが一番効果的です。その後で、実際に仕事に使う場合にはコードの検証やら正確性やらが必要になってくるので、AI コードそのままを使うことはできませんが、それでも私自身の場合は、

  • 複雑怪奇になってしまったコードの解析を AI に頼む
  • 長々と出てくるエラーコードの解析を AI に頼む
  • ちょっと古めのコードを AI に読んで貰って、修正点のアイデアを出して貰う

のようなことをやります。最近は AI 任せにするツールや手法が盛んではありますが、その一歩手前の「AIペアプロ」がお勧めです。まあ、慣れてきたら、設計書を書くなりして一晩ぐるぐる回すほうが効果的ではあるのですが、慣れないうちはちまちま設計用の Readme.md や Agents.md(ファイル名は実は何でも構いません)に書いておいて、AI にちょっと作って貰うというのを繰り返すのがよいでしょう。自分なりのコーディングスタイルを掴んでください。

C++ でバイブコーディングできるのか?

巷に公開されているものは React などの Node.js や TypeScript を使った Web 開発のものが多いでしょう。設計書ノウハウ(「仕様書駆動」や「sepc駆動」というやつです)も、そのあたりのものが多いです。Web 開発の場合、コードを修正した途端に UI が変更になるとか、npm を使うとかするパターンが多いので、果たして C++ のように間にコンパイルが挟む場合はどうなるのか? という不安はありますが、大丈夫です。C++ でも十分使えます。しかも、Siv3D のような独自なライブラリを使っている場合でも、最近の生成 AI はうまく扱ってくれます。おそらく、Siv3D のチュートリアルサイト https://siv3d.github.io/ja-jp/ があるのが大きいと思います。つまり、Web サイトにある情報をうまく学習しているのが、現在の AI エージェントのモデルになっているわけです。

また、AI エージェントによるプログラム言語のコンバートの能力も上がっています。ロジックに関しては、一般的なプログラム言語はかなり網羅されています。別件ではありますが、Python のコードを VB.NET のコードに変換することもできます。あるいは、Kotlin や Swift のコードに変換したりします。それぞれデータベースなどライブラリの使い方は異なるのですが、それもプログラム言語特有のもの、かつ、そのプログラム言語で使われているライブラリをうまく使って変換してくれます。

Siv3Dでバイブコーディングしてみる

まあ、ここまで長々と書いてようやく Siv3D のコーディングに辿り着くわけですが、あまりやることがないので、ちょっと長々と書いてしまっているだけです。

AI エージェントでは、Visual Studio Code + Claude Sonnet を使っています。GitHub Copilot ならば月10ドルで契約が可能です。学生ならば 0 円で利用ができます。他にも結構高めなものもありますが、夜中にぐるぐる回さない限りこれで十分です。Google の Gemini のほうは分からないのですが、どの AI エージェントを使ってもだいたい似た感じでいけます。好きなものを使ってください。

AI エージェントによっては、プロジェクトを自動作成するところからできるパターンも多いのですが、このように Visual Studio を使ってプロジェクトテンプレートを使ってひな形のプロジェクトだけ作っておくとよいです。ビルドも自動化できるのですが、結構面倒なので、AI ペアプロとしてビルドは人間のほうの担当にします。

仕事としてはファイルを分けたほうがいいのですが、今回は面倒なので Main.cpp に全てを突っ込みます。この初期状態でビルドができるところまで確認しておきます。

agents.md を作成する

実はファイル名は Agents.md でも Readme.md でも Claudes.md でもなんでも構いません。夜中に自動化しようとすると、ファイル名を決めたほうがうまく AI エージェントに伝わるのですが、AI ペアプロの場合には「agents.md に従ってコードを作成して」とプロンプトで伝えるだけで十分です。ファイル名を頼りにうまく探してくれます。

agents.md の中身は以下のようになっています。

# ウマ娘レース

## 概要

ウマ娘レースは、ウマ娘たちが競い合うレースイベントです。
プレイヤーは、ウマ娘のパラメータを調節してトップを目指します。

## ルール

- レースは、横一列に並んだ5人のウマ娘で行なわれる
- 各ウマ娘には、スピード、スタミナ、パワー、根性、賢さの5つのパラメータがある
- プレイヤーは、自分のウマ娘のパラメータを調整してレースに挑む
- レースは複数のターンで構成され、各ターンでウマ娘たちは前進する
- 最終的にゴールに最も早く到達したウマ娘が勝者となる


## パラメータの説明

- スピード: ウマ娘の基本的な速さを決定するパラメータ
- スタミナ: ウマ娘が長距離を走る際の持久力を決定するパラメータ
- パワー: ウマ娘の加速力や坂道での強さを決定するパラメータ
- 根性: ウマ娘が苦しい状況でも踏ん張る力を決定するパラメータ
- 賢さ: ウマ娘がレース中に適切な判断を下す能力を決定するパラメータ

パラメータは、合計 20 ポイントまで振り分けることができる。


## レースの進行

- 各ターンでウマ娘たちは、パラメータに基づいて前進距離が決定される

サイコロ 1から6までのサイコロを2個振る。

前進距離 =
スピード * サイコロA +
スタミナ * サイコロB +
パワー * (サイコロA + サイコロB) / 2 +
根性 * ランダム値(3から6) +
賢さ * ランダム値(1から3)

各ウマ娘は順番サイコロを振り、出た目の大きい順に前進距離を計算していく。
最初に 1000 メートルに到達したウマ娘が勝者となる。

## 画面構成

- レーストラック: ウマ娘たちが走るコースが表示される。横長の一列でよい。
- 自分のウマ娘のパラメータを入れる
- 他のウマ娘のパラメータはランダムに設定される
- スタートボタンを押すと、レースが開始される。1秒毎に順番サイコロを振る。

## 設計

// ウマ娘の構造体
struct UmaMusume {
name: String,
speed: u8,
stamina: u8,
power: u8,
guts: u8,
wisdom: u8,
position: u32,
};

// レースの構造体
struct Race {
uma_musumes: Vec<UmaMusume>,
track_length: u32
};

これも慣れるとここまで書けるのですが、慣れないうちはそんなに細かく書かなくてもいいです。はっきり言って、概要とルールだけ書いても、このウマ娘レースは作成されてしまいます。どうやら、この手のゲームロジック(ブロック崩しとかインベーダーゲームとか)は生成 AI の学習データにあるっぽくて、それらしい何処かで見たようなものをうまく出してくれます。まあ、端的に言えばパクりなのですが、ここでは目をつぶっておきましょう。私的範囲内の利用ということです。

AI にコーディングしてもらう。

プロンプトで「agents.md に従ってコーディングして」と頼むだけです。AI エージェントのほうもだんだん賢くなっているので、結構なスピードでコードを生成してくれます。

見てわかるのですが、

  • パラメータを入れるためのセットアップ画面
  • レース中の画面
  • 結果を表示する画面

の3つに分かれています。この要素は agents.md に入れていないので、つまりはこれはどこからからパクって来たものです。こんな風に典型的な画面の作りの場合には AI エージェントが一番効率的に動きます。逆に、この3つの画面を、うまくひとつの画面に落とし込むのはなかなか苦労します。独自画面は苦手なんですよね。

そのような場合は、あらかじめコードのほうに、1画面の配置をコーディングしてしまうとうまくいきます。agents.md にあれこれと画面構成を記述する方法も可能なのですが、AI エージェント自身が既存のコードを解析しながら、そこに付け加えるように進めていくのでコード自身で伝えるほうが効果的です。

逆に、うまくコードで伝わらないときは、agents.md を作り直して一からバイブコーディングをしてしてみてください。バイブコーディングの良いところは、うまくいかなかった時はすべてを捨ててやり直しができるところです。これが人間がコーディングをすると、手間がかかっていたり再利用を考えたりするところなのですが、バイブコーディングの場合はコーディングの作成時間が短い&人間の労力が少ないので、最初からやり直してしまったほうが早いです。同じ agents.md であっても、確率的に別な構造になるので、何度かやってうまくいったものを利用する手があります。

もっとも、数行のプロンプトだけでうまくいくまで AI に書いて貰うという学校の課題方式ではだめです。ちょっとずつ agents.md を書き変えて、うまくパターンをみつけるのが人間の仕事になります。

できあがった Main.cpp

しばらく待つと Main.cpp ができあがります。

# include <Siv3D.hpp> // Siv3D v0.6.16

// ウマ娘の構造体
struct UmaMusume
{
	String name;
	int32 speed;
	int32 stamina;
	int32 power;
	int32 guts;
	int32 wisdom;
	int32 position;
	Color color;

	// パラメータの合計を計算
	int32 totalParams() const
	{
		return speed + stamina + power + guts + wisdom;
	}

	// 前進距離を計算
	int32 calculateAdvance() const
	{
		int32 diceA = Random(1, 6);
		int32 diceB = Random(1, 6);
		int32 gutsRandom = Random(3, 6);
		int32 wisdomRandom = Random(1, 3);

		int32 advance = speed * diceA
			+ stamina * diceB
			+ power * (diceA + diceB) / 2
			+ guts * gutsRandom
			+ wisdom * wisdomRandom;

		return advance;
	}
};

// レースの構造体
struct Race
{
	Array<UmaMusume> umaMusumes;
	int32 trackLength = 1000;
	bool isRunning = false;
	bool isFinished = false;
	int32 winnerIndex = -1;
	Stopwatch turnTimer;

	// ランダムなパラメータを生成(合計20ポイント)
	static UmaMusume createRandomUma(const String& name, const Color& color)
	{
		UmaMusume uma;
		uma.name = name;
		uma.color = color;
		uma.position = 0;

		// ランダムに20ポイントを振り分け
		Array<int32> params = { 1, 1, 1, 1, 1 }; // 最低1ずつ
		int32 remaining = 15; // 残り15ポイント

		for (int32 i = 0; i < remaining; ++i)
		{
			int32 idx = Random(0, 4);
			params[idx]++;
		}

		uma.speed = params[0];
		uma.stamina = params[1];
		uma.power = params[2];
		uma.guts = params[3];
		uma.wisdom = params[4];

		return uma;
	}

	// レースを1ターン進める
	void advanceTurn()
	{
		if (isFinished) return;

		// 各ウマ娘の前進距離を計算
		Array<std::pair<int32, int32>> advances; // (前進距離, インデックス)
		for (size_t i = 0; i < umaMusumes.size(); ++i)
		{
			advances.push_back({ umaMusumes[i].calculateAdvance(), static_cast<int32>(i) });
		}

		// 前進距離の大きい順にソート
		std::sort(advances.begin(), advances.end(), [](const auto& a, const auto& b) {
			return a.first > b.first;
		});

		// 順番に前進
		for (const auto& [advance, idx] : advances)
		{
			umaMusumes[idx].position += advance;

			// ゴール判定
			if (umaMusumes[idx].position >= trackLength && !isFinished)
			{
				isFinished = true;
				winnerIndex = idx;
				isRunning = false;
			}
		}
	}
};

void Main()
{
	// ウィンドウサイズを設定
	Window::Resize(1200, 700);
	Scene::SetBackground(ColorF{ 0.3, 0.6, 0.3 });

	// フォントを作成
	const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
	const Font smallFont{ FontMethod::MSDF, 32 };

	// ウマ娘の絵文字
	const Texture umaEmoji{ U"🏇"_emoji };

	// ウマ娘の名前と色
	const Array<String> umaNames = { U"プレイヤー", U"スペシャル", U"サイレンス", U"トウカイ", U"マチカネ" };
	const Array<Color> umaColors = { Palette::Red, Palette::Blue, Palette::Green, Palette::Orange, Palette::Purple };

	// レース
	Race race;

	// プレイヤーのパラメータ
	double playerSpeed = 4;
	double playerStamina = 4;
	double playerPower = 4;
	double playerGuts = 4;
	double playerWisdom = 4;

	// ゲーム状態
	enum class GameState { Setup, Racing, Result };
	GameState state = GameState::Setup;

	while (System::Update())
	{
		// タイトル表示
		font(U"🏇 ウマ娘レース 🏇").drawAt(48, Vec2{ 600, 40 }, Palette::White);

		if (state == GameState::Setup)
		{
			// パラメータ設定画面
			font(U"パラメータを設定してください").drawAt(32, Vec2{ 600, 100 }, Palette::Yellow);

			const int32 sliderX = 400;
			const int32 sliderWidth = 200;
			int32 y = 150;

			// パラメータスライダー
			SimpleGUI::Slider(U"スピード: {:.0f}"_fmt(playerSpeed), playerSpeed, 1.0, 10.0, Vec2{ sliderX, y }, 180, sliderWidth);
			y += 50;
			SimpleGUI::Slider(U"スタミナ: {:.0f}"_fmt(playerStamina), playerStamina, 1.0, 10.0, Vec2{ sliderX, y }, 180, sliderWidth);
			y += 50;
			SimpleGUI::Slider(U"パワー: {:.0f}"_fmt(playerPower), playerPower, 1.0, 10.0, Vec2{ sliderX, y }, 180, sliderWidth);
			y += 50;
			SimpleGUI::Slider(U"根性: {:.0f}"_fmt(playerGuts), playerGuts, 1.0, 10.0, Vec2{ sliderX, y }, 180, sliderWidth);
			y += 50;
			SimpleGUI::Slider(U"賢さ: {:.0f}"_fmt(playerWisdom), playerWisdom, 1.0, 10.0, Vec2{ sliderX, y }, 180, sliderWidth);

			// 合計ポイント表示
			int32 total = static_cast<int32>(playerSpeed) + static_cast<int32>(playerStamina)
				+ static_cast<int32>(playerPower) + static_cast<int32>(playerGuts) + static_cast<int32>(playerWisdom);

			Color totalColor = (total <= 20) ? Palette::Lime : Palette::Red;
			font(U"合計: {} / 20 ポイント"_fmt(total)).drawAt(28, Vec2{ 600, 430 }, totalColor);

			if (total > 20)
			{
				smallFont(U"※ 合計20ポイント以下にしてください").drawAt(24, Vec2{ 600, 470 }, Palette::Red);
			}

			// スタートボタン
			if (SimpleGUI::Button(U"レーススタート!", Vec2{ 500, 520 }, 200, (total <= 20)))
			{
				// レースを初期化(代入ではなくメンバごとに再初期化)
				race.umaMusumes.clear();
				race.trackLength = 1000;
				race.isRunning = false;
				race.isFinished = false;
				race.winnerIndex = -1;
				race.turnTimer.restart(); // タイマーをリセットして再スタート(既存インスタンスを再利用)

				// プレイヤーのウマ娘を作成
				UmaMusume player;
				player.name = umaNames[0];
				player.color = umaColors[0];
				player.speed = static_cast<int32>(playerSpeed);
				player.stamina = static_cast<int32>(playerStamina);
				player.power = static_cast<int32>(playerPower);
				player.guts = static_cast<int32>(playerGuts);
				player.wisdom = static_cast<int32>(playerWisdom);
				player.position = 0;
				race.umaMusumes.push_back(player);

				// 他のウマ娘をランダムに作成
				for (size_t i = 1; i < umaNames.size(); ++i)
				{
					race.umaMusumes.push_back(Race::createRandomUma(umaNames[i], umaColors[i]));
				}

				race.isRunning = true;
				race.turnTimer.restart();
				state = GameState::Racing;
			}

			// パラメータ説明
			y = 580;
			smallFont(U"スピード: 基本的な速さ | スタミナ: 持久力 | パワー: 加速力").draw(18, Vec2{ 200, y }, Palette::White);
			smallFont(U"根性: 踏ん張る力 | 賢さ: 判断力").draw(18, Vec2{ 200, y + 30 }, Palette::White);
		}
		else if (state == GameState::Racing)
		{
			// レース画面
			const int32 trackY = 200;
			const int32 trackHeight = 80;
			const int32 trackStartX = 100;
			const int32 trackWidth = 1000;

			// トラック背景を描画
			for (size_t i = 0; i < race.umaMusumes.size(); ++i)
			{
				int32 laneY = trackY + static_cast<int32>(i) * trackHeight;

				// レーン背景
				Rect{ trackStartX, laneY, trackWidth, trackHeight - 5 }
					.draw(ColorF{ 0.8, 0.6, 0.4 })
					.drawFrame(2, Palette::Brown);

				// ゴールライン
				Rect{ trackStartX + trackWidth - 10, laneY, 10, trackHeight - 5 }.draw(Palette::Red);
			}

			// 1秒ごとにターンを進める
			if (race.isRunning && race.turnTimer.ms() >= 1000)
			{
				race.advanceTurn();
				race.turnTimer.restart();
			}

			// ウマ娘を描画
			for (size_t i = 0; i < race.umaMusumes.size(); ++i)
			{
				const auto& uma = race.umaMusumes[i];
				int32 laneY = trackY + static_cast<int32>(i) * trackHeight;

				// 位置を計算(トラック幅に合わせてスケーリング)
				double progress = static_cast<double>(uma.position) / race.trackLength;
				progress = Min(progress, 1.0);
				int32 drawX = trackStartX + static_cast<int32>(progress * (trackWidth - 50));

				// ウマ娘の絵文字を描画
				umaEmoji.scaled(0.5).drawAt(drawX + 25, laneY + trackHeight / 2 - 2);

				// 名前と位置を表示
				smallFont(uma.name).draw(18, Vec2{ 10, laneY + 20 }, uma.color);
				smallFont(U"{}m"_fmt(uma.position)).draw(16, Vec2{ 10, laneY + 45 }, Palette::White);
			}

			// レース情報
			font(U"ゴール: {}m"_fmt(race.trackLength)).draw(24, Vec2{ 100, 620 }, Palette::White);

			// レース終了判定
			if (race.isFinished)
			{
				state = GameState::Result;
			}
		}
		else if (state == GameState::Result)
		{
			// 結果画面
			font(U"🎉 レース終了! 🎉").drawAt(48, Vec2{ 600, 150 }, Palette::Yellow);

			if (race.winnerIndex >= 0)
			{
				const auto& winner = race.umaMusumes[race.winnerIndex];
				font(U"優勝: {}"_fmt(winner.name)).drawAt(40, Vec2{ 600, 220 }, winner.color);

				if (race.winnerIndex == 0)
				{
					font(U"おめでとうございます!").drawAt(32, Vec2{ 600, 280 }, Palette::Lime);
				}
				else
				{
					font(U"残念...次は勝てるかも!").drawAt(32, Vec2{ 600, 280 }, Palette::Orange);
				}
			}

			// 順位表示
			Array<std::pair<int32, size_t>> ranking;
			for (size_t i = 0; i < race.umaMusumes.size(); ++i)
			{
				ranking.push_back({ race.umaMusumes[i].position, i });
			}
			std::sort(ranking.begin(), ranking.end(), [](const auto& a, const auto& b) {
				return a.first > b.first;
			});

			int32 y = 340;
			smallFont(U"【最終順位】").draw(24, Vec2{ 500, y }, Palette::White);
			y += 40;

			for (size_t rank = 0; rank < ranking.size(); ++rank)
			{
				const auto& uma = race.umaMusumes[ranking[rank].second];
				smallFont(U"{}位: {} ({}m)"_fmt(rank + 1, uma.name, uma.position))
					.draw(22, Vec2{ 480, y }, uma.color);
				y += 35;
			}

			// リトライボタン
			if (SimpleGUI::Button(U"もう一度プレイ", Vec2{ 500, 580 }, 200))
			{
				state = GameState::Setup;
			}
		}
	}
}

実は、生成されるコードはビルドが通るとは限りません。今後の AI エージェントでは改善されると思いますが、文法的にちょっと間違っていたり、関数の整合性が合わないところがちょこちょこ出てきます。

このコードでは既に修正してありますが、スタートボタンを押したときの「// レースを初期化(代入ではなくメンバごとに再初期化)」の部分で、Race 構造体の初期化でコンパイルエラーがでていました。

race = Race{} ;

Race 構造体にデフォルトコンストラクタがないので、これでは駄目です。

race.umaMusumes.clear();
race.trackLength = 1000;
race.isRunning = false;
race.isFinished = false;
race.winnerIndex = -1;
race.turnTimer.restart(); // タイマーをリセットして再スタート(既存インスタンスを再利用)

まあ、他にも修正点はあるかもしれませんが、ひとまずビルドして動かしてみましょう。

動作確認

動かすと、馬が後ろ向きに走ってしまっているとか、パラメータを保存できないとか、ケース結果が蓄積されないとか、いろいろ改善点があります。

これは agents.md に書き込んで「この部分を修正して」とプロンプトに入れてもよいし、自分でコードを書き直してもよいです。コードのコメントに修正案を書いて、「この部分を実装して」でも AI がコードを作ってくれます。

では、AI ペアプロで、よい Siv3D プログラミングライフを!

サンプルコード

moonmile/siv3d_uma_race https://github.com/moonmile/siv3d_uma_race

カテゴリー: 開発 | Siv3D でもバイブコーディング!!! はコメントを受け付けていません

エコーチェンばーちゃんの開発

7月頃だったか、新人研修が終わって AI エージェントがちょっと流行り始めた頃に1か月ほどあれこれと弄ってい時期があります。その頃は Claude Sonnet 4 を使って試していたのですが、いまだと Claude Opus 4.5 が使えるようになったので、もうちょっとマシになっているかなと思ってのお試しです。

この手のブラウザを使ったなんらかの Web サービスみたいなのは React で作っておくと楽です。私自身は React は得意じゃないのですが、AI エージェントが得意ならばそれでいいです。AI エージェントの得意分野のほうにあわせましょう、というスタイルですね。

これも、あらかじめ、React プロジェクトを作成しておきます。AI エージェントでプロジェクトから作成して貰ってもいいのですが、初期状態はバージョン関係か初期値のフォルダーの問題とかがあるので、手作業でやります。

npx create-react-app echo-cham-baachan

で、プロジェクトを作成しておいて、ここからスタートです。

Readme.md を作る

なかみは夏ごろに作ったものに少し手を入れています。書き方は機能から作ってもいいし、画面構成から考えてもいいです。本当は、いろいろと目的からスタートすればいいのですが、基本的に「エコーチェンバー現象」のシミュレーションツールというネタ機能なので、これだけで十分です。

# エコーチェンばぁちゃん

小中学生向けに、自分の意見が通る「エコーチェンバー現象」を疑似体験するツール。
反対意見がでてこないので、自分の意見が正しいと錯覚しやすくなる。

エコーチェンバー現象 - Wikipedia 
https://ja.wikipedia.org/wiki/%E3%82%A8%E3%82%B3%E3%83%BC%E3%83%81%E3%82%A7%E3%83%B3%E3%83%90%E3%83%BC%E7%8F%BE%E8%B1%A1

## 機能

- 自分の意見を入れると、5人のエコーチェンばぁちゃんが賛同してくれる。
- ばぁちゃんたちは、賛同の言葉をランダムに変化させる。
- 画面は、LINE のように吹き出しとばぁちゃんのアイコンが表示される。
- ばぁちゃんの性格は、いくつかのシステムプロンプトを用意して切り替えられる。

## 画面構成

- 入力エリア
  - 自分の意見を入力するテキストエリア
  - 送信ボタン
- チャットエリア
  - ばぁちゃんのアイコンと吹き出しで構成されるチャット表示エリア

## 技術スタック

- フロントエンド: React
- フロントエンドから OpenAI API へのリクエスト: Axios
- デプロイ: Vercel
- AI モデル: OpenAI GPT-5

## 環境変数 .env

- OPENAI_API_KEY: OpenAI API キー

Plan.prompt.md を作る

開発プランを vscode + copilot の Plan モードを使って作って貰います。

## Plan: エコーチェンばぁちゃん アプリ実装

README.mdに基づき、小中学生向けのエコーチェンバー現象疑似体験ツールを実装する計画です。Create React Appの初期状態から、LINEライクなチャットUIと5人のばぁちゃんAIを構築します。

### Steps

1. **依存関係のインストール** - `axios`を追加し、`package.json`を更新
2. **環境変数の設定** - `.env`ファイルを作成し、`REACT_APP_OPENAI_API_KEY`を定義
3. **UIコンポーネントの作成** - `src/components/`配下に`ChatContainer`、`MessageBubble`、`GrandmaAvatar`、`InputArea`を実装
4. **ばぁちゃんの設定ファイル作成** - `src/data/grandmas.js`に5人のばぁちゃん情報(名前、アイコン、システムプロンプト)を定義
5. **OpenAI APIサービスの実装** - `src/services/openai.js`でAPIリクエスト処理を作成
6. **メインApp.jsの実装** - `src/App.js`でチャット状態管理とコンポーネント統合
7. **LINEライクなスタイリング** - `src/App.css`で吹き出し・チャットUIのCSSを実装

### Further Considerations

1. **APIキーのセキュリティ** - フロントエンドから直接APIを呼ぶとキーが露出します。Vercel Serverless Functions (`/api/chat.js`) でラップする方式に変更しますか?

Vercel Serverless Functions を使う方式で。

2. **ばぁちゃんアイコン** - 5人分のアイコン画像はどこから用意しますか?(絵文字/生成AI/フリー素材)

ひとまず、絵文字で。

3. **性格の切り替え機能** - READMEに「システムプロンプトを用意して切り替えられる」とありますが、UIでの切り替え方法は?(ドロップダウン/タブ/設定画面)

設定が画面を作って。

足りない設定は「Further Considerations」に書かれているので、これを付けたします。いきなり Agent モードで作成すると、ばぁちゃんアイコンとか設定を想定で作ってしまうので、後からの修正が結構面倒です。なので、あらかじめ Plan を出して貰ってから、その後で Agent で進めるのがコツですね。

開発する

開発の頼み方はいろいろあるのですが、要は AI に通じればいいです。今回の場合は 30 分位で完了です。途中、いくつかフォルダーを作ったりするときに承認ボタンがでてきますが、これを押せば ok です。

実行する

まあ、質問をすると、なんでも肯定的に返してくれるので、こんな感じになります。

内部で使われているシステムプロンプトがこんな感じ。このシステムプロンプトも AI エージェント自身が作っているので、私は手をいれていません。他の性格を作りたいときは、この部分を直接書き変えてしまえばよいです。

// 性格タイプ別のシステムプロンプト
export const systemPrompts = {
  supportive: [
    `あなたは「ウメばぁちゃん」という優しいおばあちゃんです。
相手の意見には必ず賛同し、応援してください。
「そうそう」「その通りじゃ」「よく言った」などの言葉を使ってください。
返答は2〜3文程度で、温かみのある口調で話してください。
語尾は「〜じゃよ」「〜じゃね」「〜じゃのう」を使ってください。`,

    `あなたは「ハナばぁちゃん」という物知りなおばあちゃんです。
相手の意見には必ず賛同し、「さすがじゃ」「賢いのう」と褒めてください。
返答は2〜3文程度で、穏やかな口調で話してください。
語尾は「〜じゃよ」「〜じゃね」「〜じゃのう」を使ってください。`,

    `あなたは「トメばぁちゃん」という元気なおばあちゃんです。
相手の意見には必ず賛同し、「いいねぇ」「最高じゃ」と盛り上げてください。
返答は2〜3文程度で、明るい口調で話してください。
語尾は「〜じゃよ」「〜じゃね」「〜じゃのう」を使ってください。`,

    `あなたは「キヨばぁちゃん」という優しいおばあちゃんです。
相手の意見には必ず賛同し、「よく分かるよ」「うんうん」と共感してください。
返答は2〜3文程度で、包み込むような口調で話してください。
語尾は「〜じゃよ」「〜じゃね」「〜じゃのう」を使ってください。`,

    `あなたは「フミばぁちゃん」という知的なおばあちゃんです。
相手の意見には必ず賛同し、「なるほど」「深いのう」と感心してください。
返答は2〜3文程度で、落ち着いた口調で話してください。
語尾は「〜じゃよ」「〜じゃね」「〜じゃのう」を使ってください。`,
  ],

ChatGPT との会話でエコーチェンバー化するときは1対1なので、末尾のおべっかあたりを無視すればいいのですが、こんな風に5人の人格(ってほど分けられてはいないけど)にホめられると、ちょっといい気分になりそうなのが怖いですw

参考

GitHub https://github.com/moonmile/echo-cham-baachan

Vercel https://echo-cham-baachan.vercel.app で動作確認

設定から「陰謀論型」を選んだ時。

カテゴリー: 開発 | エコーチェンばーちゃんの開発 はコメントを受け付けていません

vscode + copilot の plan モードを実務の計画に応用できるか確認してみよう

別に Claude Code のプランモードが駄目という訳ではないのですが、IT 屋の範疇でいる “Plan” と、実務的な “Plan” とは大きな差があるので、そこだけ高速化したり自動化したりしても仕方がないんですよ。というのが本記事の主旨です。いわゆる、部分最適化に陥り勝ちになるので、じゃあ、全体を見渡した時に昨今の AI エージェントの Plan モードあるいは spec 駆動が、どのように実務に活用できるのか、という実験です。

プログラムを作るとか IT システムを組むとかいう範囲ではなくて、もう少し広い範囲で考えてみます。例えば、次のような要件での入札案件が出て来たとしましょう(実際に案件としてあるわけだし)。実際には入札までの設計とか見積もりとか人員の調達などが入るのですが、じゃあ、実務見積もりとしてどのくらい AI エージェントの機能が貢献できるのか? という実験をしてみます。これ、入口の部分は今書いている書籍に入ってはいるのですが、その続きはどうなるのかわからないので、結論はよくわからないところからスタートします。

Readme.md で目的を立てる

AI に資料を渡さないとスタートができないので、Readme.md にスタートとゴールの記述をします。

# 幼保小の架け橋プログラムに関する調査研究事業のまとめ

## 目的

「幼保小の架け橋プログラムに関する調査研究事業」の各都道府県の成果報告書をまとめる。
成果報告書があがっているが、フォーマットが統一されていないので、内容を整理する必要がある。
これを整理しつつ、目的のポイントを抑えて、参考となりそうな上位5件程度をピックアップしてまとめる。

## 進め方

1. 各都道府県の成果報告書を収集する。
2. ピックアップする内容、ポイントを抽出する。
3. ピックアップ項目に対して、各都道府県別の調査報告書から抜き出して、まとめる。
4. まとめた内容をレビューし、注目すべき上位5件ずつを選定する。
5. 最後に、ピックアップする項目単位で目次を作り、報告書を PDF にまとめる。

## 収集元

- 幼保小の架け橋プログラム:文部科学省 https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00002.htm
- 【幼保小の架け橋プログラム】中間成果報告会発表資料:文部科学省 https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00029.htm
- 【幼保小の架け橋プログラム】令和5年度成果報告書:文部科学省 https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00028.htm
- 【幼保小の架け橋プログラム】事業成果報告会(令和7年2月10日):文部科学省 https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00035.htm

## ピックアップ項目

- 全体的に、都道府県名、総人口、施設数を取りだす。
- 本プログラムの主旨に沿っているかチェックする
- 本プログラムの成果を確認する
- 本プログラムの次回の課題を確認する
- カリキュラム中の議事録やワークシートのリンク先をピックアップする

ピックアップ項目は、本プログラムの成果物をまとめた段階で、追加・修正する可能性がある。

いわゆる、入札案件の要件定義を自分たちで書き出すのと、見通してとしての計画を立てておきます。このあたりは、経験が必要なので IT 業界で2,3年では難しいかもしれませんが、逆に言えば非ITの実務業界としては、このあたりがスタート地点になりますよね。さらっと、A4 の用紙に1枚で書けるようになるといいです。

で、これはたたき台なので、その前身として AI を使ってもかまいません。ただし、AI の提案するプランはフルスペックなものが多いので、適度に端折らなければいけません。いわゆる、適度な予算で組めるような計画を立てないいけないのです。コツとしては、松竹梅で作っておいて、竹になるように工夫するわけですが、そのあたりは別のノウハウですね。

軽く「進め方」を書いてありますが、これは非 IT 業界の人でも可能です。

  • なんらかの形で「成果物報告書」を収集する(手作業でも可)
  • なんらかの形で「成果物から内容をピックアップする(手作業…というか、人が読むのも可)

というわけで、大抵は人手で頑張ります。基本 IT 屋さんも人手に頼るところもあるのですが、そこは IT 業界の強みとして、何らかのツールを使って高速化/省力化していきたいです。さらに言えば、AI エージェントなどの力を借りて、労力を下げたり、ひとよりも精度をアップさせたいわけです。そこが、非 IT の人との差別化になりますよね。IT に関してはプロなわけですから、道具を活用できるように少し頭を働かせてみようというわけです。

Plan.md を作成する

では、vscode + copilot を “plan” モードに切り替えて、データ収集とまとめのプランを立てて貰いましょう。

Plan モードって、手順を作るモードじゃなくて手順通りに進めるというモードなんですかね?このあたりが不明だけど、まあ、リンク先のファイルを読み込んで「19自治体の成果物」ってのは、たしかに正確ですね。

impliments とeditor があるので「editor」を選択しました。多分、impliments は即実行してしまうので危ういです。いったん editor で plan.prompt.md を確認しておきましょう。

# Plan: 幼保小の架け橋プログラム調査研究のまとめ

readme.md の目的を達成するため、19自治体の成果報告書(PDF形式)を収集・整理し、ピックアップ項目に基づいて上位5件を選定、最終レポートとしてPDFにまとめる計画です。

---

## Steps

1. **フォルダ構造の作成** - `data/`(年度別PDF保存用)、`analysis/`(比較分析用)、`output/`(最終成果物用)を readme.md と同階層に作成

2. **PDF一括ダウンロードスクリプトの作成** - 令和5年度・6年度成果報告書、中間報告会資料、事業成果報告会資料を19自治体分(計約70〜100ファイル)を自動取得するPowerShellまたはPythonスクリプトを作成

3. **基本情報収集シートの作成** - 19自治体(北海道、岐阜県、滋賀県、広島県、山口県、高知県、大館市、白石市、西会津町、川越市、横浜市、袋井市、掛川市、京都市、枚方市、箕面市、津和野町、高松市、竹田市)の総人口・施設数をExcel/CSVにまとめる

4. **ピックアップ項目の抽出と比較表作成** - 各報告書から「主旨との整合性」「成果」「次回課題」「カリキュラム・ワークシートのリンク」を抽出し、`analysis/summary.xlsx`に一覧化

5. **スコアリング基準に基づく上位5件の選定** - 先進性、エビデンスの質、再現可能性、地域特性の多様性を考慮して評価・ランキング

6. **最終レポートPDFの作成** - ピックアップ項目単位の目次構成で、選定した5自治体の詳細分析をまとめてPDF化

---

## Further Considerations

1. **PDFテキスト抽出ツールの選定** - 手作業で読み込むか、PyMuPDF/pdfplumberで自動抽出するか?(自動化推奨:19自治体×複数ファイル)

2. **評価基準の重み付け** - 「主旨との整合性」「成果の具体性」「課題の明確さ」のどれを優先するか?事前に決定が必要

3. **年度の扱い** - 令和5年度と6年度の両方を分析対象にするか、最新の6年度(最終年度)のみに絞るか?

---

## 対象自治体一覧(19自治体)

### 県レベル(6件)
| 自治体 |
|--------|
| 北海道 |
| 岐阜県 |
| 滋賀県 |
| 広島県 |
| 山口県 |
| 高知県 |

### 市町村レベル(13件)
| 自治体 | 所在県 |
|--------|--------|
| 大館市 | 秋田県 |
| 白石市 | 宮城県 |
| 西会津町 | 福島県 |
| 川越市 | 埼玉県 |
| 横浜市 | 神奈川県 |
| 袋井市 | 静岡県 |
| 掛川市 | 静岡県 |
| 京都市 | 京都府 |
| 枚方市 | 大阪府 |
| 箕面市 | 大阪府 |
| 津和野町 | 島根県 |
| 高松市 | 香川県 |
| 竹田市 | 大分県 |

---

## 推奨フォルダ構造

```
h:\ai-plan-junior-school-research\
├── readme.md
├── data\
│   ├── r5_reports\           # 令和5年度成果報告書
│   ├── r6_reports\           # 令和6年度成果報告書
│   ├── interim_reports\      # 中間報告会資料
│   └── final_reports\        # 事業成果報告会資料
├── analysis\
│   └── summary.xlsx          # 比較分析シート
└── output\
    └── final_report.pdf      # 最終成果物
```

---

## 収集元URL

- 幼保小の架け橋プログラム:https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00002.htm
- 中間成果報告会発表資料:https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00029.htm
- 令和5年度成果報告書:https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00028.htm
- 事業成果報告会(令和7年2月10日):https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00035.htm

フォルダーの構成とかを作ってくれますね。このあたり、非IT業界だと日本語で作るところですが、IT屋さんとしては Python をあたりを使って自動化したいところなので、このまま使います。多分、フォルダ構成を日本語に直しても AI エージェントのほうでうまくやってくれるはずです。

Steps が具体的な手順で、Further Considerations が設定しなければいけない要素ですね。対象自治体一覧はサイト https://www.mext.go.jp/a_menu/shotou/youchien/1258019_00035.htm をざっと見て確認しておいてください。うまく抽出できている模様です。これは文部科学省のサイトがうまく構造化されているということですね。場合によっては、このあたりが読み込めないサイトもあるでしょうから注意が必要です。たぶん、JavaScript を利用した CSR のサイトは難しいので、そのあたりは手作業が必要かもしれません。

Further Considerations に追加する

## Further Considerations

1. **PDFテキスト抽出ツールの選定** - 手作業で読み込むか、PyMuPDF/pdfplumberで自動抽出するか?(自動化推奨:19自治体×複数ファイル)

Python の PyMuPDF を使って自動収集する


2. **評価基準の重み付け** - 「主旨との整合性」「成果の具体性」「課題の明確さ」のどれを優先するか?事前に決定が必要

「成果の具体性」を最優先にして評価を行って。


3. **年度の扱い** - 令和5年度と6年度の両方を分析対象にするか、最新の6年度(最終年度)のみに絞るか?

令和5年度と6年度の両方を分析対象にして。

たぶん、それぞれの項目に設定値を書いておけばいいはずです。このあたりは、うまく AI エージェントが読み取ってくれます。

この後、Plan で動かすのか Agent で動かすのかが不明なのですが、Plan モードにしたままで、Plan.prompt.md を実行してもらいましょう。

ここでは「Start Implimentation」のボタンをクリック…できあがるのかな?

自動承認を有効にするか?

vscode + copilot で動かしたときに、Allow ボタンがでて、いちいちステップ実行の確認を取ります。これ、真夜中に動かしたいばあいは「自動承認」と言う形でやってしまうのがいいのですが、現時点では悪意ある MCP の防御ができなかったり、サイトの読み込み時に不備が発生しそうなので、人間がいちいち承認するほうがよいです。

何回か同じプロンプトを動かして、安全とわかっている場合にはいいのですが、最初に動かすプロンプトの場合は要注意かなと。

あと、このスクリプトのままだと Python の仮想環境を AI エージェントが作るので初期設定がちょっと面倒ですね。Python の仮想環境だけは、あらかじめ手作業で作っておいたほうがよさそうです。

ダウンロードスクリプトとか、もうベタに作ってくれます。

# -*- coding: utf-8 -*-
"""
幼保小の架け橋プログラム - 成果報告書PDFダウンロードスクリプト
文部科学省の成果報告書ページから19自治体分のPDFを一括ダウンロードします。
"""

import os
import requests
from pathlib import Path
from urllib.parse import urljoin
import time

# ベースURL
BASE_URL = "https://www.mext.go.jp"

# 保存先ディレクトリ
DATA_DIR = Path(r"h:\ai-plan-junior-school-research\data")

# 令和5年度成果報告書(2024年7月9日公開)
R5_REPORTS = {
    "北海道": {
        "成果報告書": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-1.pdf",
        "カリキュラム": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-2.pdf",
        "成果物": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-3.pdf",
    },
    "岐阜県": {
        "成果報告書": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-4.pdf",
        "カリキュラム": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-5.pdf",
    },
    "滋賀県": {
        "成果報告書": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-6.pdf",
        "カリキュラム": "https://www.mext.go.jp/content/20240709-mxt_youji-000023526-7.pdf",
    },
...

見ると分かるのですが、ファイル名がべた書きですよね。これはこれでいいのです。治具=使い捨てのツールとして、Python スクリプトが用いられているわけで、これをファイルから読み込むとか何かの設定から読み込むとかしなくて十分なのです。ダウンロードスクリプトなんて1回しか動かさないし、ファイル名なんて固定で良い訳です。

これがプログラマだったり、プログラムを外注したりするとあれこれと設計やら打合せが必要になるのですが、AI エージェントががりがりとベタで作ってくれるので、その分手間が省けます。逆に言えば、ちょっと修正したい場合(自治体を増やしたい場合とか)は、Plan.prompt.md に自治体とリンク先を追加して、もういちど AI エージェントを使って実行して貰えばいいのです。

このあたりの繰り返しが非常に高速になったのが AI エージェントの利点です。どこのブログだったかツイートだったか忘れましたが「ウォーターフォール開発のプロセスを 15 分で廻せるようになった」のが大きいです。いままでは、この部分をアジャイル開発だとか計画駆動とかで設計を練る、あるいは動作させてから考え直す、というループが必要だったのですが、AI エージェントがすべてをやり直してくれるので「高速にまわる計画駆動」ができるようなったのが大きいですね。

まあ、この部分はPDF のダウンロード&分析という比較的やりやすいところをターゲットにしているので AI エージェントが有効に働きますが、これが部品の品質点検&改良とか、食品加工での調味料の組み合わせ試験、とかになると AI エージェントだけでは回らないので工夫が必要です。そういうときは別な計画が必要になります。他にも、組み込み機器で実測とか、Android 機器の BLE 相性あわせ(これをやっている)とかは AI エージェントだけでは回りません。

分析の完了

さて、2時間ほど掛かりましたが分析レポートが作成されました。

このレポートの点数付けは analyze_reports.py の analyze_report 関数で計算しているので、単純な加点形式なのですが、ひとまず下調べとしてはよいでしょう。

def analyze_report(municipality: str) -> dict:
    """
    自治体の成果報告書を分析する
    
    Args:
        municipality: 自治体名
    
    Returns:
        分析結果の辞書
    """
    result = {
        "自治体名": municipality.replace("_", "(") + ")" if "_" in municipality else municipality,
        "成果報告書": "",
        "主旨との整合性": "",
        "主な成果": "",
        "次回の課題": "",
        "カリキュラム・ワークシート": "",
        "成果の具体性スコア": 0,
        "備考": ""
    }
    
    # 令和5年度成果報告書を読み込む
    r5_report_path = DATA_DIR / "r5_reports" / f"{municipality}_成果報告書.pdf"
    r5_text = ""
    if r5_report_path.exists():
        r5_text = extract_text_from_pdf(r5_report_path)
        result["成果報告書"] = "あり"
    else:
        result["成果報告書"] = "なし"
        result["備考"] = "令和5年度成果報告書が見つかりません"
    

本来ならば、ピックアップしたい用語などを含めて PDF を OpenAI API に流し込んで、AI にスコア判定をさせる方法がよいです。これをやるためには、plan.prompt.md を書き変えて、評価の重みづけをするツールを Python スクリプトを作るのがよいです。このあたりは、プログラマの領分になってしまうので、またの機会にしましょう。

スコア計算のツールを AI エージェントを使って作るればいいだけなのですが、プロンプトの作成と OpenAI の API キーコードが必要になってしまうので、ちょっと非 IT 業界の人には荷が重いかもしれません。このあたり、自動化をしないのであれば、ChatGPT に PDF を手作業で突っ込みながらも可能なので、要件自体は満たせます。

final_report.md を python の md-to-pdf を使って PDF ファイルに直したものです。スコアをどう見るかは、中身に確認していかないと駄目なのですが、下調べ段階としてはこれで十分でしょう。すべてを調ベルのは大変なので、優先度としてスコアの高いものから順にチェックしていけばいいのです。そこは AI の判断を信用するかどうかは別なのですが。

まあ、こんな感じで非 IT 業界でも vscode + copilot の AI エージェントを使って資料作成とか情報収集とかができるようになりますよ、という例です。特に、この手のツールをを外注したり自前で時間をかけて作る必要がなくなるのが良いかなと。Plan のほうは、自分で計画立てないと途中で頓挫しそうですが、少しは頼りになるでしょう。

参考先

https://github.com/moonmile/ai-plan-junior-school-research

追記 OpenAI API を使う

もう少し実用的な例を含めてみようと思って、OpenAI API を使ってそれぞれの報告書のスコアを出してみましょう。

Plan.prompt.md に新しい評価基準を追加します。

### 評価基準(成果の具体性スコア: 最大100点)

評価基準関数 analyze_report を OpenAI API を使って再実装する
- analyze_report_ai 関数とする


- 成果報告書の有無 20点
- 主旨との整合性 20点
  主要キーワードが上手く織り込まれているかをチェック
- 主な成果 20点
  成果の主張や具体的なデータ・事例の提示がされているかをチェック
- 次回の課題 20点
  問題点を明らかにして、次回以降の課題が具体的に締召されているかをチェック
- カリキュラム・ワークシートの有無 20点
  カリキュラムやワークシートのリンクが提供されているかをチェック

この内容を OpenAI のプロンプトと成果物の文書を一緒に渡して、評価結果を返して貰う事になります。以前は、システムプロンプトを作ったり、OpenAI API を呼び出す関数を作ったりと色々大変でしたが、いまでは AI エージェントが適切なコードを作ってくれます。

ここからはプログラマの領域に踏み込むので、非 IT 業界の方には少し辛いかもしれませんが、大丈夫です。概ねは AI エージェントがやってくれます。が、一発ではうまく動かない(大抵は JSON 形式が喰い違ってうまくいかない)のですが、これも AI エージェントが少しずつ直していってくれます。

このあたりが、AI エージェントが Excel VBA のように一般に広まるかどうかの肝ですね。いわゆる、バグ直しをしないといけないので、これは従来のプログラミングとほとんど変わりません。コードを書かない代わりに、不具合を見つけてうまく AI に指示を出すとか、自分が納得できるまで AI エージェントを働かせ続けることが必要になります。つまりは、根気がいるわけですが…ここはちょっと分かりません。私はプログラマなので慣れているのですが、一般の人はどう思うのか?

結果として、こんな風に Excel 形式で分析結果がでます。

それぞれのスコアもそれっぽく出ているので、プログラムの動きとしては問題なさそうです。

システムプロンプトに関しては、以下のようになっているので、この内容を書き変えれば別の評価基準になります。

# OpenAI クライアント(環境変数 OPENAI_API_KEY を自動的に使用)
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# 評価プロンプト
EVALUATION_PROMPT = """あなたは「幼保小の架け橋プログラム」の成果報告書を評価する専門家です。
以下の自治体の成果報告書を評価してください。

## 評価対象自治体
{municipality}

## 成果報告書の内容(抜粋)
{report_text}

## カリキュラム・成果物の有無
{materials_info}

## 評価基準(最大100点)

以下の5つの観点で各20点満点で評価してください:

### 1. 成果報告書の有無・充実度(20点)
- 成果報告書が存在するか
- 報告書の内容が充実しているか
- 構成が整理されているか

### 2. 主旨との整合性(20点)
以下の主要キーワードが適切に織り込まれているかをチェック:
- 架け橋期、5歳児、小学校1年生
- 連携、接続
- 主体的、対話的、深い学び
- 多様性、学びの基盤

### 3. 主な成果(20点)
- 成果の主張が明確か
- 具体的なデータや数値が提示されているか
- 実践事例が具体的に記載されているか
- エビデンスに基づいた成果報告になっているか

### 4. 次回の課題(20点)
- 問題点が明確に示されているか
- 次回以降の課題が具体的に提示されているか
- 改善に向けた方向性が示されているか

### 5. カリキュラム・ワークシートの有無(20点)
- カリキュラムが提供されているか
- ワークシートや成果物が提供されているか
- 他自治体でも活用可能な形式か

## 出力形式
以下のJSON形式で回答してください(コードブロックなしで純粋なJSONのみ):

{{"成果報告書スコア": 15, "成果報告書評価": "評価コメント", "主旨整合性スコア": 18, "主旨整合性評価": "評価コメント", "成果スコア": 16, "成果評価": "評価コメント", "課題スコア": 14, "課題評価": "評価コメント", "成果物スコア": 12, "成果物評価": "評価コメント", "総合スコア": 75, "総合評価": "総合的な評価コメント", "主な成果要約": "成果の要約(200文字以内)", "主な課題要約": "課題の要約(200文字以内)"}}
"""

いままで、このプロンプトを書くのが大変で「プロンプトエンジニアリング」と呼ばれていたものですが、こんな風にレポートを出したり要約を出す程度であれば、AI エージェントが作成してくれるプロンプトで構いません。それほど手を入れなくて済みます。

まあ、謎な画像AIのプロンプトならば別なのでしょうが、OpenAI API などを使って AI とやり取りするための JSON 形式や内容を変換するようなプロンプトをを作る場合には AI エージェント自身に作成してもらったほうがいいでしょう。

コード自体は、https://github.com/moonmile/ai-plan-junior-school-research/tree/openai のほうにブランチ openai にしておくので、そこからダウンロードしてください。

レポートを見ると、分析手法が書いてあります。成果の具体性スコアも変わっています。これれは、実際に報告書を読んで人間が判断する必要があります。

カテゴリー: 開発 | vscode + copilot の plan モードを実務の計画に応用できるか確認してみよう はコメントを受け付けていません

数学的な問題について画像AIによる嘘を避ける方法

この手の話は、DALL-E の頃から言われていて、何かと数学的な図を書かせようとするとどこからかのなんちゃって画像を持ってくるために変なことになります。たぶん、古い教科書のスキャン画像とかを学習データにいれてしまっていて、そこから引っ張ってきているだけです。そもそも、画像の生成 AI に関しては、「教師なし学習」での推論でしかなくて、数学や物理のような自然科学的な解答のある「教師あり学習」の結果を求めようとしても無駄です。このあたりは、漫画やイラストを描かせた場合にはなんとなくいいけれど、部分的に手の指がおかしかったり腕が三本あったりするのがそれです。このあたりの正確性≒正解と明確に分かるものは、将来的にAIエージェントによる自己チェック機能で避けることができると思います。

まあ、その自己チェックを入れてあげれば、この手の図も正確にできるようになると、という例が以下のものです。

現状の唯一の方法としては、先の「シュレディンガー方程式」については、直接画像AIを使うのではなく、いったん Python などを使って正確な式から正確な図を描くようにします。こうすると、当たり前ですが正確な図ができますね。これを、切り貼りする(素材として画像AIに渡してもいいでしょう)ことで、「数学的に正確な図」を私達は得ることができます。

当たり前といえば、当たり前なのですが、この手のなんちゃって画像AI全般に言えることで、プロンプトがどうという話ではなく、さきに書いた通り

・「教師なし学習」的な正解ではないもの、つまりは「創造性」みたいなものを求めるのか?
・「教師あり学習」的な数学や物理のように自然科学として正解があるものを求めるのか?

という違いです。先の X のポストから言えば、当然後者のほうではあるのですが、実は意図として「数学的には正しくはないけれど、なんとなく中世で扱っていた数学っぽい SF 的な図を作り出して」というプロンプトであれば、前者が求められるというわけです。

で、実験的に Python でコードを出力もらったらどうなのか? ということを試してみましょう。以下は「Claude Sonnet 4.5」を使って Python コードを出力したものです。画像は、matplotlib.pyplot を使って PNG 形式で得ることができます。

ランダム値

プロンプトで「ランダム値をプロットして」というと、これもなんちゃって画像が生成されます。実際にランダム値の正確な図が欲しいのであれば、Python コードで書けばいいだけです。さぼってはいけませんw

# 一様分布のグラフを描く
import numpy as np
import matplotlib.pyplot as plt

# 日本語フォントの設定
plt.rcParams['font.sans-serif'] = ['MS Gothic', 'Yu Gothic', 'Meiryo']
plt.rcParams['axes.unicode_minus'] = False

# 一様分布からランダム値を生成
np.random.seed(42)  # 再現性のため
n_samples = 10000

# 0から1の範囲で一様分布
uniform_values = np.random.uniform(0, 1, n_samples)

# グラフの作成
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 1. ヒストグラム
axes[0, 0].hist(uniform_values, bins=50, edgecolor='black', alpha=0.7)
axes[0, 0].set_title('一様分布のヒストグラム')
axes[0, 0].set_xlabel('値')
axes[0, 0].set_ylabel('度数')
axes[0, 0].grid(True, alpha=0.3)

# 2. 累積分布
axes[0, 1].hist(uniform_values, bins=50, cumulative=True, edgecolor='black', alpha=0.7)
axes[0, 1].set_title('累積分布')
axes[0, 1].set_xlabel('値')
axes[0, 1].set_ylabel('累積度数')
axes[0, 1].grid(True, alpha=0.3)

# 3. 散布図(サンプル順)
sample_indices = np.arange(min(500, n_samples))
axes[1, 0].scatter(sample_indices, uniform_values[:len(sample_indices)], alpha=0.5, s=10)
axes[1, 0].set_title('ランダム値の分布(最初の500サンプル)')
axes[1, 0].set_xlabel('サンプル番号')
axes[1, 0].set_ylabel('値')
axes[1, 0].grid(True, alpha=0.3)

# 4. 理論値との比較
sorted_values = np.sort(uniform_values)
theoretical = np.linspace(0, 1, n_samples)
axes[1, 1].plot(theoretical, sorted_values, 'b-', alpha=0.5, label='実測値')
axes[1, 1].plot([0, 1], [0, 1], 'r--', label='理論値(y=x)')
axes[1, 1].set_title('Q-Qプロット(理論値との比較)')
axes[1, 1].set_xlabel('理論分位点')
axes[1, 1].set_ylabel('実測分位点')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('一様分布.png', dpi=300, bbox_inches='tight')
plt.show()

print(f'サンプル数: {n_samples}')
print(f'平均値: {np.mean(uniform_values):.4f} (理論値: 0.5000)')
print(f'標準偏差: {np.std(uniform_values):.4f} (理論値: {1/np.sqrt(12):.4f})')
print(f'最小値: {np.min(uniform_values):.4f}')
print(f'最大値: {np.max(uniform_values):.4f}')

波動関数


波動関数をグラフにしたものです、波動関数自体は数学的な式なので、画像AIに頼るよりも Python などで正確に描いたほうが良いです。ここぐらいまでは、コードやグラフを眺めて、ほぼ出ているだろうというレベルでしょう。


# シュレディンガー方程式の「波動関数」と「確率密度」
# 波動関数の例を 2D グラフで
# 確率密度のグラフを 3D グラフで

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 日本語フォントの設定
plt.rcParams['font.sans-serif'] = ['MS Gothic', 'Yu Gothic', 'Meiryo']
plt.rcParams['axes.unicode_minus'] = False

# 1次元無限井戸型ポテンシャルの波動関数
def wave_function_1d(x, n, L):
    """
    1次元無限井戸型ポテンシャルの波動関数
    n: 量子数 (1, 2, 3, ...)
    L: 井戸の幅
    """
    return np.sqrt(2/L) * np.sin(n * np.pi * x / L)

# 2次元波動関数(例:水素原子の2p軌道)
def wave_function_2d(x, y):
    """
    簡易的な2次元波動関数の例
    """
    r = np.sqrt(x**2 + y**2)
    return r * np.exp(-r) * np.cos(np.arctan2(y, x))

# 確率密度関数(波動関数の絶対値の2乗)
def probability_density(psi):
    """
    確率密度 = |ψ|²
    """
    return np.abs(psi)**2

# ===== 1. 波動関数の2Dグラフ =====
fig = plt.figure(figsize=(16, 10))

# 1次元波動関数(複数の量子状態)
x = np.linspace(0, 1, 1000)
L = 1.0

ax1 = plt.subplot(2, 3, 1)
for n in [1, 2, 3, 4]:
    psi = wave_function_1d(x, n, L)
    ax1.plot(x, psi, label=f'n={n}')
ax1.set_xlabel('位置 x')
ax1.set_ylabel('波動関数 ψ(x)')
ax1.set_title('1次元無限井戸型ポテンシャルの波動関数')
ax1.legend()
ax1.grid(True, alpha=0.3)
ax1.axhline(y=0, color='k', linestyle='-', linewidth=0.5)

# 確率密度(1次元)
ax2 = plt.subplot(2, 3, 2)
for n in [1, 2, 3, 4]:
    psi = wave_function_1d(x, n, L)
    prob = probability_density(psi)
    ax2.plot(x, prob, label=f'n={n}')
ax2.set_xlabel('位置 x')
ax2.set_ylabel('確率密度 |ψ(x)|²')
ax2.set_title('確率密度(1次元)')
ax2.legend()
ax2.grid(True, alpha=0.3)

# 波動関数の実部と虚部(時間発展を含む例)
ax3 = plt.subplot(2, 3, 3)
t = 0
n = 2
psi = wave_function_1d(x, n, L)
E = n**2  # エネルギー固有値(簡略化)
psi_real = psi * np.cos(E * t)
psi_imag = psi * np.sin(E * t)
ax3.plot(x, psi_real, label='実部 Re(ψ)', color='blue')
ax3.plot(x, psi_imag, label='虚部 Im(ψ)', color='red')
ax3.plot(x, np.abs(psi), label='振幅 |ψ|', color='green', linestyle='--')
ax3.set_xlabel('位置 x')
ax3.set_ylabel('波動関数')
ax3.set_title(f'波動関数の実部・虚部(n={n}, t={t})')
ax3.legend()
ax3.grid(True, alpha=0.3)
ax3.axhline(y=0, color='k', linestyle='-', linewidth=0.5)

# ===== 2. 2次元確率密度の3Dグラフ =====

# 2次元グリッド
x_2d = np.linspace(-5, 5, 100)
y_2d = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x_2d, y_2d)

# 波動関数を計算
psi_2d = wave_function_2d(X, Y)
prob_2d = probability_density(psi_2d)

# 3Dプロット
ax4 = plt.subplot(2, 3, 4, projection='3d')
surf = ax4.plot_surface(X, Y, prob_2d, cmap='viridis', alpha=0.8)
ax4.set_xlabel('x')
ax4.set_ylabel('y')
ax4.set_zlabel('確率密度 |ψ|²')
ax4.set_title('2次元確率密度(3D表示)')
plt.colorbar(surf, ax=ax4, shrink=0.5)

# 2Dヒートマップ(上から見た図)
ax5 = plt.subplot(2, 3, 5)
contour = ax5.contourf(X, Y, prob_2d, levels=20, cmap='viridis')
ax5.set_xlabel('x')
ax5.set_ylabel('y')
ax5.set_title('確率密度(ヒートマップ)')
ax5.set_aspect('equal')
plt.colorbar(contour, ax=ax5)

# 等高線プロット
ax6 = plt.subplot(2, 3, 6)
contour_lines = ax6.contour(X, Y, prob_2d, levels=15, colors='black', linewidths=0.5)
ax6.contourf(X, Y, prob_2d, levels=20, cmap='plasma', alpha=0.7)
ax6.clabel(contour_lines, inline=True, fontsize=8)
ax6.set_xlabel('x')
ax6.set_ylabel('y')
ax6.set_title('確率密度(等高線)')
ax6.set_aspect('equal')

plt.tight_layout()
plt.savefig('波動関数と確率密度.png', dpi=300, bbox_inches='tight')
plt.show()

# 統計情報を出力
print("=" * 50)
print("1次元波動関数の統計(n=1の場合)")
print("=" * 50)
psi_1 = wave_function_1d(x, 1, L)
prob_1 = probability_density(psi_1)
print(f"波動関数の最大値: {np.max(np.abs(psi_1)):.4f}")
print(f"確率密度の積分(規格化確認): {np.trapz(prob_1, x):.4f}")
print(f"期待値 <x>: {np.trapz(x * prob_1, x):.4f}")

print("\n" + "=" * 50)
print("2次元確率密度の統計")
print("=" * 50)
total_prob = np.sum(prob_2d) * (x_2d[1] - x_2d[0]) * (y_2d[1] - y_2d[0])
print(f"確率密度の総和(近似): {total_prob:.4f}")
print(f"最大確率密度: {np.max(prob_2d):.6f}")
max_idx = np.unravel_index(np.argmax(prob_2d), prob_2d.shape)
print(f"最大確率密度の位置: (x={X[max_idx]:.2f}, y={Y[max_idx]:.2f})")

水素原子の電子軌道

実は、水素原子の軌道計算がちょっとアヤシイです。自分の場合は、原子力学科なのでこの軌道計算は最初の頃にやった筈なのですが(まあ、波動関数自体はいわゆる常識の範囲なので)、図の書き方が一般的に流通するものと違うのでなんとも言えないです。

ただし、電子軌道計算は、https://betterlate-thannever.github.io/Chemistry-2e/%E7%AC%AC6%E7%AB%A0-%E5%85%83%E7%B4%A0%E3%81%AE%E9%9B%BB%E5%AD%90%E6%A7%8B%E9%80%A0%E3%81%A8%E5%91%A8%E6%9C%9F%E7%9A%84%E6%80%A7%E8%B3%AA.html#%E9%87%8F%E5%AD%90%E8%AB%96%E3%81%AE%E7%99%BA%E5%B1%95 にあるように描かれるのが定番ではあるのですが、実際には電子雲の確率として示されるので、ちょっと旧来の書き方はいわゆる電子の粒のイメージが強くて、微妙なんですよね。確かに、私も「ダンベル型」になるという覚えがあるのですが、このイメージよりも単純な電子雲つまり数式そのものとしてはあくするようないい気がしています。まあ、どちらにせよ、模式図でしかないので、計算するとこうなるよという Python コードと図です。

# 水素原子の電子軌道の 3D グラフ
# s、p、f、d 軌道も追加

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.special import sph_harm_y, genlaguerre, factorial
import matplotlib.colors as mcolors

# 日本語フォントの設定
plt.rcParams['font.sans-serif'] = ['MS Gothic', 'Yu Gothic', 'Meiryo']
plt.rcParams['axes.unicode_minus'] = False

# ボーア半径(原子単位)
a0 = 1.0

def radial_wave_function(r, n, l):
    """
    動径波動関数 R_nl(r)
    n: 主量子数
    l: 軌道角運動量量子数
    """
    rho = 2 * r / (n * a0)
    norm = np.sqrt((2 / (n * a0))**3 * factorial(n - l - 1) / (2 * n * factorial(n + l)))
    laguerre = genlaguerre(n - l - 1, 2 * l + 1)(rho)
    return norm * np.exp(-rho / 2) * rho**l * laguerre

def hydrogen_orbital(r, theta, phi, n, l, m):
    """
    水素原子の波動関数 ψ_nlm(r, θ, φ)
    n: 主量子数 (1, 2, 3, ...)
    l: 軌道角運動量量子数 (0, 1, ..., n-1)
    m: 磁気量子数 (-l, ..., 0, ..., l)
    """
    R_nl = radial_wave_function(r, n, l)
    Y_lm = sph_harm_y(l, m, theta, phi)
    return R_nl * Y_lm

def create_orbital_visualization(n, l, m, resolution=50, r_max=None):
    """
    軌道を3D可視化
    """
    if r_max is None:
        r_max = n**2 * a0 * 3  # 適切な範囲を設定
    
    # 球座標グリッド
    theta = np.linspace(0, np.pi, resolution)
    phi = np.linspace(0, 2*np.pi, resolution)
    THETA, PHI = np.meshgrid(theta, phi)
    
    # 確率密度の最大値を探すための半径
    r_values = np.linspace(0.1, r_max, 100)
    max_prob = 0
    optimal_r = r_max / 2
    
    for r_test in r_values:
        psi = hydrogen_orbital(r_test, np.pi/2, 0, n, l, m)
        prob = np.abs(psi)**2 * r_test**2
        if prob > max_prob:
            max_prob = prob
            optimal_r = r_test
    
    # 複数の半径で等値面をプロット
    r_surfaces = [optimal_r * factor for factor in [0.5, 0.8, 1.0]]
    
    return THETA, PHI, r_surfaces

# 各軌道の名前
orbital_names = {
    (1, 0, 0): '1s',
    (2, 0, 0): '2s',
    (2, 1, -1): '2p_y',
    (2, 1, 0): '2p_z',
    (2, 1, 1): '2p_x',
    (3, 0, 0): '3s',
    (3, 1, -1): '3p_y',
    (3, 1, 0): '3p_z',
    (3, 1, 1): '3p_x',
    (3, 2, -2): '3d_xy',
    (3, 2, -1): '3d_yz',
    (3, 2, 0): '3d_z²',
    (3, 2, 1): '3d_xz',
    (3, 2, 2): '3d_x²-y²',
    (4, 0, 0): '4s',
    (4, 1, 0): '4p_z',
    (4, 2, 0): '4d_z²',
    (4, 3, -3): '4f_y(3x²-y²)',
    (4, 3, -2): '4f_xyz',
    (4, 3, -1): '4f_yz²',
    (4, 3, 0): '4f_z³',
    (4, 3, 1): '4f_xz²',
    (4, 3, 2): '4f_z(x²-y²)',
    (4, 3, 3): '4f_x(x²-3y²)',
}

# 可視化する軌道(s, p, d, f 軌道を含む)
orbitals_to_plot = [
    (1, 0, 0),   # 1s
    (2, 1, 1),   # 2px
    (3, 2, 1),   # 3dxz
    (4, 3, 1),   # 4fxz²
]

fig = plt.figure(figsize=(20, 16))

for idx, (n, l, m) in enumerate(orbitals_to_plot, 1):
    ax = fig.add_subplot(3, 5, idx, projection='3d')
    
    THETA, PHI, r_surfaces = create_orbital_visualization(n, l, m, resolution=60)
    
    # 各半径で等値面をプロット
    for i, r in enumerate(r_surfaces):
        # 直交座標に変換
        X = r * np.sin(THETA) * np.cos(PHI)
        Y = r * np.sin(THETA) * np.sin(PHI)
        Z = r * np.cos(THETA)
        
        # 波動関数を計算
        psi = hydrogen_orbital(r, THETA, PHI, n, l, m)
        
        # 確率密度(実部の符号で色分け)
        prob = np.abs(psi)**2
        phase = np.angle(psi)
        colors = np.real(psi)
        
        # 正負で色分け(vmin < vcenter < vmax を保証)
        vmin, vmax = colors.min(), colors.max()
        if vmin >= 0:
            vmin = -1e-10
        if vmax <= 0:
            vmax = 1e-10
        norm = mcolors.TwoSlopeNorm(vmin=vmin, vcenter=0, vmax=vmax)
        
        surf = ax.plot_surface(X, Y, Z, facecolors=plt.cm.RdBu(norm(colors)),
                              alpha=0.7 - i*0.2, shade=True, 
                              linewidth=0, antialiased=True)
    
    # 軸設定
    orbital_name = orbital_names.get((n, l, m), f'{n},{l},{m}')
    ax.set_title(f'{orbital_name} (n={n}, l={l}, m={m})', fontsize=12, fontweight='bold')
    ax.set_xlabel('x (a₀)')
    ax.set_ylabel('y (a₀)')
    ax.set_zlabel('z (a₀)')
    
    # 範囲を統一
    max_range = n**2 * a0 * 2
    ax.set_xlim(-max_range, max_range)
    ax.set_ylim(-max_range, max_range)
    ax.set_zlim(-max_range, max_range)
    
    # 視点を調整
    ax.view_init(elev=20, azim=45)
    
    # グリッドを薄く
    ax.grid(True, alpha=0.2)

plt.tight_layout()
plt.savefig('水素原子の電子軌道.png', dpi=300, bbox_inches='tight')
plt.show()

# 軌道の特徴を出力
print("=" * 60)
print("水素原子の電子軌道の特徴")
print("=" * 60)

for n, l, m in orbitals_to_plot:
    orbital_name = orbital_names.get((n, l, m), f'{n},{l},{m}')
    
    # 動径波動関数の最大値の位置(最も確率の高い半径)
    r_values = np.linspace(0.01, n**2 * a0 * 3, 1000)
    radial_prob = [radial_wave_function(r, n, l)**2 * r**2 for r in r_values]
    max_idx = np.argmax(radial_prob)
    r_max_prob = r_values[max_idx]
    
    print(f"\n{orbital_name}軌道:")
    print(f"  主量子数 n = {n}")
    print(f"  角運動量量子数 l = {l} ({'s' if l==0 else 'p' if l==1 else 'd' if l==2 else 'f'}軌道)")
    print(f"  磁気量子数 m = {m}")
    print(f"  最大確率密度の半径: {r_max_prob:.3f} a₀")
    print(f"  エネルギー準位: E_{n} = -13.6/{n}² = {-13.6/n**2:.3f} eV")

print("\n" + "=" * 60)
print("凡例:")
print("  赤色: 波動関数が正")
print("  青色: 波動関数が負")
print("  透明度: 外側ほど薄く表示")
print("=" * 60)

元ツイ主が理系なのか文系なのかわからないのですが、、数学的・物理的に正確な図を求める場合には、画像AIに頼るのではなく、いったんプログラムコードで正確に描画するほうが正しい図が得られるよ、という老婆心であります。

カテゴリー: 開発 | 数学的な問題について画像AIによる嘘を避ける方法 はコメントを受け付けていません

漫画村関連で「土管」米Cloudflareに賠償命令についての考察

この日経新聞のポストに関して、脊髄反射的に「土管が賠償責任を負うなんて」という意見が付いてるが、考え直したほうがよいです。この問題は単なるインフラ=土管として捉えているのではなくて、契約上「反社」としてわかっているところと契約をした上で、警告を無視して(米クラウドウェアじゃなくて日本営業所なのだろうけど)ずるずると契約し続けていた、というところが大きな問題です。

賠償金額は合計5億円(四社が各社1億2650万円)なので、ほぼ原告通りの金額が通ったと思われます。ただし、月間3億アクセスあることと海賊版の頒布という「幇助」が重なると、実際の被害額はさらに多かったはずですが、この場合「土管」のように見えるインフラ業者も敗訴する場合がある、というところが重要です。

今回の判決のその前に考慮する事柄

海賊版については、昨今の中国のあれこれも含めて、国内ならばなんとかなるものの国外に出てしまうと著作権の扱いが異なったりしてかなりややこしいです。このややこしいところを利用して「漫画村」のような海賊版配布サイトが発生したわけですが、その前提を踏まえておく必要があります。

  • 「漫画村」のような直接的な海賊版配布サイトとその主催者
  • 海賊版サイトの運営者と契約をしている、ホスティングサイト
  • 海賊版サイトに接続する中間通信業者(プロキシサーバー)
  • 海賊版サイトと契約する通信事業者

といういくつかのパターンがあります。このほかにも、海賊版サイトを裏で運営するための WEB サイトの請負業者や保守業者というものがあります。このあたりは、裁判沙汰にはなっていませんが、「反社条項」に照らし合わせると、芋づる式に警察に引っ張られる可能性があるので会社としては注意が必要です。

海賊版配布サイトとその主催者

まずは、海賊版配布サイトとその主催者は、あきらかに犯罪行為となるので、即捕まることになります。すでに刑事処罰を受けた人が出所しているぐらい時間が経っているので、犯罪であることはいまとなっては明らかなことです。ただし、判決として「懲役3年・罰金1,000万円」となるので、出版社等の想定被害総額(200億円程度と言われる)から見ると雀の涙ほどでしかありあません。これは民事訴訟で争うしかありません。

「漫画村」に関する損害賠償請求事件の判決言渡について | ニュースリリース | KADOKAWAグループ ポータルサイト https://group.kadokawa.co.jp/information/news_release/2024041801.html

これ、主催者に請求しても支払い能力がない(広告収入はあっただろうけど、果たしてそれが200億円に達するかわからない)ので、民事では 17 億円の賠償となっているようです。

ホスティングサイトの責任

現時点で「ホスティングサイト」の責任を問うときに、CDNのクラウドフレア社の件しかでてこないので、検証が難しいのですが、過去の例をみるとホスティングサイトにも責任があります。ホスティング会社の場合、コンテンツ業者との契約が発生しますがコンテンツの内容が問われることがあまりありませんでした。しかし、性的なコンテンツや反社的なコンテンツがあるとホスティング業者自体が廃業に追い込まれます。良い例としては FC2 があります。

企業コンプライアンスで次々と性的コンテンツ(静的ではないです)や違法動画を流すことをやめるホスティング業者が多くなっている中、 FC2 はそれらを野放しにしました。というか、経営的にコンテンツの内容を問わない、という形を貫きました。コンテンツの内容を問わないという点では「表現の自由」を支えることにはなるのでしょうが、違法コンテンツの配信をそのままにしておくという「犯罪幇助」に引っ掛かってしまいます。

FC2の法的責任:著作権侵害コンテンツを放置中!米国のDMCA(デジタルミレニアム著作権法)プラットフォーム責任の観点から整理|アメリカ移民ケニー小倉の裏ログ https://note.com/onoshin_digital/n/n816a97c3e878

なので、単なる「場」としてのホスティング業者であっても違法コンテンツの配信を野放しにするわけにはいかないのです。

中間通信業者の例

違法コンテンツは電子的な配信がなされるため直接ユーザーと繋がっているわけではありません。途中に中間通信業者(プロキシサーバー等)を通ります。これは、順法コンテンツだとしてもかわりません。

このあたりを KADOKAWA が規制しようとした事実がありますが、その規制自体は違法です。

発端としたは「漫画村」のサイトに繋がる経路(IPアドレス、DNSサーバー)を制限しようとする法案を国会で通そうとましたが、失敗しています。いわゆる DNS によるブロッキングです。
しかし、これは「通信の秘匿」という意味で違法であり、却下されています。たしかに違法である漫画村サイトに対して DNS ブロッキングを行えば一般ユーザーからは接続はできなくなります。しかし、この DNS ブロッキングの方式は、先の順法サイトへのブロッキングも可能になるという法的な問題が発生してしまいます。
漫画村のような違法サイトであるということを誰が判断するのか?という問題です。 

DNS ブロッキングが通ってしまうと、ときの政府の思惑で「通信の秘匿」が侵される危険性が高いです。実際、中国では金盾でブロッキングされているわけですから、技術的には可能ですよね。抜け道としては VPN で抜けてしまっているのですから、これも違法サイトだけブロックするわけにはいかないことは明白です。

「漫画村」ブロッキング――誰が、どんな経緯で動いたのか – Yahoo!ニュース https://news.yahoo.co.jp/feature/1039/

というわけで、単なるデータを媒介する形での中間通信業者は、この件に関しては違法性はありません。逆に警察や政府が DNS ブロッキングを要請してきたとしても跳ねのけるだけの法的根拠があるというわけです。
まあ、実際のところはどうなのかわかりませんが。NTT が動いてしまった具合ですから。いわゆるときの忖度ですよね。

海賊版サイトと契約する通信事業者

いわゆる「土管」=インフラ業者としてのクラウドフレア社のような場合はどうなるのか?というのが今回の判決です。まず、違法性の伝播としては、今回の反社と契約しているか否かにあります。当然のことながら契約書自体に反社条項が入っていれば、反社(この場合は漫画村の経営者)と契約を結ぶこと自体が違法です。
当初、クラウドフレア社は「違法な契約者かどうかがわからない」ことを主張してきましたが、これは出版社による再三の警告(あるいは通告?)により「違法性が高い」ことは認識されていたとみるでしょう。これを放置したことにより「犯罪の幇助」という判決に至ります。

だから、ある意味では契約時点ではわからないのは仕方がないです。実際に、契約した後に反社になるかもしれないので、契約時点あるいは契約後自体のそれは問われないはずです。しかし、契約している途中で客観的になんらかの形で反社としてわかった場合には、契約を見直すことをしなければいけません。これは、法的というよりも、今回の判決のように裁判に負けてしまうからです。会社として不味いですよね。

金額的にクラウドフレア社にとって5億円という金額は大したことはないでしょう。しかし、今後、コンテンツ業者が訴えた場合に、同じように敗訴になる可能性が高く、海賊版サイトとの契約の見直しが大量に発生する、というところがこの判決の影響になります。

さらなる波及として

おそらく、問題は Meta 等が広げてしまっている違法広告に訴訟が及ぶ可能性が高いです。Meta や Google は、違法広告をそのまま流しています。しかし、それは広告主の問題であって「土管」としての Meta や Google には責任がないという判断を各社がしていますが、これがひっくり返ります。反社であるとわかっていて契約をし続けた場合には、今回のクラウドフレア社のように敗訴する可能性が高くなります。ですから、Meta や Google は広告主と契約を結ぶ場合に、広告主が反社であるか否か、広告主が違法であることを警告された場合にそれに対処しなければいけないという義務(とリスク対処)が発生します。

実際のところ、ネット広告の出品は自動化されており、Meta や Google 自身がほとんど関与していません。「私は反社ではありません」のチェックボックスぐらいでしょう。逆に言えば、その関与していないことが今回の判決において問題になるわけで、次なるは違法広告の問題に発展するでしょうね。原告が誰になるかが微妙ではありますが、何かの集団訴訟にはなると思われます。

関連法案

この手の話は、電気通信事業法の第三号事業者とプロバイダ制限責任法の両方を把握しておきます。前者はホスティング等の通信事業者(仲介的に掲示板提供とかツイッターのようなミニブログとかも含まれる可能性あり)が守るべき義務と、後者は何か訴訟がおこったときに無限責任ではなく有限であるという意味で責任範囲を規定するものです。片方だけ知ってても片手落ちなので、両方知っておいてください。

電気通信事業法における第三号事業者とは?自社の分類を把握しよう! – オーリック・システムズ・ジャパン株式会社 https://www.auriq.co.jp/blog/kaiseidenki-daisango-category/

プロバイダ責任制限法とは|削除請求・開示請求わかりやすく解説 | 誹謗中傷弁護士相談Cafe https://www.fuhyo-bengoshicafe.com/bengoshicafe-260.html

カテゴリー: 開発 | 漫画村関連で「土管」米Cloudflareに賠償命令についての考察 はコメントを受け付けていません

チームを壊す “ブリリアントジャーク” には向き合わないほうがよい多数の理由

元ネタが消えてしまったので、ちょっとここに解説を書いておきます。

まず、ブリリアントジャーク(Brilliant Jerk)が「優秀だけれど協調性に欠け、組織に悪影響を及ぼす人物」という意味通りならば、できるだけ彼/彼女から避けてください、の一択です。Web で検索をすると「受け入れる」案がたくさんあるのですが、小規模のチームの問題ならばなおさらです。これは明確に “チーム殺し” via 「ピープルウェア」にあたるので、チーム自体が崩壊しかねません。なにがどのように優秀なのか? 目の前のチームが何を成し遂げようとしているのかをチームリーダーは見極めなければいけません。

元記事が大人の事情で消えてしまったので、状況だけを示しておきますが、

・アジャイル開発スクラムのメンバーである
・優秀なメンバーとして後から入ったが協調する気がまったくなかった

という場面です。そもそもアジャイル開発スクラムにおいてはチームメンバーの価値観の統一が最優先になります。これはスプリントと呼ばれる2週間の短期間のうちにプロジェクトの目標を次々と成し遂げないといけないために、まさしく “スクラム” を組み一丸となって進むことを示しています。たまにテック系の行動規範として「相手を尊重する」ことが入っているコミュニティを見かけますが、まさしくその通り、同じチームを組む以上チームメンバーを尊重することが必要です。これは、自分の意見を通すだけでなく相手の意見も聞くという意味も含めます。そのような意味でも、同じ価値観がなければ、チームで組むことはできないと他のメンバーも考えるし、スプリントの中で「徹夜」や「残業」などの嫌なことを乗り越えていくことができないでしょう。

そうなんです、アジャイル開発スクラムの場合は、メンバーの合意のもとでは「徹夜もします」ってのが条件だったりするんですよ、実は。

まあ、そんな訳でスクラムマスター(おそらくリーダー役?)が諭して直るパターンであれば、ブリリアントジャークというほどでもないし、ちょっとした勘違いテック野郎だったんじゃないですかね? という具合です。

では、どう対処するのか?の具体例を示しておきます。IT 業界で「優秀だけど嫌な奴」の筆頭といえば、リーナス・トーバルズ氏です。口が悪くて相手への態度も悪い、容赦がないので有名ですね。でも優秀です。Linux を作った人ですし、現在も Linux を現役で支えている人です。最近の業界ではないのですが、IT の黎明期ではこのような天才的な才能があれば、なんとでも行ける部分があるので、結構こういう人が多いです。ちなみに私はリーナス氏が好きか嫌いかというと、いやどちらでもないです。どちらでもない理由は後述しますが、無責任な話でいえば、そういう人も必要ではあるだろうなぁという話です。これも無責任ですが、同じく後で理由を話します。

これ、IT 業界に限らずクラシックの指揮者とか、映画監督とか、アニメとか漫画家とかいますよね。ひとりの才能が拡散されている業界はこの手の「ジャーク(嫌な奴)」でもやってける部分があります。でも、やっていけるのはそれなりに理由(本人ではなく業界としての理由)があるわけで、ひとまず構造的にやれるようにメンバーを組むというのがひとつの方法です。漫才あたりとかテレビ業界もそうですが、「売れればよい」といのがそれです。そのあたりは市場原理もあるので、否定しません。

チーム内のジャークをどう扱うか?

アジャイル開発スクラムではない場合は、なんとかなります。そもそも優秀なのだから(何を以って優秀というのかは明確にしておいてください)、その「優秀さ」を最大限生かせるようにチームを組み直します。いえ、ある意味でチームを解体します。

先に言ったようにジャークは優秀であろうとチーム殺しの一つなので、チームに取り入れてはいけません。しかし、なんらかの事情でチームに取り込まないといけないという状況になったと仮定しましょう。実際、そういう場面はいくつかあります。

・プロジェクトが炎上してしまって、外部からジャークを呼ばないといけない。
・レガシー開発をしていたジャークしか直せないバグが発生した
・社内政治のナントカ(社長の息子とか取引先の縁故とか)でジャークが入ってきた

のような場合は、どうしてもジャーク君を排除できません。これはもう仕方がないです。諦めましょう。このジャーク君にどう対処して、できるだけ早くジャーク君がいらない状況を作ってしまうのが先決です。メンバーの方が大切です。ジャーク君を育てることを考えてはいけません。まあ、三番目の縁故の場合は、ジャーク君に取り入ることも可能なのですが、それは別の話です。

炎上プロジェクトの助っ人やレガシー開発での助っ人みたいなジャーク君に対しては、もうこれは仕方がないので、マネージャが接待してください。この一手で十分です。いわゆる、バスケでいうところのマンツーマンですね。

・ジャーク君が素早く開発できる環境を、ジャーク君専用で整える
・ジャーク君は、朝のミーティングとかチーム内ルールを免除する
・ジャーク君の暴言がチームメンバに向かったら、すかさずマネージャが割り込む

という具合で、本来のチームを持ってください。それがマネージャの役割です。そして、ジャーク君にはさっさと仕事を終えて貰って出て行ってもらいましょう。育てるとかルールを守って貰うとか何とか考えてはいけません。ジャーク君は別の世界の人ですから、私達には関係ないのです。ジャーク君が作る恩恵だけを享受しましょう。それ以外は不要です。対抗しようとしてはいけません。限りなく受け流してください。

社内のジャークをどう扱うか?

どちらかというと、こっちのほうが問題です。Netflix のカルチャーメモにあるように会社としても「ブリリアントジャーク」を排除してしまうのがベストなのでしょうが、まあ、そうはいっても入社してしまったし、というのが日本的な風土の問題ですね。また、リーナス氏のような優秀な(とも言えないけど)人材が会社に入ってきたらどうでしょう? なかなか排除ってわけにもいかんでしょう、という心情はわかります。また、業界にもよっても違うわけで、クラシックの指揮者とか、アニメーションや映画の監督とか、舞台の役者とか、漫才師みたいなのは、真ん中のジャーク君を盛り立てて成り立っている業界的な構造もあるので外すことができません。つまり代替が効かないというパターンです。

ただし、このあたりの構造はダウンタウンの松本氏やフジテレビの問題やジャニーズの問題のように崩壊することが多いので、慎重に扱わねばなりません。ジャーク君は当然のことながら、素行が悪いだけでなく、法的なラインも自分中心に超えてくることが多いので、そのまま扱うと会社自体が崩壊しかねません。これは経営判断となるので取締役以上で決めることですね。一般的な会社員が決められることではありません。

それぞれの会社がどのようにジャーク君を扱うか、業界ごとに異なるでしょうから、ここでは IT 業界の会社の例に絞っておきましょう。

まず、小規模の会社(10人位とか)の場合は、もう駄目です。小規模の会社の場合は、社員=チームメンバーという形になってしまうので、先のスクラムチームと同じ状態になってしまいます。この場合は、社長自らがジャーク君と対峙するしかありません。あるいは、ジャーク君担当の取締役を付けるしかありません。まあ、小規模 IT 会社の場合は、社長そのものがジャーク君の場合が多いので、その場合は社員が逃げてしまうので大丈夫です。よほどジャーク君が優秀でなければ生き残ることができません。他社と付き合わないといけないわけですから、疑似的であれ表面的な協調性は必要ですよね。芸能界でいえば、マネージャを間に挟むところですが、IT 業界の場合そういうものはありませんので潰れてしまいます。リーナス氏の場合は、かなり例外的です。

問題は100人程度の中規模な会社です。会社としてはジャーク君の配属を変えることができるし、ジャーク君の「優秀」という恩恵だけを会社が受け取れる状態になります。迷惑なのは社員のほうですが、これはうまく会社のほうで対処しなくてはいけません。そうしないと次々と退職者が出てきてしまいます。会社として、新人をひとり入れるのに年収の 1/3 程度がかかります。少なくとも一人の退職者が出ると百万円レベルの損失を考えないといけません。ジャーク君が配属された部署からひとり退職者が出るたびに、ジャーク君のボーナスから百万円を差し引いてもよいぐらいです。それぐらいのダメージを覚悟してください。

というわけで、中規模の会社の場合は、ジャーク君に権限を与えないようにします。先の火消しのようにジャーク君を使い潰してください。そのたびに、太鼓持ち風のマネージャを付けて申し送りをすればよいのです。ジャーク君が改心するかどうかはわかりません。

会社としては、ジャーク君の「優秀」な部分を取り出して、別の会社に売ればよいので、それだけで十分です。まあ、それでも Netflix のように排除するほうがいいと思いますけどね。

さて、いわゆる大手 SIer の場合はどうでしょうか?

実はジャーク君は組織の中に一定数、ちらほらと確率的に存在します。中学校のクラスの中でいじめが発生するのと同じぐらいの確率で存在しますね。いわば、組織が進化する上の必要悪…というより、ちょっとした不可欠な要素という面もあります。学校の中のいじめの問題は別な対応が必要なのですが(クラスメンバーが平等という前提があるので)、大手会社の場合は別な方法がとれます。なぜならば、大人数の組織の中では、それなりに上下関係ができてしまうものですし、会社組織としては給与体系とかあり上下があるのが普通だからです。学校の平等とは違います。

だからといって、大手組織の中でジャーク君を放っておくことはできません。先のフジテレビの問題のようになってしまいます。権限を与えてしまうと、権限が権限を呼び、先行き会社を傾きかねない事態に陥ってしまいます。フジテレビの場合は、ジャーク君自体が社長になってしまったので、時代性もあり仕方がないですね、ってのとどうしようもないね、ってのが私からの視点ですが、IT 業界でもたまにありますね。

唯一のうまい方法としては、ジャーク君たちをひとつの部署に集めることです。

実は大手の会社となると確率的に複数名のジャーク君がいます。ジャーク君は弱肉強食の中で弱者に対していじわるなだけなので、ジャーク君達、つまりは複数名をひとつにまとめてしまってください。いわゆる特殊部隊というやつです。ジャーク君自身には権限を与えてはいけないので、タフなマネージャーを据えてください。マネージャはジャーク君に同情はしません。操るだけです。

なんか見たことがあるでしょう?「攻殻機動隊」の公安8課とかパトレーバーの特車二課とかいくつか思い浮かぶはずです。公安8課の部長なんて、ちょうどいい感じでできていますよね。あれ、物語自体はフィクションではありますが、心理描写や組織体系は現実から逃れられないので(リアリティを出すために) “部長” の立ち位置と言動が本物に近いです。もっとも、政治に近いところであれができるかどうか不明ですが(おそらくできないような気がしますが)、理想像はアレには違いありません。

ジャーク君達は、研究職やら R&D やらで頑張って頂けばいいのです。彼らは優秀なので徹夜だとか勤務時間は全然気にしません。当然勤務態度も悪いのですが、そこは特別部署なので御咎めなしです。ただし、成果は出さないといけないので、弱肉強食ですよね。はたして、ジャーク君チームに入りたいかどうかは、一般的にはわかりません。

もちろん、研究職や R&D チームでも礼儀正しく協調的にやるほうがいいのですが、会社に入ってしまったジャーク君たちをどう扱うかという話になるので、こういうパターンもできます、ということです。

退職を促す方法については、閑職に移すとか色々あるので訴えられない方法を選んでください。これは実情がいろいろ世の中にころがっています。

もう 20 年以上前になりますが、マーチン・ファウラー氏が XP 関係で来日したことがあります。彼の講演でよく覚えているのが「私達の世代では、技術力を盾にしてひとりでやることが多かったが、これからチームでの社会性や協調性が必要になってくると思う」という話でした。アジャイル開発の黎明期でもあり、個人的な開発力よりもチーム力が重んじられてきた時期です。それ以前では、プログラマが知識と腕力で犯罪スレスレでもあってもいいから技術力を磨いてのし上がってきたわけですが(ファウラー氏もそうみたいだし)、これからはそうではないです、というのを彼の娘を例にして話していたのが印象的です。

別に仕事なのですから、学校のときのように仲良しこよしでやる必要はありません。時には給与査定もあるのですから、競争することもあるでしょう。しかし、いまどき敢えてジャークである必要はありません。プロジェクトという目的があれば協力し、プロジェクトがなくなれば特に協調しなくてもよいのです。仕事ですから。

そういう意味で、例えばリーナス氏のようなジャーク君が会社にいて、とある部署で業績を上げていたとして(それがジャーク君チームの R&D だとして)、それをどう思うかといえば、無関係ですよね、自分に被害が及ばない範囲であれば、と私は思う訳です。モノホンのリーナス氏はよく知らないので、なんとも言えないんですよね。なので、ここはリーナス氏風のジャーク君がいたとしての仮定のお話です。

カテゴリー: 開発 | チームを壊す “ブリリアントジャーク” には向き合わないほうがよい多数の理由 はコメントを受け付けていません

Visual Studio 2026 と逆引きシリーズの関係

もうこんな重たい IDE を使わくてもいいだろう、という形なのか、名前が「Visual Studio」に戻った Visual Studio 2026 がリリースされました。

Windows、Mac、Linux 用の Visual Studio と VS Code のダウンロード https://visualstudio.microsoft.com/ja/downloads/

インストールした後にスタート画面で「2026」で検索しても出て来ないので、おかしいなぁと思ったら「Visual Studio」になっているという具合ですね。私の PC では互換用に 2019 と 2022 がインストールされているのですが、今回の 2026 は間に挟まっています。ちょっと見つけ辛い。

ちなみに、起動時にスプラッシュ画面やヘルプメニューからの「Visual Studio の登録」を見ると、きちんと “2026” の文字が入っているので区別が付きます。

たぶん、従来の Windows フォームとか ASP.NET Core MVC アプリとかを作っている間は以前と変わらないと思います。.NET が 10.0 なので昔のプロジェクトを開くときは、*.csproj を開いて変えてしまえばよいでしょう。

特筆すべきは、Visual Basic で iOS アプリが作れる(らしい)ことですね。本当に作れるのか不安なのですが、.MAUI ベースじゃなくて、Objective-C ベースを VB に直したコードをがテンプレートになっています。

なんなのですか!この魔改造っぽいプロジェクトはw

逆引きシリーズとの比較

ざっとですが、逆引きの C# 2022 のプロジェクトが Visual Studio 2026 で動作するか確認してみました。

『現場ですぐに使える! Visual C# 2022逆引き大全 500の極意』https://github.com/moonmile/gyakubiki-vcs2022

第1章から第17章までを開いてみる限り、ターゲットフレームワークを「.NET 6.0」から「.NET 10.0」に変更すれば ok です。サンプルコードでは、src 配下に global.json で .NET 6.0 固定にしてあるので、このファイルを削除してください。

第16章 モバイル環境の極意は古い MAUI を使っているので動かない可能性が大です。
第11章 データベース操作の極意 と 第17章 Excelの極意 は、ひとまず NuGet でライブラリを最新にしてください。多分、互換があって動くとは思うのですが、DB のほうはちょっと未検証です。

逆引きシリーズをどうしたものかと思っているのですが、実は 2022 のときにもうこれが最後だろうと思っていたので結構無茶な形で組み込んでいます。VB のほうは、自前のテンプレートを作ったりして無理矢理 C# に合わせたり、ライブラリ化して Android で動かしたりという感じです。
いや、さすがにひとりで1000ページは辛いので、これが最後という感じだった訳ですが。

その後、秀和システムが無くなって、シン・秀和システム…じゃなくて秀和システム新社になったわけですが、逆引きシリーズはどうるのだろう?と思っているのですが、今サイトを見ると ACCESS とかの逆引きが出ているので、続いてはいる模様です。

となると、ここは是非「Visual Basic で作る iOS アプリ」という誰に需要があるかわからない章を追加しないといけないわけで(Visual Basic の逆引きには先に書いた通り、無理矢理 .NET MAUI の章があります)、これを試さねばなりません。というわけで、ひと通り見たら、連絡を出しましょうか。
中味的には AI エージェントを入れてコードを追加して 2022 よりも盛ることは可能なんですよね。ページ数的にはもう一杯一杯だと思うので、ページに合わせて詰め込んでしまうか、コードを少し端折りめにするか。逆引きのコードは基本全文が載っているので、そのあたりは要相談で。

追記

確かに、VB のコードが iOS 上で動いています。SwiftUI は動かないようなので、従来型の storyboard 形式で書かないといけないのでなかなか敷居が高いですね。storyboard 形式は Xcode で作成するか、最近だと Copilot の Agent モードを使っても書いてくれます。
なかみはほぼ Objective-C のコードの引き写しになるので、従来の C# + Xamarin コードを知っている人ならば勘でなんとかなるだろう、とは思うのですが…これって、誰得なのか? そもそも、これを開発した Microsoft 社員は誰なのか? が非常に興味があるとこです。

ちなみに、ASP.NET Core MVC の VB テンプレートは入っていないので、これは自分で作らないといけません。むしろ、こっちのほうを MS さんは作って欲しかった !!!

カテゴリー: 開発 | Visual Studio 2026 と逆引きシリーズの関係 はコメントを受け付けていません

Z 世代が思う「人格まで否定されたと感じる経験」とは?

微妙にネタツイっぽい気がするのだが、レスのほうに「人格まで否定されたと感じる経験」がよくわからないという意見が多かったので、その部分だけ補足しておきます。

Z世代つまり2000年以降に生まれた世代が 25 歳になったわけで、ぼちぼちと就職してきます。大卒であれば 22 歳ぐらなので、ここ3年位から続いている訳です。なにも2000年からいきなり人類が切り替わったわけではないので幅があります。教育課程でいえば実はZ世代は、いわゆる「ゆとり世代」の後にくる世代になります。当時ゆとり教育が問題になって、円周率は3で計算するというのが話題になりました。小中学校での授業時間も減り、大学入学時までに習得する学習過程も大幅に減ってきたところです。しかし、学力低下がみられるところから一変して「ゆとり教育」を廃止して、授業数が多くなったのが Z 世代です。最近では土曜授業も月に1,2回行われるようになって、授業数は増えています。平日の授業も6,7 時間と増えているところもあります。

この平日の授業時間の増加は、昭和の世代からみても多いものです。これはゆとり教育の反省というよりも、現在義務教育で教えなければいけない要素が多くなってしまったということでしょう。様々な道徳教育や情報、理科にしても社会にしても以前よりも数多くの事実が体系化されるようになりました。中学校の教科書もページ数が多く、さらに副読本もついているので実に大変です。詰め込み部分も多くみられます。

そんななかで、大学の一芸入試や OA 入試とよばれる推薦入試が一般化してきました。これは高校入試でも同じで、中学のときの内申書(いわゆる五段階評価)に加えて技術家庭などの副教科を加えた内申の点数で推薦先を決めることが多いです。昭和世代だと、推薦入試なんてそう多くない人数だったと思うのですが(これは、出身中学や高校によるのでしょうが)、いまの中学校では、1/3 程度が推薦入試を受けます。つまり、試験一発で受かる一般入試は 2/3 程度の中学生しかいないということです。
推薦入試は、高校からすれば、素行の悪い学生を排除することができる良い制度ではありますが、推薦する人数が 1/3 ともなると、学力もたいしたことがないことが伺えます。平均よりもちょっと上程度の位なのですから、昭和世代のクラスで1人か2人程度の推薦枠どころではありません。

そうなると、先の内申書が問題になってきます。
本来ならば、内申書というのはある程度クリアできていればよいもの(極端に成績が悪い人を落とす)程度のものだったはずが、推薦入試(東京都では併願確約というのもあります)を通すために、普段の授業の点数を上げることに必死になってしまうのです。ただし、必死になるのは生徒ではなくて、教師側のほうです。
教師が生徒たちの内申をつけるために、授業の手を上げる回数だとか、グループ発表の点数だとか、遅刻の数だとか、クラブ活動の態度だとか、諸々の基準で数値化していきます。この評価が実に大変で、授業ごとに生徒が手をあげた回数&発表した回数を数えないといけないし、答える人も順番にあてないといけません(平均的に当てないと、親からクレームが来ます)。昭和の頃にも、教師が「内申をさげるぞ」と脅すことがたびたびあったのですが、それは推薦の子に限って。一般入試の子にはさほど響きません。しかし、現状のように 1/3 もの推薦(落ちる子も含めれば 1/2 に近い形で推薦入試を受けます)枠になってしまうと、「内申が落ちる」という脅しはかなりの人数で効いてきてしまうのです。

小学校のころに運動会で平等にとか学級会の話し合いでとかいう次の中学校でこんな具合なわけですから、それぞれの「人格」がどうというものは消え去ってしまいます。
もちろん、建前上、「個性」を重んじるようには見えますが、結局のところ推薦入試のために偏った細かすぎる評価基準のためにそれぞれの「個性」は見えない状態になり形骸化してしまいます。
それもあって、不登校の子も多いのです。クラスに1,2人は必ずいるという状態です。

そのような意味で「人格まで否定されて」という雰囲気が中学生時代にあり、それを経て高校・大学その後に就職というのが現在の Z 世代の現状です。否定されるというか、無視されてというか実に「個性」と「評価基準」との間を行き来しながら今に至っていると考えられます。
なので、最近の Z 世代は相手に対して実にきれいな敬語をつかいます。これは上司とかではなく、同期であっても敬語を使うし、最初からフレンドリーということはありません。勿論、新人教育の中で少しずつ慣れてくるのですが、そのあたりの「きれいな敬語」(私からみると場をわきまえない、TPOにそぐわない変な敬語)を使うのは Z 世代特有の、相手を傷つけない争いを起こさない、という下地あるいは防御本能から来るものと考えられます。

で、元ネタの「構造~」なんとかはさておき(ネタっぽいし)、この場合「遅刻前には連絡してね」で十分です。Z 世代は先に話したようにルールに厳格な人が多いので(まあ、その後の高校によったり、性格によるものがあるでしょうが)、IT に限って言えば、生真面目過ぎるのが難点なぐらいです。

サイトを見るとわかりますが、アフリサイトなので御察しですね。


カテゴリー: 開発 | Z 世代が思う「人格まで否定されたと感じる経験」とは? はコメントを受け付けていません

C/C++ の文字列終端と Delphi の文字列の扱いが異なるので転生に失敗する世界線

某所で失敗したのは3日間ほどなのですが、これ意外と知られていないので流しておきます。
以前、会社にいたころに XML-DB を扱う自社製品があって、それにアクセスする I/F を作っていました。外部的には Java ライブラリを使ってアクセスするのですが、ちょっと事情があって内部的にアクセスするライブラリを C/C++ で開発することになったのです。

で、その XML-DB がですね、実は Delphi で作られていたのです!!!
いまだと Delphi という名はあまり知られていないものの 30 年近く前には、意外とメジャーな言語でした。ググると分かるのですが、Delphi のベースは Pascal です。もともと Pascal は教育言語として開発されたものなのですが、それを実用化したのが Delphi というわけです(当時は Borland 社が開発・販売していて、名前は違うのですが、ここでは Delphi に統一しておきます)。

今だと何故に Pascal 言語が? と思うかもしれませんが、まだ Java も広がっていなくて C# も出ていない時代です。Windows アプリケーションを組むとなると VC++ でがりがり組むか、Visual Basic 6.0 で GUI を組むかという時代です。
当時、クラスライブラリが乏しくて、C++ だと XML をパースするのに Xerces などの外部ライブラリを使う必要がありました。で、VB6.0 の場合は GUI は簡単に組めるのですが、この手のロジックあたりが弱くて、そういう場合は仕方がなく VC++ で組むことになります。
まあ、当時の VC++ は GUI の開発環境が貧弱で MFC のライブラリ以前だったり、その後に出てきた MFC も使いづらかったりしたのですが、そこで登場したのが Delphi だったのです。VCL と言う GUI ライブラリがあってですね、それが広く使われていたのです。
で、今で言えば科学計算を学ぶには Python が一番!!! というように、Windows アプリケーションを組むならば Delphi!!! という時代があったわけです。皆さん、わざわざ Pascal 言語を学んでいたのですね。すごい。

そういう経緯があって、ちょっと先進的な GUI だったり、ちょっと気の利いたライブラリだったりは Delphi で作られていることが多かった時代があるので、ちょっと優秀なプログラマが XML-DB を組むときに Delphi で組むのも不思議ではなかった時代があったのです。

で、悲劇はその後に起こります。

その後 Microsoft が VC++ を改良して、MFC というクラスライブラリを充実させていきました。先に書いた Xerces などのライブラリも C/C++ から使えるようになってきました。MFC のボリュームが VCL に近づき、会社の規模から見て VCL を凌駕していったわけです。

そうなると、開発者のボリュームとして、Delphi を使う人が減少してきました。VC++ の GUI 環境が整うにつれて、VB6.0 からも VC++ に流れて来たのです。最終的には C# や VB.NET に移っていくわけですが、その間に VC++ で書かれた Windows アプリケーションのコードがたくさんあります。

その時点で起こる現象として、Delphi で作られた XML-DB のライブラリを C/C++ で呼び出すことになります。つまり、遺産をうまく使っていこうという発想です。

そんな状況で Pascal を知らない C/C++ プログラマ(つまり私)が移植担当になって、調べていくとですね、あれ? 文字列の呼び出しが変? ということになります。

ご存じの通り、C/C++ の文字列の終端は NULL 文字(’\0’)になっています。

C 言語

char str[] = "Hello";

この場合、str は ‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’ という文字列になります。

ってな具合に Copilot に書いてもらうくらい簡単なものです。
じゃあ、Delphi の場合は? というと、Delphi の文字列は長さ情報を持っているのです。つまり、文字列の先頭に長さ情報が入っているわけです。

Pascal

var str: string;
str := 'Hello';

この場合、str は長さ 5 の情報と ‘H’, ‘e’, ‘l’, ‘l’, ‘o’ という文字列になります。

Pascal の場合には、NULL 終端ではなくて、長さ情報が先頭に入っているわけですね。

C 言語的に言えば

  • str[0] が文字列の先頭
  • str[-4] が文字列の長さ(4 バイト整数)

ってわけですよ。

えええ!!! 配列をマイナスにしていいのかい???

ってくらいです。C/C++ プログラマにとっては。

文字列よりも前に何かメモリが必要ってのは不思議でもありますが、ASN.1 の規約を知っていれば不思議じゃないもので(これもググってください)、規約として先頭に文字列の長さを入れることがあります。

Java や C# だと string クラスを使うのが普通ですが、C/C++ や Pascal だと文字列は配列なので、こういうことが起こるわけです。まあ、正確に言えば、配列に埋めているだけなので、ASCII なのか、Unicode なのか、UTF-8 なのか、UTF-16 なのかで終端も変わってくるんですけどね。特に Unicode の場合には wchar_t 型を使うので、2 バイトの NULL 終端になります。これも 1 バイト終端と間違えてバグる可能性大です。

C/C++ と Delphi の文字列の扱いや配列の扱いが異なるので、これを相互変換しなければなりません。さらに、この手の情報をファイルに落としたり、メモリで一括で扱うときには、NULL 終端の場合は 1 バイトなんですが、長さ情報は 4 バイト使っている !!! ってことになり、バイナリデータの扱いも変わってしまうのです。

Delphi でバイナリデータを作って C 言語で読む場合にはちょっと面倒なことになります。
配列とかすべて再定義しないといけないですからね、もう大変ですよ。

そんなわけで、当時はまだ Delphi の名残が残っていたので、まあなんとか文字列終端の違いに気が付いたものですが、さらに 30 年程経ってしまうとですね。

化石的な Delphi ライブラリが残っていて、これに遭遇するわけです。
Java でアクセスするとか、C# でアクセスするとかの問題ではありません。

なにこれ、変? なんなのこれ???

と3日間ほど悩んでも仕方がないところです。

と、まあ、このあたりは私の想像なので、実際のところはよくわかりませんが、そのあたりが垣間見れてしまったので、ちょっと面白かったです、って話です。自分のことだときついのですが、所詮、他人事ですから。ははははははは、はぁ、お疲れ様です。

カテゴリー: 開発 | C/C++ の文字列終端と Delphi の文字列の扱いが異なるので転生に失敗する世界線 はコメントを受け付けていません

生成 AI によるカクヨム小説の自動作成の解説

最初に断っておくと、この手の生成 AI による小説書きについては是でも否でもありません。先の小説の解説を見れば AI で書いてあることは明白であるし、その戦略を明示されていて、アンフェアな感じはしません。YouTube で F5 キーを押して回転数を稼いでいるわけでもないし、偽装メールアドレスを使って ☆ を使って稼いでるわけでもなさそうなので、これはこれでよいのでしょう。

実際「数で稼ぐための創作論」という形で、カクヨムの数(多分、ランキングに上がるための☆の数)を稼ぐための手法としては、非常に有効な手段であると思います。

ただし、数を稼いだからと言って、商業デビューできるとは限らないのですが、ここでは☆の数だけに注目してみます。

ハーレクインロマンスというジャンル

AI に小説を書かせるときには、登場人物やある舞台背景を設定します。当該の異世界転生の令嬢という話であるならば、そこそこの設定を書けば十分です。できるだけ、現在の流行りの設定を書くのがよいでしょう。

昔(いまでもですが)、ハーレクインロマンスというジャンルがありました。ハーレクインロマンスは、アメリカのロマンス小説の一ジャンルで、女性向けに書かれた恋愛小説です。特徴としては、裕福で魅力的な男性と普通の女性が出会い、恋愛関係に発展するというストーリーが多いことです。登場人物は典型的なキャラクターであり、男性は強くて保護者的であり、女性は魅力的で感情豊かです。物語はしばしばドラマチックで、感情的な葛藤や障害を乗り越えることがテーマとなっています…という筋書きがあらかじめ決まっています。この解説文も Copilot の拾ってきたもので、Copilot 自身もよくハーレクインロマンスの構造がわかっています。

ハーレクインでは、導入部分がどうなるのか、展開がどうなるのかというページ数がほぼ決まっています。当時は、AI というモノがなかったので、ゴーストライターがたくさん集まって、次々と似たような小説を出しています。いわゆる、昼メロのドラマの視聴者をターゲットにしたアメリカの小説ですね。もう、40年程前からあるものなので、家庭の主婦を対象にしています。そして、毎回同じメロドラマが繰り返されるのです。

これ、面白いかと言うと、まあ、1冊だとそこそこ読めるようにできているのですが、5冊ほど買って読んでみてください。できれば、同時並行で読むのがお勧めです。同時並行で読むと、登場人物たちが、どのように恋愛をして、どの部分で何かの事件に巻き込まれるのか(ちょっと覚えていないので、事件があったかどうか定かではないのですが)、どのように解決してロマンスに陥っていくのかが、ページ数で決まっているのです。だから、どんな小説家、というかライターが書いても似たような小説ができます。構成にあわせた、量産品小説ができるのです。

この作戦は、なにもハーレクインに限ったものではありません。雑誌のゼクシィやバイク雑誌、フランス書房なども似た感じで作っています。私が好きだったのは 30 年前のティーンエイジャー小説なのですが、これは学園もので、ちょうど現在の異世界転生の学園ものに近い感じです。アメリカ高校生のダンスパーティのシーンがあったり、生徒会が出てきたりします。これも定番で、どの本を読んでも似たようにダンスパーティと生徒会が出てきます。まあ、3,4冊で飽きてしまうのですが、暇つぶしにはいいです。たしか、ハヤカワ文庫であったはずなのですが、今は見当たりません。これは、当時、各出版社が作っていて、結構シリーズ化されたんですよね。漫画でいえば渡辺多恵子の「ファミリー!」が近いです。「ファミリー!」自体は量産品ではないのですが、このようなスクール生活中心の物語が、ハーレクインのように繰り返し出版されていました。たしか、中高生が漫画しか読まなくなって、小説が激減した時期で、それを盛り返そうとしてアメリカの青春小説を輸入しはじめたのが発端だと思うのですが、まあ、すぐに廃れました。SF が売れない時期で、ハヤカワもこんなのに手を出したのか、と思った次第です。まあ、その後 SF が復興したんですけどね。

そういう意味では、異世界転生のラノベブームも似たようなものですが、異世界転生の場合は設定が多様化していることと、意図的に似せてはこなかった、むしろ設定を変えて差別化してきたところに特徴があります。

量産するという占い方式

ところがですね、「数で稼ぐ~」の展開としては、これを意図的に逆にしています。

つまりは、ハーレクイーンの時代に戻して、構成を同じにしたわけですね。

さらに、カクヨムの特性として、新作リストがトップページ等に出ることを使って、似たような設定でたくさんの連載小説を AI で作るようにしました。つまり、量産したうちの 1 本が当たればよいというスタイルです。これは「占い方式」で、相談者に適当に YES/NO で答えて、YES で当たっていた方だけを残していく方式です。たくさんの同型の小説をアップしておいて、当たりだけを残せばいいのです。Web テストの A/B テストみたいな感じです。

作者のページを見ると同時並行的に10本以上の連載小説が並んでいます。どうやら、日に38本位を同時にアップしているそうなので、新作のリストが埋まってしまうという苦情も寄せられています。

人が書いた場合にはさすがに 38 本も同時には書けないのですが、生成 AI では難しくはありません。ただし、人が内容を確認するとスピードが遅くなってしまうので、内容はほぼ確認していないと思われます。

そんな中で今回は、そのうちの1本がヒットして、総合ランキングの1位になったわけです。おそらく、たびたびジャンル別のランクには上がっていたと思うのですが(過去の☆を見ると、取れそうな感じはするので)、今回話題になったのは「総合1位」という話題性でしょう。

自動生成されているので、小説の中身は問いません。

ただし、小説を読んで☆を付けている人がいるわけで、それが人の書いた小説よりもランクが上になったという事実がここにあります。

まあ、作戦的には「AI で量産する」という人間業では無理ということをやっているので、多少反則な気もしますが、それは、将棋 AI が人間に勝った、みたいなものです。まあ、読者は人間なので、判断的にも人間が凌駕したともいえます。

自動生成の実践

仕掛けがわかったところで、実践をしてみましょう。

私自身は、AI による自動小説はあまり興味がないのですが、実験的にやります。以前、まだ ChatGPT 4 あたりが出たばっかりのころに設定を使って書いてみたのですが、あまり面白いものはできませんでした。最近では、結構、キャラ付けをすると面白いことができます。

文体に関しては、例えば「村上春樹風に」とか「星新一風に」とか「夏目漱石風に」とか結構できます。今回は「庄司薫風に」してみましょう。庄司薫は「あかずきんちゃん気を付けて」などを書いた芥川賞作家です。青春小説の走りみたいな形で、薫くんシリーズは 4 冊しか出ていないのですが、当時はエポックメイキング的なところがあって、誰もが教科書的に読んだものです。

時代は大学の学生運動の頃なのですが、皆が血気さかんな時期に自制して思考することを優先した青年の話ですね。いわゆる、学生運動や当時の社会思想的な小説家たちが「行動すること」を中心とした時代へのアンチテーゼみたいなものです。

手順としては、以下のように作っています。構成については、あえて、総合1位のものをパクってきています。これは、どの小説でも構いません。

1. 曲がり角でぶつかった少女に回復魔法を使ったら不治の病と盲目なのを治してしまってめちゃくちゃ懐かれてた(夏見ナイ) – カクヨム https://kakuyomu.jp/works/822139837599758883 から、全話を抜き出します。
2. NotebookLM に突っ込んで、マインドマップを作ります。
3. 登場人物のリストを抜き出します。
4. 設定や舞台背景を抜き出します。
5. 大まかな事件を抜き出します。
6. これらを元にして、SF 風に ChatGPT に仕立てて貰います。
7. 生成された文章を、さらに ChatGPT に庄司薫風に直して貰います。

※ 登場人物の名前は著者に敬意を示すために、そのまま残してあります。
※ AI 生成そのままなので、著作権はないんですけどね。すこし手直しすると、著作権が発生します。

できあがった、小説と途中の markdown ファイルは、NotebookLM https://notebooklm.google.com/notebook/9508ee51-4a21-42d4-bf6c-856cfc9274aa に共有しておきます。

ハーレクイーンのようにバリエーションを付ける場合は、SF的展開.md のように、古代風とか中世風とかで作ってください。事件もろもろは、適当に追加すれば ChatGPT が整合性をあわせてくれます。おすすめはしませんが「数で稼ぐ~」のようにカクヨムにアップしてもいいのですが、これは自己責任でお願いします。

これ、実験的には面白い試みではあるのですが、小説的に面白いかどうかは別ですね。

さらに、商業的にデビューを目指すのであれば、全面的な AI 生成はやめておいたほうがいいと思います。文章力がつかないし、構成力も借り物にしかならないので結果的に面倒くさいです。ただし、将棋 AI のように、論理的に突き進む場合(誤字がないとか、構成的な矛盾が出ないとか)は、AI のほうが向いています。私としては、AI とのペアプロというかペアで執筆がお勧めです。誤字とか構成チェックに AI を使うとか、ところどころの定型文で AI に書いて貰うとかしたらよいでしょう。

余談ですが、LLM のモデルとしてカクヨムの 100 万本の小説が抜き出されて、それを活用して、という噂話があるんですが、これは本当かどうかはわかりません。

そのモデルを使えば、確かにカクヨム読者に特化した文体と中身が出来そうな気もするのですが、先に書いたように「量産して1本だけ当たった」状態なので、あまり意味がないです。この場合、量産して全てを当てるか、1本だけ書いて1本当てる、パターンで使うのが正しいので、今回のように10本以上の連載のうちに 1本だけ当たったというのは、確率的に質が悪いです。

それに以下の ChatGPT に書いて貰ったものを見ると分かるのですが、いまの GPT5 だと、結構書けるんですよね。こうなると、わざわざカクヨムの小説を学習させる必要もないような気がします。

以下は、自動作成した小説の第1章をサンプル的に

第1章 転移とユウキの静かな願い

帝都の夜って、星が負けるんだよな(いい勝負する日もあるけど)。二つの衛星が雲の切れ目からのぞいて、軌道リングを牛乳みたいに縁取っている。俺は六畳ちょいのモジュールで、ぬるい合成コーヒーをすすっていた。重力は薄い、眠気は濃い、みたいな感じで。

俺――ユウキ・アスカワ。前世は日本の社畜で、定時は神話、終電は日常、っていう生活。で、ある晩に限って紙を拾おうと屈んだら視界が暗転した。ありがちな黒い画面のあと、あんまりありがたくない白い部屋。青白いイケメンがポテチ食べながら言うわけだ。「願いは?」って(そんな軽いテンションで訊く?)。

「穏やかに暮らしたい」。はい、反射で出た。戦わない、目立たない、誰にも使われない。要するに、静かで、勝手で、ちょっと疲れてる人の願い。彼は肩をすくめて、電子ノイズっぽい声で「加護を授与。生体ナノ群体、管理権限付与。君の手は癒やしの光になる」とか言う。いや、それ、穏やか要素どこ。

目を開けたら天井は白くなくて、金属と消毒薬の匂いがした。帝都軌道ハビタットの医療区画。手のひらに意識を寄せると、そこに“ざわめき”がある。見えない粒が、命令待ちの兵隊みたいに。恐る恐る擦り傷に触れると、金の粉塵みたいに光って、熱で皮膚が縫われた。

「……派手すぎ」

安堵より先に、それ。黄金って、とにかく目立つ。目立つって、つまり危険(この帝国では特に)。生体ナノ群体は軍事と政治のど真ん中に置かれる技術だし、俺が誰かの“所有物”になる可能性なんか想像しただけで、前世の偏頭痛が後頭部でうずく。

だから、決めた。——誰も見てないところでしか使わない。小さな傷だけ。血も涙も避ける。黄金は俺のためだけ。以上。

退院して渡されたのは、身分コード、住所モジュール、星港補給デッキの軽作業の紹介。帝国は新参者をいきなり実験台にしない(少なくとも表向きは)。俺は無表情の練習をして、荷役に混じった。

補給デッキは帝都の胃袋だ。肉、穀物、機械部品、誰かの手紙。コンテナはどれも金属の匂いがして、フォークリフトのホイールとマニピュレータの油が静かに歌う。遠心重力のわずかな傾きが足裏を撫で、時々、貴族仕様の白いコートが視界を横切る(襟の紋章で家柄が読めるの、何回見ても慣れない)。

俺は端っこで暮らす方法を覚えた。朝はドックの冷気、昼は肉屋の親父の端肉、夜は薄重力の部屋で旧地球の音楽を小さく。

「兄ちゃん、また端っこでいいのかい」

肉屋の親父は、俺の好み(脂多め)を勝手に覚えるタイプ。太い腕、笑うと目尻が消える。店はプロムナード寄りで、貴族も庶民も肉の前では平等に真剣だ。

「端っこが一番うまいんですよ」

「そういうの、わかる口だ」

冗談を返せるくらいには、暮らしが体に馴染んできた。手のひらの群体は賢くて、命令の粒度を落とせば光は抑えられる。小さな裂傷なら、皮膚の色がほんの少し温むくらい。誰も気づかない。俺は“傷を作らない”歩き方も練習した(これが意外と難しい)。

……でも、目を逸らせない時ってある。夕方、補給デッキの影で小さく泣く声。膝を破いた少年。血が透明フィルムに貼りついて、見てるだけで痛い。

「大丈夫か」

しゃがんで、手のひらをかざす。閾値は最低。発光はゼロ寄り。空気がほんの少し金色に濁って、痛みがほどける。

「……あれ、痛くない」

「気のせい。よくある」

立ち上がると、少年の目が一瞬だけ大きくなって、すぐ普通に戻る。礼を言って走っていく背中を見送りながら、俺は手を見る。光はない。昼夜サイクルは、少しだけ夕方へ傾いた。

目立たない。目立たない。目立たない。これは呪文。前世で生き延びた術が、今世でも通用するかのテスト(合格してほしい)。

ハビタットは巨大な円環都市で、内側に人工の空と木々、外側に星と軍艦。帰り道はいつも同じ。正面エスカレータは使わない。螺旋のメンテ階段、広告が少ない側道。世界から半歩浮いて歩くと、なぜか安心する。

その頃から、星港の“噂”が耳に入ってきた。近衛艦隊司令の一人娘――シルフィード公爵家の令嬢が、長らく神経インターフェース不全で視覚補助が効かない、とか。帝都医療局総出でも原因不明、とか。噂ってのは、たいてい最初の一文で充分。残りは聞かない(関わる未来、想像したくない)。

続きに興味があれば https://notebooklm.google.com/notebook/9508ee51-4a21-42d4-bf6c-856cfc9274aa を見てください。

補足 2025/11/01

AI 作家による大量投稿によって、新着リストが埋まるのでは? という懸念が X に上がっていますが、実際にはそんなことにはならないです。例えば、以下はカクヨムの「異世界ファンタジー」の新着リストになります。
このリストの新着時刻を見ると、

  • 2025年11月1日 11:22
  • 2025年11月1日 11:16
  • 2025年11月1日 11:14
  • 2025年11月1日 11:11
  • 2025年11月1日 11:11

のように、10分間以内にも数件上がってくる様子で、1時間もあれば新着リストが一巡してしまう勢いです。しかも筆者は別々になった状態です。

つまりは、既にカクヨムの新着投稿では1時間で一巡するぐらいの流量があるので、AI 作家がちょっとやそっと入れたところで新着投稿のリストを埋めることはできません。もし、AI 作家が 1時間に1回以上の投稿をすればリストに載る程度のもので、埋めようと思うならば、1時間に40本位は上げないとリストは埋まらないでしょう。つまり、実質としてはひとりの AI 作家がリストを埋めるのは無理です。
もちろん、AI 作家が 10 人位でてきて、同じように 1 時間に 2,3 本ペースで up していったとしたら、新着リストは「複数の AI 作家」によって埋まってしまうかもしれませんが、それは、そのときになったときに判断すれば良いでしょう。少なくとも、運営側が判断する話です。現在のところ、傾向としては 1 人の AI 作家なので問題は少ない。しかも AI 作家だとしても、1 時間に 1 回程度の投稿であれば(24時間であれば 1 日 24 本まで投稿が可能です)、特に新着リストを荒らすことはありません。十分、許容できる範囲と思われます。

もちろん、それは実際に作家になりたい投稿者と☆の数だけが欲しい投稿者との混在になってしまうのですが、現状でも似たような感じなので、そこは AI 作家の問題とは異なるものです。

まあ、個人的に言えば、「あ、これ面白い」と思ったものが AI で書かれていたものだとしたら、ちょっと鼻白みますね。AI を活用して書いたのならばいいけど、全面的に AI に頼っているものを読むのは騙された感じがするので、二度と読まないと思います。

追記 2025/11/14

カクヨムから声明がでました。生成 AI に対してという訳ではないですが、過度な頻度での投稿の禁止です。

過度な頻度で作品やエピソードを投稿する行為はお控えください – カクヨムからのお知らせ https://kakuyomu.jp/info/entry/2025/11/13/170248

AI からの自動生成は禁止しないけど、あまり極端なのはやめてね、という具合ですね。当該のアカウントは BAN されていはないので、OK なようです。毎日更新は続けているので、それはそれで良いのかなぁと。

カテゴリー: 開発 | 生成 AI によるカクヨム小説の自動作成の解説 はコメントを受け付けていません