💯

スマホ一台でAI採点まで出来る「応用情報技術者試験」過去問演習サイトを作った

に公開

はじめに

...応用情報技術者試験の午後試験の過去問演習ってめんどくさくないか?!

と思ったのは私だけだろうか?私の嘆きを聞いていただきたい。IPAの高度試験や応用情報技術者の過去問演習にはめんどくさいポイントがいくつかあると思っている。

  • 解説がない
  • 本が重い
  • 書き込み問題が解けない
  • スマホ一台で完結して過去問演習ができない

基本的に勉強とは問題を解く→解説を見る→へぇってなるの繰り返しだと思っている。もちろんただひたすらに教科書みたいなのを読む勉強もあるが、こと資格試験の過去問演習ではこのループの繰り返しであることに大きな異論のある方はいないだろう。

このループで大事な「解説を見る」という行為をできないのが、IPAの午後試験の過去問演習だと思っている。IPA公式が出している過去問PDFでは全く解説など載っていないし、我らが過去問道場さんでもまだ手が回っていないようだ。

過去問道場午後問題の解説

では本で勉強すればいいじゃないか。本ならば解説が載っているだろうと。そう思われる方もいるだろう。なるほど道理だ。では例えば紙の本を買ったとする。上述したように重い。私がしたいのは筋トレではなく、過去問演習だ。と誰に主張するでもなく叫びたくなる。

では電子書籍ならいいではないか。スマホ一台で済むし、軽いじゃないか。そう思っていた時期が私にもあった。それはまやかしだ。電子書籍では書き込み問題に対応できないのだ。

書き込み問題とはこういうものだ。線を付け足して完成させなさいみたいな定番の問題である。

応用情報技術者試験の午後試験の書き込み問題

読者諸君がどの電子書籍リーダーを使っているかとんと見当もつかぬが、少なくとも私が使っている電子書籍リーダーは書き込みができない。書き込み問題だけでなく、他の普通の問題もメモ帳に解くなどせねば、過去問演習ができない。

こういった理由から私はスマホ一台で応用情報技術者試験の午後問題の過去問演習をしたいと常々思っているのだ。だがただ思っているだけでは何も叶わぬのは世の常。

「求めよ、さらば与えられん」

そんな世の中だったらどれだけ良かったか。悲しいかなぴよぴよ鳴いていれば、親鳥が餌を運んできてくれるような甘い現実は存在しないのだ。

ながす) では作るか

と思って作り上げたのがこの過去問記述ラボだ!

https://www.kakomon-lab.jp/

この記事では

  • どういうサービスか
  • 技術構成はどうしたか
  • 実装のこだわり・苦労したこと・工夫したこと

あたりを書いていこうと思っている。単なるサービス紹介ではなく、何か読者諸君の身になればと思って書いているので是非読んでいってくれると嬉しい。

恥ずかしながら、人並みの承認欲求も持ち合わせているのでいいねボタンもポチッと押してくれると私が非常に喜ぶ。

またQiitaでも同様の記事を書いているが、大幅にリライトして実験している。どちらの文体の方が好まれるだろうかという実験である。私としてはこちらの方が書いていて楽なのだが、読むとなると少々堅苦しいだろう。読者諸君の反応によって今後の文体を決めようと思う。

なので「同じの投稿してんじゃねぇ」という誹りはやめてほしい。いや...ほぼ同じ内容を投稿しているので、甘んじて受け入れようとは思うが、労力はかけて多少内容を変えているので許して欲しい。推敲版だと思ってもらえれば。

https://qiita.com/nagasunari/items/6934369c178bb8c15474

過去問記述ラボの概要

まずはサービス概要を説明していく。技術構成から入っても良いのだが、どういうものを作ったかの後に説明された方がわかりやすいだろうという配慮だ。要らぬ世話だという人は飛ばすのが良いだろう。

個人的には結構いいサービスができたと思っている。他の誰が使わなくとも私だけは使い続けると思ってくらいには気に入っているし、便利だ。自分のために作ったものだから、別段使ってもらわなくとも構わないとさえ思っている。ただこんな便利なものを一人で使うのも勿体なかろうという思いで公表している。

