ã¯ããã« åæïŒãšãŒãžã§ã³ãã®æ§æ 課é¡ïŒç»é¢ãé¢ãããšåçãæ¶ãã èšèšæ¹éïŒå®è¡ã®äœæãšè³Œèªãåé¢ãã DB ã¹ããŒãïŒæ®ãå±¥æŽãšå®è¡äžã®ç¶æ
ãåãã ä¿ååäœã¯ãAG-UI ã® Message 1 ä»¶ = 1 è¡ã DynamoDB ã§ã¯ãªã Aurora MySQL ãéžãã çç± äŒè©±å±¥æŽã¯ãµãŒããŒãçµã¿ç«ãŠã æžã蟌ã¿èšèšïŒã€ãã³ãã¯ä¿åãããçæéäžã®åçããäžæžããã ååæµïŒäŒè©±å
šäœã®ã¹ãããã·ã§ããã§è¿œãã€ã åæå®è¡å¶åŸ¡ïŒå®è¡äžããã¯ã NULL å¯ã®ãŠããŒã¯åã§äœã ããã¯ã®è§£æŸæŒãã«åãã 忢ïŒåæãšãã£ã³ã»ã«ãåºå¥ãã Redis ã¯èŠãã ãŸãšã ã¯ããã« éçºæ¬éš éçº1éšã® ãããŸã ã§ãã ç§ãã¡ã®ããŒã ã§ã¯ãWeb ã¢ããªã®æ°æ©èœãšããŠããã£ãã圢åŒã§ããŒã¿ãåæã§ãã AI ãšãŒãžã§ã³ããéçºäžã§ããéçºãé²ããäžã§ããåçã®çæäžã«ç»é¢ãé¢ãããšããã®åçãåãåããªããªããäŒè©±ãæ®ããªãããšãã課é¡ã«åãåãããšã«ãªããŸããã æ¬èšäºã§ã¯ããã®èª²é¡ã解決ããããã«è¡ã£ããäŒè©±å±¥æŽã®æ°žç¶åããšãããã¯ã°ã©ãŠã³ãå®è¡ãã®èšèšãšå®è£
ã玹ä»ããŸããDB ã¹ããŒãã»å®è£
ã³ãŒãã»æ€èšããŠæšãŠãæ¡ãŸã§å«ããŠæžããŸãã åæïŒãšãŒãžã§ã³ãã®æ§æ ãã®ãšãŒãžã§ã³ãã¯æ¬¡ã®æ§æã§åããŠããŸãã ãã©ãŠã¶ïŒãã£ãã UIïŒ â AG-UI ã€ãã³ãïŒSSEïŒ âŒ Next.jsïŒAPI Route ââ ãã©ãŠã¶ãš AgentCore ã®äžç¶åœ¹ïŒ â InvokeAgentRuntimeïŒSSEïŒ âŒ Amazon Bedrock AgentCore RuntimeïŒStrands Agents 補ãšãŒãžã§ã³ãïŒ â MCP ⌠MCP ãµãŒããŒïŒèªç€ŸããŒã¿ã®æ€çŽ¢ã»éèšããŒã«çŸ€ïŒ Amazon Bedrock AgentCore : AI ãšãŒãžã§ã³ãã®å®è¡åºç€ãšãªã AWS ã®ãµãŒãã¹ã§ããã»ãã·ã§ã³ããšã« microVM åäœã§å®è¡ç°å¢ãåé¢ãããŸãã Strands Agents : AWS ãå
¬éããŠãããªãŒãã³ãœãŒã¹ã® AI ãšãŒãžã§ã³ã SDK ã§ãã AG-UI : ãšãŒãžã§ã³ããšããã³ããšã³ãéã®ã€ãã³ãã¹ããªãŒãã³ã°ã®ãããã³ã«ã§ãã RUN_STARTED ã» TEXT_MESSAGE_CONTENT ã» TOOL_CALL_* ã» RUN_FINISHED ãªã©ã®ã€ãã³ãåãå®ããŠããŸããè»¢éæ¹æ³ã¯ SSE ã«éå®ãããŸãããããã®ã¢ããªã§ã¯ SSE ã§æµããŠããŸãã ãŠãŒã¶ãŒã質åãéããšããšãŒãžã§ã³ãã MCP ããŒã«ã§ããŒã¿ãååŸã»åæããåçãã¹ããªãŒãã³ã°ã§è¿ããŸããããŒã«ãç¹°ãè¿ãåŒã¶ããã1 åã®åçã«æ°åç§ãããããšããããŸãã 課é¡ïŒç»é¢ãé¢ãããšåçãæ¶ãã AI ãã£ããã§åºã䜿ãããã®ã¯ãPOST + ã¹ããªãŒãã³ã°å¿çãã®æ§æã§ãããã©ãŠã¶ã質åã POST ãããµãŒããŒãçæã€ãã³ããæµããç»é¢ã«é次衚瀺ããŸããç»é¢é¢è±ãæ³å®ããªããã°ãããã§ååã«æ©èœããŸããç§ãã¡ã®åæå®è£
ããã®æ§æã§ããã ç§ãã¡ã®å Žåã¯åçã«æ°åç§ãããããããçæäžã«ç»é¢ãé¢ããŠãå®è¡ã¯å®èµ°ããŠã»ããããšããèŠä»¶ãå ãããŸããããã®èŠä»¶ãæºããããšãããšã3 ç®æãåé¡ã«ãªããŸãã æ¹ä¿®åã®æ§é ãç»é¢é·ç§»ããç¬éã«ã以éã®ã€ãã³ããåãåãææ®µããªããªã 1 ã€ç®ã¯ããã³ããšã³ãã§ãã ãã®æ§æã§ã¯ããã£ããç»é¢ã® hook ã unmount æã«å®è¡ãäžæïŒ abortRun() ïŒããäœãã«ãªããã¡ã§ããç»é¢é·ç§»ããã®ãŸãŸå®è¡äžæã«ãªããŸãã // ãã£ããç»é¢ã® hookïŒunmount æã«å®è¡ãäžæããäœãïŒ useEffect( () => () => { stopRequestedRef. current = true ; agentRef. current ?.abortRun(); } , [] , ); 2 ã€ç®ã¯äžç¶åœ¹ã® API Route ã§ãã ãã©ãŠã¶ãš AgentCore ã®éã§ SSE ãäžç¶ãã Next.js ã® API Route ã¯ãã¯ã©ã€ã¢ã³ãã®åæãäžæµã® AgentCore ãžã®èªã¿åããã£ã³ã»ã«ãšããŠäŒæããŸãã ReadableStream ã® cancel() ã¯ãã¯ã©ã€ã¢ã³ããããèªãŸãªãããšãã«åŒã°ããã³ãŒã«ããã¯ã§ãããã§äžæµã®èªã¿åããæ¢ãããšãåæãšãã£ã³ã»ã«ã®åºå¥ããªããªããŸãã // äžç¶åŠçïŒã¯ã©ã€ã¢ã³ããåãããšäžæµã®èªã¿åããæ¢ãŸãäœãïŒ const readable = new ReadableStream( { async start ( controller ) { // äžæµïŒAgentCoreïŒã® SSE ãèªã¿ããã®ãŸãŸã¯ã©ã€ã¢ã³ããžäžç¶ãã } , cancel () { reader.cancel(); } , } ); 3 ã€ç®ã¯ä¿åå
ã§ãã ã€ãã³ãã¯äžç¶ãããã ãã§ãã©ãã«ãä¿åãããŸããã仮㫠1 ã€ç®ãš 2 ã€ç®ãçŽããŠå®è¡ãå®èµ°ããããã«ããŠããæ»ã£ãŠããç»é¢ã«è¡šç€ºããããŒã¿ããããŸããã ãå®è¡ç¶æ
ã React ã®ã°ããŒãã«ã¹ãã¢ã«æãŠã°ãç»é¢é·ç§»ã«èããããã®ã§ã¯ããšããæ¡ãæ€èšããŸãããããããã®ã¢ããªã§ã¯ããã£ããç»é¢ããä»ã®ç»é¢ãžã®é·ç§»ã window.location.href ã«ããããŒãžå
šäœã®åèªã¿èŸŒã¿ã§å®è£
ãããŠããŸããåèªã¿èŸŒã¿åŸã®ããŒãžã¯ JavaScript ã®å®è¡ç°å¢ããšæ°ããäœããããããReact ã® state ãã°ããŒãã«ã¹ãã¢ã«å
¥ããå€ã¯åŒãç¶ãããŸããã èšèšæ¹éïŒå®è¡ã®äœæãšè³Œèªãåé¢ãã 倧ããå€ããã®ã¯æ¬¡ã® 3 ã€ã§ãã äœæãšè³Œèªã®åé¢ : POST /runs ã¯å®è¡ãéå§ã㊠202 { runId } ãå³åº§ã«è¿ããŸãã衚瀺㯠GET /runs/{runId}/events ã® SSE ã§åãåããŸãããã®ãSSE ãåä¿¡ãç¶ããããšãããæ¬èšäºã§ã¯ã賌èªããšåŒã³ãŸãã賌èªã¯ãã€åããŠããããäœåºŠã§ãåéã§ããŸãã å®è¡ã¯ãŒã«ãŒã®ç¬ç« : AgentCore ã® SSE ãæåŸãŸã§èªã¿åã£ãŠèšé²ããåŠçïŒå®è¡ã¯ãŒã«ãŒïŒããHTTP ã¬ã¹ãã³ã¹ããç¬ç«ããéåæã¿ã¹ã¯ã«ããŸããããã©ãŠã¶ãåæããŠãå®è¡ã¯å®èµ°ããŸãã äºå±€ã®ä¿å : å®è¡äžã¯ãçæéäžã®åçãã DB ã«äžæžãä¿åãç¶ããå®äºããã宿ããã¡ãã»ãŒãžã DB ã®å±¥æŽããŒãã«ã«ä¿åããŸããããŒãã«æ§æã¯æ¬¡ã®ç¯ã§èª¬æããŸãã ãªããå®è¡ã¯ãŒã«ãŒã¯ Next.js ãšåãããã»ã¹å
ã§åãããŠããããããªã¯ãšã¹ãããšã«å®è¡ç°å¢ãçµäºãããµãŒããŒã¬ã¹ç°å¢ã§ã¯ãã®åœ¢ã¯åããŸãããçŸåšã¯æ€èšŒæ®µéã®ãããã®æ§æã«ããŠããŸãããNext.js ã®ãããã€ã«èµ°è¡äžã®å®è¡ãå·»ã蟌ãŸããªãããã«ãããããæ¬æ¥ã¯å®è¡ã¯ãŒã«ãŒãç¬ç«ããããã»ã¹ã«åãåºãæ¹ãæãŸãããšèããŠããŸããçŸç¶ãããã»ã¹ããããã€ãªã©ã§æ¢ãŸãå Žåã®åŸå§æ«ã¯ãåæå®è¡å¶åŸ¡ã®ç¯ã§èª¬æããååã®ä»çµã¿ãæ
ããŸãã æ¹ä¿®åŸã®æ§é ãå®è¡ã¯æ¥ç¶ãšç¡é¢ä¿ã«å®èµ°ãã賌èªã¯äœåºŠã§ãåå
¥å Žã§ãã ãã©ãŠã¶ãšãµãŒããŒã®éã® API ã¯æ¬¡ã® 5 æ¬ã§ãã API åœ¹å² POST /runs å®è¡ãäœæã㊠202 { runId, conversationId } ãå³è¿ã GET /runs/{id}/events SSE 賌èªãåæã»åå
¥å Žãèªç± POST /runs/{id}/cancel æç€ºçãªãã£ã³ã»ã« GET /conversations äŒè©±äžèЧïŒå±¥æŽãµã€ãããŒçšïŒ GET /conversations/{id} äŒè©±ã®å
šã¡ãã»ãŒãž + å®è¡äžã® runïŒããã°ïŒ æåŸã® API ããã€ã³ãã§ãããªããŒããå¥ã¿ãã§äŒè©±ãéããçŽåŸãã¯ã©ã€ã¢ã³ãã¯äŒè©± ID ããç¥ãããå®è¡äžã® run ããããã©ãããåãããŸãããããã§ GET /conversations/{id} ã¯ãäŒè©±ã®ã¡ãã»ãŒãžã«å ããŠãå®è¡äžã® run ã® IDããè¿ããŸããã¯ã©ã€ã¢ã³ãã¯ãã® ID ã§ GET /runs/{id}/events ã賌èªããçæéäžãã衚瀺ãåéããŸãã DB ã¹ããŒãïŒæ®ãå±¥æŽãšå®è¡äžã®ç¶æ
ãåãã ãã®ã¢ããªã§ã¯ä»¥åãããæ¬äœæ©èœã®ããŒã¿ã Aurora MySQL 8.0 + Prisma ã§ç®¡çããŠããŸãããšãŒãžã§ã³ãã®å±¥æŽãåã DB ã«ã3 ã€ã®ããŒãã«ã§æã€ããšã«ããŸããããã£ãšæ®ããå±¥æŽããšãå®è¡äžã ã䜿ããå®è¡ç¶æ
ãã§ããŒãã«ãåããŠããŸãã åºå ããŒãã« åœ¹å² è¡ã®æ±ã å±¥æŽ conversations äŒè©±ã¹ã¬ãã 1 ä»¶ã®ã¡ã¿æ
å ± ãã£ãšæ®ã å±¥æŽ conversation_messages ã¡ãã»ãŒãž 1 ä»¶ = 1 è¡ã宿ããçºè©±ãä¿å ãã£ãšæ®ã å®è¡ç¶æ
runs å®è¡ 1 åã®ç¶æ
+ çæéäžã®åç + ãã㯠è¡ã¯å®è¡ 1 åããšã«å¢ããçµäºåŸãèšé²ãšããŠæ®ããçæéäžã®åçãããã¯ã¯å®è¡äžã ã䜿ã ER å³ Prisma ã¹ããŒãã¯æ¬¡ã®éãã§ããå®éã«æ¡çšãããã®ãããã¿ã€ã ã¹ã¿ã³ãåã»ãªã¬ãŒã·ã§ã³å®çŸ©ã»enum å®çŸ©ïŒRunStatus / MessageStatusïŒãçããŠããŸãã model Conversation { id String @id @default(cuid()) companyId Int @map("company_id") userId String @map("user_id") threadId String @map("thread_id") @db.Char(36) title String @db.VarChar(255) deletedAt DateTime? @map("deleted_at") @@unique([companyId, userId, threadId]) @@map("conversations") } model ConversationMessage { id String @id @default(cuid()) conversationId String @map("conversation_id") runId String? @map("run_id") sequence Int role String @db.VarChar(16) parts Json status MessageStatus @default(complete) @@unique([conversationId, sequence]) @@map("conversation_messages") } model Run { id String @id @default(cuid()) conversationId String @map("conversation_id") clientTurnId String @map("client_turn_id") @db.VarChar(64) status RunStatus @default(queued) lockKey String? @unique @map("lock_key") ownerInstanceId String? @map("owner_instance_id") @db.VarChar(64) errorCode String? @map("error_code") @db.VarChar(64) partialState Json? @map("partial_state") heartbeatAt DateTime @default(now()) @map("heartbeat_at") @@unique([conversationId, clientTurnId]) @@index([status, heartbeatAt]) @@map("runs") } lockKey ã® UNIQUEã clientTurnId ã®è€åãŠããŒã¯ã [status, heartbeatAt] ã®ã€ã³ããã¯ã¹ãããããäœã®ããã«ãããã¯ãåŸã®ç¯ã§é ã«èª¬æããŸãã ãŸããæ¬èšäºã«ã¯ 4 çš®é¡ã® ID ãç»å ŽããŸããããã§æŽçããŠãããŸãã ID äœãæãã conversationId DB äžã®äŒè©±ãAPI ã§äŒè©±ãæããšãã«äœ¿ã threadId AG-UI äžã®äŒè©± IDãDB äžã®äŒè©±ïŒ conversationId ïŒãš 1 察 1 ã§å¯Ÿå¿ runId 質å 1 åã¶ãã®å®è¡ runtimeSessionId AgentCore ã®å®è¡ç°å¢ãæãã IDã t{companyId}-u{userId}-{threadId} ã®åœ¢åŒã§ãäŒè©±ããšã«åºå® ä¿ååäœã¯ãAG-UI ã® Message 1 ä»¶ = 1 è¡ã conversation_messages ã¯è¿œèšå°çšã§ãAG-UI ã® Message ããã®ãŸãŸ parts ïŒJSONïŒã«æ ŒçŽããŸããããã¹ãã ãã®ã¿ãŒã³ã¯ user / assistant ã® 2 è¡ãããŒã«ã䜿ãã¿ãŒã³ã¯ assistantïŒããŒã«åŒã³åºãïŒãš toolïŒçµæïŒã®è¡ãæãŸã£ãŠ 4 è¡ä»¥äžã«ãªããŸãã 1 äŒè©±ã®ã¡ãã»ãŒãžè¡ã®äŸãããŒã«ã䜿ãã¿ãŒã³ã¯ userã»assistantïŒããŒã«åŒã³åºãïŒã»toolã»assistant ã® 4 è¡ã䜿ããªãã¿ãŒã³ã¯ 2 è¡ã«ãªã ãã®ä¿ååäœãéžãã çç±ã¯ãããã³ãã®è¡šç€ºããžãã¯ã®äœãã«ãããŸããã©ã€ã衚瀺ã¯ãAG-UI ã® Message é
åãåãåããã¿ãŒã³ã®åºåããããŒã«ã®å®è¡ã¹ããã衚瀺ãçµã¿ç«ãŠãçŽç²é¢æ°ããšããŠèªåã§å®è£
ããŠããŸããä¿åãã Message åããã®ãŸãŸãã®é¢æ°ã«æž¡ãã°ãç»é¢ãé¢ããªãã£ãå Žåãšåäžã®è¡šç€ºãåçŸãããŸããä¿åæã«è¡šç€ºçšã®åœ¢ãžå å·¥ããŠããŸããšãåã衚瀺ãåçŸã§ããªããªããŸãã DynamoDB ã§ã¯ãªã Aurora MySQL ãéžãã çç± äŒè©±å±¥æŽã®ã¢ã¯ã»ã¹ãã¿ãŒã³ïŒäŒè©± ID + é£çªã§é ã«å
šä»¶ååŸã远èšå°çšãJSON äž»äœïŒã¯ DynamoDB ã®åŸæé åã§ãå®éã«ç§»è¡æ¡ãæ€èšããŸãããããã§ã Aurora MySQL äžæ¬ã«ããŠããŸãã ãŸãããã©ã³ã¶ã¯ã·ã§ã³èŠä»¶ãæ§æã®éžæè¢ãçµããŸãã質åã®å仿ã«ã¯ãäŒè©± + user ã¡ãã»ãŒãž + å®è¡ïŒããã¯ïŒã® INSERTãããå®äºæã«ã¯ãassistant ã¡ãã»ãŒãžã® INSERT + å®è¡ã®å®äº + ããã¯è§£æŸãããããããåäžãã©ã³ã¶ã¯ã·ã§ã³ã§è¡ãå¿
èŠããããŸãããå±¥æŽã¯ DynamoDBãå®è¡ç¶æ
㯠Auroraãã®ããã« 2 ã€ã®ã¹ãã¢ã«åãããšããã®ååæ§ãä¿èšŒã§ããŸãããååæ§ãç¡ããšãããšãã°æ¬¡ã®ãããªå£ãæ¹ãããŸãã åçã¯æ®ã£ãã®ã«æ¬¡ã®è³ªåãã§ããªã : å®äºåŠçã®ãåçãä¿åããšãããã¯è§£æŸãã®éã§ããã»ã¹ãèœã¡ããšãç»é¢ã«ã¯åçãåºãŠããã®ã« DB ã¯ããã¯ãæ¡ã£ããŸãŸã«ãªããæ¬¡ã®è³ªåããå®è¡äžã§ãããšæåŠããç¶ããŸãã çãã®ãªã質åãå±¥æŽã«æ®ã : éä¿¡ã®äºåºŠæŒãã§ 2 æ¬ç®ãã質åãä¿å â ããã¯ã§åŒŸããããã®é ã«é²ããšã誰ãåçããªã質åã ããå±¥æŽã«æ®ããŸãã1 ãã©ã³ã¶ã¯ã·ã§ã³ãªãããã¯ååŸã®å€±æãšåæã«è³ªåã®ä¿åãåãæ¶ããããšã©ãŒå¿çã ããè¿ããŸãã ãããã£ãŠéžæè¢ã¯ãå
šéš Auroraãããå
šéš DynamoDBãã«çµãããŸããåŸè
ãæè¡çã«ã¯æç«ããŸãïŒDynamoDB ã§ã TransactWriteItems ã§è€æ°ã®é
ç®ããŸãšããŠååçã«æžããŸãïŒã ããã§ã Aurora ã«ããã®ã¯ãæ¢åã®éçšãšã®äžè²«æ§ã®ããã§ãããã®ã¢ããªã®ä»ã®ããŒã¿ã¯ãã¹ãŠ Aurora + Prisma ã§ç®¡çããŠããŠããã€ã°ã¬ãŒã·ã§ã³ã®æé ãã¬ãã¥ãŒã®èгç¹ãšãã£ãããŒã ã®éçšãããã§æã£ãŠããŸããããŒã¿ã¹ãã¢ã 2 ã€ã«ãããšããã®éçšã 2 系統ã«ãªããŸããèŠæš¡ã®é¢ã§ããDB ãžã®æžã蟌ã¿ã¯ããŒã¯ã§ãæ¯ç§æ°ååã®èŠç©ããã§ãAurora ã§ååã«åããããŸããDynamoDB ã®ã¹ã±ãŒã«æ§èœãå¿
èŠã«ãªãæ°Žæºã§ã¯ãããŸããã äŒè©±å±¥æŽã¯ãµãŒããŒãçµã¿ç«ãŠã ãšãŒãžã§ã³ãã¯æ¯åã®åŒã³åºãã§äŒè©±ã®å
šå±¥æŽãåãåããç¶æ
ããŒãããçµã¿ç«ãŠçŽãäœãã«ããŠããŸãããã®å
šå±¥æŽã誰ãçšæãããã«ã¯ 2 ã€ã®åœ¢ããããŸããã¯ã©ã€ã¢ã³ããæå
ã® Message é
åãæ¯åéããã ãµãŒããŒã DB ããçµã¿ç«ãŠã ãã§ããç§ãã¡ã¯åŸè
ã«ããŸãããã¯ã©ã€ã¢ã³ããéãã®ã¯æ°ããã¡ãã»ãŒãž 1 ä»¶ã ãã§ãã åè
ãé¿ããçç±ã¯ãããã¯ã°ã©ãŠã³ãå®è¡ãšçžæ§ãæªãããã§ããå®è¡ãæŸçœ®ããŠå¥ã®ã¿ãã§å®èµ°ããããšãå
ã®ã¿ããæã£ãŠããå±¥æŽã¯å€ããŸãŸã«ãªããŸãããã®å€ãã¿ãããæ¬¡ã®è³ªåãå±¥æŽããšéããšãå®èµ°ããã¯ãã®åçãã¢ãã«ãžã®å
¥åããæãèœã¡ãäŒè©±ã®ã€ãã€ãŸãåããªããªããŸããåŸè¿°ããããã¯ã¯å®è¡äžããå¹ããªãããããã®äºæ
ã¯é²ããŸãããææ°ã®äŒè©±ãåžžã«æã£ãŠããã®ã¯ DB ã ãã§ãã ãªããAgentCore åŽã«äŒè©±ã®ç¶æ
ãæãããæ¡ã 2 ã€æ€èšããèŠéããŸããã å®è¡ç°å¢ïŒmicroVMïŒã®ã¡ã¢ãªã«æã€ : ã»ãã·ã§ã³ ID ã¯äŒè©±ããšã«åºå®ãªã®ã§ãåãäŒè©±ã®åŒã³åºãã¯åãå®è¡ç°å¢ã«å±ããã¡ã¢ãªã«ç¶æ
ãæ®ãããšèªäœã¯ã§ããŸãããã ããã®ç°å¢ã¯ç¡æäœ 15 åïŒããã©ã«ãïŒãªã©ã§çµäºããã¡ã¢ãªããšæ¶ããŸããæéã空ããŠç¶ãäŒè©±ã®çœ®ãå Žã«ã¯ã§ããŸãã Memory ãµãŒãã¹ã«æã€ : AgentCore ã«ã¯äŒè©±ãä¿åãã Memory ãšãããµãŒãã¹ããããŸãããã ãå±¥æŽã¯ã©ã®ã¿ã¡è¡šç€ºã®ããã«èªåã® DB ãžä¿åããã®ã§ãè¶³ããšåã圹å²ã®ä¿åå
ã 2 ã€ã«ãªããŸã POST /runs ã®ããã£ã¯ { conversationId, message, clientTurnId } ã ãã§ããã¢ãã«ãžæž¡ãå±¥æŽã¯ãå®è¡ã¯ãŒã«ãŒã Aurora ããçµã¿ç«ãŠãŸãã // å®è¡ã¯ãŒã«ãŒã®äžéšïŒDB ããäŒè©±å±¥æŽãèªã¿åºããã¢ãã«å
¥åçšã«æŽãã export async function buildModelMessages ( conversationId : string ): Promise < ModelMessagesResult > { const rows = await prisma.conversationMessage.findMany( { where : { conversationId , status : "complete" } , orderBy : { sequence : "asc" } , select : { parts : true } , } ); return normalizeHistory(rows); } // å®è¡ã¯ãŒã«ãŒã®äžéšïŒçµã¿ç«ãŠãå±¥æŽããšãŒãžã§ã³ãã«æž¡ããŠçæãéå§ãã const history = await buildModelMessages(claimed.conversationId); const { companyId , userId , threadId } = claimed.conversation; const agent = new AgentCoreAgent( { threadId , initialMessages : history .messages, agentArn , runtimeUserId : `c ${ companyId } :u ${ userId } ` , runtimeSessionId : `t ${ companyId } -u ${ userId } - ${ threadId } ` , } ); ãããããšãäŒè©±ã®å
容ã¯ãµãŒããŒïŒDBïŒã ããæã€æ§é ã«ãªããŸããAgentCore ã® microVM ãã¿ã€ã ã¢ãŠãã§çµäºããŠããã¯ã©ã€ã¢ã³ãããªããŒãã§ç¶æ
ã倱ã£ãŠããäŒè©±ã¯ Aurora ããåæ§æã§ããŸãã æžã蟌ã¿èšèšïŒã€ãã³ãã¯ä¿åãããçæéäžã®åçããäžæžããã 1 åã®åçã§ AG-UI ã€ãã³ãã¯æ°åãæ°çŸåæµããŸããæ¬æã®æçïŒãã«ã¿ïŒ1 〠1 ã€ãããŒã«åŒã³åºããããããã€ãã³ãã«ãªããããåçãé·ãã»ã©å¢ããŸããããã 1 è¡ã〠INSERT ãããšã1 åçããšã«å€§éã®è¡ãæ°žä¹
ã«ç©ã¿äžãããŸããæ¡çšããã®ã¯æ¬¡ã®åœ¢ã§ãã æç¹ DB æäœ å
容 質åéä¿¡ INSERT conversations ã«äŒè©±ïŒæ°èŠäŒè©±ã®ãšãã®ã¿ïŒã conversation_messages ã«è³ªåã runs ã«å®è¡ã¬ã³ãŒãïŒããã¯ååŸãå
ŒããïŒã®æå€§ 3 è¡ çæäž runs.partial_state ãäžæžã UPDATE AG-UI ã®ã€ãã³ãã§ã¯æ¬æã现åãïŒãã«ã¿ïŒã§å±ããå®è¡ã¯ãŒã«ãŒã¯ãããã€ãªãåãããããã®æç¹ã®ã¡ãã»ãŒãžé
åããä¿æããŠããããããæ°ç§ããšã«åã 1 è¡ãžäžæžãä¿åãè¡ã¯å¢ããªã å®äº conversation_messages ã« INSERT ãã®ã¿ãŒã³ã§çãŸããã¡ãã»ãŒãžïŒåçãããŒã«ã䜿ã£ãå Žåã¯ãã®åŒã³åºããšçµæãïŒãä¿åã runs.partial_state ã空ã«ããããã¯ãè§£æŸ è³ªåéä¿¡æã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ä»¥äžã®ããã«ãªã£ãŠããŸããããã¯ïŒ lockKey ïŒã®ååŸãšè³ªåã®ä¿åããåæã«æç«ãããåæã«å€±æãããã®ã©ã¡ããã«ãªããŸãã // API Route ã®äžéšïŒè³ªååä»æã®æžã蟌㿠return prisma.$transaction( async ( tx ) => { const conversationId = existingId ?? ( await tx.conversation.create( { /* çç¥ */ } )).id; // ããã¯ååŸã«å€±æããããäžã§ä¿åãã質åããšåãæ¶ãããïŒåäžãã©ã³ã¶ã¯ã·ã§ã³ã®ããïŒ const run = await tx.run.create( { data : { conversationId , clientTurnId , lockKey : conversationId } , select : { id : true } , } ); // aggregateïŒéèšã¯ãšãªïŒã§äŒè©±å
ã®æå€§ sequence ãåããæ¬¡ã®é£çªãæ¯ã const highest = await tx.conversationMessage.aggregate( { where : { conversationId } , _max : { sequence : true } , } ); await tx.conversationMessage.create( { data : { conversationId , runId : run. id , sequence : (highest._max.sequence ?? 0 ) + 1 , role : "user" , parts : { id : randomUUID(), role : "user" , content : message } , } , select : { id : true } , } ); return { runId : run. id , conversationId } ; } ); çæäžã® partial_state 㯠3 ç§ééã§éåŒããŠæžããŸããéåŒãã«å ããŠãåã® UPDATE ãå®äºãããŸã§ã次㮠UPDATE ãçºè¡ããªãããšããå¶åŸ¡ãå
¥ããŠããŸããUPDATE ãçºè¡ããé ãš DB ã«åæ ãããé ã¯äžèŽãããšã¯éããªããããå€ãå
容㮠UPDATE ãæ°ããå
容ã®åŸã«é©çšããããšãä¿åæžã¿ã®ãçæéäžã®åçããå·»ãæ»ã£ãŠããŸãããã§ãã // å®è¡ã¯ãŒã«ãŒã®äžéšïŒçæéäžã®åçãæ°ç§ããšã« DB ãžäžæžãä¿åãã const PARTIAL_STATE_INTERVAL_MS = 3_000 ; return { schedule() { // åã®æžã蟌ã¿ãå®äºãããŸã§æ¬¡ãã¹ã±ãžã¥ãŒã«ããªãïŒå€ãå
容ãžã®å·»ãæ»ããé²ãïŒ if (timer || writing || truncated) return ; timer = setTimeout (() => { timer = null ; writing = true ; void writePartialState(runId, ownerInstanceId, produced()) . then (( state ) => { truncated = state.truncated; } ) . catch (( error : unknown ) => console .error( "partial_state ã®æŽæ°ã«å€±æããŸãã" , { runId , error } ), ) . finally (() => { writing = false ; } ); } , PARTIAL_STATE_INTERVAL_MS); } , } ; æ°ç§ããã« UPDATE ãçºè¡ãç¶ã㊠DB ã®è² è·ã¯å€§äžå€«ãªã®ãããšããç¹ã¯æ€èšããŸãããçµè«ãšããŠã¯ãåæã«èµ°ãçæãå€ããŠãæ°åæ¬ãšããèŠæš¡ã§ã¯åé¡ã«ãªããŸãããæŽæ°ã¯åå®è¡ãèªåã® 1 è¡ã ããäž»ããŒæå®ã§è¡ããå®è¡éã®ããã¯ç«¶åã¯ãããŸãããããã«ãæ¥ç¶äžã®ãŠãŒã¶ãŒã®ç»é¢ãžã¯å®è¡ã¯ãŒã«ãŒãã¡ã¢ãªäžã®ã€ãã³ããçŽæ¥æµãããã partial_state ã®çšéã¯åŸè¿°ããååæµã ãã§ããæ¯ç§æžãå¿
èŠããã€ãã³ãã 1 åãã€æžãå¿
èŠããããŸããã å®äºæã¯ãåçã®ç¢ºå®ä¿åããå®è¡ã¹ããŒã¿ã¹ã®å®äºãžã®æŽæ°ããããã¯è§£æŸããçæéäžã®åçïŒ partial_state ïŒã®åé€ãã 1 ãã©ã³ã¶ã¯ã·ã§ã³ã§è¡ããŸãã // å®è¡ã¯ãŒã«ãŒã®äžéšïŒå®äºæã®æžã蟌ã¿ãlock_key ãå€ãæãããšãã®äŒè©±ãæ°žä¹
ã« 409 ã«ãªã return prisma.$transaction( async ( tx ) => { const claimed = await tx.run.updateMany( { where : terminableWhere(runId, ownerInstanceId), data : { status , errorCode , finishedAt : new Date (), lockKey : null , partialState : Prisma.DbNull, } , } ); // å¥ã®çµè·¯ïŒãã£ã³ã»ã«ããåŸè¿°ããç°åžžçµäºæã®åååŠçïŒãå
ã«ãã®å®è¡ã // çµããããŠããããçæç©ã¯ä¿åããªã if (claimed. count === 0 ) return false ; await tx.conversationMessage.createMany( { data : messages. map (( message , index ) => ( { conversationId : targetId, runId , sequence : base + index + 1 , role : message.role, parts : message as Prisma.InputJsonValue , status : messageStatusAt( status , message. id , openMessageIds), } )), } ); return true ; } ); ã¡ãã»ãŒãžã® status ã¯éåžž complete ã§ä¿åããŸãããã£ã³ã»ã«ããšã©ãŒã§å®è¡ãæ£åžžã«çµãããªãã£ãå Žåã¯ããããŸã§ã«çæã§ããŠããåã partialïŒéšåçãã®æå³ïŒãšããŠä¿åããç»é¢ã«æ®ããããã«ããŠããŸãã ååæµïŒäŒè©±å
šäœã®ã¹ãããã·ã§ããã§è¿œãã€ã å®è¡äžã®äŒè©±ã«è³Œèªè
ãå
¥ã£ãŠãããšããµãŒããŒã¯ãŸã RUN_STARTED ïŒãå®è¡ãé²è¡äžã§ããã®åå³ïŒãš MESSAGES_SNAPSHOT ãéããŸããã©ã¡ããäžæµããå±ããã€ãã³ãã®äžç¶ã§ã¯ãªãããã®è³Œèªã®ããã«ãµãŒããŒãæ°ããäœã£ãŠéããã®ã§ãã MESSAGES_SNAPSHOT ãåãåã£ãã¯ã©ã€ã¢ã³ãã¯ãæå
ã®ã¡ãã»ãŒãžäžèŠ§ãæšãŠãŠãã¹ãããã·ã§ããã®å
容ã§äžžããšçœ®ãæããŸãããã®ãããã¹ãããã·ã§ããã«çæéäžã® 1 ä»¶ã ããå
¥ãããšãéå»ã®ã¡ãã»ãŒãžãç»é¢ãããã¹ãŠæ¶ããŠããŸããŸããå¿
ãäŒè©±ã®å
šã¡ãã»ãŒãžãå
¥ããŠéããŸãã ãã®åŸã®é
信㯠2 ã€ã®ã¢ãŒãã«åãããŸããåããç®ã¯ã賌èªããã€å§ãŸã£ãããã§ãã ã¢ãŒã ãã€äœ¿ãããã é
ä¿¡å
容 live 質åã®éä¿¡çŽåŸãã賌èªããŠããå ŽåïŒçæã€ãã³ãããŸã 1 ä»¶ãæµããŠããªããã¡ã«è³Œèªãå§ãŸã£ããšãïŒ å®è¡ã¯ãŒã«ãŒãåãåãçæã€ãã³ãïŒ TEXT_MESSAGE_CONTENT ãªã©ïŒããã¡ã¢ãªãããã®ãŸãŸé次äžç¶ poll ãã以å€ãã¹ãŠïŒãªããŒãã»å¥ã¿ãã»é¢è±ããŠæ»ã£ãŠããå ŽåïŒ 1 ç§ééã§ DB ãèªã¿ãç¢ºå®æžã¿å±¥æŽãš partial_state ã®çæéäžåçãããŒãžããäŒè©±å
šäœã® MESSAGES_SNAPSHOT ããå
容ãå€ãã£ããšãã ãéãçŽããå®è¡ãçµãã£ãã RUN_FINISHED ïŒãŸã㯠RUN_ERROR ïŒã§ç· ãã ã€ãŸããéäžããæ»ã£ãŠãã賌èªè
ãåãåãã®ã¯ live é
ä¿¡ã®ã€ãã³ãåã§ã¯ãªãããäŒè©±å
šäœã®ã¹ãããã·ã§ããã®éãçŽããã§ãã // é
ä¿¡ã¢ãŒãã®éžæãã€ãã³ãã 1 ä»¶ã§ãæµããåŸã«å§ãŸã£ã賌èªã¯ poll ã«åã export function attach ( runId : string , signal : AbortSignal ): LiveSubscription | null { const fanout = fanouts. get (runId); if (!fanout) return pollInstead(runId, "fanout_absent" ); if (fanout. closed ) return pollInstead(runId, "fanout_closed" ); // 1 ä»¶ã§ãäžç¶æžã¿ãªãåã®éäžããã«ãªãã®ã§ãå±¥æŽãåºãã poll ã«ä»»ãã if (fanout.relayed > 0 ) return pollInstead(runId, "already_relayed" ); // çç¥ïŒè³Œèªè
ãç»é²ããçæã€ãã³ããæµã AsyncGenerator ãè¿ãïŒ } // poll é
ä¿¡ã®ã«ãŒããäŒè©±å
šäœã®ã¹ãããã·ã§ããããå
容ãå€ãã£ããšãã ãéãçŽã while ( true ) { const event = snapshot(stored, readPartialMessages(progress.partialState)); const serialized = JSON . stringify (event); if (serialized !== previous) { previous = serialized; yield event; } if (isTerminal(progress. status )) break ; await sleep(POLL_INTERVAL_MS, signal); progress = await readProgress(run. id ); if (isTerminal(progress. status )) stored = await loadConversationMessages(run.conversationId); } yield terminalEvent(run, progress); éäžåæµã®è³Œèªè
ã live ã®ã€ãã³ãåã«åæµããã poll ã«åãã®ã¯ãæ£ãããåªå
ããããã§ãããã«ã¿ã®ç¶ãããæµãã«ã¯ããã¹ãããã·ã§ããã«å«ããåããšãããããæµããã«ã¿ãã®å¢çãå³å¯ã«åãããå¿
èŠããããŸããå¢çãããããšã content += delta ã®ç©ã¿äžãã§æ¬æãäºéã«é£çµãããŸããäŒè©±å
šäœã®ã¹ãããã·ã§ãããéãçŽã圢ãªããæ¯åãäžžããšã®çœ®ãæããªã®ã§ããã®äºæ
ãåççã«èµ·ããŸããããã®ä»£ãããpoll é
ä¿¡ã®ç»é¢ã¯ live é
ä¿¡ã®ãããªã¹ããªãŒãã³ã°è¡šç€ºã«ã¯ãªãããæ°ç§ããã«æç« ããŸãšãŸã£ãŠé²ã衚瀺ã«ãªããŸããéäžåæµã§ãã¹ããªãŒãã³ã°è¡šç€ºã«ããããšã¯ãåŸç¶ã®èª²é¡ã«ããŠããŸãã åæå®è¡å¶åŸ¡ïŒå®è¡äžããã¯ã NULL å¯ã®ãŠããŒã¯åã§äœã ãåäžäŒè©±ã«å®è¡äžã® run 㯠1 æ¬ã ããã DB ã§åŒ·å¶ããŸããPostgreSQL ãªã éšåã€ã³ããã¯ã¹ ïŒpartial indexã CREATE UNIQUE INDEX ... WHERE status IN ('queued','running') ã®ããã«ãæ¡ä»¶ãæºããè¡ã ããžäžæå¶çŽããããããŸãïŒã§æžããŸãããMySQL 8.0 ã«ã¯çžåœããæ§æãçšæãããŠããŸããã 代ããã« runs.lock_key ïŒNULL å¯ã»UNIQUEïŒã䜿ããŸãããå®è¡äžã¯ lock_key = conversationId ãçµäºæã« NULL ãžæ»ããŸããMySQL ã®ãŠããŒã¯ã€ã³ããã¯ã¹ã¯ NULL ãéè€ãšããŠæ±ããªã ãããçµäºæžã¿ã® run ã¯äœæ¬ã§ãå
±åã§ããå®è¡äžã¯äŒè©±ããšã« 1 æ¬ã«çµãããŸãã åäžäŒè©±ãžã® 2 æ¬ç®ã® POST /runs ã¯ãINSERT æã«ãŠããŒã¯å¶çŽéåã®ãšã©ãŒãšããŠååçã«åŒŸãããŸããéè€ã«ã¯ 2 çš®é¡ãããŸãã1 ã€ã¯ãåãéä¿¡ã®äºåºŠæŒããã§ããã¯ã©ã€ã¢ã³ãã¯éä¿¡ 1 åããšã« IDïŒ client_turn_id ïŒãçºè¡ãããªãã©ã€ã§ãåã ID ãéãããããã®åã®éè€ã§æ€åºã§ããŸããéä¿¡ãã¿ã³ã®é£æã¯ããã³ãã§ãææ¢ã§ããŸããããããã¯ãŒã¯äžèª¿æã®èªååéãªã©ããã³ãã®å¶åŸ¡ã§ã¯é²ããªãçµè·¯ãæ®ããããDB ã§ãå®ããŸãããã 1 ã€ã¯ãå¥ã®è³ªåã®äžŠè¡éä¿¡ãïŒ lock_key ã®éè€ïŒã§ãåãäŒè©±ãè€æ°ã®ã¿ãã§éããŠãããšãã«èµ·ããŸããã©ã¡ãã ã£ãããåŒãçŽããŠãå¿çãåå²ããŸãã // API Route ã®äžéšïŒéè€ããŒãšã©ãŒã®è§£é } catch (error) { if (!isUniqueViolation(error)) throw error; // äºåºŠæŒããªããå
è¡ã® run ããã®ãŸãŸè¿ãïŒåãé信㯠1 åãšããŠæ±ãïŒ const raced = await findRunByClientTurnId(params); if (raced) return { ok : true , runId : raced. id , conversationId : raced.conversationId } ; // 䞊è¡éä¿¡ãªããå®è¡äžã® run ãæ·»ããŠæåŠãž const activeRunId = await findActiveRunIn(conversationId); if (activeRunId) return { ok : false , reason : "active_run" , activeRunId } ; } // API Route ã®äžéšïŒäžŠè¡éä¿¡ãžã®å¿ç if (result.reason === "active_run" ) { return Response .json( { errors : "ãã®äŒè©±ã¯ããŸå®è¡äžã§ã" , activeRunId : result.activeRunId } , { status : 409 } , ); } 409 ã®ã¬ã¹ãã³ã¹ã« activeRunId ãå«ããŠããã®ã¯ãUI ãããã䜿ã£ãŠãæåŠãã§ã¯ãªããå®è¡äžã® run ãžã®è³Œèªåãæ¿ããã«å€æã§ããããã«ããããã§ãã ããã¯ã®è§£æŸæŒãã«åãã ããã¯ã«ã¯è§£æŸæŒããžã®åããå¿
èŠã§ãããµãŒããŒã®ããã»ã¹ãçªç¶èœã¡ããšãrunning ã®ãŸãŸããã¯ãæ¡ã£ã run ãæ®ããŸãããããªããšã誰ãå®è¡ããŠããªãã®ã«ãã®äŒè©±ãžã®è³ªåããå®è¡äžã§ãããšæåŠããç¶ããŸããåã㯠2 ã€ã®ä»çµã¿ã®çµã¿åããã§ãã å®è¡ã¯ãŒã«ãŒã¯ãå®è¡äžã® run ã® heartbeat_at ã宿çã«çŸåšæå»ãžæŽæ°ããŸãïŒåŠçãç¶ããŠããããšã®èšé²ã§ãïŒ ãããšã¯å¥ã®æé€åŠçãã heartbeat_at ã®æŽæ°ãäžå®æéæ¢ãŸã£ãŠãã queued / running ã® run ããæ
åœããã»ã¹ãç°åžžçµäºããããšã¿ãªã㊠failed ã«ããããã¯ãè§£æŸããŸãã heartbeat_at 㯠INSERT æã«çŸåšæå»ãå
¥ãããã202 ãè¿ããçŽåŸã»å®è¡ãå§ãŸãåã«ããã»ã¹ãèœã¡ãŠ queued ã®ãŸãŸæ®ã£ã run ãããã®çµè·¯ã§ååãããŸãïŒã¹ããŒãã® @@index([status, heartbeatAt]) ã¯ãã®æ€çŽ¢çšã§ãïŒ ããµãŒããŒèµ·åæã«ãæ®ã£ãŠãã running ãå
šéš failed ã«ããããšããããåçŽãªæ¹æ³ã¯æ¡ããŸããã§ããããããã€äžã¯æ°æ§ã®ãµãŒããŒããã°ããåæã«åããŠãããæ§ãµãŒããŒããŸã å®è¡ããŠããæäžã® run ããæ°ãµãŒããŒã®èµ·ååŠçã誀ã£ãŠ failed ã«ããŠããŸãããã§ããrun ã« owner_instance_id ïŒã©ã®ãµãŒããŒããã®å®è¡ãæ
åœããŠãããïŒãæãããŠããã®ãåãçç±ã§ããæé€åŠçã¯ãèªåã®ãµãŒããŒãããŸå®è¡ããŠãã run ã誀ã£ãŠååããªãããããã® ID ãšã¡ã¢ãªäžã®å®è¡äžèЧãçªãåãããŠå€å®ããŸãã ãã®ååã®ä»çµã¿ã¯ããããã€ãã¹ã±ãŒã«ã€ã³ã§ããã»ã¹ããšæ¢ããããå Žåã®åŸå§æ«ãå
ŒããŠããŸããæ¢ãŸã£ãããã»ã¹ãæ±ããŠããå®è¡ã¯éäžããåéã§ããŸããããheartbeat ãéçµ¶ããããæ°å以å
ã« failed ã«ãªãããããŸã§ã®çæå㯠partial ãšããŠå±¥æŽã«æ®ããäŒè©±ã®ããã¯ãè§£æŸãããŸãããŠãŒã¶ãŒã¯å€±æã確èªããŠãããæ¬¡ã®è³ªåã«é²ããŸãã 忢ïŒåæãšãã£ã³ã»ã«ãåºå¥ãã ãã®èšèšã§ã¯ãã¿ããéããã»ç»é¢ãé·ç§»ããã®ã¯ãåæãã§ãããå®è¡ã¯ç¶ç¶ããŸããæç€ºçã«æ¢ããããšã㯠POST /runs/{id}/cancel ãåŒã³ãŸããå®è¡ã¯ãŒã«ãŒã«ãã£ã³ã»ã«èŠæ±ã®å°ãç«ãŠãŠäžæµãžã®è³Œèªãåãé¢ããå®è¡ãããã£ã³ã»ã«ããšããŠèšé²ããŸããèšé²åŸã«é
ããŠå±ããçæç©ã¯ãåè¿°ã®å®äºæãã©ã³ã¶ã¯ã·ã§ã³ã®ãå¥ã®çµè·¯ãå
ã«çµããããŠãããä¿åããªããåå²ã§ç Žæ£ãããŸãã // API Route ã®äžéšïŒãã£ã³ã»ã«åŠç if (getActiveRun(runId) || run.ownerInstanceId === OWNER_INSTANCE_ID) { // çµäºã®èšé²ã¯å®è¡ã¯ãŒã«ãŒã«ä»»ãããããã§æžããšãã¯ãŒã«ãŒããå
ã«çµäºæžã¿ããšå€å®ããŠçæç©ãæšãŠã const active = registerRun(runId); active.cancelRequested = true ; await active.agent?.detachActiveRun(); return { ok : true } ; } // å¥ã®ãµãŒããŒãæ
åœããŠãã runãäŒè©±ã®ããã¯ãè§£æŸããããã«èšé²ã ãæžã await finalizeRun( { runId , status : "cancelled" , finalizedBy : `cancel: ${ OWNER_INSTANCE_ID } ` } ); å®è¡äžã®äŒè©±ãžã®è¿œå éä¿¡ã¯ãåè¿°ã®ããã¯ã«ãã 409 ã§æåŠãããŸãããã ã 409 ãè¿ãã ãã ãšããæ»ã£ãŠãããç»é¢ãæ¢ãŸã£ãŠèŠãã â ããäžåºŠéã â ãšã©ãŒããšããæµãã«ãªãããããããéäžçµéã®å¯èŠåïŒååæµïŒãååãªãªãŒã¹ã®ç¯å²ã«å«ããŠããŸããå®è¡äžã§ããããšãèŠããŠããã°è¿œå éä¿¡ã¯èµ·ãã«ãããæ¹åãå€ãããå Žåãã忢ããŠããéããå°ç·ã«èªå°ã§ããŸãã Redis ã¯èŠãã åçš®ã®èšèšã§ã¯ãå®è¡äžã€ãã³ãã®å
±æã« RedisïŒRedis StreamsïŒãäœ¿ãæ§æãããç¥ãããŠããŸãããã ã Redis ãå¿
èŠã«ãªãã®ã¯ãã¿ã¹ã¯ã 2 ã€ä»¥äžã«å¢ããããã€ã¹ããªãŒãã³ã°è¡šç€ºãä¿ã¡ãããå Žåã§ããä»åã¯ã©ã¡ãã«ãåœãŠã¯ãŸããªããããå
¥ããŠããŸããã çŸåšã¯ ECS 1 ã¿ã¹ã¯ã§åãããŠãããéåžžæã¯åæ¥ç¶ã®ãªã¯ãšã¹ããå®è¡ã¯ãŒã«ãŒãšåãããã»ã¹ã«å±ããŸããã€ãã³ãã¯ããã»ã¹å
ã®ã¡ã¢ãªã§ææž¡ãããããRedis ãªãã§ live é
ä¿¡ãæç«ããŸãã ã¿ã¹ã¯ã 2 ã€ä»¥äžã«å¢ãããšã賌èªã®ãªã¯ãšã¹ããå®è¡ã¯ãŒã«ãŒã®ããªãæ¹ã®ã¿ã¹ã¯ãžå±ãããšããããŸããlive é
ä¿¡ã¯ã¯ãŒã«ãŒãšåãããã»ã¹ã®ã¡ã¢ãªãä»ããŠæãç«ã£ãŠãããããå¥ã®ã¿ã¹ã¯ã«å±ãã賌èªã§ã¯äœ¿ããŸããããã ã DB ã¯ã©ã®ã¿ã¹ã¯ãããèªããã®ã§ãpoll é
ä¿¡ã¯ãã®ãŸãŸåããŸããã€ãŸã live é
ä¿¡ã§ããã¯ãã®è³Œèªã poll é
ä¿¡ã«ãªããã¹ããªãŒãã³ã°è¡šç€ºãæ°ç§ããã®æŽæ°ã«ãªãã ãã§ãå±¥æŽãéäžçµéãèŠãããŸããèšèšæ¹éã®ç¯ã§è§Šãããå®è¡ã¯ãŒã«ãŒãç¬ç«ããããã»ã¹ã«åãåºããå Žåããã¯ãŒã«ãŒãšè³Œèªè
ãå¿
ãå¥ããã»ã¹ã«ãªããããåããäžç¶ãå¿
èŠã«ãªããŸããåœé¢ã¯ 1 ã¿ã¹ã¯ã§è¶³ããèŠæš¡ã®ãããçŸæç¹ã§ã¯ãã®æ§æã«ããŠããŸãã ãŸãšã å®è¡ã®äœæãšè³Œèªãåé¢ããå®è¡ã¯ãŒã«ãŒã HTTP æ¥ç¶ããç¬ç«ãããããšã§ãç»é¢ãé¢ããŠãå®è¡ãå®èµ°ããæ§é ã«ããŸããã å±¥æŽã¯ãã¡ãã»ãŒãž 1 ä»¶ = 1 è¡ãã§ãã£ãšæ®ããçæéäžã®åçã¯äžæžãæŽæ°ã® 1 è¡ã«åããŸãããã€ãã³ãã®é次ä¿åã¯ãããã¢ãã«ãžæž¡ãå±¥æŽããµãŒããŒã DB ããçµã¿ç«ãŠãŸãã åæå®è¡å¶åŸ¡ã¯ MySQL ã®ãNULL å¯ãŠããŒã¯åãã«ããããã¯ã§å®çŸããŸããããã£ã³ã»ã«ã¯è³Œèªã®åãé¢ããšãå®è¡ãããã£ã³ã»ã«ããšããŠèšé²ããããšã§å®çŸããåæãšã¯æç¢ºã«åºå¥ããŠããŸãã AI ãã£ããã®ãå±¥æŽããšãããã¯ã°ã©ãŠã³ãå®è¡ãã¯å¥ã
ã®æ©èœã«èŠããŸãããäœã£ãŠã¿ããšãã©ã¡ãããäŒè©±ã®ç¶æ
ã¯ãµãŒããŒåŽã§æã€ããšããåãèšèšã«è¡ãçããŸãããAI ãã£ããã®å®è¡åºç€ãäœãéã«å
±éããŠçŸããè«ç¹ã ãšæãã®ã§ãåããã®ãäœãæ¹ã®åèã«ãªãã°å¹žãã§ãã