안녕하세요 dev_writer입니다. 오늘은 저번에 말씀드린 대로 Spring AI에서 지원하는 PromptTemplate과 프롬프트의 근본적인 종류를 알려드리겠습니다.
프롬프트란
이제 프롬프트 (Prompt)라는 단어는 일상생활에서 쉽게 접할 수 있는 말이 되었습니다.
위키백과에서는 프롬프트를 생성형 AI 모델로 해석되고 이해할 수 있는 명령, AI가 수행해야 하는 작업을 설명하는 자연어 텍스트라 정의하고 있습니다.
효과적으로 프롬프트를 적용할 수 있는 사례를 정리한 글도 참고하시면 좋을 듯합니다.
Prompt 클래스
기본적으로 Spring AI에서 프롬프트를 나타내는 Prompt 클래스의 인스턴스를 생성할 때, 생성자를 보면 UserMessage로 생성됨을 보실 수 있습니다. 그리고 그 이외에도 Message 타입들이 있는 것을 보실 수 있습니다.
Message 인터페이스
다음으로 Message 인터페이스를 보겠습니다.
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)의 메시지를 통해 만든다는 것을 파악할 수 있습니다.
PromptTemplate 클래스
PromptTemplate 클래스는 텍스트 기반 템플릿 엔진을 활용하여 효과적으로 프롬프트를 생성할 수 있도록 합니다.
만약 다음 프롬프트가 제대로 동작하기 위해서는..
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로 저장하기 때문입니다.
개인적인 추측으로는, 이렇게 템플릿이 필요할 정도로 텍스트가 길어지는 경우는 유저 메시지를 만들 때라 그런 것 같다는 생각이 듭니다. 시스템 메시지 같은 경우에는 단순히 역할 부여로도 할 수 있으나 유저 메시지의 경우에는 질의할 메시지가 매우 길어질 수 있기 때문입니다.
여러 메시지를 주입하고 싶다면?
하나의 프롬프트 메시지에서 (PromptTemplate을 활용한) 유저 메시지 말고도 시스템 메시지 등을 함께 넣고자 한다면, 위의 Prompt 클래스에서 보셨듯이 List<Message>로 Prompt를 생성하시면 됩니다.
그렇다면 PromptTemplate을 활용한 유저 메시지의 경우에는 어떻게 해야 할까요?
일단 PromptTemplate의 create 메서드는 Prompt를 반환하니, 이것보다는 String 형태가 더 나을 것입니다. PromptTemplate에서는 render 메서드를 통해 정리된 String을 반환합니다.
이를 응용하면 아래 예제 코드처럼 작성할 수 있습니다.
예제 코드
@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";
}
}
응답은 아래와 같이 나왔습니다.
이렇게 PromptTemplate과 메시지들을 통한 효과적인 프롬프트 방법을 알아보았습니다. 읽어주셔서 감사합니다!
Reference
'🚀 팁 (기술 적용 방법 등) > 🤖 Spring AI 파헤치기' 카테고리의 다른 글
[Spring AI 🤖] Spring AI 변경점 이슈 알아보기 (24.05.22 Issue) (0) | 2024.05.26 |
---|---|
[Spring AI 🤖] Spring AI를 적용해보자! (3) | 2024.05.02 |