過去問記述ラボの目的

スマホ一台で応用情報技術者試験の午後問題の過去問演習をできるようにすることが至上目的である。これを解決できなかったら、そもそもこのサービスの存在意義がない部分である。

またそれ以外の達成したい目的としてさらに効率的に過去問演習ができるようにするという目的もある。スマホ一台で過去問演習できたとて、苦しかったら意味がない。効率的に勉強したい分だけ勉強できるようにする方が良い。

過去問記述ラボの機能

目的を達成するため、過去問記述ラボにつけたメイン機能は2つだ。そのほかにもこだわりは多くあるのだが、あまりに長すぎると読む気をなくすだろうから、今回はこの2つに絞って紹介していく。

  • 書き込み問題への対応
  • AI採点の導入

書き込み問題への対応

応用情報技術者試験の午後の書き込み問題
応用情報技術者試験の午後の書き込み問題の書き込み後

画像のように書き込み問題では、スマホの画面を指でなぞると赤い線を書き込むことができる。
HTMLのcanvasを使って実現しているが、当方に全く知識がなかったので、

ながす) うわぁ...JSでなんかゴリゴリ書かないと線を描くとかできなさそうだなぁ...

とか思っていたが、HTML様様だ。御神酒でも捧げれば喜んでもらえるだろうか?結構昔から機能自体はあったらしい。私の無知を晒しただけだが、便利な機能がHTMLに実装されていて非常に助かる。実装に携わった多くの人たちに感謝を。

長いので畳むが、こんなコードで実装してみた。こうやってみるとリファクタリングできそうな箇所がいくつかあって非常に恥ずかしい。だが、あとで直すと心に決めて恥を晒そうと思う。私は拙速を尊ぶ。

canvasのコード
"use client";

import { Button } from "@heroui/button";
import type React from "react";
import { useCallback, useEffect, useRef, useState } from "react";

interface Coordinate {
	x: number;
	y: number;
}

interface DrawingPath {
	points: Coordinate[];
	color: string;
	size: number;
}

type CanvasProps = {
	originalImageUrl: string;
	imageUrl: string;
	aspectRatio: number;
	onSave: (dataUrl: string) => void;
};

