์๋
ํ์ธ์ dev_writer์
๋๋ค. ์ค๋์ ์ ๋ฒ์ ๋ง์๋๋ฆฐ ๋๋ก Spring AI์์ ์ง์ํ๋ PromptTemplate๊ณผ ํ๋กฌํํธ์ ๊ทผ๋ณธ์ ์ธ ์ข
๋ฅ๋ฅผ ์๋ ค๋๋ฆฌ๊ฒ ์ต๋๋ค.
ํ๋กฌํํธ๋
์ด์ ํ๋กฌํํธ (Prompt)๋ผ๋ ๋จ์ด๋ ์ผ์์ํ์์ ์ฝ๊ฒ ์ ํ ์ ์๋ ๋ง์ด ๋์์ต๋๋ค.
์ํค๋ฐฑ๊ณผ์์๋ ํ๋กฌํํธ๋ฅผ ์์ฑํ AI ๋ชจ๋ธ๋ก ํด์๋๊ณ ์ดํดํ ์ ์๋ ๋ช
๋ น, AI๊ฐ ์ํํด์ผ ํ๋ ์์
์ ์ค๋ช
ํ๋ ์์ฐ์ด ํ
์คํธ๋ผ ์ ์ํ๊ณ ์์ต๋๋ค.
ํจ๊ณผ์ ์ผ๋ก ํ๋กฌํํธ๋ฅผ ์ ์ฉํ ์ ์๋ ์ฌ๋ก๋ฅผ ์ ๋ฆฌํ ๊ธ๋ ์ฐธ๊ณ ํ์๋ฉด ์ข์ ๋ฏํฉ๋๋ค.
Prompt ํด๋์ค
๊ธฐ๋ณธ์ ์ผ๋ก Spring AI์์ ํ๋กฌํํธ๋ฅผ ๋ํ๋ด๋ Prompt ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ๋, ์์ฑ์๋ฅผ ๋ณด๋ฉด UserMessage๋ก ์์ฑ๋จ์ ๋ณด์ค ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ด์ธ์๋ Message ํ์
๋ค์ด ์๋ ๊ฒ์ ๋ณด์ค ์ ์์ต๋๋ค.
![](https://blog.kakaocdn.net/dn/6InI9/btsH9Yd0kBf/3xuh9kTqgkbVRCFR0FEDY1/img.png)
Message ์ธํฐํ์ด์ค
๋ค์์ผ๋ก Message ์ธํฐํ์ด์ค๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
![](https://blog.kakaocdn.net/dn/XZo13/btsH8LNAoK9/cuS3rBw5hiXwXyJLaXMRQk/img.png)
Message ์ธํฐํ์ด์ค ์ค๋ช
์ ๋ฐ๋ฅด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Message ์ธํฐํ์ด์ค๋ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ ์กํ๊ฑฐ๋ ์์ ํ ์ ์๋ ๋ฉ์์ง๋ฅผ ๋ํ๋ ๋๋ค. ๋ฉ์์ง๋ ๋ด์ฉ, ๋ฏธ๋์ด ์ฒจ๋ถ ํ์ผ, ์์ฑ ๋ฐ ๋ฉ์์ง ์ ํ์ ๊ฐ์ง ์ ์์ต๋๋ค.
์ถ์ ํด๋์ค์ธ AbstractMessage๋ฅผ ์ ์ธํ๊ณ ๋๋จธ์ง 4๊ฐ์ ๋ฉ์์ง์ ์ญํ ๊ณผ ์ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. Dan Vega (Spring AI ์๊ฐ ๊ฐ๋ฐ์)์ ์์์ ์ ๋ฆฌํ ์ ์์
๋๋ค.
- System: AI์ ํ๋๊ณผ ์๋ต ์คํ์ผ์ ์๋ดํ๋ฉฐ, AI๊ฐ ์ ๋ ฅ์ ํด์ํ๊ณ ์๋ตํ๋ ๊ท์น์ด๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ค์ ํฉ๋๋ค. ๋ํ๋ฅผ ์์ํ๊ธฐ ์ ์ AI์๊ฒ ์ง์ ์ฌํญ์ ์ ๊ณตํ๋ ๊ฒ๊ณผ ์ ์ฌํฉ๋๋ค. ์ญํ ๋ถ์ฌ, ํฌ๋งท ์ ์ ๋ฑ์ด ํด๋น๋ฉ๋๋ค.
- User: ์ฌ์ฉ์์ ์ ๋ ฅ์ ๋ํ๋ ๋๋ค. ์ฌ์ฉ์์ ์ง๋ฌธ, ๋ช ๋ น ๋๋ AI์ ๋ํ ์ง์ ์ ๋๋ค. ์ด ์ญํ ์ AI์ ์๋ต์ ๊ธฐ์ด๋ฅผ ํ์ฑํ๋ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
- Assistant: AI๊ฐ ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ํด ์๋ตํ๋ ๋ถ๋ถ์ ๋๋ค. ๋จ์ํ ๋ต๋ณ์ด๋ ๋ฐ์ ์ด์์ผ๋ก, ๋ํ์ ํ๋ฆ์ ์ ์งํ๋ ๋ฐ ์ค์ํฉ๋๋ค. ์์คํ ์ AI์ ์ด์ ์๋ต์ ์ถ์ ํ์ฌ, ์ผ๊ด๋ (coherent) ์ํฉ์ ๋ง๋ ์ํธ์์ฉ (interactions)์ ๋ณด์ฅํฉ๋๋ค.
- Function: ๋ํ ์ค ํน์ ์์ ์ด๋ ์์ ์ ์ฒ๋ฆฌํ๋ ์ญํ ์ ๋๋ค. ์์คํ ์ญํ ์ด AI์ ์ ๋ฐ์ ์ธ ๋์์ ์ค์ ํ๋ ๋ฐ๋ฉด, ๊ธฐ๋ฅ ์ญํ ์ ์ฌ์ฉ์๊ฐ ์์ฒญํ ํน์ ์์ ์ด๋ ๋ช ๋ น์ ์ํํฉ๋๋ค. ๋ํํ๋ ๊ฒ ์ด์์ ๊ณ์ฐ, ๋ฐ์ดํฐ ๊ฒ์ ๋๋ ๊ธฐํ ์์ ์ ์ํํ ํ์๊ฐ ์์ ๋ ํน์ ๊ธฐ๋ฅ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. ์ด ์ญํ ์ ํตํด AI๋ ๋ํ์ ์๋ต ์ธ์๋ ์ค์ฉ์ ์ธ ๋์์ ์ ๊ณตํ ์ ์์ต๋๋ค.
์ด ์ค๋ช
์ ๋ฐ๋ฅด๋ฉด, Prompt ํด๋์ค๋ฅผ String๊ณผ ํจ๊ป ์์ฑํ ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ์ (User)์ ๋ฉ์์ง๋ฅผ ํตํด ๋ง๋ ๋ค๋ ๊ฒ์ ํ์
ํ ์ ์์ต๋๋ค.
์ฌ๋ด์ผ๋ก ์ด ์ ์๋ค์ Spring AI์์๋ ํ์ธํ์ค ์ ์๋๋ก ์ง์ Spring AI์ ๊ด๋ จ ์ ์๋ฅผ ์์ฑํ์์ต๋๋ค. ์ด๊ณณ์์ ๋ณด์ค ์ ์์ต๋๋ค.
PromptTemplate ํด๋์ค
PromptTemplate ํด๋์ค๋ ํ ์คํธ ๊ธฐ๋ฐ ํ ํ๋ฆฟ ์์ง์ ํ์ฉํ์ฌ ํจ๊ณผ์ ์ผ๋ก ํ๋กฌํํธ๋ฅผ ์์ฑํ ์ ์๋๋ก ํฉ๋๋ค.
![](https://blog.kakaocdn.net/dn/dr68gd/btsH8lICabX/c0p2KBS5EWFevSw64UMSB1/img.png)
๋ง์ฝ ๋ค์ ํ๋กฌํํธ๊ฐ ์ ๋๋ก ๋์ํ๊ธฐ ์ํด์๋..
Tell me a {adjective} joke about {content}.
์๋์ ๊ฐ์ด ์์ฑํด์ผ ํฉ๋๋ค.
String command = "Tell me a {adjective} joke about {content}.";
PromptTemplate template = new PromptTemplate(command);
template.add("adjective", "funny");
template.add("content", "life");
Prompt prompt = template.create();
// ๊ฒฐ๊ณผ: Tell me a funny joke about life.
// ๋๋ ์๋์ ๊ฐ์ด ๋ง๋ค์ด๋ ๋ฉ๋๋ค.
Map<String, Object> map = new HashMap<>();
map.put("adjective", "funny");
map.put("content", "life");
template = new PromptTemplate(command, map);
prompt = template.create();
// ๋ค๋ฅธ ์๋ก๋ ๋ ๊ฐ๋จํ ๋ง๋ค ์๋ ์์ต๋๋ค.
template = new PromptTemplate(message, Map.of("artist", artist));
๊ทธ๋ฐ๋ฐ ๋ง์ฝ ์๋ชป๋ ํ
ํ๋ฆฟ์ ์์ฑํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๊ฐ๋ น, ์์์๋ "adjective"์ "content"์ ๋ํ ๊ฒ์ ๋ฃ๊ณ ์ ํ์์ต๋๋ค. ์๋ ํค๋ฅผ ๋ฃ๊ณ ์ ํ๋ค๋ฉด, ์์ธ (IllegalStateException)๊ฐ ๋ฐ์ํฉ๋๋ค.
// ์์ธ 1: ์๋ ํค๋ฅผ ๋ฃ๊ณ ์ ํ ๊ฒฝ์ฐ
String command = "Tell me a {adjective} joke about {content}.";
PromptTemplate template = new PromptTemplate(command);
template.add("adjective", "funny");
template.add("content", "life");
template.add("name", "david");
Prompt prompt = template.create();
// ์์ธ 2: ๋ฃ์ด์ผ ํ ํค์ ๊ฐ์ด ๋ค์ด๊ฐ์ง ์์ ๊ฒฝ์ฐ (์์ ๊ฒฝ์ฐ์์ content๋ฅผ ๋น์ด ๊ฒฝ์ฐ ๋ฑ)
String command = "Tell me a {adjective} joke about {content}.";
PromptTemplate template = new PromptTemplate(command);
template.add("adjective", "funny");
Prompt prompt = template.create();
์ด๋ PromptTemplate์์ validate ๊ณผ์ ์ ํ ๋ ๋ด๋ถ์ ์ผ๋ก ์ฃผ์
ํ ํ
ํ๋ฆฟ ๋ณ์๋ค์ ๋ชจ๋ ์์ฑํ๋์ง, ํ
ํ๋ฆฟ ๋ณ์ ์ด์ธ์ ๋ค๋ฅธ ํค๋ค๋ ํจ๊ป ๋ฃ์ง ์์๋์ง ๋ฑ์ ๊ฒ์ฆ์ ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
PromptTemplate์ UserMessage๋ง ๋ง๋ญ๋๋ค.
์ด๋ ๊ฒ ํจ๊ณผ์ ์ผ๋ก ํ๋กฌํํธ๋ฅผ ์ ์ํ ์ ์๋๋ก ํด ์ฃผ์ง๋ง, PromptTemplate์ ์ฌ์ฉํ ๋๋ ์ฃผ์ํ ์ ์ด ์์ต๋๋ค. ๊ทธ๊ฒ์ ๋ฐ๋ก ๋ด๋ถ์ ์ผ๋ก UserMessage๋ง ์์ฑํ๋ค๋ ์ ์
๋๋ค.
๊ทธ ์ด์ ๋ PromptTemplate์ด ๋ด๋ถ์ ์ผ๋ก create ๋ฉ์๋๋ฅผ ํตํด Prompt๋ฅผ ๋ง๋ค ๊ฒฝ์ฐ, String์ ๋ฐํํ๊ฒ ๋๋๋ฐ (render ๋ฉ์๋ ํธ์ถ), Prompt๋ฅผ String์ผ๋ก ๋ง๋ค ๊ฒฝ์ฐ UserMessage๋ก ์ ์ฅํ๊ธฐ ๋๋ฌธ์
๋๋ค.
![](https://blog.kakaocdn.net/dn/mGncF/btsH8lPq2eZ/F9jrFzrlfEyMAGpf87ckNK/img.png)
![](https://blog.kakaocdn.net/dn/bZkybR/btsH82n1dUD/RKwSWMYubW7wNWcbCSiG4K/img.png)
๊ฐ์ธ์ ์ธ ์ถ์ธก์ผ๋ก๋, ์ด๋ ๊ฒ ํ
ํ๋ฆฟ์ด ํ์ํ ์ ๋๋ก ํ
์คํธ๊ฐ ๊ธธ์ด์ง๋ ๊ฒฝ์ฐ๋ ์ ์ ๋ฉ์์ง๋ฅผ ๋ง๋ค ๋๋ผ ๊ทธ๋ฐ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ญ๋๋ค. ์์คํ
๋ฉ์์ง ๊ฐ์ ๊ฒฝ์ฐ์๋ ๋จ์ํ ์ญํ ๋ถ์ฌ๋ก๋ ํ ์ ์์ผ๋ ์ ์ ๋ฉ์์ง์ ๊ฒฝ์ฐ์๋ ์ง์ํ ๋ฉ์์ง๊ฐ ๋งค์ฐ ๊ธธ์ด์ง ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
์ฌ๋ฌ ๋ฉ์์ง๋ฅผ ์ฃผ์ ํ๊ณ ์ถ๋ค๋ฉด?
ํ๋์ ํ๋กฌํํธ ๋ฉ์์ง์์ (PromptTemplate์ ํ์ฉํ) ์ ์ ๋ฉ์์ง ๋ง๊ณ ๋ ์์คํ
๋ฉ์์ง ๋ฑ์ ํจ๊ป ๋ฃ๊ณ ์ ํ๋ค๋ฉด, ์์ Prompt ํด๋์ค์์ ๋ณด์
จ๋ฏ์ด List<Message>๋ก Prompt๋ฅผ ์์ฑํ์๋ฉด ๋ฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด PromptTemplate์ ํ์ฉํ ์ ์ ๋ฉ์์ง์ ๊ฒฝ์ฐ์๋ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์?
์ผ๋จ PromptTemplate์ create ๋ฉ์๋๋ Prompt๋ฅผ ๋ฐํํ๋, ์ด๊ฒ๋ณด๋ค๋ String ํํ๊ฐ ๋ ๋์ ๊ฒ์
๋๋ค. PromptTemplate์์๋ render ๋ฉ์๋๋ฅผ ํตํด ์ ๋ฆฌ๋ String์ ๋ฐํํฉ๋๋ค.
![](https://blog.kakaocdn.net/dn/cxa1gR/btsH9pC6WGB/JTwBrfyvI1SAuhE5EdKN61/img.png)
์ด๋ฅผ ์์ฉํ๋ฉด ์๋ ์์ ์ฝ๋์ฒ๋ผ ์์ฑํ ์ ์์ต๋๋ค.
์์ ์ฝ๋
@RequestMapping("/test")
@RestController
public class AiController {
private final ChatModel chatModel;
public AiController(final ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping
public String test() {
String command = "Tell me a {adjective} joke about {content}.";
PromptTemplate template = new PromptTemplate(command);
template.add("adjective", "funny");
template.add("content", "life");
// Prompt prompt = template.create();
String message = template.render();
Message userMessage = new UserMessage(message);
Message systemMessage = new SystemMessage("translate to korean");
// Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
// ๋ฐ๋ก ์๋ต ๋ฉ์์ง๋ง ์ป๊ณ ์ถ๋ค๋ฉด Prompt ๋ณด๋ค ๋ฐ๋ก ...Message๋ฅผ ์ถ์ฒํฉ๋๋ค.
String response = chatModel.call(userMessage, systemMessage);
System.out.println("response = " + response);
return "ok";
}
}
์๋ต์ ์๋์ ๊ฐ์ด ๋์์ต๋๋ค.
![](https://blog.kakaocdn.net/dn/VEuMt/btsH8UwTARL/5YlpD79jDloeJlllVgMmQ1/img.png)
์ด๋ ๊ฒ PromptTemplate๊ณผ ๋ฉ์์ง๋ค์ ํตํ ํจ๊ณผ์ ์ธ ํ๋กฌํํธ ๋ฐฉ๋ฒ์ ์์๋ณด์์ต๋๋ค. ์ฝ์ด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค!