AI指示書の作り方
簡単なサンプルで指示書、DB定義書の組み合わせによるコーディングをしてみます。
成果物は最後に添付します。
AIに指示を出す時に要件定義、仕様書を併せ持った指示書を作成し指示します
- impl/doc/create_account.md に指示を記載
- impl/doc/resource_design.md にDB定義を記載
AI指示プロンプト
impl/doc/create_account.md
の指示に従いコードを作成してください
リソース定義は impl/doc/resource_design.md を参照
AI指示書
impl/doc/create_account.md
# 作成条件:
- /impl/usecase/create_account/usecase.py として作成
- /impl/usecase/create_account/ 以下にソースを収める、上層ディレクトリを参照しない
- コードファイル構成は以下に従い、追加ファイルは作成しない
- コードルール:
- 主処理: usecase.py → service.py の機能を並べて呼ぶだけ
- 各機能: service.py
- データアクセス: repository.py
- データクラス: model.py
- domain.py, misc.py, util.py, db.py などの追加ファイルは作成しない
- 細かく分割しすぎず、ある程度 service.py にまとめて実装する
- service.py は肥大化して構わない
# 入力処理
## 入力パラメータ:
- 辞書型変数
## 入力パラメータ取得処理:
- account_id を 辞書型変数 から取得
- 不正時(account_id が存在しない場合)
- "InvalidInputAccountId" を raise
- password を 辞書型変数 から取得
- 不正時(password が存在しない場合)
- "InvalidInputPassword" を raise
- 正常終了時:
- account_id, password 構造体を返却
# 主処理
## 入力パラメータ:
- account_id
- password
## 主処理
- account_id の正当性チェック
- 不正時
- "InvalidId" を raise
- password の正当性チェック
- 不正時
- "InvalidPassword" を raise
- パスワードハッシュの作成(password_hash)
- 正常終了時
- account_id, password_hash 構造体を返却
# 出力処理
## 入力パラメータ
- account_id
- password_hash
## 出力処理
- create_time の設定
- UNIXTIME(ミリ秒)
- ddbAccount に保存
- 保存項目
- account_id
- password_hash
- create_time
- 不正時
- "AccountSaveError" を raise
- 例外ログを出力
- 正常終了時:
- account_id, password_hash 構造体を返却
DB定義書
impl/doc/resource_design.md
# DB定義書
- ddbAccount
- Type: DynamoDB
- Fields:
- account_id: "hash_key, type=string, min_length=3, max_length=32"
- password_hash: "type=string,comment='hashed password'"
- create_time: "type=int,comment='unix time milliseconds'"
- ddbPosts
- Type: DynamoDB
- Fields:
- post_id: "hash_key, type=string, comment='{uuid4}.{uuid4}'"
- account_id: "type=string,max_length=32"
- body: "type=string,max_length=500"
- create_time: "type=int, comment='unix time milliseconds'"
- Relations:
- # ローカルフィールド → 連携先
- "account_id -> ddbAccount.account_id"
細かく指示することの意味
「AIが作ってくれました」として説明能力が無いと提示先、例えば顧客が納得してくれないと思いますので、この程度の指示書まで落とし込んで作成だけ自動というほうが良いでしょう
ここまで細かく指示するとコーディングを大差無いようにも思いますが、AIコーディングが当たり前になった世界では 仕様のわかりやすさ 、 検証の確かさ が重要になり、AI向け指示書を作る=コーディングになっていくのでしょうね。
成果物
以下、実際にAIに作ってもらったpythonコードです。
# usecase.py
from . import service
from .model import ProcessedParams
def execute(params: dict) -> ProcessedParams:
input_params = service.get_input_params(params)
processed_params = service.validate_and_hash(input_params)
result = service.save_account(processed_params)
return result
# service.py
import hashlib
import logging
import time
from . import repository
from .model import InputParams, ProcessedParams
logger = logging.getLogger(__name__)
def get_input_params(params: dict) -> InputParams:
if "account_id" not in params:
raise Exception("InvalidInputAccountId")
if "password" not in params:
raise Exception("InvalidInputPassword")
return InputParams(account_id=params["account_id"], password=params["password"])
def validate_and_hash(input_params: InputParams) -> ProcessedParams:
account_id = input_params.account_id
if not isinstance(account_id, str) or len(account_id) < 3 or len(account_id) > 32:
raise Exception("InvalidId")
password = input_params.password
if not isinstance(password, str) or len(password) == 0:
raise Exception("InvalidPassword")
password_hash = hashlib.sha256(password.encode()).hexdigest()
return ProcessedParams(account_id=account_id, password_hash=password_hash)
def save_account(processed_params: ProcessedParams) -> ProcessedParams:
create_time = int(time.time() * 1000)
try:
repository.save_account(
account_id=processed_params.account_id,
password_hash=processed_params.password_hash,
create_time=create_time,
)
except Exception as e:
logger.exception(e)
raise Exception("AccountSaveError")
return processed_params
# repository.py
import boto3
def save_account(account_id: str, password_hash: str, create_time: int) -> None:
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("ddbAccount")
table.put_item(
Item={
"account_id": account_id,
"password_hash": password_hash,
"create_time": create_time,
}
)
# model.py
from dataclasses import dataclass
@dataclass
class InputParams:
account_id: str
password: str
@dataclass
class ProcessedParams:
account_id: str
password_hash: str