const Canvas: React.FC<CanvasProps> = ({
	originalImageUrl,
	imageUrl,
	aspectRatio,
	onSave,
}) => {
	const canvasRef = useRef<HTMLCanvasElement>(null);
	const imageRef = useRef<HTMLImageElement | null>(null);

	const [isDrawing, setIsDrawing] = useState<boolean>(false);
	const [, setDrawingPaths] = useState<DrawingPath[]>([]);

	const currentColor = "#ff0000"; // ブラシ色
	const brushSize = 2; // ブラシサイズ

	// キャンバスの初期化
	const setupCanvas = useCallback(
		(srcUrl?: string): void => {
			const canvas = canvasRef.current;
			if (!canvas) return;
			const ctx = canvas.getContext("2d");
			if (!ctx) return;

			const dpr = window.devicePixelRatio || 1;

			// 横幅基準でサイズ決定(例: 最大600pxに)
			const displayWidth = Math.min(window.innerWidth, 600);
			const displayHeight = displayWidth / aspectRatio;

			// ピクセル密度を考慮したcanvasサイズ
			canvas.width = displayWidth * dpr;
			canvas.height = displayHeight * dpr;

			// 見た目サイズはCSSで
			canvas.style.width = `${displayWidth}px`;
			canvas.style.height = `${displayHeight}px`;

			// スケーリング(リセットしてからスケール)
			ctx.setTransform(1, 0, 0, 1, 0, 0);
			ctx.scale(dpr, dpr);

			const img = new Image();
			img.crossOrigin = "anonymous";
			img.onload = (): void => {
				ctx.drawImage(img, 0, 0, displayWidth, displayHeight);
				imageRef.current = img;
			};
			img.src = srcUrl || imageUrl;
		},
		[imageUrl, aspectRatio],
	);

	useEffect(() => {
		setupCanvas();
	}, [setupCanvas]);

	// キャンバス上のイベント座標を取得
	const getCoordinates = (
		e: React.PointerEvent<HTMLCanvasElement>,
	): Coordinate => {
		const canvas = canvasRef.current;
		if (!canvas) return { x: 0, y: 0 };
		const rect = canvas.getBoundingClientRect();
		return {
			x: e.clientX - rect.left,
			y: e.clientY - rect.top,
		};
	};

	// 描画開始
	const startDrawing = (e: React.PointerEvent<HTMLCanvasElement>): void => {
		e.preventDefault();
		const coords = getCoordinates(e);
		setIsDrawing(true);
		setDrawingPaths((prev) => [
			...prev,
			{ points: [coords], color: currentColor, size: brushSize },
		]);
	};

	// 描画中
	const draw = (e: React.PointerEvent<HTMLCanvasElement>): void => {
		if (!isDrawing) return;
		e.preventDefault();

		const coords = getCoordinates(e);
		const canvas = canvasRef.current;
		const ctx = canvas?.getContext("2d");
		if (!ctx) return;

		setDrawingPaths((prev) => {
			const paths = [...prev];
			const currentPath = paths[paths.length - 1];
			currentPath.points.push(coords);

			// 線を描画
			ctx.globalCompositeOperation = "source-over";
			ctx.lineCap = "round";
			ctx.lineJoin = "round";
			ctx.strokeStyle = currentPath.color;
			ctx.lineWidth = currentPath.size;

			const pts = currentPath.points;
			if (pts.length > 1) {
				const from = pts[pts.length - 2];
				const to = pts[pts.length - 1];
				ctx.beginPath();
				ctx.moveTo(from.x, from.y);
				ctx.lineTo(to.x, to.y);
				ctx.stroke();
			}
			return paths;
		});
	};

	// 描画終了
	const stopDrawing = (): void => {
		setIsDrawing(false);
	};

	// 描画をクリアして元画像を再描画
	const clearDrawing = (): void => {
		setupCanvas(originalImageUrl); // 元画像を指定して初期化
		setDrawingPaths([]);
	};

	// キャンバスを PNG にしてコールバック
	const saveImage = (): void => {
		const canvas = canvasRef.current;
		if (!canvas) return;
		const dataUrl = canvas.toDataURL("image/png");
		onSave(dataUrl);
	};

	return (
		<div className="flex flex-col gap-4">
			<div className="flex justify-end gap-2 p-2">
				<Button onPress={clearDrawing} variant="bordered">
					消去
				</Button>
				<Button onPress={saveImage} className="bg-black text-white">
					保存
				</Button>
			</div>
			<canvas
				ref={canvasRef}
				onPointerDown={startDrawing}
				onPointerMove={draw}
				onPointerUp={stopDrawing}
				onPointerLeave={stopDrawing}
				className="rounded cursor-crosshair touch-none"
				style={{
					touchAction: "none",
					maxWidth: "100%",
					maxHeight: "70vh",
				}}
			/>
		</div>
	);
};

export default Canvas;

AI採点の導入

例えば過去問記述ラボで応用情報技術者試験の過去問演習中にこんな解答をしたとしよう。

過去問記述ラボの応用情報技術者試験の解答確認ページ

「ハッシュ値だから」だとちょっと足りないのはわかる。しかしながら、模範解答と比べてどの要素が足りないかを判断するのは少々難しい。採点基準もわからない。かといって半分得点するのはやり過ぎか。などと色々考えてしまう。ただ演習だから厳しめにつけた方が良いかと思うが、そんなことを繰り返すと点数が低く出て慌てる。記述問題のある程度正確な丸つけは難しい。少なくとも私はそういう問題を慢性的に抱えているわけである。

そんな時はAI採点をポチッとするのだ。

過去問記述ラボの応用情報技術者試験の解答確認ページのAI採点後

このように推定配点のうちの何点分得点していて、かつあなたの解答にはどういう要素が足りないか?まで教えてくれるのだ。なんと便利か。こういうものが欲しかった。

