AIエージェントのコード品質を劇的に高める「Skills」実践ガイド:React & FastAPI編

Summary

生成AIを使ってコードを書くとき、こんな経験はありませんか?

「昨日は完璧なコードを書いてくれたのに、今日はなぜかスタイルが違う」 「エラーハンドリングを毎回忘れるので、指摘するのが面倒」 「シニアエンジニアなら絶対にやらないような実装をしてしまった」

Claude CodeやAntigravityのような自律型エージェントは非常に強力ですが、デフォルトの状態では「極めて優秀だが、プロジェクトのルールをまだ知らない新人エンジニア」のようなものです。チーム固有の設計思想や「好み」までは理解していません。

そこで登場するのがSkillsです。

前回の記事ではSkillsの概念について解説しましたが、今回はその続編として、実際の開発現場で使える「Skills」の実装例を具体的に紹介します。Frontend(React)とBackend(FastAPI)を題材に、AIエージェントを「信頼できるテックリード」に育てるための実践ガイドをお届けします。

なぜプロンプトではなくSkillsなのか?

多くの人は「プロンプトエンジニアリング」でこの問題を解決しようとします。「常にエラーハンドリングを書いて」と毎回指示したり、システムプロンプトに長大なルールを書き込んだりします。しかし、これはスケールしません。

Skillsを使うことで、以下の利点が得られます:

  1. 文脈に応じた発動: Reactのコンポーネントを作るときだけ「Reactのルール」が読み込まれます。
  2. 強制力: 「知っている」だけでなく「手順書を見ながら作業する」状態になるため、ミスが激減します。
  3. 資産化: チームのベストプラクティスが、ドキュメントではなく「実行可能なスキル」として蓄積されます。

The Quality Gap

それでは、具体的な実装を見ていきましょう。


Lv.1 Frontend: React Component Architect

Reactの開発では、コンポーネントの書き方に個人の癖が出がちです。AIも学習データに含まれる様々なパターン(Class Component, Arrow Function, Default Export vs Named Export)を無作為に選んでしまいます。

これを統一するためのSkillを作成します。

1. 定義ファイル: .agent/skills/react-architect/SKILL.md

まず、スキル定義を作成します。

---
name: react-architect
description: Use when creating new React components, refactoring UI code, or fixing styling issues.
---
# React Component Architecture
You are the Lead Frontend Architect. Adhere strictly to these rules when touching any `.tsx` file.
## 1. Structure Rules
- **Named Exports Only**: Never use default exports.
- ✅ `export const Button = ...`
- ❌ `export default function Button...`
- **Interface Definition**: Define a generic `Props` interface immediately before the component.
- **Top-Level Hooks**: All `useState`, `useEffect`, and custom hooks must be at the very top of the component body.
## 2. Logic & View Separation
- **No Complex Logic in JSX**: If a conditional or mapping logic takes more than 3 lines, extract it to a variable or helper function inside the component.
- **Custom Hooks**: If `useEffect` is complex (>5 lines), extract it to a custom hook immediately.
## 3. Styling Standards
- **Tailwind CSS**: Use utility classes.
- **Dynamic Classes**: ALWAYS use `clsx` or `tailwind-merge` for conditional classes.
- ✅ `className={clsx("p-4", isActive && "bg-blue-500")}`
- ❌ `className={"p-4 " + (isActive ? "bg-blue-500" : "")}`
## 4. Accessibility (a11y)
- **Interactive Elements**: Buttons and Links MUST have an `aria-label` if they contain only icons.

2. Before & After

このSkill導入前と導入後のAIの出力の違いを見てみましょう。

Before (AI Default)

// ❌ 悪い例:型定義が雑、インラインスタイル、クラス名の条件分岐が読みにくい
import React, { useState } from 'react'
export default function UserCard({ user }) {
const [open, setOpen] = useState(false)
return (
<div className={'card ' + (open ? 'active' : '')} style={{ padding: '20px' }}>
<h3>{user.name}</h3>
<button onClick={() => setOpen(!open)}>Toggle</button>
{open && <div>{user.bio}</div>}
</div>
)
}

After (With react-architect Skill)

// ✅ 良い例:Named Export、明示的な型定義、clsxの使用、a11y配慮
import { useState } from 'react'
import { clsx } from 'clsx'
interface UserCardProps {
user: {
name: string
bio: string
}
}
export const UserCard = ({ user }: UserCardProps) => {
const [isOpen, setIsOpen] = useState(false)
const toggleOpen = () => setIsOpen((prev) => !prev)
return (
<div
className={clsx(
'p-5 rounded-lg border border-gray-200 transition-all',
isOpen ? 'bg-blue-50 border-blue-500 shadow-md' : 'bg-white'
)}
>
<h3 className="text-lg font-bold text-gray-900">{user.name}</h3>
<button
onClick={toggleOpen}
className="mt-2 px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
aria-label={isOpen ? 'Hide details' : 'Show details'}
>
{isOpen ? 'Hide' : 'Show'} Details
</button>
{isOpen && <div className="mt-4 text-gray-700 leading-relaxed">{user.bio}</div>}
</div>
)
}

Skillがあるだけで、AIは「自分はテックリードである」というロールを認識し、指定されたベストプラクティスを順守します。コードレビューの手間が劇的に減るのがわかるでしょう。

