*์์ : ๊ทธ๋ฅ LLM์ด ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด๋ฅผ ์ดํดํด์ฃผ๋ฉด ์ ๋ ๊น? ๋ฒ๋ค๋ง์ ํตํ RAG ์๋* # ๋ชฉ์ฐจ 1. [๊ฐ์](#๊ฐ์) 1. [๋ฐฐ๊ฒฝ์ง์](#๋ฐฐ๊ฒฝ์ง์) - [โ์ฝ๋๋ฒ ์ด์คโ๋?](#์ฝ๋๋ฒ ์ด์ค) - [LLM์ด ๋ฐฉ๋ํ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ดํดํ๋ ค๋ฉด](#LLM_์ฝ๋๋ฒ ์ด์ค) - [RAG์ ํ์์ฑ](#RAG) 1. [๊ฐ์ค](#๊ฐ์ค) 1. [๊ฐ์ค ๊ฒ์ฆ](#๊ฐ์ค๊ฒ์ฆ) 1. [๊ฒ์ฆ ๋ฐฉ๋ฒ](#๊ฒ์ฆ๋ฐฉ๋ฒ) - [๋ฒ๋ค๋ง์ด๋?](#๋ฒ๋ค๋ง์ด๋) 1. [ํ ์คํธ ์ค๊ณ](#ํ ์คํธ์ค๊ณ) 1. [๋ฒ๋ค๋ง ์ (์๋ณธ ์ฝ๋๋ฒ ์ด์ค)](#๋ฒ๋ค๋ง์ ) 1. [๋ฒ๋ค๋ง ํ (LLM์๊ฒ ์ ๋ฌํ ๋ด์ฉ)](#๋ฒ๋ค๋งํ) 1. [ํ ์คํธ 1: ChatGPT๋ฅผ ํตํ API ๋ฌธ์ ์์ฑ](#ํ ์คํธ1) - [ํ ์คํธ 1 ๊ฒฐ๊ณผ: ChatGPT๋ฅผ ํตํ API ๋ฌธ์ ์์ฑ](#ํ ์คํธ1๊ฒฐ๊ณผ) - [๋์กฐ๊ตฐ๊ณผ์ ๋น๊ต](#ํ ์คํธ1๋น๊ต) 1. [ํ ์คํธ 2: ChatGPT๋ฅผ ํตํ ๋งค๋ด์ผ ์์ฑ](#ํ ์คํธ2) - [ํ ์คํธ 2 ๊ฒฐ๊ณผ: ChatGPT๋ฅผ ํตํ ๋งค๋ด์ผ ์์ฑ](#ํ ์คํธ2๊ฒฐ๊ณผ) 1. [ํ๊ณ์ ](#ํ๊ณ์ ) - [ChatGPT์์ ํ์ฉ์ ๊ดํ ํ๊ณ์ ](#ChatGPTํ๊ณ์ ) - [๋ฒ๋ค๋ง์ ๊ดํ ํ๊ณ์ ](#๋ฒ๋ค๋งํ๊ณ์ ) 1. [๋ฐ๊ฒฌ](#๋ฐ๊ฒฌ) - [์ ํต์ ์ธ ๋๊ตฌ๋ฅผ ์จ์ RAG๋ฅผ ์ฑ์ทจํ๋ค๋ ์ ](#์ ํต์ ) - [๋ค๋ฅธ ์ธ์ด๋ก ์์ฑ๋ ์ฝ๋๋ฒ ์ด์ค์ ๋ํ ์ผ๋ฐํ ๊ฐ๋ฅ์ฑ](#์ผ๋ฐํ) - [Semantic search์์ ์๋์ง](#๋ค๋ฅธ๋ฐฉ๋ฒ๊ณผ์๋น๊ต) 1. [๊ฒฐ๋ก ](#๊ฒฐ๋ก ) 1. [์ ๋ฐ์ดํธ (2025-04-23)](#์ ๋ฐ์ดํธ1) <div id="๊ฐ์"> # ๊ฐ์ </div> ์ด ๊ธ์์๋ ๋ง์ ํ์ผ์ ๋ดํฌํ๋ ํน์ TypeScript ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ฒ๋ค๋ง(bundling)์ ํตํด 1๊ฐ์ JavaScript ํ์ผ๋ก ์์ถํ ํ LLM์๊ฒ ์ ๋ฌํ์์ ๋, LLM์ด ์ฝ๋๋ฒ ์ด์ค์ ๊ด๋ จ๋ ์ง๋ฌธ์ ์ผ๋ง๋ ์ ํํ๊ฒ ๋ต๋ณํ ์ ์๋์ง ํ์ธํ ๊ฒ์ด๋ค. ์ํํธ์จ์ด ์์คํ ๋ถ์[^software_analysis_static] [^software_analysis_dynamic]์ ์ํด์๋ ์ฝ๋๋ฒ ์ด์ค์ ์์ฑ๋ ํ์ผ๋ค์ โ๋ฐฉ๋ฌธโํ๋ ๊ฒ์ด ํ์์ ์ด๋ค. ์๋ฅผ ๋ค์ด, ๋น์ฆ๋์ค ๋ก์ง์ ๊ดํ ์ง๋ฌธ์ LLM์ด ๋๋ตํ๊ธฐ ์ํด์๋, LLM์ ๊ทธ ๋น์ฆ๋์ค ๋ก์ง๊ณผ ๊ด๋ จ๋ ๋ชจ๋ ํ์ผ์ ์ฝ์ ์ ์์ด์ผ ํ๋ค[^rag]. ํํธ, ์ฝ๋๋ฒ ์ด์ค๋ ์ผ์ข ์ ๋น์ ํ ๋ฐ์ดํฐ์ ๋ชจ์์ผ๋ก ๋ณผ ์ ์๋๋ฐ, LLM์ด ๋น์ ํ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ํ๋ ์ผ๋ฐํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฟ ์กด์ฌํ๋ค [^semantic_search] [^chatgpt_fileupload]. ์ด ๊ธ์์๋ ์ฝ๋๋ฒ ์ด์ค๋ฅผ RAGํ๊ธฐ ์ํ ํ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก์จ ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด๋ฅผ ์์ถํ ํ LLM์๊ฒ ์ ๊ณตํ๋ ๊ฒ์ ์๋ํ ๊ฒ์ด๋ค. [^software_analysis_static]: ์ ์ ๋ถ์์ ์ํ๋ ์: ํธ์ถ ๊ทธ๋ํ ์์ฑ์ ํตํ ์ ์ด ํ๋ฆ ํ์ & ์ฐ์ ์์ ํ์ธ, (์น ์๋ฒ์ ๊ฒฝ์ฐ) โ์ปจํธ๋กค๋ฌโ ์ฝ๋๋ฅผ ์์์ผ๋ก ๋ถ์ ์งํ, ์ฝ๋๋ฒ ์ด์ค์ ์ด๋ฏธ ๋์ ๋ ์ํคํ ์ณ ํจํด์ด ๋ฌด์์ธ์ง ํ์ ํ ํ, ์ฐ์ญ์ ์ถ๋ก ์ ํตํ ๋ถ์ ๋ฐฉ๋ฒ ์๋ฆฝ. [Wikipedia: Call graph](https://en.wikipedia.org/wiki/Call_graph) [^software_analysis_dynamic]: ๋์ ๋ถ์์ ์ํ๋ ์: ํตํฉ ํ ์คํธ ๊ณผ์ ์์ ํธ์ถ๋๋ ์ฝ๋์ ๊ทธ๋ ์ง ์์ ์ฝ๋๋ฅผ ๋ถ๋ฅํ์ฌ ๊ฐ ์ฝ๋๊ฐ ๊ด๊ณ๋ฅผ ํ์ . [Wikipedia: Runtime verification](https://en.wikipedia.org/wiki/Runtime_verification) [^rag]: LLM ๋ชจ๋ธ์ ์ง์์ ๋น ๋ฅด๊ฒ ์ถ๊ฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก Retrieval-augmented generation(RAG)๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ค. [Wikipedia: Retrieval-augmented generation](https://en.wikipedia.org/wiki/Retrieval-augmented_generation) [^semantic_search]: ์๋ฏธ๋ก ์ ๊ฒ์ ๊ธฐ๋ฒ. [Wikipedia: Semantic_search](https://en.wikipedia.org/wiki/Semantic_search) [^chatgpt_fileupload]: [OpenAI: "How does the new file uploads capability work? "](https://help.openai.com/en/articles/8555545-file-uploads-faq) - ChatGPT์ ํ์ผ ์ ๋ก๋(File Upload)๋ ์ ์ฒ๋ฆฌ, ๋ณํ, ์ถ์ถ์ ๊ฑฐ์ณ ์ ๋ณด๋ฅผ ์ ์ ํ๋ค. ์๋ฅผ ๋ค์ด Word ๋ฌธ์๋ฅผ ์ฝ์ ๋์๋ ์๊ณ ๋ฆฌ์ฆ์ ์ผ๋ก ๋ฏธ๋ฆฌ ํด์ํ๊ณ ๋ฌธ์์ ์ ๋ชฉ/๋ถ์ ๋ชฉ๋ค์ ์ถ์ถํ์ฌ ๋ฉํ๋ฐ์ดํฐ๋ก ํ์ฉํ๋ค. <div id="๋ฐฐ๊ฒฝ์ง์"></div> # ๋ฐฐ๊ฒฝ์ง์ <div id="์ฝ๋๋ฒ ์ด์ค"></div> ## โ์ฝ๋๋ฒ ์ด์คโ๋?  *์ฌ์ง: ๋ฆฌ๋ ์ค ์ฝ๋๋ฒ ์ด์ค* ํ ์ํํธ์จ์ด๋ฅผ ์ด๋ฃจ๋ ์์ค ์ฝ๋ ํ์ผ์ ๋ชจ์์ ์ฝ๋๋ฒ ์ด์ค๋ผ๊ณ ํ๋ค. ์ํํธ์จ์ด์ ๊ธฐ๋ฅ์ด ๋ง์์๋ก, ์ฝ๋๋ฒ ์ด์ค๋ ์์ฐ์ค๋ฝ๊ฒ ๋ฐฉ๋ํด์ง๋ค. <div id="LLM_์ฝ๋๋ฒ ์ด์ค"></div> ## LLM์ด ๋ฐฉ๋ํ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ดํดํ๋ ค๋ฉด ์ฝ๋๋ฒ ์ด์ค์ ๊ด๋ จ๋ ์์ ์ LLM์ด ์ฒ๋ฆฌํด์ค ์ ์์๊น? - โ๋ก๊ทธ์ธ ํ์ด์ง์ ๋ฒํผ์ ์ถ๊ฐํด์คโ - โ์์ค์ฝ๋์์ 'ํด๋ฉด ๊ณ์ '๊ณผ ๊ด๋ จ๋ ๋ก์ง์ ์ ๊ฑฐํด์คโ - โ์ค๋ ์์ ํ ์ฝ๋๋ค์ ๋ํด ๋จ์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํด์คโ - โ์ด ํด๋์ ๋ค์ด์๋ ์์ค์ฝ๋๋ค์ ํ ๋ฒ ๊ฒํ ํด์คโ ๋น์ฐํ๊ฒ๋ ์ฝ๋๋ฒ ์ด์ค๋ฅผ LLM์๊ฒ ์ ๋ฌํ๋ฉด ๋ ๊ฒ์ด๋ค. ํ์ง๋ง ์ฝ๋๋ฒ ์ด์ค๊ฐ ๋ฐฉ๋ํ ์๋ก ๊ณ ๋ คํ ์ ์ด ๋์ด๋๋ค. - LLM์ด ํ ๋ฒ์ ๋ฐ์๋ค์ผ ์ ์๋ ์ ๋ณด์ ์์ LLM๋ง๋ค ๋ค๋ฅด๋ค. ๊ทธ๋ฆฌ๊ณ ๋ ๋ง์ ์ ๋ณด๋ฅผ ์ ๋ฌํ ์๋ก ๋น์ฉ์ด ๋ ๋ง์ด ๋ถ๊ณผ๋๋ค. - ์ค์ฌ LLM์ด ๋ฐ์๋ค์ผ ์ ์๋ ์์ด ๋ฌด์ ํ์ด๋๋ผ๋, ์ฐ๋ฆฌ๋ ๊ทธ ๋ฐฉ๋ํ ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด๋ฅผ ๋คํธ์ํฌ๋ฅผ ํตํด ์ ๋ถ ์ ๋ฌํด์ผ ํ๋ ๋ฒ๊ฑฐ๋ก์์ ๋ถ๋ดํด์ผ ํ ๊ฒ์ด๋ค. ์ด๊ฒ์ ๋น๋จ ์ฝ๋๋ฒ ์ด์ค๋ง์ ๋ฌธ์ ๋ ์๋๋ค. LLM์ ํตํด ๋ฐฉ๋ํ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌ์ํค๊ธฐ ์ํด์๋ ๋ฐ๋์ ํด๊ฒฐํด์ผ ํ๋ ๋ฌธ์ ์ด๋ค. <div id="RAG"></div> ## RAG์ ํ์์ฑ  *์ฌ์ง: RAG์ ์ ์ฐจ* ๋ฐฉ๋ํ ์ง์์ LLM์๊ฒ ์๋ ค์ฃผ๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ก **RAG**(Retrieval-Augmented Generation)๊ฐ ์๋ค. RAG๋ฅผ ๊ตฌํํ๋ ์๋จ ์ค ํ๋๋ก๋ semantic search๊ฐ ์๋ค. ์ฝ๊ฒ ๋งํ์๋ฉด ์ ์ฌ๋ ๊ฒ์์ ํตํ ์ง์ ์ ํ์ด๋ค. ์๋ต์ ์์ฑํ๊ธฐ ์ ์ ์ง์ ๋ฒ ์ด์ค์์ โ์ง๋ฌธ๊ณผ ๊ด๋ จ๋์์ ํ๋ฅ ์ด ๋์ ์ ๋ณด๋ค๋ง ์ฟผ๋ฆฌโํ์ฌ LLM์๊ฒ ์ ๋ฌํ๋ค. ์ง๋ฌธ๋ง๋ค ํ์ํ ์ง์๋ง์ ์ถ๋ ค์ ๋ต๋ณ์ ๋ฐ์ํ๋ ๊ฒ์ด๋ค. ํ์ง๋ง, ๋ฐ์ดํฐ๋ฒ ์ด์คํ๋ฅผ ์๋ฌด๋ฆฌ ์ ํ๋๋ผ๋, ์ํ๋ ์ง์์ด ์ ๋๋ก ์กฐํ๋์ง ์๋๋ค๋ฉด ๊ฒฐ๊ตญ ๋ต๋ณ์ ํ์ง์ด ๋จ์ด์ง ๊ฒ์ด๋ค. ์ฆ, RAG ์์คํ ์ ๊ตฌ์ถํ์ฌ LLM์ ์๋ต ํ์ง์ ๋์ผ ์ ์์ง๋ง, ์ง์์ ์ ์ ํ๊ฒ ์ ๊ณตํด์ผ ํ๋ ๊ฒ์ ๋ณ์น ์๋๋ค. RAG ๋ฐฉ๋ฒ๋ก ์ ์ง๊ธ๋ ์๋กญ๊ฒ ์ฐ๊ตฌ๋๊ณ ์๋ค. <div id="๊ฐ์ค"></div> # ๊ฐ์ค **์ฝ๋๋ฒ ์ด์ค๋ฅผ (LLM์ด ํ์ฉํ๋ ์ ์์) ํต์งธ๋ก ์ ๋ฌํ ์ ์๋ค๋ฉด, ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด์ ๋ํ ์ ์๋ฏธํ RAG๋ฅผ ๋น๊ต์ ์ฝ๊ฒ ์ฑ์ทจํ ์ ์์ ๊ฒ์ด๋ค.** ์ด๋ฌํ RAG์ ์ฅ์ ์ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ด๋ค. - RAG๋ฅผ ๊ตฌํํ๊ธฐ ์ํด โ๊ฒ์ ์์คํ โ์ ๋ฐ๋์ ๊ตฌํํ์ง ์์๋ ๋๋ค. - ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด์ ๋ํ ๋ฌธ๋งฅ์ ํ๋ณดํ ์ ์์ด, ์ง๋ฌธ์๊ฐ ๊ณ ๋ คํ์ง ๋ชปํ ๋ถ๋ถ์ ๋ํด์๋ LLM์ด ํ์ ํด์ค ์ ์๋ค. ํด๊ฒฐํด์ผ ํ๋ ๋ถ๋ถ์ ์๋์ ๊ฐ์ ๊ฒ์ด๋ค. - ์ฝ๋๋ฒ ์ด์ค๋ฅผ โ์์ถ'ํด์ผ ํ๋ค. - ๋ฌด์์ค ์์ถ์ ์ฌ์ค์ ๋ถ๊ฐ๋ฅํ๊ธฐ์, ์ ๋ณด ์์ค์ ๊ฐ์ํ๊ณ ์์ถ์ ์๋ํด์ผ ํ๋ค. - ์์ถ ๋ฐฉ๋ฒ์ ์ผ๋ฐํ๊ฐ ๊ฐ๋ฅํด์ผ ํ๋ค. <div id="๊ฐ์ค๊ฒ์ฆ"></div> # ๊ฐ์ค ๊ฒ์ฆ <div id="๊ฒ์ฆ๋ฐฉ๋ฒ"></div> ## ๊ฒ์ฆ ๋ฐฉ๋ฒ ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด๋ฅผ LLM์ RAGํ๊ธฐ ์ํ ์์ถ ๋ฐฉ๋ฒ์ผ๋ก์จ ๋ฒ๋ค๋ง์ ์ฌ์ฉํ๊ณ ์ ํ๋ค. ๋ง์ ํ์ผ์ ๋ดํฌํ๋ TypeScript ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ฒ๋ค๋ง์ ํตํด 1๊ฐ์ JavaScript ํ์ผ๋ก ์์ถํ ํ LLM์๊ฒ ์ ๋ฌํ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ , LLM์ด ์ฝ๋๋ฒ ์ด์ค์ ๊ด๋ จ๋ ์ง๋ฌธ์ ์ผ๋ง๋ ์ ํํ๊ฒ ๋ต๋ณํ ์ ์๋์ง ํ์ธํ ๊ฒ์ด๋ค. <div id="๋ฒ๋ค๋ง์ด๋"></div> ### ๋ฒ๋ค๋ง์ด๋?  TypeScript/JavaScript ์ธ์ด ์ง์์์์ โ๋ฒ๋ค๋งโ(bundle, bundling)์ ์ฝ๋๋ฒ ์ด์ค ์์ ์์ฑ๋์ด ์๋ ์ฌ๋ฌ ์์ค ํ์ผ๋ค์ ๋จ ๋ช ๊ฐ์ ์์ค ํ์ผ๋ก ์ฎ๋ ํ์๋ฅผ ๋ปํ๋ค. ๋ฒ๋ค๋ง์ ํน์ง: - ์ฃผ์, Dead Code, ํ ์คํธ ์ฝ๋ ๋ฑ ๋น์ฆ๋์ค ๋ก์ง๊ณผ ๊ด๊ณ์๋ ๊ฒ๋ค์ ์ ์ธ๋ ์ฝ๋๊ฐ ๋์ถ๋๋ค. ๊ทธ๋ผ์๋ ๋์์ ๋์ผ์ฑ์ด ๋ณด์ฅ๋๋ค. - ๋ฐฉ๋ํ ์์กด์ฑ ํจํค์ง๋ค(์: node_modules)์ ์ ๋ถ ๋ชจ์ ํ ํ์ผ์ ํฌํจ์ํจ๋ค. - Syntactic sugar๋ฅผ ์ ๊ทน ํ์ฉํ์ฌ ์ฝ๋๋ฅผ ์งง๊ฒ ์ค์ธ๋ค. <div id="ํ ์คํธ์ค๊ณ"></div> ## ํ ์คํธ ์ค๊ณ ๋ฒ๋ค๋ง์ ์ํด ์ฌ์ฉํ ์ค์ [^esbuild_config]์ ์๋์ ๊ฐ๋ค. [^esbuild_config]: ์ด์ ์ ์์ฑํ ์ ์ด ์๋ esbuild ๋น๋ ์ค์ ์ ์กฐ๊ธ ์์ ํ์ฌ ๊ทธ๋๋ก ์ฌ์ฉํ์๋ค. ์๋ณธ์ GitHub์์ ํ์ธ ๊ฐ๋ฅํ๋ค. [GitHub: build-option.ts](https://github.com/atjsh/mini-dice-v1/blob/main/builders/server/src/lib/build-option.ts) ``` const projectRoot = path.resolve(process.cwd(), "..", ".."); const commonBuildOptions = { entryPoints: [ { in: `${projectRoot}/apps/server/src/main.ts`, out: "index" } ], tsconfig: `${projectRoot}/apps/server/tsconfig.json`, format: "esm", platform: "node", target: "node19", outExtension: { ".js": ".mjs" }, legalComments: "none", banner: { /** https://github.com/evanw/esbuild/issues/1921#issuecomment-1152991694 */ js: "import{createRequire}from'module';const require=createRequire(import.meta.url);" + "import{fileURLToPath}from'node:url';import{dirname as __pathDirname}from'node:path';const __filename=fileURLToPath(import.meta.url);const __dirname=__pathDirname(__filename);" }, charset: "utf8", plugins: [ esbuildDecorators({ tsconfig: `${projectRoot}/apps/server/tsconfig.json` }), esbuildProgressPulgin() ] } satisfies esbuild.BuildOptions; await esbuild.build({ ...commonBuildOptions, outdir: `${projectRoot}/apps/server/dist/bundle-minify-nokeepnames-package-external`, bundle: true, minify: true, keepNames: false external: [ "@fastify/aws-lambda", "@fastify/cookie", "@fastify/helmet", "@nestjs/axios", "@nestjs/common", "@nestjs/config", "@nestjs/core", "@nestjs/jwt", "@nestjs/passport", "@nestjs/platform-fastify", "@nestjs/typeorm", "aws-lambda", "axios", "class-transformer", "class-validator", "fastify", "joi", "jsonwebtoken", "lodash", "passport", "passport-jwt", "pg", "reflect-metadata", "rxjs", "typeorm", "uuid" ], } satisfies esbuild.BuildOptions); ``` ์ธ๋ถ ํจํค์ง๋ค์ ๋ฒ๋ค๋์ง ์๋๋ก ํ๊ณ , ์์ค์ฝ๋ ๋ด๋ถ ์ฝ๋๋ง ๋ฒ๋ค๋๋๋ก ์ค์ ํ์๋ค. ํ ์คํธ ํ๊ฒฝ: - ํ ์คํธ ๋์ ์ฝ๋๋ฒ ์ด์ค: TypeScript๋ก ์์ฑ๋ Node.js ๋ฐํ์์ฉ ์น ์๋ฒ[^source] - ๋ฒ๋ค๋ง ์๋จ: [esbuild](https://esbuild.github.io/getting-started/#bundling-for-node)๋ก minified bundle 1ํ ์งํ - LLM: OpenAI o3-mini ๋ชจ๋ธ [^price] [^source]: [GitHub: atjsh/mini-dice-v1](https://github.com/atjsh/mini-dice-v1), [Mini Dice ์๊ฐ](https://blog.atj.sh/post/8) [^price]: o3-mini๋ OpenAI์์ ์ ๊ณตํ๋ ๊ฐ์ฅ ์ ๋ ดํ LLM ์ค ํ๋์ด๋ค. [OpenAI Pricing](https://platform.openai.com/docs/pricing) <div id="๋ฒ๋ค๋ง์ "></div> ## ๋ฒ๋ค๋ง ์ (์๋ณธ ์ฝ๋๋ฒ ์ด์ค) - ์ฝ๋ ์ค: ์ฝ 15,000์ฌ์ค์ TypeScript - ํ์ผ ๊ฐ์: ์ฝ 300์ฌ๊ฐ - ์์ค ์ฝ๋ ํฌ๊ธฐ: ์ฝ 2MB - ์ธ๋ถ ํจํค์ง๋ค์ ํฌํจํ ์์ค ์ฝ๋ ํฌ๊ธฐ: ์ฝ 1GB [^node_modules] [^node_modules]: devDependencies์ ์ํ๋ ํจํค์ง ํฌํจ. <div id="๋ฒ๋ค๋งํ"></div> ## ๋ฒ๋ค๋ง ํ (LLM์๊ฒ ์ ๋ฌํ ๋ด์ฉ)  *์ฌ์ง: ์ฝ๋๋ฒ ์ด์ค ํ์ผ ์ ์ฒด๋ฅผ JavaScript ํ์ผ 1๊ฐ๋ก ์์ถํ ๊ฒฐ๊ณผ๋ฌผ* :img[]{src="https://blog.atj.sh/post-attachments/v/01962f1c-6f8c-71b1-8d27-941610085bf6" .half}:img[]{src="https://blog.atj.sh/post-attachments/v/01962f1c-81f0-7a13-b083-8c9b3f68bc52" .half} - *์ผ์ชฝ ์ฌ์ง: ํ ํฐ ๊ฐ์ ๊ณ์ฐ ๊ฒฐ๊ณผ* - *์ค๋ฅธ์ชฝ ์ฌ์ง: ํ์ผ ์ ๋ณด* ๋ฒ๋ค๋ง ํ ์ฝ๋๋ฒ ์ด์ค๋ ๋ค์๊ณผ ๊ฐ์ด ์์ถ๋์๋ค. - ๋ฌธ์์: 239,143๊ฐ - ํ ํฐ ๊ฐ์: ์ฝ 76,706๊ฐ - ํ์ผ ํฌ๊ธฐ: 248KB - ํ์ผ ๊ฐ์: 1๊ฐ <div id="ํ ์คํธ1"></div> ## ํ ์คํธ 1: ChatGPT๋ฅผ ํตํ API ๋ฌธ์ ์์ฑ **์ฝ๋๋ฒ ์ด์ค๋ฅผ ์์ถํ ํ์ผ 1๊ฐ๋ง ์์ด๋, ChatGPT๊ฐ Swagger API ๋ฌธ์๋ฅผ ์์ฑํ ์ ์์๊น?**  *์ค์จ๊ฑฐ(Swagger)๋ ๊ฐ๋ฐ์๊ฐ REST ์น ์๋น์ค๋ฅผ ์ค๊ณ, ๋น๋, ๋ฌธ์ํ, ์๋นํ๋ ์ผ์ ๋์์ฃผ๋ ์คํ ์์ค ์ํํธ์จ์ด ํ๋ ์์ํฌ์ด๋ค.* **ํ ์คํธ ์ ์ฐจ** 1. ๋ฒ๋ค ์์ฑ 2. ์์ถ๋ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์๋ ํ๋กฌํํธ ์์ ํ ์คํธ๋ก ์ฒจ๋ถ 3. ChatGPT์ ์ ๋ฌ **ํ๋กฌํํธ** ``` Rules: - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF RFC 2119 (https://datatracker.ietf.org/doc/html/rfc2119). Context: - [index.mjs] is a bundled JavaScript code of a TypeScript codebase. - [index.mjs] was generated by esbuild to reduce size and remove unnecessary contents. - [index.mjs] keeps every business logic that original codebases implements. Request: - Create a OpenAPI Specification 3.0 content based on [filename]. And, response the specification's content only. Requirements: - The result MUST be in JSON format. - The result MUST include every HTTP API and it's HTTP Method as path information. - The result SHOULD include security, schema, response information for each API. - The result MAY include tag information for each API. `package.json`'s content: (์ฝ๋๋ฒ ์ด์ค์์ ์ฐ์ธ ์์กด์ฑ ๋ชฉ๋ก) `index.mjs`'s content: (๋ฒ๋ค๋ ์ฝ๋ ๋ด์ฉ) Response: ``` <div id="ํ ์คํธ1๊ฒฐ๊ณผ"></div> ## ํ ์คํธ 1 ๊ฒฐ๊ณผ: ChatGPT๋ฅผ ํตํ API ๋ฌธ์ ์์ฑ **๋๋ถ๋ถ์ ์๋์์ 21๊ฐ ์๋ํฌ์ธํธ ์ค 19๊ฐ ์ด์์ ์๋ํฌ์ธํธ๋ฅผ ์ ํํ๊ฒ ๋ฌธ์ํํ๋ ๋ฐ ์ฑ๊ณตํ๋ค.** ์๋ํฌ์ธํธ๊ฐ ํฌํจ๋ API ๋ฌธ์๋ YAML ํ์ ์ค๋ฅ ์์ด ์์ฑ๋์์ผ๋ฉฐ, URL, Method ์ ๋ณด๊ฐ ์ ํํ๊ฒ ๊ธฐ์ฌ๋์๋ค. :img{src="https://blog.atj.sh/post-attachments/v/01962f75-a787-7ad3-a71f-e5561556d0b5"} *์ฌ์ง: ChatGPT๊ฐ ์์ฑํ Swagger API ๋ฌธ์๋ฅผ [https://editor.swagger.io](https://editor.swagger.io/)์์ ํ์ธํ ๋ชจ์ต* <div id="ํ ์คํธ1๋น๊ต"></div> ### ๋์กฐ๊ตฐ๊ณผ์ ๋น๊ต ChatGPT๋ฅผ ํตํด ์์ฑํ API ๋ฌธ์๊ฐ ์ผ๋ง๋ ์ฌ์ค์ ๊ฐ๊น์ด์ง ํ์ธํ๊ธฐ ์ํด, ์น ํ๋ ์์ํฌ์์ ์์ฒด์ ์ผ๋ก ์์ฑํ Swagger ๋ด์ฉ๊ณผ ๋น๊ตํ์๋ค. #### ๋์กฐ๊ตฐ <details> <summary> ์น ํ๋ ์์ํฌ์์ ์์ฒด์ ์ผ๋ก ์์ฑํ Swagger ํ์ผ ํ์ธํ๊ธฐ </summary> [์น ํ๋ ์์ํฌ์์ ์์ฒด์ ์ผ๋ก ์์ฑํ Swagger ํ์ผ ๋ค์ด๋ก๋ (yaml)](https://blog.atj.sh/post-attachments/v/01962fb2-ea7d-7aa0-bbb9-bc6a004fca61) ```yaml openapi: 3.0.0 paths: /: get: operationId: AppController_root parameters: [] responses: '200': description: '' tags: - App /ads.txt: get: operationId: AppController_adsTxt parameters: [] responses: '200': description: '' tags: - App /auth/access-token: get: operationId: AccessTokenController_getAccessToken parameters: [] responses: '200': description: '' tags: - AccessToken /auth/logout: post: operationId: LocalJwtController_logout parameters: [] responses: '201': description: '' tags: - LocalJwt get: operationId: LocalJwtController_logoutGet parameters: [] responses: '200': description: '' tags: - LocalJwt /auth/google-oauth/{web}: get: operationId: GoogleOAuthController_authUserWithGoogleOauthCode parameters: - name: code required: true in: query schema: type: string - name: web required: true in: path schema: type: string responses: '200': description: '' tags: - GoogleOAuth /temp-signup: post: operationId: TempSignupController_temporarySignUpUser parameters: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TemporarySignUpDto' responses: '201': description: '' tags: - TempSignup /frontend-error: post: operationId: FrontendErrorController_insert parameters: [] responses: '201': description: '' tags: - FrontendError /land-comments: post: operationId: UserLandCommentController_registerComment parameters: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Function' responses: '201': description: '' tags: - UserLandComment /land-events: get: operationId: LandEventController_getLandEvents parameters: [] responses: '200': description: '' tags: - LandEvent /profile/me: get: operationId: PublicProfileController_getProfile parameters: [] responses: '200': description: '' tags: - PublicProfile patch: operationId: PublicProfileController_updateUserById parameters: [] responses: '200': description: '' tags: - PublicProfile /profile/others: get: operationId: PublicProfileController_getOthersProfiles parameters: [] responses: '200': description: '' tags: - PublicProfile /profile/complete-signup: patch: operationId: PublicProfileController_completeSignup parameters: [] responses: '200': description: '' tags: - PublicProfile /profile: delete: operationId: PublicProfileController_terminateUser parameters: [] responses: '200': description: '' tags: - PublicProfile /user-interaction-web: post: operationId: UserInteractionWebController_makeUserInteractionAndGetWebMessageResponse parameters: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UserInteractionDto' responses: '201': description: '' tags: - UserInteractionWeb /dice-toss: post: operationId: DiceTossController_tossDiceAndGetWebMessageResponse parameters: [] responses: '201': description: '' tags: - DiceToss /recent-skill-logs: get: operationId: RecentSkillLogsController_getRecentSkillLogsWeb parameters: - name: limit required: true in: query schema: type: number responses: '200': description: '' tags: - RecentSkillLogs /scenarios/d1/map: get: operationId: D1Controller_getAliases parameters: [] responses: '200': description: '' tags: - D1 /health/detail: get: operationId: HealthController_readiness parameters: [] responses: '200': description: '' tags: - Health /health: get: operationId: HealthController_simple parameters: [] responses: '200': description: '' tags: - Health info: title: Cats example description: The cats API description version: '1.0' contact: {} tags: - name: cats description: '' servers: [] components: schemas: TemporarySignUpDto: type: object properties: {} Function: type: object properties: {} UserInteractionDto: type: object properties: {} ``` </details> #### o3-mini Generation <details> <summary> ChatGPT๊ฐ ์์ฑํ Swagger ํ์ผ ํ์ธํ๊ธฐ </summary> [ChatGPT๊ฐ ์์ฑํ Swagger ํ์ผ ๋ค์ด๋ก๋ (yaml)](https://blog.atj.sh/post-attachments/v/01962fbd-fd8d-75c2-a115-f39c9cd0c1ad) ```yaml openapi: "3.0.0" info: title: "Server API" version: "1.0.0" servers: - url: "https://example.com" description: "Primary server (update with actual URL)" components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT cookieAuth: type: apiKey in: cookie name: refreshToken schemas: ContactResponse: type: string example: "contact: lifegame2021team@gmail.com" AdsTxtResponse: type: string example: "ADS TXT content from configuration" TokenResponse: type: object properties: accessToken: type: string example: "eyJhbGciOiJIUzI1NiIsInR..." GenericResponse: type: object additionalProperties: true ErrorResponse: type: object properties: message: type: string paths: /: get: tags: - Root summary: "Get root contact info" responses: "200": description: "Contact information" content: application/json: schema: $ref: "#/components/schemas/ContactResponse" /ads.txt: get: tags: - Root summary: "Get ads.txt content" responses: "200": description: "ADS TXT content" content: text/plain: schema: $ref: "#/components/schemas/AdsTxtResponse" /auth/access-token: get: tags: - Auth summary: "Obtain a new access token using a valid refresh token" security: - cookieAuth: [] responses: "200": description: "Access token generated successfully" content: application/json: schema: $ref: "#/components/schemas/TokenResponse" "401": description: "Unauthorized โ invalid or missing credentials" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /auth/logout: post: tags: - Auth summary: "Logout user (POST)" security: - cookieAuth: [] responses: "200": description: "User successfully logged out" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" get: tags: - Auth summary: "Logout user (GET)" security: - cookieAuth: [] responses: "200": description: "User successfully logged out" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" /auth/google-oauth/{web}: get: tags: - Auth summary: "Authenticate user with Google OAuth" parameters: - in: path name: web required: true schema: type: string description: "A dynamic segment representing the web redirect path" - in: query name: code required: true schema: type: string description: "The OAuth authorization code returned by Google" responses: "200": description: "Google OAuth callback response" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "400": description: "Bad Request" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /temp-signup: post: tags: - Temp Signup summary: "Temporarily sign up a new user with hCaptcha verification" requestBody: required: true content: application/json: schema: type: object properties: hCaptchaSuccessToken: type: string username: type: string countryCode3: type: string required: - hCaptchaSuccessToken - username - countryCode3 responses: "200": description: "Temporary signup successful" content: application/json: schema: type: boolean example: true "400": description: "Bad Request โ invalid hCaptcha token or missing fields" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /land-events: get: tags: - Land Events summary: "Retrieve a list of recent land events" parameters: - in: header name: timezone schema: type: string required: false description: "Timezone identifier (e.g., 'Asia/Seoul')" security: - bearerAuth: [] responses: "200": description: "A list of land event summaries" content: application/json: schema: type: array items: $ref: "#/components/schemas/GenericResponse" "401": description: "Unauthorized" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /dice-toss: post: tags: - Dice Toss summary: "Toss dice and receive a gaming response message" requestBody: required: true content: application/json: schema: type: object properties: userId: type: string required: - userId security: - bearerAuth: [] responses: "200": description: "Dice toss result with game data" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "400": description: "Bad Request โ invalid input" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /profile/me: get: tags: - Profile summary: "Retrieve the authenticated user's profile information" security: - bearerAuth: [] responses: "200": description: "User profile data" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "401": description: "Unauthorized" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" patch: tags: - Profile summary: "Update the authenticated user's profile" security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: username: type: string countryCode3: type: string required: - username - countryCode3 responses: "200": description: "Profile updated successfully" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "400": description: "Bad Request โ validation errors" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /profile/others: get: tags: - Profile summary: "Retrieve profiles of other users" security: - bearerAuth: [] parameters: - in: query name: limit required: false schema: type: integer description: "Maximum number of profiles to return" - in: query name: page required: false schema: type: integer description: "Page number for pagination" - in: query name: updatedAfter required: false schema: type: string format: date-time description: "Filter profiles updated after this datetime" responses: "200": description: "List of other user profiles" content: application/json: schema: type: array items: $ref: "#/components/schemas/GenericResponse" "401": description: "Unauthorized" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /profile/complete-signup: post: tags: - Profile summary: "Complete the authenticated user's signup process" security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: countryCode3: type: string username: type: string required: - countryCode3 - username responses: "200": description: "Signup completed successfully" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "400": description: "Bad Request" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /profile: delete: tags: - Profile summary: "Terminate (delete) the authenticated user's account" security: - bearerAuth: [] responses: "200": description: "User account terminated successfully" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "401": description: "Unauthorized" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /recent-skill-logs: get: tags: - Skill Logs summary: "Retrieve recent skill logs for the authenticated user" security: - bearerAuth: [] parameters: - in: query name: limit required: false schema: type: integer description: "The maximum number of logs to retrieve" responses: "200": description: "A list of recent skill logs" content: application/json: schema: type: array items: $ref: "#/components/schemas/GenericResponse" "401": description: "Unauthorized" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /land-comments: post: tags: - Land Comments summary: "Register a comment on a land (game event)" security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: userId: type: string comment: type: string required: - userId - comment responses: "200": description: "Comment registered successfully" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "400": description: "Bad Request" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /scenarios/d1/map: get: tags: - Scenarios summary: "Retrieve skill group aliases for scenario D1" security: - bearerAuth: [] responses: "200": description: "A mapping of skill groups and their aliases" content: application/json: schema: type: object additionalProperties: true /user-interaction-web: post: tags: - User Interaction summary: "Perform a user interaction call to trigger a skill" security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: callingSkillRoute: type: string callingSkillParam: type: object required: - callingSkillRoute responses: "200": description: "Response from the user interaction call" content: application/json: schema: $ref: "#/components/schemas/GenericResponse" "400": description: "Bad Request" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /health/detail: get: tags: - Health summary: "Detailed health check" responses: "200": description: "Detailed health status" content: application/json: schema: type: string example: "OK" /health: get: tags: - Health summary: "Simple health check" responses: "200": description: "Simple health status" content: application/json: schema: type: string example: "m" security: - bearerAuth: [] ``` </details> <div id="ํ ์คํธ2"></div> ## ํ ์คํธ 2: ChatGPT๋ฅผ ํตํ ๋งค๋ด์ผ ์์ฑ **์ฝ๋๋ฒ ์ด์ค๋ฅผ ์์ถํ ํ์ผ 1๊ฐ๋ง ์์ด๋, ChatGPT๊ฐ ๋น์ฆ๋์ค ๋ก์ง์ ์ดํดํ๊ณ โ๋งค๋ด์ผโ์ ์์ฑํ ์ ์์๊น?** **ํ ์คํธ ์ ์ฐจ** 1. ํธ์๋ฅผ ์ํด ํ ์คํธ 1์์ ์ค๊ฐ ๋ํ๋ฅผ ๊ทธ๋๋ก ์ ์ง 2. ํ๋กฌํํธ ์ ๋ฌ **ํ๋กฌํํธ** ``` Generate manual for 'POST /temp-signup' endpoint. [for non-coder] 1. ELI5 for teammates who cannot code 2. runtime behavior 3. 'how dose it works' explanation - should include technical details 4. business logics 5. possible edge cases [for coder] 1. ELI5 for teammates who cannot code 2. runtime behavior 3. 'how dose it works' explanation - should include technical details 3.1. technical detail for framework and libraries 3.2. sequence diagram if possible 4. possible design pattern it implements 5. possible improvements 6. possible edge cases tone: no emoji, professional tone, literacy style each in markdown format one in english, one in korean. ``` <div id="ํ ์คํธ2๊ฒฐ๊ณผ"></div> ## ํ ์คํธ 2 ๊ฒฐ๊ณผ: ChatGPT๋ฅผ ํตํ ๋งค๋ด์ผ ์์ฑ **๋น๊ฐ๋ฐ์/๊ฐ๋ฐ์์ฉ ๋งค๋ด์ผ์ ๋์์ ์ฑ๊ณต์ ์ผ๋ก ์์ฑํ ์ ์์๋ค.** :img{src="https://blog.atj.sh/post-attachments/v/01962f7e-6c1c-7212-8ec9-47b14d773f16"} *์ฌ์ง: ChatGPT๊ฐ ์์ฑํด๋ธ ์ํ์ค ๋ค์ด์ด๊ทธ๋จ์ ํตํ ์์คํ ์ค๋ช * <details> <summary> "๋น๊ฐ๋ฐ์๋ฅผ ์ํ ๋งค๋ด์ผ" ์์ฑ๋ฌผ ํ์ธํ๊ธฐ </summary> POST /temp-signup ์๋ํฌ์ธํธ ๋งค๋ด์ผ (Korean) *๋น๊ฐ๋ฐ์๋ฅผ ์ํ ์ค๋ช * **1. ELI5 ์ค๋ช (์ฝ๋๋ฅผ ๋ชจ๋ฅด๋ ํ์์ ์ํ ์ค๋ช )** ์ด ์๋ํฌ์ธํธ๋ ์์ ์ฌ์ฉ์ ๊ณ์ ์ ์์ฑํฉ๋๋ค. hCaptcha๋ผ๋ ์ฌ๋์์ ํ์ธํ๋ ์ ์ฐจ(๋น๋ฐ ์ฝ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ฒ๊ณผ ๊ฐ์ ๋ฐฉ์)๋ฅผ ๊ฑฐ์ณ์, ์ด๋ฆ, ์ด๋ฉ์ผ, ๊ตญ๊ฐ ์ฝ๋ ๋ฑ์ ์ ๋ณด๋ฅผ ์ ์ถํ๋ฉด ์์๋ก ๊ณ์ ์ด ๋ง๋ค์ด์ง๊ณ , ๊ทธ ๊ณ์ ์ผ๋ก ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค. **2. ๋ฐํ์ ๋์** ์ฌ์ฉ์๊ฐ ํ์๊ฐ์ ์ ๋ณด๋ฅผ ์ ์กํ๋ฉด ์๋ฒ๋ ๋จผ์ hCaptcha ํ ํฐ์ ๊ฒ์ฌํ์ฌ ์ฌ์ฉ์๊ฐ ๋ก๋ด์ด ์๋๋ผ๋ ๊ฒ์ ํ์ธํฉ๋๋ค. ๊ทธ ํ, ์์ ์ฌ์ฉ์ ๊ณ์ ์ ์์ฑํ๊ณ , ์ฌ์ฉ์ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ ์ฟ ํค(๋ฆฌํ๋ ์ ํ ํฐ)๋ฅผ ์ค์ ํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก, ํ์๊ฐ์ ์ด ์ฑ๊ณตํ์์ true/false ๊ฐ์ผ๋ก ๋ฐํํฉ๋๋ค. **3. ๋์ ๋ฐฉ์ (๋์ ์์ค์ ์ค๋ช )** ์ ๋ ฅ ๊ฒ์ฆ: hCaptcha ํ ํฐ, ์ฌ์ฉ์ ์ด๋ฆ, ์ด๋ฉ์ผ, ๊ตญ๊ฐ ์ฝ๋ ๋ฑ ํ์ ํ๋๊ฐ ํฌํจ๋์ด ์๋์ง ํ์ธํฉ๋๋ค. ์ธ๊ฐ ์ฌ๋ถ ํ์ธ: hCaptcha ํ ํฐ์ ์ธ๋ถ hCaptcha ์๋น์ค์ ์ ์กํ์ฌ ์ฌ๋์ด ๋ง๋์ง ํ์ธํฉ๋๋ค. ๊ณ์ ์์ฑ: ๊ฒ์ฆ์ด ์ฑ๊ณตํ๋ฉด, ์์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค(๋๋ ๋ด๋ถ ์ ์ฅ์)์ ์ ์ฅํฉ๋๋ค. ์ฟ ํค ์ค์ : ์์ฑ๋ ๋ฆฌํ๋ ์ ํ ํฐ์ HTTP ์ ์ฉ ์ฟ ํค๋ก ์ค์ ํ์ฌ, ์ดํ ์ฌ์ฉ์๊ฐ ๊ณ์ ์ธ์๋ ์ ์๋๋ก ํฉ๋๋ค. ์๋ต: ํ์๊ฐ์ ์ฑ๊ณต ์ฌ๋ถ๋ฅผ ์๋ตํฉ๋๋ค. **4. ๋น์ฆ๋์ค ๋ก์ง** ์ฌ์ฉ์ ๊ฒ์ฆ: hCaptcha๋ฅผ ์ฌ์ฉํ์ฌ ์คํธ๊ณผ ์๋ ๊ฐ์ ์ ๋ฐฉ์งํฉ๋๋ค. ์์ ๊ณ์ ์์ฑ: ์ฌ์ฉ์๊ฐ ์ฆ์ ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์๋๋ก ์์ ๊ณ์ ์ ๋ง๋ค๋, ์ดํ์ ์ ์ ๊ฐ์ ์ ์ฐจ๊ฐ ์ถ๊ฐ๋ ์ ์์ต๋๋ค. ๋ณด์ ๊ด๋ฆฌ: ๋ฆฌํ๋ ์ ํ ํฐ์ ๋ณด์ ์ฟ ํค๋ก ๋ฐ๊ธํ์ฌ ์ธ์ ๋ณด์์ ๊ฐํํฉ๋๋ค. **5. ๊ฐ๋ฅํ ์ฃ์ง ์ผ์ด์ค** ์ ํจํ์ง ์์ hCaptcha ํ ํฐ: hCaptcha ํ ํฐ์ด ์๊ฑฐ๋ ์๋ชป๋ ๊ฒฝ์ฐ ํ์๊ฐ์ ์ด ๊ฑฐ๋ถ๋ฉ๋๋ค. ๋ถ์์ ํ ๋ฐ์ดํฐ: ์ฌ์ฉ์ ์ด๋ฆ, ์ด๋ฉ์ผ, ๊ตญ๊ฐ ์ฝ๋ ์ค ํ๋๋ผ๋ ๋น ์ง ๊ฒฝ์ฐ ์คํจํ ์ ์์ต๋๋ค. ์๋ฒ ์ค๋ฅ: ์ผ์์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ ๋คํธ์ํฌ ๋ฌธ์ ๋ก ์ธํด ์๊ธฐ์น ๋ชปํ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ค๋ณต ๊ฐ์ : ์ด๋ฉ์ผ์ด๋ ์ฌ์ฉ์ ์ด๋ฆ์ด ์ด๋ฏธ ์ฌ์ฉ ์ค์ธ ๊ฒฝ์ฐ ์ถ๊ฐ ๊ฒ์ฆ์ด ํ์ํ ์ ์์ต๋๋ค. </details> <details> <summary> "๊ฐ๋ฐ์๋ฅผ ์ํ ๋งค๋ด์ผ" ์์ฑ๋ฌผ ํ์ธํ๊ธฐ </summary> POST /temp-signup ์๋ํฌ์ธํธ ๋งค๋ด์ผ (Korean) *๊ฐ๋ฐ์๋ฅผ ์ํ ์ค๋ช * **1. ELI5 ์ค๋ช (์ฝ๋๋ฅผ ๋ชจ๋ฅด๋ ํ์์ ์ํ ์ค๋ช )** ํ์๊ฐ์ ๊ณผ์ ์ ํฐ์ผ ๋ถ์ค์ ๋น์ ํ๋ค๋ฉด, ์ฌ์ฉ์๋ hCaptcha๋ผ๋ ๋น๋ฐ ์ฝ๋๋ฅผ ์ ์ํ์ฌ ๋ก๋ด์ด ์๋์ ์ฆ๋ช ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ถ์ค์์๋ ์์ ํ์ ์นด๋๋ฅผ ๋ฐ๊ธํ๊ณ , ๋์ค์ ํด๋ฝ์ ๋ค์ ๋ฐฉ๋ฌธํ ์ ์๋๋ก ๋ธ๋ ์ด์ฌ๋ฆฟ(์ฟ ํค)์ ์ ๊ณตํฉ๋๋ค. **2. ๋ฐํ์ ๋์** POST ์์ฒญ์ด /temp-signup ๊ฒฝ๋ก๋ก ์ค๋ฉด, ์๋ฒ๋ JSON ํ์์ ํ์ด๋ก๋๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ์ ๋ ฅ๊ฐ์ด ๊ฒ์ฆ๋๊ณ , ์ธ๋ถ hCaptcha ์๋น์ค์์ hCaptcha ํ ํฐ์ ํ์ธํ ํ, ์์ ์ฌ์ฉ์ ๋ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. ์ดํ, ๋ณด์ HTTP ์ ์ฉ ์ฟ ํค์ ๋ฆฌํ๋ ์ ํ ํฐ์ ์ค์ ํ๊ณ , ์ต์ข ์ ์ผ๋ก ๊ฐ์ ์ฑ๊ณต ์ฌ๋ถ๋ฅผ Boolean ๊ฐ์ผ๋ก ์๋ตํฉ๋๋ค. **3. ๋์ ๋ฐฉ์ โ ๊ธฐ์ ์ ์ธ๋ถ์ฌํญ** **3.1. ํ๋ ์์ํฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ด๋ จ ๊ธฐ์ ์ธ๋ถ์ฌํญ** NestJS ํ๋ ์์ํฌ: ์ด ์๋ํฌ์ธํธ๋ NestJS ์ปจํธ๋กค๋ฌ๋ก ๊ตฌํ๋์ด ์์ผ๋ฉฐ, @Controller(), @Post() ๋ฑ ๋ฐ์ฝ๋ ์ดํฐ์ ์์กด์ฑ ์ฃผ์ (@Injectable())์ ์ฌ์ฉํฉ๋๋ค. hCaptcha ์ฐ๋: @nestjs/axios์ HttpService๋ฅผ ์ฌ์ฉํ์ฌ "https://hcaptcha.com/siteverify" URL์ POST ์์ฒญ์ ๋ณด๋ด hCaptcha ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํฉ๋๋ค. ํ๊ฒฝ๋ณ์๋ก ๊ด๋ฆฌ๋๋ hCaptcha ๋น๋ฐ ํค(HCAPTCHA_SECRET_KEY)๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋: TypeORM(@nestjs/typeorm)์ ํตํด ์์ ์ฌ์ฉ์ ๋ ์ฝ๋๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํฉ๋๋ค. ์ฟ ํค ๊ด๋ฆฌ: @fastify/cookie ํจํค์ง๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด์ ์ฟ ํค๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ฟ ํค๋ HTTP ์ ์ฉ, ๋ณด์, ์๋ช ๋ ์ฟ ํค๋ก ์ค์ ๋ฉ๋๋ค. ๋ฐ์ดํฐ ๊ฒ์ฆ: NestJS์ Validation Pipe ๋ฐ ์ ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(class-validator ํน์ Joi)๋ฅผ ์ฌ์ฉํด ์ ๋ ฅ ๋ฐ์ดํฐ์ ์ ํจ์ฑ์ ๋ณด์ฅํฉ๋๋ค. **3.2. Sequence Diagram (ํ ์คํธ ๊ธฐ๋ฐ)** ```mermaid sequenceDiagram participant Client participant Controller as POST /temp-signup participant hCaptchaService participant UserService participant RefreshTokenService Client->>Controller: JSON payload {hCaptchaSuccessToken, username, email, countryCode3} Controller->>hCaptchaService: Validate hCaptcha token hCaptchaService-->>Controller: Return true/false alt hCaptcha valid Controller->>UserService: Create temporary user record UserService-->>Controller: Return new user object Controller->>RefreshTokenService: Generate refresh token RefreshTokenService-->>Controller: Return token Controller->>Client: Set HTTP-only cookie and return true else Controller->>Client: Return error response (signup failed) end ``` **4. Possible Design Patterns** ์๋น์ค ์งํฅ ์ํคํ ์ฒ: ์ธ์ฆ, ์ฌ์ฉ์ ๊ด๋ฆฌ, ํ ํฐ ๊ด๋ฆฌ ๋ฑ ๊ฐ๊ฐ์ ์ฑ ์์ ๊ฐ๋ณ ์๋น์ค๋ก ๋ถ๋ฆฌํฉ๋๋ค. ์์กด์ฑ ์ฃผ์ : NestJS์ ์ฃผ์ ํน์ง์ ํ์ฉํด ๊ฐ ์๋น์ค๊ฐ ๋ค๋ฅธ ์๋น์ค์ ์์กดํ ์ ์๋๋ก ๊ตฌ์ฑํฉ๋๋ค. ํ์ฌ๋ ํจํด: ์ปจํธ๋กค๋ฌ๋ ์ฌ๋ฌ ๋ด๋ถ ์๋น์ค(hCaptcha, User, Token ์๋น์ค)๋ฅผ ๋จ์ํํ์ฌ ํด๋ผ์ด์ธํธ์ ์ ๊ณตํ๋ ์ญํ ์ ํฉ๋๋ค. **5. Possible Improvements** ๊ณ ๋ํ๋ ๊ฒ์ฆ: class-validator ๋๋ Joi์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ๋ ์์ธํ ์์ฒญ ์คํค๋ง ๊ฒ์ฆ์ ์ํ. ์๋ฌ ํธ๋ค๋ง ๊ฐ์ : ํด๋ผ์ด์ธํธ์ ์ข ๋ ๊ตฌ์ฒด์ ์ธ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ ์ ์๋๋ก ์๋ฌ ํธ๋ค๋ง ๊ตฌ์กฐ๋ฅผ ๊ฐ์ . ์๋ ์ ํ: ์๋ํฌ์ธํธ ๋จ์ฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์๋ ์ ํ(Rate Limiting) ๊ธฐ๋ฅ ๋์ . ๋ก๊น ๋ฐ ๋ชจ๋ํฐ๋ง: ์ธํฐ์ ํฐ๋ฅผ ํตํ ์์ธ ๋ก๊น ์ ์ถ๊ฐํ์ฌ ์ด์ ๋ฐ ๊ฐ์ฌ์ ๋๋น. ์ค๋ณต ์ฒดํฌ: ๊ธฐ์กด ์ฌ์ฉ์์์ ์ค๋ณต ๊ฐ์ ์ฌ๋ถ๋ฅผ ๋ฏธ๋ฆฌ ํ์ธํ์ฌ ๋ถํ์ํ ๋ฐ์ดํฐ ์์ฑ ๋ฐฉ์ง. **6. Possible Edge Cases** ์ ํจํ์ง ์๊ฑฐ๋ ๋ง๋ฃ๋ hCaptcha ํ ํฐ: ์ธ๋ถ hCaptcha ์๋น์ค์์ ์ ํจ์ฑ ๊ฒ์ฆ์ ์คํจํ ๊ฒฝ์ฐ. ํ์ ์ ๋ ฅ ๋๋ฝ: ์ฌ์ฉ์ ์ด๋ฆ, ์ด๋ฉ์ผ ๋๋ ๊ตญ๊ฐ ์ฝ๋์ ๋๋ฝ. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฅ์ : ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฅ์ ์ ์์ ๊ณ์ ์์ฑ ์คํจ. ์ฟ ํค ๊ตฌ์ฑ ์ค๋ฅ: ์ฟ ํค ์ค์ ์ต์ (HTTP ์ ์ฉ, ๋ณด์ ๋ฑ)์ด ์ ๋๋ก ์ค์ ๋์ง ์์ ๊ฒฝ์ฐ๋ก ์ธํ ๋ณด์ ์ทจ์ฝ์ฑ. ์์ธ ์ฒ๋ฆฌ ๋ฏธํก: ์ธ๋ถ hCaptcha API ์๋ต์์ ๋นํ์ค ์๋ต์ด ์ฌ ๋ ์ฒ๋ฆฌํ ๋ก์ง์ ๋ถ์ฌ. </details> ์ด ํ ์คํธ์์ ๋๋ ๋ํ์ ์ ๋ฌธ์ ์์นด์ด๋ธ์์ผ ๋์๋ค. [ChatGPT ๋ํ ๊ธฐ๋ก](https://chatgpt.com/share/67fbc4cb-5988-8001-b968-b80682e2e8a1)์์ ํ์ธํด๋ณผ ์ ์๋ค. <div id="ํ๊ณ์ "></div> # ํ๊ณ์ <div id="ChatGPTํ๊ณ์ "></div> ## ChatGPT์์ ํ์ฉ์ ๊ดํ ํ๊ณ์ :img{src="https://blog.atj.sh/post-attachments/v/01962f25-1c49-7b91-8720-e57b5d738d00"} *์ฌ์ง: GPT-4.5 ๋ชจ๋ธ์ด ์๋ต์ ๊ฑฐ๋ถํ๋ ๋ชจ์ต.* ๋ฒ๋ค๋ JavaScript ํ์ผ์ ChatGPT ๋ํ์ ์ฒจ๋ถํ ๋, โChatGPT ํ์ผ ์ ๋ก๋โ๋ฅผ ํตํด ์ ๋ก๋ํ๋ ๊ฒ๋ณด๋ค, ํ๋กฌํํธ ์์ ํ์ผ ๋ด์ฉ์ ์ง์ ํฌํจ์ํค๋ ๊ฒ์ด ๋ต๋ณ์ ์ ํ๋๋ฅผ ๊ฑฐ์ ์๋ฒฝํ ์์ค์ผ๋ก ๋์ธ๋ค๋ ์ ์ ๋ฐ๊ฒฌํ๋ค. ๊ธ๋ฒ ํ ์คํธ์์๋ o3-mini ๋ชจ๋ธ์ ์ฌ์ฉํ์๋ค. ํํธ, ๋ค๋ฅธ ๋ชจ๋ธ์ ํตํ ๋ต๋ณ ์์ฑ์ ์๋ํ์ ๋์๋ โ๋ฉ์์ง ๊ธธ์ด ์ ํโ์ ๊ฑธ๋ ค ์๋ต์ ๋ฐ์๋ผ ์ ์์๋ค. <div id="๋ฒ๋ค๋งํ๊ณ์ "></div> ## ๋ฒ๋ค๋ง์ ๊ดํ ํ๊ณ์ :img{src="https://blog.atj.sh/post-attachments/v/01962f25-2ae0-7c12-84bb-b7fddae990de"} *์ฌ์ง: ์์ค ์ฝ๋ ํ์ผ ์์น๋ฅผ ๋ฌป๋ ์ง๋ฌธ์ ์๋ต์ ๊ฑฐ๋ถํ๋ ๋ชจ์ต.* ๋ฒ๋ค๋ง์ ํ๊ธฐ ์ํด์๋, ๋ฒ๋ค๋ฌ ๋๊ตฌ ์ฌ์ฉ๋ฒ์ ๊ณต๋ถํด์ผ ํ ๊ฒ์ด๋ค. ์ฝ๋๋ฒ ์ด์ค์ ๋ํ ๋ฒ๋ค๋ง์ ์๋ํ๊ธฐ ์ํด์๋ ๋ฒ๋ค๋ง์ ์คํจํ ๋งํ ๋ฌธ๋ฒ์ ์ค๋ฅ๊ฐ ์์ค์ฝ๋์ ์กด์ฌํด์๋ ์ ๋๋ค. ๋ฒ๋ค๋ง ์ค ์์ค๋๋ ์ ๋ณด๋ LLM์ ์ ๋ฌ๋์ง ์๋๋ค. ๋ณ๋์ RAG๊ฐ ํ์ํ๋ค. <div id="๋ฐ๊ฒฌ"></div> # ๋ฐ๊ฒฌ <div id="์ ํต์ "></div> ## ์ ํต์ ์ธ ๋๊ตฌ๋ฅผ ์จ์ RAG๋ฅผ ์ฑ์ทจํ๋ค๋ ์ ์ฝ๋๋ฒ ์ด์ค๊ฐ context window์ ํฌํจ๋ ์ ์๊ฒ๋ โ์์ค ์์ถโํ์ฌ๋ ๋์๊ณผ ๊ด๋ จ๋ ์ง์์ ์ ๋ฌํ ์ ์์์ ํ์ธํ์๋ค. ๋ํ, ์ด๋ฏธ ์กด์ฌํ๋ ๋ฒ๋ค๋ง ๋๊ตฌ๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ์์์ ์๋ฏธ๊ฐ ์๋ค. <div id="์ผ๋ฐํ"></div> ## ๋ค๋ฅธ ์ธ์ด๋ก ์์ฑ๋ ์ฝ๋๋ฒ ์ด์ค์ ๋ํ ์ผ๋ฐํ ๊ฐ๋ฅ์ฑ TypeScript/JavaScript ์ฝ๋ ์ง์์์๋ ์ค๋ซ๋์ ๋ฒ๋ค๋ง์ ๋ํ ์ฐ๊ตฌ๊ฐ ์ด๋ฃจ์ด์ง ์ํฉ์ด๋ผ, ๋ฒ๋ค๋ง ์์คํ ์ ๊ตฌ์ฑํ๋ ๋๋๋ ๋น๊ต์ ๋ฎ๋ค. ํ์ง๋ง ๋ค๋ฅธ ์ธ์ด๋ ์ํฉ์ด ๋ค๋ฅด๋ค. ๋จ์ ์ธ ์๋ก์จ ์ปดํ์ผ ์ธ์ด(C++ ๋ฑ)๋ก ์์ฑ๋๋ ์ฝ๋๋ฒ ์ด์ค์ ๋ํด์๋ ์ด๋ฌํ ๋ฒ๋ค๋ง์ด ๊ฐ๋ฅํ์ง ํ์ธ์ด ํ์ํ ๊ฒ์ด๋ค. ๋ค๋ง, LLM์ด .exe ํ์ผ์ ์ดํดํ๊ณ , ํ์ด์ฌ ํฌํ ํ๋ ๋ฐ ์ฑ๊ณตํ๋ค๋ฉฐ ์ฃผ์ฅํ๋ ์ฌ๋ก๊ฐ ์กด์ฌํ๋ค[^exe]. ๋ฐ๋ผ์, ์ฝ๋๋ฒ ์ด์ค์ ๋ํ ์ ์ ํ ์์ถ์ด ์ด๋ฃจ์ด์ง๋ค๋ฉด LLM์ด ์ดํดํ๋ ๋ฐ์๋ ๋ฌธ์ ๊ฐ ์๋ค๊ณ ๋ณผ ์ ์์ ๊ฒ์ด๋ค. [^exe]: [GeekNews: 27๋ ๋ EXE ํ์ผ์ Claude 3.7์ ์ ๋ก๋ํ ํ ์ผ์ด๋ ๋๋ผ์ด ์ผ](https://news.hada.io/topic?id=19493) <div id="๋ค๋ฅธ๋ฐฉ๋ฒ๊ณผ์๋น๊ต"></div> ## Semantic search์์ ์๋์ง **semantic search์ ๋ฒ๋ค๋ง๋ ์ฝ๋๋ฒ ์ด์ค ์ ๋ณด๋ฅผ ๋์์ RAG์ ํ์ฉํ๋ค๋ฉด, ์๋ก ์ํธ๋ณด์์ ์ผ๋ก ์์ฉํ์ฌ ์์นํจ๊ณผ๋ฅผ ๋ณผ ์ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ค.** ํ์ฌ ์์ฉ ์ฝ๋ฉ AI ์์ด์ ํธ๋ค์ ์ฌ๋ฌ ํ์ผ๋ก ๊ตฌ์ฑ๋ ์ฝ๋๋ฒ ์ด์ค์ ์ ์ฒด์ ์ธ ๋งฅ๋ฝ์ ์จ์ ํ ์ดํดํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ๊ฐ ๋ค๋ฐ์ฌ์ด๋ค. ์๋ฅผ ๋ค์ด, โ์ด์์ ๋ก๊ทธ์ธ ๋ก๊ทธ๊ฐ โISMS ๋ก๊ทธ ํ ์ด๋ธโ์ ๊ธฐ๋ก๋๋๋ก ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ฌ ์ฃผ์ญ์์คโ๋ผ๋ ์์ฒญ์ด ์ฃผ์ด์ง๋ฉด, AI ์์ด์ ํธ๋ โ์ด์์ ๋ก๊ทธ์ธโ ๊ธฐ๋ฅ๊ณผ โISMS ๋ก๊ทธ ํ ์ด๋ธโ๊ณผ ๊ด๋ จ๋ ๋ชจ๋ ์์ค ์ฝ๋๋ฅผ ํ์ํ๋ ๊ณผ์ ์์ semantic search(์๋ฏธ ๊ธฐ๋ฐ ๊ฒ์)๋ฅผ ์ํํ๋ค. Semantic search ๊ธฐ๋ฒ์ ์ ๋ ฅ๋ ํค์๋์ ๊ฐ์ฅ ์ ์ฌํ ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์๋ณํ๋ ๋ฐ ๊ธฐ์ฌํ๋, ๊ฒ์ ๋์์ ํฌํจ๋์ง ์์ ํ์ผ์ ์์ด์ ํธ๊ฐ ์ธ์งํ์ง ๋ชปํ ์ํ์ด ์๋ค. ํํธ, ๋ฒ๋ค๋ง์ ํตํด ์์ถ๋ ์ฝ๋๋ฒ ์ด์ค๋ฅผ LLM์๊ฒ ์ฌ์ ์ ์ ๊ณตํ๊ณ , ์ฌ๊ธฐ์ semantic search๋ฅผ ๊ฒฐํฉํ๋ค๋ฉด, ์ฝ๋๋ฒ ์ด์ค์ ์ ๋ฐ์ ์ธ ๋งฅ๋ฝ์ ๋ณด๋ค ์ถฉ์คํ ์ดํดํจ๊ณผ ๋์์ ๋ฐ์ดํฐ๋ฒ ์ด์คํ๋ ์๋ณธ ์์ค ์ฝ๋์ ํจ๊ณผ์ ์ผ๋ก ์ ๊ทผํ ์ ์์ด ์ ๋ฆฌํ ์ํฉ์ ๋ง๋ จํ ์ ์๋ค. <div id="๊ฒฐ๋ก "></div> # ๊ฒฐ๋ก LLM์ ๋ํด ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด๋ฅผ RAGํ๊ธฐ ์ํด, ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด๋ฅผ ํ ํ์ผ๋ก ์์ถํ์ฌ LLM์๊ฒ ์ ๋ฌํ๋ ํ ์คํธ๋ฅผ ์ค๊ณํ๋ค. ํ์กดํ๋ ๋ฒ๋ค๋ง ํด์ ๊ทธ๋๋ก ์ฌ์ฉํ์ฌ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์์ถํ์์ ๋, LLM์ ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด์ ๋ํ API ๋ฌธ์ํ๋ฅผ ์งํํ๊ฑฐ๋, ํน์ API์ ๋ํ ์์ธํ ๋งค๋ด์ผ์ ์์ฑํ ์ ์์๋ค. ์ฝ๋๋ฒ ์ด์ค ์์ถ์ ์งํํ๋ฉฐ ๋ฐ์ํ๋ ์ ๋ณด ์์ค์ ๋ํด์๋ ์๋ณธ ํ์ผ์ ๋ํ ์ถ๊ฐ์ ์ธ Semantic search๋ฅผ ํตํด ๋ณด์ํ ์ ์์ ๊ฒ์ผ๋ก ์ ๋งํ๋ค. *[GeekNews์์ ๋๊ธ์ ๋จ๊ธฐ์ค ์ ์์ต๋๋ค.](https://news.hada.io/topic?id=20309)* <div id="์ ๋ฐ์ดํธ1"></div> # ์ ๋ฐ์ดํธ (2025-04-23) ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์์ถ ์์ด tarball๋ก ๋ฌถ์ด LLM์๊ฒ ์ฃผ์์ ๋ context window๊ฐ ์ถฉ๋ถํ ํฐ ๊ฒฝ์ฐ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ ์ธ์ํ ๊ฒ์ด๋ค. ๋ ์ฝ๊ณ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํ์ฌ ๊ณต์ ํ๋ค.