今回の文だと不可逆性の要素がどうやら足りないということがわかった。では次にほぼ満点だが、ちょっと言い回しが違う文の挙動を見てみよう。満点であって欲しいがその部分はAI採点では汲み取ってくれるのだろうか?

「ハッシュ値を元に戻すのは困難だから」のような解答をした時にどうなるのかみてみよう。模範解答とは違う解答だが、個人的には満点をつけても良いと思う。

試してみよう。

過去問記述ラボの応用情報技術者試験の解答確認ページのAI採点後2

素晴らしい!きちんと満点が取れている。このように記述問題の自分でやると曖昧になりがちな採点をキーワードが入っているか、模範解答と言っていることの本質はあっているかなどの観点からAIが柔軟に自動で丸つけをしてくれる。

そしてその解答に即した解説を自動で作ってくれるのでより効率的に学習ができる。

なぜ間違えたのか。どうすれば得点が取れるようになるのか。 この辺りをきちんと簡単に教えてくれるサービスは私の知る限りない。だから過去問記述ラボはいいサービスである。ぜひ使ってみてほしい。

ただAIを無料で使えるわけではない。だからAI採点機能は有料にした。↓のキャンペーンなどで安く使えるようにしているので、気軽に使ってもらえればと思う。

https://www.kakomon-lab.jp/pricing/campaign

過去問記述ラボの技術構成

ここから過去問記述ラボの技術構成について話していく。技術構成としては以下だ。

  • Next.js(App Router)
  • Supabase
  • Vercel

モダン?モダンというには手垢がつきすぎている気がするが、あえてモダンと言い張ろう。それぞれ一つずつなぜ選定したか使ってみた感想とか工夫あたりを語ろうと思う。

Next.js(App Router)

まず過去問記述ラボはフロントエンドとバックエンドを一つのサーバーで設計した。Vercelに全部載せることにした。

理由としてはバックエンドが必要な場面がそこまで大きくないということだ。

別でサーバーを建てるのほどのサイズ感のバックエンドにはならないだろうという見通しで一つのサーバー具体的にはVercelのサーバー一つにしている。またバックエンドが肥大化してきたら...その時考えようと思っているが、基本的にはそんなに機能を追加するつもりはないので大丈夫だろうとタカを括っている。痛い目をみそうな気がしている。

方針としては

  • 認証まわりやAI採点などはServer Actionsを用いて、OG画像などはRoute Handlers(/api)を使っている
  • またプロジェクト全体をフルTypeScriptで統一して、型の共有でフロント/バックエンド間の齟齬を減らしている

得られたメリットとしては型の一元化である。めちゃくちゃ便利。想像の3倍便利だった。フロントとバックで型が共有とれているので不整合が絶対にあり得ないし、同じような型をバックエンドとフロントエンドで二重管理になるようなことがなくて便利だ。
また運用が単純化されて、リポジトリも一つ、デプロイ先も一つなので、コストと認知負荷を下げる事に一役買っている。...がたまに今これはサーバーを書いているのか?フロントか?と一瞬脳みそがバグることはあるがご愛嬌。

デメリットやリスクとしては、柔軟性が低そうだなという感想だ。サーバーだけスケールしたいとか、フロントだけ〇〇にしたいというような要件に対応するのが難しそう。またこれは私の知識不足もあると思うが、なんでもServer Actionsでやってしまうきらいがあって、Server Actionsの本質がPOSTなのにGETでも使ってしまうみたいな乱用が勃発している。どこかで戦争が起こりそうだ。本当は良くないんだろうなと思いつつ便利なので使ってしまっている。私が戦争を起こさないことを心の底から願っているし、同じような人がたくさんいると嬉しい。個人開発ならギリ許されそうだが、実務だと怒られること必至。

総じて実務やきちんと運用しようという考えだったら、この構成は結構バツである。信頼性とか柔軟性が低い構成だ。ただ個人開発の小さいプロジェクトを一人で回すと考えたら、ミニマムでコストも低く、認知負荷も低く相当快適ではあるが、戦争の火種になりそうだ。

