Spring AI Component - thought-corner/backend-roadmap GitHub Wiki
- ChatClient ๋ด๋ถ์๋ ์ ์ ์ ์ง๋ฌธ์ด AI๋ฅผ ๊ฑฐ์ณ ์ต์ข ๊ฒฐ๊ณผ๋ฌผ๋ก ๋์ค๊ธฐ๊น์ง ๊ฐ๊ฐ์ ์ญํ ์ ์ํํ๋ 5๊ฐ์ง์ ํต์ฌ ์ปดํฌ๋ํธ๊ฐ ์ ๊ธฐ์ ์ผ๋ก ์ฐ๊ฒฐ๋์ด ์๋ค.
- AI ๋ํ์ ์์๊ณผ ๋์ ๊ด๋ฆฌํ๋ ์ปจํธ๋กค๋ฌ ์ญํ ์ ํ๋ค.
- ํด๋น ๊ฐ์ฒด์
.prompt()๋ฉ์๋๋ฅผ ์์์ผ๋ก ์ ์ฒด ๋ํ ๊ณผ์ ์ ์ ์ดํ๋ค.- Spring AI ์ํ๊ณ์์ AI ๋ชจ๋ธ(ChatGPT, Claude ๋ฑ)๊ณผ ๋ํ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๋ชจ๋ ๊ณผ์ ์ ์ด๊ดํ๊ณ ์ ์ดํ๋ ์ต์์ ํต์ฌ ์ธํฐํ์ด์ค์ด๋ค.
-
ChatClient๋ ์ด ๋ณต์กํ ๋ํ ํ์ดํ๋ผ์ธ์ ์คํ๋ง์์ ์ฝ๊ฒ ๊ด๋ฆฌํ๊ธฐ ์ํด ๋ง๋ค์ด์ก๋ค. - ๋น๋ ํจํด(Fluent API) ์คํ์ผ์ ์ ๊ณตํ์ฌ ํ์ํ ์ต์ ๋ค์ ์ง๊ด์ ์ผ๋ก ์กฐ๋ฆฝ ๊ฐ๋ฅํ๋ค.
- ์ ์ฒ๋ฆฌ ๋จ๊ณ
- ์ ์ ๊ฐ ๋ณด๋ธ ์ง๋ฌธ์ด AI ๋ชจ๋ธ๋ก ๋์ด๊ฐ๊ธฐ ์ง์ , ์ค๊ฐ์ ๊ฐ์ ํ์ฌ ์ง๋ฌธ์ ๊ฐ๊ณตํ๊ฑฐ๋ ํ์ํ ๋ฐฐ๊ฒฝ์ง์(Context)์ ์ฃผ์ ํ๋ค.
- ์ด์ ๋ํ ๊ธฐ๋ก์ ๋ถ๋ฌ์ ์ง๋ฌธ์ ๋ถ์ฌ์ฃผ๊ฑฐ๋, Vector DB ๊ด๋ จ ๋ฌธ์๋ฅผ ์ฐพ์์ ์ฐธ๊ณ ์๋ฃ๋ก ๊ฒฐํฉํด์ฃผ๋ ์ญํ ์ ์ํํ๋ค.
- AI ๋ชจ๋ธ๊ณผ ์ฃผ๊ณ ๋ฐ๋ ์์ฒญ๊ณผ ์๋ต์ ์ค๊ฐ์์ ๊ฐ๋ก์ฑ ๋ฐ์ดํฐ๋ฅผ ๋์ ์ผ๋ก ์์ , ํ์ฅ, ์ฐจ๋จํ ์ ์๊ฒ ํด์ฃผ๋ ์ปดํฌ๋ํธ์ด๋ค.
- ์คํ๋ง ์น ๊ฐ๋ฐ์ ์ธํฐ์ ํฐ, ํํฐ, ์ ํต AOP์ ๋์ผํ ์ญํ ์ ์ํํ๋ค๊ณ ๋ณผ ์ ์๋ค.
- Chat Memory Advisors(๋ํ ํ๋ฆ ๊ด๋ฆฌ)
-
MessageChatMemoryAdvisor: ๋ํ ์ด๋ ฅ์ ์ ์ /AI ๋ฉ์์ง ๊ตฌ์กฐ ๊ทธ๋๋ก ์ ์งํ๋ฉฐ ํ๋กฌํํธ์ ์ถ๊ฐ -
PromptChatMemoryAdvisor: ๊ณผ๊ฑฐ ๋ํ๋ฅผ ๋จ์ ํ ์คํธ๋ก ๋ฝ์์ ์์คํ ํ๋กฌํํธ์ ์ฝ์
-
- Question Answering Advisors(RAG ๊ฒ์ ์ฆ๊ฐ ์์ฑ)
-
QuestionAnswerAdvisor: Vector DB ์๋ ์ฐ๋ ๋ฑ์ ํจํด์ ์ํ -
RetrievalAugmentationAdvisor: ๊ณ ๋ํ๋ RAG ์ํคํ ์ฒ๋ฅผ ๊ตฌํํ ๋ ์ฌ์ฉ
-
- Reasoning & Safety Advisors(์ถ๋ก ๋ฐ ๋ณด์)
-
ReReadingAdvisor(RE2): LLM์ ์ถ๋ก ๋ฅ๋ ฅ์ ๋์ด๊ธฐ ์ํด ์ ๋ ฅ๋ ์ง๋ฌธ์ ํ ๋ฒ ๋ ์ฝ๊ฒ๋ ํ๋กฌํํธ๋ฅผ ์๋์ผ๋ก ๋ณด๊ฐ -
SafeGuardAdvisor: AI ๋ชจ๋ธ์ด ํด๋กญ๊ฑฐ๋ ๋ถ์ ์ ํ ๋ต๋ณ์ ์์ฑํ์ง ์๋๋ก ์ฌ์ ์ ๋ฐฉ์ด๋ง์ ์ณ์ค๋ค.
-
Advisor์ ํต์ฌ ๋์ ์๋ฆฌ : ์คํ(Stack) ๊ตฌ์กฐ
- ์คํ์์ ๊ท์น :
getOrder()๋ฉ์๋๊ฐ ๋ฐํํ๋ ๊ฐ์ด ์์์๋ก(=์ฐ์ ์์๊ฐ ๋์์๋ก) ์ฒด์ธ์ ๊ฐ์ฅ ๋ฐ๊นฅ์ชฝ(=๋งจ ์)์ ์์นํ๋ค.
- ์์ฒญ(Request) ๋จ๊ณ : ์ฐ์ ์์๊ฐ ๋์(=Order ๊ฐ์ด ์์) Advisor๊ฐ ๊ฐ์ฅ ๋จผ์ ์์ฒญ์ ๊ฐ๋ก์ฑ์ ์ ์ฒ๋ฆฌํ๋ค.
- ์๋ต(Response) ๋จ๊ณ : ์ฐ์ ์์๊ฐ ๋์(=Order ๊ฐ์ด ์์) Advisor๊ฐ ๊ฐ์ฅ ๋ง์ง๋ง์ ์๋ต์ ๊ฐ๋ก์ฑ์ ํ์ฒ๋ฆฌํจ
- ์ต์ข ํ๋กฌํํธ ์์ฑ
- Advisors๊ฐ ์์งํ ๋ฐฐ๊ฒฝ์ง์(Context)๊ณผ ์ ์ ๊ฐ ์ฒ์ ์ ๋ ฅํ ๋ด์ฉ์ ๊ฒฐํฉํ์ฌ, AI ๋ชจ๋ธ์ด ์๋ฒฝํ๊ฒ ์ดํดํ ์ ์๋ ์ต์ข ํ๋กฌํํธ(๋ช ๋ น์ด)๋ฅผ ์์ฑํ๋ ๋จ๊ณ์ด๋ค.
-
Prompt ๊ฐ์ฒด์ ๋ด๋ถ๋
List<Message>์ChatOptions์ด ์๋ค.-
ChatOptions: ๋ํ์ ๋งฅ๋ฝ์ ๊ตฌ์ฑํ๋ ์ฌ๋ฌ ์ข ๋ฅ์ ๋ฉ์์ง ๋ฌถ์ -
List<Message>: ์จ๋, ์ฌ์ฉํ ๋ชจ๋ธ๋ช ๊ณผ ๊ฐ์ AI ์คํ ์ต์
-
SYSTEM: AI์ ์ฑ๊ฒฉ, ์ง์ , ํ๋ ์ง์นจ, ์ ์ฝ ์ฌํญ ๋ฑ์ ์ธ๋์ํค๋ ๋ฉ์์งUSER: ์ค์ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ์ ์ ๊ฐ ์ ๋ ฅํ ์ง๋ฌธ์ด๋ ์ง์ ๋ด์ฉASSISTANT: AI๊ฐ ์ด์ ์ ๋๋ตํ๋ ์๋ต ๋ด์ฉ์ ์ฑ๋ด์ด ๊ธฐ์ตํ๊ณ ์ด์ด๊ฐ๊ธฐ ์ํด(Chat Memory) ๋ง๋ถ์ด๋ ๋ฉ์์งTOOL: AI๊ฐ ์ธ๋ถ API๋ ํจ์(์: ๋ ์จ ์กฐํ, ์ฌ๋ด DB ์กฐํ)๋ฅผ ํธ์ถํ๊ณ ๋์์จ ๊ฒฐ๊ณผ๊ฐ์ ๋ด๋ ํน์ ๋ฉ์์ง
- ์ค์ ๋ก ์ง๋ฌธ์ด ๊ณ ์ ๋์ด ์์ง ์๊ธฐ์ ์ ์ ์ ์ ๋ ฅ๊ฐ์ ๋ฐ๋ผ ์ง๋ฌธ ๋ด์ฉ์ด ๋งค๋ฒ ๋ฐ๋์ด์ผ ํ๋ฏ๋ก
PromptTemplate์ ํ์์ ์ผ๋ก ์ฌ์ฉํ๋ค.- ๋น์ฆ๋์ค ๋ก์ง(์๋ฐ ์ฝ๋)๊ณผ ํ๋กฌํํธ ๋ฌธ๊ตฌ(ํ ์คํธ)๋ฅผ ๊น๋ํ๊ฒ ๋ถ๋ฆฌํ ์ ์์ด ์ ์ง๋ณด์๊ฐ ๋งค์ฐ ํธํด์ง๋ค.
ChatOptions๋, ์จ๋(Temperature), ์ฌ์ฉํ ๋ชจ๋ธ๋ช (GPT-4)์ ๊ฐ์ AI ์คํ ์ต์ ์ ๋งํ๋ค.Temperature(์จ๋)
- 0.0 ~ 0.3(๋ฎ์ ์จ๋) : ๋งค์ฐ ๊ฒฐ์ ์ ์ด๊ณ ์ผ๊ด๋ ์๋ต, ์ฌ์ค ๊ธฐ๋ฐ ๋ต๋ณ, ๋ฐ์ดํฐ ๋ถ๋ฅ, ์ฝ๋ ์์ฑ์ ์ ํฉํ๋ค.
- 0.4 ~ 0.7(์ค๊ฐ ์จ๋) : ๊ท ํ ์กํ ์๋ต, ์ผ๋ฐ์ ์ธ ๋ํ๋ ์ ๋ณด ์ ๊ณต์ฉ ์ฑ๋ด์ ๊ฐ์ฅ ๋ง์ด ์ฐ๋ ํ์ค ๊ฐ์ด๋ค.
- 0.8 ~ 1.0(๋์ ์จ๋) : ์ฐฝ์์ ์ด๊ณ ๋ค์ํ ์๋ต, ์๋ฑํ๊ณ ๊ธฐ๋ฐํ ์๊ฐ์ด ํ์ํ ์คํ ๋ฆฌํ ๋ง, ์์ค ์ฐ๊ธฐ, ์์ด๋์ด ๋ธ๋ ์ธ์คํ ๋ฐ์ ์ ํฉํ๋ค.
Output Length(์ต๋ ๊ธธ์ด ์ ํ)
- 5 ~ 25 : ํ๋ ๋จ์ด, ์งง์ ๊ตฌ์ , ํน์ "๊ธ์ /๋ถ์ " ๊ฐ์ ๋ถ๋ฅ ๋ผ๋ฒจ์ด๋ค.
- 50 ~ 500 : ํ๋์ ๊น๋ํ ๋ฌธ๋จ์ด๋ ์งง์ ์ค๋ช ์ ์ํ ๋ ์ ํฉํ๋ค.
- 1000+ : ์ฅ๋ฌธ์ ๊ธ, ์์ค ์คํ ๋ฆฌ, ๋ณต์กํ ๋ก์ง์ ์ํคํ ์ฒ ์ค๋ช ์ด๋ค.
Sampling Controls(์ํ๋ง ์ ์ด)
- AI๊ฐ ๋ค์์ ์ฌ ๋จ์ด(ํ ํฐ) ํ๋ณด๊ตฐ์ ์ถ๋ ค๋ด๋ ๊ณ ๋์ ํํฐ๋ง ๊ธฐ๋ฒ์ด๋ค.
- Top-K(์์ K๊ฐ ํํฐ๋ง) : ๋ค์ ํ ํฐ์ ์ ํํ ๋, ํ๋ฅ ์ด ๊ฐ์ฅ ๋์ ์์ K๊ฐ์ ํ ํฐ์ผ๋ก๋ง ํ๋ณด๊ตฐ์ ์ ํํ๋ค. ๊ฐ์ด ํด์๋ก ๋ค์ํ ๋จ์ด๊ฐ ์์ฌ ๋์ ๋ค์์ฑ์ด ์ฆ๊ฐํ๊ณ , ์์์๋ก ๋ ์ฐ๋ ๋จ์ด๋ง ์จ์ ๊ฒฐ์ ์ ์ธ ๋ต๋ณ์ด ๋์จ๋ค.
- Top-P (๋์ ํ๋ฅ ํํฐ๋ง / Nucleus Sampling) : ํ๋ณด ๋จ์ด๋ค์ ํ๋ฅ ๋์ ์์ผ๋ก ์ค ์ธ์ด ๋ค, ๋์ ํ๋ฅ ์ด P(์: 90%)๋ฅผ ์ด๊ณผํ๊ธฐ ์ ๊น์ง๋ง ๋์ ์ผ๋ก ๋จ์ด ํ๋ณด๊ตฐ์ ์ ํํ๋ค. ์์ 90%์ ์์ ํ ๋จ์ด๋ค ์์์๋ง ๊ณ ๋ฅด๊ฒ ํ๋ฏ๋ก ๋ฌธ๋งฅ์ด ๊ผฌ์ด์ง ์์ผ๋ฉด์๋ ์์ฐ์ค๋ฌ์ด ๋ณํ๋ฅผ ์ฃผ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก 0.8 ~ 0.95 ์ฌ์ด์ ๊ฐ์ ์ฌ์ฉํ๋ค.
Spring AI ํ๋กฌํํธ ์์ง๋์ด๋ง 9๊ฐ์ง ํจํด
- Zero-Shot Prompting : ์ฌ์ ์ ๋ณด๋ ์์ ์์ด AI์๊ฒ ๊ณง๋ฐ๋ก ์ง๋ฌธ์ ๋์ง๋ ๋ฐฉ์
- Few-Shot Prompting : AI์๊ฒ 1๊ฐ ๋๋ ์ฌ๋ฌ ๊ฐ์ ์ ๋ต ์์๋ฅผ ๋ฏธ๋ฆฌ ๋ณด์ฌ์ฃผ๊ณ ํจํด์ ํ์ต์ํจ ๋ค ์ง๋ฌธ์ ๋์ง๋ ๋ฐฉ์
- Role & System Prompting : ์์คํ ํ๋กฌํํธ๋ฅผ ์ฌ์ฉํด AI์๊ฒ 'ํ๋ฅด์๋(์ง์ , ์ฑ๊ฒฉ, ํค์ค๋งค๋)'๋ฅผ ๋ถ์ฌํ๋ ๋ฐฉ์
- Step-Back Prompting : AI๊ฐ ์ฃ๋ถ๋ฆฌ ๋๋ตํ๊ธฐ ์ ์, ์ํฉ์ ๋จผ์ ๊ฐ๊ด์ ์ผ๋ก ๋ถ์ํ๊ณ ์ฑ์ฐฐํ๋๋ก ์ ๋ํ๋ ๋ฐฉ์
- Chain-of-Thought, CoT : ๋จ์ํ ๋ต๋ง ๋ฑ๋ ๊ฒ ์๋๋ผ, ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ณผ์ ์ ๋จ๊ณ๋ณ๋ก ํ์ด์ ์ค๋ช ํ๋๋ก ์ง์ํ๋ ๋ฐฉ์
- Self-Consistency Prompting : CoT(์๊ฐ์ ์ฌ์ฌ) ํ๋กฌํํธ๋ฅผ ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณตํด์ ํธ์ถํ ๋ค, ๊ฐ์ฅ ๋ง์ด ๋์จ(์ผ๊ด๋) ๋ต๋ณ์ ์ต์ข ์ ๋ต์ผ๋ก ์ฑํํ๋ ๋ฐฉ์
- Tree-of-Thoughts, ToT : ํ๋์ ๋ฌธ์ ์ ๋ํด ์ฌ๋ฌ ๊ฐ์ง ํด๊ฒฐ์ฑ ์ ๋จผ์ ์ ์ํ๊ฒ ํ๊ณ , ๊ทธ ์ค ๊ฐ์ฅ ์ข์ ๊ฒ์ ์ค์ค๋ก ์ ํํด ํ๊ฐํ๊ฒ ๋ง๋๋ ๋ฐฉ์
- Automatic Prompt Engineering : ๋ด๊ฐ ์ด ๋ถ์คํ ํ๋กฌํํธ๋ฅผ AI์๊ฒ ๋์ ธ์ "๋ค๊ฐ ๋ ์๋ฒฝํ ํ๋กฌํํธ๋ก ๋ค๋ฌ์ด๋ด"๋ผ๊ณ ์ํค๋ ๋ฐฉ์
- Code Prompting : ์ฌ์ฉ์์ ์ ๋ ฅ์ ๊ธฐ๋ฐ์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๊ฑฐ๋ ๋ถ์ํ๋๋ก ์์ฒญํ๋ ๋ฐฉ์
- AI ๋ชจ๋ธ ์คํ
- ์์ฑ๋ ์ต์ข ํ๋กฌํํธ๋ฅผ ์ค์ ์ธ๋ถ AI API(OpenAI, ๊ตฌ๊ธ ๋ฑ)์ ๋์ ธ ๋ต๋ณ์ ๋ฐ์์จ๋ค.
- ์ด ๋จ๊ณ์์ ์ค์ (์ผ๋ฐ ์๋ต vs ์คํธ๋ฆฌ๋ฐ)์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ํต์งธ๋ก ๋ฐ์์ง, ๊ธ์ ๋จ์๋ก ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ์ผ๋ก ๋ฐ์์ง ์๋ต ๊ท๊ฒฉ์ด ๊ฒฐ์ ๋๋ค.
- OpenAI(ChatGPT), Google(Gemini), Anthropic(Claude) ๋ฑ ๋ค์ํ ์ธ๋ถ AI ์๋น์ค์ ํต์ ํ๊ธฐ ์ํ ์๋ฐ ํ์ค ์ธํฐํ์ด์ค
- Spring AI Models๋ ์๋ฐ์ ๋คํ์ฑ(Polymorphism)์ ๊ทน๋ํํ์ฌ, ๊ฐ๋ฐ์๊ฐ ๋จ์ผํ ์คํ๋ง ์ธํฐํ์ด์ค(Model)๋ง ๋ณด๊ณ ์ฝ๋ฉํ๋๋ก ์ค๊ณ๋์ด์๋ค.
- application.yaml๊ณผ ๊ฐ์ ์ค์ ํ์ผ์์ API ํค์ ์์กด์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ๊ต์ฒดํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
- ChatModel : ํ ์คํธ ๋ํ ์์ง, ํ ์คํธ(Prompt)๋ฅผ ์ ๋ ฅ๋ฐ์ ํ ์คํธ(ChatResponse)๋ฅผ ๋ฐํํ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๊ณ ํต์ฌ์ ์ธ ๋ชจ๋ธ
- EmbeddingModel : Vector ๋ณํ ์์ง, RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์์คํ ์ ํต์ฌ. ์ค๊ธ ํ ์คํธ๋ฅผ ์ ๋ ฅ๋ฐ์ Vector DB์ ์ ์ฅํ ์ ์๋๋ก ์ซ์ ๋ฐฐ์ด(Vector)๋ก ๋ณํํด์ฃผ๋ ๋ชจ๋ธ
- ImageModel : ์ด๋ฏธ์ง ์์ฑ ์์ง, ํ ์คํธ ํ๋กฌํํธ๋ฅผ ์ ๋ ฅ๋ฐ์ ์ด๋ฏธ์ง๋ฅผ ์์ฑ
- AudioModel : ์์ฑ ์ฒ๋ฆฌ ์์ง, ์์ฑ์ ํ ์คํธ๋ก ๋ณํ(STT)ํ๊ฑฐ๋, ํ ์คํธ๋ฅผ ์์ฑ์ผ๋ก ๋ณํ(TTS)ํ๋ ๋ชจ๋ธ
- ํ์ฒ๋ฆฌ ๋ฐ ๊ฐ์ฒด ๋ณํ
- AI ๋ชจ๋ธ์ด ๋ฑ์ด๋ธ ์ค๊ธ ํํ์ ํ
์คํธ ๋ต๋ณ์ ๋ฐ์, ๋ฐฑ์๋ ๋ก์ง์์ ์ฆ์ ์ฌ์ฉํ ์ ์๋๋ก ์ ํด์ง ์๋ฐ ๊ฐ์ฒด(DTO)๋ JSON ๊ท๊ฒฉ์ผ๋ก ์๋ ํ์ฑํด์ฃผ๋ ์ต์ข
๋ณํ ๋จ๊ณ์ด๋ค.
- AI ๋ชจ๋ธ์ด ๋ฑ์ด๋ด๋ ์์ธก ๋ถ๊ฐ๋ฅํ ๋ฌธ์์ด(String) ํํ์ ๋ต๋ณ์, ๋ฐฑ์๋ ์๋ฒ๊ฐ ์ฆ์ ์ฌ์ฉํ ์ ์๋ ์ ํํ๋ ๋ฐ์ดํฐ ๊ท๊ฒฉ(JSON, ์๋ฐ ๊ฐ์ฒด, ๋ฆฌ์คํธ ๋ฑ)์ผ๋ก ๊ฐ์ ํ๊ณ ๋ณํํด์ฃผ๋ ํ๋ ์์ํฌ ์ง์ ๊ธฐ๋ฅ์ด๋ค.
- Structured Output ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด, ๋ฐฑ์๋ ๋ก์ง์ AI์ ์๋ต์
String์ด ์๋ ์ฒ์๋ถํฐ ์๋ฐ DTO๋List<String>๊ฐ์ ๊น๋ํ ๊ฐ์ฒด ํํ๋ก ๋ฐ๋ก ๊ฑด๋ค๋ฐ์ ์ ์๋ค.
- BeanOutputConverter : AI์ ๋ต๋ณ์ ๊ฐ๋ฐ์๊ฐ ์ง์ ๋ง๋ ์ปค์คํ ์๋ฐ ํด๋์ค(DTO ๋๋ Record)๋ก ๋ณํํ๋ค.
- ListOutputConverter : ๋ต๋ณ์ ๋จ์ํ
List<String>ํํ๋ก ๋ฐํํ๋ค.- MapOutputConverter : ๋ต๋ณ์
Map<String, Object>ํํ์ ํค-๊ฐ ์์ผ๋ก ๋ฐํํ๋ค.
spring:
application:
name: spring-ai
ai:
# anthropic:
# api-key: "TEST-API-KEY"
# chat:
# model: claude-opus-4-8
# max-tokens: 4096
ollama:
init:
pull-model-strategy: when_missing
chat:
model: hf.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF # https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF@RestController
public class ChatController {
private final ChatClient client;
@Autowired
public ChatController(ChatClient.Builder builder) {
this.client = builder.build();
}
// 1) ๋จ์ํ๊ฒ ๋ฐ๊ธฐ: call().content() ๋ก ์๋ต ๋ณธ๋ฌธ ํ
์คํธ๋ง String ์ผ๋ก ๋ฐํ๋ฐ๋๋ค. ๊ฐ์ฅ ๊ธฐ๋ณธ ํํ.
@GetMapping("/chat/simple")
public String simple(@RequestParam String prompt) {
return this.client.prompt()
.user(prompt)
.call()
.content();
}
// 2) ChatResponse ๊ฐ์ฒด๋ก ๋ฐ๊ธฐ: call().chatResponse() ๋ก ๋ณธ๋ฌธ + ๋ฉํ๋ฐ์ดํฐ๋ฅผ ํต์งธ๋ก ๋ฐ๋๋ค.
// ๋ณธ๋ฌธ ํ
์คํธ โ getResult().getOutput().getText(), ํ ํฐ ์ฌ์ฉ๋ โ getMetadata().getUsage()
@GetMapping("/chat/response")
public ChatResponse response(@RequestParam String prompt) {
return this.client.prompt()
.user(prompt)
.call()
.chatResponse();
}
// 3) ์๋ฐ ๊ฐ์ฒด๋ก ๋ฐ๊ธฐ: call().entity(ActorFilms.class) ๋ก ์๋ต์ DTO(record)์ ๋งคํํ๋ค.
// Spring AI ๊ฐ JSON ์ถ๋ ฅ ํฌ๋งท ์ง์นจ์ ํ๋กฌํํธ์ ์๋์ผ๋ก ๋ง๋ถ์ฌ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด๋ก ๋ณํํ๋ค.
@GetMapping("/chat/entity")
public ActorFilms entity(@RequestParam String actor) {
return this.client.prompt()
.user(u -> u.text("{actor}์ด(๊ฐ) ์ถ์ฐํ ๋ํ ์ํ 5ํธ์ ์๋ ค์ค.")
.param("actor", actor))
.call()
.entity(ActorFilms.class);
}
// 4) Flux ๋ก ๋ฐ๊ธฐ: stream().content() ๋ก ํ ํฐ์ ์์ฑ๋๋ ์ฆ์ ํ๋ ค๋ณด๋ธ๋ค(SSE).
// produces = text/event-stream ์ด๋ผ ์๋ต์ด data: ์ฒญํฌ๋ก ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ๋๋ค. (curl -N ๋ก ํ์ธ)
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam String prompt) {
return this.client.prompt()
.user(prompt)
.stream()
.content();
}
}