React Component Anatomy


Lv.2 Backend: FastAPI Route Master

バックエンド、特にAPI開発において最も重要なのは「安全性」と「予測可能性」です。Pythonは柔軟な言語なので、辞書型(dict)をそのままAPIレスポンスとして返せてしまいますが、これはメンテナンスの悪夢を生みます。

PydanticとFastAPIの機能を最大限に活用させるためのSkillを定義しましょう。

1. 定義ファイル: .agent/skills/fastapi-master/SKILL.md

---
name: fastapi-master
description: Use when creating new API endpoints, modifying routes, or working on backend services in FastAPI.
---
# FastAPI Route Master Standards
Ensure all backend code complies with strictly typed, secure API patterns.
## 1. Schema First Development
- **No Dicts in Routes**: NEVER return a raw `dict` or accept raw arguments.
- **Pydantic Models**:
- Define all Request/Response models in `src/schemas/`.
- Use Pydantic v2 `BaseModel`.
- Always set `ConfigDict(from_attributes=True)` for ORM compatibility.
## 2. Route Definition Rules
- **Explicit Response Model**: Every `@router` decorator MUST have `response_model` defined.
- **Status Codes**: Explicitly define `status_code` for creation (201) and deletion (204).
- **Dependency Injection**:
- Use `Depends(get_db)` for database sessions.
- Use `Depends(get_current_user)` for protected routes.
## 3. Error Handling Protocol
- **No Bare Excepts**: Never use `except: pass`.
- **HTTPExceptions**: Use `raise HTTPException(status_code=..., detail=...)` for logic errors.
- **404 Handling**: Always check if a resource exists before operating on it.
## 4. Service Layer Separation
- **Thin Routes**: Route functions should only handle HTTP concerns (params, status).
- **Fat Services**: Move business logic and DB queries to `src/crud/` or `src/services/`.

2. Before & After

Before (AI Default)

# ❌ IMPLICIT: 辞書を返し、エラー処理もない危険なコード
@app.post("/users")
def create_user(item: dict, db = Depends(get_db)):
user = db.query(User).filter(User.email == item['email']).first()
if user:
return {"error": "exists"} # ステータスコードが200になってしまう!
new_user = User(email=item['email'], password=item['password'])
db.add(new_user)
db.commit()
return new_user # JSONへのシリアライズが不安定

After (With fastapi-master Skill)

# ✅ EXPLICIT: 型安全、適切なステータスコード、明確な責務分離
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from src import schemas, crud
from src.deps import get_db
router = APIRouter()
@router.post(
"/users",
response_model=schemas.UserResponse,
status_code=status.HTTP_201_CREATED,
summary="Create a new user"
)
def create_user(
user_in: schemas.UserCreate,
db: Session = Depends(get_db)
):
# 1. Check constraints
db_user = crud.get_user_by_email(db, email=user_in.email)
if db_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Email already registered"
)
# 2. Delegate creation to CRUD layer
return crud.create_user(db=db, user=user_in)

このSkillがあれば、AIは「とりあえず動くコード」ではなく「本番運用に耐えるコード」を最初から提案してくれます。特にresponse_modelの強制は、API仕様書(Swagger UI)の品質を保つ上で非常に重要です。

FastAPI Flow Diagram


Skillsをどう管理・運用するか?

Skillsの効果を実感したら、次は運用方法です。

全体か、プロジェクト個別か?

  • Global Skills (~/.gemini/skills/):
    • どのプロジェクトでも使う汎用的なルール(例:Gitのコミットメッセージ規約、英語の命名規則など)。
  • Workspace Skills (.agent/skills/ またはリポジトリルート):
    • そのプロジェクト固有の技術スタック(React, FastAPI, Next.jsなど)に関するルール。

推奨はWorkspace Skillsです。プロジェクトごとに技術選定やルールは異なるため、リポジトリの中にSkillを含めてGitで管理することで、チーム全員(とAI)が同じルールセットを共有できます。

育て方:AIに作らせる

実は、Skill自体もAIに作らせることができます。

「最近、AIがTailwindのクラス順序を間違えることが多いな」と感じたら、こう頼んでみましょう。

「君がReactコンポーネントを書くときに、Tailwindのクラス順序と命名規則を厳守するための react-style-guide Skillを作成して。SKILL.mdの形式で出力して」

AIは自分自身への指示書を書くのが得意です。これをベースに人間が微調整すれば、強力なSkillが数分で完成します。

まとめ:AIは「教育」して初めてパートナーになる

生成AIを単なる「時短ツール」として使うのはもったいないことです。Skillsを通じて彼らにプロジェクトの文脈と品質基準を教え込むことで、彼らは:

  1. 一貫性のあるコードを書き、
  2. 予期せぬバグを防ぎ、
  3. チームの一員として振る舞うようになります。

まずは、あなたが普段「コードレビューでよく指摘すること」を一つだけ、Skillにしてみてください。その小さな投資が、日々の開発体験を劇的に変えるはずです。

参考文献 & リンク


参考文献

Footnotes

  1. React - Your First Component - Official React Documentation on component structure.

  2. FastAPI - Bigger Applications - Structuring FastAPI for production.

  3. Anthropic - Building Skills - Guide on creating effective Agent Skills.