Supabase

RDBを無料で触れるからというのが選定理由だ。
なんか流行ってたから触ってみようかと思ったのも偽らざる本音だが、慣れてるRDBを安く使いたかったというのも嘘ではない。クラウドのRDBを使おうと思うと、AWSのRDSやGCP,Azureとかになると思うのだが...高い...。なんか結構お値段するのだこいつら。安く済ませようと思うとNoSQLとかのDBになるが、それはそれで結構癖があって使いづらい...。

まぁもちろんNoSQLを使いこなせるようになればいいだけの話ではあるが、無料で使えるRDBがあるということで、使ってみようと思ったことが選定理由か。

使ってみた感想としては相当いい。ただのRDBとして使うのであればかなりいいモノだと思う。無料だし、無料だし。

ただ使い方が結構難しいなぁという感想だ。Supabaseは一応SaaSというよりはBaaSといって、Backend As A ServiceということでSupabase自体がバックエンドになるというコンセプトだ。

つまり本来的にはフロント側で叩くことを想定されているサービスなわけだ。あれ?そしたらDBのデータ盗みたい放題じゃね?と賢明な読者の皆さんなら気づくわけですが、それをRLSという仕組みでうまいことやっている。

それを知らないvibe coderたちがセキュリティ周りで結構危ないのでは?みたいなことが一時期話題になったが、さもありなん。閑話休題。

フロントから叩くのはちょっと抵抗ある。ただバックエンドを介さずに直接Supabaseを叩くほうがパフォーマンス的にはもちろんいい。(大きく変わるかは実際に測る必要があるが)よっぽど重要な情報じゃなければ、フロントから叩いてもいい気がする...少しのミスでDBの中身見放題だから綱渡りだ。

という感じで個人的には結構評価が微妙なラインである。もちろん普通のRDBとして使うのであればいいサービスだ。手軽だし、無料だし。が...フロントから直接叩くのはどうなのだ?という問題に対しては...うーんミスらない自信があるなら...いいんじゃないのか?くらいの気持ちでいる。

判断は保留。というのが私の気持ちだ。

あとsupabase Authのメールの送信数の少なさはどうにかならないかと思っている。一時間あたり最大2通(?!)しか送れない。(2025/08/02現在)個人開発とはいえ、本番に耐えうるような量ではないので、別でメールサービスを持ってきて連携しなきゃいけないのが面倒だ。

https://supabase.com/docs/guides/auth/rate-limits

Vercel

ここは特に大きな選定理由はない。Next.js使ってるし、無料だし。と簡単に選定した。

デフォルトでCDが備わってるのは嬉しい。案外この辺のCI/CD周りって面倒だったりするわけで、後回しになりがちだ。だが最初からついていれば面倒なこともなくするっとできるのは結構嬉しい機能だと思う。

ただvercelちゃんにもちょっとこれ...と思うところがある。それはログ機能の貧弱さだ
貧弱は言い過ぎか。ランタイムエラーをなんかslackかなんかに通知するような仕組みが今のところvercelにはない。エラー監視のためには外部ツールと連携したりする必要があるわけなのだが、vercelが持つべき機能では?と思いつつ、開発リソースの問題とかで先送りになってたりするのか?と想像している。

まぁそれかもう餅は餅屋でログ監視は俺らの仕事じゃないと割り切っているのかもしれない。

実装のこだわり・苦労したこと・工夫したこと

ここからは打って変わって実装した上での、こだわり等々を語っていこうと思う。

スマホで見やすくするためのこだわり

スマホの画面って想像以上に小さい あんまり普段は意識したことがないが、レスポンシブデザインを考えたりするとPCサイズではこうすれば見やすいと思った配置がサイズ的にできないことがある。フロントを触るのは2回くらいだが、そう思った。

応用情報技術者試験の午後試験を過去問記述ラボでといている画像

こだわりは一つ。

問題文を読みながら該当部分を読みたい

今回の場合だったら問題文に書いてある下線①の部分を一緒に見比べたいとずっと思っていた。IPAが出している過去問PDFでも過去問道場さんでも書籍でも毎回一緒に見比べるのは難しい。

