はじめに
はじめまして、Miyoki(Miyoki Labs)です。
AIプロダクトエンジニアとして、個人でAIを使ったプロダクトを作っています。
Qiitaでは技術解説を中心に書いていくので、初回は自己紹介を兼ねて 「いま自分が使っている技術スタック」と「AIにどこまで任せているか」 を具体的に共有します。
同じように一人でAIプロダクトを回そうとしている人の、構成の参考になればと思います。
いま使っているスタック
一言でいうと「個人1人でも運用が破綻しない構成」を優先して選んでます。
無料枠と静的ホスティングを軸に、撤退リスクを低く保つのが方針です。
| 領域 | 使っているもの |
|---|---|
| フロント | React / TypeScript / Tailwind CSS(ブログは Astro) |
| バックエンド | Node.js / Python |
| AI | Claude API(生成・診断)/OpenAI API(画像系) |
| DB | Neon(PostgreSQL)+ Drizzle ORM |
| ホスティング | Cloudflare Pages(静的・商用可・無料)/一部 Render |
| 認証 | Better Auth |
派手な技術は入れてません。
「一人で保守できるか」を最優先にすると、だいたいこの辺に落ち着きました。
AIにどこまで任せているか
開発はほぼ Claude Code と二人三脚です。
ただ丸投げはしていません。自分の中の線引きはシンプルで、こうしてます。
- AIに任せる:実装、リファクタ、調査、下書き生成(自然文・コード)
- 人間が握る:何を作るかの判断、構造化フィールドの確定、公開のGO判断
とくに大事にしているのが3つ目です。
たとえばAIに日付やIDのようなフォーマットが決まった値を生成させない。
ここを守らないと痛い目を見ます。
// NG: period(期間)までAIに生成させる → "2026年6月" / "2026年06月" が混在して重複が出る
const report = await ai.generate('period も含めて JSON で返して')
// OK: period はサーバー側で確定、AIは本文だけ書かせる
const content = await ai.generate('レポート本文のみ生成して')
const report = { period, ...content }
「AIが主役、人は確認と判断に集中する」——これは自分のサービス(Nompass)の設計思想でもあり、開発そのもののやり方でもあります。
AIも自分も同じように騙される、という前提
線引きの話をもう一歩だけ具体的に。AIに任せる/握るを分けても、両方が同時に騙されることはあります。最近踏んだのがこれです。
// 型定義上は string。でも Neon の timestamp は RSC 経由で Date になって届く
started_at.slice(0, 10) // ← Date に .slice は無い → TypeError で処理が止まる
型は string と言っているのに、実体は Date。**型がついているのに、その型が嘘をついている。
** こういうとき、人もAIも「stringって書いてあるからstringだろう」と信じて、まんまと通してしまいます。
しかもこの例外がイベントハンドラ内で握りつぶされ、UIは「無言で何も起きない」ように見える。
原因(日付の型)と症状(別の機能が動かない)が、画面上まったく別の場所に出ました。
教訓はシンプルで、「UIが黙っているときこそ、まずconsole」。値を疑うより先に観測を疑う。AIと組んでいるからこそ、この順番を人間側が握っておくのが効くなと思ってます。
作ってきたもの
上のスタックで、こういうものを作ってきました。
- 説明可能なRAG:回答の根拠チャンクをUIで見せる。AIに判断させず、人が確認できる形にする
- ブログ自動化パイプライン:キーワードから記事下書きまで6ステップで生成
- 提案文ジェネレーター / 執筆補助ツール:システムプロンプトで文体を固定する系
- Nompass:小規模事業者向けのAI活用サービス(自分で立ち上げた実事業)
このNompassは実際に運営中です。
これから書くこと
Qiitaでは、上みたいな「AIと開発するときの具体的な作法」や、ハマったエラーの解決手順を書いていきます。
検索で同じ問題に当たった人がショートカットできるように、というのを意識するつもりです。
各媒体そろえてあるので 「@miyoki_labs」 で探してもらえれば見つかります。
作ったものはポートフォリオにまとめてます。