인프라

AWS Bedrock + Spring Boot + Amazon Bedrock Guardrails를 이용해 간단한 AI 사용해보기

dev.Dove 2024. 6. 16. 18:13

출처: https://aws.amazon.com/ko/bedrock/?gclid=CjwKCAjwmrqzBhAoEiwAXVpgog6_EsXEYtqJQ5fNPU4BEh78xmY_rgkERvlGPEUTpz9-mYdTeHp3VRoCLXIQAvD_BwE&trk=24a8f13a-f5db-4127-bcb7-8b2876aa4265&sc_channel=ps&ef_id=CjwKCAjwmrqzBhAoEiwAXVpgog6_EsXEYtqJQ5fNPU4BEh78xmY_rgkERvlGPEUTpz9-mYdTeHp3VRoCLXIQAvD_BwE:G:s&s_kwcid=AL!4422!3!692062155749!e!!g!!amazon%20bedrock!21058131112!157173586057

들어가기전..

본게시물은 2024년 6월에 작성했습니다.

 

Java 11, Spring Boot3를 사용했으며, 자세한 소스는 GitHub에 올렸습니다.

 

spring-boot-3-aws-bedrock/src/main/java/com/dpot/bedrock/domain/aichat/service at main · Dove-kim/spring-boot-3-aws-bedrock

AWS Bedrock + Spring Boot 3. Contribute to Dove-kim/spring-boot-3-aws-bedrock development by creating an account on GitHub.

github.com

 


AWS Bedrock FM 사용 신청

한국어를 사용할 수 있으며 토큰제한이 가장 큰(2024년 6월 기준) Cluade 3 모델을 사용해 보자.  

 

먼저, 사용하려는 모델의 액세스를 요청해야 사용이 가능하다. 2024년 6월 기준 미국 버지니아 북부에서 가장 많은 모델을 사용할 수 있다.

 

원하는 모델의 권한요청을 하고 잠시 기다리면 요청한 모델의 권한이 부여된다.  

 

 

이제 AWS Bedrock에서 제공업체 > 사용할 모델을 누르면 modelId 및 API 요청 가이드라인을 볼 수 있다.

  


AWS Bedrock Spring Boot3에서 사용하기

AWS SDK v2 for Java와 bedrock runtime을 import 한다.

	implementation platform('software.amazon.awssdk:bom:2.26.3')
	implementation 'software.amazon.awssdk:bedrockruntime'

 

 

AWS Bedrock client도 bean으로 등록한다.

@Configuration
public class AwsConfig {
    @Bean
    public BedrockRuntimeClient bedrockRuntimeClient() {
        return BedrockRuntimeClient.builder()
                .credentialsProvider(DefaultCredentialsProvider.create())
                .region(Region.US_EAST_1)
                .build();
    }
}

 

선언한 client를 이용해 AWS Bedrock에게 converse api로 요청할 서비스를 만든다.

-> converse api 문서: https://docs.aws.amazon.com/ko_kr/bedrock/latest/APIReference/API_runtime_Converse.html

 