実際にやってみるとわかるが、見比べるためには紙をペラペラ、スクロールして戻したりしなければならない。その悩みを解消した。これだけで個人的には価値があると思っている。

もちろんこの状態で後ろの本文もスクロールできるし、ボトムシートを閉じることもできる。スマホだとこのように配置している。画面が小さく、縦長なのでうまく画面の中で配置をしようと思うとこれがベストである。

逆にPCでは潤沢なキャンバスがあるので、こんなふうに贅沢に使って常時見比べられるようにしてある。(ちょっと時計の配置が変なので直す。)

PCで応用情報技術者試験の午後試験を過去問記述ラボでといている画像

PCとスマホでレイアウトを変えるとコードが複数生まれるので、あまり保守性的に良くないことなのかもしれない。今回はUXの名の下に保守性に犠牲になってもらった。

一番このサービスのキモとなる部分だったので妥協なしで実装したかった。

過去問PDFからマークダウン化の自動化

お安く便利に実行したい

見やすくするために、過去問記述ラボではPDFを直接表示するのではなく、PDFをマークダウンにして見やすく整形してから表示するようにしている。

過去問PDF→マークダウンの工程はAIにもちろんやらせている。claudeにPDFをプロンプトとともに渡して、ちまちま1問ずつ手作業で元々やっていた。OpenAIやGeminiでもやって見たのだが、このPDFの形式では無理と言われたが、そんな中、claudeちゃんだけはちゃんとやってくれた。控えめにいって神である。

ただそんなぽちぽちやるのがだるくなってきた。PDFをアップロードして、プロンプトコピペして...ああ面倒だ。そもそも面倒を効率化するのがエンジニアではないか。と考えたのでお金はかかるが、Anthoropic APIに並列で投げてやることにした。ただPDFはトークン数が結構取られる。確か最初の愚直にPDFを渡す形式だと、試験一回分の文字起こしに2$くらいかかった。

15年分くらい文字起こししなくちゃならんので、1年に2回あるわけで60$くらいかかる計算だ。そんなのやってられない。ふざけるな。お金は有限なのだ。そこで対策を講じてなんとか試験一回につき、0.1$まで抑えた。

何をしたかというとバッチキャッシュを使った。詳しくはまた別記事にでも起こそうかなと思っている、そちらを後ほど参考にしてくれると嬉しい。ここで書くと大変長くなりそうだ。

AIのブレをいかに対策するか

おんなじプロンプトで指示してもちょっと認識違いの文字起こしをする。全部意図通りに文字起こししてくれることももちろんあるが、ブレがあるのだ。そしてそのブレにも法則性があったりする。これが面白い。

{
  "id": "ap_2020_autumn_pm_q2_group_1",
  "text": "設問1",
  "questions": [
    {
      "id": "ap_2020_autumn_pm_q2_group_1_question_1",
      "text": "本文中の下線①の状態のままでは危惧される、W社の事業に関する機会損失リスクを、25字以内で述べよ。",
      "question_info": [
        {
          "id": "ap_2020_autumn_pm_q2_group_2_question_1_info_1",
          "key": "q1",
          "label": "",
          "type": "text",
          "limitLength": 25,
          "format": [
            "upTo"
          ],
          "modelAnswer": [
            "新事業の創出につながる機会が失われる。"
          ],
          "point": 3
        }
      ]
    }
  ]
}

↑これが設問の正しい文字起こしJSONだが、このJSONをたまに↓こういう感じで返す。

{
  "id": "ap_2020_autumn_pm_q2_group_1",
  // ↓このテキストに全部突っ込んで
  "text": "設問1 本文中の下線①の状態のままでは危惧される、W社の事業に関する機会損失リスクを、25字以内で述べよ。",
  "questions": [
    {
      "id": "ap_2020_autumn_pm_q2_group_1_question_1",
      //↓ここを空っぽにしてくる
      "text": "", 
      "question_info": [
        {
          "id": "ap_2020_autumn_pm_q2_group_2_question_1_info_1",
          "key": "q1",
          "label": "",
          "type": "text",
          "limitLength": 25,
          "format": [
            "upTo"
          ],
          "modelAnswer": [
            "新事業の創出につながる機会が失われる。"
          ],
          "point": 3
        }
      ]
    }
  ]
}

