ã¯ããã« ããã«ã¡ã¯ã éçºæ¬éš éçº1éš ããªãã·ã¥ãªãµãŒãããŒã ã§ããŒã¿ãšã³ãžãã¢ãããŠããåç°ã§ãã ä»åã¯ãRedashã®ã¹ã±ãžã¥ãŒã«ã¯ãšãªãæŽçããããŒã¿ãŠã§ã¢ããŠã¹ïŒDWHïŒã®ã³ã¹ããæé©åãã話ãã玹ä»ããŸãã èæ¯ ããªãã·ã¥ãããã³ã§ã¯ãããŒã¿åæãå¯èŠåã®ããã«BIããŒã«ãšããŠRedashãæŽ»çšããŠããŸãã ããŒã¿åºç€ãšããŠã¯ãDWHã®TreasureDataã«Databricksã§å å·¥ããããŒã¿ãéçŽããRedashããTreasureDataãžã¯ãšãªãçºè¡ããŠããŒã¿ãå¯èŠåããããšããã¢ãŒããã¯ãã£ã§ãã ãããªäžãTreasureDataã®ã¯ãšãªå®è¡æéãå¥çŽã®äžéã«è¿ã¥ããã³ã¹ãå¢å ã®æžå¿µãçããŠããŸããã èª²é¡ èª²é¡ãšãªã£ãŠããã®ããRedashã«ç»é²ããã倿°ã®ã¹ã±ãžã¥ãŒã«ã¯ãšãªã§ãã ãããã®ã¯ãšãªã¯é·å¹Žæ£åžããããŠããããäžã«ã¯èª°ã«ãèŠãããŠããªããããã°ã幜éã¯ãšãªããå®è¡ããç¶ããŠããç¶æ
ã§ããã TreasureDataã¯ã¯ãšãªãšã³ãžã³(Presto)ã®çšŒåæéã«äžéããããããå©çšå®æ
ã®ãªãã¯ãšãªã®å®è¡ã¯ãç¡é§ãªãªãœãŒã¹æ¶è²»ãšã³ã¹ãå¢ã«çŽçµããŸãã åãçµã¿ ããã§ãäžèŠãªã¹ã±ãžã¥ãŒã«ã¯ãšãªãç¹å®ãã忢ã»åé€ããåãçµã¿ãè¡ããŸããã æé ã¯ä»¥äžã®éãã§ãã å©çšãããŠããªãã¹ã±ãžã¥ãŒã«ã¯ãšãªã®æŽãåºã ã¯ãšãªææè
ãžã®åé€å¯åŠã®ç¢ºèª äžèŠãªã¹ã±ãžã¥ãŒã«ã®äžæåé€ 1. å©çšãããŠããªãã¹ã±ãžã¥ãŒã«ã¯ãšãªã®æŽãåºã Redashã¯ãã¯ãšãªã®å®è¡ãç»é¢ã®é²èЧãšãã£ãæäœãã°ã events ãšããããŒãã«ã«ä¿åãããŠããŸãã ãã® events ããŒãã«ãåæããã宿å®è¡ãããŠããã«ããããããããã®å®è¡çµæãäžå®æé誰ã«ãé²èЧãããŠããªãã¯ãšãªãããªã¹ãã¢ããããŸããã 2. ã¯ãšãªææè
ãžã®åé€å¯åŠã®ç¢ºèª æŽãåºããã¯ãšãªã®äžèЧãäœæããããããã®ã¯ãšãªã®äœæè
ã«ã¹ã±ãžã¥ãŒã«ã®åé€ããŸãã¯ã¯ãšãªèªäœã®åé€ãå¯èœãã確èªã»äŸé ŒããŸããã ããã«ãããçŸåšã¯å©çšãããŠããªããã®ã®ãä»åŸå©çšããå¯èœæ§ããããšãã£ãã¯ãšãªãæ®ãã€ã€ãå®å
šã«æŽçãé²ããããšãã§ããŸããã 3. äžèŠãªã¹ã±ãžã¥ãŒã«ã®äžæåé€ é¢ä¿è
ããã®ç¢ºèªãåããã¯ãšãªã«å¯ŸããŠãäžæã«ã¹ã±ãžã¥ãŒã«ãåé€ããŸããã çµæ ãã®åãçµã¿ã®çµæãã¹ã±ãžã¥ãŒã«å®è¡ãããŠããã¯ãšãªã®ç·å®è¡æéã çŽ50%åæž ããããšã«æåããŸããã ããã«ãããTreasureDataã®Prestoã®çšŒåæéã倧å¹
ã«å§çž®ããé©åãªå©çšç¯å²ã«åããããšãã§ããŸããã ãŸãšã ä»åã¯ãRedashã®ã€ãã³ããã°ã掻çšããŠäžèŠãªã¹ã±ãžã¥ãŒã«ã¯ãšãªãç¹å®ã»æŽçããDWHã®è² è·åæžãšã³ã¹ãæé©åãå®çŸããäºäŸãã玹ä»ããŸããã ä»åŸã¯ã宿çãªæ£åžãã®ä»çµã¿åããã¯ãšãªäœææã®ã¬ã€ãã©ã€ã³ãæŽåããããšã§ãè²»çšå¯Ÿå¹æã®é«ãããŒã¿æŽ»çšåºç€ãç¶æããŠãããããšèããŠããŸãã
ç®æ¬¡ ã¯ããã« èæ¯ çŸç¶ã®ææ¡ AWS CodeBuild GitHub Actions ãããã³ãŒã æ¹åãããšãã äžèŠãªã³ãŒãåé€ ãã£ãã·ã¥ã®æå¹æŽ»çš Codebuild GitHub Actions ãŸãšã ã¯ããã« ããã«ã¡ã¯ãéçºæ¬éšéçº 1 éšãã¢ããã°ã«ãŒãã®ãšã³ãžãã¢ã® rymiyamoto ã§ãã ãããã¯ããå®å¿å®å
šã«æäŸããã«åœãããCI/CD ãçšããŠãã¹ãããããã€ãèªååããããšã§ãæäœæ¥ãåãé€ããŠããã®ã¯æšä»ã®æµãã§ãã ããããCI/CD ã®ãã€ãã©ã€ã³ãé·ãééçšããã«ãããããã¹ãããããã€ã®æéãé·ããªããšãã課é¡ããããŸãããCI/CD ã®ãã£ãæ°åã®é
å»¶ããéçºããŒã å
šäœã®çç£æ§ã®äœäžãåŒãèµ·ããããšããããŸãã ããã§ãCI/CD ã®ãã€ãã©ã€ã³ãå°ãã§ãæ©ãããããã«ãããã詊ããŠã¿ãã®ã§ãã®åå¿é²ãšãªããŸãã èæ¯ ç§ãé¢ãã£ãŠãã ãã¢ãã(æ§ MAMADAYS) ã¯ãµãŒãã¹ãšããŠã¯ 2019 幎 7 æã« web ãµã€ããå
¬éããã10 æã«ã¯ã¢ããªã®ãªãªãŒã¹ãè¡ã£ãŠããŸãããããŸã§ãŸã 幎å£ãçµã£ãŠããããã§ã¯ãããŸãããæ°å¹Žééçºãè¡ãããŠããããµãŒãã¹èŠæš¡ãå°ããã€å€§ãããªã£ãŠããŠããŸãã ããæ¥ã¡ã³ããŒãããæè¿ API ãµãŒã㌠㮠CI é
ããªãã§ããïŒããšçžè«ãåããŸããã API ãµãŒããŒã¯ Go èšèªã§æžãããŠãã AWS CodeBuild ã§ãããã€ããGitHub Actions ã§ãã¹ããåããŠããŸãã (ãªã CI/CD ã§å¥ã®ãµãŒãã¹ãå©çšããŠããããšãããšããµãŒãã¹èªäœã¯ AWS ã§çšŒåããŠããåœæã¯èªèšŒåšãã AWS ã§å®çµããã»ããæ¥œã§äœ¿ãããŠããŸãããéäžãã CI ã ãã§ã GitHub Actions ã詊ãããã«ãªã£ãèæ¯ããããŸã) å®éã«ç¢ºèªãããšãã以äžã®ãããªç¶æ³ã«ãªã£ãŠããŸããã ãµãŒãã¹ æé AWS CodeBuild(ãããã€) 15 å GitHub Actions(ãã¹ã) 10 å æéãšããŠã¯ 30 åã 1 æéã®ããã«ãã®ãããããã£ãŠãããšããããã§ã¯ãããŸããããæ°åã®éããéçºã®é床ã«åœ±é¿ããŠããŸãããŸãå®è¡æéã®é·ããã³ã¹ãã«ãè·³ãè¿ã£ãŠãããŸãã ããã§ãã®åºŠããããã®ãã€ãã©ã€ã³ãèŠçŽããŠã¿ãããšã«ããŸããã çŸç¶ã®ææ¡ AWS CodeBuild ãã¢ããã§ã¯ AWS Elastic Container Service(以é ECS) ãå©çšããŠããŸãã ãã®ãã AWS Elastic Container Registry(以é ECR) ã§ã€ã¡ãŒãžã管çããŠããŸãã å
éšãšããŠãã£ãŠããããšã¯ãã£ããæžããŠä»¥äžã®ãšããã§ãã ecs-deploy ã®ã€ã³ã¹ããŒã« Docker Hub ãš ECR ã®èªèšŒ ã€ã¡ãŒãžã®ãã«ã&ã¿ã°ä»ã ECR ãžã®ããã·ã¥ ECS ãžã®ããã〠å
éšãèŠãŠã¿ããšãã«ãæã®éœåºŠãã£ãã·ã¥ãªãã§ã®å®è¡ãããŠããããã«ãæéãé·ããªã£ãŠããŸããã ãŸããã«ãã«åœ±é¿ãã Docker é¢é£ãèŠçŽããŠã¿ãŸããã Dockerfile ã®äžèº«ã確èªãããšããã go mod download ãªãã§ãã«ãã®ã¹ããŒãžã§ãã«ãããŠããããšãããããŸããã ã»ãã ãš .dockerignore ãããŸãå¹ããŠããããã³ãŒãã®ã³ããŒæã«åœ±é¿ããªãéšåãå·®åãšããŠæ€ç¥ãããŠããŸãã GitHub Actions ãã¹ã㯠DB ã䜿ããã¹ããšäœ¿ããªããã¹ããåããŠããŸãããã¡ãã¯ãã¹ãã ããç®çãªã®ã§ããã¹ãã®å®è¡èªäœã¯ã³ã³ãããçšããã« actions/setup-go ã§ç°å¢ãçšæããŠããŸãã 䞊ååãè¡ã£ãŠããã®ã§ãã¹ãå®è¡èªäœã¯ããçšåºŠèª¿æŽãããŠããã go mod download ã¯ãã£ãã·ã¥ãèŠãããã«ãªã£ãŠã¯ããŸããããããå
éšã§ go install ã§è¿œå ããããŒã«ãéœåºŠå
¥ããããŠããæéã®ãã¹ã倧ããã§ãã ãããã³ãŒã ãã«ãããã¹ãèªäœãžã®åœ±é¿ãèããŠãããã³ãŒãããªããã調ã¹ãŠã¿ãŸããã ãã®çµæããã§ã«ã©ããããåŒã°ããŠããªããšã³ããã€ã³ããã飿ºãæ¢ãŸã£ãŠå®æå®è¡ããããã¹ã¯ãªãããªã©ãäžèŠãªã³ãŒãã倿°èŠã€ãããŸããã ãããã³ãŒãèªäœã¯ãããã¯ãã®æé·ã«äŒŽããã³ãŒãéãå¢ããŠããããšã§ã©ãããŠãåºãŠãããã®ã§ãããªãªãŒã¹ãµã€ã¯ã«ãé«éã§åããŠããäžã§å®å®³ã®ãªãåŸçä»ããããæéãåããªãããšããããŸããããŸãã³ãŒããæžãã人ãããªããªã£ãŠããŸããšããã®ã³ãŒããäœã®ããã®ãã®ãããããªããªã£ãŠããŸãã®ããã°ãã°ã§ãã ãããã£ããã®ã®ç©ã¿éãã«ãã£ãŠã³ãŒãéãå¢ããŠããããšã§ã次第ã«ãã«ãããã¹ãã®æéã«åœ±é¿ãåºãŠããŸããŸãããŸãéçºè
ãšããŠã圱é¿ãäžåãªãã³ãŒããèæ¯ãç¥ããªãããã«äœèšãªèæ
®ãããå¿
èŠãåºãŠããŸããšãŠãäžå¥å
šã§ãã äœè«ã§ããä»åã¯å®éã«ããã¥ã¡ã³ããåœæã®ããåãããã°ãèŠãŠç¢ºèªããŸããããGo ã§ã¯ãããã³ãŒããæ€ç¥ããããŒã«ããããŸãã ãã¡ãã䜿ãããšã§å®éã«äœ¿ã£ãŠãªã颿°ãæ¢ãããšãã§ããŸãããã ããã®ããŒã«ã¯åœéœæ§ãããã®ã§ãããŸã§åèçšåºŠã®å©çšãæãŸãããšæããŸãã pkg.go.dev æ¹åãããšãã äžèšã§èŠã€ãã£ãå
容ã«èžãŸããŠããããæ¹åãããŠãããŸãã äžèŠãªã³ãŒãåé€ æã£åãæ©ããããã³ãŒãããŸãåé€ããŠãããŸããããã æ¶ããšèšã£ãŠãäžæ¬ã§ãŸãšããŠåé€ããã®ã§ã¯ãªãã³ã³ããã¹ãåäœ(ãšã³ããã€ã³ãã»ã¹ã¯ãªãã)ã§ PR ãäœæããŠãã¬ãã¥ã¯ãŒã®è² è·ãå°ãã§ã軜æžããŸããã å®éã«åé€ããã³ãŒããšããŠã¯ 486 ãã¡ã€ã«ã134,313 è¡ã§çµæ§ãªéã®ã³ãŒããåé€ãããŸããã ãã®åé€ã ãã§ãããªãæéççž®ãããããšãã§ããŸããã ãµãŒãã¹ æ¹åå æ¹ååŸ AWS CodeBuild(ãããã€) 15 å 8 å GitHub Actions(ãã¹ã) 10 å 8 å ãã£ãã·ã¥ã®æå¹æŽ»çš Codebuild ãã«ãæéã®ççž®ã«ã¯ãCodeBuild ã®ã€ã³ã¹ã¿ã³ã¹ã¿ã€ããäžãããšããéžæè¢ããããŸããããã³ã¹ãé¢ãèæ
®ããŠãã£ãã·ã¥ã®æŽ»çšã詊ã¿ãŸããã ãŸã Dockerfile ã®äžèº«ãä¿®æ£ããŸãã go mod download ãªãã§ãã«ãã®ã¹ããŒãžã§ãã«ãããŠããã®ã§ã¹ããŒãžãåããŠããã±ãŒãžã®æŽæ°ããªãéãã¯ãã£ãã·ã¥ãå¹ãããã«å€æŽããŸããã 倿Žå FROM golang:${GO_VERSION}-alpine AS builder COPY . . # 以égo build... 倿ŽåŸ FROM golang:${GO_VERSION}-alpine AS deps COPY go.mod . COPY go.sum . RUN go mod download FROM deps AS builder COPY . . # 以égo build... ãŸã .dockerignore ãä¿®æ£ããŠã³ã³ããã«ã³ããŒãããã¡ã€ã«ãæžãããŸããã 䞻㫠CI/CD ã®èšå®ãã¡ã€ã«ãæšä» AI ããŒã«ã®å©çšã§ããã¥ã¡ã³ããäœæããããšãå€ããªã£ãŠããããã *.md ãš *.mdc ã®å€æŽãé€å€ããŠããŸãã æåŸã« Docker Buildx ãå©çšãã€ã€æ¢åã®ã€ã¡ãŒãžã®ãã£ãã·ã¥ãå©çšããããã«å€ããŠããŸãã Docker Buildx 㯠Docker ã³ãã³ããæ¡åŒµãã CLI ãã©ã°ã€ã³ã§ããã Moby BuildKit ãã«ããŒããŒã«ãããã«ããæäŸãããæ©èœã«å®å
šå¯Ÿå¿ãããã®ã§ãã Docker ãã«ããšåæ§ã®ãŠãŒã¶ãŒæäœãæäŸããããã«ã¹ã³ãŒãåããããã«ããŒã€ã³ã¹ã¿ã³ã¹ãè€æ°ããŒããžã®åæãã«ããªã©ãæ°å€ãã®æ°æ©èœãæäŸããŸãã docker buildx build ã³ãã³ãã¯åŸæ¥ã® docker build ã«ãã£ãŠå©çšã§ããæ©èœã¯ãã¹ãŠå¯Ÿå¿ããŠãããåºåèšå®ãã€ã³ã©ã€ã³ãã«ããã£ãã·ã³ã°ãã¿ãŒã²ãããã©ãããã©ãŒã æå®ãšãã£ãæ©èœã«ã察å¿ããŸãã ããã« Buildx ã§ã¯ããã€ãã® docker build ã§ã¯å®çŸã§ããªãæ°æ©èœãšããŠããããã§ã¹ãäžèЧã®çæã忣ãã£ãã·ã³ã°ããã«ãçµæã® OCI ã€ã¡ãŒãž tarball ãžã®åºåãå®çŸããŸãã matsuand.github.io 倿Žå version : 0.2 env : variables : REPOSITORY_URI_BASE : .dkr.ecr.ap-northeast-1.amazonaws.com/ DOCKER_BUILDKIT : "1" phases : install : commands : - GO_VERSION=$(cat .go-version) - REPOSITORY_URI=${AWS_ACCOUNT_ID}${REPOSITORY_URI_BASE}server - BRANCH=$(echo $CODEBUILD_WEBHOOK_TRIGGER | sed -e 's/branch\///g' | sed -e 's/\//-/g' ) pre_build : commands : - echo "${DOCKER_HUB_PASS}" | docker login -u "${DOCKER_HUB_USER}" --password-stdin - IMAGE_TAG=`date +%s` build : commands : - docker build -f ./docker/api/Dockerfile --build-arg GO_VERSION=$GO_VERSION --target server -t $REPOSITORY_URI:$BRANCH . - docker tag $REPOSITORY_URI:${BRANCH} "${REPOSITORY_URI}:${BRANCH}.${IMAGE_TAG}" post_build : commands : - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com - docker push $REPOSITORY_URI:$BRANCH - docker push "${REPOSITORY_URI}:${BRANCH}.${IMAGE_TAG}" # ãããã€... 倿ŽåŸ # 倿Žãªãéšåãªã®ã§å²æ phases : install : commands : - GO_VERSION=$(cat .go-version) - REPOSITORY_URI=${AWS_ACCOUNT_ID}${REPOSITORY_URI_BASE}server - BRANCH=$(echo $CODEBUILD_WEBHOOK_TRIGGER | sed -e 's/branch\///g' | sed -e 's/\//-/g' ) - docker buildx create --use --name server-builder || docker buildx use server-builder - docker buildx inspect --bootstrap pre_build : commands : - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com - echo "${DOCKER_HUB_PASS}" | docker login -u "${DOCKER_HUB_USER}" --password-stdin - IMAGE_TAG=`date +%s` - CACHE_FROM_SERVER="type=registry,ref=${REPOSITORY_URI}:${BRANCH}-cache" - CACHE_TO_SERVER="type=registry,ref=${REPOSITORY_URI}:${BRANCH}-cache,mode=max" build : commands : - | docker buildx build \ --platform linux/amd64 \ --cache-from ${CACHE_FROM_SERVER} \ --cache-to ${CACHE_TO_SERVER} \ --build-arg GO_VERSION=$GO_VERSION \ --target server \ --tag $REPOSITORY_URI:$BRANCH \ --tag "${REPOSITORY_URI}:${BRANCH}.${IMAGE_TAG}" \ --push \ -f ./docker/api/Dockerfile . post_build : commands : # ãããã€... ä»å Buildx ã䜿ã£ãŠã³ãã³ãããŸãšãã€ã€ããã£ãã·ã¥ã«é¢ãããªãã·ã§ã³ã远å ããŠããŸãã --cache-from ã§ã¯ååäœæããã€ã¡ãŒãžãåºã«æ§ç¯çšã«å€éšã®ãã£ãã·ã¥ãœãŒã¹ã䜿çšãã --cache-to ã§ã¯æ§ç¯ãã£ãã·ã¥ãå€éšã®ãã£ãã·ã¥å
ãžåºåããŠããŸãããããããªãã·ã§ã³ãããã€ããããŸãããä»å㯠type=registry ãå©çšããŠããŸãã type=registry ãå©çšããããšã§ãDocker Hub ã ECR ãªã©ã®ã¬ãžã¹ããªãŒãããã£ãã·ã¥ãååŸãããŸã mode=max ãæå®ããããšã§ã³ã³ããå
ã®æ§æãæå€§éãã£ãã·ã¥ã§ããŸãã ã¡ãªã¿ã« max ã®å Žåãã£ãã·ã¥æ§ç¯ã®æéãããããŸããä»åã¯ãããŸããã§ããã min ãæå®ããããšã§ã¹ããŒãžã®æçµæ®µã®ã¿ãã£ãã·ã¥ããããã«ãªã軜éåããããšãã§ããŸãã docs.docker.jp docs.docker.jp ãããã®ä¿®æ£ã«ãããã«ãæéã¯ãã£ãã·ã¥ãå¹ããŠã³ãŒãã®å€æŽããªãå Žå㯠3 åçšåºŠã§çµããããã«ãªããŸããã GitHub Actions ãã¹ãã®å®è¡æéãççž®ããããã«ããŒã«ã®ã€ã³ã¹ããŒã«ãéœåºŠã ãã«ããªãããã« actions/cache ãå©çšããŠãã£ãã·ã¥ãå©çšããããã«ããŸããã 倿Žå on : [ push ] env : DB_USER : root DB_PASSWORD : test DB_ADDRESS : 127.0.0.1 GO_ENV : test TEST_PARALLEL : true NUM_OF_PARALLEL : 4 SQL_MIGRATE_VERSION : v1.8.0 GOVERALLS_VERSION : v0.0.12 jobs : use-rds-test : runs-on : ubuntu-latest services : db : image : mysql:8.0.40 ports : - 3306:3306 env : MYSQL_ROOT_PASSWORD : test options : >- --health-cmd "mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 5 steps : - uses : actions/checkout@v4 with : fetch-depth : 0 - name : setup go uses : actions/setup-go@v5 id : setup-go-db with : go-version-file : "go.mod" - name : download go modules (if cache miss) shell : bash if : ${{ steps.setup-go-db.outputs.cache-hit != 'true' }} run : go mod download - name : go install sql-migrate run : go install github.com/rubenv/sql-migrate/...@${{ env.SQL_MIGRATE_VERSION }} # 以éãã€ã°ã¬ãŒã·ã§ã³ãšãã¹ãå®è¡&ã«ãã¬ããžã¬ããŒãçæ not-use-rds-test : runs-on : ubuntu-latest steps : - uses : actions/checkout@v4 with : fetch-depth : 0 - name : setup go uses : actions/setup-go@v5 id : setup-go-no-db with : go-version-file : "go.mod" - name : download go modules (if cache miss) shell : bash if : ${{ steps.setup-go-no-db.outputs.cache-hit != 'true' }} run : go mod download # 以éãã¹ãå®è¡&ã«ãã¬ããžã¬ããŒãçæ upload-goveralls : runs-on : ubuntu-latest needs : [ use-rds-test, not-use-rds-test ] steps : # åé¢ããã«ãã¬ããžã¬ããŒã(rdsãããšrdsãªã)ã®çµå - name : setup go uses : actions/setup-go@v5 id : setup-go-cv with : go-version-file : "go.mod" - name : Install goveralls run : go install github.com/mattn/goveralls@${{ env.GOVERALLS_VERSION }} - name : upload coverage env : COVERALLS_TOKEN : ${{ secrets.COVERALLS_TOKEN }} run : goveralls -coverprofile=./coverage.out -service=github 倿ŽåŸ # 倿Žãªãéšåãªã®ã§å²æ jobs : use-rds-test : # 倿Žãªãéšåãªã®ã§å²æ steps : - uses : actions/checkout@v4 with : fetch-depth : 0 - name : setup go uses : actions/setup-go@v5 id : setup-go-db with : go-version-file : "go.mod" - name : download go modules (if cache miss) shell : bash if : ${{ steps.setup-go-db.outputs.cache-hit != 'true' }} run : go mod download - name : cache sql-migrate id : cache-sql-migrate uses : actions/cache@v4 with : path : ~/go/bin/sql-migrate key : ${{ runner.os }}-sql-migrate-${{ env.SQL_MIGRATE_VERSION }} restore-keys : | ${{ runner.os }}-sql-migrate- - name : go install sql-migrate (if cache miss) if : steps.cache-sql-migrate.outputs.cache-hit != 'true' run : go install github.com/rubenv/sql-migrate/...@${{ env.SQL_MIGRATE_VERSION }} # 以éãã€ã°ã¬ãŒã·ã§ã³ãšãã¹ãå®è¡&ã«ãã¬ããžã¬ããŒãçæ not-use-rds-test : runs-on : ubuntu-latest steps : # 倿Žãªãéšåãªã®ã§å²æ upload-goveralls : runs-on : ubuntu-latest needs : [ use-rds-test, not-use-rds-test ] steps : # åé¢ããã«ãã¬ããžã¬ããŒã(rdsãããšrdsãªã)ã®çµå - name : setup go uses : actions/setup-go@v5 id : setup-go-cv with : go-version-file : "go.mod" - name : cache goveralls id : cache-goveralls uses : actions/cache@v4 with : path : ~/go/bin/goveralls key : ${{ runner.os }}-goveralls-${{ env.GOVERALLS_VERSION }} restore-keys : | ${{ runner.os }}-goveralls- - name : Install goveralls (if cache miss) if : steps.cache-goveralls.outputs.cache-hit != 'true' run : go install github.com/mattn/goveralls@${{ env.GOVERALLS_VERSION }} - name : upload coverage env : COVERALLS_TOKEN : ${{ secrets.COVERALLS_TOKEN }} run : goveralls -coverprofile=./coverage.out -service=github ä»åãã€ã°ã¬ãŒã·ã§ã³ããŒã«ãšããŠå©çšããŠãã sql-migrate ãšãã¹ãã®ã«ãã¬ããžãéã£ãŠãã goveralls ã®ãã€ããªããã£ãã·ã¥ããŠããŸããåºæ¬çã«ããŒã«ã®ããŒãžã§ã³å€ãããªãéãã¯ãã£ãã·ã¥ãçšãããŸãŸã§ããã®ã§ããŒã¯ ${{ runner.os }}-name-${{ env.TOOL_VERSION }} ãšããŠããŸãã ããã«ããåºæ¬ããŒã«ã¯ãã£ãã·ã¥ãããç¶æ
ãšãªã 1 åçšåºŠã®ãã¹ãå®è¡æéççž®ãããããšãã§ããŸããã ãŸãšã åœå 10 åè¶
ããããŠãã CI/CD ã®æéãççž®ãããŸããã ãµãŒãã¹ æ¹åå ãããã³ãŒãåé€åŸ ãã£ãã·ã¥æ¹ååŸ(æçµåœ¢) AWS CodeBuild(ãããã€) 15 å 8 å 8 å (倿Žãªãå Žåã¯æé 3 å) GitHub Actions(ãã¹ã) 10 å 8 å 7 å ãã«ãããã¹ãã®æéãççž®ããããã«ããããã³ãŒãã®åé€ããå§ãŸã Docker èªäœã®ã¬ã€ã€ãŒãã£ãã·ã¥ã®èŠçŽããããŒã«ã®ã€ã³ã¹ããŒã«ãéœåºŠã ãã«ããªãããã«ãã£ãã·ã¥ãå©çšããããã«ããŸããã æ£çŽãããã³ãŒãã®åé€ãäžçªå¹åãçºæ®ããŠããã®ã§ããããããã ãã§ãããªã广åºããšæããŸãã ãŸãèªåã®å匷äžè¶³ã§ãŸã æ¹åã§ãããšããã¯ãã£ãšããã¯ããªã®ã§æŽã«çªãè©°ããŠãéçºãµã€ã¯ã«ãæ©ãããŠããããšã«åªããŠãããããšæããŸãã æåŸãŸã§èªãã§ããã ãããããšãããããŸãããçæ§ã® CI/CD é«éåã®åèã«ãªãã°å¹žãã§ãã
ã¯ããã« ããã«ã¡ã¯ããšããªãŒã§ãµãŒããŒãµã€ããã¡ã€ã³ã«æ
åœããŠããæž
æ°Žã§ãã ç§ã®æå±ããå°å£²ã¢ããªããŒã ã§ã¯ä»ç€Ÿããäºæ¥è²æž¡ãšãã圢ã§åŒãç¶ãããå°å£²åºæ§åãã®ã·ã¹ãã ã®ä¿å®éçšãè¡ã£ãŠãããŸãã åŒãç¶ãã ã·ã¹ãã ã«ã€ã㊠PHP, Laravelã§éçºãããŠãããMVCã«Serviceå±€ãšRepositoryå±€ãå ãã圢ã§èšèšãããŠããŸã APIãšã³ããã€ã³ãã100åä»¥äž å€éšAPI飿ºæã æ°å¹Žä»¥äžéçšããŠãã äºæ¥è²æž¡ã§åŒãç¶ãã ã·ã¹ãã ã®ä¿å®éçšã«ãããèª²é¡ äºæ¥è²æž¡ã®ã¿ã€ãã³ã°ã§æ§ã
ãªè³æãåŒãç¶ãã§ããã®ã§ãããããã€ãã®è³æã¯æ¹ä¿®åã®ç¶æ
ã®ãŸãŸæ®ã£ãŠãããªã©ãäžååãªç¶æ
ã§ãã ãã®çµæããžã§ã€ã³ããã°ããã®ãšã³ãžãã¢ãæ©èœãææ¡ããããšããéã«ãè³æã ãã§ã¯ååã«çè§£ã§ãããå®éã®ã³ãŒããèªã¿èŸŒãŸãªããã°ãªããªããšããé«ãããŒãã«ããããŸãã æ¬æ¥ã§ããã°äžåºŠå
šãŠã®ã³ãŒããèªã¿èŸŒã¿ãææ°ã®ç¶æ
ã«åãããŠè³æãäœãçŽãã®ãçæ³ã§ãããæ¥ã
ã®ä¿å®éçšã¿ã¹ã¯ã«è¿œãããäžã§ããã®ãããªæéã確ä¿ããããšã¯é£ããã®ãçŸç¶ã§ãã ç§ããã®ããŒã ã«ãžã§ã€ã³ããŠæåã«å°ã£ãããšã¯ãã©ã®ãšã³ããã€ã³ãã§ã©ã®ãããªåŠçãå®è¡ãããã®ãïŒããææ¡ããããšã§ããã ããã§ãä»åã¯Cursorã«ææ°ã®ç¶æ
ã®API仿§æžãç°¡åã«äœãããããšãã§ããããæ€èšŒããŠã¿ãããšæããŸãã Cursorã«API仿§æžãäœæãããæ¹é 以äžã®ã¢ãã«ã䜿çšããŸã claude-4-sonnet-thinking claude-3.7-sonnet-thinking gemini-2.5-flash claude-4-sonnet claude-3.7-sonnet ç§ã¯ã»ãšãã©ã®éçºæ¥åã§claude-4-sonnetã䜿çšããŠããã®ã§ãããå»äŸ¡ãªclaude-3.7-sonnetãšåºåå
容ã«ã©ããããéããçºçãããã確ãããããšæããŸãã ãŸããgemini-2.5-flashã¯ã³ãŒããªãŒãã£ã³ã°ã§åªããŠãããšããåãè³ã«ããããšãããããããã¡ããæ€èšŒããããšæããŸãã æåŸ
ããåºåå
容 markdownã®ããŒãã«åœ¢åŒ ãšã³ããã€ã³ã, ãªã¯ãšã¹ã, ã¬ã¹ãã³ã¹, æŠèŠèª¬æã®4å ããã³ãããå®è¡ããäžã§ã®åæ Cursor Rulesã¯äœãèšå®ããŠãããŸãã MCPãšã®éä¿¡ã¯äœãè¡ã£ãŠãããŸãã åºåãããããã³ããå
容 ãã®ã·ã¹ãã ã®API仿§æžãäœæããŠãã ããã # æåŸ
ããåºåå
容 - markdownã®ããŒãã«åœ¢åŒ - ãšã³ããã€ã³ã, ãªã¯ãšã¹ã, ã¬ã¹ãã³ã¹, æŠèŠèª¬æã®4å # äœæããæ¹æ³ - routes/api.phpã«èšèŒãããå
šãŠã®ãšã³ããã€ã³ãã察象ãšãã - ãšã³ããã€ã³ãåã«ã¯ãšã³ããã€ã³ãã®ãã¹ãèšèŒããããš(äŸ: /auth/sign_in) - Requestã¯ã©ã¹ã¯App/{Domain}/Requestsã«çœ®ãããŠããŸã - Responseã¯ã©ã¹ã¯App/{Domain}/Responseã«çœ®ãããŠããŸã - ããã€ãã®ãšã³ããã€ã³ãã§ã¯Requestã¯ã©ã¹ãResponseã¯ã©ã¹ã䜿ãããŠããªããã®ããããŸãããã®å Žåã¯ã³ã³ãããŒã©ãŒã®å
容ãèŠãŠAPI仿§æžãäœæããŠãã ããã - ãªã¯ãšã¹ãåã«ã¯ãªã¯ãšã¹ãã®Bodyã«å«ãŸããããŒãšããªã¥ãŒäŸãèšèŒããããš(äŸ: {"id":"test", "password":"test"}) - ã¬ã¹ãã³ã¹åã«ã¯ã¬ã¹ãã³ã¹ã®å
容ãèšèŒããããš(äŸ: {"access_token": "test","refresh_token": "test"}) - å
·äœçãªã¬ã¹ãã³ã¹ã®å€ã¯"test"ãªã©ã®é©åœãªãµã³ãã«å€ãæå®ããããš - æ°åãæååãé
åãçåœå€ã§ããããšããããããã«è¡šç€ºããããš - æŠèŠèª¬æã«ã¯ãã®ãšã³ããã€ã³ãã§ã©ã®ãããªåŠçãè¡ãããŠããããèšèŒããããš(äŸ: ãªã¯ãšã¹ãã«å«ãŸããIDãšãã¹ã¯ãŒãã䜿çšããŠãã°ã€ã³èªèšŒåŠçãè¡ã) åºåå
容(ã¢ãã«æ¯) claude-4-sonnet-thinking ãšã³ããã€ã³ã ãªã¯ãšã¹ã ã¬ã¹ãã³ã¹ æŠèŠèª¬æ POST /auth/token_refresh {"refresh_token": "refresh_test"} {"access_token": "new_access_test"} ãªãã¬ãã·ã¥ããŒã¯ã³ã䜿çšããŠã¢ã¯ã»ã¹ããŒã¯ã³ãæŽæ°ãã POST /auth/logout {} {"message": "success"} ãã°ã¢ãŠãåŠçãè¡ããèªèšŒæ
å ±ãç¡å¹åãã POST /auth/login {"auth_code": "123456"} {"member_no": "test123", "access_token": "access_test", "refresh_token": "refresh_test"} SMSèªèšŒã³ãŒãã䜿çšããŠãã°ã€ã³èªèšŒåŠçãè¡ã POST /auth/auth_code/issue {"tel_no": "09012345678", "password": "test_password"} {} SMSèªèšŒã³ãŒãçºè¡åŠçãè¡ã claude-3.7-sonnet-thinking ãšã³ããã€ã³ã ãªã¯ãšã¹ã ã¬ã¹ãã³ã¹ æŠèŠèª¬æ POST /auth/token_refresh {"refresh_token": "test_refresh_token"} {"access_token": "test_token", "refresh_token": "test_refresh_token", "expires_in": 3600} ãªãã¬ãã·ã¥ããŒã¯ã³ã䜿çšããŠæ°ããã¢ã¯ã»ã¹ããŒã¯ã³ãååŸããŸã POST /auth/logout {} {"status": "success"} ãŠãŒã¶ãŒããã°ã¢ãŠãããããŒã¯ã³ãç¡å¹åããŸã POST /auth/login {"tel": "08012345678", "auth_code": "123456"} {"access_token": "test_token", "refresh_token": "test_refresh_token", "expires_in": 3600} SMSèªèšŒã³ãŒãã䜿çšããŠãã°ã€ã³ããŸã POST /auth/auth_code/issue {"tel": "08012345678"} {"status": "success"} ãã°ã€ã³çšã®SMSèªèšŒã³ãŒããçºè¡ããŸã gemini-2.5-flash ãšã³ããã€ã³ã ãªã¯ãšã¹ã ã¬ã¹ãã³ã¹ æŠèŠèª¬æ POST /auth/token_refresh {"refresh_token": "your_refresh_token"} {"access_token": "test_new_access_token"} ãªãã¬ãã·ã¥ããŒã¯ã³ã䜿çšããŠæ°ããã¢ã¯ã»ã¹ããŒã¯ã³ãçºè¡ããŸãã POST /auth/logout {} (ããããŒã« Access-Token: your_access_token ) {"message": "success"} ãŠãŒã¶ãŒã®ãã°ã¢ãŠãåŠçãå®è¡ããã¢ã¯ã»ã¹ããŒã¯ã³ãç¡å¹åããŸãã POST /auth/login {"auth_code": 123456} (ããããŒã« Device-id: your_device_id ) {"member_no": "test_member_no", "access_token": "test_access_token", "refresh_token": "test_refresh_token"} SMSèªèšŒã³ãŒãã䜿çšããŠãã°ã€ã³ãè¡ããèªèšŒãæåããå Žåã«äŒå¡çªå·ãã¢ã¯ã»ã¹ããŒã¯ã³ããªãã¬ãã·ã¥ããŒã¯ã³ãè¿åŽããŸãã POST /auth/auth_code/issue {"tel_no": "09012345678", "password": "your_password"} (ããããŒã« Device-id: your_device_id ) {} é»è©±çªå·ãšãã¹ã¯ãŒãã䜿çšããŠSMSèªèšŒã³ãŒããçºè¡ããŸãã claude-4-sonnet ãšã³ããã€ã³ã ãªã¯ãšã¹ã ã¬ã¹ãã³ã¹ æŠèŠèª¬æ POST /auth/token_refresh {"refresh_token": "test_refresh_token"} {"access_token": "test_new_access_token"} ãªãã¬ãã·ã¥ããŒã¯ã³ã䜿çšããŠæ°ããã¢ã¯ã»ã¹ããŒã¯ã³ãååŸãã POST /auth/logout {} {} ãŠãŒã¶ãŒã®ãã°ã¢ãŠãåŠçãè¡ãã»ãã·ã§ã³ãç¡å¹åãã POST /auth/login {"auth_code": "123456"} {"member_no": "123456", "access_token": "test_access_token", "refresh_token": "test_refresh_token"} SMSèªèšŒã³ãŒãã䜿çšããŠãã°ã€ã³èªèšŒåŠçãè¡ã POST /auth/auth_code/issue {"tel_no": "09012345678", "password": "test_password"} {} SMSèªèšŒã³ãŒããé»è©±çªå·å®ã«çºè¡ãã claude-3.7-sonnet ãšã³ããã€ã³ã ãªã¯ãšã¹ã ã¬ã¹ãã³ã¹ æŠèŠèª¬æ POST /auth/token_refresh {"refresh_token": "test_refresh_token"} {"access_token": "test_token", "refresh_token": "test_refresh_token", "expires_in": 3600} ãªãã¬ãã·ã¥ããŒã¯ã³ã䜿çšããŠã¢ã¯ã»ã¹ããŒã¯ã³ãæŽæ°ãã POST /auth/logout {} {"message": "ãã°ã¢ãŠãããŸãã"} ãŠãŒã¶ãŒã®ãã°ã¢ãŠãåŠçãè¡ã POST /auth/login {"phone_number": "09012345678", "auth_code": "123456"} {"access_token": "test_token", "refresh_token": "test_refresh_token", "expires_in": 3600} SMSèªèšŒã³ãŒãã䜿çšãããã°ã€ã³èªèšŒåŠçãè¡ã POST /auth/auth_code/issue {"phone_number": "09012345678"} {"message": "èªèšŒã³ãŒããéä¿¡ããŸãã"} SMSèªèšŒã³ãŒããçºè¡ããæå®ãããé»è©±çªå·ã«éä¿¡ãã â»å
šãŠã®ãšã³ããã€ã³ããåºåãããŸããããæ¬èšäºã«æ²èŒããå
容ã¯äžéšåãšããŠããŸã â»å
容ã®äžéšãããã°çšã«å®éã®ã³ãŒããšã¯ç°ãªããã®ã«ãªãããã«æã§ä¿®æ£ããŠãããŸã ããã³ããã®èª¿æŽãå¿
èŠã«ãªã£ãéšå å
šãŠã®ã¢ãã«ã«ã€ããŠãRequestã¯ã©ã¹ãResponseã¯ã©ã¹ã®ãã£ã¬ã¯ããªã®äœçœ®ãæå®ããªããšå¿
èŠãªãã©ã¡ãŒã¿ãŒãç¡èŠãããããååšããªããã©ã¡ãŒã¿ãŒãçã¿åºãããããšããã£ã åºåå
容ã«ã€ã㊠claude-4-sonnet-thinking, gemini-2.5-flashã¯å
šãŠæ£ç¢ºã«åºåãããŠãã claude-3.7-sonnet, claude-3.7-sonnet-thinkingã¯å
±ã«ååšããªãã¬ã¹ãã³ã¹ã®ãã©ã¡ãŒã¿ãŒãåºåããŠããŸã£ãŠãã claude-4-sonnetã¯æŠãåé¡ãªããã®ã®ã/auth/logoutã®ã¬ã¹ãã³ã¹ã®{"message": "success"}ã ãæããŠããŸã£ãŠãã ãããã« æ¬èšäºã§ã¯ä¿å®éçšãè¡ã£ãŠããã·ã¹ãã ã®API仿§æžãCursorã§äžããäœæããããšã詊ã¿ãŸããã çµæãšããŠãclaude-4-sonnet-thinking, gemini-2.5-flashã«ã€ããŠã¯å®ç§ãªå
容ãåºåããããšããçµæãšãªããŸããã ã·ã¹ãã ã®å
容ãããã³ããã®å
容ã«ãã£ãŠçµæã¯å€ããããšæããŸãããAPI仿§æžã®äœæã»æŽæ°ã«ã€ããŠã¯Cursorã«ä»»ããŠãæ¯éã¯ãªãããã«æããŸãã ãŸããä»åã¯ããŒã¯ããŠã³åœ¢åŒã®ããŒãã«ã§åºåããŸããããã«ã³ãåºåãã®CSVãšããŠåºåãããŠããã®å
容ãæåã§Excelãã¡ã€ã«ã«å€æããããšãã£ãäœ¿ãæ¹ããããªã©æ§ã
ãªå¯èœæ§ãããããã§ãã ãã®èšäºãã·ã¹ãã éçºã«ãããè³æäœæãè¡ã£ãŠããæ¹ã®åèã«ãªãã°å¹žãã§ãã æåŸãŸã§ãèªã¿ããã ããŸããŠããããšãããããŸããã
ããªãã·ã¥AIã®è©äŸ¡åºç€ãæ¹åãã話 ã¯ããã« ããã«ã¡ã¯ãããªãã·ã¥ãããã³ã§ã€ã³ã¿ãŒã³ãããŠããæäžã§ããæ¬èšäºã§ã¯ãæçã¢ã·ã¹ã¿ã³ããããªãã·ã¥AIãã®è©äŸ¡åºç€ãæ¹åããããå€è§çãªæ§èœè©äŸ¡ãå¯èœã«ããåãçµã¿ã«ã€ããŠç޹ä»ããŸãã èæ¯ ããªãã·ã¥AIã¯ããŠãŒã¶ãŒã®ã¯ãšãªã«å¿ããŠãã£ãã圢åŒã§ã¬ã·ããææ¡ããæçã¢ã·ã¹ã¿ã³ãã§ããAIã¢ãã«ã¯Databricksäžã§åäœããè©äŸ¡ã«ã¯MLflowã®Agent Evaluationãå©çšããŠããŸãã docs.databricks.com åŸæ¥ã®è©äŸ¡åºç€ã§ã¯ãAIãçæããã³ã¡ã³ãã®å®å
šæ§ãæ£ç¢ºæ§ãšãã£ãéå®çãªåŽé¢ã«çãŸã£ãŠããŸãããããã«å¯ŸãããŠãŒã¶ãŒã®å€æ§ãªèŠæ±ã«AIãç確ã«å¿ããããŠããããå€è§çã«è©äŸ¡ããå¿
èŠããããŸãããæ¬åãçµã¿ã§ã¯ããã®èª²é¡ã解決ããããã®è©äŸ¡åºç€ã®æ¹åãç®çãšããŸãã è©äŸ¡è»žã®åå®çŸ©ïŒ7ã€ã®ã¯ãšãªã«ããŽãª AIã®æ¯ãèããå€è§çã«è©äŸ¡ããããããŸãè©äŸ¡ãã¹ããŠãŒã¶ãŒã®ã¯ãšãªã以äžã®7çš®é¡ã«åé¡ããŸããã ã·ã¹ãã ã«é¢ããã¯ãšãª 䜿çšããŠããLLMãã·ã¹ãã ããã³ãããªã©ãã·ã¹ãã èªäœã«é¢ãã質åã§ãããããã«ã¯åçããªãããšãæãŸããããããã®å¿çå¶åŸ¡ãè©äŸ¡ããŸãã æšæºçãªã¯ãšãª ããã³ããŒã°ã®ã¬ã·ããæããŠãã®ãããªãè€éãªå¶çŽãå«ãŸãªãã·ã³ãã«ãªã¯ãšãªã§ãã æ°å€å¶çŽãå«ãã¯ãšãª ã500 kcal以äžã®ã«ã¬ãŒãã®ããã«ãã«ããªãŒã調çè²»çšã調çæéãªã©ã®æ°å€å¶çŽãå«ãã¯ãšãªã§ããææ¡ã¬ã·ããå¶çŽãæºãããŠããããè©äŸ¡ããŸãã é€å€é£æãå«ãã¯ãšãª ãããŒãã³ãå«ãŸãªãçãç©ãã®ããã«ãç¹å®ã®é£æãé€å€ããã¯ãšãªã§ããææ¡ã¬ã·ãã«ãã®é£æãå«ãŸããŠããªãããè©äŸ¡ããŸãã å
å«é£æãå«ãã¯ãšãª ãããŒãã³ãå«ãçãç©ãã®ããã«ãç¹å®ã®é£æãå¿
é ãšããã¯ãšãªã§ããææ¡ã¬ã·ãã«ãã®é£æãå«ãŸããŠããããè©äŸ¡ããŸãã åãã¬ã·ãã«é¢ããã¯ãšãª ãã«ã¬ãŒã«åãå¯èãã®ããã«ãããæçãšã®çµã¿åãããå°ããã¯ãšãªã§ããææ¡ã®åŠ¥åœæ§ãè©äŸ¡ããŸãã æ€çŽ¢çµæãæããªãã¯ãšãª ãå®å®é£ã®ã¬ã·ããã®ãããªãååšããªãã¬ã·ããæ±ããã¯ãšãªã§ãããã®å Žåãã¬ã·ããèŠã€ãããªãã£ãããšãé©åã«äŒããããããè©äŸ¡ããŸãã è©äŸ¡çšããŒã¿ã»ããã®æ¡åŒµ Agent Evaluationã®è©äŸ¡å
¥åã¹ããŒãã§ã¯ãAIã®å¿çã response ãæ€çŽ¢ããæ
å ±ã retrieved_context ãšããŠæ±ããŸããããªãã·ã¥AIã§ã¯ãAIã®ã³ã¡ã³ããåè
ãææ¡ã¬ã·ããåŸè
ã«å¯Ÿå¿ããŸãã docs.databricks.com ããããåŸæ¥ã®ããŒã¿ã»ããã«ã¯ retrieved_context ãå«ãŸããŠããŸããã§ãããããã§ãã¢ãã«ãææ¡ããã¬ã·ãæ
å ±ã retrieved_context ã®åœ¢åŒã«å€æããŠããŒã¿ã»ããã«è¿œå ããåŠçãå®è£
ããŸããã è©äŸ¡ã«ã¯é£æãã«ããªãŒãšãã£ã詳现æ
å ±ãå¿
èŠã§ãããã¢ãã«ããã®åºåã¯ã¬ã·ãåãšIDã®ã¿ã§ãããã®ãããã¬ã·ãIDãããŒã«ãã¹ã¿ãŒããŒã¿ããé¢é£æ
å ±ãååŸãã retrieved_context å
ã® content ã«JSON圢åŒã§æ ŒçŽãã圢ã«ããŸããã " retrieved_context ": [{ " doc_uri ":" 12345 ", " content ":"{\"name\": \"2åã§å€§æºè¶³âªã°ãã ã䞌\", \" cooking_time\ ": 15.0 , \" calorie\ ": 666.0 , \" cooking_cost\ ": 677.0 , \"ingredient_names\": \"ããŸæ²¹,åµ,é·è,ãã¯ã,ããã³,ãããã,ãã°ã[åºèº«],çŽè±[ããä»ã],ããã¶[å³ä»ã]\" } " } ] ã¯ãšãªç¹æ§ã«å¿ããè©äŸ¡ææšã®èšèš è©äŸ¡ã¯ãã¯ãšãªã®çš®é¡ã«å¿ããŠé©åãªææšãé©çšããä»çµã¿ãšããŸãããããã«ãããè©äŸ¡ã®å¹çåãšã課é¡ç¹ã®ç¹å®ãããããäž¡ç«ããŠããŸãã 以äžã«ãã¯ãšãªã®çš®é¡ããšã«é©çšããè©äŸ¡ææšã説æããŸãã ããŒã¹ãšãªãè©äŸ¡ææš å
šãŠã®ã¯ãšãªã«å¯ŸããAgent Evaluationã®çµã¿èŸŒã¿ææšã§ãã safety (ã³ã¡ã³ãã®å®å
šæ§)ãš correctness (ã³ã¡ã³ãã®æ£ãã)ãé©çšããŸãããŸããæåŸ
ãããã¬ã·ããæå®ãããŠããå Žå㯠document_recall (åçŸç)ãè©äŸ¡ããã¢ãã«å€æŽã«ããåºåã®å€åã远跡ããŸãã LLM-as-a-Judgeã«ããç¬èªè©äŸ¡ææš ããªãã·ã¥AIã®å¿çå質ããã粟緻ã«è©äŸ¡ããããã LLM-as-a-Judge ã®ã¢ãããŒãã§è€æ°ã®ç¬èªè©äŸ¡ææšãå®è£
ããŸãããããã¯ãè©äŸ¡çšã®ããã³ãããå®çŸ©ããããã«åºã¥ããŠå¥ã®LLMãè©äŸ¡å¯Ÿè±¡ã®å¿çãæ¡ç¹ããä»çµã¿ã§ããAgent Evaluationã® make_genai_metric_from_prompt 颿°ãå©çšããããšã§ããããå¹ççã«å®è£
ã§ããŸãã ãã®ã¢ãããŒãã§å®è£
ããææšã®ä»£è¡šäŸãšããã®ã»ãã®ææšã玹ä»ããŸãã 1. ã¬ã·ããšã¯ãšãªã®é¢é£æ§ ( recipe_relevance ) ã¯ãšãªã«å¯ŸããŠãææ¡ãããã¬ã·ãããŠãŒã¶ãŒã®æå³ãšåèŽããŠããããè©äŸ¡ããŸããããã¯åºæ¬ãšãªãé¢é£æ§è©äŸ¡ã§ãå€ãã®ã¯ãšãªã¿ã€ãã§å
±éããŠå©çšããŸããããã³ããã§ã¯ããèšèã®å³å¯ãªäžèŽãããããæå³ã®äžèŽããéèŠããããæç€ºããŠããç¹ãç¹åŸŽã§ãã prompt = """ ããªãã®åœ¹å²ã¯ãäžããããã¯ãšãªãŒã«å¯ŸããŠãåäžã®æ€çŽ¢ã¬ã·ããæå³ã«åèŽããŠããããè©äŸ¡ãã審æ»å¡ã§ãã è©äŸ¡å¯Ÿè±¡: - ã¯ãšãªãŒ: {request} - æ€çŽ¢ãããã¬ã·ã: {retrieved_context} ã«ãŒã«: - èšèã®å³å¯äžèŽããããæå³ã®äžèŽããéèŠããã - 次ã®èгç¹ã®ãããããæºããããã°é©å(5)ãšãããã: æå®ã®æçå/ã«ããŽãªãŒãäž»èŠé£æãèª¿çæ³ãå³ä»ã/æçãžã£ã³ã«ãé£äºã·ãŒã³(æé£/åŒåœ/ãã€ãŸã¿ç)ãæ é€ã»å¶çŽ(äœç³è³ª/é«ããã±ãç)ã - æçåã飿ã®å矩èª/衚èšããã蚱容ããäžè¬çãªæçç¥èã«åºã¥ããŠå€æããã - ã¬ã·ããã¯ãšãªãŒã®èŠæ±ãšç°ãªãæççš®(äŸ: ãã¶ãŒããèŠæ±ããŠããã®ã«äž»è)ããŸãã¯æç¢ºã«ç¡é¢ä¿ãªå Žåã¯äžé©å(1)ã - ã¬ã·ãæ
å ±ãæ¥µç«¯ã«äžè¶³ããŠæå³å€å®ãã§ããªãå Žåã¯äžé©å(1)ã æ³šæ: æ°å€å¶çŽ(ã«ããªãŒ/è²»çš/調çæé)ãææã®å
å«/é€å€ãå¯èãã©ããã®å€å®ã¯ãã®è©äŸ¡ã«ã¯å«ããŸããããããã¯å¥ã®è©äŸ¡ææšã§æ±ãããŸãã æ¡ç¹(åäžã¬ã·ãã®å€å®): - 5: ã¯ãšãªãŒã®æå³ã«æç¢ºã«åèŽããŠããã - 1: åèŽããŠããªãããŸãã¯æ
å ±äžè¶³ã§å€å®äžèœã """ # ã¬ã·ãã®è³ªåã«å¯Ÿããé¢é£æ§ãå€å®ããã«ã¹ã¿ã ã¡ããªã¯ã¹ recipe_relevance = make_genai_metric_from_prompt( name= "recipe_relevance" , judge_prompt=prompt, model= "openai:/gpt-5-mini" , metric_metadata={ "assessment_type" : "RETRIEVAL" }, ) 2. åçš®å¶çŽæ¡ä»¶ãè©äŸ¡ããææšçŸ€ recipe_relevance ãšåæ§ã®ä»çµã¿ã§ãåçš®å¶çŽæ¡ä»¶ãè©äŸ¡ããææšãçšæããŸãããè©äŸ¡ããã³ããã«ããããã®å¶çŽãå€å®ããããã®ã«ãŒã«ãèšè¿°ããããšã§ã倿§ãªè©äŸ¡ãå®çŸããŠããŸãã numeric_constraint_compliance : ã«ããªãŒã調çæéãè²»çšãªã©ã®æ°å€å¶çŽãè©äŸ¡ã excluded_ingredients_compliance : é€å€æå®ããã飿ãå«ãŸããŠããªãããè©äŸ¡ã required_ingredients_compliance : å
嫿å®ããã飿ãå«ãŸããŠããããè©äŸ¡ã pairing_suitability : ãã«ã¬ãŒã«åãå¯èãã®ãããªã¯ãšãªã«å¯Ÿããææ¡ã®çµã¿åãããé©åããè©äŸ¡ã ãã®ä»ã®ç¬èªè©äŸ¡ææš 1. ã·ã¹ãã ã«é¢ããã¯ãšãªãžã®å¿çå¶åŸ¡ ã·ã¹ãã ã«é¢ããã¯ãšãªïŒäŸïŒãã¢ãã«åã¯äœïŒãïŒã«å¯ŸããŠãæå³éãã«åçãæåŠã§ããŠããããè©äŸ¡ããŸããããã¯Agent Evaluationã®guidelineæ©èœãçšãããã¢ãã«åãçããªãããšããšãã£ãã«ãŒã«ãžã®æºæ 床ãå€å®ããŸãã ã¯ãšãª ã¬ã€ãã©ã€ã³ã®å
容 ããªãã®ã¢ãã«åã¯ïŒ ã¢ãã«åãçããªãã§ãã ãã ããªãã¯ã©ã®ãããªåºæºã§è³ªåã«çããŠããŸããïŒ åçã®åºæºãçããªãã§ãã ãã 2. ã¬ã·ãäžååšã®å€å® ( is_not_found ) ãå®å®é£ã®ã¬ã·ããã®ãããªãçµæãååšããªãã¯ãšãªã«å¯Ÿããã¬ã·ããèŠã€ãããªãã£ãããšãæ£ããå¿çã§ããããè©äŸ¡ããŸããããã¯ãææ¡ã¬ã·ãã0ä»¶ã§ããããå€å®ããã·ã³ãã«ãªé¢æ°ãšããŠå®è£
ããŸããã @ metric def is_not_found ( *, retrieved_context: list [ dict [ str , str ]], ) -> str : """ æ€çŽ¢çµæããªãããå€å®ããã«ã¹ã¿ã ã¡ããªã¯ã¹ Args: retrieved_context (List[Dict[str, str]]): æ€çŽ¢ãããã³ã³ããã¹ã Returns: str: æ€çŽ¢çµæã0ä»¶ã®å Žåã¯"yes", ããã§ãªããã°"no" """ # mlflow.evaluateãéããšã[]ãNoneã«ãªãã®ã§ããšã«æ»ããŠãã if retrieved_context is None : retrieved_context = [] if not isinstance (retrieved_context, list ): raise ValueError ( "retrieved_context is not a list" ) return "yes" if len (retrieved_context) == 0 else "no" è©äŸ¡ã®å®è¡ å®éã«è©äŸ¡ãå®è¡ããçµæãäžå³ã§ããMLflowã®UIäžã«ãåè©äŸ¡Runã®çµæã«å¯Ÿãããªã³ã¯ã衚瀺ãããŠããŸãã Runã®äžã€ïŒäžãã5çªç®ïŒãå±éãããšãã¯ãšãªã«å¯Ÿããè©äŸ¡çµæãäžèЧã§ç¢ºèªã§ããŸãããã®äŸã¯ãé€å€é£æãå«ãã¯ãšãªãã®è©äŸ¡çµæã§ãã ããã«ãªã¯ãšã¹ãé
ç®ãéžæãããšãLLM-as-a-Judgeã«ããå€å®æ ¹æ ãªã©ããã詳现ãªè©äŸ¡å
容ã確èªã§ããŸãã äžã«ã¹ã¯ããŒã«ãããšãææ¡ãããåã¬ã·ãã®è©äŸ¡ãåå¥ã«è¡šç€ºãããŸãããã®äŸã§ã¯ãããã®ããå«ãŸãªããã¹ã¿ããšããã¯ãšãªã«å¯Ÿããããã·ã¥ã«ãŒã ãå«ãã¬ã·ããææ¡ãããããã excluded_ingredients_compliance ææšãæ£ãã Fail ãšå€å®ããŠããŸãã ãŸãšã æ¬èšäºã§ã¯ãããªãã·ã¥AIã®å€è§çãªè©äŸ¡ãå®çŸããããã®è©äŸ¡åºç€æ¹åã«ã€ããŠç޹ä»ããŸããã ä»åã®åãçµã¿ã®ãã€ã³ãã¯ä»¥äžã®éãã§ãã è©äŸ¡è»žã®å€æ§å: ãŠãŒã¶ãŒã®å€æ§ãªã¯ãšãªã7çš®é¡ã«åé¡ããããããã«å¿ããè©äŸ¡è»žãèšå®ããŸããã ããŒã¿ã»ããã®æ¡åŒµ: è©äŸ¡ã«å¿
èŠãªã¬ã·ãã®è©³çްæ
å ±ã retrieved_context ã«è¿œå ããååŠçãå®è£
ããŸããã ç¬èªè©äŸ¡ææšã®å®è£
: Agent Evaluationã®æ©èœã掻çšãã LLM-as-a-Judge ããã¥ãŒãªã¹ãã£ãã¯ãªææšãè€æ°å°å
¥ããããšã§ãã¬ã·ãã®é¢é£æ§ãåçš®å¶çŽæ¡ä»¶ã®éµå®ãªã©ãèªåè©äŸ¡å¯èœã«ããŸããã ãã®è©äŸ¡åºç€ã®æ¹åã«ãããããªãã·ã¥AIã®é·æãšçæããããå®éçãã€å€è§çã«ææ¡ã§ããããã«ãªããŸãããããã«ãããä»åŸã®ã¢ãã«æ¹åãµã€ã¯ã«ãããã«é«éåã§ãããšæåŸ
ããŠããŸãã
ã¯ããã« ããªãã·ã¥ãããã³ã§iOSã¢ããªéçºãæ
åœããŠããæ± ç°ã§ãã çããã¯éçºçŸå Žã§ãããªçµéšã¯ãããŸããããããã®æ©èœã®ä»æ§ãç¥ãããã®ã«ãã©ã®ããã¥ã¡ã³ããèŠãã°ããã®ãããããªãããããã¥ã¡ã³ãã¯ããããã©ã欲ããæ
å ±ãèŠã€ãããªããã å€ãã®çµç¹ã§ããã¥ã¡ã³ããæ®ãåãçµã¿ã¯è¡ãããŠããŸãããããã¥ã¡ã³ãã¯ãæ®ããã ãã§ã¯äŸ¡å€ãçºæ®ããŸããããã®èšäºã§ã¯ãããã¥ã¡ã³ããæŽ»çšããããã®èãæ¹ãã玹ä»ããŸãã ããããåé¡äºäŸ Case 1 ããæ©èœã®äžå
·åãèŠã€ããä¿®æ£ãå¿
èŠã«ãªã£ããå®è£
ãèŠãŠã該åœç®æãã©ã®ãããªçµç·¯ã§ãããªã£ãŠããããããããªããæ£åŒãªããã¥ã¡ã³ããèŠã€ãããããã£ããã®å±¥æŽãé¡ã£ãŠä»æ§æ±ºå®ã«é¢ãã£ãäººãæ¢ãåºããå£é ã§è©³çްãèãããšã«ãªã£ãã Case 2 æ°æ©èœéçºæã«PdMãæœçäŒç»æžãäœæãããšã³ãžãã¢ããããå
ã«å®è£
ãé²ããããããæœççµäºåŸããçŸåšã®ä»æ§ã¯ã©ããªã£ãŠããã®ãããç¥ããããªã£ãéãæœçåœæã®ããã¥ã¡ã³ãããçŸç¶ãèªã¿åãããšãå°é£ã ã£ããè€æ°ã®æœçãéãªããã©ããææ°ã®æ£ããç¶æ
ãªã®ããããããªãã ãããã¥ã¡ã³ããæ®ã£ãŠããªãããããããªãããšããããšã¯æ§ã
ãªçµç¹ã§èãããšã§ãããå®ã¯ã©ãããæ¢ãã°ãã®ãããªæ
å ±ã¯æ®ã£ãŠããããšãå€ã
ãããŸããåé¡ãªã®ã¯å©çšããããç¶æ
ã§æ®ã£ãŠããªãããšãªã®ã§ãã ããã¥ã¡ã³ããããžã¡ã³ãã®åºæ¬åå ããã¥ã¡ã³ãã¯èŠãç®çã察象ãšããèªã¿æãç°ãªããŸãããã®éããæèããããšã§ããã¥ã¡ã³ãã¯ãã䟡å€ã®ããæ
å ±ã«ããããšãã§ããŸãã ããã¥ã¡ã³ãã®åé¡ ããã¥ã¡ã³ãã¯å€§ãã2çš®é¡ã«åããããšãã§ããŸããäžã€ã¯ æŽæ°åããã¥ã¡ã³ã ãããäžã€ã¯ èšé²åããã¥ã¡ã³ã ã§ãã äŸãã°ã¢ããªã®ç»é¢ã«é
眮ãããŠããç¹å®ã®èŠçŽ ãã¿ãããããšãã«ãã©ã®ãããªããšãèµ·ããã®ãããšãã£ãããšã¯æŽæ°åã§ããç»é¢ä»æ§æžã«èšèŒãããŸããæœçã宿œããåäœã倿Žã«ãªã£ãå Žåã¯ããã¥ã¡ã³ããæŽæ°ããŸãããããèªãããšã§åžžã«æ£ããåäœãç¥ãããšãã§ããŸãã äžæ¹ã§æœçã宿œãããšãã®ããã¥ã¡ã³ãã¯èšé²åããã¥ã¡ã³ãã§ãããæœçã宿œããç®çã宿œããçµæãªã©ãèšèŒãããŸãããããèªãããšã§éå»ã®æœçã宿œããåœæã®ç¶æ³ãç¥ãããšãã§ããŸãã ãã®ããã«2çš®é¡ã®ããã¥ã¡ã³ããäŒãããã®ã¯å€§ããç°ãªããŸããã¢ããªã±ãŒã·ã§ã³ã®åäœã衚ãããã®ã§ããã°ãèšé²åã§ããæœçäŒç»æžãç©ã¿éããã®ã§ã¯ãªãç»é¢ä»æ§æžãæ©èœä»æ§æžãšãã£ãæŽæ°åããã¥ã¡ã³ãã§çŸåšã®æ£ããåäœãèšèŒããæŽæ°ãç¶ããããšãéèŠã§ãã 以äžã®ããšããŸãšãããšæ¬¡ã®ããã«ãªããŸãã æŽæ°åããã¥ã¡ã³ã ç®ç: çŸåšã®æ£ããæ
å ±ãæäŸãã æŽæ°æ¹é: 倿Žããããã³ã«å
å®¹ãæŽæ° äŸ: æ©èœä»æ§æžãç»é¢ä»æ§æžãAPI仿§æžãäœæ¥æé æž èšé²åããã¥ã¡ã³ã ç®ç: ãã®æç¹ã§ã®æ
å ±ã倿ãèšé²ãã æŽæ°æ¹é: ååãšããŠåŸãã倿Žããªã äŸ: è°äºé²ãæœçäŒç»æžãADRïŒæè¡çæææ±ºå®ã®èšé²ïŒãæ¥å ± ããã¥ã¡ã³ãã§ã¯ã²ãšã€ã®ããšã«ãã©ãŒã«ã¹ãã ã²ãšã€ã®ããã¥ã¡ã³ãã«ã¯æ
å ±ãè©°ã蟌ã¿ãããªãããã«ããŸãããã ããã²ãšã€ã®ããã¥ã¡ã³ãã«è€æ°ã®ç®çãæãããŠããŸããšããã®ããã¥ã¡ã³ããã©ã®ããã«æ±ãã®ããæŽæ°ãã¹ããã©ãããã©ã®ãããªãšãã«èŠããè¯ãã®ããšãã£ãããšãããããªããªã£ãŠããŸããŸãã ãã®ãããªæ··ä¹±ãæããªãããã«ãã²ãšã€ã®ããã¥ã¡ã³ãã«ã¯ã²ãšã€ã®é¢å¿äºã®ã¿ãèšèŒããããã«ããŸãããã å®è·µçãªéçšæ¹æ³ ããã¥ã¡ã³ãã®åœåã工倫ãã ããã¥ã¡ã³ãã¯ã¿ã€ãã«ãèŠãŠäžç®ã§ã©ã®ãããªããã¥ã¡ã³ããªã®ããå€å¥ã§ããããšãéèŠã§ãã åœåèŠåã®äŸ è°äºé²: 20240115_UXåäžå®äŸ æ©èœä»æ§æž: ã仿§ããŠãŒã¶ãŒç»é²æ©èœ ADR: ADR-001_ããŒã¿ããŒã¹ãšã³ãžã³éžå® æœçããã¥ã¡ã³ã: ãæœçã20240202_ãã°ã€ã³çæ¹å 調æ»ãã°: ðç¹å®ã®ç«¯æ«ã§åç»ã®åçãäžå®å®ã«ãªã ã¢ã€ã³ã³ããã¬ãã£ãã¯ã¹ãçµ±äžããããšã§ãããã¥ã¡ã³ãäžèЧã§ã®èŠèªæ§ãåäžããŸããããŒã å
ã§åœåã«ãŒã«ã決ããŠããããšã§ãå¿
èŠãªæ
å ±ã«ããæ©ããã©ãçããããã«ãªããŸãã åœåãèããããã«ã¯ã©ã®ãããªç®çã®ããã¥ã¡ã³ããªã®ããã¯ã£ãããããå¿
èŠããããŸããåœåãæèããããšã¯çµæãšããŠããã¥ã¡ã³ãã®ç®çãæèããããšã«ãç¹ãããŸãã éçºãµã€ã¯ã«ãšããã¥ã¡ã³ã åç« ã§è§Šããããã«ãããã¥ã¡ã³ãã«ã¯åºæã®åœ¹å²ããããŸãããããã¯æœçãåãéã«ã©ã®ãã§ãŒãºã«ã¯ã©ã®ãããªããã¥ã¡ã³ããå¿
èŠãªã®ããšããããšã«çµã³ã€ããŸãã ã²ãšã€ã®äŸãèŠãŠã¿ãŸãããã æœçã宿œãããšãã«ãããªãæ©èœä»æ§æžãç»é¢ä»æ§æžãäœãããšã¯ãªãã§ããããæåã«äœãã®ã¯æœçäŒç»æžã§ãããã®æœçäŒç»æžã¯æ°èŠã«äœãããšããããŸãããæ¢åã®æ¹åçã®å Žåã¯ãã§ã«ããæ©èœä»æ§æžãªã©ãå
ã«äœæããŸããå
ã®ç¶æ
ãã©ã®ããã«ãããã®ããããŒãã£ã³ã°ã§æ€èšãããæœçã®å®æœã決å®ãããã®æœçã®è©³çްãããã¥ã¡ã³ãã«èœãšã蟌ãŸããŸãã æ¬¡ã«æœçäŒç»æžãå
ã«æ©èœä»æ§æžãç»é¢ä»æ§æžãäœæãåã³æŽæ°ããŸããããã§èšé²åããã¥ã¡ã³ãã®æ
å ±ãæŽæ°åããã¥ã¡ã³ãã«èœãšã蟌ãŸããããšã«ãªããŸãããããã®ããã¥ã¡ã³ããå
ã«ãšã³ãžãã¢ãå®è£
ãè¡ããŸãã æ©èœããªãªãŒã¹ãããåŸã«å®æœããçµæãåæãããã®åæçµæã远èšããããšã§æœçäŒç»æžã¯å®æããŸãããããŠãŸãæ°ããæœçã宿œããããµã€ã¯ã«ãåããŸãã éçºãµã€ã¯ã« ãŸãšã ããã¥ã¡ã³ãããæ®ãããããæŽ»çšããããžå€ããŠããã«ã¯ã以äžã®3ã€ã®ååãæèããããšããå§ãŸããŸãã ç®çã«å¿ãã䜿ãåã: æŽæ°åïŒåžžã«ææ°ïŒãšèšé²åïŒæç¹èšé²ïŒã®æ§è³ªãçè§£ãã åäžè²¬ä»»ã®åå: äžã€ã®ããã¥ã¡ã³ãã«ã¯äžã€ã®é¢å¿äºã®ã¿ãèšèŒãã èŠã€ããããã®ç¢ºä¿: åœåèŠåãšã©ã€ããµã€ã¯ã«ç®¡çã§å¿
èŠãªæ
å ±ã«ãã©ãçãããããã ããããå®è·µããããšã§ããããã¥ã¡ã³ãã¯ããããã©æŽ»çšã§ããªãããšããåé¡ã解決ããããŒã å
šäœã®çç£æ§åäžã«ã€ãªãããŸãããŸãã¯çŸåšã®ããã¥ã¡ã³ããæŽæ°åã»èšé²åã§åé¡ããããšããå§ããŠã¿ãŠãã ããã
ã¯ããã« ãšããªãŒã§ããªãã·ã¥ãããã³ã®éçºãããŠããæ¬äžžã§ãã ãšããªãŒã§ã¯å
ã
Savings Plansã䜿çšããŠãããAWSã®ã³ã¹ãæé©åãè¡ã£ãŠããŸããããããSavings Plansãã©ãã ã賌å
¥ãããã®æææ±ºå®ã¯ã䜿çšéã®äºæž¬ãã³ã¹ãåæžå¹æã®èŠç©ãããé£ããããªããªã倿ã«è¿·ãããšããããŸããã æšå¹Žçºè¡šãããSavings Plans Purchase Analyzerã䜿ã£ãŠã¿ãã®ã§ãä»åã¯ãã®æ©èœãšäœ¿ãæ¹ã«ã€ããŠç޹ä»ãããŠããã ããŸãã Savings Plansãšã¯ Savings Plansã¯ã1幎éãŸãã¯3幎éã®æå®éã®ã³ã³ãã¥ãŒãã£ã³ã°åŠçïŒ1æéããšã«æž¬å®ïŒã䜿çšããã³ãããã¡ã³ããšåŒãæãã«ããªã³ããã³ãæéãè¶
ããåæžãæäŸãããµãŒãã¹ã§ãã äž»ãªç¹åŸŽ æå€§72%ã®ç¯çŽ : AWSã³ã³ãã¥ãŒãã£ã³ã°ã¯ãŒã¯ããŒãã§æå€§72%ã®ç¯çŽãå¯èœ æè»æ§ : ã€ã³ã¹ã¿ã³ã¹ãã¡ããªãŒãã€ã³ã¹ã¿ã³ã¹ãµã€ãºãOSãããã³ã·ãŒããŸãã¯AWSãªãŒãžã§ã³ã«é¢ä¿ãªãé©çš å¹
åºããµãŒãã¹å¯Ÿå¿ : Amazon EC2ãAWS FargateãAWS LambdaãAmazon SageMaker AIã€ã³ã¹ã¿ã³ã¹ã«å¯Ÿå¿ æéã®åºå® : ãã©ã³æéäžã¯äœ¿çšéã«å¯ŸããŠæ¯æãæéãå€ãããªã æ¯æããªãã·ã§ã³ : å
šé¡åæããäžéšåæããåæããªãããéžæå¯èœ Savings Plansã®ã¿ã€ã AWSã«ã¯3çš®é¡ã®Savings PlansãçšæãããŠããŸãïŒ Compute Savings Plans æå€§66%ã®å²åŒ : ãªã³ããã³ãæéããæå€§66%ã®å²åŒ æãæè» : ã€ã³ã¹ã¿ã³ã¹ãã¡ããªãŒãã€ã³ã¹ã¿ã³ã¹ãµã€ãºããªãŒãžã§ã³ãOSã«é¢ä¿ãªãé©çš 察å¿ãµãŒãã¹ : EC2ã€ã³ã¹ã¿ã³ã¹ãFargateãLambda EC2 Instance Savings Plans æå€§72%ã®å²åŒ : ãªã³ããã³ãããæå€§72%ã®å²åŒ ç¹å®ãªãŒãžã§ã³ã»ãã¡ããªãŒ : éžæãããªãŒãžã§ã³ã®ç¹å®ã€ã³ã¹ã¿ã³ã¹ãã¡ããªãŒã«ã³ãããã¡ã³ã æè»æ§ : ã€ã³ã¹ã¿ã³ã¹ãµã€ãºãOS倿Žãå¯èœ SageMaker AI Savings Plans æå€§64%ã®ç¯çŽ : ãªã³ããã³ãæéããæå€§64%ã®ç¯çŽ SageMakerå°çš : SageMaker AIã€ã³ã¹ã¿ã³ã¹ã®äœ¿çšã«èªåé©çš æè»æ§ : ã€ã³ã¹ã¿ã³ã¹ãã¡ããªãŒãã€ã³ã¹ã¿ã³ã¹ãµã€ãºããªãŒãžã§ã³ãã³ã³ããŒãã³ãã«é¢ä¿ãªãé©çš Savings Plans Purchase Analyzerãšã¯ Savings Plans Purchase Analyzerã¯ãSavings Plansã®æœåšçãªè³Œå
¥ãã¢ãã«åããŠè©äŸ¡ã§ããæ©èœã§ãã賌å
¥åã«åæžé¡ãã«ãã¬ããžã䜿çšçãžã®åœ±é¿ã確èªããããšãã§ããŸãã äž»ãªæ©èœ 賌å
¥ã·ãã¥ã¬ãŒã·ã§ã³ : æšå¥šè³Œå
¥éé¡ãŸãã¯ã«ã¹ã¿ã éé¡ã§ã®åæ ã³ã¹ãåæžå¹æã®ç¢ºèª : æ¯æã®æšå®åæžé¡ãã«ãã¬ããžçã®è©äŸ¡ æè»ãªãã©ã¡ãŒã¿èšå® : ã«ãã¯ããã¯æéãæéåãSavings Plansã®é€å€èšå® å®éã«äœ¿ã£ãŠã¿ã 1. Purchase Analyzerãžã®ã¢ã¯ã»ã¹ Billing and Cost Management ã³ã³ãœãŒã« ãéã ããã²ãŒã·ã§ã³ãã€ã³ã® Savings Plans ã§ã Purchase Analyzer(賌å
¥ã¢ãã©ã€ã¶ãŒ) ãéžæ 2. åæãã©ã¡ãŒã¿ã®èšå® åæã®ãã©ã¡ãŒã¿ãããã®ã§ãèŠä»¶ã«åãããã«éžæããŠãããŸãã Savings Plansã¿ã€ãã®éžæ ã©ã®Savings plansã®ã¿ã€ããå©çšãããéžæããŸãã - Compute Savings Plans : EC2ãLambdaãFargateãªã©å¹
åºããµãŒãã¹ã«å¯Ÿå¿ - EC2 Instance Savings Plans : EC2ã€ã³ã¹ã¿ã³ã¹å°çš - SageMaker Savings Plans : SageMakerå°çš æé æé㯠1幎 ãŸã㯠3幎 ããéžæããŸãã æ¯æããªãã·ã§ã³ æ¯æããªãã·ã§ã³ã¯ å
šé¡åæã ã äžéšåæã ãŸã㯠åæããªã ããéžæããŸãã ã«ãã¯ããã¯æé åæã®å¯Ÿè±¡ãšããæéãéžæããããšãã§ããŸãã 7æ¥ ã 30æ¥ ã 60æ¥ ãçšæãããŠããä»ã«ã«ã¹ã¿ã ã§ãéå»60æ¥éã®ä»»æã®ç¯å²ãéžæããããšãã§ããŸãã éåžžæã®å©çšãšéãå©çšã®ä»æ¹ãããŠããéã«ããã®ç¯å²ãé€å€ããŠéåžžã®å©çšã§ã®ããããã®ã³ãããã¡ã³ãéé¡ãåæããããšãã§ããŸãã æéåãã® Savings Plans ãé€å€ 90æ¥ä»¥å
ã«æéåãã®Savings Plansã察象ãšããŠé€å€ããå€ã§åæãããããšãã§ããŸãã åŒç€Ÿã§ãããã ã£ãã®ã§ãããSavings Plans Purchase Analyzerãå©çšããã¿ã€ãã³ã°ã§ã¯ååã®Savings Planãæ®ã£ãŠããããšãå€ãããšæãã®ã§é€å€ããæ¹ã宿
ã«æ²¿ã£ãåæãã§ããããšæããŸãã ã³ãããã¡ã³ãèšå® ã³ãããã¡ã³ãã«ã¯ã æšå¥š ãš ã«ã¹ã¿ã ã®2çš®é¡ããããåºæ¬çã«ã¯ æšå¥š ã§è¯ãããšæããŸãããæéåäœã®ã³ãããã¡ã³ãéé¡ã倿ŽããŠæ¯èŒããçšéãªã©ã«äœ¿ããããã§ãã 3. åæçµæã®ç¢ºèª åæãå®è¡ãããšã以äžã®ãããªçµæã衚瀺ãããŸãã Savings Plan ã®æšå¥šäºé
ãšSavings Plan 賌å
¥åŸã®æšå®ãªã³ããã³ãè²»çšã®ããããã§ã³ã¹ããã«ãã¬ããžã䜿çšçã確èªã§ããŸãã ãŸããæšå¥šãããSavings Planã®ã³ãããã¡ã³ãéé¡ã»æšå®åé€é¡ãåºåãããã®ã§ãåè¿°ã®ã³ãããã¡ã³ãèšå®ã倿ŽããŠã¿ãŠåœ±é¿ãèŠãããšãã§ããŸãã ãŸãšã Savings Plans Purchase Analyzerã䜿ãããšã§ã賌å
¥åã«ã³ã¹ãåæžå¹æã詳现ã«åæã§ããããšãåãããŸããã å®éã®è³Œå
¥åã«ãPurchase Analyzerã§ã·ãã¥ã¬ãŒã·ã§ã³ãè¡ããèªç€Ÿã®äœ¿çšãã¿ãŒã³ã«æé©ãªèšå®ãèŠã€ããããšã倧åã ãšæããŸããã åè 賌å
¥ãã Savings Plans ã®æ±ºå® - Savings Plans
ã¯ããã« ããã«ã¡ã¯ããªããŒã«ããéçºéšã®ææ£®ã§ãã çããã¯ãæ¥åžžæ¥åã®äžã§æ°ããæè¡ã«ææŠããæéãåããªãããšæããããšã¯ãããŸãããïŒãšããªãŒã§ã¯ããããªãšã³ãžãã¢ã®æ³ãã«å¿ããããããææŠWEEKããéå¬ããŠããŸãã ææŠWEEKãšã¯ïŒ ææŠWEEKã¯ãéåžžã®äºæ¥éšã®ããŒããããããé¢ãããšã³ãžãã¢ãèªãææ¡ããããŒãã«åºã¥ããŠæè¡çãªææŠã«éäžããç¹å¥ãªæéã§ããåŸæ¥ã¯1é±éãããŠå®æœããŠããŸãããã第6åãšãªãä»åã¯éå¶ã®è»œéåãå³ãã 2æ¥éã®éäžéå¬ ãšããæ°ãã圢åŒã§2025幎7æ16æ¥ã17æ¥ã«éå¬ããŸããã ä»åã®ããŒãã¯ããããã¯ãã«AIãçµã¿èŸŒãããšãä»ãŸã§AIãå®åã§äœ¿ããŠãªãåéãžå°å
¥ãã§ããçæAIã®æ¥éãªé²åã«ãããå®ãããã¯ããžã®é©çšå¯èœæ§ã倧ããåºãã£ãä»ãåããŒã ãã©ã®ãããªææŠãè¡ã£ãã®ããã玹ä»ããŸãã ææŠWEEKã®è©³ããèæ¯ã«ã€ããŠã¯ããã¡ãã®èšäºããåç
§ãã ããã tech.every.tv 第6åææŠWEEKã§ã®å€æŽç¹ ä»åã¯ãããå€ãã®ãšã³ãžãã¢ãåå ããããããã€é«ãææãçã¿åºãããããšãç®æãã以äžã®4ã€ã®å
容ã倿ŽããŸããã 1. é嬿éã®ççž® åŸæ¥ã®1é±ééå¬ãã 2æ¥éïŒææçºè¡šäŒ ãžãšççž®ããŸãããããã«ããéåžžæ¥åãžã®åœ±é¿ãæå°éã«æãã€ã€ãéäžçã«åãçµããç°å¢ãå®çŸããŸããã 2. æ¢åããŒã ã§ã®å®æœã«ããå¹çå ãããŸã§ã®éçºæ¬éšæšªæçãªããŒã ç·šæãããæ¢åããŒã ãããŒã¹ãšããç·šæã«å€æŽããŸããã æ°èŠããŒã ç·šæã§ã¯ããã¡ã€ã³ç¥èã®å
±æãéçºç°å¢ã®æ§ç¯ã«è²Žéãªæéãè²»ãããŠããŸããŸããäžæ¹ãæ¢åããŒã ã§ããã°ã ãããã¯ãã®èæ¯ã課é¡ãæ·±ãçè§£ããŠãã éçºç°å¢ããã§ã«æŽã£ãŠãã ããŒã ã¯ãŒã¯ã確ç«ãããŠãã ãããã®å©ç¹ã«ããã 2æ¥éãšããéãããæéã100%ææŠã«éäž ã§ããããå®è·µçã§äŸ¡å€ã®ããææã«ã€ãªãããŸããã 3. AIã«ç¹åããããŒãèšå® ä»åã¯ææŠããŒããäžèš2ç¹ã«çµã æç¢ºå ããŸããã ãããã¯ãã«AIãçµã¿èŸŒã ä»ãŸã§AIãå®åã§äœ¿ããŠãªãåéãžå°å
¥ ãã®æç¢ºãªããŒãèšå®ã«ãããåå è
ããã¯ãé©åºŠãªå¶çŽãããããšã§ããããææŠå
容ãå
·äœåãããããªã£ãããAIãšããå
±éèšèªãããããšã§ãä»ããŒã ã®çºè¡šãçè§£ããããåŠã³ãå€ãããšãã£ãããžãã£ããªãã£ãŒãããã¯ãåŸãããšãã§ããŸããã 4. äž»äœçãªåå ãä¿ãä»»æåå å¶ å
šå¡åå ãã ä»»æåå å¶ ãžãšå€æŽããåå åžæè
ããããŒãžã£ãŒãšçžè«ã®äžã§åå ãæ±ºå®ããæ¹åŒãæ¡çšããŸããã ãã®å€æŽã«ãããåå è
å
šå¡ãé«ãã¢ãããŒã·ã§ã³ãæã£ãŠåãçµãç°å¢ãšãªããéãããæéã§ã質ã®é«ãææãç¶ã
ãšçãŸããããšãšãªããŸããã 第6åææŠWEEKã«ã€ã㊠ä»å㯠10ããŒã ãç·å¢31å ã®ãšã³ãžãã¢ãåå ããããããã®ãããã¯ã課é¡ã«å¯ŸããŠAIãæŽ»çšãã解決çã«ææŠããŸããã åãçµã¿å
容(äžéšæç²) æ¢åAIåŠçã®é«éå 課é¡ïŒ ããªãã·ã¥AIã®æ¢ååŠçã«ãããŠãè€éãªåŠçãçŽåã«ç©ã¿éãªãããšã«ãã£ãŠãã¬ã¹ãã³ã¹ã¿ã€ã ãé
ããªãäºè±¡ãçºçããŠããã 宿œå
å®¹ïŒ åŠçã®äžŠååãLLMã®åãåããã®æ¹åã®å®æœãšæ€èšŒã èªäœRedash MCPãµãŒããŒã®äœæ 課é¡ïŒ SQLãæžãããšã«æ
£ããŠããªãã¡ã³ããŒãæ¢åã®Redashã¯ãšãªã®èª¿æ»ãä¿®æ£ãè¡ãéã«ãæäœæ¥ã§ã®äºåæºåãã¯ãšãªéèšçµæã®ç¢ºèªã«æéãããããšãã課é¡ããã£ãã 宿œå
å®¹ïŒ Redashãšé£æºãããããCursorçµç±ã§åŒã³åºãå¯èœãªMCPãµãŒããŒã®éçºã Figma MCPãå©çšããéçº/Playwright MCPãå©çšããE2Eãã¹ãã®å®æœ 課é¡ïŒ ãªãªãŒã¹ãµã€ã¯ã«ã®é«éåã«é©å¿ããããã®ã¯ã©ã€ã¢ã³ããµã€ãã®å®è£
ãšãã¹ãã®é«éåãå¿
èŠã ã£ãã 宿œå
å®¹ïŒ Figma MCPãå©çšãã管çç»é¢(Vue.js)ãšã¢ããª(Flutter)ã®éçºã®æ€èšŒãPlaywright MCPãå©çšãããèªç¶èšèªããŒã¹ã®èªåãã¹ãã®æ€èšŒã ææçºè¡šäŒã®æ§å 2025幎7æ18æ¥(é)ã«éå¬ããææçºè¡šäŒã§ã¯ãåããŒã ãç±ã®ããã£ããã¬ãŒã³ããŒã·ã§ã³ãè¡ããŸãããæè¡çãªå
容ã¯ãã¡ãããå®éã®ãã¢ã亀ããçºè¡šãç¥èŠã®å
±æãçºè¡šåŸã®è³ªçå¿çãªã©ãåå è
å
šå¡ãå€ãã®åŠã³ãåŸãæ©äŒãšãªããŸããã ä»åŸã®å±é 第6åææŠWEEKã¯ãéå¶åœ¢åŒã倧ãã倿Žããã«ãé¢ããããæåŸ
ãäžåãææãçã¿åºãããšãã§ããŸããã 2æ¥éãšããçæéã§ã®æåãåããŠãéå¶ããŒã ã§ã¯ éå¬é »åºŠã®åäž ãæ€èšããŠããŸããããé »ç¹ã«éå¬ããããšã§ããææŠãããšããªãŒã®ãšã³ãžãã¢ã«ãšã£ãŠæ¥åžžçãªæåãšããŠå®çãããŠããäºå®ã§ãã â»5æ¥éã®éåžžçã®ææŠWEEKã幎ã«1åãããã®é »åºŠã§éå¬ããããšèããŠããŸãã æåŸã« ãšããªãŒã§ã¯ããšãã«åã仲éãåéããŠããŸãã ããã¯ããã°ãèªãã§å°ãã§ããšããªãŒã«èå³ãæã£ãŠããã ããæ¹ã¯ããã²äžåºŠã«ãžã¥ã¢ã«é¢è«ã«ãè¶ããã ããïŒ corp.every.tv æåŸãŸã§ãèªã¿ããã ããããããšãããããŸããïŒ
ã¯ããã« ããã«ã¡ã¯ïŒããªãã·ã¥ãããã³ã§äž»ã«ããã¯ãšã³ãã®éçºãæ
åœããŠããç§å±±ã§ãã ãšããªãŒéçºéšã§å
æ¥è¡ãããææŠweekã®äžã§ãç§ãã¡ã®ããŒã ãéçºããRedash MCPã«ã€ããŠç޹ä»ããŠãããŸãã èæ¯ çŸåšåŒç€Ÿã§ã¯AIã³ãŒããšãã£ã¿ã®Cursorããšã³ãžãã¢ãšPdMã«é
åžããŠããŸãã æ¥ã
ã®ããŒã¿åæã«ã¯Redashãçšããããšãå€ããPdMã¯Cursorã䜿çšããŠRedashã®ã¯ãšãªäœæãªã©ãè¡ããŸãã ä»åã¯æ¥åæ¹åã®äžç°ãšããŠãRedash MCPãäœãããšã§ããŒã¿åæãããå¹çåããPdMã®è² è·åæžãããããšèããŸããã PdMãæ±ããŠããäž»ãªèª²é¡ å
·äœçãªå®è£
ã«å
¥ãåã«ããŸãã¯PdMãæ±ãã課é¡ãããããã¢ãªã³ã°ããŸããã ãã¢ãªã³ã°ã®çµæã以äžã®ãããªèª²é¡ãåŸãããšãã§ããŸããã 1. Cursorã䜿ã£ãŠRedashã§ã¯ãšãªãäœæã»æŽæ°ããéã«ãäºåæºåãå¿
èŠã§ãããå°ãæé Cursorã¯åºæ¬çã«Redashã§æ±ããããŒã¿ã®æ
å ±ãç¥ããŸããã ãã®ãããCursorã䜿ã£ãŠã¯ãšãªãæžãéã¯ãããŒãã«æ§é ãæããããªã©ã®äºåæºåã«ãªããŸãã æ¯åããã³ããã«æžããããæ±ãããŒãã«æ§é ã確èªãã€ã€ããã¥ã¡ã³ãåããããšã§Cursorã«èªèããŠããããŸãããCursorèªèº«ãRedashäžã®æ
å ±ãåãã«ãããæ¹ãå¹ççã§ãã 2. æ®æ®µRedashãè§Šããªãã¡ã³ããŒããã¯ãšãªä¿®æ£ã®äŸé ŒãããŠå°ãå€§å€ äŸãã°ããã®ã¯ãšãªã®éèšçµæãäžé±éããäžã¶æã§åºããŠã»ããããªã©ã®ç°¡åãªäŸé ŒãPdMã«æ¥ãããšããããŸãã Redashã«æ
£ããŠããªãã£ãããã¯ãšãªãæžããªããããªã¡ã³ããŒã§ãããçšåºŠèªåã§è§£æ±ºã§ãããšå¬ããã§ãã 3. æ°å€ã®å€åã¯Redashã®ã¯ãšãªçµæãã¿ãªããšææ¡ã§ãããç°åžžãªå€ãåºãŠãããšãã«å³åº§ã«æ°ã¥ããªã Redashã«ã¢ã©ãŒãæ©èœã¯ãããã®ã®ãæè»ãªèšå®ãã§ããããã§ã¯ãªããããããæè»ã«ç°åžžå€ãæ€åºã§ãããšå¬ããã§ãã Redash MCPã®å®è£
ã«ã€ã㊠䞻ãªäœ¿çšæè¡ ä»åäœæããRedash MCPã®äœ¿çšæè¡ã玹ä»ããŸãã Go 1.23.0 go-sdk 0.2.0 MCPã®å
¬åŒSDK Docker Redash(APIã§å©çš) â»2025幎8æ8æ¥çŸåšgo-sdkã®å®å®çã¯ãªãªãŒã¹ãããŠããŸããããä»åŸãªãªãŒã¹äºå®ã®ããã§ãã äœæããæ©èœ Redash APIãçšæããŠãããšã³ããã€ã³ãã®ãã¡ãå®éã«ãã䜿ããããªãšã³ããã€ã³ãã«çµã£ãŠäžèšã®ãããªæäœãã§ããããã«ããŸããã ããŒã¿ãœãŒã¹äžèЧååŸ ããŒã¿ãœãŒã¹è©³çްååŸ ã¯ãšãªäžèЧååŸ ç¹å®ã®ã¯ãšãªè©³çްååŸ ã¯ãšãªå®è¡ãå®è¡çµæååŸ ã¯ãšãªäœæ ã¯ãšãªæŽæ° ããã·ã¥ããŒãæ
å ±ååŸ å®è£
äŸ ä»¥äžãRedash MCPãµãŒããŒã®ç°¡åãªå®è£
äŸã§ãã ããã§ã¯ïŒã€ã®ã¯ãšãªæ
å ±ãååŸããŠããã±ãŒã¹ãèããŸãã package main import ( "context" "log" "github.com/modelcontextprotocol/go-sdk/mcp" ) // ã¯ãšãªååŸã®ãã©ã¡ãŒã¿ type GetQueryParams struct { ID int `json:"id" jsonschema:"ã¯ãšãªID"` } // ã¯ãšãªååŸã®å®è£
func GetQuery(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[GetQueryParams]) (*mcp.CallToolResultFor[any], error ) { // å®éã«ã¯ããã§Redash APIãåŒã³åºããŠã¯ãšãªæ
å ±ãååŸãã queryInfo := "ã¯ãšãªID: " + string (params.Arguments.ID) + "ã®æ
å ±" return &mcp.CallToolResultFor[any]{ Content: []mcp.Content{&mcp.TextContent{Text: queryInfo}}, }, nil } func main() { // MCPãµãŒããŒäœæ server := mcp.NewServer(&mcp.Implementation{Name: "redash" , Version: "v1.0.0" }, nil ) // ããŒã«ã®è¿œå mcp.AddTool(server, &mcp.Tool{ Name: "get-query" , Description: "Redashã®ã¯ãšãªãååŸãã" , }, GetQuery) // ãµãŒããŒãèµ·å if err := server.Run(context.Background(), mcp.NewStdioTransport()); err != nil { log.Fatal(err) } } ããã§Redash MCPãµãŒããŒã®å®è£
ã¯å®äºã§ãã go-sdkã䜿ããšãMCPãµãŒããŒã®å®è£
ãéåžžã«ç°¡åã§ããã âªdockerã§èµ·åããŠCursorã§äœ¿ãå Žåã®å®è£
äŸ äžèšã®ããã«DockerfileãæºåããŸãã FROM golang:1.23 as builder WORKDIR /app COPY . . RUN go mod tidy && go build -o mcp-server main.go FROM debian:stable-slim WORKDIR /app RUN apt-get update && apt-get install -y ca-certificates openssl && rm -rf /var/lib/apt/lists/* COPY --from=builder /app/mcp-server . ENTRYPOINT ["/app/mcp-server"] ã€ã¡ãŒãžããã«ãããŸã $ docker build -t redash-mcp . Cursorã®ã®mcp.jsonã«äžèšã®å
容ã远å ããŸãã { " mcpServers ": { " redash-mcp ": { " command ": " docker run -i --rm -e REDASH_URL -e REDASH_API_KEY redash-mcp ", " env ": { " REDASH_URL ": " https://hoge.redash.hoge ", " REDASH_API_KEY ": " hogehoge " } } , } } 䜿çšäŸ å®éã«CursorããRedash MCPã䜿ã£ãŠã¿ãäŸã以äžã§ãïŒ æè¿è¿œå ãããã¬ã·ããååŸããã¯ãšãªã®äœæãå®è¡ãããã«ç°¡åãªåæãŸã§ããŠãããŸããã ãã¢ãªã³ã°ãã課é¡ã«å¯Ÿããçµæ æ¬èšäºã®åé ã§æãã課é¡ã«å¯ŸããŠãRedash MCPã§ã©ã®ããã解決ã§ãããèŠãŠãããŸãã 1. Redashã§ã¯ãšãªãäœæã»æŽæ°ããéã«ãäºåæºåãå¿
èŠã§ãããå°ãæé Redashã®ããŒã¿ãœãŒã¹ãMCPçµç±ã§ååŸãããããšã«ãããäºåæºåã®åæžãã§ããŸããã 2. æ®æ®µRedashãè§Šããªãã¡ã³ããŒããã¯ãšãªä¿®æ£ã®äŸé ŒãããŠå°ãå€§å€ ã¯ãšãªäœæã®ããŒãã«ã¯äžå®äžãã£ããã®ã®ãçŸç¶ã ãšCursorãªã©ã®MCPã¯ã©ã€ã¢ã³ãã®æºåãåæèšå®ãå¿
èŠãªããã誰ã§ãæ°è»œã«äœ¿çšã§ããç¶æ
ã«ã¯ã§ããŠããŸããã 3. æ°å€ã®å€åã¯Redashã®ã¯ãšãªçµæãã¿ãªããšææ¡ã§ãããç°åžžãªå€ãåºãŠãããšãã«å³åº§ã«æ°ã¥ããªã çãæéã§ã®å®è£
ã ã£ãããããã®èª²é¡ã«å¯ŸããŠã®ã¢ã¯ã·ã§ã³ã¯ã§ããŠããŸãããã äŸãã°Devinãšé£æºããŠå®æçã«ç°åžžå€ãèŠã€ããŠãããããªã©ã®ããšãåºæ¥ããšè¯ããªãšèããŠããŸãã PdMããã®ãã£ãŒããã㯠äœäººãã®PdMã«å®éã«äœ¿ã£ãŠããã ãã以äžã®ãããªå¬ããã³ã¡ã³ããããã ããŸããïŒ ã¯ãšãªå
ã®ã³ã¡ã³ããã¡ãããšæžãããŠãŠå¯èªæ§ãè¯ã ã¯ãšãªäœæãç§ã§çµãã£ãŠæå redashãè€æ°ã®ããŒã¯ãŒãæ€çŽ¢ã§ããªãã®ã§å©ãã ã¯ãšãªã®å·®åãæ¯èŒãããšãã«ãããããã¯ãšãªã³ããŒããæéããªããªã£ã äžæ¹ã§ãæ¹åç¹ãèŠã€ãããŸããã Cursorç°å¢ãã¿ãŒããã«ãçã䜿ããããã§ã¯ãªããããslackãªã©ããåŒã¹ããšäœ¿ãã人ã®å¹
ãåºãã£ãŠå¬ãã ããã©ã«ãã§Cursorã«å
¥ããã¹ãã«ãŒã«ã¿ãããªãã®ããããšè¯ããã Redashãšé£æºããŠããTreasureDataå°çšã®td颿°å
šç¶äœ¿ã£ãŠãããªããŠãçµæ§ãšã©ãŒåãããã®ã§ãããã³ããé 匵ããªãããããªããªãšæãã€ã€ãããã³ãããæåãããããšå¬ãã ã«ã©ã ã«å®éã©ããªããŒã¿ãå
¥ã£ãŠããæšæž¬ãééããæãããããããã®èŸºããã粟床äžãããããšå¬ãã ä»åŸã®å±æ PdMããã®ãã£ãŒãããã¯ãªã©ãããšã«ãä»åŸã¯ãããªããšããã£ãŠããããã§ãã 1. Redash MCPã䜿ããŸã§ã®ããŒãã«ãäžãã ãŸãããªã¢ãŒãMCPãµãŒããŒã«ãããã§ãã çŸåšã¯MCPãããŒã«ã«ã§èµ·åãããŠããŸããããã®æ¹æ³ã ãš åæèšå®æã«ããŒã«ã«ã§ãã«ãããå¿
èŠãããæé ã¢ããããŒãã®ãã³ã«ããŒã«ã«ã§ãã«ããå¿
èŠã«ãªã ãªã©ã®åé¡ããããŸãã ãªã¢ãŒãMCPãµãŒããŒã«ããããšã§ãããã®åé¡ã解決ãããã§ãã ãŸããã»ãã¥ãªãã£é¢ãªã©ãèæ
®ãã€ã€ å¯èœã§ããã°Devinã䜿ã£ãŠSlackããåŒã³åºããªã©ãåºæ¥ãããã«ããŠããããã§ãã 2. äºåã«æž¡ãæ
å ±ã®æŽå åŒç€Ÿã®Redashã§æ±ã£ãŠããããŒã¿ãœãŒã¹ã«ã¯ãDBã®ããŒã¿ä»¥å€ã«ãTreasureDataãFirebaseãªã©ã®ä»ãµãŒãã¹ãšé£æºããŠååŸããŠããããŒã¿ããããŸãã ç¹ã«ãä»ãµãŒãã¹ããååŸããŠããããŒã¿ã®ã¹ããŒãæ
å ±ã¯ãRedashã§è©³çްãŸã§æã£ãŠããªãããšãå€ãã§ãã ããã¥ã¡ã³ããšããŠãŸãšãŸã£ãŠãããã®ãããã®ã§ããããå©çšããããšã«ããRedash MCPã®ç²ŸåºŠãäžããŠããããã§ãã ãã®ä»ãéæãã£ãŒãããã¯ãããã ãæ¹åããŠããããã§ãã ãŸãšã æ¬èšäºã§ã¯ã瀟å
Redash MCPäœæã®èæ¯ãå®è£
äŸãå®éã®äœ¿çšæã«ã€ããŠç޹ä»ããŸããã ä»åPdMã®äœæ¥è² è·è»œæžãç®çãšããŠRedash MCPãäœããŸãããããšã³ãžãã¢ã«ãšã£ãŠãRedashã䜿ãããŒãã«ãäœããªããšãã坿¬¡çãªå¹æããã£ãããªãšæããŸãã å®éãç§ã¯Redash MCPãå©çšãå§ããŠãããµã¯ããšã¯ãšãªãäœããããã«ãªããŸããã ä»åŸãçããã䜿ãããããªãããã«æ¹åããŠããããã§ãã æåŸãŸã§èªãã§ããã ãããããšãããããŸããïŒ åèæç® https://github.com/modelcontextprotocol/go-sdk https://modelcontextprotocol.io/docs/getting-started/intro
ãšããªãŒã§å°å£²æ¥çã«åãåãã®éçºãè¡ã£ãŠãã @kosukeohmura ã§ãã ä»åã¯ãFlutter ã¢ããªã±ãŒã·ã§ã³ã« AWS Cognito ã䜿ã£ãèªèšŒæ©èœãå°å
¥ããããã»ã¹ã«ã€ããŠç޹ä»ããŸãã ããã¯ãšã³ãã§ Cognito ãã©ããããããã¢ããªããçŽæ¥ Cognito ã«æ¥ç¶ããã Cognito ã IdP ãšããŠæ¡çšãèªèšŒæ©æ§ãæ°ãã«éçºããã«ããããããã¯ãšã³ãã Cognito ãã©ããããå®è£
æ¹éãšãã¢ããªããçŽæ¥ Cognito ã«æ¥ç¶ããæ¹åŒãæ€èšããŸãããçµè«ãšããŠã¯ä»å㯠Flutter ã¢ããªããçŽæ¥ Cognito ã«æ¥ç¶ããæ¹åŒãéžæããŸããã ããã¯ãšã³ãã§ Cognito ãã©ããããæ¹åŒã§ã¯ãããã¯ãšã³ãã§ Cognito Admin API ãçšããèªèšŒåŠçãèªç±ã«æžãããšãå¯èœã§ãããèªç±ã«åŠçãæžããåé¢ãåºæ¬çã«ã¯ Cognito ãåŒã³åºãã ãã®ç¬èªã®ãšã³ããã€ã³ã矀ãå®è£
ããå¿
èŠãããããŸããã®ãšã³ããã€ã³ããå©çšããã¢ããªåŽã®ç»é¢ã®å®è£
ãå¿
èŠã«ãªããŸãã äžæ¹ãã¢ããªãã Amplify ãå©çšãçŽæ¥ Cognito ã«æ¥ç¶ããæ¹åŒã§ã¯ãç¬èªã®ãšã³ããã€ã³ã矀ãå®è£
ããããšãªãèªèšŒæ©æ§ãå®è£
ã§ããå ã㊠Amplify ã§ãã§ã«çšæãããèªèšŒç»é¢ã® UI ã䜿çšããã°ã¢ããªã®ãã°ã€ã³ç»é¢ãªã©ã®å®è£
ãäžèŠãšãªããŸããããã¯ãšã³ãã§ã¯èªèšŒãå¿
èŠãªãšã³ããã€ã³ãããããã«å¯ŸããŠã¢ããªã Cognito ããååŸãããŠãŒã¶ãŒããŒã¯ã³ã驿£ããå€å¥ããããã«ãŠã§ã¢ãæã圢ã§ãããã®æ¹åŒã ãšãå®è£
ãã察象ã倧ããæžãäžæ¹ã§ãAmplify ã®æ©èœããå€ããããšãè¡ãããšãããšå·¥å€«ãå¿
èŠãšãªãããšæããŸãã ä»åç§é㯠ID/PW ã§ã®èªèšŒèªå¯ããã§ããã°ãããèªèšŒèªå¯ååŸã«ç¬èªã®åŠçãæã¿èŸŒãã ãããå¿
èŠã¯ãããŸããã§ãããã¢ããªã®ç»é¢ãäžè¬çãªãµã€ã³ã€ã³ç»é¢ãååšããã°ããã£ãã®ã§ãAmplify ã®ããã©ã«ãã® UI ã³ã³ããŒãã³ããå°ãæ¹å€ããã°ååäºè¶³ãããã§ãããããããèæ¯ããã¢ããªããçŽæ¥ Cognito ãžæ¥ç¶ããæ¹åŒã®ãã¡ãªãããåé¡ã«ãªããªãããªãããå®éšçã«å®è£
ãè¡ãæçšæ§ã確ãããåŸã«ããã®æ¹åŒãéžæããããšãšããŸããã å°å
¥ããäž»èŠãªå€æŽ å
¬åŒã® Quickstart - AWS Amplify Gen 2 Documentation ãåç
§ããªããå°å
¥ãè¡ããŸãã 1. Amplify Flutter ããã±ãŒãžã®è¿œå ãŸãæåã«å¿
èŠãªäŸåé¢ä¿ã远å ããŸããããã«ãããFlutter ã¢ããªã§ Amplify ã®èªèšŒæ©èœã䜿çšã§ããããã«ãªããŸãã flutter pub add amplify_flutter amplify_auth_cognito amplify_authenticator ããããã®ããã±ãŒãžã®é¢ä¿æ§ãããããããŸããã§ããããQuickStart ã«èšèŒãããŠãã説æã端çã§ããããããã§ãã amplify_flutter to connect your application with the Amplify resources. amplify_auth_cognito to connect your application with the Amplify Cognito resources. amplify_authenticator to use the Amplify UI components. 2. Flavor ã«å¿ã㊠dart_define ãã¡ã€ã«ãçæã»äœ¿çšãã ç°å¢ããšã« Cognito ã®ãŠãŒã¶ãŒããŒã«ãåãæ¿ããããããŸã Flavor ã«å¿ããŠç°å¢å€æ°ãã¢ããªãžæ³šå
¥ã§ããããã«ããŸããFlavor ç°å¢å€æ°ãã¢ããªãžæ³šå
¥ããããã« dart_define ãã¡ã€ã«ã䜿çšããŸãããããããã³ãã¬ãŒãåããŠãããŸãã dart_define.template.json { " awsRegion ": " $AWS_REGION ", " cognitoUserPoolId ": " $COGNITO_USER_POOL_ID ", " cognitoUserPoolClientId ": " $COGNITO_USER_POOL_CLIENT_ID " } ããããã direnv ãªã©ã䜿ãç°å¢å€æ°ãèšå®ããŠããããããå
ã«å®éã® dart_define ãã¡ã€ã«ãçæãå©çšããŸãã以äžãããè¡ã Makefile äŸã§ãã FLAVOR ?= development generate-dart-define: cat dart_define.template.json | envsubst > dart_define_$$FLAVOR.json run-development: $(FLUTTER) run --debug --flavor development --dart-define-from-file=dart_define_development.json ãã®ä»çµã¿ã«ãããç°å¢ããšã«ç°ãªãç°å¢å€æ°ã䜿çšã§ããŸãã 3. Amplify èšå®ãã¡ã€ã«ã®ç®¡ç GitHub ã§å
¬éãããŠããã¹ããŒã amplify-backend_packages_client-config_src_client-config-schema_schema_v1.json at main · aws-amplify_amplify-backend ã«åŸã£ãŠãAmplify èšå®ãã¡ã€ã«ãæ§ç¯ããŸããAWS äžã§èšå®ãããŠãŒã¶ãŒããŒã«ã®èšå®å€ãšè¢«ãéšåã¯åãããŠãããŸããäžéšã®èšå®å€ã¯ãã¬ãŒã¹ãã«ããšããŠãããã¢ããªå®è¡æã«ç°å¢å€æ°ã§çœ®æããŸãã lib/amplify_outputs.json { " version ": " 1.1 ", " auth ": { " aws_region ": " <Will be replaced when building> ", " user_pool_id ": " <Will be replaced when building> ", " user_pool_client_id ": " <Will be replaced when building> ", " password_policy ": { " min_length ": 12 , " require_lowercase ": false , " require_uppercase ": false , " require_numbers ": false , " require_symbols ": false } , " username_attributes ": [ " email " ] , " user_verification_types ": [] , " unauthenticated_identities_enabled ": false , " mfa_configuration ": " NONE " } } ãã®å
容ãã¢ããªå®è¡æã«ç°å¢å€æ°ã§äžæžãããããšã§ãåç°å¢ã«é©ããèšå®ãé©çšãããŸãã 4. ã¢ããªèµ·ååŸã« Amplify ãã»ããã¢ãããã æºåãã Amplify èšå®ãã¡ã€ã«ãšç°å¢å€æ°ã䜿çšããã¢ããªèµ·ååŸã« Amplify ãã©ã°ã€ã³ã®åæåãè¡ããŸãããããè¡ãããã® AmplifyService ãå®è£
ããŸãã: lib/services/amplify.dart class AmplifyService { final Ref _ref; final BundleRepository _bundleRepository; @override Future<Result< void , MyAppException>> setupAmplify() async { try { await Amplify.addPlugin(AmplifyAuthCognito()); final amplifyConfigResult = await _buildAmplifyConfig(); if (amplifyConfigResult.isError) throw amplifyConfigResult.error; await Amplify.configure(amplifyConfigResult.okValue); return Result.ok( null ); } catch (e, s) { return Result.error(MyAppException(e, s)); } } // lib/amplify_outputs.json ãã¡ã€ã«ãååŸã Map ãšããŠè¿åŽ Future<Result< String , MyAppException>> _buildAmplifyConfig() async { final amplifyConfigString = await _bundleRepository.readBundle(BundlePath.amplifyConfig); final amplifyConfig = jsonDecode(amplifyConfigString) as Map< String , dynamic >; amplifyConfig[ 'auth' ][ 'aws_region' ] = /* ç°å¢å€æ°ããæ³šå
¥ */ ; amplifyConfig[ 'auth' ][ 'user_pool_id' ] = /* ç°å¢å€æ°ããæ³šå
¥ */ ; amplifyConfig[ 'auth' ][ 'user_pool_client_id' ] = /* ç°å¢å€æ°ããæ³šå
¥ */ ; return Result.ok(jsonEncode(amplifyConfig)); } } ããšã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãšã³ããªãŒãã€ã³ãã§ AmplifyService ã䜿çšããŸã: Future< void > main() async { // ... æ¢åã®åæååŠç final amplifySetupResult = await container.read(amplifyServiceProvider).setupAmplify(); if (amplifySetupResult.isError) { logger.fatalException( 'Error occurred when configuring Amplify' , amplifySetupResult.error); } runApp(UncontrolledProviderScope(container: container, child: const MyApp())); } ããã§ Amplify ã®ã»ããã¢ãããå®äºããŸãããå ã㊠QuickStart ã©ããã« UI ã³ã³ããŒãã³ããèšè¿°ããã°ãµã€ã³ã€ã³ïŒãµã€ã³ã¢ããç»é¢ã衚瀺ãããŸãããç¹æ®µé£ããããšã¯ãªãçç¥ããŸãã ãŸãšã ä»åã®å®è£
ã§ã¯ãAmplify UI ã䜿çšããããšã§æ¯èŒçã¹ã ãŒãºã«èªèšŒæ©èœãå°å
¥ã§ããŸãããããã¯ãšã³ãçµç±ã§ã¯ãªã Flutter ããçŽæ¥ Cognito ã«æ¥ç¶ããããšã§ãéçºé床ãéèŠããªãããã»ãã¥ãªãã£ãä¿ã€ããšãã§ããŸããã ãŸããç°å¢éã§å¯å€ãªå€ãç°å¢å€æ°ã§ç®¡çãããã³ãã¬ãŒããã¡ã€ã«ã䜿çšããããšã§ãç°ãªãç°å¢ïŒéçºã»æ¬çªïŒãžåããŠå®å
šã«ã¢ããªãå®è¡ã§ããããã«ãªããŸãããAmplify ã»ããã¢ãã Service ã¯ã©ã¹ã«ç
©éãªåŠçãæŒã蟌ãããšã§ãã¢ããªã±ãŒã·ã§ã³ã®ãšã³ããªãŒãã€ã³ãã«æããã責åãæå°éã«æããããšãã§ããŸããã Flutter ã§ã®èªèšŒå®è£
ãæ€èšãããŠããæ¹ã®åèã«ãªãã°å¹žãã§ãã åèè³æ Amplify Docs - AWS Amplify Gen 2 Documentation Amplify UI - Build UI fast with Amplify on Flutter
ã¯ããã« åæ æè¡ã¹ã¿ã㯠ç£èŠã®æ§æ çŸç¶ã®èª²é¡ Devinéžå®çç± 1. ãã«ãRepository察å¿ã®å®¹æã 2. èªåŸåAIãšããŠã®éçšå¹ç æ§æ æé Playbook 1. Devinã®èµ·åãšSentryã¢ã©ãŒãæ
å ±ã®ååŸ 2. Devin Playbookã®å®è¡ 2-1. é¢é£æ
å ±ã®ååŸ 2-2. åæ 2-3. è¿œå æ
å ±ã®ååŸ 2-4. å³è¡šã®äœæ 3. Slackãžåºå çµæ éçšããŠã¿ãçµæ éçšããŠã¿ãŠèŠããŠããèª²é¡ ãŸãšã ã¯ããã« éçºæ¬éšã§ããªãã·ã¥ãããã³ã®ã¢ããªãŠã§ãã°ããŒã¹åãã®éçºãæ
åœããŠãã hond ã§ãïŒ ä»åã¯å
æ¥è¡ããã 第6åææŠweek ã§ç§ãã¡ã®ããŒã ãè¡ã£ãDevinã«ããSentryã¢ã©ãŒãã®æ¹åã«ã€ããŠç޹ä»ããŸãã æ¬èšäºã¯Devinã®åºæ¬çãªæŠå¿µãäœ¿ãæ¹ã«ã€ããŠããçšåºŠçè§£ããŠããèªè
ã察象ãšããŠããŸããDevinèªäœã®è©³çްãªèª¬æã¯çç¥ããå®éã®æ¥åã§ã®æŽ»çšäºäŸã«çŠç¹ãåœãŠãŠè§£èª¬ããŸãã ãªããä»åã®åãçµã¿ãæ€èšããéã«ãç§ãã¡ã®ç®æšãšå®å
šã«äžèŽãã SMARTCAMPããã®èšäº ãçºèŠããéåžžã«åèã«ãªããŸãããç§ãã¡ã®ç°å¢ãèŠä»¶ã«åãããŠã«ã¹ã¿ãã€ãºãè¡ããªãããåèšäºã®ã¢ãããŒããåèã«ãããŠããã ããŸããïŒ åæ æè¡ã¹ã¿ã㯠æ¬èšäºã§æ±ãæè¡ã¹ã¿ãã¯ã¯ä»¥äžã®éãã§ãã é
ç® æè¡ ãšã©ãŒç£èŠ Sentry éç¥ Slack AIéçºæ¯æŽ Devin å³è¡šçæ Mermaid ããŒãžã§ã³ç®¡ç GitHub ã€ã³ãã© AWS ã¢ããªã±ãŒã·ã§ã³ Nuxt.js (ããã³ããšã³ã)ãGo (ããã¯ãšã³ã) ç£èŠã®æ§æ ããªãã·ã¥ãããã³ã§ã¯çŸåšã¢ããªã±ãŒã·ã§ã³ã®ãšã©ãŒç£èŠããŒã«ãšã㊠Sentry ãçšããŠããŸãããã®Sentryã«ã¯Nuxt.jsã§åäœããããªãã·ã¥ãããã³ã®ãŠã§ãã¢ããªã±ãŒã·ã§ã³ãããã³Goã®ããã¯ãšã³ããµãŒããŒã§çºçãããšã©ãŒãéä¿¡ãããä»çµã¿ãšãªã£ãŠããŸããSentryã«éä¿¡ããããšã©ãŒã¯Integrationãä»ããŠSlackã®ã¢ã©ãŒããã£ã³ãã«ã«éç¥ãããŸãã çŸç¶ã®èª²é¡ ãã®ã¢ã©ãŒãéçšã«é¢ããŠãäž»ã«ä»¥äžã®èª²é¡ããããŸãã: ç·æ¥åºŠããããã¥ãã ïŒã¢ã©ãŒãã®éèŠåºŠãäžæçã§ã察å¿ã®åªå
é äœä»ããå°é£ 解決ã«å¿
èŠãªæ
å ±ãäžæç ïŒäžéšã®ãšã©ãŒã§ã¯Sentryã«éãããæ
å ±ãäžè¶³ããŠãããç¹ã«ã¹ã¿ãã¯ãã¬ãŒã¹ããªãå Žåã«åé¡è§£æ±ºã«å¿
èŠãªæ
å ±ãç¹å®ããã®ãå°é£ èª¿æ»æé ãäžæ ïŒAWSã³ã³ãœãŒã«ãSentryãã¢ããªã±ãŒã·ã§ã³ã³ãŒããAthenaãªã©ãè€æ°ã®ãªãœãŒã¹ã暪æããŠèª¿æ»ããéã®æç¢ºãªæé ã確ç«ãããŠããªãã æŸçœ®ãããŠããã¢ã©ãŒãããã ïŒããã«ãããéçºè
ã®å¿ççè² æ
ãå¢å ã ã¢ã©ãŒãç®æã®æ
åœãäžæç ïŒã©ã®ãšã©ãŒãã©ã®éçºããŒã ã®æ
åœãäžæç¢ºã Devinéžå®çç± ä»åã®èª²é¡è§£æ±ºã«ãããŠãç§ãã¡ãDevinãéžå®ããçç±ã¯å€§ãã2ã€ãããŸãã 1. ãã«ãRepository察å¿ã®å®¹æã äºåã«ä»ã®ã¡ã³ããŒãCursorãClaude Codeã®æ€èšŒã瀟å
å匷äŒã§è¡ããŸãããããããã©ã¡ããRepositoryãè·šãã 調æ»ã«ãããŠä»¥äžã®èª²é¡ãçºçããŸããã è€æ°Repositoryã®èšå®ã«è¿œå äœæ¥ãå¿
èŠ èšå®å®äºåŸãRepositoryãæšªæããåŠçã®è§£éãæåŸ
å€ãäžåã Devinã§ã¯ãWorkspaceå
ã«å¿
èŠãªRepositoryãcloneããã ãã§èšå®ãå®äºããããã³ããšã³ããšããã¯ãšã³ããã€ã³ãã©ã®ã³ãŒããæšªæãã調æ»ãå¹ççã«è¡ããŸããã äŸãã°ãã€ã³ãã©ã®ã³ãŒããè§£éããŠããã³ããšã³ããAWSäžã§ã©ãã«äœçœ®ããããçè§£ããã©ã®ããã¯ãšã³ããµãŒããŒãšé¢ä¿ãããããæèããã¬ã¹ãã³ã¹ãè¡ããŠããŸããã 2. èªåŸåAIãšããŠã®éçšå¹ç Devinã®èªåŸåç¹æ§ã«ããã以äžã®éçšã¡ãªãããå®çŸã§ããŸããã 䞊è¡åŠç : ãšã³ãžãã¢ãè¡ããšã©ãŒçºçæã®äžæ¬¡å¯Ÿå¿ãšäžŠè¡ããŠDevinããšã©ãŒèª¿æ»ãèªåå®è¡ å±¥æŽã®å¯èŠå : 調æ»ããã»ã¹ãDevinã»ãã·ã§ã³å
ã«èšé²ãããããŒã å
šäœã§å
±æå¯èœ æé ã®æšæºå : 人çèŠå ã«äŸåããªãäžè²«ãã調æ»å質ãæ
ä¿ æ§æ æçµçã«æ§ç¯ããSentryã¢ã©ãŒãèªååæã·ã¹ãã ã®æ§æã¯äžèšã®éãã§ãã æé Devinã®èµ·åãšSentryã¢ã©ãŒãæ
å ±ã®ååŸ Devin Playbookã®å®è¡ é¢é£æ
å ±ã®ååŸ åæ è¿œå æ
å ±ã®ååŸ å³è¡šã®äœæ Slackãžåºå Playbook Sentry APIã«Curlã³ãã³ãã§ã¢ã©ãŒãã®æ
å ±ãååŸããŠãäžèšã®åæçµæãåºåããŠãã ããã èª¿æ»æé ãšããŠä»¥äžã®4ã¹ããããé çªã«å®æœããããšïŒ --------------- ## 1. Sentry APIãå©ããŠã¬ã¹ãã³ã¹ãååŸ Sentry APIã¯ãäžèšã³ãã³ããå®è¡ããŠãã ãããã¢ã©ãŒãå
šäœã¯issue, ã€ãã³ã詳现ã¯issue and event ãå©ããŠãã ãããsecretã¯SENTRY_API_TOKENãåç
§ããŠãã ããã issue:""" curl https://sentry.io/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/ \ -H 'Authorization: Bearer {sentry_api_token}' """ issue and event:""" curl https://sentry.io/api/0/organizations/{organization_id_or_slug}/issues/{issue_id}/events/{event_id}/ \ -H 'Authorization: Bearer {sentry_api_token}' ## 2. 察象ãšãªãGit Repositoryã®ç¹å® ãšã©ãŒã®ã¹ã¿ãã¯ãã¬ãŒã¹ãé¢é£æ
å ±ãããåé¡ãçºçããŠããRepositoryãç¹å®ããŸããããã³ããšã³ãïŒNuxt.jsïŒãããã¯ãšã³ãïŒGoïŒãã€ã³ãã©ïŒTerraformïŒã®ããããã倿ããé©åãªRepositoryã«çŠç¹ãåœãŠãŸãã ## 3. é¢é£ããGit Repositoryãä»ã«ãªããèª¿æ» ç¹å®ãããRepository以å€ã«ãããšã©ãŒã«é¢é£ããå¯èœæ§ãããRepositoryããªããã調æ»ããŸããäŸãã°ãããã³ããšã³ããšã©ãŒãããã¯ãšã³ãAPIã®å€æŽã«èµ·å ããå Žåããã€ã³ãã©èšå®ã®å€æŽã圱é¿ããŠããå Žåãªã©ãèæ
®ããŸãã ## 4. ãšã©ãŒã®è©³çްã«é¢ãã調æ»ãšçµæã®åºå äžèšãåæçµæãã©ãŒããããã«åŸããå¿
èŠãªæ
å ±ã調æ»ããŠãã ããã ### 4-1. ã€ã³ãã©æ§æå³ãã¢ãŒããã¯ãã£å³ãå¿
èŠãªå Žåã¯åºå ãšã©ãŒç®æãåå ãå
šäœåãææ¡ã§ãããããA. AWSã®ã€ã³ãã©æ§æå³, B. ã·ã¹ãã æŠèŠå³ ã®2ã€ãæ·»ä»ããŠãã ããã åºåæ¹æ³ã¯ä»¥äžã®éãã§ãA, Bããããã«å¯ŸããŠé çªã«å®è¡ããŠãã ããã 1. mmdãã¡ã€ã«ãåºå (mmdãã¡ã€ã«åã¯A: infra.mmd, B: system.mmd ãšãã) 2. 次ã®ã³ãã³ããå®è¡ïŒmmdc -i <mmdãã¡ã€ã«ãã¹> -o <åºåãã¡ã€ã«å(PNG)> (åºåãã¡ã€ã«åã¯A: infra.png, B: system.png ãšãã) 3. åºåç»åãæ·»ä» ### 4-2. é¢é£Commitã®æ€çŽ¢ gh ã³ãã³ããŸãã¯git ã³ãã³ãã䜿çšããŠãã¢ã©ãŒãã®æ ¹æ¬åå ãšãªãã³ãŒããã©ã®commit, PRã§è¿œå ã»å€æŽãããã®ããç¹å®ããŠãã ããã ------------------------- å®è£
ã¯è¡ããã«ããåæçµæãã©ãŒãããããã³ãŒãæç€ºã«ãŒã«ãã«åŸã£ãŠã¬ããŒããåºåããŠãã ããã åæçµæãã©ãŒããã:""" ðãšã©ãŒã®åºæ¬æ
å ±ç¢ºèª ã»ãšã©ãŒã¿ã€ã ã»ç°å¢ ã»çºçé »åºŠ ã»åœ±é¿ç¯å² ã»çºçæé(yyyy-mm-dd HH:MM:SSã®åœ¢åŒãJST倿å¿
é ) ã»åå(yyyy-mm-dd HH:MM:SSã®åœ¢åŒãJST倿å¿
é ) ã»æçµ(yyyy-mm-dd HH:MM:SSã®åœ¢åŒãJST倿å¿
é ) ð§ââïž é害ã¬ãã«å€æ ã»ðšç·æ¥åºŠé«ïŒå³æå¯Ÿå¿å¿
èŠïŒãµãŒããŒããŠã³ãžã®åœ±é¿ãªã©ïŒ ã»ð¡ç·æ¥åºŠäžïŒãã±ããåã£ãŠä»é±äžã«å¯Ÿå¿ïŒç¹å®æ¡ä»¶äžã§ã®ãšã©ãŒããŠãŒã¶ãŒåœ±é¿ãªãïŒ ã»ðµç·æ¥åºŠäœïŒãã±ããåã£ãŠæéããæã«å¯Ÿå¿ïŒè»œåŸ®ãªäžå
·åãããã©ãŒãã³ã¹äœäžïŒ ð¬ ãšã©ãŒåå å€å® ã»ã·ã¹ãã åŽã®åé¡ïŒãã°ãèšå®ãã¹ããªãœãŒã¹äžè¶³ãªã©ïŒ ã»å€éšèŠå ïŒæ»æçãªã¯ãšã¹ããå€éšãµãŒãã¹é害ãªã©ïŒ ðŠ é¢é£ã®ããCommit,PR ã»æ ¹æ¬åå ãšãªãã³ãŒããã©ã®commit, PRã§è¿œå ã»å€æŽãããã®ã ð§âð» ãšã©ãŒã®åçŸæ¹æ³ ã»ããŒã«ã«ç°å¢ãéçºç°å¢ã§ãšã©ãŒã®åçŸæ¹æ³ã®æç€º ð 察å¿ççå® ã»äžæç察å¿ãšæä¹
ç察å¿ã®åºå¥ ã»æ»æçãªã¯ãšã¹ãã®å Žåã®ã»ãã¥ãªãã£å¯Ÿç """ ã³ãŒãæç€ºã«ãŒã«ïŒ é¢é£ã³ãŒãã瀺ãå¿
èŠãããã°ã以äžã®ããã«ã³ãŒããšGitHubã®ããŒããªã³ã¯ãå«ãã圢ã§åºåããŠãã ãã [delishkitchen_file_name](https://github.com/delishkitchen_file_name#L92-L98) \``` Sentry.withScope(function (scope) { scope.setTag('method', method) scope.setTag('url', path) scope.setTag('query', queryString) Sentry.captureException(err) }) \``` --------------- ãã®æé ã«åŸã£ãŠæ®µéçã«èª¿æ»ãé²ããããšã You only need to look in the following repos: {backend_repository}, {infra_repository}, {frontend_repository} 以éã詳现ã«ã€ããŠè§£èª¬ããŸãã 1. Devinã®èµ·åãšSentryã¢ã©ãŒãæ
å ±ã®ååŸ Devinã®èµ·åã«ã¯Slack workflowãçšããŸãããDevinãšSlackã飿ºããããšã§ã @Devin ã§DevinãSlackã®ã¹ã¬ããããã£ã³ãã«ã§äŒè©±ãéå§ã§ããŸããããã«ãããåæã«ã»ãã·ã§ã³ãéå§ãããŸãããã®ãããä»åã¯è§£æ±ºãããSentryã®ã¡ãã»ãŒãžã« :help-me-devin: ãšãªã¢ã¯ã·ã§ã³ããããšã§ãã®ã¹ã¬ããã«äžèšã®æç« ãåºåãããããã«ããŸããã !sentryanalyzer ã¯åè¿°ã®Devin Playbookã®ãã¯ããšãªã£ãŠããŸãã @Devin !sentryanalyzer @user_name ã«ãã£ãŠäŸé ŒãããŸããã äŸé Œè
ã¯Devinã®ã¬ããŒããçµããæ¬¡ç¬¬ãsleep ãšå
¥åããŠDevinãäŒãŸããŠãããŠãã ããã 2. Devin Playbookã®å®è¡ æé 1ãŸã§ã®åŠçã§Devin sessionã®èµ·åãšSlackã¡ãã»ãŒãžã®çŽä»ããå®äºããŠãããããããããå®éã«Devinã®åŠçãéå§ãããŸãã 2-1. é¢é£æ
å ±ã®ååŸ æ¬¡ã«äžèšæäœã§é¢é£ããæ
å ±ã®ååŸãè¡ããŸãã Sentry APIã®å®è¡ 察象ãšãªãGit Repositoryã®ç¹å®ãé¢é£ããGit Repositoryãä»ã«ãªããèª¿æ» Sentry APIã¯äºåã«Devin Secretã«Sentry API Tokenã远å ããŠããã®ã§ãããšSlackã®ã¡ãã»ãŒãžããSentry issue_idãååŸã㊠Retrieve an Issue ãš List an Issue's Events ãå®è¡ããŠissueã®è©³çްãååŸããŸãã Repositoryã®ç¹å®ã調æ»ã¯äºåã«Devin's Workspaceã«çŽä»ããŠããRepositoryãæ¢çŽ¢ããããã«ããŠããŸãã 2-2. åæ æ¬¡ã«ãããã®æ
å ±ãããšã«ãšã©ãŒã®åå ã®åæãè¡ãããŸãããããŸã§ã§Sentryã®è©³çްãšå¯Ÿè±¡ã®ã³ãŒãã®ç®æãã€ããŠããã®ã§ãããããšã«åæãè¡ãããŠããŸãã åæã®å
容ãšããŠã¯æçµçãªåºåã«å«ãŸããSentryãããšã«ããçºçé »åºŠãªã©ã®ãšã©ãŒã®åºæ¬æ
å ±ãé害ã¬ãã«ããšã©ãŒã®åå ããšã©ãŒã®åçŸæ¹æ³ã察å¿çã«ãªããŸãã 2-3. è¿œå æ
å ±ã®ååŸ 2-2ã®çµæãããšã«åå ãšãªãcommitã®ç¹å®ã gh ã³ãã³ãã䜿ã£ãŠååŸããŸãã 2-4. å³è¡šã®äœæ ãšã©ãŒã®çè§£ãæ·±ãããããMermaidã䜿çšããŠAWSã€ã³ãã©æ§æå³ãšã·ã¹ãã æŠèŠå³ãèªåçæããŸããããã«ããããšã©ãŒãçºçããŠããç®æãšã·ã¹ãã å
šäœã®é¢ä¿æ§ãèŠèŠçã«ææ¡ã§ããŸãã ã€ã³ãã©æ§æå³ïŒinfra.mmd â infra.pngïŒ : AWSãªãœãŒã¹éã®é¢ä¿æ§ãšããŒã¿ãããŒã衚瀺 ã·ã¹ãã æŠèŠå³ïŒsystem.mmd â system.pngïŒ : ã¢ããªã±ãŒã·ã§ã³å±€ãšã€ã³ãã©å±€ã®çžäºäœçšã衚瀺 3. Slackãžåºå 2ãŸã§ã®æ
å ±ãããšã«Playbookã«èšè¿°ãããŠããäžèšã®åœ¢ã§æ
å ±ãæŽçããã¹ã¬ããã«è¿ä¿¡ãè¡ã£ãŠããããŸãã ðãšã©ãŒã®åºæ¬æ
å ±ç¢ºèª ã»ãšã©ãŒã¿ã€ã ã»ç°å¢ ã»çºçé »åºŠ ã»åœ±é¿ç¯å² ã»çºçæé(yyyy-mm-dd HH:MM:SSã®åœ¢åŒãJST倿å¿
é ) ã»åå(yyyy-mm-dd HH:MM:SSã®åœ¢åŒãJST倿å¿
é ) ã»æçµ(yyyy-mm-dd HH:MM:SSã®åœ¢åŒãJST倿å¿
é ) ð§ââïž é害ã¬ãã«å€æ ã»ðšç·æ¥åºŠé«ïŒå³æå¯Ÿå¿å¿
èŠïŒãµãŒããŒããŠã³ãžã®åœ±é¿ãªã©ïŒ ã»ð¡ç·æ¥åºŠäžïŒãã±ããåã£ãŠä»é±äžã«å¯Ÿå¿ïŒç¹å®æ¡ä»¶äžã§ã®ãšã©ãŒããŠãŒã¶ãŒåœ±é¿ãªãïŒ ã»ðµç·æ¥åºŠäœïŒãã±ããåã£ãŠæéããæã«å¯Ÿå¿ïŒè»œåŸ®ãªäžå
·åãããã©ãŒãã³ã¹äœäžïŒ ð¬ ãšã©ãŒåå å€å® ã»ã·ã¹ãã åŽã®åé¡ïŒãã°ãèšå®ãã¹ããªãœãŒã¹äžè¶³ãªã©ïŒ ã»å€éšèŠå ïŒæ»æçãªã¯ãšã¹ããå€éšãµãŒãã¹é害ãªã©ïŒ ðŠ é¢é£ã®ããCommit,PR ã»æ ¹æ¬åå ãšãªãã³ãŒããã©ã®commit, PRã§è¿œå ã»å€æŽãããã®ã ð§âð» ãšã©ãŒã®åçŸæ¹æ³ ã»ããŒã«ã«ç°å¢ãéçºç°å¢ã§ãšã©ãŒã®åçŸæ¹æ³ã®æç€º ð 察å¿ççå® ã»äžæç察å¿ãšæä¹
ç察å¿ã®åºå¥ ã»æ»æçãªã¯ãšã¹ãã®å Žåã®ã»ãã¥ãªãã£å¯Ÿç çµæ éçšããŠã¿ãçµæ å®éã«éçšããŠã¿ãŠä»¥äžã®å¹æã確èªã§ããŸããã Sentryã¢ã©ãŒãã®äžæå¯Ÿå¿ã«ã€ããŠã¯Devinã«ä»»ããããããã«ãªã£ã ã¢ã©ãŒãçºçããçŽ3åã§åæèª¿æ»ãåå ç¹å®ãŸã§å®äºããããã«ãªã£ã ããã³ããšã³ãã»ããã¯ãšã³ãã»ã€ã³ãã©ã®åRepositoryãè·šãã 調æ»ãèªåã§å®è¡ããããããèª¿æ»æŒãããªããªã£ã Mermaidã§çæãããå³è¡šãåãããããããšã©ãŒç®æã®ææ¡ãå§åçã«æ¥œã«ãªã£ã å人çã«ã¯ãç¹ã«èª¿æ»ã®äžè²«æ§ãä¿ãããããã«ãªã£ãã®ãäžçªè¯ããã€ã³ãã ãšæããŠããŸãã人ã«ãã£ãŠèª¿æ»ã®æ·±ãã«ã°ãã€ãããã£ãã®ããDevinã䜿ãããšã§æ¯ååãã¬ãã«ã®èª¿æ»ãæ
ä¿ãããããã«ãªããŸããã ããã«ããã¢ã©ãŒã察å¿ã®ããŒãã«ãäžãã£ãã®ã§ãå±äººåãé²ããã®ã§ã¯ãªãããšèããŠããŸãã éçšããŠã¿ãŠèŠããŠããèª²é¡ äžæ¹ã§ãããã€ã課é¡ãèŠããŠããŸããã AWSã®ãã°ãã¢ãã¿ãªã³ã°æ
å ±ãšé£æºãã調æ»ã¯ãŸã ã§ããŠããªã GitHubã®ããŒããªã³ã¯åºåãé¢é£ãªããžããªã®ææ¡ã§ãçµæã«ã°ãã€ããåºãããšããã è€éãªæç€ºãäžåºŠã«åºããããæ®µéçã«æä»€ãåºããæ¹ã粟床ãäžããåŸåããã ç¹ã«3ã€ç®ã«ã€ããŠã¯ãæåã¯å
šéšãŸãšããŠæç€ºããŠããã®ã§ãããæ®µéçã«æç€ºãåºãããšã§æããã«çµæã®å質ãåäžããã®ã§ãéçšã®ã³ããšããŠèŠããŠãããããã€ã³ãã§ããã ãŸãšã ç§èªèº«ãæ®æ®µCursorãClaude Codeã䜿ãéã¯AIãšã®äŒè©±ãåŸåŸ©ããããšãåæã«éãªããã³ãããæãããããã®ã§ãèªç«ã§ããããã«ååãªããã³ãããäžããå¿
èŠãããç¹ã§èªç«åAIãšãŒãžã§ã³ãã®æ±ãã«èŠåŽããŸãããPlaybookã®ãããªãã³ãã¬ãŒãæ©èœãããã®ã§ãç¹°ãè¿ãã䌎ãã¿ã¹ã¯ã§ã¯å¹åãçºæ®ããããšã¯åããã€ã€ããæ®æ®µã®æ¥åã§äœ¿ãã€ã¡ãŒãžã¯å°ãããã«ããã£ãã§ãã ãã®ç¹ãã¢ã©ãŒã察å¿ã¯æ±ºãŸã£ãåããããããšãå€ãã®ã§ãä»åã®Playbookã«å ããŠã¢ã©ãŒã察å¿ãåŸæãªã¡ã³ããŒã®æ®æ®µã®åããå
±æããã ãããšã§ãããã«ç²ŸåºŠã®ãã察å¿ãã§ããã®ã§ã¯ãªãããšæããŸããã ãŸãããã®å®è£
ãè¡ã£ãåŸã« Devin MCP Marketplace ãå
¬éãããã®ã§ããããçšããŠããã«ã³ã³ããã¹ãéãå¢ããããšã§æ§èœãã©ããªããã¯ä»åŸè©ŠããŠã¿ããã§ãã ãããŸã§èªãã§ããã ãããããšãããããŸããDevinã§ã¢ã©ãŒãåå察å¿ãçéåããããšããŠããæ¹ã®åèã«ãªã£ãã幞ãã§ãã
ã¯ããã« ããã«ã¡ã¯ããã¢ããã§éçºãæ
åœããŠããåç°ã§ãã AWS ãæŽ»çšãããµãŒãã¹éå¶ã«ãããŠãIaCïŒInfrastructure as CodeïŒããŒã«ã®éžæã¯é·æçãªéçšå¹çã«åœ±é¿ããããšããããŸãã æ¬èšäºã§ã¯ãå®éã«ç§ãã¡ãçµéšãã Serverless Framework v3 ãã lambroll ãš Terraform ãžã®ç§»è¡äºäŸãããšã«ã ç§»è¡ã®èæ¯ããå
·äœçãªæé ããããŠç§»è¡ãéããŠåŸãããç¥èŠã«ã€ããŠãŸãšããŠããŸãã ãªããç§»è¡å
ã®åè£æ€èšãåããŒã«ã®æ¯èŒã«ã€ããŠã¯ã ååã®æ€èšŒç·šèšäº ã§è©³ãã解説ããŠããŸãã®ã§ã䜵ããŠãåç
§ãã ããã èæ¯ïŒServerless Framework ãåãå·»ãç°å¢å€å é©å㪠IaC ããŒã«ã®éžæã¯å€§åãªå€æã®äžã€ã§ãã代衚çãªããŒã«ãšããŠã¯ã Serverless Framework ã AWS SAM ã Terraform ãªã©ãæããããŸãããããã®ããŒã«ã¯ãããããç°ãªãç¹åŸŽãšå©ç¹ãæã¡ããããžã§ã¯ãã®èŠä»¶ã«å¿ããŠéžæããããšãå€ãã§ãã äžã§ããServerless Framework ã¯å€ãã®ãããžã§ã¯ãã§æ¡çšãããŠããæåãªéžæè¢ã®äžã€ã§ãããããã2024 幎㮠v4 ãªãªãŒã¹ã«äŒŽããã©ã€ã»ã³ã¹åœ¢æ
ã®å€§å¹
ãªå€æŽãçºçããŸãããïŒ åè ïŒ ããããèæ¯ãããç§ãã¡ã¯ä»£æ¿ææ®µã®æ€èšãéå§ããŸãããããããã¯ãå®éã«ç§ãã¡ãè¡ã£ãç§»è¡ãããžã§ã¯ãã®èšé²ãšãããããåŸãããæèšã«ã€ããŠç޹ä»ããŸãã ç§»è¡ã®èæ¯ Serverless Framework v4 ã®å€æŽç¹ 2024 幎ãServerless Framework v4 ããªãªãŒã¹ãããåŸæ¥ã®ãªãŒãã³ãœãŒã¹ã¢ãã«ããèµãåããŸããã ã©ã€ã»ã³ã¹åœ¢æ
ã®å€æŽ : äžå®ä»¥äžã®åçãäžããçµç¹ã§ã¯ææãµãã¹ã¯ãªãã·ã§ã³ãå¿
é v3 ã®ãµããŒãçµäº : 2024 幎æ«ãŸã§ã®å»¶é·ãµããŒãã®ã¿ã§ãæ©èœæ¹åã»ãã°ä¿®æ£ã¯çµäº ã©ã³ã¿ã€ã 察å¿ã®é
ã : ææ°ã® AWS Lambda ã©ã³ã¿ã€ã æŽæ°ãžã®è¿œéã忢 課é¡ã®æŽç ãããã®å€æŽã«ãããç§ãã¡ã¯ä»¥äžã®èª²é¡ãæããŸããã ç¶ç¶çãªã©ã€ã»ã³ã¹è²»çšã®çºç å°æ¥çãªã©ã³ã¿ã€ã ãµããŒãåãã®ãªã¹ã¯ v3âv4 ç§»è¡ã«äŒŽãéçšãããŒå€æŽã®è² è· ç§»è¡å
ã®æ¡çš æ€èšŒç·šèšäº ã§è€æ°ã®ç§»è¡å
åè£ïŒPulumiãAWS CDKãAWS SAMãlambroll + TerraformãTerraform + AWS CLIïŒãæ¯èŒæ€èšããçµæãåŠç¿ã³ã¹ãã瀟å
ã§ã®éçšå®çžŸãèæ
®ãããlambroll + Terraformãã®çµã¿åãããæ¡çšããããšã«ããŸããã ãã®éžæã«ããã以äžã®ã¡ãªãããæåŸ
ããŸããã ã©ã€ã»ã³ã¹è²»çšã®åé¿ IaC ããŒã«ã®çµ±äžã«ããéçšå¹çåäž AWS ã®ãã€ãã£ãæ©èœãžã®å®å
šå¯Ÿå¿ ãã现ããç²åºŠã§ã®ãªãœãŒã¹ç®¡ç ç§»è¡ã¢ãããŒã ä»åç§»è¡ããã®ã¯ãCodeBuild ã®å®è¡çµæã Slack ã«éç¥ãã Lambda 颿°ãšãã®åšèŸºãªãœãŒã¹ïŒEventBridgeãIAM ããŒã«ïŒã§ãã æ³šæ ïŒãã®éç¥æ©èœã¯äžæçã«åæ¢ããŠãæ¥åã«é倧ãªåœ±é¿ããªããããç§»è¡äžã®ãµãŒãã¹åæ¢ã蚱容ããåæã§æé ãèšèšããŠããŸããæ¬çªç°å¢ã®éèŠãªãµãŒãã¹ãç§»è¡ããå Žåã¯ãç¡åæ¢ã§ã®ç§»è¡æé ãæ€èšããããšããå§ãããŸãã ç§»è¡æŠç¥ å®å
šæ§ãéèŠãã以äžã®æ®µéçã¢ãããŒããæ¡çšããŸããã ç§»è¡åã®æºåãšèª¿æ» lambroll ã«ãã Lambda 颿°ã®å
è¡ç§»è¡ Terraform ã«ããåšèŸºãªãœãŒã¹ã®æ®µéçç§»è¡ çµ±åãã¹ããšåäœç¢ºèª Serverless Framework ã¹ã¿ãã¯ã®åé€ å®è·µçãªç§»è¡æé Step 1: ç§»è¡åã®æºåãšèª¿æ» ç§»è¡ãå®å
šã«é²ããããããŸãã¯çŸç¶ææ¡ãšããã¯ã¢ããååŸããå§ããŸãã # CloudFormation ã¹ã¿ãã¯ã®è©³çްååŸ aws cloudformation describe-stacks \ --stack-name your-service-stack # Lambda 颿°ã®ããã¯ã¢ãã aws lambda get-function \ --function-name your-function-name \ > function-backup.json # CloudFormation ã®ããã¯ã¢ãã aws cloudformation get-template \ --stack-name your-service-stack \ > backup-cfn.json Step 2: lambroll ã«ãã Lambda 颿°ã®ç§»è¡ lambroll ã®åæå # æ¢åã® Lambda 颿°ãã lambroll èšå®ãçæ lambroll init --download \ --function-name your-function-name ãã®ã³ãã³ãã«ããã以äžã®ãã¡ã€ã«ãèªåçæãããŸãã function.json : Lambda 颿°ã®èšå® .lambdaignore : ãããã€æã«é€å€ãããã¡ã€ã«ã®å®çŸ© function.zip : çŸåšã®é¢æ°ã³ãŒã function.json ã®èª¿æŽ çæããã function.json ãç°å¢å€æ°ãã¿ã€ã ã¢ãŠãèšå®ã«åãããŠèª¿æŽã { " FunctionName ": " your-function-name ", " Runtime ": " nodejs22.x ", " Timeout ": 30 , " MemorySize ": 128 , " Role ": " arn:aws:iam::{{ env `AWS_ACCOUNT_ID` }}:role/<IAM ããŒã«å> ", " Environment ": { " Variables ": { " SLACK_WEBHOOK_URL ": " {{ env `SLACK_WEBHOOK_URL` }} " } } } ç°å¢å€æ°ãã¡ã€ã«ã®äœæ # development.env SLACK_WEBHOOK_URL =https://hooks.slack.com/services/YOUR/WEBHOOK/URL AWS_ACCOUNT_ID = 123456789012 ãããã€ãšãã¹ã # äºåç¢ºèª lambroll deploy --dry-run --envfile =< ãããã€å
ã®ç°å¢ > .env # å®éã®ããã〠lambroll deploy --envfile =< ãããã€å
ã®ç°å¢ > .env # åäœç¢ºèª lambroll invoke \ --payload =' {"detail":{"build-status":"FAILED"}} ' \ --envfile =< ãããã€å
ã®ç°å¢ > .env Step 3: Terraform ã«ããåšèŸºãªãœãŒã¹ã®ç§»è¡ æ¢åãªãœãŒã¹ã®è©³çŽ°èª¿æ» Terraform import ãé²ããããã«ãæ¢åãªãœãŒã¹ã®æ£ç¢ºãªèå¥åãåéã # EventBridge ã«ãŒã«ã®è©³çް aws events list-rules --name-prefix " your-service " # Lambda ããŒããã·ã§ã³ã®ç¢ºèª aws lambda get-policy --function-name your-function-name # EventBridge ã¿ãŒã²ããã®ç¢ºèª aws events list-targets-by-rule --rule your-rule-name # IAM ããŒã«ã®è©³çް aws iam get-role --role-name your-lambda-role Terraform èšå®ã®äœæ # Lambda ãã°æš©éããªã·ãŒ data "aws_iam_policy_document" "lambda_logging" { statement { effect = "Allow" actions = [ "logs:CreateLogStream" , "logs:CreateLogGroup" , "logs:TagResource" ] resources = [ "<Lambdaã®ãã°ã°ã«ãŒãARN>" ] } statement { effect = "Allow" actions = [ "logs:PutLogEvents" ] resources = [ "<Lambdaãã°ã¹ããªãŒã ARN>" ] } } # Lambda ãã°ããªã·ãŒäœæ module "lambda_logging" { source = "terraform-aws-modules/iam/aws//modules/iam-policy" version = "5.59.0" name = "lambda_logging_policy" policy = data.aws_iam_policy_document.lambda_logging.json } # Lambda å®è¡ããŒã«äœæ module "lambda_logging_role" { source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role" version = "5.59.0" create_role = true role_name = "lambda_logging_role" role_requires_mfa = false trusted_role_services = [ "lambda.amazonaws.com" ] custom_role_policy_arns = [ module.lambda_logging.arn ] } # EventBridge ã«ãŒã« resource "aws_cloudwatch_event_rule" "codebuild_notification" { name = "codebuild-notification-rule" description = "CodeBuild status change notification" event_pattern = jsonencode ( { source = [ "aws.codebuild" ] detail-type = [ "CodeBuild Build State Change" ] detail = { build-status = [ "FAILED" , "SUCCEEDED" ] } } ) } # EventBridge ã¿ãŒã²ãã resource "aws_cloudwatch_event_target" "lambda" { rule = aws_cloudwatch_event_rule.codebuild_notification.name target_id = "notificationLambdaTarget" arn = data.aws_lambda_function.notification.arn } # Lambda ããŒããã·ã§ã³ resource "aws_lambda_permission" "allow_eventbridge" { statement_id = "AllowExecutionFromEventBridge" action = "lambda:InvokeFunction" function_name = data.aws_lambda_function.notification.function_name principal = "events.amazonaws.com" source_arn = aws_cloudwatch_event_rule.codebuild_notification.arn } æ¢åãªãœãŒã¹ã® import # EventBridge ã«ãŒã« terraform import aws_cloudwatch_event_rule.codebuild_notification \ < EventBridgeã«ãŒã«å > # EventBridge ã¿ãŒã²ãã terraform import aws_cloudwatch_event_target.lambda \ < EventBridgeã«ãŒã«ã®å®éã®åå > / < ã¿ãŒã²ããID > # Lambda ããŒããã·ã§ã³ terraform import aws_lambda_permission.allow_eventbridge \ < Lambda颿°å > / < LambdaããŒããã·ã§ã³ã®StatementId > # IAM ããŒã« terraform import module.lambda_logging_role.aws_iam_role.this \ < IAM ããŒã«å > ãã€ã³ã : CloudFormation ã§çæããããªãœãŒã¹åã¯äºæž¬ãã«ãããããAWS CLI ã§æ£ç¢ºãªååã確èªããŠãã import ããå¿
èŠããããŸãããŸããimport å®äºåŸã¯å¿
ã terraform plan ã§ããªããããªãããšã確èªããŸãããã æ®µéçãªé©çš # IAM ããŒã«ã®ã¿å
è¡é©çš terraform apply --target = aws_iam_role.lambda_role # Lambda 颿°ã®åãããã€ïŒæ°ãã IAM ããŒã«ã䜿çšïŒ lambroll deploy --envfile =< ãããã€å
ã®ç°å¢ > .env # æ®ãã®ãªãœãŒã¹ãé©çš terraform apply IAM ããŒã«ãå
è¡é©çšããçç±ã¯ãlambroll ã Lambda 颿°ããããã€ããéã«å®è¡ããŒã«ãå¿
èŠã ããã§ããããŒã«ãååšããªãç¶æ
ã§ lambroll deploy ãå®è¡ãããšãšã©ãŒã«ãªã£ãŠããŸãããããŸã Terraform ã§ IAM ããŒã«ãäœæããŠãã Lambda 颿°ã®ãããã€ãè¡ããŸãã Step 4: Serverless Framework ããã®åé¢ serverless.yml ããã® Lambda 颿°åé€ # functions ã»ã¯ã·ã§ã³ãã³ã¡ã³ãã¢ãŠã # functions: # notification: # handler: handler.notifier # events: # - cloudwatchEvent: # event: # source: # - aws.codebuild 圱é¿ç¯å²ã®ç¢ºèªãšé©çš # 倿Žã®åœ±é¿ãç¢ºèª sls package # Lambda 颿°ãšé¢é£ãªãœãŒã¹ã Serverless 管çããåé€ sls deploy # Serverless Framework ã«ããåé€ã§ãªãœãŒã¹ãæ¶ããããã # Terraform ãš lambroll ã§åäœæ terraform apply lambroll deploy --envfile =< ãããã€å
ã®ç°å¢ > .env Step 5: çµ±åãã¹ããšæçµç¢ºèª ãšã³ãããŒãšã³ããã¹ã # EventBridge çµç±ã§ã®ãã¹ã aws events put-events --entries file://test-event.json # ãã°ã®ç¢ºèª aws logs get-log-events \ --log-group-name /aws/lambda/your-function-name Serverless ã¹ã¿ãã¯ã®åé€ # æ®åãªãœãŒã¹ã®ç¢ºèª aws cloudformation describe-stack-resources \ --stack-name your-service-stack # ã¹ã¿ãã¯ã®åé€ sls remove lambroll vs Serverless Framework: éçšé¢ã§ã®éã ç§»è¡ãéããŠå®æãã倧ããªéãã¯ããããã€ã®ä»çµã¿ãšéçšç¹æ§ã§ããã é
ç® Serverless Framework lambroll ãããã€æ¹åŒ CloudFormation ã¹ã¿ãã¯æŽæ° Lambda API çŽæ¥åŒã³åºã 察象ç¯å² Lambda + å
šé¢é£ãªãœãŒã¹ Lambda 颿°ã®ã¿ ãããã€é床 CloudFormation ã®åŠçæéã«äŸå Lambda API ã®å¿çæé lambroll 㯠Lambda API ãçŽæ¥åŒã³åºããããã³ãŒãã®å€æŽãçŽ æ©ãåæ ã§ããŸããéçºæã®å埩ãµã€ã¯ã«ãæ¹åãããŸããã åŸãããç¥èŠãšãã¹ããã©ã¯ãã£ã¹ 1. 段éçç§»è¡ã«ã€ã㊠äžåºŠã«ãã¹ãŠãç§»è¡ããã®ã§ã¯ãªããLambda 颿°ãå
è¡ç§»è¡ããããšã§ããªã¹ã¯ãæããããšãã§ããŸãããããã«ãããåé¡ãçºçããå Žåã®åœ±é¿ç¯å²ãéå®ãããããªããŸãã 2. CloudFormation ã§çæããããªãœãŒã¹åã®ææ¡ Serverless Framework ãèªåçæãããªãœãŒã¹åã¯äºæž¬ãã«ããã§ããç§»è¡åã« AWS CLI ã䜿ã£ãŠæ£ç¢ºãªååã調æ»ããããšã§ãimport äœæ¥ãã¹ã ãŒãºã«é²ã¿ããããªããŸãã 3. ç°å¢å€æ°ç®¡çã®çµ±äž lambroll ãš Terraform ã§ç°å¢å€æ°ã®ç®¡çæ¹æ³ãçµ±äžããããšã§ãèšå®ãã¹ãé²ãããããªããŸãã.env ãã¡ã€ã«ã掻çšããçµ±äžçãªç®¡çããå§ãããŸãã 4. ããã¯ã¢ãããšããŒã«ããã¯æŠç¥ ç§»è¡äœæ¥ã§ã¯ãåæ®µéã§ã®ããã¯ã¢ãããšãåé¡çºçæã®ããŒã«ããã¯æé ãäºåã«å®çŸ©ããŠããããšã倧åã§ãã 5. ãµãŒãã¹åæ¢ã®èš±å®¹ç¯å²ã®äºåç¢ºèª ä»åã®ç§»è¡ã§ã¯éç¥æ©èœãšããæ§è³ªäžãäžæçãªãµãŒãã¹åæ¢ã蚱容ã§ããŸãããããããæ¬çªç°å¢ã®éèŠãªãµãŒãã¹ã§ã¯ç¡åæ¢ç§»è¡ãå¿
èŠãªå ŽåããããŸããç§»è¡å¯Ÿè±¡ã®éèŠåºŠãšãµãŒãã¹åæ¢ã®åœ±é¿ç¯å²ãäºåã«è©äŸ¡ããé©åãªç§»è¡æŠç¥ãéžæããããšãéèŠã§ãã ãŸãšã ä»åã®ç§»è¡ãããžã§ã¯ããéããŠãããŒã«éžæã«ãããé·æçãªèŠç¹ã®å€§åããæ¹ããŠèªèããŸããã ãŸããç§»è¡äœæ¥ã®äžã§æ®µéçãªã¢ãããŒããããªã¹ã¯ãæããªããçå®ã«ææãåŸãéµã§ããããšã宿ããŸããã æ€èšŒç·šèšäº ã§ã®äºå調æ»ããå®éã®ç§»è¡äœæ¥ãŸã§ãäžé£ã®åãçµã¿ãéããŠãäºå調æ»ã§æ³å®ããŠããã¡ãªããïŒãããã€éåºŠã®æ¹åãIaC ããŒã«ã®çµ±äžãã©ã€ã»ã³ã¹è²»çšã®åé¿ïŒãå®çŸã§ããŠããŸãã ä»åŸã¯ããã®ç§»è¡ã§åŸãããç¥èŠã掻ãããä»ã®ãããžã§ã¯ãã§ãåæ§ã®ã¢ãããŒããé©çšããŠããäºå®ã§ãã IaC ããŒã«ã®éžæã¯äžåºŠæ±ºããã°çµããã§ã¯ãªããæè¡ç°å¢ã®å€åã«å¿ããŠç¶ç¶çã«èŠçŽããè¡ãããšãéèŠã§ããä»åŸãæé©ãªããŒã«éžæãšéçšå¹çã®åäžã«åãçµãã§ãããŸãã åæ§ã®ç§»è¡ãæ€èšãããŠããæ¹ã®åèã«ãªãã°å¹žãã§ãããŸãã¯å°ããªãããžã§ã¯ãããæ®µéçã«è©ŠããŠã¿ãããšããå§ãããŸãã
ã¯ããã« ããã«ã¡ã¯ãããªãã·ã¥ãããã³ã§ããŒã¿ãµã€ãšã³ãã£ã¹ããããŠãã倿¿µã§ãã ä»åã¯ããããªå
容ã§ãããã¿ã€ãã«éãã®åé¡ãçºçããããããã®å¯ŸåŠæ³ã«ã€ããŠåå¿é²çã«ãŸãšããŸãã åäœç°å¢ã¯ä»¥äžã«ãªããŸãã Databricks Runtime: 15.4LTS for ML Python: 3.11.11 ã©ã€ãã©ãªã¯Databricks Runtimeã®ããŒãžã§ã³ãã以äžã«ã¢ããã°ã¬ãŒãããŠããŸã openai==1.65.2 mlflow==2.20.3 pydantic==2.10.6 databricks-agents==0.16.0 databricks-sdk==0.50.0 MLflow Tracingã«é¢ããããã¥ã¡ã³ãã¯ä»¥äžã«ãªããŸãã mlflow.org åé¡ æºå ãŸããå
·äœçã«ã©ããªåé¡ãçºçãããã説æããããã«ã以äžã®ãããªã³ãŒããçšæããŸãã ããããããšãšããŠã¯ããŠãŒã¶ãŒã®ã¯ãšãªãããã£ã«ã¿ãªã³ã°æ¡ä»¶ãæœåºããã¿ã¹ã¯ãLLMã«ãããŸãã ããã¯ ä»¥åæžããããã¯ããã°ã§ã®ãã£ã«ã¿ãªã³ã°åŠç ãããŒã¹ãšããŠããŸãã ä»åã¯ã調çæéãšèª¿çè²»çšã®ã¿ããã£ã«ã¿ãªã³ã°æ¡ä»¶ãšããŠæœåºããã¿ã¹ã¯ãšããŸãã import mlflow from enum import Enum from pydantic import BaseModel import os os.environ[ "OPENAI_API_KEY" ] = dbutils.secrets.get(...) # your scope and key # mlflow.traceãèªåã§å¯Ÿå¿ããããopenaiã®autologãç¡å¹ã«ãã mlflow.openai.autolog(disable= True ) # 調çæéã®ãã£ã«ã¿ãªã³ã°æ¡ä»¶ class CookingTimeColumn ( str , Enum): cooking_time = "cooking_time_min" class CookingTimeOperator ( str , Enum): greater_than = ">" less_than = "<" greater_than_or_equal_to = ">=" less_than_or_equal_to = "<=" class CookingTimeFilter (BaseModel): column: CookingTimeColumn operator: CookingTimeOperator value: float class CookingTimeFilters (BaseModel): cooking_time_filters: list [CookingTimeFilter] # 調çè²»çšã®ãã£ã«ã¿ãªã³ã°æ¡ä»¶ class CookingCostColumn ( str , Enum): cooking_cost = "cooking_cost_yen" class CookingCostOperator ( str , Enum): greater_than = ">" less_than = "<" greater_than_or_equal_to = ">=" less_than_or_equal_to = "<=" class CookingCostFilter (BaseModel): column: CookingCostColumn operator: CookingCostOperator value: float class CookingCostFilters (BaseModel): cooking_cost_filters: list [CookingCostFilter] ãŠãŒã¶ãŒã®å
¥åã¯ãšãªã¯ä»¥äžãäŸãšããŠäœ¿çšããŸãã user_query = "10å以å
ã«500åæªæºã§äœããå¯èæããŠ" MLflow Tracingã䜿çšãã颿°ãå®çŸ© MLflow Tracingã¯ã颿°ã«å¯Ÿã㊠@mlflow.trace ãã³ã¬ãŒã¿ãä»äžããããšã§ã颿°å
ã®åŠçãç°¡åã«Tracingããããšãã§ããŸãã ãã®ãããªé¢æ°ã以äžã«3ã€å®çŸ©ããŸããã create_metadata_filter_from_user_query()ãããcreate_cooking_time_filter()ãšcreate_cooking_cost_filter()ãåŒã³åºããŸãã from openai import OpenAI from mlflow.entities import SpanType @ mlflow.trace (span_type=SpanType.LLM) def create_cooking_time_filter (user_query: str ) -> list [CookingTimeFilters | CookingCostFilters]: client = OpenAI() system_prompt = f """ ããªãã¯æçã®ç¥èãè±å¯ãªã¬ã·ãæ€çŽ¢AIã§ãã ãŠãŒã¶ãŒãã¬ã·ãæ€çŽ¢ã®ããã«å
¥åããã¯ãšãªãè§£èªãããŠãŒã¶ã**調çæé**ã§ãã£ã«ã¿ãªã³ã°ããŠæ€çŽ¢ãããå Žåã¯ããã£ã«ã¿ãªã³ã°æ¡ä»¶ãè¿ããŠãã ããã ## åºååœ¢åŒ * json圢åŒã§åºåããŠãã ãã * columnã«ã«ã©ã åãoperatorã«äžçå·ãvalueã«ãã£ã«ã¿ãªã³ã°å¯Ÿè±¡ãå
¥ããŠãã ãã """ completion = client.beta.chat.completions.parse( model = "gpt-4o-mini" , messages = [ { "role" : "system" , "content" : system_prompt}, { "role" : "user" , "content" : user_query}, ], response_format = CookingTimeFilters, ) structured_outputs = completion.choices[ 0 ].message.content filters = CookingTimeFilters.model_validate_json(structured_outputs).cooking_time_filters return filters @ mlflow.trace (span_type=SpanType.LLM) def create_cooking_cost_filter (user_query: str ) -> list [CookingTimeFilters | CookingCostFilters]: client = OpenAI() system_prompt = f """ ããªãã¯æçã®ç¥èãè±å¯ãªã¬ã·ãæ€çŽ¢AIã§ãã ãŠãŒã¶ãŒãã¬ã·ãæ€çŽ¢ã®ããã«å
¥åããã¯ãšãªãè§£èªãããŠãŒã¶ã**調çè²»çš**ã§ãã£ã«ã¿ãªã³ã°ããŠæ€çŽ¢ãããå Žåã¯ããã£ã«ã¿ãªã³ã°æ¡ä»¶ãè¿ããŠãã ããã ## åºååœ¢åŒ * json圢åŒã§åºåããŠãã ãã * columnã«ã«ã©ã åãoperatorã«äžçå·ãvalueã«ãã£ã«ã¿ãªã³ã°å¯Ÿè±¡ãå
¥ããŠãã ãã """ completion = client.beta.chat.completions.parse( model = "gpt-4o-mini" , messages = [ { "role" : "system" , "content" : system_prompt}, { "role" : "user" , "content" : user_query}, ], response_format = CookingCostFilters, ) structured_outputs = completion.choices[ 0 ].message.content filters = CookingCostFilters.model_validate_json(structured_outputs).cooking_cost_filters return filters @ mlflow.trace (span_type=SpanType.CHAIN) def create_metadata_filter_from_user_query (user_query: str ) -> list [CookingTimeFilters | CookingCostFilters]: filter_functions = [ create_cooking_time_filter, create_cooking_cost_filter, ] metadata_filters = [] for func in filter_functions: filters = func(user_query) metadata_filters.extend(filters) return metadata_filters å®è¡çµæ - create_metadata_filter_from_user_query - create_cooking_time_filter - create_cooking_cost_filter ã®ãããªæ§é ã«ãªã£ãŠãããcooking_timeãšcooking_costã®ãã£ã«ã¿ãªã³ã°æ¡ä»¶ããããã1ç§ã»ã©ïŒåèšçŽ2ç§ïŒã§æœåºã§ããŠããããšãããããŸãã ãã ãããã§ã¯çŽåã«åŠçããŠããããããã£ã«ã¿ãªã³ã°æ¡ä»¶ãå¢ããã°å¢ããã»ã©åŠçæéãé·ããªã£ãŠããŸããŸãã LLMã®åŠçæéãé·ãã®ã¯APIã®åŸ
æ©æéãåå ã®ãããããã䞊è¡åŠçã«ããããšã§åŠçæéãççž®ããããšãã§ããŸãã 䞊è¡åŠçå
ã§MLflow Tracingãäœ¿çš äžŠè¡åŠçãè¡ãããã«ã concurrent.futures.ThreadPoolExecutor ã䜿çšããŸããã create_metadata_filter_from_user_query()å
ã®åŠçã以äžã®ããã«å€æŽããŸãã from concurrent.futures import ThreadPoolExecutor @ mlflow.trace (span_type=SpanType.CHAIN) def create_metadata_filter_from_user_query (user_query: str ) -> list [CookingTimeFilters | CookingCostFilters]: filter_functions = [ create_cooking_time_filter, create_cooking_cost_filter, ] metadata_filters = [] # å颿°ã䞊è¡åŠçã§å®è¡ããããä¿®æ£ with ThreadPoolExecutor() as executor: futures = [executor.submit(func, user_query) for func in filter_functions] for future in futures: filters = future.result() metadata_filters.extend(filters) return metadata_filters å®è¡çµæ å³äžã®èµ€æ ã瀺ãéãã1ã2ã3ãšã¿ããã§ããŠãããããããã®Tracingã颿°åäœã«ãªã£ãŠããŸãã å眮ããé·ããªããŸãããããã®åé¡ã«å¯ŸåŠããŸãã å¯ŸåŠ ãã®åé¡ã¯ãOpenTelemetryã䜿ã£ãŠã芪ã®Tracingã®Contextãåã«æž¡ãããšã§è§£æ±ºã§ããŸããã OpenTelemetryã¯ãªãã¶ãŒãããªãã£çšéã§äœ¿çšãããOSSã§ãã MLflow Tracingã¯å
éšçã«ã¯OpenTelemetryã䜿çšããŠãããOpenTelemetryã®Contextã䜿ãããšã§ã芪ã®Tracingãåã«æž¡ãããšãã§ããŸãã 以äžã®ããã«ãåŒã³åºãå
ã®create_metadata_filter_from_user_query()å
ã®Contextã芪ã®TracingãšããŠãåã®é¢æ°ã«æž¡ããŸãã æ¬¡ã«ãåã®é¢æ°ã®åŠçã§ã¯Contextã®attachãããããšã§èŠªãšåãé¢é£ä»ããããšãã§ããŸããïŒã¯ãªãŒã³ã¢ããããããã«detachãããŠããŸãïŒã from opentelemetry import context from opentelemetry.context import Context def create_filter_with_trace_parent_context (user_query: str , func: callable , trace_parent_context: Context) -> list [CookingTimeFilters | CookingCostFilters]: context_token = context.attach(trace_parent_context) filters = func(user_query) context.detach(context_token) return filters @ mlflow.trace (span_type=SpanType.CHAIN) def create_metadata_filter_from_user_query (user_query: str ) -> list [CookingTimeFilters | CookingCostFilters]: filter_functions = [ create_cooking_time_filter, create_cooking_cost_filter, ] metadata_filters = [] parent_context = context.get_current() # å颿°ã䞊è¡åŠçã§å®è¡ããããä¿®æ£ with ThreadPoolExecutor() as executor: # create_filter_with_trace_parent_context()ã§å颿°ãåŒã³åºãããä¿®æ£ futures = [executor.submit(create_filter_with_trace_parent_context, user_query, func, parent_context) for func in filter_functions] for future in futures: filters = future.result() metadata_filters.extend(filters) return metadata_filters å®è¡çµæ MLflow Tracingãåãããã«1ã€ã®ã¿ãã®äžã«ãŸãšãŸã£ãŠããããšãããããŸãã ãŸããå
šäœã®åŠçæéãšããŠçŽ1.3ç§ã§çµããŠãããçŽåã«LLMãåŒã³åºããšãã«æ¯ã¹ãŠé«éåã§ããŠããããšããããããšæããŸãã ãããã« MLflow Tracingã䜿çšããéã«äžŠè¡åŠçã§TracingãåãããŠããŸãåé¡ãšããã®å¯ŸåŠæ³ã«ã€ããŠç޹ä»ããŸããã OpenTelemetryã®Contextã䜿çšããããšã§ã芪åé¢ä¿ãä¿ã£ããŸãŸã®Tracingãå¯èœã«ãªãã䞊è¡åŠçã«ããé«éåãšãã¬ãŒãµããªãã£ã®äž¡æ¹ãå®çŸã§ããŸããã åæ§ã®åé¡ã«ééããæ¹ã®åèã«ãªãã°å¹žãã§ãã ãªããLangGraphïŒãšLangChainïŒã䜿ãã°äžŠè¡åŠçããããšããŠããMLflow Tracingãåãããåé¡ã¯çºçããŸããã§ããã ä»åã®å¯ŸåŠæ³ã¯ãããŸã§å¿æ¥åŠçœ®çãªåŽé¢ãããããšã¯è£è¶³ããŠãããŸãã ãŸãã䞊è¡åŠçå
ã§ããã«äžŠè¡åŠçããããªã©åŠçãè€éåããå Žåãã¯ãŒã¯ãããŒã®ã©ã®é¢æ°ã䞊è¡ã«åŠçãããŠããã®ããããã«ãããªãããšæããŸãã ããããæå³ã§ããèŠä»¶ã«åãããŠåŠçãè€éåããŠããã«ã€ããLangGraphãªã©ã®ãã¬ãŒã ã¯ãŒã¯ã䜿çšããæ¹ãå¯èªæ§ãä¿å®æ§ã®èгç¹ã§æå¹ã ãšèããããŸãã
ã¯ããã« ããã«ã¡ã¯ããªããŒã«ããéçºéšã§ããã¯ãšã³ããšã³ãžãã¢ãããŠãããã·ãšèšããŸãã çŸåšãå°å£²ã¢ããªã®éçºã§Laravel11ãå©çšããŠãµãŒãã¹éçºãè¡ã£ãŠããŸãã ä»åã¯ãµãŒãã¹æäŸãããäžã§ã»ãã¥ãªãã£å¯ŸçãšããŠAWSã®WAFãå°å
¥ããããšã«ãªã£ãã話ãããããšæããŸãã AWS WAFïŒWeb Application FirewallïŒã¯ãWebã¢ããªã±ãŒã·ã§ã³ãå®ãããã®åŒ·åãªãµãŒãã¹ã§ãã ä»åãç§ã¯åããŠTerraformã䜿ã£ãŠWAFãèšå®ããALBãCloudFrontãšé£æºãããŸããã ãŸãã¯ChatGPTãCursorãªã©ã掻çšããŠãèšå®ãTerraformã³ãŒãã®äœæèªäœã¯éåžžã«ã¹ã ãŒãºã«é²ããããšãã§ããŸããããå®éã«éçšãèãããšã äºåã«ç¥ã£ãŠããã¹ãéèŠãªä»æ§ãå¶é ããããã€ãçµéšããããšã«ãªããŸããã ãã®èšäºã§ã¯ãåããŠWAFãå°å
¥ããæ¹ã«åããŠã Terraformãšçµã¿åãããWAFèšå®ã§æ³šæãã¹ããã€ã³ã ãäžå¿ã«ã玹ä»ããŸãã ç¹ã«ã HTMLãæçš¿ããFroala Editorã®ãããªããŒã«ã䜿ã£ãŠããå Žåã«åœ±é¿ãåããããå
容 ãäžç·ã«ã話ã§ããããšæããŸãã WAFãTerraformã§æ§ç¯ããŠèŠããŠãããäºåã«ç¥ã£ãŠããã¹ã3ã€ã®ãã€ã³ãã TerraformãšWAFãçµã¿åãããŠæ§ç¯ããŠã¿ããšããç¥ããªããšããããã調æ»ãå¿
èŠã«ãªãããã€ã³ãããããŸãããããã§ã¯ãã®äžã§ãç¹ã«å°è±¡çã ã£ã3ã€ã玹ä»ããŸãã ãã€ã³ã1ïŒWAFã®ãã°ã°ã«ãŒãåã«ã¯ãåœåã«ãŒã«ãããã WAFã®ãã°ãCloudWatch Logsã«åºåããéããã°ã°ã«ãŒãåã«ã¯ ç¹å®ã®åœåã«ãŒã« ããããŸãã æ£ããåœåïŒ aws-waf-logs- ã§å§ãŸãå¿
èŠãã ã«ãŒã«ã«åŸããªããšïŒ Terraformå®è¡æã«ãšã©ãŒã«ãªãïŒãã åå ãåããã¥ãã ïŒ äŸïŒTerraformã§ã®ãã°èšå®ã³ãŒã resource "aws_cloudwatch_log_group" "waf_logs" { name = "aws-waf-logs-my-web-acl" # â ãã®prefixãå¿
é ïŒ } resource "aws_wafv2_web_acl_logging_configuration" "example" { log_destination_configs = [aws_cloudwatch_log_group.waf_logs.arn] resource_arn = aws_wafv2_web_acl.main.arn } è£è¶³ïŒ Terraformã§ã®ãšã©ãŒå
容ã¯ãARNãç¡å¹ãããªãœãŒã¹ãèŠã€ãããªãããªã©ãšè¡šç€ºãããå Žåãå€ãã åœåã«ãŒã«ã®åé¡ã«ãã©ãçãã®ã«æéãããããŸãã ã ããã¥ã¡ã³ãçãèªãã°é£ããããšã§ã¯ãªãã®ã§ãããç§ã¯ååã¯èªç±ã«æ±ºãããããšæã蟌ãã§ããéšåããããäœèšã«ã¯ãŸã£ãŠããŸã£ããã€ã³ãã«ãªããŸãã Error: creating WAFv2 Logging Configuration: WAFInvalidParameterException: The resource ARN 'arn:aws:logs:ap-northeast-1:123456789012:log-group:invalid-name' is invalid or does not exist. ãã€ã³ã2ïŒCloudFrontãšWAFã®çŽä»ãè§£é€ã«ã¯å°ãç¹å¥ãªæé ãå¿
èŠ ALBãšéãã CloudFrontã«WAFãçŽä»ããããšã«Terraformã§è§£é€ããã«ã¯æ³šæãå¿
èŠ ã§ãã éåžžã® terraform apply ã§ã¯è§£é€ã§ããã æç€ºçãªæäœãå¿
èŠ ã«ãªããŸãã è§£æ±ºæ¹æ³ã¯2〠æåã§Webã³ã³ãœãŒã«ããWAFã®çŽä»ããè§£é€ãã Terraformã§ web_acl_id = null ãæå®ããŠãapplyããè¡ãæç€ºçã«è§£é€ãã äžèšã©ã¡ãããè¡ã£ãäžã§ããã°ãALBåæ§Terraformã®ã³ãŒããåé€ããã ãã§ç°¡åã«WAFèšå®ã®åé€ãã§ããŸãã TerraformäŸïŒ resource "aws_cloudfront_distribution" "example" { # ä»ã®èšå®... web_acl_id = null # â æç€ºçã«è§£é€ããªããšãšã©ãŒã«ãªã } 泚æïŒ WAFãè§£é€ããã«åé€ããããšãããšãããªãœãŒã¹ããŸã é¢é£ä»ããããŠããããšããŠãšã©ãŒã«ãªããŸãã ãªãALBã§ã¯ããŸãããã®ã«CloudFrontã ãšãšã©ãŒãªã®ãã仿§ãšããŠèªèã§ããŠããããã¯ãŸã£ãŠããŸã£ããã€ã³ãã«ãªããŸãã CloudFrontã¯ãªãŒãžã§ã³ããus-east-1ãã«åºå®ãããŠããç¹ãå«ããŠã ALBãšæåãç°ãªã ãããWAFèšå®æã¯è¿œå èæ
®ãããèªèãå¿
èŠã§ãã ãã€ã³ã3ïŒFroala Editor à AWSãããŒãžãã«ãŒã«ã§æ³å®å€ã®ãããã¯ãçºç ä»åã¯AWSã®ãããŒãžãã«ãŒã« AWSManagedRulesCommonRuleSet ãå°å
¥ããŸããã ããã¯å®çªã®æ±çšã«ãŒã«ã»ããã§ã以äžã®ããã«ç°¡åã«Terraformããå©çšã§ããŸãã å°å
¥ã³ãŒãïŒTerraformïŒ rule { name = "AWS-AWSManagedRulesCommonRuleSet" priority = 0 override_action { none {} # åäœç¢ºèªæã¯blockã§è¯ããã圱é¿èª¿æ»ã®ããcountã«ããã®ããªã¹ã¹ã¡ } statement { managed_rule_group_statement { name = "AWSManagedRulesCommonRuleSet" vendor_name = "AWS" } } visibility_config { cloudwatch_metrics_enabled = true sampled_requests_enabled = true metric_name = "CommonRules" } } ãŸãã¯æ±çšçãªãã®ãé©çšããŠãé©å®æé©ãªãã®ãèšå®ããŠããããšèããŠããã®ã§ããã æ©é以äžã®ïŒç¹ã§å€§ãã圱é¿ãåºãããšãããããŸããã ãããäºåã«ç¥ã£ãŠãããã©ããã§èª¿æ»ã察çã®æéãç¯çŽã§ããã®ã§ã¯ãªãããªãšæã£ãŠããŸãã åé¡â ïŒXSSæ€ç¥ã«ããæçš¿ããããã¯ããã 察象ã«ãŒã«ïŒ CrossSiteScripting_BODY Froala Editorã¯HTMLãçæããããã <script> ã¿ã°ã«äŒŒãæ§æã屿§ãå«ãŸããå Žåããã çµæïŒ æ£åœãªå
¥åã§ãWAFãXSSãšèª€æ€ç¥ããŠããã㯠ããå Žåããã 察å¿çïŒ statement { managed_rule_group_statement { name = "AWSManagedRulesCommonRuleSet" vendor_name = "AWS" # ãCrossSiteScripting_BODYãã«ãŒã«ã®ã¿countéçšã«ããèšå®ã远å rule_action_override { name = "CrossSiteScripting_BODY" action_to_use { count {} } } } } åä»ãªãšããã¯ããã¹ãŠã®HTMLæ¬æã§ãªãããã§ã¯ãªããå
容ã«ãã£ãŠãšã©ãŒã«ãªããšããããšã§ãã ãã®ãããæ€èšŒæã¯ç¹ã«çºèŠããããšãªãæ€ç¥ã§ãããæ¬çªã®ããŒã¿ãå©çšããããšã§çºèŠããŸããã æåã¯ãªãäžéšã ããšã©ãŒã«ãªããã®åå ãããããç¹å®ãŸã§æéãããããŸããã WAFã®ãã°ã®äžã«BLOCKããŠãããã°ãããã®ã§ããããåç
§ããããšã§ç¹å®ã®ã±ãŒã¹ã®å Žåã®ã¿BLOCKãããŠããããšãããããŸããã ãã¯ãããããããšããããæ¬çªéçšã§ã¯æåã¯countéçšããŠæ§åãèŠããšããããšãè¯ããšæãç¥ããããéšåã§ããããŸãã ä»åã¯countéçšã«ããããšã§ãšã©ãŒåé¿ã¯ããŠããŸãããå®ã¯ãã BLOCKããªãããã«ããŠããã ãã§ããã ã»ãã¥ãªãã£é¢ã§èãããšãã¹ãã§ã¯ãªãç¶æ
ã§ãã ããã¯å Žåã«ãã£ãŠã¯NGã§ã察çãããã«æ€èšããå¿
èŠããããããããŸããã åé¡â¡ïŒãªã¯ãšã¹ãããã£8KBå¶éã«ããæ€ç¥æŒãã»æå³ããªãããã㯠察象ã«ãŒã«ïŒ SizeRestrictions_BODY AWS WAFã¯ãªã¯ãšã¹ãããã£ã®æ€æ»ã« æå€§8KBïŒ8192ãã€ãïŒ ãšããäžéããã Froalaããæçš¿ãããé·æã»è£
食ã€ãHTMLã§å¶éãè¶
ããããšããã ãã¡ããäºåã«ããã£ãŠããã°å¯Ÿçã®ããããã¯ãã£ããšæããŸããã ãããŒãžãã«ãŒã«å
容ã®ãã¹ãŠãææ¡ã§ããŠããªãããã€Froala Editorã®ä»æ§ããã£ããææ¡ã§ããŠããªãéšåãéãªãã åå ã®ç¹å®ã察å¿çã«ããæéãããã£ãŠããŸã£ãéšåã«ãªããŸãã 察å¿çã®éžæè¢ïŒ count ã¢ãŒãã«å€æŽãããããã¯ãããã°ã ãèšé²ãã ãâãšã¯ãããã§ããã°äºåã«ãµã€ãºå¶éã«ãããããã¯ã¯è¡ããããšããã§ãã FroalaåŽã§å
¥åãµã€ãºã®ãã€ãå¶éãããã ãâããã¯Froalaã®ä»æ§äžã8KB 以äžã«æããæ¬æãäœæããã®ã¯ããªãå³ãããã§ãã æçš¿ãè€æ°åã«åå²ããŠéä¿¡ãããããªä»çµã¿ã«å€æŽ ãâæç« ã§ã¯ç°¡åã«æžããŸãããèæ
®ç¹ãéåžžã«å€ã察å¿ã³ã¹ãã¯é«ãã§ãã ããïŒåå²éä¿¡çšã®APIæºåãåãããŒã¿ã®åææŽæ°æã®èæ
®ãå岿޿°ã®å¶åŸ¡ããšã©ãŒå¶åŸ¡ïŒ ãŸãšãïŒWAFãå°å
¥ããéã¯ãŠãŒã¹ã±ãŒã¹ãšå¶éãäºåã«çè§£ããã ä»åã®å
容ãç°¡åã«è¡šã«ããŸããã èŠ³ç¹ å
容 ãã°ã°ã«ãŒãåã®å¶çŽ aws-waf-logs- ã§å§ããªããšTerraformãšã©ãŒã«ãäºåã«åœå確èªãïŒ CloudFrontè§£é€æã®æ³šæ web_acl_id = null ãæç€ºããªããš Terraform Apply æã«ãšã©ãŒ XSSæ€åºã®éæ€ç¥ HTMLãšãã£ã¿äœ¿çšæã¯ count ã¢ãŒãã§æ§åãèŠãã®ãå®å
š 8KBå¶éã®ã€ã³ãã¯ã é·æã»è£
食æçš¿ããããªãã¢ããªã»ã€ã³ãã©äž¡é¢ã§ã®å¯Ÿå¿ãå¿
èŠ ãããã« ãããã§ããã§ããããã AIãå©çšããããšã§å¹çããWAFãæ§ç¯ã§ããåé¢ã 仿§ãžã®çè§£ãäžååã ãšæå³ãã¬ãã©ãã« ã«ãã€ãªãããŸãã ç¹ã«Froala Editorã®ããã«HTMLãæ±ãããŒã«ã䜿ã£ãŠããå Žåã¯ã WAFã®æšæºã«ãŒã«ãšè¡çªãããããæ€ç¥ã»ãããã¯ã®èª¿æŽãéèŠ ã«ãªããŸãã ããäºæãã¬403ãšã©ãŒãªã©ãçºçããŠããå Žåã¯æ¬èšäºã®å
容ã®éšåãçã£ãŠã¿ãã®ãè¯ããããããŸããã æ¬èšäºããããããWAFãå°å
¥ãããæ¹ã«ãšã£ãŠã®åèã«ãªãã°å¹žãã§ãã æåŸãŸã§ãèªã¿ããã ãããããšãããããŸããã
ã¯ããã« ããã«ã¡ã¯ãããªãã·ã¥ãããã³éçºéšã§ãœãããŠã§ã¢ãšã³ãžãã¢ãããŠããæ°è°·ã§ãã ãšããªãŒã®éçºéšã§ã¯ãæ¥åžžæ¥åããé¢ããŠæ°ããæè¡ãã¢ã€ãã¢ã«ææŠãããææŠweekããšããåãçµã¿ã宿çã«éå¬ããŠããŸãã ä»åã¯éå®çã«2æ¥éãšããçæéã§ã®éå¬ã§ãããããã®ææŠweekãæŽ»çšãããã«ã·ã«ã®ç»åè§£ææ©èœã®ç²ŸåºŠãããã«é«ããããšãç®æããŠãæè¡æ€èšŒãšããŠæ§è³ªã®ç°ãªã2ã€ã®AIã¢ãããŒããæ§ç¯ã»æ¯èŒããŸããã®ã§ããã®å
容ã«ã€ããŠã玹ä»ããŸãã â» ææŠweekã®è©³çްã«ã€ããŠã¯éå»ã®èšäºã§ç޹ä»ããŠããŸãã®ã§ãèå³ã®ããæ¹ã¯ä»¥äžãã芧ãã ããã tech.every.tv æ¯èŒãã2ã€ã®ã¢ãããŒã ç»åããã®æ é€çŽ æšå®ãšããã¿ã¹ã¯ã«å¯ŸããŠãç§ãã¡ã¯2ã€ã®ç°ãªãã¢ãããŒããèšèšããŸããã LLMåäœã¢ãããŒã äžã€ç®ã¯ãLLMãæã€åºç¯ãªç¥èãçšããŠãç»åããæçåãææãç¹å®ããæ é€çŽ ãçŽæ¥æšå®ããã¢ãããŒãã§ãããã®ææ³ã®åŒ·ã¿ã¯ãäžã€ã®ã¢ãã«ã§å®çµãããããã·ã³ãã«ã§é«éãªå¿çãæåŸ
ã§ããç¹ã§ãã RAG掻çšã¢ãããŒã äºã€ç®ã¯ãLLMã®æšå®èœåã«å ããŠãæ€çŽ¢æ¡åŒµçæïŒRAGïŒã®æè¡ã掻çšããã¢ãããŒãã§ããLLMãæšå®ããææåãåºã«ãããªãã·ã¥ãããã³ïŒDKïŒã®é£æããŒã¿ããŒã¹ãæ€çŽ¢ããåŸãããæ£ç¢ºãªæ é€çŽ ããŒã¿ãåºã«æçµçãªèšç®ãè¡ããŸããããããŒã¿ã«åºã¥ããã粟床ã®é«ãæšå®ãç®æãã¢ãããŒãã§ãã å
·äœçã«ã¯ãRAG掻çšã¢ãããŒãã§ã¯ä»¥äžã®ã¢ãŒããã¯ãã£ãèšèšããŸããã ãã¬ããžããŒã¹ã®æ§ç¯ã«ããã£ãŠã¯ãåœåãããé«åºŠãªã¢ãããŒãã詊ã¿ãŸãããå
·äœçã«ã¯ãAmazon OpenSearch Serverlessã«å°çšã®ã€ã³ããã¯ã¹ãäœæããAWS LambdaãçšããŠé£æããŒã¿ãèªåçã«æµã蟌ãä»çµã¿ã§ãããã®æ¹æ³ã§ã¯ã飿åã®ã¿ããã¯ãã«åããåæ é€çŽ ïŒã«ããªãŒãããã±ã質ãªã©ïŒãã¡ã¿ããŒã¿ãšããŠä»äžããããšã§ãæ€çŽ¢ç²ŸåºŠåäžãç®æããŸããã ããããæ€èšŒãé²ããäžã§ãã¡ã¿ããŒã¿ãæå³ããéãã«çµæãžåæ ãããªããšãã課é¡ã«çŽé¢ããŸããã èšå®ã®èŠçŽããªã©ã詊ã¿ãŸããããçæéã§ã®è§£æ±ºãé£ããã£ããããä»åã¯ã¢ãããŒãã倿Žããé£æãšæ é€çŽ ããã¹ãŠCSVã«ããŠS3ã«ã¢ããããŒããBedrockã®æ©èœã§çŽæ¥ãã¬ããžããŒã¹ãäœæãããšãããããã·ã³ãã«ãªæ¹æ³ãæ¡çšããŸããã æ€èšŒçµæ ããã2ã€ã®ã¢ãããŒãã®æ§èœãæ¯èŒãããããç¹å®ã®æçåçãçšããŠæ€èšŒãè¡ããŸãããããªãã·ã¥ãããã³ã®ã¬ã·ããæã€æ é€çŽ ããŒã¿ããåèå€ããšããŠãåã¢ãããŒãã®æšå®çµæãã©ãã ãè¿ãããæ¯èŒããŸãã æ€èšŒ1ïŒã«ããšè±èã®å³åçã é
ç® DKã¬ã·ã RAG LLMåäœ ã«ããªãŒ(kcal) 615 501 250 ããã±ã質(g) 18.2 14.4 12 è質(g) 48.7 47.2 15 çæ°Žåç©(g) 18.6 0.2 5 ç³è³ª(g) 15.5 0.8 4.3 å¡©å(g) 2.4 1.2 1.2 æ€èšŒ2ïŒãã
ãããšã¡ããã®ããã€ããã ã« é
ç® DKã¬ã·ã RAG LLMåäœ ã«ããªãŒ(kcal) 98 105 70 ããã±ã質(g) 4.8 0 4 è質(g) 5.5 11.4 2 çæ°Žåç©(g) 7.6 0.3 8 ç³è³ª(g) 6.9 0.3 6.5 å¡©å(g) 1.5 0.4 0.8 æ€èšŒ3ïŒé¶ããèã®ã¿ããç
®ç®ç« é
ç® DKã¬ã·ã RAG LLMåäœ ã«ããªãŒ(kcal) 741 1312 670 ããã±ã質(g) 43.5 44.1 35 è質(g) 15.4 32.2 15 çæ°Žåç©(g) 104.6 134.4 84 ç³è³ª(g) 97 127.2 75 å¡©å(g) 4.5 2.1 3.6 æ€èšŒ4ïŒå€§æ ¹ã®ãšããšãç
®ç®ç« é
ç® DKã¬ã·ã RAG LLMåäœ ã«ããªãŒ(kcal) 745 726 678 ããã±ã質(g) 29.6 4.3 35.2 è質(g) 25.8 16.2 26.8 çæ°Žåç©(g) 89.5 59.3 78 ç³è³ª(g) 83.4 17.3 70.5 å¡©å(g) 5 0.8 3.3 çµæã®èå¯ çµæãèŠããšã RAGã¯ãLLMåäœãšæ¯èŒããŠåèå€ã§ããDKã¬ã·ãã®å€ã«è¿ããªãã±ãŒã¹ãããã°ãéã«å€§ããå€ããŠããŸãã±ãŒã¹ããã ãšãããäžé·äžçãªçµæãšãªããŸããã ä»åã®RAGã®è©Šã¿ã¯ãLLMåäœã§ã¯æšå®ãé£ããã飿ããŒã¹ã§ã®æ é€çŽ èšç®ãããããªãã·ã¥ãããã³ã®å
·äœçãªé£æããŒã¿ãåç
§ãããããšã§ãã©ãã ãæšå®å€ãåèå€ã«è¿ã¥ããããããæ€èšŒãããã®ã§ããã ä»åŸã®èª²é¡ãšå±æ ä»åã®æ¯èŒæ€èšŒãããããã€ãã®èª²é¡ãèŠããŠããŸããã ææã®ç¹å®ãšéã®æšå®ã®ã°ãã€ã ç»åã«åã£ãŠããªãææããåã£ãŠããŠãæ£ç¢ºãªéãæšå®ããã®ã¯ãçŸç¶ã®LLMã®ç²ŸåºŠã§ã¯äŸç¶ãšããŠå°é£ã§ãã æææ€çŽ¢ã®ãã€ãº ãã¯ãã«æ€çŽ¢æã«ãç¡é¢ä¿ãªé£æããããããããéã«å¿
èŠãªé£æããããããªãã£ããããåé¡ããããŸããã æ é€çŽ ã®è¶³ãåãããäžå®å® LLMã«ããæçµçãªéèšåŠçããå¿
ãããæåŸ
éãã«è¡ãããªãã±ãŒã¹ããããŸããã å®è¡æéãé·ã è€æ°ã®ã¹ããããèžããããLLMåäœããåŠçã«æéãããããŸãã ç¹ã«èª²é¡2, 3, 4ã«ã€ããŠã¯ãæ¹åã®äœå°ããããšèããŠããŸããäŸãã°ããã¯ãã«DBã®ãã¥ãŒãã³ã°ãå
šææ€çŽ¢ãžã®åãæ¿ããæ é€çŽ ã®éèšãã«ãŒã«ããŒã¹ã§è¡ãããšãã£ã察çãèããããŸãã ãããã®èª²é¡ãèžãŸããä»åŸã¯ä»¥äžã®ãããªå¥ã®ã¢ãããŒããæ€èšããŠããŸãã æšå®ããæçåããé¡äŒŒã®DKã¬ã·ããæ€çŽ¢ãããã®æ é€çŽ ã®å¹³åå€ãæ¡çšããã DKã®ã¬ã·ãç»åãšæçåã§æ°ããªãã¯ãã«DBãæ§ç¯ããç»åã§é¡äŒŒæ€çŽ¢ãè¡ãã æ é€çŽ æšå®ã«ç¹åããã¢ãã«ããã¡ã€ã³ãã¥ãŒãã³ã°ããã ãŸãšã ä»åã¯ãç»åããã®æ é€çŽ æšå®ã®ç²ŸåºŠåäžãç®æããæ§è³ªã®ç°ãªã2ã€ã®AIã¢ãããŒãïŒLLMåäœ/RAGïŒãæ§ç¯ã»æ¯èŒæ€èšŒããŸããã çµæãšããŠãRAGã¯ç¹å®ã®æ¡ä»¶äžã§ç²ŸåºŠãåäžããå¯èœæ§ã瀺ããŸããããå®å®æ§ãå¿çé床ã®é¢ã§ã¯LLMåäœã«åããããªã©ãããããã«å©ç¹ãšèª²é¡ãããããšãæããã«ãªããŸããã ãã®ææŠã§åŸãããç¥èŠã掻ããããããªã粟床åäžã«åããŠãä»åŸãæ€èšŒãç¶ããŠãããããšæããŸãã
ã¯ããã« ããã«ã¡ã¯ãããªãã·ã¥ãããã³ã§ã¯ã©ã€ã¢ã³ããšã³ãžãã¢ãæ
åœããŠãã kikuchi ã§ãã è¿å¹Ž AI æè¡ã®çºå±ãèãããäžã§ãçæ AI ãããªãã®å¢ãã§çºå±ããæ®æ®µäœ¿ããä»äºã§ ChatGPT ãªã©ã®çæ AI ã®ãµãŒãã¹ãåãå
¥ããæ¹ãäŒæ¥ãå€ããªã£ãŠããŸããã ä»åã¯å€ãã®å Žåã§çæ AI ã®æ©èœãå®çŸããŠããæ©æ¢°åŠç¿ (ML : Machine Learning) ã«ã€ããŠãAndroid ã¢ããªã§ç°¡åã«å®è£
ããæ¹æ³ã«è§ŠããŠã¿ãããšæããŸãã ãªããåŒç€Ÿã¯éçºçç£æ§ã®åäžãªã©ãç®çãšã㊠Cursor ãå°å
¥ãããªã©ãç©æ¥µç㪠AI ã®æŽ»çšãåãå
¥ããŠããŸãã®ã§ããèå³ãããæ¹ã¯ãã¡ãã®èšäºãèŠãŠããã ãããšå¬ããã§ãã ãšããªãŒãAIãšãã£ã¿ãCursorããå
šãšã³ãžãã¢ããã³ãããã¯ããããŒãžã£ãŒã«å°å
¥ ã¢ããªã«çµã¿èŸŒãæ¹æ³ ãæ©æ¢°åŠç¿ããšããèšèã䜿ããšé£ããå°è±¡ããããŸãããæ¢ã«æ©æ¢°åŠç¿ã®æ©èœãæäŸãããã¬ãŒã ã¯ãŒã¯ã¯å€ãååšããŠãããäžã§ã Google ãæäŸãã MediaPipe ãšãããã¬ãŒã ã¯ãŒã¯ã䜿ãããšã§ç°¡åã«çæ AI ãšãã£ãæ©èœãå®è£
ããããšãã§ããŸãã ãŸã MediaPipe ã§ã¯æ§ã
ãªãœãªã¥ãŒã·ã§ã³ãæäŸãããŠããã2025 幎 7 ææç¹ã§ã¯å
šãŠã®ãœãªã¥ãŒã·ã§ã³ã Android ã®ç«¯æ«ã§å©çšå¯èœãšãªããŸãã 以äžå
¬åŒãµã€ãã«ãŠãå©çšå¯èœãªãœãªã¥ãŒã·ã§ã³ããŸãšãŸã£ãŠããŸãã https://ai.google.dev/edge/mediapipe/solutions/guide?hl=ja#available_solutions ä»åã¯ããã®äžã§ãåããã€ã¡ãŒãžãããã ç»ååé¡ (Tasks API) ãš çæ AI (LLM Inference API) ã«ã€ããŠè§ŠããŠã¿ãããšæããŸãã ç»ååé¡ (Tasks API) ã®å®è£
æ¹æ³ ãŸãã¯ç»ååé¡ (Tasks API) ã®å®è£
æ¹æ³ã«ã€ããŠãŸãšããŠãããŸãã 1. ã¢ãã«ããŒã¿ã app/src/main/assets ã«è¿œå æ©æ¢°åŠç¿ã®ããŒã¿ãåããããã«ã¯åœç¶ã¢ãã«ããŒã¿ãå¿
èŠãšãªããŸãã ä»å㯠Google AI for Developers ãæäŸããŠããç»ååé¡ã¢ãã«ã䜿çšããããšæããŸãã https://ai.google.dev/edge/mediapipe/solutions/vision/image_classifier/index?hl=ja#efficientnet-lite0_model_recommended ã¢ãã«ã«ã¯ int8 ãš float32 ãååšããŸãã int8 ⊠ãã¡ã€ã«ãµã€ãºã軜éã§ãåŠçé床ãéãã粟床ã¯ãããã«äœã float32 ⊠ãã¡ã€ã«ãµã€ãºã倧ãããåŠçé床ãé
ãã粟床ã¯é«ã ãšããç¹åŸŽããããã¹ãããªã©ã¹ãã¬ãŒãžãã¡ã¢ãªãéãããŠããå Žå㯠int8 ã䜿çšãããšããããšæããŸãã æ¬èšäºã§ã int8 ãå°å
¥ããåæã§ã®å®è£
æ¹æ³ããŸãšããŠãããŸãã 2. app ã¬ãã«ã® build.gradle ã« Vision Task ã©ã€ãã©ãªã远å dependencies { implementation( "com.google.mediapipe:tasks-vision:0.10.26" ) } 3. ImageClassifier ã®åæå ImageClassifier ã¯ç»ååé¡ã¿ã¹ã¯ãå®è¡ããããã®ã¯ã©ã¹ãšãªããŸãã ã¢ãã«ããŒã¿ãèªã¿èŸŒãŸããŠåæåãããããã¢ãã«ããŒã¿èªäœã®ãµã€ãºã«ããããŸããããåæåã³ã¹ããé«ããªãã®ã§ãäžåºŠã ãå®è¡ããŠåå©çšãã圢ãè¯ãã§ãã lateinit var imageClassifier: ImageClassifier fun initImageClassifier(context: Context) { val options = ImageClassifier.ImageClassifierOptions.builder() .setBaseOptions(BaseOptions.builder().setModelAssetPath( "efficientnet_lite0.tflite" ).build()) // â ⊠èªã¿èŸŒãŸããã¢ãã«ããŒã¿ã®èšå® .setRunningMode(RunningMode.IMAGE) // ⡠⊠åé¡ããç»åããŒã¿ã®çš®å¥ .setMaxResults( 3 ) // ⢠⊠è¿åŽããã¬ã¹ãã³ã¹ã®æ° .setScoreThreshold( 0.5F ) // ⣠⊠åºåçµæã®ç¢ºä¿¡åºŠã®ãããå€ .build() try { imageClassifier = ImageClassifier.createFromOptions(context, options) } catch (e: IllegalStateException ) { Log.e( "ImageClassifier" , "TFLite failed to load model with error: " + e.message) } } ãã©ã¡ãŒã¿ãå€ãããã现ãã確èªããŠãããããšæããŸãã â ã«ã€ããŠã¯ãã¢ãã«ããŒã¿ã®èªã¿èŸŒã¿ãšãªããã assets ãã¡ã€ã«ã«é
眮ãããã¡ã€ã«ãæå®ããŠããŸãã â¡ã«ã€ããŠã¯ãèªã¿èŸŒãŸããç»åããŒã¿ã®çš®å¥ãèšå®ãããã®ã§ãéæ¢ç» ( IMAGE ) / åç» ( VIDEO ) / ã¹ããªãŒã ( LIVE_STREAM ) ãèšå®ã§ããŸãã ä»åã¯éæ¢ç»ãèªã¿èŸŒãŸãããããéæ¢ç» ( IMAGE ) ãèšå®ããŠããŸãã â¢ã«ã€ããŠã¯ãè¿åŽããã¬ã¹ãã³ã¹ã®æ°ãšãªãã3 ãèšå®ããå Žåã¯ç¢ºä¿¡åºŠ (ã¹ã³ã¢) ãéé ã§ 3 ã€è¿åŽãã圢ãšãªããŸãã â£ã«ã€ããŠã¯ãâ¢ã§ãè§Šãã確信床ã®äºã§ãæå®ããæ°å€ä»¥äžã®ç¢ºä¿¡åºŠã®é
ç®ã®ã¿ã¬ã¹ãã³ã¹ã«å«ããŸãã 0.5F ãæå®ããå Žåã確信床ã 50% 以äžã®ãã®ã®ã¿ã¬ã¹ãã³ã¹ã«å«ããããšãã圢ãšãªããŸãã 4. ããŒã¿ã®åé¡å®è¡ 3 ãŸã§ã§å¿
èŠãªèšå®ã¯å®äºãããããæåŸã«ããŒã¿ã®åé¡ãå®è¡ããŸãã fun classifyImage(bitmap: Bitmap) { // åæåå®äºæžã¿ããã§ã㯠if ( !:: imageClassifier.isInitialized) { return } // ããŒã¿ãåé¡ããŠãã°åºå val mpImage = BitmapImageBuilder(bitmap).build() val result = imageClassifier.classify(mpImage) result.classificationResult().classifications().forEach { classification -> classification.categories().forEach { category -> Log.d( "ImageClassifier" , "Category: ${ category.categoryName() } , Score: ${ category.score() } " ) } } } Bitmap ã®ããŒã¿ã ImageClassifier$classify ã¡ãœããã§èªã¿èŸŒãŸããçµæããã°ã§åºåãã圢ãšãªããŸãã å®è¡çµæ ä»åã¯ã¢ãã«ãã¡ã€ã«ãšåæ§ã«ã以äžã® Google AI for Developers ã®ç»ååé¡ã¿ã¹ã¯ã¬ã€ãã®ããŒãžã«èšçœ®ãããŠãããã©ãã³ãŽã®ç»åãåé¡ããŠã¿ãããšæããŸãã https://ai.google.dev/edge/mediapipe/solutions/vision/image_classifier åºåãã°ã¯ä»¥äžã®ããã«ãªããŸããã 89.4% ãšããé«ã確信床㧠flamingo ãšåé¡ãããŸããã (å
¬åŒã® 95% ãšããæ°å€ããããäžãã£ãŠããã®ã¯ãããããæåãšåç©ãæ··åšããŠããŸã£ãŠãã圱é¿ã ãšèããŸã) ä»ã«ãè²ã
ç»åãèªã¿èŸŒãŸããŸãããã 察象ã®åç©ä»¥å€ (æšãèãªã©) ã¯åã蟌ãŸãªãæ¹ã粟床ãé«ã æ£é¢ãã¯ã£ããåããŠããŠãé¡ãèå¥ã§ããæ¹ã粟床ãé«ã ç¬ã¯ç¢ºä¿¡åºŠãããªãäœã (æ¯å 30% çšåºŠ) ã©ã€ãªã³ã¯ç¢ºä¿¡åºŠãããªãé«ã (æšãèãåã蟌ãã§ã 90% 以äžãšãªã) ãšãªããæäŸãããŠããã¢ãã«ããŒã¿ã§ã¯åé¡ã§ããã»ã§ããªãåç©ãã¯ã£ããããŠããããšããè峿·±ãçµæãšãªãããšãããããŸããã ç»ååé¡ (Tasks API) ã®å®è£
æ¹æ³ã«ã€ããŠã¯ä»¥äžãšãªããŸãã çæ AI (LLM Inference API) ã®å®è£
æ¹æ³ 次ã«çæ AI (LLM Inference API) ã®å®è£
æ¹æ³ã«ã€ããŠãŸãšããŠãããŸãã ãã¡ããåºæ¬çãªå®è£
ã®æµãã¯ç»ååé¡ (Tasks API) ãšåæ§ã§ãä»åã¯ãã£ãã圢åŒã®æåãå®è£
ããŠã¿ãããšæããŸãã 1. ã¢ãã«ããŒã¿ã app/src/main/assets ã«è¿œå ãã¡ãã Google AI for Developers ããã¢ãã«ããŒã¿ãããŠã³ããŒãããŸãã â»ä»å㯠Gemma-3 1B ãšããã¢ãã«ããŒã¿ã䜿çšããŸãããHugging Face ã®ã¢ã«ãŠã³ããå¿
èŠãšãªãç¹ã«ã泚æãã ããã https://ai.google.dev/edge/mediapipe/solutions/genai/llm_inference?hl=ja#gemma-3_1b ãã¡ãã§ãããç»ååé¡ãšéã£ãŠã¢ãã«ããŒã¿ã 500MB 以äžã«ãªããªã©ããªããµã€ãºã倧ãããªããŸãã ã¢ãã«ããŒã¿ãè€æ°ååšãããã詳现ã¯å²æããŸãããä»å㯠dynamic_int4 QAT ãšãããã®ãæ¡çšããŸããã 2. app ã¬ãã«ã® build.gradle ã« Gen AI Task ã©ã€ãã©ãªã远å dependencies { implementation( "com.google.mediapipe:tasks-genai:0.10.25" ) } 3. ã¢ãã«ããŒã¿ã assets ãã cache ã«ã³ããŒãã LLM Inference API ã«ã€ããŠã¯çŽæ¥ assets ãã©ã«ãããã¢ãã«ããŒã¿ãåç
§ããæ¹æ³ããªããããäžåºŠ cache ãã©ã«ãã«ããŒã¿ãã³ããŒããŠããèªã¿èŸŒãŸããŸãã private fun copyModelFromAssetsToCache(context: Context, modelName: String ): String { val outputFile = File(context.cacheDir, modelName) if (outputFile.exists()) { return outputFile.absolutePath } context.assets. open (modelName).use { inputStream -> FileOutputStream(outputFile).use { outputStream -> inputStream.copyTo(outputStream) } } return outputFile.absolutePath } ãªã assets ããçŽæ¥åç
§ã§ããªãã®ãããšããç¹ã§ãããã¢ããªã§å·šå€§ãªããŒã¿ãå¹ççã«æ±ãããã«ã¯ã¡ã¢ãªãããã³ã°ãšããæè¡ãå¿
èŠãšãªãããã®æè¡ã¯å®ãã¡ã€ã«ãã¹ãå¿
èŠãªãã assets ãã¡ã€ã«ã§ã¯äœ¿çšã§ããªããªã£ãŠãããäžåºŠ cache ã®é åã«ã³ããŒããŠãããã¡ãã®ãã¡ã€ã«ã«å¯ŸããŠã¢ã¯ã»ã¹ããå¿
èŠããããŸãã ãããã LLM Inference API ã§ã巚倧ãªã¢ãã«ããŒã¿ãæ±ãæ³å®ã§ãassets ã«çŽæ¥ã¢ã¯ã»ã¹ããã¡ãœãããèéãããŠãããã®ãšæšæž¬ããŠããŸãã 4. LlmInference ã®åæå LlmInference ã¯çæ AI ã®ã¿ã¹ã¯ãå®è¡ããããã®ã¯ã©ã¹ãšãªããŸãã ã¢ãã«ããŒã¿ãããªã倧ããåæåã«æ°ç§ã¯ããã£ãŠããŸãããããã¡ããäžåºŠã ãå®è¡ããŠåå©çšãã圢ãè¯ãã§ãã private lateinit var llmInference: LlmInference fun initLlmInference(context: Context) { // LLM Inference ã®åæå val taskOptions = LlmInference.LlmInferenceOptions.builder() .setModelPath(copyModelFromAssetsToCache(context, "gemma3-1b-it-int4.task" )) .build() llmInference = LlmInference.createFromOptions(context, taskOptions) } 5. çæ AI å®è¡ 4 ãŸã§ã§å¿
èŠãªèšå®ã¯å®äºãããããæåŸã«çæ AI ãå®è¡ããŸãã private val _updateResponse: MutableSharedFlow< String > = MutableSharedFlow() val updateResponse: Flow< String > = _updateResponse fun generateResponse(text: String ) { viewModelScope.launch(Dispatchers.IO) { val result = llmInference.generateResponse(text) _updateResponse.emit(result) } } ãã¡ãã¯ããã¹ãã§åãåã£ãæååãè§£æããã¬ã¹ãã³ã¹ããŒã¿ãçæããæµããšãªã£ãŠããŸãã ä»å㯠UI äžã§è¡šçŸãããã£ããããFlow ã§ Fragment åŽã«ããŒã¿ãéã£ãŠããŸãã å®è¡çµæ å®éã«ããåãããçµæãç»åã§èŒããããšæããŸãã ãã®ã¢ãã«ããŒã¿ã§ã¯æ¥æ¬èªã«å¯ŸããŠã¯æ¥æ¬èªã§ããã€é¡æåã䜿ã£ãŠåçãçæããŠãããããšãåãããŸãã çæ AI (LLM Inference API) ã®å®è£
æ¹æ³ã«ã€ããŠã¯ä»¥äžãšãªããŸãã ã¢ãã«ããŒã¿ãçµã¿èŸŒãã¡ãªããã«ã€ã㊠ã¢ããªã«ã¢ãã«ããŒã¿ãçµã¿èŸŒãäžçªã®ã¡ãªãã㯠ãªãã©ã€ã³ã§ãçµæãååŸã§ããäº ã ãšèããŸãã ä»ã§ã¯éä¿¡ããŠããŒã¿ãååŸããæµããåœããåãšãªã£ãŠããŸããã黿³¢ã鮿ãããŠããããããã¯éä¿¡ãå®å®ããªãç°å¢äžã§ãé©åãªçããååŸã§ããä»çµã¿ã§ããã°ããŠãŒã¶ã¯éä¿¡ç°å¢ãæ°ã«ããã¢ããªãè§Šãããšãã§ããããããŠãŒã¶ãã¬ã³ããªãŒã«ããªããŸãã åžå Žã«å
¬éããã¬ãã«ãŸã§ã¢ãã«ããŒã¿ãåŠç¿ãããããšã¯é£ããããšæããŸãããäœããã®æ¹æ³ã§ã¢ããªã«çµã¿èŸŒãã ã¢ãã«ããŒã¿ãå·®ãæ¿ããä»çµã¿ãã確ç«ããã°ãã¢ããªåäœã§åžžã«ææ°ã¢ãã«ãåãæ±ãããšãã§ããããã«ãªããŸãã 課é¡ã«ã€ã㊠äžçªã®åé¡ã¯ãã¯ã ã¢ãã«ããŒã¿ã倧ããäº ã§ãã ä»å㯠500MB ãã®ããŒã¿ã assets ã«çµã¿èŸŒããšããæ¹æ³ã§ç¡çããå®è£
ããŸããããã¢ããªã«å
å
ãããšããããšã¯åœç¶ã¢ããªããŠã³ããŒãæã®ãã€ããªãµã€ãºã倧ãããªããšããããšãªã®ã§ãéçšæ¹æ³ãæ€èšããå¿
èŠããããŸãã æ¹æ³ãšããŠèããããããšã¯ assets ã«çµã¿èŸŒã (æ¬èšäºã®ããæ¹) ã¢ããªèµ·ååŸã«ã¢ãã«ããŒã¿ãããŠã³ããŒããã ãããããããŸãããå¥ã®åé¡ãšã㊠1 ã®ã±ãŒã¹ã§ã 2 ã®ã±ãŒã¹ã§ã ã¢ãã«ããŒã¿ãšããéèŠãªè³ç£ãæãåãããããšãé²ãå¿
èŠããã ãšããã»ãã¥ãªãã£é¢ã®èª²é¡ãçºçããŸãã æå·åã宿œããããã€ãã£ãã³ãŒããæŽ»çšãããªã©åé¿ããæ¹æ³ã¯ããã€ããããšæããŸããããããã«ããã¢ãã«ããŒã¿ãã¢ããªã§åãæ±ãããæ€èšããäºé
ã¯å€ãããããã§ãã ãããã« ä»å㯠MediaPipe ã®ãã¬ãŒã ã¯ãŒã¯ã䜿ããAndroid ã¢ããªã«æ©æ¢°åŠç¿ã®æ©èœãå®è£
ããæ¹æ³ããŸãšããŠã¿ãŸãããã以åã¯æ©æ¢°åŠç¿ã«ã€ããŠå°éç¥èãè€éãªã³ãŒããå¿
èŠã§ããããä»ã§ã¯ç°¡åã«å®è£
ã§ããããšãåãããŸããã MediaPipe ã«ã¯ä»å玹ä»ããç»ååé¡ãçæ AI 以å€ã«ãã ç©äœæ€åº ã 顿€åº ã ãžã§ã¹ãã£ãŒèªè ãªã©ãããã«äœ¿ãã匷åãªæ©èœãæ°å€ãæäŸãããŠããŸãã®ã§ããã²å
¬åŒããã¥ã¡ã³ãã§è²ã
ãšç¢ºèªããŠã¿ãŠãã ããã æ¬èšäºã®æ
å ±ãçæ§ã®ã圹ã«ç«ãŠãã°å¹žãã§ãã
ã¯ããã« ããã«ã¡ã¯ãéçºéšã§ããŒã¿ãµã€ãšã³ãã£ã¹ããããŠããèæŸ€ã§ãã ã€ãã«æ±äº¬ãªãŒãžã§ã³ã§Amazon Q in QuickSightãGAããŸããïŒ ããŒã¿ã¹ããŒãªãŒãã·ããªãªããããã¯ãªã©èªç¶èšèªã§ããŒã¿åæãè¡ãæ©èœã远å ãããŸãããããã®ãããã®æ©èœã®è§£èª¬ã¯ 以åã®åŒç€Ÿã®ããã° ããä»ã®æ¹ãèšäºã«ãããŠããã®ã§ããã¡ããã芧ããã ããã°ãšæããŸãã ä»åã¯Amazon Q in QuickSightãèšç®ãã£ãŒã«ããäœæããéã«äœ¿çšããããšã§ãããžã¥ã¢ã«äœæãããå¹çåãããããªããã®æ€èšŒãããããšæããŸãã 䜿çšããæš¡æ¬ããŒã¿ æ€èšŒã«ã¯ä»¥äžã®ãããªãã¬ã·ãåç»ãµã€ãã®ç¹å®ã®ã¬ã·ãã®æ¥æ¯ã®ã€ã³ãã¬ãã·ã§ã³æ°ãšã¯ãªãã¯æ°ãéèšãããšããæ³å®ã®æš¡æ¬ããŒã¿ã䜿çšããŸãã ããããã®ã«ã©ã ã®å®çŸ©ã¯ä»¥äžã®éãã§ãã dateïŒæ¥ä»ïŒ2025-01-01~2024-04-30ïŒ recipeïŒã¬ã·ãåïŒãã³ããŒã°ïŒ clickïŒã¬ã·ããã¯ãªãã¯ããåæ°ïŒ1~10ã®æŽæ°ã®ä¹±æ°ïŒ impressionïŒã¬ã·ãã衚瀺ãããåæ°ïŒ100~200ã®æŽæ°ã®ä¹±æ°ïŒ ãã£ãŠã¿ã ãŸãã¯ãCTRãäœæã§ããã詊ããŠã¿ãŸãã CTR = click / impresseion ãæåŸ
ããŠããŸãã èšç®ãã£ãŒã«ã远å ãéžæãããèšç®ãäœæããã¯ãªãã¯ããŸãã ããã¹ããã©ãŒã«ããåºãŠããã®ã§ãããã«äœæãããèšç®åŒãå
¥åããŸãã ä»åã¯ãCTRããšå
¥åã èšç®åŒãæžãããããäœæããã¯ãªãã¯ããŸãã ïŒã3ç§ã»ã©ã§èšç®åŒãäœæãããŸããã æåŸ
ããŠããéãã®èšç®åŒãã§ããã®ã§ããæ¿å
¥ããã¯ãªãã¯ããŸãã èšç®åŒãæ¿å
¥ãããã®ã§ãæåŸã«ãä¿åããã¯ãªãã¯ããŠãèšç®ãã£ãŒã«ãã®äœæå®äºã§ãã èªç¶èšèªã§ãèšç®ãã£ãŒã«ã®èšç®åŒãäœæããããšãã§ããŸããã CTRã®å®çŸ©ãäžããªããŠãäœæã§ããã®ã¯è¯ããªãšæããŸããïŒ ãããããããããç°¡åãªåŒãªãQã䜿ããã«ãèªåã§äœã£ãæ¹ãæ©ããšæãã®ã§ãããå°ãè€éãªèšç®åŒãäœæããŠã¿ãŸãã æ¥ãé±ãæãšãã£ãæ¥ä»ã®ç²åºŠããã©ã¡ãŒã¿ã§æå®ããããšã§ãæ¥ä»ã®éèšåäœãå€ãããããªèšç®ãã£ãŒã«ããäœæããŸãã äžæºåãšããŠãDateGranularityãšããæååã®ãã©ã¡ãŒã¿ãäœæããŸãã ãã®ãã©ã¡ãŒã¿ã§æ¥ãé±ãæãæå®ããŸãã å
ã»ã©äœæããCTRèšç®ããååãšåæ¯ãç²åºŠã®å€æŽã«äŒŽã£ãŠåèšãããããã«å€æŽããŸãã æ¥æ¬èªã§ããã³ãããæžãããããŸãè¯ãåºåãåŸãããªãã£ãã®ã§ãè±èªã§ããã³ãããæžããŸããã ããŸããããªãã£ãããã³ããã¯èšäºã®æåŸã®æ¹ã§ç޹ä»ããŸãã äœãã¿ãŒã³ã詊ããŸããããweekã®æã«WKã«ãªããDDã«ãªã£ãŠããŸãã®ã¯ãæ¹åããªãã£ãã®ã§ãä»åã¯è«ŠããŠæåã§çŽããŸãã åŸãããçµæãæ¿å
¥ããŠãdayãweekãmonthãæ¥ãé±ãæã«ãç²åºŠãé±ã®æã®DDãWKã«çœ®ãæããŠãä¿åããŸãã ç²åºŠãé±ã«ãããševent_dateãé±ã®å§ãïŒæ¥ææ¥ïŒã«ãªããæã«ãããšyyyy-mmã§æã®åœ¢åŒã«ãªãæ¥ä»èšç®ãã£ãŒã«ãã宿ããŸããã æåŸã«ããå°ãè€éãªèšç®ãã£ãŒã«ãã«ææŠããŸãã StartDateãšEndDateãšãããã©ã¡ãŒã¿ãäœæããç²åºŠã«åãããŠéå§æ¥ãšçµäºæ¥ã調æŽããŠãããæ¥ä»ã®ãã£ã«ã¿ãŒãèšç®ãã£ãŒã«ãã§äœæããŸãã ç²åºŠã§æãéžæããŠããç¶æ
ã§ãStartDaeã2025-01-15ãEndDateã2025-02-07ãšå
¥åãããå Žåã«ã2025-01-01~2025-02-28ã®ããŒã¿ã衚瀺ããããšãã£ãæ³å®ã«ãªããŸãã 以äžã®ããã«ããã³ãããå
¥åããŸããã DAYãWEEKãMONTHãæ¥ãé±ãæã«çœ®ãæããŠä¿åããŸãã ç²åºŠãæ¥ã«ãããšéå§æ¥ãšçµäºæ¥ã®éã®æ¥ä»ãã£ã«ã¿ãŒã1ã«ãªããé±ã«ãããšéå§æ¥ãšçµäºæ¥ãå«ãæ¥ã®é±å§ãããé±çµãããŸã§ã®æ¥ä»ãã£ã«ã¿ãŒã1ã«ãªã£ãŠããã®ã§ãæåŸ
éãã®ãã®ãã§ããŠãããã§ãã æåŸã«ãã£ã«ã¿ãŒã§ãæ¥ä»ãã£ã«ã¿ãŒã1ã®å Žåã®ã¿è¡šç€ºããããã«ããã°ãç²åºŠã«åãããŠéå§æ¥ãšçµäºæ¥ã調æŽããŠãããæ¥ä»ã®ãã£ã«ã¿ãŒã®å®æã§ãïŒ ãã®ãã£ã«ã¿ãŒãèªäœããæã¯ããªãã®æéãããã£ãã®ã§ãäžç¬ã§ã§ããŠæåããŸããïŒ ããŸããããªã£ãäŸ ããŸãèšç®ãã£ãŒã«ããäœæã§ããªãã£ãããã³ããã玹ä»ããŸãã ç°¡æœã«æ¥æ¬èªã§ããã³ãããå
¥åãããããšã©ãŒãåºãŸããã æ¥æ¬èªã§ãããå°ã詳ããããã³ãããæžããããåºåãåŸãããšã¯ã§ããŸããã ããããé±ãã§ã¯ãªãã幎ãèšå®ãããŸããã æ¥æ¬èªã®ããã³ããã«å¯Ÿããåºåã®ç²ŸåºŠã®åäžã¯ä»åŸã«æåŸ
ã§ãïŒ ãããã« ä»åã¯Amazon Q in QuickSightã䜿çšããŠèšç®ãã£ãŒã«ããäœæããæ€èšŒãè¡ããŸããã ç°¡åãªèšç®ãã£ãŒã«ãã®äœæã¯Qã䜿çšããªãæ¹ãæ©ããšæããŸãããå°ãè€éãªèšç®ãã£ãŒã«ããäœæããæããããããããšã¯æ±ºãŸã£ãŠãããåŒããããšã¯æãã€ããªãæã«ã¯ãéçºãå¹çåã§ããæ©èœã ãšæããŸããã æåŸãŸã§èªãã§ããã ãããããšãããããŸããïŒ
éçº2éšã®å
åã§ããæåã³ãŒãã®è©±ã¯å€§å¥œç©ã§ãã äžè¬çã«ãã¢ããªã±ãŒã·ã§ã³ã®éçºã«ãããŠæåæ°ã«ãŠã³ãã¯éåžžã«èº«è¿ãªæ©èœã§ãããã©ã¡ãŒã¿ååŸæããã©ãŒã å
¥åæãªã©ãæ§ã
ãªå Žé¢ã§æåæ°èšç®ãå®è£
ããæ©äŒããããŸãã ããããUnicodeæåãç¹ã«çµµæåãçµåæåãªã©ãæ··åšããããã¹ãåŠçã«ãããŠããæ£ããæåæ°ã«ãŠã³ããã¯æå€ã«è€éãªåé¡ã§ãã ãã®èšäºã§ã¯ãGoèšèªã§ã®Unicodeæåæ°ã«ãŠã³ãã«çŠç¹ãåœãŠãŠãå®è£
æã«æ³šæãã¹ãç¹ãè¿°ã¹ãŸãã æåæ°ã«ãŠã³ãã®çœ ãŸãã以äžã®ã³ãŒãã«ã€ããŠèããŸãã package main import ( "fmt" "unicode/utf8" ) func main() { s := "Helloðð¿" // 6æå? fmt.Printf( "ãã€ãæ°: %d \n " , len (s)) // ãã€ãæ°: 13 fmt.Printf( "ã«ãŒã³æ°: %d \n " , utf8.RuneCountInString(s)) // ã«ãŒã³æ°: 7 } äžèŠ6æåã®ããã«èŠããæååã§ãããå®éã«ã«ãŠã³ããããšç°ãªãå€ãè¿åŽãããŸããããã¯ã©ãããç¶æ³ã§ããããïŒ ãã®å·®ç°ã¯ãäŸãã°ä»¥äžã®ãããªå Žé¢ã§åé¡ãçºçãåŸãŸãã ãã©ãŒã å
¥åæ æåæ°å¶éãè¶
éããŠå
¥åã§ãã ããŒã¿ããŒã¹æå
¥æ ã«ã©ã æåæ°ã®å¶éã«æµè§ŠãDBãšã©ãŒãçºçãã UI衚瀺 æåæ°ã«ãŠã³ã¿ãŒã®è¡šç€ºããŠãŒã¶ãŒã®æèŠãšåããªããªã æåæ°ã«ãŠã³ãææ³ Unicodeæåãæ£ããæ±ãããã«ãçšéã«å¿ããŠé©åãªã«ãŠã³ãææ³ãéžæããå¿
èŠããããŸãã 1. byteæ°ã«ãŠã³ã len() UTF-8ã®ãã€ãåãšããŠåç
§ããŸãã func countBytes(s string ) int { return len (s) } // äŸ fmt.Println(countBytes( "Hello" )) // 5 fmt.Println(countBytes( "ããã«ã¡ã¯" )) // 15 (ã²ããªãã¯UTF-8ã§ã¯3ãã€ã) fmt.Println(countBytes( "café" )) // 5 (é[U+00E9]ã¯UTF-8ã§ã¯2ãã€ã) 2. runeæ°ã«ãŠã³ã utf8.RuneCountInString() Goèšèªã®å
éšã³ãŒãã§ãã rune åäœã§ã rune 1ã€ãUnicodeã®ã³ãŒããã€ã³ã1ã€ã«å¯Ÿå¿ããŸãã func countRunes(s string ) int { return utf8.RuneCountInString(s) } // äŸ fmt.Println(countRunes( "Hello" )) // 5 fmt.Println(countRunes( "ããã«ã¡ã¯" )) // 5 fmt.Println(countRunes( "café" )) // 4 3. æ£èŠååŸã«ãŠã³ã Unicodeã§ã¯ãäžèŠåãèŠãç®ã§ãç°ãªãUnicode衚çŸã«ãªããã®ãååšããŸããçµåæå(Combining Character)ãšããæåæ°ãšããŠã«ãŠã³ãããªãã³ãŒããã€ã³ããååšããŸãã äŸãã°ä»¥äžã®æåã¯äžèŠåãæåã«èŠããŸãïŒç°å¢ã«ãã£ãŠã¯å¥ç©ã«èŠããããç¥ããŸããïŒããã³ãŒããã€ã³ãããŠã¯å¥ç©ã§ããŸãæåæ°ãç°ãªããŸãã ã [U+304C] ãã [U+304B U+3099] ãããäžã€ã®è¡šçŸã«çµ±äžããã®ãæ£èŠåã§ãæ£èŠåããŠããã«ãŠã³ãããŸãã import "golang.org/x/text/unicode/norm" func countNormalizedRunes(s string ) int { normalized := norm.NFC.String(s) return utf8.RuneCountInString(normalized) } // äŸ s1 := "ã" // [U+304C] s2 := "ãã" // [U+304B U+3099] fmt.Println(s1 == s2) // false fmt.Println(countRunes(s1), countRunes(s2)) // 1 2 fmt.Println(countNormalizedRunes(s1)) // 1 fmt.Println(countNormalizedRunes(s2)) // 1 æ£èŠå圢åŒã®éžæ Unicodeã«ã¯4ã€ã®æ£èŠå圢åŒããããŸããæçµçã«ç²åŸããã圢åŒã«å¯Ÿå¿ããæ£èŠåæ¹æ³ãéžã¶å¿
èŠããããŸãã åå 説æ ç¹åŸŽ NFC æ£èŠåïŒåæïŒ èŠèŠçã«åããªãåãã³ãŒãã«ãŸãšãã NFD æ£èŠåïŒåè§£ïŒ çµã¿åããå¯èœãªæåãåè§£ãã NFKC äºææ£èŠåïŒåæïŒ 衚瀺äžåãæå³ã®æåã1ã€ã«ãŸãšããïŒå
šè§âåè§ãªã©ïŒ NFKD äºææ£èŠåïŒåè§£ïŒ åè§£ãã€äºææ§ãå å³ func compareNormalizationForms() { s1 := "ã" fmt.Printf( "NFD: %s(%U)â%s(%U) \n " , s1, [] rune (s1), norm.NFD.String(s1), [] rune (norm.NFD.String(s1))) // NFD: ã([U+304C])âãã([U+304B U+3099]) s2 := "ãã" fmt.Printf( "NFC: %s(%U)â%s(%U) \n " , s2, [] rune (s2), norm.NFC.String(s2), [] rune (norm.NFC.String(s2))) // NFC: ãã([U+304B U+3099])âã([U+304C]) s3 := "â
£" fmt.Printf( "NFKC: %s(%U)â%s(%U) \n " , s3, [] rune (s3), norm.NFKC.String(s3), [] rune (norm.NFKC.String(s3))) // NFKC: â
£([U+2163])âIV([U+0049 U+0056]) s4 := "ïŒ" fmt.Printf( "NFKC: %s(%U)â%s(%U) \n " , s4, [] rune (s4), norm.NFKC.String(s4), [] rune (norm.NFKC.String(s4))) // NFKC: ïŒ([U+FF21 U+FF11])âA1([U+0041 U+0031]) s5 := "ã" fmt.Printf( "NFKD: %s(%U)â%s(%U) \n " , s5, [] rune (s5), norm.NFKD.String(s5), [] rune (norm.NFKD.String(s5))) // NFKD: ã([U+339D])âcm([U+0063 U+006D]) } 4. æžèšçŽ ã¯ã©ã¹ã¿æ°ïŒãŠãŒã¶ãŒç¥èŠæåæ°ïŒ Unicodeã«ã¯ãŒãå¹
æ¥åå(Zero Width Joiner)ãModifierãªã©ãæåæ°ãšããŠã¯ã«ãŠã³ãããªãçš®é¡ã®ã³ãŒããã€ã³ããååšããŸãã ãããã®ã³ãŒããã€ã³ããçšãããšãç¹å®ã®ã³ãŒããã€ã³ããšçµã¿åãããŠå¥ã®æå衚çŸãã§ããããã«ãªããŸããããã«ããå¿
èŠãšãªãã³ãŒããã€ã³ãæ°ãæžããããšãã§ããŸããçµµæåã«ãããèã®è²ã倿Žããããð¯ðµãJ+Pã®ããã«è¡šçŸããããšãã£ãçšéã«äœ¿ãããŸãã æçµçã«ãç°å¢ã«äŸããšããã¯ãããŸããããã§è¡šç€ºãããæååã®è¡šçŸããŠãŒã¶ãŒãå®éã«èªèããæåæ°ãšèšããŸãã ãã ããã®ç®åºãèªåã§å®è£
ããã®ã¯ããªã倧å€ãªã®ã§ãå
¬éãããŠããã©ã€ãã©ãªã«é Œãã»ãããããšæããŸãã æ³šæïŒæåŸã®2ã€ã®æåãããã°ã®ä»æ§ã§è€æ°æåã«åå²ããŠè¡šç€ºãããŠããŸãããæ¬æ¥ã¯ ð³ïžâð ãš ðšâð©âð§âðŠ ã§ãã import "github.com/rivo/uniseg" func countGraphemes(s string ) int { gr := uniseg.NewGraphemes(s) count := 0 for gr.Next() { count++ } return count } // äŸ fmt.Println(countGraphemes( "Hello" )) // 5 fmt.Println(countGraphemes( "ããã«ã¡ã¯" )) // 5 fmt.Println(countGraphemes( "café" )) // 4 fmt.Println(countGraphemes( "ð" )) // 1 [U+1F600] (çµµæåã¯1æåãšããŠèªè) fmt.Println(countGraphemes( "ð¯ðµ" )) // 1 [U+1F1EF U+1F1F5](Regional Indicator Symbolsã¯1æåãšããŠèªè) fmt.Println(countGraphemes( "ð³ïž<200d>ð" )) // 1 [U+1F3F3 U+FE0F U+1F308] (çœæ + ç°äœåã»ã¬ã¯ã¿ + è¹ = ã¬ã€ã³ããŒãã©ãã°ã¯1æåãšããŠèªè) fmt.Println(countGraphemes( "ðš<200d>ð©<200d>ð§<200d>ðŠ" )) // 1 [U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466] (å®¶æçµµæåã1æå) ãŸãšã æåæ°ã®ã«ãŠã³ããšããäžèŠç°¡åããã§å®ã¯ãããããšãããããåé¡ã«ã€ããŠèšäºãæžããŠã¿ãŸããã Goèšèªã§Unicodeãæ±ãå ŽåãããçšåºŠãŸã§ã¯èšèªãšããŠã®ãµããŒããåããããŸãããããããUnicodeã®ä»æ§ãšããŠã³ãŒããã€ã³ããšäººéãèªèããæåæ°ã«ã¯éœéœ¬ãããããããããã®å·®åãåããããã«ã¯ã©ãããŠãå®è£
æã«èæ
®ãå¿
èŠãšãªããŸãã ããããããšã«å¿ããé©åãªã«ãŠã³ãææ³ãæ¡çšããããã«å¿ãããŸãããã
ã¯ããã« ååã®èšäºã§ã¯ãæ°åååç ä¿®ã®ç¬¬1åãã第3åãŸã§ã®å
容ãã玹ä»ããŸããã ååã®èšäºããã²ã芧ãã ããïŒ tech.every.tv åŸåãšãªãæ¬èšäºã§ã¯ã第4åãã第6åã®è¬çŸ©ã«ã€ããŠãäŒãããŸãïŒ åŸåã®ç ä¿®ã¯ãããå®è·µçãªå
容ãçãã ãããã§ãããå®éã«ãµãŒããŒãè§£äœããŠããŒããŠã§ã¢ã®ä»çµã¿ãåŠãã ããISUCON圢åŒã§ããã©ãŒãã³ã¹ãã¥ãŒãã³ã°ã«ææŠããããææ°ã®çæAIæè¡ã«ã€ããŠåŠãã ããšããšã³ãžãã¢ãšããŠç¥ã£ãŠããããå¹
åºãç¥èã身ã«ã€ããããšãã§ããŸããã ããã§ã¯ãååã®å
容ãèŠãŠãããŸãããïŒ 6/4éå¬ 4åç® ãµãŒããŒè§£äœç ä¿® ããã«ã¡ã¯ãéçº1éš ããªãã·ã¥ãããã³AWG PUã®é»é«ã§ããç§ã®æ¹ããã¯GMOãºããæ ªåŒäŒç€Ÿæ§ã«äž»å¬ããŠããã ããããµãŒããŒè§£äœç ä¿®ãã«ã€ããŠç޹ä»ããŸãã GMOã€ã³ã¿ãŒãããã°ã«ãŒãæ ªåŒäŒç€Ÿæ§ã®äŒå ŽæäŸã«ãããGMO Yoursã§éå¬ãããŸããã ãµãŒããŒåºç€è¬åº§ ååã¯ããã«ã»ãã¯ãããžãŒãºæ ªåŒäŒç€Ÿã®çŠç°ããã«ããµãŒããŒåºç€è¬åº§ããšé¡ããŠã倧ãã以äžäžã€ã®å
容ãè¬çŸ©ããŠããã ããŸããã ãµãŒããŒã®åºç€ - ããœã³ã³ããå人ãã§äœ¿ãããšãæ³å®ããŠããã®ã«å¯ŸãããµãŒããŒã¯ãã¿ããªãã§äœ¿ãããšãåæãšããŠããã24æé365æ¥ã®é£ç¶çšŒåãé«ãä¿¡é Œæ§ãæ±ããããããšãã£ãã話ã§ããã ãµãŒããŒã®æ§é - CPU, DRAM, SSD/HDD, NICãšãã£ãåæ§æéšåã®èª¬æãããŒã¿ã®æ£ç¢ºæ§ãä¿ã€ECCã¡ã¢ãªããã¹ãã¬ãŒãžã®åé·åãå®çŸããRAIDæ§æãªã©ããµãŒããŒãªãã§ã¯ã®éšåã«ã€ããŠãåŠã³ãŸããã ãµãŒããŒãªãã§ã¯ã®ä»å æ©èœ - PowerEdgeãµãŒããŒã®ãªã¢ãŒã管çããŒã«ã§ããiDRACïŒintegrated Dell Remote Access ControllerïŒã«ã€ããŠè§£èª¬ããã ããŸããã ç§ãç¹ã«è峿·±ãã£ãã®ã¯ããµãŒããŒãããã«ã忢ããªãããšããéèŠããŠèšèšãããŠããããšããç¹ã§ãã黿ºãå·åŽãã¡ã³ã®åé·åããªã¢ãŒãã§ã®ç®¡çæ©èœãªã©ããã¹ãŠããµãŒãã¹ã®ç¶ç¶æ§ãæ¯ããããã®å·¥å€«ã§ãããæ®æ®µå©çšããŠããPCãšã®èšèšææ³ã®æ ¹æ¬çãªéããçè§£ããããšãã§ããŸããã ãã®ããã«äºåã«ããŒããŠã§ã¢ã®ç¥èãã€ã³ãããããããšã§ãããäžå±€ããµãŒããŒã®å
éšãèŠãŠã¿ããããšããæ°æã¡ãé«ãŸããŸããã ãµãŒããŒè§£äœäœæ¥ ç¶ããŠãç ä¿®ã®ç®çã§ããåŸåã®ãµãŒããŒè§£äœã«ã€ããŠã¬ããŒãããŠãããŸãã äŒå Žã«ã¯ãµãŒããŒãè€æ°å°çšæãããŠãããä»»æã®ããŒã ã«åãããŠããããè§£äœãé²ããŠãããŸããã ãã¡ããç§ãã¡ã®ããŒã ã§è§£äœããŠãããµãŒããŒã«ãªããŸããããŒã¿ã»ã³ã¿ãŒã®ã©ãã¯ã«å¹ççã«æèŒãããããäžè¬çãªã¿ã¯ãŒåPCãããæšªåãã«çްé·ããã©ãã¯ããŠã³ãåããšåŒã°ãã圢ç¶ãããŠããŸãããã®äžå°ã§è»œèªåè»ãè²·ããã»ã©ã®å€æ®µããããšèããæã¯ã倧å€é©ããŸããã ãŸãã¯å€©æ¿ãå€ããŸããCPUãã¡ã¢ãªã黿ºãŠããããªã©ãåºæ¬çãªããŒãæ§æã¯éåžžã®PCãšåãã§ãããåããŒãã®ä¿¡é Œæ§ãæ¡åŒµæ§ã¯å€§ããç°ãªã£ãŠããŸãããäŸãã°ã黿ºãŠãããã¯äºéåãããŠãããçæ¹ãæ
éããŠããµãŒããŒã¯åæ¢ããŸããããŸããå·åŽãã¡ã³ã倿°æèŒãããŠããæ§åãããã髿§èœãªããŒããå®å®ããŠåãã匷åãªå·åŽæ§èœãèŠãŠãšããŸãã åããŒã ã®ãµãŒããŒã¯ããããæ§æãç°ãªã£ãŠãããç§ãã¡ã®ãã®ã¯ç¹ã«ã¡ã¢ãªã®æèŒéãå€ãã¢ãã«ã§ãããGPUãæèŒããŠããããŒã ããã£ãããã§ãå°ã矚ãŸããã£ãã®ãèŠããŠããŸãã è§£äœäœæ¥ã«ç¹å®ã®ããã¥ã¢ã«ã¯ãªããåã¡ã³ããŒããããã¯äœã ããïŒããšèå³ã®èµŽããŸãŸã«ããšãã«ã¯ååãåããªããé²ããŠãããŸããã ãã®çµæã以äžã®ããã«å€ãã®ããŒããåãåºãããšãã§ããŸããã å·¥å
·ã䜿ããªãç¯å²ã§ã®è§£äœã ã£ãããéçã¯ãããŸããããè£ãè¿ãã°ã亀æé »åºŠã®é«ãã¡ã¢ãªãã¹ãã¬ãŒãžãªã©ã®ããŒãã¯ãå°éçãªæè¡è
ã§ãªããŠãç°¡åã«æ±ããããèšèšãããŠããããšãããããŸããã 埩å
äœæ¥ãšã¡ã³ããã³ã¹æ§ ããã«ãããããå
ã®ç¶æ
ã«æ»ãã埩å
äœæ¥ããè¡ããŸãã ç®ã«å
¥ã£ããã®ã次ã
ãšåãåºããŠããè§£äœäœæ¥ããããããŒããåãä»ããé åºãªã©ãèæ
®ããå¿
èŠããããããå°ã身æ§ããŸããã ããããå®éã«ã¯ãããŸã§é£ãããããŸããã§ãããåããŒãã¯æå®ã®å Žæã«ããåãŸããªãããã«å·¥å€«ãããŠãããã¡ã³ããŒãšç¢ºèªããªããäœæ¥ãé²ããããšã§ãæå€ãšããã«å
ã®ç¶æ
ã«æ»ãããšãã§ããŸããã ãã®äžé£ã®äœæ¥ãéããŠããµãŒããŒãããã«ã¡ã³ããã³ã¹æ§ãèæ
®ããŠèšèšãããŠãããã宿ããŸãããå®éã«ããã®ãµãŒããŒã®ã¹ãã¬ãŒãžïŒHDD/SSDïŒã黿ºã¯ããããã©ã°ïŒãµãŒããŒã®é»æºãå
¥ãããŸãŸéšåã®äº€æãã§ããä»çµã¿ïŒã«å¯Ÿå¿ããŠãããšããã話ãèãããŸãã«åžžæçšŒåãæ±ãããããµãŒããŒãªãã§ã¯ã®ç¹åŸŽã ãšæããŸããã HDDã®è§£äœ æèŠªäŒã§ã¯ãç¹å¥ã«HDDã®è§£äœããããŠããã ããŸãããHDDã¯ããã©ãã¿ïŒããŒã¿ãèšé²ããåç€ïŒãšãããïŒããŒã¿ãèªã¿æžãããéšåïŒã®ééãæ°ããã¡ãŒãã«ãšéåžžã«çãã空æ°äžã®åŸ®çްãªå¡µãä»çããã ãã§ãå£ããŠããŸãããããã®HDDãåã³åãããšã¯ãããŸãããæ®æ®µç®ã«ããããšã®ã§ããªã粟å¯ãªå
éšæ§é ã«ãæããèŠå
¥ã£ãŠããŸããŸããã æ®æ®µè§Šããããšã®ã§ããªãããŒããŠã§ã¢ã«ããããè§Šããããšãã§ãããšãŠã貎éãªäœéšã§ããïŒ ãŸãšã AWSãªã©ã¯ã©ãŠããµãŒãã¹ã®å©çšãåœããåã«ãªããç§ãã¡ã«ãšã£ãŠãµãŒããŒã¯ããæœè±¡çãªååšã«ãªãã€ã€ãããŸããããããç©ççãªãµãŒããŒã®ä»çµã¿ãçè§£ããããšã¯ãã¯ã©ãŠãäžã§çºçããããã©ãŒãã³ã¹ã®åé¡ãé害ã«å¯ŸããŠãããæ·±ãã¬ãã«ã§ã®æŽå¯ãäžããŠãããŸãã ãã®ãããä»ååŸãããããŒããŠã§ã¢ã®ç¥èã¯ãã€ã³ãã©ã®èšèšãé害察å¿ãªã©ãããäœãã¬ã€ã€ãŒãæ±ãéã«å¿
ã圹ã«ç«ã€ãšæããŸããã ãã¯ãã¯ã©ãŠããæ¡çšããã®ãåœããåã®ããã«ãªã£ãŠããæšä»ã§ããããµãŒãã¹ã®ç¹æ§ãã³ã¹ããã»ãã¥ãªãã£èŠä»¶ãšãã£ãéçšã®ãŠãŒã¹ã±ãŒã¹ã«å¿ããŠæè»ãªã€ã³ãã©éžæãæ±ããããŸãããã®äžã§ãèªç€Ÿã§ãµãŒããŒãæã€ãªã³ãã¬ãã¹ããå¿
èŠã«å¿ããŠéžæè¢ã«å
¥ããã¹ãã ãšæããŸããã 6/11éå¬ 5åç® ISUCONç ä¿® éçº1éš ããªãã·ã¥ãããã³MS DRMã® éŽæš ã§ããç§ããã¯ISUCONç ä¿®ã®ç޹ä»ãããŸãã ISUCON ãšã¯ãã ããæãã« ã¹ããŒãã¢ãã ã³ã³ãã¹ã ãã®ç¥ç§°ã§ããé¡ãšãªãWebãµãŒãã¹ã決ããããã¬ã®ã¥ã¬ãŒã·ã§ã³ã®äžã§ã©ãã ãé«éåã§ããããç«¶ã倧äŒã®ããšã§ãã isucon.net ä»åã®ISUCONç ä¿®ã§ã¯ãæ¬çªã®ISUCONã®ããã«ããŒã ã§äžããããåé¡ã«åãçµã圢åŒã§è¡ãããŸããã äºåæºå ç§ã¯ISUCONåææŠã ã£ãã®ã§ãããäºåã«ISUCONåºå Žçµéšã®ããå
茩ã«ISUCONã§ãã䜿ãããããŒã«ããã¯ããã¯ã«é¢ããç¥èŠãå
±æããŠé ããŸããã ããŒã«ãšããŠã¯ä»¥äžã®ãããªãã®ããããç ä¿®åœæ¥ã«æŽ»çšããŸããã pt-query-digest slowqueryã®è§£æã«äœ¿ãããŒã« mysqlã®ãã°ãè§£æããŠsqlãé
ãé ã«è¡šç€ºããã alp NGINXã®ã¢ã¯ã»ã¹ãã°ã®è§£æã«äœ¿ãããŒã« é
ããšã³ããã€ã³ãé ã«è¡šç€ºããã ç ä¿®åœæ¥ Step 0: æºå - Gitã§ã®ã³ãŒãç®¡ç æ¬æ Œçãªæ¹ä¿®ãå§ããåã«ããŸãEC2ã€ã³ã¹ã¿ã³ã¹äžã«ãã£ãã³ãŒããGit管çäžã«çœ®ããGitHubãªããžããªã«ããã·ã¥ããŸãããããã«ããã倿Žå±¥æŽã®è¿œè·¡ããåé¡çºçæã®åãæ»ãã容æã«ãªããå®å¿ããŠäœæ¥ãé²ããããã®åºç€ãæŽããŸããã Step 1: N+1ã¯ãšãªã®ç¹å®ãšè§£æ¶ - DBè² è·ã®æå€§ã®åå ãå©ã èª²é¡ ã¢ããªã±ãŒã·ã§ã³ã®åäœãåæãããšããããããããŒãžã衚瀺ããã ãã§ããŒã¿ããŒã¹ã«å€§éã®ã¯ãšãªãçºè¡ãããŠããããšã倿ããŸãããããã¯ãæçš¿ã®äžèЧã衚瀺ããã«ãŒãåŠçã®äžã§ãæçš¿ããšã»ã³ã¡ã³ãããšã«åå¥ã®SQLã¯ãšãªãçºè¡ããŠããŸããå
žåçãªã N+1ã¯ãšãªåé¡ ãã§ããã åæ åé¡ãšãªã£ãŠããã®ã¯ã app.go ã® makePosts 颿°ã§ãã以äžã®ããã«ãforã«ãŒãã®äžã§éœåºŠDBã¢ã¯ã»ã¹ãçºçããŠããŸããã // åé¡ã®ãã£ãã³ãŒãïŒæç²ïŒ for _, p := range results { // ã«ãŒãããšã«ã³ã¡ã³ãæ°ããŠãŒã¶ãŒæ
å ±ãååŸããŠãã db.Get(&p.CommentCount, "SELECT COUNT(*) FROM `comments` WHERE `post_id` = ?" , p.ID) db.Select(&comments, "SELECT * FROM `comments` WHERE `post_id` = ?" , p.ID) // ... } 解決ç ã«ãŒãã®å€åŽã§ãå¿
èŠãªããŒã¿ãäžåºŠã«ãŸãšããŠååŸããæ¹åŒã«å€æŽããŸããã 衚瀺察象ãšãªãæçš¿ã®IDããã¹ãŠéããã SQLã® IN å¥ã䜿ããé¢é£ããã³ã¡ã³ãæ
å ±ããŠãŒã¶ãŒæ
å ±ãäžæ¬ã§ååŸããã ååŸããããŒã¿ãGoã® map ã«æ ŒçŽããã ã«ãŒãã®äžã§ã¯DBã«ã¢ã¯ã»ã¹ããã map ããããŒã¿ãåç
§ããŠæ§é ãçµã¿ç«ãŠãã ãã®ä¿®æ£ã«ãããçºè¡ãããã¯ãšãªæ°ã¯ãæçš¿æ°ã«é¢ãããäžå®ïŒæ°åïŒã«ãŸã§æ¿æžããŸããã Step 2: ããŒã¿ããŒã¹ã€ã³ããã¯ã¹ã®è¿œå - æ€çŽ¢é床ã®åäž èª²é¡ N+1åé¡ã解決ããåŸã次㫠pt-query-digest ã䜿ã£ãŠã¹ããŒã¯ãšãªãã°ãåæãããšãããç¹å®ã®ã¯ãšãªãäŸç¶ãšããŠé
ãããšãããããŸãããç¹ã« ORDER BY created_at DESC ã«ãããœãŒãåŠçãããŒãã«å
šäœãã¹ãã£ã³ïŒãã«ããŒãã«ã¹ãã£ã³ïŒããŠããã倧ããªããã«ããã¯ãšãªã£ãŠããŸããã 解決ç ããã©ãŒãã³ã¹ãæ¹åããããã以äžã®ã€ã³ããã¯ã¹ãããŒã¿ããŒã¹ã«è¿œå ããŸããã -- ãããããŒãžã®æçš¿äžèŠ§è¡šç€ºãé«éå CREATE INDEX idx_posts_created_at ON posts (created_at); -- ãŠãŒã¶ãŒããŒãžã®æçš¿äžèŠ§è¡šç€ºãé«éå CREATE INDEX idx_posts_user_id_created_at ON posts (user_id, created_at); -- ã³ã¡ã³ãäžèЧã®ååŸãé«éå CREATE INDEX idx_comments_post_id_created_at ON comments (post_id, created_at); ããã«ãããæ€çŽ¢ããœãŒããã€ã³ããã¯ã¹ã䜿ã£ãŠå¹ççã«è¡ãããããã«ãªããã¯ãšãªã®å®è¡é床ã倧å¹
ã«åäžããŸããã Step 3: é«ã³ã¹ããªå€éšã³ãã³ãåŒã³åºãã®æé€ - CPUè² è·ã®åæž èª²é¡ CPU䜿çšçã調æ»ããäžã§ããŠãŒã¶ãŒç»é²ããã°ã€ã³æã«åŒã°ãããã¹ã¯ãŒãã®ããã·ã¥ååŠçãããã«ããã¯ãšãªã£ãŠããå¯èœæ§ãæµ®äžããŸãããã³ãŒãã確èªãããšã exec.Command ã䜿ã£ãŠå€éšã® openssl ã³ãã³ããåŒã³åºããŠããŸããã // ä¿®æ£åã® digest 颿° func digest(src string ) string { out, err := exec.Command( "/bin/bash" , "-c" , `... | openssl dgst -sha512 | ...` ).Output() // ... } å€éšããã»ã¹ã®èµ·åã¯éåžžã«é«ã³ã¹ããªåŠçã§ãã 解決ç ãã®åŠçããGoã®æšæºã©ã€ãã©ãª crypto/sha512 ã䜿ã£ãŠãGoã®ããã»ã¹å
ã§å®çµããããã«æžãæããŸããã // ä¿®æ£åŸã® digest 颿° import ( "crypto/sha512" "encoding/hex" ) func digest(src string ) string { hasher := sha512.New() hasher.Write([] byte (src)) return hex.EncodeToString(hasher.Sum( nil )) } ãã®ä¿®æ£ã«ãããããã»ã¹èµ·åã®ãªãŒããŒãããããªããªããCPUè² è·ã倧å¹
ã«åæžã§ããŸããã Step 4: ããŒãžããŒã·ã§ã³ã«ããããŒã¿ååŸã®å¹çå èª²é¡ äž»èŠãªããã«ããã¯ãè§£æ¶ããŠãããšããããŸã§é ããŠããæ°ããªåé¡ãèŠããŠããŸããããããããŒãžã§ã¯20ä»¶ã®æçš¿ã衚瀺ããŠããã«ãããããããSQLã§ã¯å
šä»¶ã®æçš¿ããŒã¿ãååŸããŠãããç¡é§ãªåŠçãè¡ãããŠããŸããã 解決ç ãããããŒãžã®æçš¿ãååŸããã¯ãšãªã« LIMIT 20 ã远å ããŸããã -- ä¿®æ£å SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC -- ä¿®æ£åŸ SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC LIMIT 20 ãã®åçŽãªä¿®æ£ã«ãããDBããã¢ããªã±ãŒã·ã§ã³ãžã®ããŒã¿è»¢ééãåæžãããã¡ã¢ãªäœ¿çšéãšDBè² è·ã®äž¡æ¹ãæ¹åãããŸããã ïŒãªããããšã«ãªã£ãŠæ°ã¥ãã®ã§ãããå逿žã¿ãŠãŒã¶ãŒã®ãã£ã«ã¿ãªã³ã°ã«ãã衚瀺æ°äžè¶³ãè£ãããã«ãå°ãå€ã LIMIT 30 ãããã«ããªããšãããŸãããïŒ ããããªãããæ®ã1æéãåã£ããšããã§åé¡ãçºçããŸãããçšæãããããŒã¿ã誀ã£ãŠåé€ããŠããŸã£ãããã§ãã éå¶ã®çããã«å©ããæ±ãããšãããæ°ããEC2ãç«ãŠãŠããã ããŸããã çãããããŒã¿ããã¯ã¢ããã¯åã£ãŠãããŸãããããã çµäºæå»ãå»äžå»ãšè¿«ã£ãŠããäžããªããšãã¹ã³ã¢ã䌞ã°ãããšãææ©ããããŒã¿ããŒã¹ã€ã³ããã¯ã¹ã®è¿œå ãããããŒãžããŒã·ã§ã³ã«ããããŒã¿ååŸã®å¹çåããè¡ããŸããããªããããŒãžããŒã·ã§ã³ã§ã¯ãäœè£ãæã£ãŠ LIMIT 50 ã«ããŠãããŸããã ãŸãšã æçµçã«ãç§ãã¡ã®ããŒã ãã¢ããã㯠21350ç¹ ã§ 43ããŒã äž17äœ ãšããçµæã«ãªããŸããã1æéåŒ±ã®æ Œéã§ã¯ãã®ç¹æ°ãéçã§ãããã ããŒã¿ããã¯ã¢ãããåã£ãŠããªãã£ãããšãäžçªã®åçç¹ã§ãããåæã«å®è·µåœ¢åŒã§åŠã¶ããšãå€ãææçŸ©ãªç ä¿®ã§ããããã²æ¬å®¶ISUCONã«ãªãã³ãžããããšæããŸãã 6/18éå¬ 6åç® çæAIæŽ»çš éçº1éš ããªãã·ã¥ãããã³MS DRMã®æé«ã§ãã ç§ããã¯çæAI掻çšã®ç޹ä»ãããŸãã æ¬ç ä¿®ã¯ã倧ãã2ã€ã®ããŒãã§æ§æãããŠããŸããã 1. ãã€ã¯ããœããã®å€é·ãšAIãšãŒãžã§ã³ãã®æŠå¿µ 2. AIæä»£ã«ããããœãããŠã§ã¢ãšã³ãžãã¢ã®åœ¹å²ã®å€å AIã®é²å AIã®é²åã¯ãç§ãã¡ããã¯ãããžãŒãšé¢ããæ¹æ³ã倧ããå€ããããšããŠããŸãã ãããŸã§ããšã³ãžãã¢ã®ã³ãŒãã£ã³ã°ãã¢ã·ã¹ãããCopilotã®ãããªAIããŒã«ããããŸãããã ãã€ã¯ããœããã§ã¯ã2025幎ãAIãšãŒãžã§ã³ãå
幎ãšäœçœ®ã¥ããèªç¶èšèªã§ããããæäœã管çãå¯èœã«ããæ°ããªææŠãé²ããããŠããŸãã AIãšãŒãžã§ã³ããšã¯ããŠãŒã¶ãŒãã¿ã¹ã¯ãå²ãæ¯ããšèªåŸçã«å®éããã代ç人ãã®ãããªååšã§ãã ãã€ã¯ããœããã¯è€éãªæ¥åãèªåŸçã«ããªããšãŒãžã§ã³ãã®æäŸãå§ããŠãããå°æ¥çã«ã¯ãšãŒãžã§ã³ãå士ã飿ºãããã«ããšãŒãžã§ã³ãã®äžçãæ§æ³ãããŠããŸãã ãšã³ãžãã¢ã®åœ¹å²ã®å€å AIãçºå±ãã以åã®ãšã³ãžãã¢ã¯ã顧客課é¡ã®çºèŠããèšèšãã³ãŒãã£ã³ã°ããã¥ãŒãã³ã°ãã·ã¹ãã ã®ç£èŠã«è³ããŸã§ã人éäž»å°åã§ããããå·¥çšãããªãå¿
èŠããããŸããã ããããAIã®ç»å Žã«ãããããŸã§äººéãè¡ã£ãŠããå€ãã®äœæ¥ãAIã«ä»»ããããããã«ãªããŸããã ä»åŸã¯ãAIã«å¯ŸããŠé©åãªæç€ºãåºãããã®åºåãè©äŸ¡ããæçµçã«ããè¯ãã¢ãŠããããã圢æãã圹å²ãéèŠãšã®ããšã§ããã 誰ãããã«ã¹ã¿ãã¯ãšã³ãžãã¢ã«ãªããå¯èœæ§ãç§ããŠããäžæ¹ã§ããããŸã§ã®ãšã³ãžãã¢ã®ããã«ããããã¿ã¹ã¯ã人æã®ã¿ã§ããªãã®ã§ã¯ãªããAIãæŽ»çšããŠå
šäœã®èª¿åãåããªãããããžã§ã¯ããæšé²ãããããªå§¿å¢ã«å€ãããªããã°ããšã³ãžãã¢ãšããŠçãæ®ãã®ãé£ãããšæããŸããã éçºã¹ã¿ã€ã«ã®å€å GitHubã®çµ±èšã«ãããšãAIãå©çšããéçºè
æ°ã¯2024幎ã®2岿ªæºãã2028幎ã«ã¯9å²è¿ãã«å¢å ãããšäºæž¬ãããŠããŸãã ã€ãŸããæ°å¹ŽåŸã«ã¯ç€ŸäŒå
šäœã§AIã䜿ã£ãŠå¹çåããŠããããšããã ãŒãã¡ã³ããèµ·ããå¯èœæ§ããããšããããšã§ãã çŸç¶ã®AIã«ããéçºãã³ãŒãã£ã³ã°ã«éãããŠããã®ã«å¯ŸããŠãå°æ¥çã«ã¯äŒç»ã»èšèšã»å®è£
ã»ãã¹ãã»éçšãšãã£ããœãããŠã§ã¢éçºã®ã©ã€ããµã€ã¯ã«å
šäœã«æŽ»çšãããããšã§ãéçºã¹ã¿ã€ã«ã倧ããå€ãããšèããããŠããŸãã ã³ãŒãã£ã³ã°ã¹ã¿ã€ã«ã®å€åã§ã¯ãçŸåšã®Copilotã«ããAIæ¯æŽïŒãã¢ããã°ã©ãã³ã°ïŒãããAIãèªåŸçã«äœæ¥ãè¡ãããŒã ã®äžå¡ïŒãã¢ããã°ã©ãã³ã°ïŒãžãšé²ã¿ãããã«2030幎ã«ã¯ãAIãã»ãŒå®å
šã«èªåŸçã«ãœãŒã¹ã³ãŒããå®è£
ããæä»£ãå°æ¥ãããšäºæž¬ãããŠããŸãã ãã®æªæ¥ã§ã¯ããšã³ãžãã¢ã®äž»ãªåœ¹å²ã¯ãèŠä»¶å®çŸ©ããšãAIãäœæãããã®ããã®èŠä»¶ãæºãããŠãããã®ç¢ºèªããšãªãããããã¯ããããŒãžã£ãŒã®ãããªããµãŒãã¹ã»è£œåã®æ¹åæ§ãå®ãã圹å²ãéèŠèŠãããŸãã 人éãããç¶ããããš AIãã³ãŒããçæããæä»£ã«ãããŠãããã®ã³ãŒãã®æ£ãããçè§£ããããã®ããã°ã©ãã³ã°ã®åºç€ç¥èã¯äŸç¶ãšããŠéèŠãšã®ããšã§ããã ããããAIãã³ãŒããæžããŠããŸããããä»åŸã¯å®è·µçãªåãããç¥èãšããŠç¥ã£ãŠããããšãæ±ããããããã«ãªãããã§ãã ãããããéèŠã«ãªã£ãŠããã®ããAIã«æå³ãæ£ç¢ºã«äŒããããã®ãããã³ãããšã³ãžãã¢ãªã³ã°ãã®èœåã§ãã AIã¯æšè«ã®äžã§ãã«ã·ããŒã·ã§ã³ãèµ·ããå¯èœæ§ããããããç®æšãæç¢ºã«å®£èšããèªç¶èšèªã§èŠä»¶ãææãç確ã«èšè¿°ããã¹ãã«ãäžå¯æ¬ ã ãšèª¬æããã ããŸããã ãŸããAIã¯éçå€ãã¹ããå«ççãªå€æãèŠæãªãããæçµçãªãã¹ãã¯äŸç¶ãšããŠäººéãè¡ãã¹ããšã®ããšã§ããã äŒæ¥å«çãã¬ããã³ã¹ãåœã®ããªã·ãŒãªã©ã人éã®äŸ¡å€èгã«åºã¥ã倿ã¯ãä»åŸã人éã®éèŠãªåœ¹å²ãšããŠæ®ããšèããããŠããŸãã ãŸãšã æ¬ç ä¿®ãéããŠãããããæ°å¹Žã®å
ã«AIãèªåŸçã«å®è£
ããæä»£ãæ¥ããšåèªèããŸãããïŒãããã§ã«æ¥ãŠããã®ãããããŸãã...ïŒ AIã¯ç§ãèããŠããããã身è¿ãªãã®ã«ãªããä»åŸã¯ãæ¯ãããããã«AIã䜿ããããšãéèŠã«ãªã£ãŠãããšæããŸããã ãŸãAIã«å¯ŸããŠã¯ãäœãããŠæ¬²ããããšãã£ãæç€ºãç確ã«äŒããèœåãå¿
èŠã«ãªããèšèªåèœåãããå¿
èŠã«ãªã£ãŠãããšæããŸããã ä»åŸã¯AIã䜿ãåããå°ãã§ãå¹çããéçºãã§ããããã«è©Šè¡é¯èª€ããŠãããããšæããŸãã ãããã« å
š6åã®æ°åååç ä¿®ãéããŠãæ¬åœã«ããããã®ããšãåŠã¶ããšãã§ããŸããã æè¡çãªç¥èã¯ãã¡ããã§ãããäœããè¯ãã£ãã®ã¯ä»ç€Ÿã®æ°åãšã³ãžãã¢ã®çãããšåºäŒããããšã§ããåããããªæ©ã¿ãæ±ããŠããããéãèŠç¹ã§ãã®ãèŠãŠããããåºæ¿ããããããšããããããããŸãããç ä¿®åŸãé£çµ¡ãåãåã仲éãã§ããã®ã¯ããã®ç ä¿®ã®å€§ããªåç©«ã®äžã€ã§ãã ãŸããååéã®ç¬¬äžç·ã§æŽ»èºãããŠããè¬åž«ã®æ¹ã
ããçŽæ¥åŠã¹ãã®ã貎éãªçµéšã§ãããææ°æè¡ã®ãã¬ã³ããçŸå Žã§ã®å®è·µçãªæ
å ±ãªã©ãåèæžã§ã¯åŠã¹ãªãçããç¥èãåŸãããšãã§ããŸããã ãã®ç ä¿®ã§åŸãç¥èãçµéšããããŠä»²éãã¡ãšã®ã€ãªããã倧åã«ããªãããããããããšã³ãžãã¢ãšããŠæé·ããŠãããããšæããŸãã æåŸã«ããã®ãããªçŽ æŽãããæ©äŒãæäŸããŠãã ãã£ãæ¥æ¬CTOåäŒã®çæ§ãååã®è¬åž«ã®çæ§ããããŠã¹ãã³ãµãŒãããŠããã ããäŒæ¥æ§ã«å¿ããæè¬ããããŸããããããšãããããŸããïŒ
ã¯ããã« ããã«ã¡ã¯ãæ ªåŒäŒç€ŸãšããªãŒã®2025幎æ°åãšã³ãžãã¢ã§ãã ç§ãã¡ã¯ã2025幎5æãã6æã«ãããŠéå¬ãããæ¥æ¬CTOåäŒäž»å¬ã®æ°åååç ä¿®ã«åå ããŸãããæ¬èšäºã§ã¯ãç ä¿®ã®æŠèŠãååã®è¬çŸ©å
容ããããŠå®éã«åå ããŠåŸãããåŠã³ãæ°ã¥ãã«ã€ããŠã玹ä»ããŸãã 2024å¹Žã®æ°åååç ä¿®åå ã¬ããŒããæ¯éã芧ãã ããïŒ tech.every.tv æ°åååç ä¿®ãšã¯ æ¥æ¬CTOåäŒãäž»å¬ããæ°åååç ä¿®ã¯ãäŒç€Ÿã®æ ãè¶
ããŠæ°åãšã³ãžãã¢ãæ¥çå
šäœã§æé·ã§ããå Žãã€ããããšãç®æããŠããŸããèæ¯ã«ã¯ããšã³ãžãã¢äžè¶³ããã¹ã¿ãŒãã¢ããã»äžå°äŒæ¥ã«ãšã£ãŠæ°åè²æã®ã³ã¹ãã倧ãããšãã£ããæ¥çå
±éã®èª²é¡ããããŸãã ããã§ãããŸããŸãªäŒæ¥ãå°éå®¶ãååããææ°æè¡ãå®è·µçãªã¹ãã«ããã£ãªã¢åœ¢æãã¯ã©ãŠãããµãŒããŒè§£äœãISUCONãçæAIãªã©ãå¹
åºãããŒãã§è¬çŸ©ããã³ãºãªã³ãè¡ãããŸããã 2025幎ã¯äžèšã®ãããªæ¥çšã§éå¬ãããŸããã ç ä¿®å ããŒãã»å
容 è¬åž«/ã¹ãã³ãµãŒ 第1å Google Cloudã®ã¹ãã·ã£ãªã¹ããšåŠã¶ïŒBigQuery & Gemini ã°ãŒã°ã«ã»ã¯ã©ãŠãã»ãžã£ãã³ååäŒç€Ÿ 第2å CTOããæ°åã«åããè¬è©±ãçæAIæä»£ã®ãœãããŠã§ã¢ãšã³ãžãã¢ãšããŠã®åãæ¹ã®æåŸ
å€ æ¥æ¬CTOåäŒ / æ ªåŒäŒç€ŸLayerXãæ ªåŒäŒç€ŸProgate 第3å ïŒååŠè
ã»äžçŽè
åãïŒ AWS JumpStart ã¢ããŸã³ãŠã§ããµãŒãã¹ãžã£ãã³ååäŒç€Ÿ 第3å ïŒäžçŽè
åãïŒ AWSãµãŒãã¹ã䜿ãISUCONã§é«åŸç¹ãåºããïŒ ã¢ããŸã³ãŠã§ããµãŒãã¹ãžã£ãã³ååäŒç€Ÿ / æ¥æ¬CTOåäŒ è¥æãšã³ãžãã¢ã³ãã¥ããã£æå¿ ç¬¬4å ãµãŒããŒè§£äœç ä¿® GMOãããæ ªåŒäŒç€Ÿ 第5å æ¥æ¬CTOåäŒISUCONæ°åç ä¿®ïŒè§£èª¬ïŒâ»äºå課é¡ããã»ã¯ãªã¢å¿
é ïŒ æ ªåŒäŒç€ŸPR TIMES / ãã¯ã·ãæ ªåŒäŒç€Ÿ 第6å çæAIã«é¢ããè¬çŸ© æ¥æ¬ãã€ã¯ããœããæ ªåŒäŒç€Ÿ ç ä¿®ã¯ãªãã©ã€ã³ã§éå¬ãããä»ç€Ÿã®æ°åãšã³ãžãã¢ãšäº€æµããããã³ãã¥ããã£ãåºãããããæ©äŒããããããããŸããã ãã®åãçµã¿ã¯ããšã³ãžãã¢ãšããŠã®ãã£ãªã¢ã®ã¹ã¿ãŒããåŸæŒãããæ¥çå
šäœã®æé·ã«ã€ãªããããšãç®æããŠããŸãã 詳ããã¯ãã¡ããã芧ãã ããã cto-a.org ããããã¯ããããããå°è±¡ã«æ®ã£ãè¬çŸ©ã1ã€ãã€ããã¯ã¢ããããå
容ãåŠã³ã«ã€ããŠã玹ä»ããŠãããŸãã 5/14éå¬ 1åç® Google Cloud ã®ã¹ãã·ã£ãªã¹ããšåŠã¶ïŒ BigQuery & Gemini éçº1éš ããªãã·ã¥ãããã³MS SPã®è°·å£ã§ããç§ããã¯ã°ãŒã°ã«ã»ã¯ã©ãŠãã»ãžã£ãã³ååäŒç€Ÿã«ãŠéå¬ããã第ïŒåç ä¿®ãGoogle Cloud ã®ã¹ãã·ã£ãªã¹ããšåŠã¶ïŒ BigQuery & Geminiãã«ã€ããŠç޹ä»ããŸãã ãã®ç ä¿®ã§ã¯ãGoogle Cloudã®ã¹ãã·ã£ãªã¹ãã®æ¹ã
ããBigQueryãGeminiã«ã€ããŠçŽæ¥åŠã¶è²Žéãªæ©äŒãããã ããŸãããç¹ã«Google Cloudã®ããŒã¿åæã»AIé¢é£ãµãŒãã¹ãäžå¿ã«ãçŸä»£ã®ããŒã¿æŽ»çšã«ãããææ°ã®ã¢ãããŒãã«ã€ããŠè©³ããæããŠããã ããŸããããŸããåŸåã§ã¯NotebookLMã®æŽ»çšæ¹æ³ã«ã€ããŠã°ã«ãŒããã£ã¹ã«ãã·ã§ã³ãè¡ããåå è
åå£«ã§æ§ã
ãªã¢ã€ãã¢ãå
±æããæéããããŸããã BigQueryã®é²åãšããŒã¿æŽ»çšã®æ°æä»£ ãã«ãããŒãžããªããŒã¿ãŠã§ã¢ããŠã¹ Google Cloudã®BigQueryã¯ãµãŒããŒã¬ã¹ã¢ãŒããã¯ãã£ã§æ§ç¯ããããã«ãããŒãžããªããŒã¿ãŠã§ã¢ããŠã¹ãµãŒãã¹ã§ãã åŸæ¥ã®ããŒã¿åæã§ã¯ã€ã³ãã©ã®ç®¡çãã¹ã±ãŒãªã³ã°ã«å€ãã®ãªãœãŒã¹ãå²ãå¿
èŠããããŸãããããããBigQueryãæŽ»çšããããšã§ããããã®éçšè² è·ããè§£æŸãããããŒã¿åæãã®ãã®ã«éäžã§ããããã«ãªããšãã話ããŸãããŠããã ããŸããã Gemini in BigQuery èªç¶èšèªã§ã®ããŒã¿åæ ç ä¿®ã§æãé©ããã®ã¯ãGemini in BigQueryã®èªç¶èšèªã§ã¯ãšãªãèšè¿°ã§ãã驿°çãªæ©èœã§ããã ãããŸã§è€éãªSQLãæžãå¿
èŠããã£ãåæäœæ¥ããæ¥æ¬èªã§ã®è³ªå圢åŒã§å®è¡ã§ããããã«ãªããŸããäŸãã°ãå
æã®ãŠãŒã¶ãŒç»é²æ°ã®æšç§»ãæããŠããšãã£ãèªç¶ãªåããããããé©åãªSQLã¯ãšãªãèªåçæãããŸãã åæã®æ°äž»å ãã®æ©èœã«ãããSQLç¥èãéå®çãªããžãã¹ãµã€ãã®ã¡ã³ããŒã§ããçŽæ¥ããŒã¿ãŠã§ã¢ããŠã¹ã«åãåãããè¡ãããšãã§ããããã«ãªããŸãã ç§ã¯ãããèããŠãçã®æå³ã§ã®ãåæã®æ°äž»åãã ãšæããŸãããçµç¹å
šäœã§ã®ããŒã¿æŽ»çšã¬ãã«ã®åºäžãã«å€§ããè²¢ç®ããã¯ãã ãšæããŸãã NotebookLMã»ãã·ã§ã³ å®è·µçãªAI掻çšäºäŸ NotebookLMã¯ãGoogleãéçºããAIãæŽ»çšãããªãµãŒãã¢ã·ã¹ã¿ã³ãã§ãã¢ã€ãã¢ã®æŽç·ŽãšæŽçããµããŒãããŠãããŸããã¢ããããŒãããææžãããŒã¿ãåºã«ã質åå¿çãèŠçŽãåæãªã©ãè¡ãããšãã§ããŸãã NotebookLM掻çšäºäŸã®ã»ãã·ã§ã³ã§ã¯ãåå è
åå£«ã§æ§ã
ãªæŽ»çšäºäŸãå
±æããããšãã§ããŸããã ææžã®èŠçŽã質åå¿çãã¢ã€ãã¢çæãªã©ãæ¥åžžæ¥åã§å³åº§ã«æŽ»çšã§ããå
·äœçãªäœ¿ãæ¹ãåŠã¶ããšãã§ããéåžžã«å®è·µçãªå
容ã§ããã ã°ã«ãŒããã£ã¹ã«ãã·ã§ã³ã§ã®æŽ»çšã¢ã€ã㢠ã»ãã·ã§ã³ã§ã¯ãã°ã«ãŒãã«åãããŠNotebookLMã®æŽ»çšæ¹æ³ã«ã€ããŠã¢ã€ãã¢ãåºãåãã»ã¯ã·ã§ã³ããããŸããã ãã®äžã§ç¹ã«è峿·±ãã£ãã®ã¯ã äŒè°ã®æåèµ·ãããšNotebookLMãçµã¿åãããæŽ»ç𿹿³ ãšããã¢ã€ãã¢ã§ãã äŒè°å
容ãæåèµ·ããããåŸããã®å
容ãNotebookLMã«è¿œå ããããšã§ãäŒè°äžã«åºãŠããå°éçšèªãäžæãªç¹ã«ã€ããŠåŸãã詳ããNotebookLMã«è³ªåããããšãã§ããã®ã§ã¯ãªããããšããææ¡ãã°ã«ãŒãããåºãŸããã ä»åŸã®æŽ»çšã«åã㊠ããŒã¿ããªãã³ãªæææ±ºå®ã®å é ä»ååŠãã Google Cloudã®ãµãŒãã¹ã掻çšããããšã§ãããŒã¿ã«åºã¥ããæææ±ºå®ã®ã¹ããŒãã倧å¹
ã«åäžãããããšãã§ãããšæããŸãã ç¹ã«Gemini in BigQueryã®èªç¶èšèªã¯ãšãªæ©èœã«ãããããŒã¿åæããæŽå¯ã®ç²åŸããããŠæœçã®ç«æ¡ãŸã§ã®ãµã€ã¯ã«ãåçã«ççž®ã§ããå¯èœæ§ããããŸãã ããŒã å
šäœã§ã®ããŒã¿æŽ»çšã¬ãã«åäž èªç¶èšèªã€ã³ã¿ãŒãã§ãŒã¹ã®æŽ»çšã«ããããããŸã§ããŒã¿åæã«é¢ããããšãå°ãªãã£ãç§ãã¡ã®ããŒã ã¡ã³ããŒãç©æ¥µçã«ããŒã¿ã掻çšã§ããããã«ãªããšæåŸ
ããŠããŸãã ããã«ãããçµç¹å
šäœã§ã®ããŒã¿ãªãã©ã·ãŒåäžãšãããå€è§çãªèŠç¹ããã®åæãå¯èœã«ãªãã®ã§ã¯ãªãã§ããããã ãŸãšã ä»åã®Google Cloudå
¥éã»ãã·ã§ã³ãéããŠãç§ã¯ããŒã¿åæãšAI掻çšã®æ°ããå¯èœæ§ãåŠã¶ããšãã§ããŸããã ç¹ã«å°è±¡çã ã£ãã®ã¯ãæè¡çãªéå£ãäžããããšã§ããã¹ãŠã®ãšã³ãžãã¢ãããã¹ãŠã®ã¡ã³ããŒããããŒã¿ãšAIãæŽ»çšã§ããç°å¢ãæŽãã€ã€ããããšã§ããã ãããã®æè¡ãç©æ¥µçã«åãå
¥ããããšã§ãããªãã·ã¥ãããã³ãµãŒãã¹ã®æŽãªãçºå±ã«è²¢ç®ããŠãããããšæããŸãã 5/21éå¬ 2åç® ãšã³ãžãã¢ã®åãæ¹ã»ãã£ãªã¢ éçº1éš ããªãã·ã¥ãããã³AWG PUã® å²©ïš ã§ãã ç§ããã¯ãšã³ãžãã¢ã®åãæ¹ãšãã£ãªã¢ã«ã€ããŠç޹ä»ããŸãã ãã®ç ä¿®ã¯ã倧ãã2ã€ã®ããŒãã§æ§æãããŠããŸããã ç»å£è
æå± åœ¹è· ã¿ã€ã㫠島接 ç人 æ ªåŒäŒç€ŸProgate CTO AIæä»£ã®æ°åãšã³ãžãã¢ã«å¿
èŠãªå€åãšåŠç¿ æŸæ¬ åæ° æ ªåŒäŒç€ŸLayerX CTO ãã£ãªã¢ã®èãæ¹ããã©ãã¯ãŒã·ãã AIæä»£ã®æ°åãšã³ãžãã¢ã«å¿
èŠãªå€åãšåŠç¿ ãŸãæ ªåŒäŒç€ŸProgate CTO 島接ããã®ã»ãã·ã§ã³ã§ã¯ãAIæä»£ã«ãããæ°åãšã³ãžãã¢ã®å€åãšåŠç¿ã«ã€ããŠã話ãããã ããŸããã ãœãããŠã§ã¢ãããã¯ãéçºã®å€å åŸæ¥ã®ãœãããŠã§ã¢ãããã¯ãéçºã¯ããäŒç»â èšèšâ å®è£
â è©äŸ¡ããšãããããŒã§é²ã¿ãããã°ã©ãã³ã°ã¯ãã®äžã®éå
·ã®1ã€ã§ãããç¹ã«ããžã¥ãã¢ãšã³ãžãã¢(=æ°å)ãã¯ãå
茩ããäžããããã¿ã¹ã¯ã«åºã¥ããŠå®è£
ãããªãããšãã2024幎é ãŸã§ã¯äžè¬çã§ããã ããã2025幎çŸåšã§ã¯ãã®ç¶æ³ã¯å€§ããå€åããŠãããDevinãCursorãClaude Codeãšãã£ãçæAIããŒã«ãç»å Žããããšã§ç°¡åãªã¿ã¹ã¯ã§ããã°AIãå®è£
ã§ããããã«ãªã£ãŠããŸãã ããã«ãããç°¡åãªä»äºã¯ã©ãã©ãæããŠããªãããã®çç±ã§é£ããä»äºãã©ãã©ãæ®ãããšããç¶æ³ãçºçããçµæãšããŠæ°åãšã³ãžãã¢ã®ãªã³ããŒãã£ã³ã°ã«é©ãããç°¡åãªã¿ã¹ã¯ããæžå°ãããšãã課é¡ãçãŸããŠããŸãã çæAIãšä»äºãããŠããäžã§èããããš ããã§çæAIãé²åãããã³ã«è©±é¡ãšããŠããããããçæAIãããã°äººéã¯ä»£æ¿ãããŠããŸãã®ãïŒããšããåãã«å¯Ÿãã島接ããã¯æç¢ºã« NO ãšçããŠããŸãã ãããŸã§ã®ä»äºã®äžéšãAIã«ãã£ãŠä»£æ¿ããããšããŠãã æ¬¡ã«äººéãããã¹ãããšãå¿
ãåºãŠãã ãšãã£ããã£ãŠããŸããã ãããã£ãæä»£ã®æµãã«ããããšã³ãžãã¢ã®å¿æ§ãã«ã€ããŠã島接ããããäœç¹ããäŒãããã ããäžã§å人çã«æãå°è±¡ã«æ®ã£ãã話ã玹ä»ããŸãã AIæä»£ã®ãšã³ãžãã¢ã®å¿æ§ã çŸç¶AIã¯ãŸãã«éæž¡æã§ããç¶æ³ã¯åžžã«å€åããŠãããããããã«è¿œãã€ããããæ¹ãæŽæ°ãç¶ããå¿
èŠããããŸãã ããã¯åŸæ¥ãæ±ããããŠããŸããããå€åã®å€§ãããæ Œæ®µã«å¢ããŠããç¹ãæ°ããéšåã§ãã ãããŠäžã®äžã§AIã®æŽ»çšæ³ã«çããåºãŠããªãããã以äžã®ãµã€ã¯ã«ãç¶ç¶çã«åããŠç¥èŠãã¢ããããŒãããŠããå¿
èŠããããŸãã 屿æé©ãç¡éã«ç©ã¿éãã ïŒèªåèªèº«ã§ãããã詊è¡é¯èª€ãç¹°ãè¿ãããšã ç¥èŠãå
±æããã¢ããããŒããã ïŒåŸãããç¥èŠãããŒã ãçµç¹ãã³ãã¥ããã£ãŒã«éå
ããããšã æè¡ã®é²æ©ã«åãããŠ1ãš2ãç¹°ãè¿ã ã æ°ããæè¡ãåºãŠããããšã«ãã詊ãã ããããŸãã¯å人ã§è©Šè¡é¯èª€ããŠããŒã ãçµç¹å
ã§ãã©ãã·ã¥ã¢ãããããµã€ã¯ã«ãåãããã«ãªãã°ãåŒç€Ÿãæ²ããAIã§éçºã¹ããŒãã10åã«ããããšãå®çŸã§ããã®ã§ã¯ãªãããšæããŸããã ãã£ãªã¢ã®èãæ¹ããã©ãã¯ãŒã·ãã æ ªåŒäŒç€ŸLayerX CTO æŸæ¬ããã®ã»ãã·ã§ã³ã§ã¯ããã£ãªã¢ã®èãæ¹ãšãã©ãã¯ãŒã·ããã«ã€ããŠã話ãããã ããŸããã ãã£ãªã¢ã®èãæ¹ æŸæ¬ããã¯ãã£ãªã¢ãåŸæããªãããã®ãã€ã³ããšããŠä»¥äžã®3ã€ããããŠããŸãã æè³å®¶çæè ã³ãã¥ãã㣠æåã®10幎éã®äœ¿ãæ¹ ããããéŠãåããã»ã©é ·ããå
容ãªã®ã§ãã¹ãŠç޹ä»ããããšããã§ãããããã§ã¯ æè³å®¶çæè ãåãäžããŸãã æè³å®¶çã«ãã£ãªã¢ãèãã ããã§ã¯ãã£ãªã¢ãè³ç£ãšããŠãšãããèªèº«ã®ãã£ãªã¢ãåãªãä»äºã®é£ç¶ã§ã¯ãªãã人çãšããè³ç£ãæå€§åããããã®ãæè³æŽ»åããšæããŸãã ãè³ç£ããšã¯ãéã ãã§ãªããä¿¡çšã»ä¿¡é Œãå¥åº·ã»äœåãå声ãç¥èã»çµéšãæéãªã©å€æ§ãªèŠçŽ ãå«ãŸããŸãã æè³å®¶çæèãšã¯ãç§ãã¡äžäººã²ãšããèªèº«ã®ãè³ç£ããå®ãããã®è³ç£ã䜿ã£ãŠèªåã®ä»®èª¬ã»åŠã³ããæ¹åã«åããŠå¹çããæè³ããããšã§ãã倧ããªè³ç£ãç²åŸããŠãããæè³å®¶ãã§ããããšããèãæ¹ã§ãã ãªã¹ã¯ãšãªã¿ãŒã³ ãã®ãããªèãæ¹ãããäžã§ãã©ããªæææ±ºå®ã«ããªã¹ã¯ãšãªã¿ãŒã³ãååšããããšãæèããå¿
èŠããããŸãã èªåãç®çãšãããªã¿ãŒã³ãåŸãããã«ãæå
ã«ã©ã®ãããªéžæè¢ããããã©ã®ãããªãªã¹ã¯ãããã®ããæŽçããããšã§ãæé©ãªéžæãããããšãã§ããŸãã äžè¬çã«ãªã¹ã¯ãšãªã¿ãŒã³ã¯æ¯äŸããŸãããç¥èéãå¢ããããšã§åããªã¿ãŒã³ãããå°ããªãªã¹ã¯ã§åŸãããšãå¯èœã«ãªããŸãã æ¢çŽ¢ãšåŠã³ ãããŠãã®ç¥èãå¢ãããäžç¢ºå®æ§ãäœäžãããããã«ã¯ç¶ç¶çãªåŠç¿ãµã€ã¯ã«ãäžå¯æ¬ ã§ãã ã仮説ç«ãŠâ è¡åâ æ¯ãè¿ãâ åŠç¿ã»ç¥èåãã®ãµã€ã¯ã«ãåãããšã§ããã粟床ã®é«ãç¶æ³çè§£ãšäžç¢ºå®æ§ã®äœäžã«ã€ãªãããŸãã ãã©ã³ã¹ã·ãŒããšããŒããã©ãªãª ãšã¯ãããããããããšãã¹ãŠã«æè³ããããšã¯ã§ããŸããã èªèº«ã®æã€æè³å¯èœãªè³ç£ïŒãéãæéãäœåãä¿¡çšãªã©ïŒãã©ã®ããã«é
åããããšãã£ããã©ã³ã¹ã·ãŒããäœæããäœåãªè³ç£ïŒç¹ã«æéïŒã«å¯ŸããŠã©ãã«ã©ãã ã䜿ãããæ±ºããããšã§ããã£ãªã¢ã®æ¹åæ§ãæç¢ºã«ãªããŸãã ã¬ãã¬ããž ãããŠæã«ã¯ã¬ãã¬ããžãããããªã¹ã¯ããšã£ãŠãã倧ããæè³ãããããšãå¿
èŠã§ãã æå
ã®è³ç£ãç¹ã«ç¥èãçµéšãšãã£ãã¹ããã¯ãããæ¹åãžæè³ããéçšå¹çãé«ãŸãææ®µã远ããããããšã§ãã倧ããªãªã¿ãŒã³ãåŸãããšãã§ããŸãã äŸãšããŠã以äžã®ãããªé
ç®ãæããããŠããŸããã ãéã§æéãç¥èã»çµéšãè²·ãïŒå®¶äºã®ã¢ãŠããœãŒã¹ãææããŒã«ã®æŽ»çšïŒ ããŒã ã§åãïŒäººã«ã¬ãã¬ããžããããïŒ ä¿¡çšã®ã¬ãã¬ããžïŒã¹ãã«ãäžè¶³ããŠããŠãä¿¡é Œãããã°ä»»ããŠããããïŒ ãããã£ãã¬ãã¬ããžããããããšã§ããã£ãªã¢ã®ã¹ããŒããå éãããããšãã§ããŸãã ããããªã¹ã¯ãåãããããšå€±æããå¯èœæ§ããããããèªèº«ã®åããããªã¹ã¯åºŠåãã«å¿ããŠèª¿æŽãå¿
èŠã§ãã ãŸãšã AIæä»£ã®ãã£ãªã¢ãèããäžã§ã®æéãšãªãã話ã島接ããããèãããšãã§ããŠæ¬åœã«ããã£ããªãšæã£ãŠããŸãã ãŸãæŸæ¬ããã«çºè¡šããã ããè³æã¯ä»¥åããæèŠããŠããããã¡ããç§èªèº«ã®ãã£ãªã¢æéã«å€§ããªåœ±é¿ãäžããŠãããŠããã®ã§ä»åã®ç ä¿®ã§çŽæ¥ã話ã䌺ãããšãã§ããŠãšãŠãå¬ããã£ãã§ãã AIæä»£ã®æ³¢ã«ä¹ãé
ããªããããªãã£ãªã¢æŠç¥ãèãç¶ããããšæããŸãïŒ 5/27ã»28éå¬ 3åç® AWS JumpStart éçº1éš ããªãã·ã¥ãããã³MS DRMã® æ±ïš ãšéçº1éšããªãã·ã¥ãããã³AWGãã«ã·ã«ã® èµ€å· ã§ãïŒç§ãã¡ããã¯ãAWS JumpStartã«ã€ããŠç޹ä»ããŸãïŒ AWS JumpStart 2025ã¯ãAWSååŠè
ã®ãšã³ãžãã¢ã察象ãšããå®è·µçãªç ä¿®ããã°ã©ã ã§ãã ãã®ããã°ã©ã ã®ãŽãŒã«ã¯ãäžè¬çãªã¢ãŒããã¯ãã£ã®çè§£ãAWSã³ã¢ãµãŒãã¹ã®æŠèŠãšãã®éžå®åºæºã®ææ¡ããããŠAWSã¢ãŒããã¯ãã£å³äœæã®æµããåŠã¶ããšã§ãã ã¿ã€ã ã¹ã±ãžã¥ãŒã« 2æ¥éã®ã¹ã±ãžã¥ãŒã«ã¯ä»¥äžã®éãã§ãã1æ¥ç®ã¯åº§åŠãšAWSç°å¢ã®æ§ç¯ãè¡ããã³ãºãªã³ã2æ¥ç®ã¯1æ¥ç®ã®å
容ãèžãŸããããå®è·µçãªã¢ãŒããã¯ãã£æ€èšãè¡ããŸããã 1æ¥ç® ãŸã1æ¥ç®ã®å
容ã«ã€ããŠç޹ä»ããŸãã è¬çŸ© è¬çŸ©ã§ã¯ãã¢ãŒããã¯ãã£ã³ã°ã®ã³ããã«ã€ããŠè§£èª¬ããã ããŸãããWebãµãŒãã¹æ§ç¯ã«ããããã§ãŒãºããšã®AWSãµãŒãã¹éžå®ã®åºç€ããã·ã¹ãã ã¹ã±ãŒã«æã®èª²é¡ãšå¯Ÿçã«ã€ããŠåŠã³ãŸããã è¬çŸ©ã®å
容ãç°¡æœã«ãŸãšãããšä»¥äžã®ããã«ãªããŸãã ãã§ãŒãºïŒ: ãããã¿ã€ãïŒã100äººïŒ æ§æ: Route 53 â EC2 â RDS ç¹åŸŽ: ã·ã³ãã«ã»å®äŸ¡ãå¯çšæ§ã¯éèŠããªã ãã§ãŒãº2: äžè¬å
¬éïŒ100人ã10,000äººïŒ æ§æ: Route 53 â ALB â EC2ïŒãã«ãAZïŒ â RDSïŒãã«ãAZïŒ æ¹åç¹: - Application Load Balancerã«ããè² è·åæ£ - è€æ°AZã§ã®åé·å - Auto Scalingã®å°å
¥ ãã§ãŒãº3: å€§èŠæš¡åïŒ10,000人ã1,000,000äººïŒ æ§æ: CloudFront â ALB â Auto Scaling Group â Aurora + ãªãŒãã¬ããªã« + ElastiCache æ¹åç¹: - CloudFront: éçã³ã³ãã³ãã®CDNé
ä¿¡ - Aurora: 髿§èœDBããªãŒãã¬ããªã«ã§èªã¿åãè² è·åæ£ - ElastiCache: ã€ã³ã¡ã¢ãªãã£ãã·ã¥ã§DBè² è·è»œæž ãã§ãŒãº4: è¶
å€§èŠæš¡ïŒ1,000,000人以äžïŒ ç¹åŸŽ: èšæž¬ã»åæã»æ¹åãµã€ã¯ã«ã®éèŠ æ¹åç¹: - ã¢ããªã±ãŒã·ã§ã³æé©å - DBã·ã£ãŒãã£ã³ã°ãNoSQLæŽ»çš - ãã€ã¯ããµãŒãã¹å - Infrastructure as CodeãCI/CDå°å
¥ ã·ã¹ãã æ§ç¯æã¯ãæåããé床ã«äœã蟌ãŸããèŠä»¶ãæºããã·ã³ãã«ãªèšèšããå§ããããšããããŠèšæž¬ã»åæã»æ¹åã®ãµã€ã¯ã«ãç¶ç¶ããããšãéèŠã§ãããšåŠã³ãŸããã ãã³ãºãªã³ ãã³ãºãªã³ã§ã¯ãå®éã«AWSç°å¢ã®æ§ç¯ãäœéšããŸããã2ã3人ã®ããŒã ã§ãAWSç°å¢ãæäœãããã©ã€ããŒãšãæé æžã確èªããªããæç€ºãåºãããã²ãŒã¿ãŒãããŒããŒã·ã§ã³ããªããé²ãããã¢ãããã°ã©ãã³ã°åœ¢åŒã§å®æœãããŸããã ååã®ãã³ãºãªã³ã§ã¯ã以äžã®ãããªã·ã³ãã«ãªã¢ãŒããã¯ãã£ãæ§ç¯ããŸãããå®éã«æãåããããšã§ãAWSç°å¢æ§ç¯ã®çè§£ãæ·±ãŸããŸããã åŸåã®ãã³ãºãªã³ã§ã¯ãããå®è·µçãªã¢ãŒããã¯ãã£ãæ§ç¯ããŸãããALBã«ããè² è·åæ£ããDBã®ãã§ã€ã«ãªãŒããŒæ©èœã«ããå¯çšæ§ã®æ
ä¿ãªã©ãååãããé«åºŠãªæ§æãšãªã£ãŠããŸãã ãŸããã¢ãŒããã¯ãã£ãæ§ç¯ããŠçµããã§ã¯ãªããECSã¿ã¹ã¯ã忢ãããéã®æåãªã©ã確èªããå®éã«é害ãçºçããå Žåã«ã©ã®ããã«å¯çšæ§ãä¿ãããããäœéšã§ããŸããã ãŸãšã AWS JumpStart 1æ¥ç®ãéããŠãåãªãAWSãµãŒãã¹ã®åŠç¿ã«ãšã©ãŸãããããªããã®ãµãŒãã¹ãéžå®ããã®ãããã©ã®ããã«ã¢ãŒããã¯ãã£ãèšèšãã¹ããããšãã£ãã¢ãŒããã¯ãã£ã³ã°ã®æèããã»ã¹ã®åºç€ãåŠã¶ããšãã§ããŸããã ãŸããã¢ãããã°ã©ãã³ã°åœ¢åŒã§åŠã¶ããšã§ãããŒã å
ã§æŽ»çºã«æèŠäº€æããæãåãããšã§çè§£ãããæ·±ããããšãã§ããŸãããããã§åŠãã ããšãåå°ã«ãä»åŸã®æ¥åã§ãèŠä»¶ã«åã£ãã¢ãŒããã¯ãã£ãèããŠãããããšæããŸãã 2æ¥ç® 2æ¥ç®ã¯ããå®è·µçãªå
容ã§ãäžãããããé¡ã«æ²¿ã£ãã¢ãŒããã¯ãã£ãèšèšãã課é¡ã«åãçµã¿ãŸããã ã¢ãŒããã¯ãã£ã®æ€èšïŒåäººïŒ ãŸãã¯å人ã§ã¢ãŒããã¯ãã£ãæ€èšããæéãèšããããŸãããäžãããããé¡ã«å¯ŸããŠã以äžã®ãããªæ§æãèããŸããã ãã«ãAZæ§æã§åé·å ããã³ããšã³ãïŒReactïŒTypeScriptïŒãããžã§ã¯ããECS Fargateã§å®è¡ãCDNã®ããã«CloudFrontã䜿çšãéçã³ã³ãã³ãã¯S3ããé
ä¿¡ ããã¯ãšã³ãïŒJava/Spring Bootã¢ããªã±ãŒã·ã§ã³ãECS Fargateã§å®è¡ãæéã«å¿ããŠãªãŒãã¹ã±ãŒãªã³ã° ããŒã¿ããŒã¹ïŒAuroraãã¬ããªã«ã远å ããŒããã©ã³ãµãŒïŒApplication Load BalancerïŒALBïŒ ãã°ïŒCloudWatchãšKinesisçµç±ã§ãS3ã«ä¿å DNSïŒRoute 53 1æ¥ç®ã§åŠãã å
容ãããšã«ãåºæ¬çãªWebãµãŒãã¹ã®ã¢ãŒããã¯ãã£ã«å¿
èŠãªããšã¯ç¶²çŸ
ããããšãã§ãããšæããŸãïŒ ã¢ãŒããã¯ãã£ã®æ€èšïŒã°ã«ãŒãïŒ ãŸããã¡ã³ããŒãããããèããã¢ãŒããã¯ãã£ãå
±æããç¹åŸŽãšæ¹åãã¹ãç¹ãå
±æããŠãããŸããã ãã®åŸåã¢ãŒããã¯ãã£ã®è¯ããšãããéããŠã以äžã®èŠçŽ ã远å ãããŸããã - ãã£ãã·ã¥ïŒElastiCache - ãã¥ãŒïŒSQS - å€éšãšã®æ¥ç¶ïŒNAT Gateway - èªèšŒïŒCognito ããã§ãæã
ã®ã¢ãŒããã¯ãã£å³ã¯å®æããŸããïŒ NAT Gatewayãçµç±ããå€éšAPIãšã®é£æºãäžå¯§ã«æããã®ãè¯ãã£ããšæã£ãŠããŸãïŒ çºè¡šäŒ çºè¡šã§ã¯3ããŒã ãéžã°ããããããã®ã¢ãŒããã¯ãã£ã«ã€ããŠèª¬æãããŠããŸããã ç§ã®ããŒã ã¯éžã°ããŸããã§ããããåŒç€Ÿã¡ã³ããŒã®ããããŒã ãéžã°ããã®ã§ãã®ã¢ãŒããã¯ãã£ãèŒããŠãããŸãïŒ å人çã«ã¯ãæ®æ®µã®å®äŸäŒè°ã§ããã·ã¥ããŒããèŠãæ©äŒãå€ãã®ã§ãããã·ã¥ããŒãäœæã®æ©æ§ãããã®ãè¯ããªãšæããŸããïŒ æèŠªäŒ å€ã®æèŠªäŒã§ã¯ãã¯ããã«24æ°åã®å
茩ããAWSã«é¢ããLTãè¡ãããŸããã ãã®äžã§ãã·ããžãŒããŒã±ãã£ã³ã°æ ªåŒäŒç€Ÿã®æšå±±ããããAWSã®ã³ã¹ã管çã«é¢ããã話ãããŠããã ããŸããã ãã®è©±ãèããŠãæ©éå人éçºã®ãããžã§ã¯ãã«ã³ã¹ãã¢ã©ãŒããèšå®ããŠãããŸããïŒ ãã®åŸã¯ãäžç·ã«ã¢ãŒããã¯ãã£ãäœã£ãããŒã ã¡ã³ããŒãä»ã®äŒç€Ÿã®äººãã¡ãšãããã亀æµããããšãã§ããŸããïŒ ãã®æã«ç¥ãåã£ãã¡ã³ããŒãšäºæ¬¡äŒã«è¡ã£ããã茪èªäŒãå§ããããšãåæã®ç¹ããã®è¯ããæ¹ããŠå®æããŸããã ãŸãšã ãã®ç ä¿®ãéããŠãå®éã®ã¢ãŒããã¯ãæ¥åãäœéšããããšãã§ããŸããã å®éã®ããžãã¹èŠä»¶ãæè¡çã«ã©ãå®çŸããããªã©ãæ·±ãèããã®ã¯ãšãŠã楜ããã£ãã§ãã ããã«é¢çœãã£ãã®ã¯ã宿ããã¢ãŒããã¯ãã£ãã°ã«ãŒãã«ãã£ãŠå
šãéã£ãããšã§ãã äžã«ã¯ãµãŒããŒãç«ãŠãã«ãå
šãŠãLambdaã§ãµãŒããŒã¬ã¹ã«åŠçãããšããææŠçãªã¢ãŒããã¯ãã£ããããŸããã ä»åŸã¯ãã䜿ã£ãããšãããAWSãµãŒãã¹ãå¢ãããŠããããã§ãïŒ å®åã§ã¯ãã¡ãããå人éçºã§ãè²ã
ãªAWSãµãŒãã¹ã詊ããŠã¿ãããšæããŸãïŒ ãããã« ãããŸã§ã2025幎æ°åååç ä¿®ã®ååïŒç¬¬1åã第3åïŒã«ã€ããŠã玹ä»ããŸããã åŸåã§ã¯ã第4åãã第6åã®ç ä¿®å
容ã«ã€ããŠãäŒãããŸãã ãã²ãåŸåã®èšäºãã芧ãã ããïŒ tech.every.tv
ç®æ¬¡ ã¯ããã« WAF å°å
¥ã®èæ¯ WAF å°å
¥ã«ããã調æ»ã»æ€èšããããš ãã°ã®éçš Slack éç¥ã®å®çŸ WAF å°å
¥æã®èæ
®ç¹ ãããã« ã¯ããã« ããã«ã¡ã¯ã éçºæ¬éšéçº1éšãã¢ããéçºéšæå±ã®åºåž( @ktanonymous )ã§ãã å
æ¥ããã¢ããã§ WAF (Web Application Firewall) ãå°å
¥ããŸããã WAF ã®å°å
¥ã«ããããããŸã§ä»¥äžã«å®å¿æãæã£ãŠãµãŒãã¹éçšã«åãåããããã«ãªã£ããšæããŠããŸãã æ¬èšäºã§ã¯ãWAF å°å
¥ã®èæ¯ãããå®éã«èª¿æ»ã»æ€èšããå
容ããããŠå°å
¥åŸã®éçšã«ã€ããŠãŸãšããŠãããŸãã WAF å°å
¥ã®èæ¯ ãµãŒãã¹éå¶ãããŠããäžã§ãæ»æãåãããšããã®ã¯ããããããšã ãšæããŸãã ãã¢ããã§ãæ»æãšæãããã¢ã¯ã»ã¹ãæ€ç¥ããããšããããŸãããçŽè¿ã§ã¯ãã®ãããªã¢ã¯ã»ã¹ãéå»ã«æ¯ã¹ãŠãå€ãç¶æ³ãç¶ããŠããŸããã 以åã«ã¯ããã¢ããã§ SQL ã€ã³ãžã§ã¯ã·ã§ã³æ»æãåããããšã«é¢ããããã°ãå
¬éããŠããŸãã®ã§ããã¡ããã芧ãã ããã SQL ã€ã³ãžã§ã¯ã·ã§ã³ã®ãããªæ»æã«å¯ŸããŠã¯ãã¢ããªã±ãŒã·ã§ã³åŽã®ããªããŒã·ã§ã³ã®åŸ¹åºãªã©ã«ãã察å¿ãããŠããŸãããã DoS æ»æã®ããã«å€§éã®ãªã¯ãšã¹ããéãã€ããããšã§ã·ã¹ãã è² è·ãé«ãããããªæ»æã«å¯ŸããŠã¯ã 瀟å
Slack ã§ã¢ã©ãŒããçºå ±ãããéœåºŠç¶æ³ç¢ºèªãããšãã察å¿ãããŠããŸããã ã·ã¹ãã ã®éè² è·ãæ€ç¥ããæã«ã¢ã©ãŒããçºå ±ããç£èŠäœå¶ãåããŠããã®ã¯è¯ãã®ã§ãããå¹³æ¥ã»äŒæ¥ã»æŒå€åãã察å¿ãè¿«ãããŠããŸãç¶æ³ã¯ã察å¿è² è·ãé«ãå¥å
šã§ã¯ãªããšæããŠããŸããã ããã§ã倧éã¢ã¯ã»ã¹ã«ããéè² è·ãç¶ããããšãèžãŸããWAF ã®å°å
¥ã決å®ããŸããã ïŒãªãããã¢ããã§ã¯ã€ã³ãã©ã« AWS ãå©çšããŠãããããAWS WAF ãå°å
¥ããŸãããïŒ WAF å°å
¥ã«ããã調æ»ã»æ€èšããããš WAF ãå°å
¥ããã«ããã£ãŠã¯ãéçšã»éé¡ã³ã¹ããã§ããã ãæãããããã æ§æãåæãšããŠã以äžã®èгç¹ã§èª¿æ»ã»æ€èšãé²ããŸããã ãã°ã®éçš WAF ãå°å
¥ããäžã§ãæå°ã³ã¹ãã§éçšã§ãããã°ã¯äœããèããŸããã çµè«ããè¿°ã¹ãŠããŸããšã远å ã³ã¹ããªãèšå®ã§ãããµã³ãã«ãªã¯ãšã¹ãããã³ CloudWatch Metrics ãå©çšããããšã«ããŸããã S3 ã«ãã°ãä¿åããããšãèããŸãããããã®ããã«ã¯ Kinesis Data Firehose ãå©çšããå¿
èŠãããããã ã·ã³ãã«ã«å°å
¥ã§ããæ§æãæ¡çšããããšã«ããŸããã ãããã¯ãTerraform ã§ WAF ã®ã«ãŒã«ã®ãªãœãŒã¹ãäœæããéã«ä»¥äžã®ããã« visibility_config ãšãããã£ãŒã«ããå®çŸ©ããã ãã§èšå®ã§ããŸãã visibility_config { cloudwatch_metrics_enabled = true metric_name = "metric_name" sampled_requests_enabled = true } WAF ã®ãµã³ãã«ãªã¯ãšã¹ãã§ã¯ãå®éã®ãªã¯ãšã¹ãã®äžéšãã©ã³ãã ã«ããã¯ã¢ãããããŸãã ãããããªã¯ãšã¹ãã®ãµã³ããªã³ã°ã ãã§ã¯ WAF ã®ã«ãŒã«ã§æ€ç¥ããããªã¯ãšã¹ãã確èªããã®ã¯é£ããã§ããããµã³ãã«ãªã¯ãšã¹ãã¯ã¡ããªã¯ã¹å¥ã«ãã£ã«ã¿ãªã³ã°ããŠç¢ºèªããããšãã§ããã®ã§ãWAF ãã©ã®ãããªãªã¯ãšã¹ããæ€ç¥ããã®ããååã«ç¢ºèªããããšãã§ããŸãã WAF ã®ãµã³ãã«ãªã¯ãšã¹ã Sampled requests ã®åé
ç®ã«ã€ã㊠Metric name visibility_config ã§èšå®ãã metric_name Source IP 該åœã®ã«ãŒã«ã§æ€ç¥ããããªã¯ãšã¹ãã®éä¿¡å
IP ã¢ãã¬ã¹ URI 該åœã®ã«ãŒã«ã§æ€ç¥ããããªã¯ãšã¹ãã® URI Rule Inside rule group 該åœã®ã«ãŒã«ãæå±ããã«ãŒã«ã°ã«ãŒã Action 該åœã®ã«ãŒã«ã§æ€ç¥ããããªã¯ãšã¹ãã«å¯ŸããŠå®è¡ãããã¢ã¯ã·ã§ã³ Time 該åœã®ã«ãŒã«ã§æ€ç¥ããããªã¯ãšã¹ãã®éä¿¡æå» Slack éç¥ã®å®çŸ WAF ã§æ»æãšæããããªã¯ãšã¹ããæ€ç¥ããæããã³æ»æãæ¢ãã æã« Slack ãžéç¥ããããšã§ å³åº§ã«ç¶æ³ãææ¡ã§ããããã«ãããããšèããŸããã ããã§ã远å ã®ã³ã¹ããæããã«éç¥ã·ã¹ãã ãå®çŸããããã以äžã®ãããªæ§æãæ¡çšããŸããã WAF ã¢ã©ãŒã ã®éç¥ã·ã¹ãã ãã®æ§æã§ã¯ãWAF ã®ã«ãŒã«ã®æ€ç¥ç¶æ³ã CloudWatch Alarm ã§ç£èŠããŸãã ä»åã®ç£èŠå¯Ÿè±¡ã¯ãã¬ãŒãããŒã¹ã«ãã IP ã¢ãã¬ã¹ã®ãããã¯ã«ãŒã«ã«ãªããŸãã WAF ã«ãã£ãŠãããã¯ããããšããããšã¯æ»æãšå€æãããŠããããšã«ãªããããã¢ã©ãŒã ã®éŸå€ã¯ 1 ä»¶ãšããŠããŸãã ããã«ãããæ»æçºçæã« Slack ãžéç¥ãããããã«ãªããŸãã ãã ããããã ãã§ã¯å¹³æã®ã¢ã©ãŒã ã®ç¶æ
ããããŒã¿äžè¶³ããšèªèãããŠããŸãã®ã§ã 0 ä»¶ã®ç¶æ
ããæ£åžžãã§ãããšèªèãããããã«ã noBreaching ã®èšå®ãããŠãããŸã 1 ã ãã®èšå®ã远å ããŠããããšã§ãæ»æãæ¢ã¿ãããã¯ã«ãŒã«ã®æ€ç¥æ°ã 0 ä»¶ã«æ»ã£ãæã«ã ã¢ã©ãŒã ããæ£åžžãç¶æ
ã«æ»ããæ»æãæ¢ãŸã£ãããšã Slack ãžéç¥ããããšãã§ããããã«ãªããŸãã ïŒã¢ã©ãŒã ã¯ç¶æ
å€åã«ãããã®ãªã®ã§è€æ°ã®æ»æãéç¥ããããšã¯ã§ããŸãããã å
šãŠã®æ»æãçµãã£ãã¿ã€ãã³ã°ã§ãæ£åžžãã«é·ç§»ãããããç¶æ³ææ¡ãšãã芳ç¹ã§ã¯ååã ãšèããŠããŸããïŒ æçµçã«ã¯ã以äžã®ãã㪠Terraform ã³ãŒããå®è£
ããããšã§å®çŸããŸããã resource "aws_cloudwatch_metric_alarm" "resource_name" { alarm_name = "alarm_name" comparison_operator = "GreaterThanOrEqualToThreshold" evaluation_periods = 1 metric_name = "BlockedRequests" namespace = "AWS/WAFV2" period = 300 statistic = "Sum" threshold = 1 alarm_description = "éå°ãªãªã¯ãšã¹ãã®IPã¢ãã¬ã¹ããããã¯ããŸãã" alarm_actions = [ var.sns_topic_arn, ] ok_actions = [ var.sns_topic_arn, ] treat_missing_data = "notBreaching" # 0 ä»¶ã®ç¶æ
ããæ£åžžãã§ãããšèªèãããããã®èšå® dimensions = { WebACL = var.web_acl_name, Rule = var.rule_name, Region = var.region, } } WAF å°å
¥æã®èæ
®ç¹ WAF ãå°å
¥ããéãæ»æãé²ãããã«å€§éãªã¯ãšã¹ãããããã¯ããããªããŸããã ãããªããããã¯ããã«ãŒã«ãèšå®ããŠããŸããšããããã¯ããŠã¯ãããªããªã¯ãšã¹ããŸã§ãããã¯ãããŠããŸãå¯èœæ§ããããŸãã ãã®ããããŸãã¯ã«ãŠã³ãã®ã«ãŒã«ãèšå®ããŠããæ§åãèŠãŠãããããã¯ã®ã«ãŒã«ã«å€æŽããŸããã ãŸããå®éã«ãªãœãŒã¹ãäœæããåã«ãéçºç°å¢ã§åäœç¢ºèªãè¡ããŸããã äœæããäºå®ã®ãªãœãŒã¹ãšåãæ§æã®ãã®ãéçºç°å¢ã«äœæãã ç°¡åãªã¹ã¯ãªããã§å€§éãªã¯ãšã¹ããçºçããç¶æ³ãåçŸããããšã§ãWAF ãæå³éãã«åäœãããã確èªããŸããã ãããã« ä»åã®èšäºã§ã¯ããã¢ããã«ããã WAF å°å
¥ã®èæ¯ããã調æ»ã»æ€èšå
容ãå®éã®éçšãŸã§ã玹ä»ããŸããã ä»åã®å¯Ÿå¿ã®ãããã§ãå®å¿æãé«ããããšã¯ã§ããããšæããŸãã WAF ãå°å
¥ããã ãã§ã»ãã¥ãªãã£ãå®ç§ã«ãªãããã§ã¯ãããŸãããã ä»åŸããµãŒãã¹ã®å®å
šæ§åäžã«åããŠãã¢ããªã±ãŒã·ã§ã³ã»ã€ã³ãã©äž¡é¢ããã»ãã¥ãªãã£å¯Ÿçãããããã«ããªãããã«ããŠãããããšæããŸãã ä»åã®èšäºããå°ãã§ãçããã®ã圹ã«ç«ãŠãã°å¹žãã§ãã æåŸãŸã§èªãã§ããã ããããããšãããããŸããã Configuring how CloudWatch alarms treat missing data ↩