Problem Generator V3 - ๊ธฐ์ ๋งค๋ด์ผ
๋ฒ์ : 2.0 (Updated for V3 Improvements) ์ต์ข ์ ๋ฐ์ดํธ: 2025๋ 5์ 23์ผ
์ต์ ์ ๋ฐ์ดํธ (v3 ๊ฐ์ ์ฌํญ)
๐ ์ฃผ์ ๊ฐ์ ์ฌํญ
- ๊ฒ์ฆ ์คํจ ์์
- Validation ์คํจ ์ ์๋์ผ๋ก โPassโ๋ฅผ ๋ฐํํ๋ fallback ๋ก์ง ์ ๊ฑฐ
- ๊ฒ์ฆ ์คํจ ์ ํ์ดํ๋ผ์ธ ์ข ๋ฃ ๋๋ ์ ์ ํ ์ฌ์์ฑ ๋ก์ง ๊ตฌํ
- ํฅ์๋ ํผ๋๋ฐฑ ์์คํ
validation_feedback
ํ๋ผ๋ฏธํฐ๋ฅผ ๋ชจ๋ ๊ฒ์ฆ ์ฒด์ธ์ ์ถ๊ฐ- ์ง๋ฅ์ ์ธ ์ปดํฌ๋ํธ ์ฌ์์ฑ ํจ์
regenerateBasedOnValidationFeedback()
๊ตฌํ - ๊ฐ ๋จ๊ณ๋ณ ๊ตฌ์ฒด์ ์ด๊ณ ์์ธํ ํผ๋๋ฐฑ ์ ๊ณต
analyzeFeedbackAndDetermineActions()
ํจ์๋ก ํผ๋๋ฐฑ ๋ถ์ ๋ฐ ์ฌ์์ฑ ๊ฒฐ์
- Intent Analysis ์ฐฝ์์ ์ปจํ
์คํธ ์ง์
creative_context
ํ๋ ์ถ๊ฐ:theme_elements
,narrative_style
,should_integrate_theme
- ์ฐฝ์์ ์์ฒญ (์: โ๋ธ๊ธฐ๊ฐ ๋ฑ์ฅํ๋ ํผ๋ณด๋์น ๋ฌธ์ โ) ์ฒ๋ฆฌ ๊ฐ์
- Description Generation์์ ํ ๋ง ์์ ํตํฉ ์ง์
- ํ์ดํ๋ผ์ธ ๊ตฌ์กฐ ๊ฐ์
- ํ์ง ๊ฒ์ฆ ํจ์ ์ถ๊ฐ:
validateIntentQuality()
,validateTestSpecsQuality()
,validateSolutionCodeQuality()
- ํฅ์๋ ์๋ฌ ํธ๋ค๋ง ๋ฐ ์ฌ์๋ ๋ก์ง
- ๋จ๊ณ๋ณ ๋ง์ถคํ ํผ๋๋ฐฑ ๋์
- ํ์ง ๊ฒ์ฆ ํจ์ ์ถ๊ฐ:
๋ชฉ์ฐจ
- ์๊ฐ
- ์์คํ ์ํคํ ์ฒ
- ๊ธฐ์ ์คํ
- ํต์ฌ ๋ฐฑ์๋ ๋ก์ง: ๋ฌธ์ ์์ฑ ํ์ดํ๋ผ์ธ
- ์ธํ๋ผ (Terraform์ ์ฌ์ฉํ AWS IaC)
- ๋ฐฐํฌ
- ๋ก์ปฌ ๊ฐ๋ฐ ๋ฐ ํ ์คํธ (๋ฐฑ์๋)
- API ์ฌ์ฉ๋ฒ (ํ๋ก ํธ์๋ ๊ด์ )
- ๋ฌธ์ ํด๊ฒฐ ๋ฐ ์๋ ค์ง ๋ฌธ์
- ํฅํ ๊ฐ์ ์ฌํญ ๋ฐ TODO
- ๊ฒฐ๋ก
1. ์๊ฐ
1.1 ๋ชฉ์
Problem Generator V3๋ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ(LLM), ํนํ LangChain ํ๋ ์์ํฌ๋ฅผ ํตํด Google์ Gemini ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ํ๋ก๊ทธ๋๋ฐ ๋ฌธ์ ๋ฅผ ์๋์ผ๋ก ์์ฑํ๋๋ก ์ค๊ณ๋ AWS ๊ธฐ๋ฐ ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ํฌ๊ด์ ์ธ ๋ฌธ์ ์ค๋ช , ์์ ํ ์คํธ ์ผ์ด์ค, ์๋ฃจ์ ์ฝ๋, ์ ์ฝ ์กฐ๊ฑด ๋ฐ ์์ ์ฝ๋ ํ ํ๋ฆฟ ์์ฑ์ ๋ชฉํ๋ก ํฉ๋๋ค. V3์ ํต์ฌ ๊ธฐ๋ฅ์ ์์ฑ๋ ์๋ฃจ์ ์ ๊ฒ์ฆํ๊ณ ์ ํํ ํ ์คํธ ์ถ๋ ฅ์ ๊ฒฐ์ ํ๊ธฐ ์ํด ์ค์ ์ฝ๋ ์คํ์ ์์กดํ์ฌ ์ด์ ๋ฒ์ ์ ๋นํด ์์ ์ฑ์ ํฌ๊ฒ ํฅ์์ํจ๋ค๋ ์ ์ ๋๋ค.
์ต์ V3 ๊ฐ์ ์ฌํญ์ผ๋ก๋ ๊ฒ์ฆ ์คํจ ์ ์ ์ ํ ์ฌ์์ฑ์ ํตํ ์์ ์ฑ ํฅ์, ์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ ์ ํตํ ํ์ง ๊ฐ์ , ๊ทธ๋ฆฌ๊ณ ์ฐฝ์์ ์์ฒญ (ํ ๋ง๊ฐ ์๋ ๋ฌธ์ ) ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ด ์ถ๊ฐ๋์์ต๋๋ค.
1.2 ์ฃผ์ ๊ธฐ๋ฅ
- LLM ๊ธฐ๋ฐ ์์ฑ: Google Gemini ๋ชจ๋ธ์ ํ์ฉํ์ฌ ์ฐฝ์์ ์ด๊ณ ๋ณต์กํ ๋ฌธ์ ๋ฅผ ์์ฑํฉ๋๋ค.
- ์คํ ๊ธฐ๋ฐ ๊ฒ์ฆ: ์์ฑ๋ ์๋ฃจ์ ์ฝ๋๋ฅผ ์ค๊ณ๋ ํ ์คํธ ์ ๋ ฅ์ ๋ํด ์คํํ์ฌ ์ ํ์ฑ์ ๊ฒ์ฆํ๊ณ ์์ ์ถ๋ ฅ์ ๋์ถํฉ๋๋ค.
- ์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ : ๊ฒ์ฆ ์คํจ ์ ๊ตฌ์ฒด์ ์ธ ํผ๋๋ฐฑ์ ๊ธฐ๋ฐ์ผ๋ก ๊ด๋ จ ์ปดํฌ๋ํธ๋ง ์ ํ์ ์ผ๋ก ์ฌ์์ฑํฉ๋๋ค.
- ์ฐฝ์์ ์ปจํ ์คํธ ์ง์: ํ ๋ง ์์๊ฐ ํฌํจ๋ ์์ฒญ (์: โ๋ธ๊ธฐ๊ฐ ๋ฑ์ฅํ๋ ํผ๋ณด๋์น ๋ฌธ์ โ)์ ์ดํดํ๊ณ ์ ์ ํ ๋ฐ์ํฉ๋๋ค.
- ๋จ๊ณ๋ณ ํ์ดํ๋ผ์ธ: ๋ค๋จ๊ณ ๋ชจ๋์ ํ์ดํ๋ผ์ธ(LangChain ์ฌ์ฉ)์ด ์๋ ๋ถ์์์ ์ต์ข ๋ฒ์ญ์ ์ด๋ฅด๊ธฐ๊น์ง ๋ฌธ์ ์์ฑ์ ๋ค์ํ ์ธก๋ฉด์ ์ฒ๋ฆฌํฉ๋๋ค.
- ์๋ฒ-์ ์ก ์ด๋ฒคํธ(SSE): Lambda ํจ์ URL ์คํธ๋ฆผ์ ํตํด ์์ฑ ๊ณผ์ ์ค ์ค์๊ฐ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ํด๋ผ์ด์ธํธ์ ์ ๊ณตํฉ๋๋ค.
- DynamoDB ํตํฉ: ๋ฌธ์ ๋ฉํ๋ฐ์ดํฐ, ์์ฑ ์ํ ๋ฐ ์ต์ข ๊ฒฐ๊ณผ๋ฌผ์ ์ ์ฅํฉ๋๋ค.
- ์์ ํ ์ฝ๋ ์คํ: ์์ฑ๋ Python ์ฝ๋์ ์๋๋ฐ์ค ์คํ์ ์ํด ๋ณ๋์ AWS Lambda ํจ์(
code-execution-service
)๋ฅผ ํ์ฉํฉ๋๋ค. - ์ฝ๋ํ ์ธํ๋ผ(IaC): AWS ๋ฆฌ์์ค๋ Terraform์ ์ฌ์ฉํ์ฌ ๊ด๋ฆฌ๋ฉ๋๋ค.
- ๋ชจ๋์ ๋ฐฑ์๋: ์ฝ๋๋ฒ ์ด์ค๋ ์๋น์ค, ์ฒด์ธ, ํ๋กฌํํธ, ์คํค๋ง ๋ฐ ์ ํธ๋ฆฌํฐ๋ก ๊ตฌ์ฑ๋์ด ์ ์ง ๊ด๋ฆฌ์ฑ์ ํฅ์์ํต๋๋ค.
- ์์ ์ฝ๋ ์์ฑ: ์ฌ์ฉ์๋ฅผ ์ํ ์์ ์ฝ๋ ํ ํ๋ฆฟ์ ์์ฑํฉ๋๋ค.
- ๋ฒ์ญ: ๋ฌธ์ ์ ๋ชฉ ๋ฐ ์ค๋ช ๋ฒ์ญ์ ์ง์ํฉ๋๋ค.
- ํ์ง ๊ฒ์ฆ: ๊ฐ ๋จ๊ณ์์ ์์ฑ๋ ๊ฒฐ๊ณผ๋ฌผ์ ํ์ง์ ๊ฒ์ฆํ๊ณ ๊ฐ์ ํฉ๋๋ค.
2. ์์คํ ์ํคํ ์ฒ
2.1 ๊ฐ์
graph TD
User[์ต์ข
์ฌ์ฉ์] -->|์ํธ์์ฉ| Frontend[ํ๋ก ํธ์๋ (Next.js/React ์ฑ)]
Frontend -->|API ํธ์ถ (SSE)| CloudFront[AWS CloudFront ๋ฐฐํฌ]
CloudFront -->|์์ฒญ ์ ๋ฌ (OAC๋ฅผ ํตํ IAM ์ธ์ฆ)| ProblemGenLambdaURL[Problem Generator Lambda ํจ์ URL]
ProblemGenLambdaURL --> ProblemGenLambda[Problem Generator Lambda (Node.js, LangChain, Gemini API)]
ProblemGenLambda -->|๋ฌธ์ ๋ฐ์ดํฐ ์ฝ๊ธฐ/์ฐ๊ธฐ| ProblemsDB[AWS DynamoDB (Problems ํ
์ด๋ธ)]
ProblemGenLambda -->|๋ชจ๋ธ ์ถ๋ก ํธ์ถ| GeminiAPI[Google Gemini API]
ProblemGenLambda -->|์ฝ๋ ์คํ ํธ์ถ| CodeExecutorLambda[Code Executor Lambda (Python)]
subgraph AWS ํด๋ผ์ฐ๋
CloudFront
ProblemGenLambdaURL
ProblemGenLambda
ProblemsDB
CodeExecutorLambda
end
2.2 ๊ตฌ์ฑ ์์
- ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์
: (
frontend/src/app
๊ธฐ๋ฐ์ผ๋ก ์ถ์ ๋ Next.js/React) ๋ฌธ์ ์์ฑ ์์ฒญ์ ์์ํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ์ํ๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ๋๋ค. - AWS CloudFront: ๊ณต๊ฐ์ ์ผ๋ก ์ ๊ทผ ๊ฐ๋ฅํ ์ง์ ์ ์ญํ ์ ํ๋ฉฐ, Origin Access Control(OAC)์ ํตํด Lambda ํจ์ URL์ ๋ํ ์บ์ฑ, HTTPS ๋ฐ ๋ณด์ ์ก์ธ์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Problem Generator Lambda ํจ์ URL: Problem Generator Lambda์ฉ HTTPS ์๋ํฌ์ธํธ๋ก, IAM ์ธ์ฆ ๋ฐ SSE์ฉ
RESPONSE_STREAM
ํธ์ถ ๋ชจ๋๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. - Problem Generator Lambda (
problem-generator-v3
):- Node.js๋ก ์์ฑ๋ ํต์ฌ ๋ฐฑ์๋ ์๋น์ค์ ๋๋ค.
- LangChain.js๋ฅผ ์ฌ์ฉํ์ฌ Google Gemini API์์ ์ํธ ์์ฉ์ ์กฐ์ ํฉ๋๋ค.
- ๋ค๋จ๊ณ ๋ฌธ์ ์์ฑ ํ์ดํ๋ผ์ธ์ ๊ด๋ฆฌํฉ๋๋ค.
- DynamoDB์ ์ํธ ์์ฉํ์ฌ ๋ฌธ์ ์์ฑ ์ํ ๋ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๊ณ ์ ๋ฐ์ดํธํฉ๋๋ค.
- ์์ฑ๋ Python ์๋ฃจ์
์ ์คํํ๊ธฐ ์ํด
Code Executor Lambda
๋ฅผ ํธ์ถํฉ๋๋ค. - SSE๋ฅผ ํตํด ์งํ ์ํฉ ์ ๋ฐ์ดํธ ๋ฐ ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์ธํธ์ ์คํธ๋ฆฌ๋ฐํฉ๋๋ค.
- Code Executor Lambda (
code-execution-service
):- ์ฌ์ฉ์๊ฐ ์์ฑํ Python ์ฝ๋ ์กฐ๊ฐ์ ์๋๋ฐ์ค ํ๊ฒฝ์์ ์์ ํ๊ฒ ์คํํ๋ ์ญํ ์ ํ๋ ๋ณ๋์ AWS Lambda ํจ์(์ผ๋ฐ์ ์ผ๋ก Python)์ ๋๋ค.
- ์ฝ๋์ ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ณ stdout, stderr, ์คํ ์๊ฐ ๋ฐ ์ํ๋ฅผ ๋ฐํํฉ๋๋ค.
- AWS DynamoDB (
alpaco-Problems-v3-production
ํ ์ด๋ธ):- ์๋ณธ ํ๋กฌํํธ, ์์ฑ๋ ์ฝํ
์ธ (์ ๋ชฉ, ์ค๋ช
, ์๋ฃจ์
, ํ
์คํธ, ์ ์ฝ ์กฐ๊ฑด), ์์ฑ ์ํ, ํ์์คํฌํ ๋ฐ
creatorId
,author
์ ๊ฐ์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ํฌํจํ ๋ฌธ์ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๋ฐ ์ฌ์ฉ๋๋ NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๋ค. - ํจ์จ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์ํ ๊ธ๋ก๋ฒ ๋ณด์กฐ ์ธ๋ฑ์ค(GSI)๋ฅผ ํฌํจํฉ๋๋ค (์:
CompletedProblemsByCreatedAtGSI
,CreatorIdCreatedAtGSI
).
- ์๋ณธ ํ๋กฌํํธ, ์์ฑ๋ ์ฝํ
์ธ (์ ๋ชฉ, ์ค๋ช
, ์๋ฃจ์
, ํ
์คํธ, ์ ์ฝ ์กฐ๊ฑด), ์์ฑ ์ํ, ํ์์คํฌํ ๋ฐ
- Google Gemini API: ํ๋ก๊ทธ๋๋ฐ ๋ฌธ์ ์ ๋ค์ํ ๊ตฌ์ฑ ์์๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ LLM ์๋น์ค์ ๋๋ค.
- AWS S3 (Terraform ์ํ์ฉ):
alpaco-tfstate-bucket-kmu
๋ Terraform ์ํ ํ์ผ์ ์ ์ฅํฉ๋๋ค. - AWS IAM: ๋ชจ๋ AWS ๋ฆฌ์์ค์ ๋ํ ๊ถํ์ ๊ด๋ฆฌํ์ฌ ์์ ํ ์ํธ ์์ฉ์ ๋ณด์ฅํฉ๋๋ค.
3. ๊ธฐ์ ์คํ
๋ถ๋ฅ | ๊ธฐ์ /์๋น์ค | ๋ชฉ์ |
---|---|---|
ํ๋ก ํธ์๋ | React, Next.js, TypeScript | ์ฌ์ฉ์ ์ธํฐํ์ด์ค ๋ฐ ํด๋ผ์ด์ธํธ ์ธก ๋ก์ง (์ถ์ ) |
ย | AWS Amplify (Auth) | ์ฌ์ฉ์ ์ธ์ฆ (์ถ์ , fetchAuthSession ๊ธฐ๋ฐ) |
๋ฐฑ์๋ (๋ฌธ์ ์์ฑ) | AWS Lambda (Node.js 20.x) | ๋ฌธ์ ์์ฑ ๋ก์ง์ ์ํ ์๋ฒ๋ฆฌ์ค ์ปดํจํ |
ย | LangChain.js | LLM ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ ํ๋ ์์ํฌ |
ย | Google Gemini API | ์ฝํ ์ธ ์์ฑ์ ์ํ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ |
ย | AWS SDK for JavaScript v3 (DynamoDB, Lambda) | AWS ์๋น์ค์ ์ํธ ์์ฉ |
ย | Zod | LLM ์ถ๋ ฅ ๋ฐ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋ํ ์คํค๋ง ์ ํจ์ฑ ๊ฒ์ฌ |
ย | uuid | ๊ณ ์ ํ ๋ฌธ์ ID ์์ฑ |
๋ฐฑ์๋ (์ฝ๋ ์คํ) | AWS Lambda (Python - ์ถ์ ) | ์๋๋ฐ์ค ์ฝ๋ ์คํ |
๋ฐ์ดํฐ๋ฒ ์ด์ค | AWS DynamoDB | ๋ฌธ์ ๋ฐ์ดํฐ ์ ์ฅ์ ์ํ NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค |
API ๋ฐ ๋คํธ์ํน | AWS CloudFront | CDN, HTTPS, Lambda์ ๋ํ ๋ณด์ ์ก์ธ์ค |
ย | AWS Lambda ํจ์ URL | Lambda์ฉ HTTPS ์๋ํฌ์ธํธ, SSE ์คํธ๋ฆฌ๋ฐ |
์ธํ๋ผ | Terraform | ์ฝ๋ํ ์ธํ๋ผ (Infrastructure as Code) |
ย | AWS S3 | Terraform ์ํ ์ ์ฅ์ |
ย | AWS IAM | ์๊ฒฉ ์ฆ๋ช ๋ฐ ์ก์ธ์ค ๊ด๋ฆฌ |
๋น๋/DevOps | Docker | Lambda ๋ ์ด์ด ๋น๋ (build-layer.sh , Dockerfile.build ) |
ย | npm | Node.js ํจํค์ง ๊ด๋ฆฌ |
4. ํต์ฌ ๋ฐฑ์๋ ๋ก์ง: ๋ฌธ์ ์์ฑ ํ์ดํ๋ผ์ธ
4.1 ํ์ดํ๋ผ์ธ ๊ฐ์
๋ฌธ์ ์์ฑ ํ๋ก์ธ์ค๋ Problem Generator Lambda์ src/services/pipeline.mjs
์ ์ํด ์กฐ์ ๋ฉ๋๋ค. ์ด๋ LLM ๋ฐ ๊ธฐํ ์๋น์ค๋ฅผ ํ์ฉํ๋ ์์ฐจ์ ์ธ ๋ค๋จ๊ณ ํ๋ก์ธ์ค์
๋๋ค. ๊ฐ ์ฃผ์ ๋จ๊ณ๋ ์คํจ ์ ์ฌ์๋๋ฅผ ์๋ํฉ๋๋ค (MAX_RETRIES
๊น์ง). ๊ฐ ๋จ๊ณ์์ SSE ์
๋ฐ์ดํธ๊ฐ ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋ฉ๋๋ค.
4.2 ์์ธ ๋จ๊ณ
ํ์ดํ๋ผ์ธ์ ๊ฐ ์์ฑ ๋จ๊ณ์ ๋ํ LLM ํ๋กฌํํธ, ์ถ๋ ฅ ํ์ ๋ฐ ํน์ ๋ก์ง์ ์บก์ํํ๋ โ์ฒด์ธโ ๋ชจ๋(src/chains/
์ ์์น)์ ๋์ ์ผ๋ก ํธ์ถํฉ๋๋ค.
๋จ๊ณ | ํจ์ (pipeline.mjs ) / ์ฒด์ธ ๋ชจ๋ | ์ค๋ช | ์ฃผ์ ์ ๋ ฅ | ์ฃผ์ ์ถ๋ ฅ |
---|---|---|---|---|
0 | ์ ๋ ฅ ํ์ฑ / ์ด๊ธฐ DB ๋ ์ฝ๋ | ์ฌ์ฉ์ ์์ฒญ(ํ๋กฌํํธ, ๋์ด๋, creatorId, author)์ ํ์ฑํฉ๋๋ค. problemId ๋ฅผ ์์ฑํฉ๋๋ค. generationStatus: "started" ๋ก DynamoDB์ ์ด๊ธฐ ๋ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. | ์ฌ์ฉ์ ์์ฒญ ๋ณธ๋ฌธ | problemId , userPrompt , difficulty , creatorId , author |
1 | runIntentAnalysis (intentAnalysis/ ) | [๊ฐ์ ๋จ] ์ฌ์ฉ์์ ํ๋กฌํํธ๋ฅผ ๋ถ์ํ์ฌ ํต์ฌ ๋ฌธ์ ๋ชฉํ, ์ฃผ์ ์ ์ฝ ์กฐ๊ฑด, ๊ด๋ จ ๊ฐ๋ , ์ ์ถ๋ ฅ ์คํค๋ง ์ค๋ช , ํ์ด ๋ธ๋ ์ดํน ๊ท์น, ๊ทธ๋ฆฌ๊ณ ์ฐฝ์์ ์ปจํ ์คํธ(theme_elements, narrative_style, should_integrate_theme)๋ฅผ ์ถ์ถํฉ๋๋ค. | user_prompt , difficulty | intent (๊ตฌ์กฐํ๋ ๊ฐ์ฒด), intentJson + creative_context ํฌํจ |
2 | runTestDesign (testDesign/ ) | [๊ฐ์ ๋จ] ์ถ์ถ๋ ์๋์ ๋์ด๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ํ ํ ์คํธ ์ผ์ด์ค ์ ๋ ฅ๊ณผ ๊ทผ๊ฑฐ๋ฅผ ์ค๊ณํฉ๋๋ค. ์ด์ ์๋ ์คํจ ์ ๊ตฌ์ฒด์ ์ธ ํผ๋๋ฐฑ์ ๋ฐ์ ๊ฐ์ ๋ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํฉ๋๋ค. | intent , intent_json , difficulty , language , feedback_section | testSpecs (์
๋ ฅ ๋ฐ ๊ทผ๊ฑฐ ๋ฐฐ์ด), testSpecsJson |
3 | runSolutionGeneration (solutionGen/ ) | [๊ฐ์ ๋จ] ์๋ ๋ฐ ํ
์คํธ ์ค๊ณ ์
๋ ฅ์ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ธ์ด(python3.12 )๋ก ์๋ฃจ์
์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. ์ง์ ๋ ๊ฒฝ์ฐ ํ์ด ๋ธ๋ ์ดํน ๊ท์น์ ๊ตฌํํ๋ฉฐ, ํผ๋๋ฐฑ์ ๋ฐ์ ๊ฐ์ ๋ ์๋ฃจ์
์ ์์ฑํ ์ ์์ต๋๋ค. | intent.goal , testSpecsJson , language , input_schema_description , tie_breaking_rule , feedback_section | solutionCode (๋ฌธ์์ด) |
4 | ์๋ฃจ์ ์คํ ๋ฐ ๊ฒ์ฆ ๋ฃจํ | V3 ํต์ฌ ๋จ๊ณ + ํผ๋๋ฐฑ ๊ธฐ๋ฐ ์ฌ์์ฑ | ย | ย |
4.a | executeSolutionWithTestCases (solutionExecution.mjs ) | Code Executor Lambda๋ฅผ ํธ์ถํ์ฌ testSpecs ์ ๊ฐ ์
๋ ฅ์ ๋ํด solutionCode ๋ฅผ ์คํํฉ๋๋ค. ์ค์ ์ถ๋ ฅ, ์คํ ์๊ฐ ๋ฐ ์ค๋ฅ๋ฅผ ์บก์ฒํฉ๋๋ค. | solutionCode , testSpecs (JSON์์ ํ์ฑ๋จ), language | executionResults (success ํ๋๊ทธ, ์ค์ ์ถ๋ ฅ์ด ํฌํจ๋ testResults ๋ฐฐ์ด, errors ๋ฐฐ์ด, LLM์ฉ feedback ์ด ํฌํจ๋ ๊ฐ์ฒด) |
4.b | (4.a ์คํจ ์) runSolutionGeneration (์ฌ์๋) | [๊ฐ์ ๋จ] ์คํ์ด ์คํจํ๋ฉด(๊ตฌ๋ฌธ ์ค๋ฅ, ๋ฐํ์ ์ค๋ฅ, ์๊ฐ ์ด๊ณผ), ์์ธํ ์คํ ํผ๋๋ฐฑ๊ณผ ํจ๊ป solutionCode ๋ฅผ ๋ค์ ์์ฑํฉ๋๋ค. MAX_RETRIES ๊น์ง ๋ฐ๋ณตํ๋ฉฐ, ํ์ง ๊ฒ์ฆ ํจ์๋ก ๊ฐ์ ๋ ์๋ฃจ์
์ ํ์ธํฉ๋๋ค. | intent.goal , testSpecsJson , language , detailed_execution_feedback | ์๋ก์ด solutionCode |
ย | ย | ย | ย | validatedSolutionCode (๋ชจ๋ ์คํ์ ํต๊ณผํ ๋ฒ์ ) |
5 | finalizeTestCasesWithEdgeCases (testCaseFinalization.mjs ) | executionResults ๋ฅผ ์ต์ข
ํ
์คํธ ์ผ์ด์ค ๊ตฌ์กฐ(์
๋ ฅ, ์คํ ๊ฒ์ฆ๋ ์์ ์ถ๋ ฅ, ๊ทผ๊ฑฐ)๋ก ํ์ํํฉ๋๋ค. ์ ํ์ ์ผ๋ก LLM์ ์ถ๊ฐ ์์ง ์ผ์ด์ค ์ ์์ ์์ฒญํ ์ ์์ต๋๋ค. | validatedSolutionCode , executionResults , llm (์ ํ ์ฌํญ), language | finalTestCases (๋ฐฐ์ด), finalTestCasesJson |
6 | runConstraintsDerivation (constraints/ ) | [๊ฐ์ ๋จ] ๋ฌธ์ ์ ์ฝ ์กฐ๊ฑด(์๊ฐ/๋ฉ๋ชจ๋ฆฌ ์ ํ, ์
๋ ฅ ๊ฐ ๋ฒ์)์ ๋์ถํ๊ณ ์๋ฃจ์
๋ฐ ํ
์คํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก judge_type (์: equal , float_eps ) ๋ฐ epsilon ์ ๊ฒฐ์ ํฉ๋๋ค. ํผ๋๋ฐฑ์ ๋ฐ์ ๊ฐ์ ๋ ์ ์ฝ์กฐ๊ฑด์ ์์ฑํ ์ ์์ต๋๋ค. | validatedSolutionCode , finalTestCasesJson , difficulty , input_schema_description , output_format_description , feedback_section | constraints (๊ฐ์ฒด), constraintsJson |
6.5 | runStartCodeGeneration (startCode/ ) | ๋ฌธ์ ์คํค๋ง ๋ฐ ์๋ฃจ์ ์ฝ๋ ์กฐ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ํจ์ ์๋ช ๋ฐ ๊ธฐ๋ณธ I/O ํํธ๋ฅผ ํฌํจํ ์ฌ์ฉ์์ฉ ์์ ์ฝ๋ ํ ํ๋ฆฟ์ ์์ฑํฉ๋๋ค. | language , input_schema_description , output_format_description , constraints_json , solution_code_snippet | startCode (๋ฌธ์์ด) |
7 | runValidation (validation/ ) | [๋ํญ ๊ฐ์ ๋จ] ์ ์ฒด ์์ฑ๋ ํจํค์ง(์๋, ์๋ฃจ์
, ํ
์คํธ, ์ ์ฝ ์กฐ๊ฑด)์ ๋ํด ์ผ๊ด์ฑ, ์์ ์ฑ์ LLM ๊ธฐ๋ฐ์ผ๋ก ๊ฒํ ํฉ๋๋ค. ๊ฒ์ฆ ์คํจ ์ ์๋ โPassโ ๋ฐํํ๋ fallback ๋ก์ง ์ ๊ฑฐํ๊ณ , ๋์ regenerateBasedOnValidationFeedback() ํจ์๋ฅผ ํตํด ์ง๋ฅ์ ์ผ๋ก ๊ด๋ จ ์ปดํฌ๋ํธ๋ง ์ฌ์์ฑํฉ๋๋ค. | ์ด์ ์ ์์ฑ๋ ๋ชจ๋ ๊ฒฐ๊ณผ๋ฌผ, validation_feedback | validationResult (status ๋ฐ details ํฌํจ ๊ฐ์ฒด) ๋๋ ์ฌ์์ฑ๋ ์ปดํฌ๋ํธ๋ค |
8 | runDescriptionGeneration (description/ ) | [๊ฐ์ ๋จ] ๋ด๋ฌํฐ๋ธ, ์
์ถ๋ ฅ ํ์, ์ ์ฝ ์กฐ๊ฑด ๋ฐ ์์ (finalTestCases ์์ ๊ฐ์ ธ์ด)๋ฅผ ํฌํจํ์ฌ ์ฌ์ฉ์์ฉ ๋ฌธ์ ์ค๋ช
์ Markdown์ผ๋ก ์์ฑํฉ๋๋ค. ์ฐฝ์์ ์ปจํ
์คํธ๊ฐ ์ ๊ณต๋ ๊ฒฝ์ฐ ํ
๋ง ์์๋ฅผ ์ฐฝ์์ ์ผ๋ก ๋ด๋ฌํฐ๋ธ์ ํตํฉํฉ๋๋ค. | intent.goal , constraintsJson , exampleTestCasesJson , difficulty , language , epsilon_value_from_constraints , tie_breaking_rule , creative_context | description (Markdown ๋ฌธ์์ด) |
9 | runTitleGeneration (title/ ) | ๊ฐ๊ฒฐํ ๋ฌธ์ ์ ๋ชฉ์ ์์ฑํฉ๋๋ค. | difficulty , intent.goal , description_snippet | problemTitle (๋ฌธ์์ด) |
10 | runTranslation (translation/ ) | problemTitle ๋ฐ description ์ DEFAULT_TARGET_LANGUAGE (์: ํ๊ตญ์ด)๋ก ๋ฒ์ญํฉ๋๋ค. | target_language , text_to_translate (์ ๋ชฉ ๋ฐ ์ค๋ช
์ฉ) | translatedTitle , translatedDescription |
11 | ์ต์ข ํ | generationStatus: "completed" ๋ฐ ๋ชจ๋ ์์ฑ๋ ๊ฒฐ๊ณผ๋ฌผ๋ก DynamoDB ๋ ์ฝ๋๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. ์ต์ข
ProblemDetailAPI ๊ฐ์ฒด๋ฅผ SSE๋ฅผ ํตํด ํด๋ผ์ด์ธํธ์ ์ ์กํฉ๋๋ค. | ๋ชจ๋ ์์ฑ๋ ๊ฒฐ๊ณผ๋ฌผ | ์ต์ข SSE โresultโ ์ด๋ฒคํธ |
4.3 ์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ
V3์ ํต์ฌ ๊ฐ์ ์ฌํญ ์ค ํ๋๋ ๊ฒ์ฆ ์คํจ๋ฅผ ์ ์ ํ ์ฒ๋ฆฌํ๋ ์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ ์ ๋๋ค.
4.3.1 ๊ฒ์ฆ ์คํจ ์ฒ๋ฆฌ ๊ฐ์
์ด์ ๋ฒ์ ์ ๋ฌธ์ ์ :
- Validation ์คํจ ์ ์๋์ผ๋ก โPassโ๋ฅผ ๋ฐํํ๋ fallback ๋ก์ง์ด ์์ด ๋ถ์ ํํ ๊ฒฐ๊ณผ๊ฐ ํต๊ณผ๋๋ ๋ฌธ์
- ๋จ์ํ ์ฌ์๋ ๋ฉ์ปค๋์ฆ์ผ๋ก ๊ตฌ์ฒด์ ์ธ ๊ฐ์ ๋ฐฉํฅ ๋ถ์กฑ
V3 ๊ฐ์ ์ฌํญ:
- Fallback ๋ก์ง ์ ๊ฑฐ: ๊ฒ์ฆ ์คํจ ์ ํ์ดํ๋ผ์ธ์ ์ ์ ํ ์ข ๋ฃํ๊ฑฐ๋ ์ง๋ฅ์ ์ผ๋ก ์ฌ์์ฑ
regenerateBasedOnValidationFeedback()
ํจ์: ๊ฒ์ฆ ํผ๋๋ฐฑ์ ๋ถ์ํ์ฌ ๊ด๋ จ ์ปดํฌ๋ํธ๋ง ์ ํ์ ์ผ๋ก ์ฌ์์ฑanalyzeFeedbackAndDetermineActions()
ํจ์: ํผ๋๋ฐฑ ๋ด์ฉ์ ๋ถ์ํ์ฌ ์ด๋ค ์ปดํฌ๋ํธ๋ฅผ ์ฌ์์ฑํ ์ง ๊ฒฐ์
4.3.2 ํผ๋๋ฐฑ ๊ธฐ๋ฐ ์ฌ์์ฑ ๋ก์ง
// ํผ๋๋ฐฑ ๋ถ์ ๋ฐ ์ฌ์์ฑ ๊ฒฐ์
const feedbackAnalysis = analyzeFeedbackAndDetermineActions(validationFeedback);
if (feedbackAnalysis.regenerateSolution) {
// ์๋ฃจ์
์ฝ๋ ์ฌ์์ฑ + ์ฌ์คํ + ํ
์คํธ ์ผ์ด์ค ์ฌ์์ฑ
}
if (feedbackAnalysis.regenerateTests) {
// ํ
์คํธ ์ค๊ณ ์ฌ์์ฑ
}
if (feedbackAnalysis.regenerateConstraints) {
// ์ ์ฝ์กฐ๊ฑด ์ฌ์์ฑ
}
4.3.3 ๋จ๊ณ๋ณ ํผ๋๋ฐฑ ํตํฉ
๋ชจ๋ ์ฃผ์ ์์ฑ ์ฒด์ธ์ feedback_section
ํ๋ผ๋ฏธํฐ๊ฐ ์ถ๊ฐ๋์ด, ์ด์ ์๋์ ์คํจ ์์ธ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ ๋ฌํฉ๋๋ค:
- Test Design: ์ด์ ํ ์คํธ ์ผ์ด์ค์ ์ปค๋ฒ๋ฆฌ์ง ๋ถ์กฑ์ด๋ ํ์ง ๋ฌธ์ ํผ๋๋ฐฑ
- Solution Generation: ์คํ ์คํจ, ๊ตฌ๋ฌธ ์ค๋ฅ, ๋ก์ง ์ค๋ฅ์ ๋ํ ์์ธํ ํผ๋๋ฐฑ
- Constraints Derivation: ๋ถ์ ์ ํ judge_type์ด๋ ์ ์ฝ์กฐ๊ฑด์ ๋ํ ํผ๋๋ฐฑ
- Validation: ์ปดํฌ๋ํธ ๊ฐ ์ผ๊ด์ฑ ๋ฌธ์ ์ ๋ํ ๊ตฌ์ฒด์ ์ธ ํผ๋๋ฐฑ
4.3.4 ํ์ง ๊ฒ์ฆ ํจ์
๊ฐ ์์ฑ ๋จ๊ณ์์ ํ์ง์ ์ฌ์ ๊ฒ์ฆํ๋ ํจ์๋ค์ด ์ถ๊ฐ๋์์ต๋๋ค:
validateIntentQuality()
: Goal, ์ ์ถ๋ ฅ ์คํค๋ง ์ค๋ช ์ ์ ์ ์ฑ ๊ฒ์ฆvalidateTestSpecsQuality()
: ํ ์คํธ ์ผ์ด์ค ์, ์์ง ์ผ์ด์ค ํฌํจ ์ฌ๋ถ, ๋์ด๋ ์ ํฉ์ฑ ๊ฒ์ฆvalidateSolutionCodeQuality()
: ํจ์ ์ ์, return ๋ฌธ, ์ฝ๋ ๊ธธ์ด ๋ฑ ๊ธฐ๋ณธ ๊ตฌ์กฐ ๊ฒ์ฆ
4.4 ์ฐฝ์์ ์ปจํ ์คํธ ์ฒ๋ฆฌ
V3์์๋ ํ ๋ง๊ฐ ์๋ ์ฐฝ์์ ์์ฒญ์ ์ดํดํ๊ณ ์ ์ ํ ๋ฐ์ํ๋ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋์์ต๋๋ค.
4.4.1 ์ฐฝ์์ ์ปจํ ์คํธ ์คํค๋ง
Intent Analysis ๋จ๊ณ์์ creative_context
ํ๋๊ฐ ์ถ๊ฐ๋์์ต๋๋ค:
creative_context: {
theme_elements: ["strawberries"], // ํ
๋ง ์์๋ค
narrative_style: "story-based with counting theme", // ๋ด๋ฌํฐ๋ธ ์คํ์ผ
should_integrate_theme: true // ํ
๋ง ํตํฉ ์ฌ๋ถ
}
4.4.2 ์ฐฝ์์ ์์ฒญ ์ฒ๋ฆฌ ์์
์ฌ์ฉ์ ์์ฒญ: โ๋ธ๊ธฐ๊ฐ ๋ฑ์ฅํ๋ ํผ๋ณด๋์น ๊ฐ๋จ ๋ฌธ์ โ
Intent Analysis ๊ฒฐ๊ณผ:
goal
: โCalculate the Nth term of a Fibonacci sequenceโcreative_context.theme_elements
: [โstrawberriesโ]creative_context.should_integrate_theme
: true
Description Generation ํตํฉ:
- ํ๋กฌํํธ์ โCREATIVE INTEGRATIONโ ์น์ ์ถ๊ฐ
- ๋ธ๊ธฐ โ ์นด์ดํ ์๋๋ฆฌ์ค ๋งคํ
- ๋ด๋ฌํฐ๋ธ์ ๋ธ๊ธฐ ์ํ, ๋ธ๊ธฐ ๋ฐฐ์ด ๋ฑ์ ์คํ ๋ฆฌ ํตํฉ
4.4.3 ํ ๋ง๋ณ ํตํฉ ๊ฐ์ด๋
Description Generation์์ ๋ค์ํ ํ ๋ง ์์๋ค์ ์ ์ ํ ๋ฌธ์ ๋ด๋ฌํฐ๋ธ๋ก ๋ณํ:
- ๋ธ๊ธฐ, ๊ณผ์ผ: ์นด์ดํ , ์์ง, ์ ๋ ฌ ์๋๋ฆฌ์ค
- ์ฐ์ฃผ, ํ์ฑ: ํํ, ๊ฑฐ๋ฆฌ ๊ณ์ฐ, ๊ถค๋ ์๋๋ฆฌ์ค
- ๊ฒ์: ๊ฒ์ ๋ฉ์ปค๋์ฆ, ์ ์ ์์คํ , ๋ ๋ฒจ๋ง ์๋๋ฆฌ์ค
- ํํ์ง: ๋ง๋ฒ, ํ์คํธ, RPG ์์ ์๋๋ฆฌ์ค
4.4.4 ๊ธฐ์ ์ ์๊ตฌ์ฌํญ๊ณผ ์ฐฝ์์ฑ์ ๊ท ํ
์ฐฝ์์ ์ปจํ ์คํธ ํตํฉ ์์๋ ํต์ฌ ์๊ณ ๋ฆฌ์ฆ์ ์๊ตฌ์ฌํญ์ ์ ์ง:
- ์๊ณ ๋ฆฌ์ฆ ๋ณต์ก๋: ๋์ด๋์ ๋ง๋ ์ ์ ํ ์๊ณ ๋ฆฌ์ฆ ์ ์ง
- ์ ์ถ๋ ฅ ์คํค๋ง: ๋ช ํํ๊ณ ๊ฒ์ฆ ๊ฐ๋ฅํ ํ์ ์ ์ง
- ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง: ์์ง ์ผ์ด์ค ํฌํจํ ์ถฉ๋ถํ ํ ์คํธ
- ํ๋จ ๊ธฐ์ค: ๋ช ํํ tie-breaking rule๊ณผ judge_type ์ค์
5. ์ธํ๋ผ (Terraform์ ์ฌ์ฉํ AWS IaC)
์ธํ๋ผ๋ capstone-2025-04/infrastructure/problem-generator-v3/
์ ์ ์๋์ด ์์ต๋๋ค.
5.1 ๊ฐ์
Terraform์ ํ์ํ ๋ชจ๋ AWS ๋ฆฌ์์ค๋ฅผ ํ๋ก๋น์ ๋ํ๊ณ ๊ด๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ํ๋ backend.tf
์ ์ ์๋ ๋๋ก S3 ๋ฒํท(alpaco-tfstate-bucket-kmu
)์ ์๊ฒฉ์ผ๋ก ์ ์ฅ๋๋ฉฐ DynamoDB(alpaco-tfstate-lock-table
)๋ฅผ ํตํด ์ ๊ธ ์ฒ๋ฆฌ๋ฉ๋๋ค.
5.2 ์ฃผ์ ๋ฆฌ์์ค
- Lambda ํจ์ (
aws_lambda_function.problem_generator_v3
-lambda.tf
):- ๋ฐํ์:
nodejs20.x
(ARM64 ์ํคํ ์ฒ). - ํธ๋ค๋ฌ:
var.lambda_handler
์ ์ํด ์ ์๋จ (์:index.handler
๋src/index.handler
๋ฅผ ๊ฐ๋ฆฌํด). - ์ฝ๋ ์์ค:
var.lambda_code_path
์์ ์์ถ๋จ (์:../../backend/lambdas/problem-generator-v3/src
). - ์๊ฐ ์ ํ: 900์ด (15๋ถ).
- ๋ฉ๋ชจ๋ฆฌ: 1024MB.
- ๋ ์ด์ด:
aws_lambda_layer_version.problem_generator_v3_deps
. - ํ๊ฒฝ ๋ณ์:
PROBLEMS_TABLE_NAME
,GOOGLE_AI_API_KEY
,GENERATOR_VERBOSE
,GEMINI_MODEL_NAME
,CODE_EXECUTOR_LAMBDA_ARN
.
- ๋ฐํ์:
- Lambda ํจ์ URL (
aws_lambda_function_url.problem_generator_v3_url
-lambda.tf
):- ์ธ์ฆ:
AWS_IAM
. - ํธ์ถ ๋ชจ๋: SSE์ฉ
RESPONSE_STREAM
. - CORS: ์ก์ธ์ค๋ฅผ ํ์ฉํ๋๋ก ๊ตฌ์ฑ๋จ (ํ๋ก๋์
ํ๊ฒฝ์์๋
allow_origins
์กฐ์ ).
- ์ธ์ฆ:
- Lambda ๋ ์ด์ด (
aws_lambda_layer_version.problem_generator_v3_deps
-layer.tf
):- Node.js ์ข
์์ฑ ํฌํจ (
package-lock.json
๊ธฐ๋ฐ). build-layer.sh
์คํฌ๋ฆฝํธ ๋ฐDockerfile.build
๋ฅผ ์ฌ์ฉํ์ฌ Docker ์ด๋ฏธ์ง(problem-generator-layer-builder
)๋ฅผ ๋น๋ํฉ๋๋ค.- Dockerfile์
/opt
๋ด๋ถ์ ํ๋ก๋์ ์ข ์์ฑ(npm ci --omit=dev
)์ ์ค์นํ ๋ค์ Lambda ๋ ์ด์ด๊ฐ ์์ํ๋ ๋๋ก/opt/nodejs/node_modules
๋ก ์ด๋์ํต๋๋ค.- Docker ์ปจํ
์ด๋์์
nodejs
๋๋ ํฐ๋ฆฌ(node_modules
ํฌํจ)๋ฅผ ๋ก์ปฌ ์ถ๋ ฅ ๋๋ ํฐ๋ฆฌ๋ก ๋ณต์ฌํฉ๋๋ค. nodejs
๋๋ ํฐ๋ฆฌ๋ฅผproblem_generator_deps.zip
์ผ๋ก ์์ถํฉ๋๋ค.
- Docker ์ปจํ
์ด๋์์
- Node.js ์ข
์์ฑ ํฌํจ (
Dockerfile.build
:public.ecr.aws/lambda/nodejs:20-arm64
๊ธฐ๋ณธ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ข ์์ฑ์ ์ค์นํ๊ณ Lambda ๋ ์ด์ด ํธํ์ฑ์ ์ํด ๊ตฌ์กฐํํฉ๋๋ค.layer.tf
์aws_lambda_layer_version
๋ฆฌ์์ค๋ ์ดproblem_generator_deps.zip
์ ์ฌ์ฉํฉ๋๋ค.null_resource.build_lambda_layer
๋package-lock.json
, ๋น๋ ์คํฌ๋ฆฝํธ ๋๋ Dockerfile์ด ๋ณ๊ฒฝ๋๋ฉดbuild-layer.sh
์คํฌ๋ฆฝํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
5.3 ์ค์ ๋ณ์ (variables.tf
)
๊ตฌ์ฑํด์ผ ํ๋ ์ฃผ์ ๋ณ์ (terraform.tfvars
๋๋ ํ๊ฒฝ ๋ณ์๋ฅผ ํตํด ์ค์ ):
google_ai_api_key
: Google AI (Gemini) API ํค. ๋ฏผ๊ฐ ์ ๋ณด.terraform.auto.tfvars.sample
์ ์ํ ์์.code_executor_lambda_arn
: ๋ฐฐํฌ๋ Code Executor Lambda ํจ์์ ARN. ์ด๋ ์์กด์ฑ์ ์์ฑํจ (6. ๋ฐฐํฌ ์ฐธ์กฐ).project_name
,environment
,aws_region
: ๋ฆฌ์์ค ์ด๋ฆ ์ง์ ๋ฐ ์ง์ญ ๋ฐฐํฌ์ฉ.lambda_runtime
,lambda_handler
,lambda_code_path
: Lambda ํจ์ ๊ตฌ์ฑ.gemini_model_name
,generator_verbose
: LLM ๋ฐ ๋ก๊น ๊ตฌ์ฑ.
5.4 Lambda ๋ ์ด์ด ๋น๋ ํ๋ก์ธ์ค
layers/
ํ์ ๋๋ ํฐ๋ฆฌ์ ์ ์๋จ:
build-layer.sh
: Node.js ์ข ์์ฑ ๋ ์ด์ด๋ฅผ ๋น๋ํ๋ ์คํฌ๋ฆฝํธ.- ์ด์ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ ์ ๋ฆฌํฉ๋๋ค.
../../backend/lambdas/problem-generator-v3/
์์package.json
๋ฐpackage-lock.json
์ ์์ Docker ๋น๋ ์ปจํ ์คํธ๋ก ๋ณต์ฌํฉ๋๋ค.Dockerfile.build
๋ฅผ ์ฌ์ฉํ์ฌ Docker ์ด๋ฏธ์ง(problem-generator-layer-builder
)๋ฅผ ๋น๋ํฉ๋๋ค.- Dockerfile์
/opt
๋ด๋ถ์ ํ๋ก๋์ ์ข ์์ฑ(npm ci --omit=dev
)์ ์ค์นํ ๋ค์ Lambda ๋ ์ด์ด๊ฐ ์์ํ๋ ๋๋ก/opt/nodejs/node_modules
๋ก ์ด๋์ํต๋๋ค. - Docker ์ปจํ
์ด๋์์
nodejs
๋๋ ํฐ๋ฆฌ(node_modules
ํฌํจ)๋ฅผ ๋ก์ปฌ ์ถ๋ ฅ ๋๋ ํฐ๋ฆฌ๋ก ๋ณต์ฌํฉ๋๋ค. nodejs
๋๋ ํฐ๋ฆฌ๋ฅผproblem_generator_deps.zip
์ผ๋ก ์์ถํฉ๋๋ค.
Dockerfile.build
:public.ecr.aws/lambda/nodejs:20-arm64
๊ธฐ๋ณธ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ข ์์ฑ์ ์ค์นํ๊ณ Lambda ๋ ์ด์ด ํธํ์ฑ์ ์ํด ๊ตฌ์กฐํํฉ๋๋ค.layer.tf
์aws_lambda_layer_version
๋ฆฌ์์ค๋ ์ดproblem_generator_deps.zip
์ ์ฌ์ฉํฉ๋๋ค.null_resource.build_lambda_layer
๋package-lock.json
, ๋น๋ ์คํฌ๋ฆฝํธ ๋๋ Dockerfile์ด ๋ณ๊ฒฝ๋๋ฉดbuild-layer.sh
์คํฌ๋ฆฝํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
6. ๋ฐฐํฌ
6.1 ์ ์ ์กฐ๊ฑด
- Terraform CLI ์ค์น.
- AWS CLI ์ค์น ๋ฐ ์ ์ ํ ์๊ฒฉ ์ฆ๋ช ๋ฐ ๋ฆฌ์ ์ผ๋ก ๊ตฌ์ฑ.
- Google AI API ํค.
code-execution-service
๋ชจ๋์ด ๋จผ์ ๋ฐฐํฌ๋์ด์ผ ํ๋ฉฐ, ํด๋น Lambda ARN์ด ์ด ๋ชจ๋์ ์ ๋ ฅ๊ฐ์ ๋๋ค.code-execution-service
๊ฐproblems_table
์ ARN์ ์์กดํ๋ ๊ฒฝ์ฐ (์:readme.md
์ ์ค๋ช ๋ ์ํ ์์กด์ฑ),problems_table
(์ด ๋ชจ๋)์ด ๋จผ์ ๋ฐฐํฌ๋์ด์ผ ํฉ๋๋ค.
6.2 ๋ฐฐํฌ ๋จ๊ณ
์ํ ์์กด์ฑ์ ๋ํ ์์ธํ ๋
ผ์๋ capstone-2025-04/infrastructure/problem-generator-v3/readme.md
๋ฅผ ์ฐธ์กฐํ์ญ์์ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๊ถ์ฅ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
problem-generator-v3
1์ฐจ ๋ฐฐํฌ (๋ถ๋ถ):variables.tf
์์code_executor_lambda_arn
์ ์์๋ก ๋๋ฏธ ๊ฐ์ผ๋ก ์ค์ ํ๊ฑฐ๋ apply ์ ๋น ๋ณ์๋ก ์ ๊ณตํฉ๋๋ค.terraform init
terraform apply
- ์ด๋ ๊ฒ ํ๋ฉด
problems_table
์ด ์์ฑ๋๊ณ ํด๋น ARN(problems_table_arn
)์ด ์ถ๋ ฅ๋ฉ๋๋ค.
code-execution-service
๋ฐฐํฌ:- ์ด ๋ชจ๋(ํ์ผ์ ์ ๊ณต๋์ง ์์์ง๋ง ์กด์ฌํ๋ค๊ณ ๊ฐ์ )์
data "terraform_remote_state"
๋ฅผ ์ฌ์ฉํ์ฌproblem-generator-v3
์ํ์์problems_table_arn
์ ์ฝ์ต๋๋ค. code-execution-service
๋ชจ๋์ ๋ฐฐํฌํฉ๋๋ค.- ์ด๋ ๊ฒ ํ๋ฉด
code_executor_lambda_arn
์ด ์ถ๋ ฅ๋ฉ๋๋ค.
- ์ด ๋ชจ๋(ํ์ผ์ ์ ๊ณต๋์ง ์์์ง๋ง ์กด์ฌํ๋ค๊ณ ๊ฐ์ )์
problem-generator-v3
2์ฐจ ๋ฐฐํฌ (์ ์ฒด):- 2๋จ๊ณ์์ ์ป์ ์ค์
code_executor_lambda_arn
๊ฐ์ผ๋กproblem-generator-v3
์terraform.tfvars
ํ์ผ์ ์ ๋ฐ์ดํธํฉ๋๋ค. problem-generator-v3
๋ชจ๋์ ๋ํด ๋ค์terraform apply
๋ฅผ ์คํํฉ๋๋ค.- ์ด๋ ๊ฒ ํ๋ฉด Problem Generator Lambda๊ฐ ์ฌ๋ฐ๋ฅธ Code Executor ARN์ผ๋ก ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
- 2๋จ๊ณ์์ ์ป์ ์ค์
infrastructure/problem-generator-v3/
๋ด ์ผ๋ฐ์ ์ธ Terraform ๋ช
๋ น์ด:
# Terraform ์ด๊ธฐํ (๋ฐฑ์๋ ๊ตฌ์ฑ ๋ณ๊ฒฝ ์ ํ ๋ฒ ์คํ)
terraform init
# ํน์ ๊ฐ์ผ๋ก terraform.tfvars ์์ฑ ๋๋ ์
๋ฐ์ดํธ
# ์: google_ai_api_key = "YOUR_KEY"
# code_executor_lambda_arn = "ARN_FROM_CODE_EXEC_SERVICE_OUTPUT" (2์ฐจ apply ์)
# ๋ณ๊ฒฝ ์ฌํญ ๊ณํ
terraform plan
# ๋ณ๊ฒฝ ์ฌํญ ์ ์ฉ
terraform apply
# (ํ๋กฌํํธ ํ์ ์ 'yes'๋ก ํ์ธ)
# ๋ฆฌ์์ค ์ญ์ (ํ์ํ ๊ฒฝ์ฐ)
terraform destroy
6.3 ๋ชจ๋ ๊ฐ ์์กด์ฑ
์ธํ๋ผ README์์ ๊ฐ์กฐ๋ ๊ฒ์ฒ๋ผ ์ ์ฌ์ ์ธ ์ํ ์์กด์ฑ์ด ์์ต๋๋ค:
problem-generator-v3
๋code-execution-service
์code_executor_lambda_arn
์ด ํ์ํฉ๋๋ค.code-execution-service
๋problem-generator-v3
์problems_table_arn
์ด ํ์ํ ์ ์์ต๋๋ค (์: ์คํ ์๋ ๋ก๊น ๋๋ DB ์ก์ธ์ค๊ฐ ํ์ํ ํ ์คํธ ์ผ์ด์ค ๊ฒ์ฆ ๋จ๊ณ์ ์ง์ ๊ด์ฌํ๋ ๊ฒฝ์ฐ).
์์ ์ค๋ช
๋ 3๋จ๊ณ ๋ฐฐํฌ ํ๋ก์ธ์ค๋ terraform_remote_state
๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์
๋๋ค. ๋ ๊น๋ํ ๋์ ์ํคํ
์ฒ๋ DynamoDB ํ
์ด๋ธ์ ๋ ์๋น์ค ๋ชจ๋์ด ๋ชจ๋ ์์กดํ๋ ๋ณ๋์ ๊ณตํต database
๋ชจ๋๋ก ์ถ์ถํ๋ ๊ฒ์
๋๋ค.
7. ๋ก์ปฌ ๊ฐ๋ฐ ๋ฐ ํ ์คํธ (๋ฐฑ์๋)
problem-generator-v3
์ฉ ๋ฐฑ์๋ Lambda ์ฝ๋๋ local-test.mjs
์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ก์ปฌ์์ ํ
์คํธํ ์ ์์ต๋๋ค.
7.1 ์ค์
-
Lambda ๋๋ ํฐ๋ฆฌ๋ก ์ด๋:
cd capstone-2025-04/backend/lambdas/problem-generator-v3/
-
์ข ์์ฑ ์ค์น:
npm install
-
์ด ๋๋ ํฐ๋ฆฌ์
.env
ํ์ผ ์์ฑํ๊ณ Google AI API ํค๋ฅผ ์ ๋ ฅํฉ๋๋ค:# capstone-2025-04/backend/lambdas/problem-generator-v3/.env GOOGLE_AI_API_KEY="์ค์ _Google_AI_API_ํค_์ ๋ ฅ" # ์ ํ ์ฌํญ: local-test.mjs ๋๋ constants.mjs์ ๊ธฐ๋ณธ๊ฐ ์ฌ์ ์ # MOCK_DYNAMODB=true # ๋๋ false # PROBLEMS_TABLE_NAME=alpaco-Problems-v3-dev # GEMINI_MODEL_NAME=gemini-1.5-flash-latest # CODE_EXECUTOR_LAMBDA_ARN="๊ฐ๋ฐ์ฉ_์ฝ๋_์คํ๊ธฐ_ARN"
local-test.mjs
์คํฌ๋ฆฝํธ๋ ์ด.env
ํ์ผ์ ๋ก๋ํฉ๋๋ค.
7.2 ๋ก์ปฌ ํ ์คํธ ์คํ
local-test.mjs
์คํฌ๋ฆฝํธ๋ Lambda ํ๊ฒฝ ๋ฐ ํ์ดํ๋ผ์ธ ์คํ์ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค.
-
๋ํํ ๋ชจ๋: ์ฌ์ฉ์ ์ ๋ ฅ(๋ฌธ์ ํ๋กฌํํธ, ๋์ด๋ ๋ฑ) ๋ฐ DynamoDB ๋ชจ๋๋ฅผ ๋ฌป์ต๋๋ค.
node local-test.mjs
-
์๋ ๋ชจ๋ (์คํฌ๋ฆฝํธ์
sampleEvent
์ฌ์ฉ):-
๊ธฐ๋ณธ ์๋ ๋ชจ๋ (์ธ์,
.env
, ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ์์ผ๋กMOCK_DYNAMODB
์ค์ ์ฌ์ฉ):```bash node local-test.mjs auto ```
-
Mock DynamoDB ๊ฐ์ ์ฌ์ฉ:
```bash node local-test.mjs mock # ๋๋ node local-test.mjs auto mock ```
-
์ค์ DynamoDB ๊ฐ์ ์ฌ์ฉ (AWS ์๊ฒฉ ์ฆ๋ช ๊ตฌ์ฑ ํ์):
```bash node local-test.mjs real # ๋๋ node local-test.mjs auto real ```
-
์ถ๋ ฅ:
- ์ฝ์ ๋ก๊ทธ๋ SSE์ ์ ์ฌํ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๋ณด์ฌ์ค๋๋ค.
- ์ต์ข
์์ฑ๋ ๋ฌธ์ (์ฑ๊ณต ์)๋
problem-gen-result-[ํ์์คํฌํ].json
์ ์ ์ฅ๋ฉ๋๋ค.
7.3 ๋ชจ์(Mocking) ์ฒ๋ฆฌ
- DynamoDB:
process.env.MOCK_DYNAMODB
๊ฐ'true'
๋ก ์ค์ ๋ ๊ฒฝ์ฐlocal-test.mjs
๋ ๋ชจ์ DynamoDB ๊ตฌํ(mock-dynamodb.mjs
)์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๋ชจ์ ๊ตฌํ์ ์ธ๋ฉ๋ชจ๋ฆฌ ์๋ฎฌ๋ ์ด์ ์ ๋๋ค. - Code Executor Lambda:
codeExecutor.mjs
์ ํธ๋ฆฌํฐ๋CODE_EXECUTOR_LAMBDA_ARN
(constants.mjs
์์ ๊ฐ์ ธ์ค๋ฉฐ.env
๋ก ์ฌ์ ์ ๊ฐ๋ฅ)์ผ๋ก ์ง์ ๋ ์ค์ AWS Lambda๋ฅผ ํธ์ถํฉ๋๋ค. AWS ์์ด ์์ ํ ๋ก์ปฌ์์ ํ ์คํธํ๋ ค๋ฉด ์ด๋ฅผ ๋ชจ์ ์ฒ๋ฆฌํ๊ฑฐ๋ ๋ก์ปฌ Python ์คํ ํ์ ํ๋ก์ธ์ค๋ฅผ (์ด์ ๋ฒ์ ์์์ฒ๋ผ) ๋ค์ ๊ตฌํํด์ผ ํฉ๋๋ค. ํ์ฌ Python ์ฝ๋ ์คํ์ ์ํ ๋ก์ปฌ ํ ์คํธ๋ ์ฌ์ ํ ๋ฐฐํฌ๋ AWS Code Executor Lambda์ ์์กดํฉ๋๋ค.
8. API ์ฌ์ฉ๋ฒ (ํ๋ก ํธ์๋ ๊ด์ )
frontend/src/api/generateProblemApi.ts
๋ฐ frontend/src/app/coding-test/solve/page.tsx
๊ธฐ๋ฐ.
8.1 ์๋ํฌ์ธํธ
- API ์๋ํฌ์ธํธ๋ ํ๊ฒฝ ๋ณ์
NEXT_PUBLIC_PROBLEM_GENERATION_API_BASE_URL
์ ํตํด ๊ตฌ์ฑ๋ฉ๋๋ค. - ์ด URL์ CloudFront ๋ฐฐํฌ ๋๋ฉ์ธ ์ด๋ฆ(์:
d123abc.cloudfront.net
)์ ๊ฐ๋ฆฌํต๋๋ค.
8.2 ์ธ์ฆ
- Lambda ํจ์ URL์
AWS_IAM
์ธ์ฆ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. - CloudFront๋ SigV4 ์๋ช ์ ์ฌ์ฉํ๋ Origin Access Control(OAC)์ ์ฌ์ฉํ์ฌ Lambda ํจ์ URL์ ์์ ํ๊ฒ ํธ์ถํฉ๋๋ค.
- ํ๋ก ํธ์๋๋ AWS Amplify(
fetchAuthSession
)๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์๊ฒฉ ์ฆ๋ช (์: Cognito ID ํ ํฐ, ์์ AWS ์๊ฒฉ ์ฆ๋ช ์ผ๋ก ๊ตํ๋๊ฑฐ๋ ์์ฒญ ์๋ช ์ ์ฌ์ฉ๋จ)์ ๊ฐ์ ธ์ฌ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. - CloudFront ์๋ํฌ์ธํธ์ ๋ํ ์์ฒญ์ Amplify๊ฐ ์ง์ ์ฒ๋ฆฌํ์ง ์๋ ๊ฒฝ์ฐ ์ ์ ํ AWS SigV4 ํค๋๋ฅผ ํฌํจํด์ผ ํ๊ฑฐ๋, Lambda URL ์์ฒด๊ฐ IAM์ผ๋ก ๋ณดํธ๋๊ณ CloudFront๊ฐ ๋จ์ํ ํต๊ณผํ๋ ๊ฒฝ์ฐ CloudFront๊ฐ IAM์ ์ ์ฉํ๋๋ก ์์กดํด์ผ ํฉ๋๋ค.
generateProblemApi.ts
์Authorization: Bearer ${idToken}
๋ฐx-amz-content-sha256
ํค๋๋ ํด๋ผ์ด์ธํธ์์ ์ง์ IAM ์๋ช ๋ ์์ฒญ์ ๋ณด๋ด๊ฑฐ๋ CloudFront๊ฐ ์ค๋ฆฌ์ง์ ๋ํ ์์ฒญ์ ๋ค์ ์๋ช ํ๋ ํต๊ณผ ๋ฉ์ปค๋์ฆ์ ์์ฌํฉ๋๋ค. OACsigning_behavior = "always"
์ด๋ฏ๋ก CloudFront๋ ์ค๋ฆฌ์ง(Lambda URL)์ ๋ํ ์์ฒญ์ ์๋ช ํฉ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ CloudFront ์์ฒด์ ๋ณด๋ด๋ ์์ฒญ์ CloudFront WAF/๋์ ์ค์ ์ ๋ฐ๋ผ IAM ์ธ์ฆ๋๊ฑฐ๋ ๊ณต๊ฐ๋ ์ ์์ต๋๋ค.
8.3 ์์ฒญ
- ๋ฉ์๋:
POST
- ํค๋:
Content-Type: application/json
Authorization: Bearer <ID_TOKEN>
(Cognito๊ฐ ํด๋ผ์ด์ธํธ ์ธ์ฆ์ ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ. OAC๊ฐ ์๋ ์ง์ Lambda URL์ ๊ฒฝ์ฐ CloudFront๊ฐ ์ค๋ฆฌ์ง์ ๋ํ ์ธ์ฆ์ ์ฒ๋ฆฌ)x-amz-content-sha256
: ์์ฒญ ํ์ด๋ก๋์ SHA256 ํด์ (SigV4 ํ์ค).
-
๋ณธ๋ฌธ (
CreateProblemRequest
):{ "prompt": "string (์ฌ์ฉ์ ๋ฌธ์ ์์ด๋์ด)", "difficulty": "Easy" | "Medium" | "Hard", // ๋๋ ํ๋ก ํธ์๋ ํ์ ์ ๋ฐ๋ผ "ํํ ๋ฆฌ์ผ", "์ฌ์", "๋ณดํต", "์ด๋ ค์" "creatorId": "string (์ ํ ์ฌํญ, ์ฌ์ฉ์ ID)", "author": "string (์ ํ ์ฌํญ, ์ฌ์ฉ์ ํ์ ์ด๋ฆ)" }
8.4 ์๋ต (SSE ์คํธ๋ฆผ)
API๋ ์๋ฒ-์ ์ก ์ด๋ฒคํธ ์คํธ๋ฆผ(Content-Type: text/event-stream
)์ผ๋ก ์๋ตํฉ๋๋ค. ๋ฉ์์ง ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
event: <์ด๋ฒคํธ_ํ์
>
data: <JSON_ํ์ด๋ก๋>
event: status
-
ํ์ด๋ก๋ (
ProblemStreamStatus
):```json { "step": number (ํ์ฌ ํ์ดํ๋ผ์ธ ๋จ๊ณ), "message": "string (์ํ ๋ฉ์์ง)" } ```
-
event: result
-
ํ์ด๋ก๋ (
ProblemStreamResult
-ProblemDetailAPI
๋ํ):```json { "payload": { /* ProblemDetailAPI ๊ฐ์ฒด */ } } ``` `ProblemDetailAPI` ๊ฐ์ฒด ํฌํจ ๋ด์ฉ: `problemId`, `title`, `title_translated`, `description`, `description_translated`, `difficulty`, `constraints` (JSON ๋ฌธ์์ด), `solutionCode`, `startCode`, `finalTestCases` (ํ ์คํธ ์ผ์ด์ค ๋ฐฐ์ด์ JSON ๋ฌธ์์ด), `generationStatus`, `language`, `targetLanguage`, `createdAt`, `completedAt`, `userPrompt`, `errorMessage`, `validationDetails`, `creatorId`, `author`, `judgeType`, `epsilon`, `schemaVersion`.
-
event: error
-
ํ์ด๋ก๋ (
ProblemStreamError
):```json { "payload": "string (์ค๋ฅ ๋ฉ์์ง)" } ```
-
์์ฑ์ด ์๋ฃ๋๊ฑฐ๋ ์น๋ช
์ ์ธ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์คํธ๋ฆผ์ด ์ข
๋ฃ๋ฉ๋๋ค. ํ๋ก ํธ์๋์ onComplete
์ฝ๋ฐฑ์ด ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.
9. ๋ฌธ์ ํด๊ฒฐ ๋ฐ ์๋ ค์ง ๋ฌธ์
9.1 ์ผ๋ฐ์ ์ธ ๋ฌธ์ ๋ค
- LLM ์คํจ:
- ์๋ชป๋ ํ์์ JSON ์ถ๋ ฅ: LLM์ด ๊ฐ๋ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ฑ๋์ง ์๋ JSON์ ์์ฑํ ์ ์์ต๋๋ค.
intentAnalysis
์ฒด์ธ์๋ ์ผ๋ถ ๋ณต๊ตฌ ๋ก์ง(cleanJsonOutput
)์ด ์์ต๋๋ค. ์ด๋ฅผ ์ต์ํํ๊ธฐ ์ํด ์๋ก์ด ์ฒด์ธ์๋ LangChain์ ๊ตฌ์กฐํ๋ ์ถ๋ ฅ ๊ธฐ๋ฅ(withStructuredOutput
)์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. - ๋น์ด ์๊ฑฐ๋ ์ ํจํ์ง ์์ ์ฝํ
์ธ : LLM์ด ๋น ๋ฌธ์์ด์ด๋ ์๋ฏธ ์๋ ์ฝํ
์ธ ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
pipeline.mjs
์ ์ฌ์๋ ๋ฉ์ปค๋์ฆ์ด ์ด๋ฅผ ์ํํ๋ ค๊ณ ์๋ํฉ๋๋ค. - API ์๋ ์ ํ/์ค๋ฅ: Google AI API ํค๊ฐ ์ ํจํ๊ณ ์ถฉ๋ถํ ํ ๋น๋์ ๊ฐ์ง๊ณ ์๋์ง ํ์ธํฉ๋๋ค.
- ์๋ชป๋ ํ์์ JSON ์ถ๋ ฅ: LLM์ด ๊ฐ๋ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ฑ๋์ง ์๋ JSON์ ์์ฑํ ์ ์์ต๋๋ค.
- ๋ฐฐํฌ ๋ฌธ์ :
- ์ํ ์์กด์ฑ:
problem-generator-v3
์code-execution-service
๊ฐ ์๋ก์ ์ถ๋ ฅ์ ์์กดํ๋ ๊ฒฝ์ฐ 3๋จ๊ณ ๋ฐฐํฌ ํ๋ก์ธ์ค๋ฅผ ์ฃผ์ ๊น๊ฒ ๋ฐ๋ฆ ๋๋ค. - IAM ๊ถํ: ์๋ชป๋ IAM ์ ์ฑ
์ Lambda ํจ์๊ฐ DynamoDB์ ์ก์ธ์คํ๊ฑฐ๋ ๋ค๋ฅธ Lambda๋ฅผ ํธ์ถํ๊ฑฐ๋ ๋ก๊ทธ๋ฅผ ์์ฑํ๋ ค๊ณ ํ ๋ ์ก์ธ์ค ๊ฑฐ๋ถ ์ค๋ฅ๋ฅผ ๋ฐ์์ํฌ ์ ์์ต๋๋ค.
iam.tf
์ ์ ์ฑ ์ ๋ค์ ํ์ธํฉ๋๋ค.
- ์ํ ์์กด์ฑ:
- ์ค์ :
GOOGLE_AI_API_KEY
๋ Lambda ํ๊ฒฝ ๋ณ์(Terraform์ ํตํด)์ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ด์ผ ํฉ๋๋ค.CODE_EXECUTOR_LAMBDA_ARN
์ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐฐํฌ๋๊ณ ์๋ํ๋ Code Executor Lambda๋ฅผ ๊ฐ๋ฆฌ์ผ์ผ ํฉ๋๋ค.
9.2 V3 ํน์ ๋ฌธ์ ๋ค
- ๊ฒ์ฆ ์คํจ ์ฒ๋ฆฌ:
- ํด๊ฒฐ๋จ: ์ด์ ์ ๊ฒ์ฆ ์คํจ ์ ์๋์ผ๋ก โPassโ๋ฅผ ๋ฐํํ๋ fallback ๋ก์ง์ด ์ ๊ฑฐ๋์์ต๋๋ค.
- ํ์ฌ: ๊ฒ์ฆ ์คํจ ์
regenerateBasedOnValidationFeedback()
ํจ์๋ฅผ ํตํด ์ง๋ฅ์ ์ผ๋ก ์ฌ์์ฑํ๊ฑฐ๋ ์ ์ ํ ์คํจ ์ฒ๋ฆฌํฉ๋๋ค.
- ํผ๋๋ฐฑ ๋ฃจํ ๋ฌดํ ๋ฐ๋ณต:
- ์ํ: ์ฌ์์ฑ์ด ๊ณ์ ์คํจํ ๊ฒฝ์ฐ
MAX_RETRIES
์ ๋๋ฌํ ๋๊น์ง ๋ฐ๋ณต - ์ํ: ๊ฐ ๋จ๊ณ๋ณ ํ์ง ๊ฒ์ฆ ํจ์๋ก ์ฌ์ ๊ฒ์ฆ, ๊ตฌ์ฒด์ ์ธ ํผ๋๋ฐฑ ์ ๊ณต์ผ๋ก ๊ฐ์ ๋ฐฉํฅ ๋ช ํํ
- ์ํ: ์ฌ์์ฑ์ด ๊ณ์ ์คํจํ ๊ฒฝ์ฐ
- ์ฐฝ์์ ์ปจํ
์คํธ ๊ณผ๋ํ ์ ์ฉ:
- ์ํ: ํ ๋ง ์์๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ๋ณต์ก์ฑ์ ํฌ์์ํฌ ์ ์์
- ์ํ: Description Generation์์ ๊ธฐ์ ์ ์๊ตฌ์ฌํญ๊ณผ ์ฐฝ์์ฑ์ ๊ท ํ ์ ์ง
9.3 ์ฝ๋ ์คํ ๊ด๋ จ
- ์๊ฐ ์ด๊ณผ: ์์ฑ ๋๋ ์คํ์ ๋๋ฌด ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ฉด Code Executor Lambda ๋๋ Problem Generator Lambda ์์ฒด๊ฐ ์๊ฐ ์ด๊ณผ๋ ์ ์์ต๋๋ค. ํ
์คํธ ์ผ์ด์ค๋น ์๋ฃจ์
์คํ์๋
EXECUTION_TIMEOUT_MS
๊ฐ ์์ต๋๋ค. - Python ํ๊ฒฝ: ์์ฑ๋ ์๋ฃจ์ ์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ ๊ฒฝ์ฐ Code Executor Lambda์ Python ํ๊ฒฝ์ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ด์ผ ํฉ๋๋ค (ํ์ฌ ํ๋กฌํํธ๋ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์๋ฃจ์ ์ ๋ชฉํ๋ก ํจ).
9.4 ๋ก์ปฌ ํ ์คํธ
.env
ํ์ผ์backend/lambdas/problem-generator-v3/
์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋์ด์ผ ํฉ๋๋ค.- Python ์ฝ๋์ ๋ก์ปฌ ์คํ(4.a ๋จ๊ณ)์ ์ฌ์ ํ ๋ฐฐํฌ๋ AWS Code Executor Lambda์ ์์กดํฉ๋๋ค. ์์ ํ ์คํ๋ผ์ธ์ผ๋ก ๋ก์ปฌ Python ์คํ์ ํ๋ ค๋ฉด
codeExecutor.mjs
์ ๋ก์ปฌ Python ํ์ ํ๋ก์ธ์ค ์คํ๊ธฐ๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
9.5 ๋คํธ์ํฌ ๋ฐ ์คํธ๋ฆผ
- SSE ์คํธ๋ฆผ ์ค๋จ: ๋คํธ์ํฌ ๋ฌธ์ ๋ก ์ธํด SSE ์คํธ๋ฆผ์ด ์ค๋จ๋ ์ ์์ต๋๋ค. ํ๋ก ํธ์๋๋ ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค (์ ๊ณต๋
generateProblemApi.ts
์๋ ๋ช ์์ ์ผ๋ก ๊ตฌํ๋์ด ์์ง ์์).
10. ํฅํ ๊ฐ์ ์ฌํญ ๋ฐ TODO
10.1 โ ์๋ฃ๋ ๊ฐ์ ์ฌํญ (V3 ์ ๋ฐ์ดํธ)
- โ ๊ฒ์ฆ ์คํจ ์์ : Fallback ๋ก์ง ์ ๊ฑฐ, ์ ์ ํ ์ฌ์์ฑ ๋ฉ์ปค๋์ฆ ๊ตฌํ
- โ
์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ
:
regenerateBasedOnValidationFeedback()
์analyzeFeedbackAndDetermineActions()
๊ตฌํ - โ ์ฐฝ์์ ์ปจํ ์คํธ ์ง์: Intent Analysis์ Description Generation ๊ฐ์ ํตํฉ๋ ํ ๋ง ์ฒ๋ฆฌ
- โ
ํ์ง ๊ฒ์ฆ ํจ์:
validateIntentQuality()
,validateTestSpecsQuality()
,validateSolutionCodeQuality()
์ถ๊ฐ - โ
ํผ๋๋ฐฑ ํ๋ผ๋ฏธํฐ ํตํฉ: ๋ชจ๋ ์ฃผ์ ์ฒด์ธ์
feedback_section
ํ๋ผ๋ฏธํฐ ์ถ๊ฐ
10.2 ๐ ์งํ ์ค์ธ ๊ฐ์ ์ฌํญ
- API ๋ฌธ์ํ: ์๋ก์ด ๊ธฐ๋ฅ๋ค์ ๋ํ ๋ฌธ์ ์ ๋ฐ์ดํธ (ํ์ฌ ์งํ ์ค)
- ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง: ์๋ก์ด ํผ๋๋ฐฑ ์์คํ ๊ณผ ์ฐฝ์์ ์ปจํ ์คํธ ์ฒ๋ฆฌ์ ๋ํ ํ ์คํธ ์ถ๊ฐ
10.3 ๐ ํฅํ ๊ณํ
10.3.1 ํต์ฌ ๊ธฐ๋ฅ ๊ฐ์
- ๋ค์ค ์ธ์ด ์ง์ ํ์ฅ:
- JavaScript, Java, C++ ๋ฑ ์ถ๊ฐ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ์ง์
- ์ธ์ด๋ณ ์ต์ ํ๋ ์๋ฃจ์ ์์ฑ ๋ฐ ์คํ
- ๋์ ๋์ด๋ ์กฐ์ :
- ์ฌ์ฉ์์ ์ด์ ํ์ด ๊ธฐ๋ก์ ๋ฐํ์ผ๋ก ๋์ด๋ ์๋ ์กฐ์
- ์ค์๊ฐ ๋์ด๋ ์ค์ผ์ผ๋ง
- ํฅ์๋ ์์ง ์ผ์ด์ค ์์ฑ:
- LLM ๊ธฐ๋ฐ ์์ง ์ผ์ด์ค ์๋ ์์ฑ ๊ฐ์
- ์ ๊ณ ํ์ค ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ํจํด ๋ถ์
10.3.2 ์ฑ๋ฅ ๋ฐ ์์ ์ฑ
- ์บ์ฑ ๋ฉ์ปค๋์ฆ:
- ์ ์ฌํ ์์ฒญ์ ๋ํ ๊ฒฐ๊ณผ ์บ์ฑ
- ์ค๊ฐ ๋จ๊ณ ๊ฒฐ๊ณผ ์บ์ฑ์ผ๋ก ์ฌ์์ฑ ์ ์ฑ๋ฅ ํฅ์
- ๋ณ๋ ฌ ์ฒ๋ฆฌ:
- ์ฌ๋ฌ ์๋ฃจ์ ํ๋ณด ๋์ ์์ฑ ๋ฐ ์ต์ ํด ์ ํ
- ํ ์คํธ ์ผ์ด์ค ๋ณ๋ ฌ ์คํ
- ๋ก๋ ๋ฐธ๋ฐ์ฑ:
- ๋ค์ค LLM ๋ชจ๋ธ ์ฌ์ฉ์ผ๋ก ๋ถํ ๋ถ์ฐ
- API ํธ์ถ ์ ํ ๋ฐ ํ์ ์์คํ
10.3.3 ์ฌ์ฉ์ ๊ฒฝํ
- ์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ:
- ์์ฑ ์ค๊ฐ ๋จ๊ณ์์ ๋ถ๋ถ ๊ฒฐ๊ณผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ ๊ณต
- ์ฌ์ฉ์ ํผ๋๋ฐฑ ๊ธฐ๋ฐ ์ค์๊ฐ ์กฐ์
- ๋ฌธ์ ํ
ํ๋ฆฟ ์์คํ
:
- ์ฌ์ ์ ์๋ ๋ฌธ์ ํจํด๊ณผ ๋ณํ ์์คํ
- ์ฌ์ฉ์ ๋ง์ถคํ ๋ฌธ์ ์์ฑ
- ํ์
๊ธฐ๋ฅ:
- ํ ๊ธฐ๋ฐ ๋ฌธ์ ์์ฑ ๋ฐ ๊ฒํ
- ์ปค๋ฎค๋ํฐ ๊ธฐ๋ฐ ๋ฌธ์ ๊ฐ์
10.3.4 ๊ธฐ์ ์ ๊ฐ์
- ์์ ํ ๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ:
- AWS ์์กด์ฑ ์๋ ์์ ํ ๋ก์ปฌ ํ ์คํธ ํ๊ฒฝ ๊ตฌ์ถ
- Docker ๊ธฐ๋ฐ ๋ก์ปฌ Code Executor ๊ตฌํ
- ๋ชจ๋ํฐ๋ง ๋ฐ ๊ด์ฐฐ์ฑ:
- ์์ธํ ๋ฉํธ๋ฆญ ์์ง ๋ฐ ๋ถ์
- ์ค์๊ฐ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ๋์๋ณด๋
- ์ค๋ฅ ํจํด ๋ถ์ ๋ฐ ์๋ ์๋ฆผ
- ๋ณด์ ๊ฐํ:
- ์ฝ๋ ์คํ ์๋๋ฐ์ค ๋ณด์ ๊ฐํ
- ์ฌ์ฉ์ ์ ๋ ฅ ๊ฒ์ฆ ๋ฐ ํํฐ๋ง ๊ฐ์
- API ํธ์ถ ํ์ ์ ํ ๋ฐ ๋จ์ฉ ๋ฐฉ์ง
10.3.5 AI/ML ๊ธฐ๋ฅ ํ์ฅ
- ๊ฐ์ธํ๋ ๋ฌธ์ ์์ฑ:
- ์ฌ์ฉ์์ ํ์ต ํจํด ๋ถ์์ ํตํ ๋ง์ถคํ ๋ฌธ์ ์์ฑ
- ์ฝ์ ๋ถ์ผ ์ง์ค ๋ฌธ์ ์์ฑ
- ์๋ ํํธ ์์คํ
:
- ๋ฌธ์ ํด๊ฒฐ ๊ณผ์ ์์ ์ ์ํ ํํธ ์ ๊ณต
- ํ์ต ์ง๋์ ๋ง๋ ๋จ๊ณ๋ณ ๊ฐ์ด๋
- ์ฝ๋ ํ์ง ๋ถ์:
- ์์ฑ๋ ์๋ฃจ์ ์ ์ต์ ํ ์์ค ํ๊ฐ
- ๋์ ์๋ฃจ์ ์๋ ์์ฑ ๋ฐ ๋น๊ต
10.4 ๐ ๊ธฐ์ ๋ถ์ฑ ๋ฐ ๋ฆฌํฉํ ๋ง
- ์ฝ๋ ๊ตฌ์กฐ ๊ฐ์ :
- ์ฒด์ธ ๋ชจ๋ ๊ฐ ์์กด์ฑ ์ ๋ฆฌ
- ๊ณตํต ์ ํธ๋ฆฌํฐ ํจ์ ์ถ์ถ ๋ฐ ์ฌ์ฌ์ฉ์ฑ ๊ฐ์
- ์๋ฌ ํธ๋ค๋ง ํ์คํ:
- ์ผ๊ด๋ ์๋ฌ ๋ฉ์์ง ํ์
- ๊ตฌ์ฒด์ ์ธ ๋ณต๊ตฌ ์ ๋ต ๋ฌธ์ํ
- ํ
์คํธ ์๋ํ:
- ํตํฉ ํ ์คํธ ๋ฐ E2E ํ ์คํธ ํ์ฅ
- ์ฑ๋ฅ ๋ฒค์น๋งํฌ ํ ์คํธ ์ถ๊ฐ
10.5 ๐ง ์ธํ๋ผ ๊ฐ์
- ๋ค์ค ํ๊ฒฝ ์ง์:
- ๊ฐ๋ฐ/์คํ ์ด์ง/ํ๋ก๋์ ํ๊ฒฝ ๋ถ๋ฆฌ
- ํ๊ฒฝ๋ณ ๋ ๋ฆฝ์ ์ธ ๋ฐฐํฌ ํ์ดํ๋ผ์ธ
- ์ํ ์์กด์ฑ ํด๊ฒฐ:
- ๊ณตํต ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ ๋ถ๋ฆฌ
- ์๋น์ค ๊ฐ ์์กด์ฑ ์ต์ํ
- ๋น์ฉ ์ต์ ํ:
- ์ฌ์ฉ๋ ๊ธฐ๋ฐ ์๋ ์ค์ผ์ผ๋ง
- ๋ฆฌ์์ค ์ฌ์ฉ๋ ๋ชจ๋ํฐ๋ง ๋ฐ ์ต์ ํ
11. ๊ฒฐ๋ก
Problem Generator V3๋ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ(LLM), ํนํ LangChain ํ๋ ์์ํฌ๋ฅผ ํตํด Google์ Gemini ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ํ๋ก๊ทธ๋๋ฐ ๋ฌธ์ ๋ฅผ ์๋์ผ๋ก ์์ฑํ๋๋ก ์ค๊ณ๋ AWS ๊ธฐ๋ฐ ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. V3์ ํต์ฌ ๊ธฐ๋ฅ์ ์์ฑ๋ ์๋ฃจ์ ์ ๊ฒ์ฆํ๊ณ ์ ํํ ํ ์คํธ ์ถ๋ ฅ์ ๊ฒฐ์ ํ๊ธฐ ์ํด ์ค์ ์ฝ๋ ์คํ์ ์์กดํ์ฌ ์ด์ ๋ฒ์ ์ ๋นํด ์์ ์ฑ์ ํฌ๊ฒ ํฅ์์ํจ๋ค๋ ์ ์ ๋๋ค.
์ต์ V3 ๊ฐ์ ์ฌํญ์ผ๋ก๋ ๊ฒ์ฆ ์คํจ ์ ์ ์ ํ ์ฌ์์ฑ์ ํตํ ์์ ์ฑ ํฅ์, ์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ ์ ํตํ ํ์ง ๊ฐ์ , ๊ทธ๋ฆฌ๊ณ ์ฐฝ์์ ์์ฒญ (ํ ๋ง๊ฐ ์๋ ๋ฌธ์ ) ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ด ์ถ๊ฐ๋์์ต๋๋ค.
์ฃผ์ ์ฑ๊ณผ
-
์์ ์ฑ ํฅ์: ๊ฒ์ฆ ์คํจ ์ ์๋์ผ๋ก โPassโ๋ฅผ ๋ฐํํ๋ fallback ๋ก์ง์ ์ ๊ฑฐํ๊ณ , ์ง๋ฅ์ ์ธ ์ฌ์์ฑ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํ์ฌ ๋ถ์ ํํ ๊ฒฐ๊ณผ๊ฐ ํต๊ณผ๋๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
-
ํ์ง ๊ฐ์ : ๊ฐ ์์ฑ ๋จ๊ณ์์ ํ์ง ๊ฒ์ฆ ํจ์๋ฅผ ๋์ ํ๊ณ , ๊ตฌ์ฒด์ ์ธ ํผ๋๋ฐฑ์ ๊ธฐ๋ฐ์ผ๋ก ๊ด๋ จ ์ปดํฌ๋ํธ๋ง ์ ํ์ ์ผ๋ก ์ฌ์์ฑํ๋ ์์คํ ์ ๊ตฌ์ถํ์ต๋๋ค.
-
์ฐฝ์์ฑ ์ง์: ํ ๋ง๊ฐ ์๋ ์ฐฝ์์ ์์ฒญ์ ์ดํดํ๊ณ ์ ์ ํ ๋ฐ์ํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ์ต๋๋ค.
-
ํ์ฅ์ฑ: ๋ชจ๋์ ์ํคํ ์ฒ์ ์ฒด๊ณ์ ์ธ ํผ๋๋ฐฑ ์์คํ ์ ํตํด ํฅํ ์ถ๊ฐ ๊ธฐ๋ฅ ๊ฐ๋ฐ๊ณผ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถํ์ต๋๋ค.
๊ธฐ์ ์ ํ์
- ์ง๋ฅ์ ํผ๋๋ฐฑ ์์คํ
:
regenerateBasedOnValidationFeedback()
์analyzeFeedbackAndDetermineActions()
ํจ์๋ฅผ ํตํ ๋ง์ถคํ ์ฌ์์ฑ - ์ฐฝ์์ ์ปจํ ์คํธ ์ฒ๋ฆฌ: Intent Analysis์ Description Generation ๊ฐ์ ํตํฉ๋ ํ ๋ง ์ฒ๋ฆฌ
- ํ์ง ๋ณด์ฆ: ๊ฐ ๋จ๊ณ๋ณ ํ์ง ๊ฒ์ฆ ํจ์๋ฅผ ํตํ ์ฌ์ ๊ฒ์ฆ ๋ฐ ๊ฐ์
- ์คํ ๊ธฐ๋ฐ ๊ฒ์ฆ: ์ค์ ์ฝ๋ ์คํ์ ํตํ ์ ํํ ํ ์คํธ ์ถ๋ ฅ ์์ฑ
ํฅํ ์ ๋ง
Problem Generator V3๋ ํ์ฌ์ ๊ฐ์ ์ฌํญ์ ๋ฐํ์ผ๋ก ๋ค์ค ์ธ์ด ์ง์, ๊ฐ์ธํ๋ ๋ฌธ์ ์์ฑ, ์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ฑ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ผ๋ก ํ์ฅ๋ ์์ ์ ๋๋ค. ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง๊ณผ ํผ๋๋ฐฑ์ ํตํด ๋์ฑ ์ ํํ๊ณ ์ฐฝ์์ ์ธ ๋ฌธ์ ์์ฑ ์๋น์ค๋ก ๋ฐ์ ํด ๋๊ฐ ๊ฒ์ ๋๋ค.
์ด ๋ฌธ์๋ Problem Generator V3์ ํ์ฌ ์ํ์ ์ต์ ๊ฐ์ ์ฌํญ์ ์ข ํฉ์ ์ผ๋ก ๋ค๋ฃจ๋ฉฐ, ๊ฐ๋ฐ์๋ค์ด ์์คํ ์ ์ดํดํ๊ณ ํ์ฉํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ถ๊ฐ์ ์ธ ์ง๋ฌธ์ด๋ ๊ฐ์ ์ ์์ด ์์ผ์๋ฉด ํ๋ก์ ํธ ํ์ ๋ฌธ์ํด ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
๋ฌธ์ ๋ฒ์ : 2.0 (Updated for V3 Improvements)
์ต์ข
์
๋ฐ์ดํธ: 2025๋
1์ 20์ผ
์์ฑ์: ALPACO ๊ฐ๋ฐํ