questionsの中のtextを空っぽにして一番上の階層のtextに問題文を詰めるのだ。これをプロンプトで強制しても、たまに無視する。これは問題の一つに過ぎない。他には配点を20点満点になるように配点してね。と言ってもいうことを聞かないし、他にも色々いうことを聞いてくれないことがある。

私はAIちゃんが毎回言うことを聞いてくれると思うのを諦めるべきだと思っている AIちゃんの出力を信用するのではなく、AIの出力を信用せずに人間側で強めに縛ってあげる必要がある。例えば今回はプロンプトでなんとかするのを諦めて、特製のリンター?(スクリプト)のようなもので縛ることにした。例えば上のようなケースならquestionstextが空なら、一個上の階層のtextから文をもってくるみたいなリンター?である。

これはコード生成の文脈ならばTDDをすれば、振る舞いで縛ることができるみたいなことと近いことだと思う。だからTDDはAIとかなり相性はいいのだと思っている。

これがそのAIを縛っているリンター?(スクリプト)群だ。一部関係ないものもあるが、大体フォーマットを合わせるためのリンター?(スクリプト)だ。これによってAIちゃんが適当な仕事を返してきても、このリンター?(スクリプト)たちがその成果をある程度担保してくれるわけである。

スクリプト群

こういうふうにAIの仕事を担保する仕組みを人間様が定義してあげる必要があると思っていて、AIとの付き合い方だと思っている。

どれだけAIの精度が上がったとしても、こういった仕組みは必要である。AI=人間だと思ってもらえればわかりやすい。AIは勘違いもするし、間違えることがある。そういったもののために必要な仕組みがリンターやTDDである。当然のようにAIにも必要になるだろう。

本当に必要なら無くなる時はAIが全く間違えを犯さなくなった時だ。だがそんな時が来たら人間様が退場するので考える必要はない。

今後やりたいこと

とりあえず以下は必ず機能として実装しようと思っている。

  • 図表番号のリンク機能
    • 図1みたいにリンクにして、それを押すと図1の元にスクロールするようにしたい
  • 演習履歴・成績分析・復習支援
    • 演習履歴を閲覧できるようにして、そこから成績の分析やどこを復習するべきかをレコメンドするようにしたい
  • レコメンド機能
    • 過去問記述ラボを開いた時に前回解いた問題から自動で次解くべき問題をレコメンドしてくれるようにしたい
  • IPA高度試験の問題を全部カバーしたい

このあたりはマストで実装しようと思っている。

前の方で別に誰が使わなくとも私が使うから誰も使わなくともいいとはいったが、どうせ公開したなら多くの人に使って欲しいと思っている。だから全力でSEOやってみようかなと思っている。その結果や知見はまた記事にまとめようかなと思ってるので、いいねを押す準備をしていて欲しい。私は承認欲求モンスターなのだ。

最後に

私の欲しかったサービスができた!アップデートはまだまだ重ねていくつもりだ。IPAの記述問題を演習するならあのサイトだよね。と言われるくらいまで認知度を高めていきたい。具体的にはMAU15000人を目標にしている。(IPA高度試験受験者数の10%程度)

そのために欲しい機能等々フィードバックがあれば、ぜひ遠慮なくお申し付けいただければ幸いだ。

また学びとしてAIの使い方を学んだ。我々がルールでガチガチに縛られているように、彼らは縛られる必要がある。もっともそれは欲しい出力と欲しいコードが大枠決まっている場合に限る。欲しいコードや振る舞いがあるのであれば、テストやなんやらでそれを満たす生成物じゃないと許さないようにするべきだ。

それでは良い個人開発ライフを!それと重ねることになるが当方は承認欲求モンスターだ。あなたの住む街を荒らされたくなければ...わかっているな?どうもありがとう。

Discussion