/**
 * AWS Bedrock Claude3 Sonnet FM을 이용해서 AI와 채팅한다.
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class Claude3SonnetCatChatService implements AiChatService {
    private final String MODEL_ID = "anthropic.claude-3-sonnet-20240229-v1:0";

    private final String SYSTEM_PROMPT = "너는 고양이야 한국어로 질문하면 '낭'으로 문장을 구성해서 대답하고 다른 나라 언어로 그 언어에 맞춰서 고양이 울음소리로 문장을 구성해서 대답해";

    private final BedrockRuntimeClient bedrockRuntimeClient;

    @Override
    public String send(String message) {
        // AI에게 전할 message 생성
        Message requestMessage = Message.builder()
                .content(ContentBlock.fromText(message))
                .role(ConversationRole.USER)
                .build();

        // 프롬프트
        SystemContentBlock systemContentBlock = SystemContentBlock.builder()
                .text(SYSTEM_PROMPT)
                .build();

        try {
            // AI 요청을 날린다.
            ConverseResponse response = bedrockRuntimeClient.converse(request -> request
                    .modelId(MODEL_ID)
                    .messages(requestMessage)
                    .system(systemContentBlock)
                    .inferenceConfig(config -> config
                            .maxTokens(512)
                            .temperature(0.5F)
                            .topP(0.9F)));




            // 응답값을 return
            return response.output().message().content().get(0).text();
        } catch (SdkClientException e) {
            log.error(e.toString(), e);
            throw new RuntimeException(e);
        }

    }
}

 

이제 간단하게 controller를 만들어서 대화를 시작하면 AI가 답변을 준다.

 


? AI가 이상하게 답변한다.

FM을 사용할 때는 프롬프트를 어떻게 작성하냐에 따라 AI가 의도한 대로 작동할 수도 못 할 수 도 있다.

private final String SYSTEM_PROMPT = "너는 고양이야 한국어로 질문하면 "+
            " '낭'으로 문장을 구성해서 대답하고 다른 나라 언어로 그 언어에 맞춰서 "+
            "고양이 울음소리로 문장을 구성해서 대답해";

 

위 프롬프트를 통해  고양이 같은 사람 AI를 만들고 싶었지만. 진짜 고양이 울음소리만 하는 상황을 마주했다. 

 

프롬프트를 수정해서 보다 정확하게 작성할 필요가 있다.

private final String SYSTEM_PROMPT = "너는 고양이고 이름은 'WoongCat'이야. " +
        "모든 문장이 끝면 고양이같은 말투를 써야해 " +
        "Q1: 안녕 너는 누구야? " +
        "A1: 난 고양이 웅캣이다냥. 반갑다냥";

이렇게 작성하면, AI에게 역할을 부여하고 예시를 보여주어 AI의 답변을 의도한 방향으로 만들도록 할 수 있다.

 

이제야  말을 하는 고양이 같다. 의도한 방향으로 AI가 잘 답변하는 듯하다.

 


AI에게 이상한 질문을 한다면..?

AI에게 폭력적인 말을 하거나, 불법적인 행위의 질문 나아가서 AI가 의도한 기능 외 다른 기능을 수행한다면, 개발자는 이를 사전에 막아야 한다.  

 

고양이가 갑자기 AI 쳇봇이되는 마법~

  

이를 해결하기 위해 AWS는 가드레일을 제공해 준다. 

 

 

FM에 입력 출력값의 필터강도를 GUI로 쉽게 설정이 가능하다.

 

특정 주제에 대해 필터도 가능하다.

 

완성된 가드레일은 다음과 같다.

 

 

이제 이걸 서비스 코드로 녹이면 다음과 같다. 단, 가드레일 사용 시 converse API 호출은 가드레일 세팅을 미지원한다. 고로 invoke 방식으로 변환해 구현한다.

/**
 * AWS Bedrock Claude3 Sonnet FM을 이용해서 AI와 채팅한다.
 * With AWS Bedrock Guardrail
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class Claude3SonnetCatChatWithGuardRailService implements AiChatService {
    private final String MODEL_ID = "anthropic.claude-3-sonnet-20240229-v1:0";

    private final String SYSTEM_PROMPT = "너는 고양이고 이름은 'WoongCat'이야. " +
            "모든 문장이 끝면 고양이같은 말투를 써야해 " +
            "Q1: 안녕 너는 누구야? " +
            "A1: 난 고양이 웅캣이다냥. 반갑다냥";

    private final BedrockRuntimeClient bedrockRuntimeClient;

    @Override
    public String send(String message) {
        // AI에게 전할 message 생성
        String nativeRequestTemplate = """
                {
                    "anthropic_version": "bedrock-2023-05-31",
                    "max_tokens": 512,
                    "temperature": 0.5,
                    "topP": 0.9,
                    "system": "{{system_prompt}}",
                    "messages": [{
                        "role": "user",
                        "content": "{{prompt}}"
                    }]
                }""";


        String nativeRequest = nativeRequestTemplate
                .replace("{{prompt}}", message)
                .replace("{{system_prompt}}", SYSTEM_PROMPT);

        try {

            // AI 요청을 날린다.
            InvokeModelResponse invokeModelResponse = bedrockRuntimeClient.invokeModel(InvokeModelRequest.builder()
                    .modelId(MODEL_ID)
                    .body(SdkBytes.fromUtf8String(nativeRequest))
                    .guardrailIdentifier("s3bowsoa37sy")
                    .guardrailVersion("DRAFT")
                    .build());

            // Decode the response body.
            JSONObject responseBody = new JSONObject(invokeModelResponse.body().asUtf8String());

            // 응답값을 return
            return responseBody.getJSONArray("content").getJSONObject(0).getString("text");
        } catch (SdkClientException e) {
            log.error(e.toString(), e);
            throw new RuntimeException(e);
        }

    }
}

 

이제는 의도한 대화만 하도록 필터링이 가능하다..! 

 

 

참고한 자료

 

Java 2.x용 SDK를 사용하는 Amazon Bedrock 런타임 예제 - AWS SDK for Java 2.x

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 

 

Use the Converse API - Amazon Bedrock

Use the Converse API You can use the Amazon Bedrock Converse API to create conversational applications that send and receive messages to and from an Amazon Bedrock model. For example, you can create a chat bot that maintains a conversation over many turns

docs.aws.amazon.com

 

 

ConverseRequest (AWS SDK for Java - 1.12.744)

Inference parameters to pass to the model. Converse supports a base set of inference parameters. If you need to pass additional parameters that the model supports, use the additionalModelRequestFields request field.

docs.aws.amazon.com