Bedrock KB를 구성했다면, 이제는 KB를 사용해보는 방법에 대해서 알아본다. KB를 만드는것처럼 아주아주 간단하다.
일반적으로 LLM, AI 관련된 서비스는 Python으로 많이들 구현하지만 필자는 Go 기반의 애플리케이션이 있기 때문에 Go로 구현했다.
AWS SDK에 이미 Bedrock KB를 구현할 수 있는 RetrieveAndGenerator SDK가 있다.
이름에서 알 수 있듯이 Opensearch serverless에서 가장 유사도 높은 문서를 검색하고(=Retrieve)
이를 검색 증강에 포함하여 풍부한 응답을 만들어 내는 것이다.(=Generator) 이를 이용하면 쉽게 RAG를 구현할 수 있다.
RetrieveAndGenerator 사용방법
처음에 구현할 때는 Go에 해당 SDK가 없어서, Python으로 Lambda 함수로 만들어서 Invoke하도록 구현했다.
하지만 Go SDK에 동일한것이 있었고, 다시 Go로 구현했다.
Using Python
먼저 Python으로는 아래처럼 구현할 수 있다. 기본적으로 Claude 3.5 Sonnet 모델을 사용했으며 별도 파라미터는 사용하지 않았다.
아래오 같이 사용하면 response에서 SessionId, Text를 확인할 수 있다.
- Text 필드에 있는 데이터가 실제로 Bedrock KB를 통해서 만들어진 응답이다.
import json
import boto3
bedrock_client = boto3.client('bedrock-agent-runtime', region_name='us-east-1')
def retrieve(prompt, knowledgeBaseId):
modelArn = 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0'
response = bedrock_client.retrieve_and_generate(
input={
'text': prompt
},
retrieveAndGenerateConfiguration={
'type': 'KNOWLEDGE_BASE',
'knowledgeBaseConfiguration': {
'knowledgeBaseId': knowledgeBaseId,
'modelArn': modelArn
}
}
)
print(response['output'])
return response['output']
def lambda_handler(event, context):
# prompt = "오늘 점심으로 한식을 먹고 싶은데, 한식 메뉴를 추천해줄래?"
# knowledgeBaseId = "XPKWAA99OK"
prompt = event.get('prompt', '')
knowledgeBaseId = event.get('knowledgebase_id', '')
response = retrieve(prompt, knowledgeBaseId)
return {
'statusCode': 200,
'body': json.dumps(response)
}
Using Go
Go로 구현할 때는 KB ParameterInput을 만드는 것과 실제로 RetrieveAndGenerator를 호출하는 것을 분리했다.
그리고 Temperature, TopP Parameter를 사용했다.
- Temperature는 쉽게 말하면 자유도를 뜻한다. 1에 가까울수록 동일한 질문에 대해서 동일한 답을 만든다.
- TopP는 유사도의 김계치를 뜻한다. 만약에 0.8이라는 수치를 주면 유사도가 80% 인 문서에 대해서만 사용하겠다는 뜻이다.
Parameter 값에 따라서 응답이 천차만별이기 때문에 여러번 테스트해서, 최적의 값을 찾는것이 중요하다.
그리고 SessionId는 Chat History를 관리하는 값이라고 보면 된다. 동일한 SessionId에 대해서는 같은 대화로 간주한다.
동일한 Session이면 지금까지 했던 내용을 모두 Context에 넣어서 질의를 하게 된다.(기본값이 24시간)
- 처음에는 DDB에 Bedrock Input/Output을 모두 넣고, 고유값을 기준으로 SELECT해서 사용할 예정이었으나 SessionId라는 것으로 쉽게 대체가 가능하다.
그렇기에 동일한 대화인지, 최초 대화인지에 따라서 SessionId Map을 만들고 이를 업데이트하거나 불러와서 사용하면 된다.
#AWS Bedrock KnowledgeBase Parameter Input 만드는 함수
func CreateBedrockKnowledgeParameters(prompt string, sessionId *string) *bedrockagentruntime.RetrieveAndGenerateInput {
bedrockagentInput := &bedrockagentruntime.RetrieveAndGenerateInput{
Input: &types.RetrieveAndGenerateInput{
Text: &prompt,
},
SessionId: sessionId,
RetrieveAndGenerateConfiguration: &types.RetrieveAndGenerateConfiguration{
Type: "KNOWLEDGE_BASE",
KnowledgeBaseConfiguration: &types.KnowledgeBaseRetrieveAndGenerateConfiguration{
GenerationConfiguration: &types.GenerationConfiguration{
InferenceConfig: &types.InferenceConfig{
TextInferenceConfig: &types.TextInferenceConfig{
Temperature: aws.Float32(0.9),
TopP: aws.Float32(0.8),
},
},
},
ModelArn: aws.String(modelArn),
KnowledgeBaseId: aws.String(knowledgeBaseId),
},
},
}
return bedrockagentInput
}
#AWS Bedrock Knowledge Parameter 중에서 SessionId를 구하거나 업데이트하는 함수
func UpdateBedrockKnowSessionId(messageTs string, SessionId *string) {
sessionMap[messageTs] = SessionId
}
func GetBedrockKnowSessionId(messageTs string) *string {
return sessionMap[messageTs]
}
그리고 ParameterInput을 만들었다면, 이를 RetrieveAndGenerate 함수에 넣어서 호출하면 된다. 아주 쉽다.
response.Output.Text 필드에는 Bedrock KB를 통해서 만들어진 응답 값이 있다. 이를 return해서 사용하면 된다.
func (b *AWSBedrockGateway) GetBedrockKnowledgeResponse(ctx context.Context, parameters *bedrockagentruntime.RetrieveAndGenerateInput) (*string, *string, error) {
response, err := b.bedrockAgentClient.RetrieveAndGenerate(ctx, parameters)
if err != nil {
b.logger.Error("can not execute bedrock knowledgebase, error: ", err)
return nil, nil, err
}
bedrockResponseString := response.Output.Text
bedrockResponseSessionId := response.SessionId
return bedrockResponseString, bedrockResponseSessionId, nil
}
Slack EventSubscribe + Bedrock KB
Slack EventSubscribe와 같이 결합하면 AI Chatbot으로 쉽게 구현할 수 있다.
- EventSubscribe를 할 때는 최초에 url_validator를 한번 해야하기 때문에 이것도 같이 고려해야 한다.
Go로 구현할 때 Prompt를 만들어서 페르소나를 정의해주기 때문에 아래와 같이 커스텀 된 응답을 주는 것을 볼 수 있다.
그리고 동일한 스레드을 경우에는 SessionId를 같은 값으로 사용하여 아래와 같이 Chat History가 유지되는 것을 볼 수 있다.
Chat History가 유지가 되어야지만 Chatbot으로서 조금 더 가치있는 일을 할 수 있다. 그렇지 않으면 단편적인 질문밖에 하지 못한다.
이외에도 API Docs 파일을 S3에 업로드하면 API FAQ Chatbot으로 사용할 수도 있고, 맛집 리스트 파일을 S3에 업로드를 하면 맛집을 추천해주는 사내 Bot으로 사용할 수 있다.
이뿐만 아니라 HR 문서 또는 각종 사내 문서를 S3에 업로드하면 쉽게 사내 CS Chatbot을 만들 수 있다.
- 예를들어) AWS 권한 신청 방법을 정리해서 S3에 업로드하거나/솔루션 사용 방법을 S3에 업로드해서 사용할 수도 있다.
AI Chatbot 도식도
필자는 API를 EKS 위의 Pod으로 배포하여 사용하고 있다. 이때 전체적인 도식도는 아래와 같다.
먼저 사용자가 Slack에서 앱멘션으로 호출하게 되면, EventSubscribe로 Pod으로 관련 데이터를 전달하게 되고 Pod에서 파싱해서 Bedrock KB를 호출한다.
그리고 Bedrock KB 호출 결과를 Slack SDK를 사용해서 Slack에 댓글을 추가하면 된다. 구현이 간단한 만큼 도식도도 간단한다.
AI Chatbot TOBE
지금은 어떤 사용자가 어떤 질문을 하고, 응답이 어떻게 되는지에 대해서 별도 저장을 하지 않고있다.
AI를 이용한만큼 적절한 응답이 나갔는지 평가하는 과정은 꼭 필요하다고 생각한다.
그래서 아직 구현은 안했지만 사용자 질문과 Bedrock KB 응답을 DDB에 저장하고 이를 일 1회정도로 평가하려고 한다.
- 부적절한 질문을 하지는 않는지?
- 부적절한 응답을 하지는 않는지?
결과적으로 부적절한 응답을 하지 않는지?가 핵심이 될것 같은데, 최근에는 AI 모델을 평가하는 모델까지 나왔다고 하니, 이를 활용해본 생각이다. 또는 RAG는 Claude 3.5 Sonnet으로 구현했다면 Claude Haiku 모델을 사용해서 모델 평가를 하면 되지 않을까한다.
이처럼 어떤 데이터를 활용하느냐, 어떻게 기획하고 사용할지에 대한 니즈에 따라서 Bedrock KB의 쓰임새가 아주 무궁무진하다.
Bedrock을 이용하여 Chatbot을 구현하는 것이 가장 쉽고, 가장 일반적인 방법이기 때문에 사내 AI Chatbot을 구현해서 사용하고 있다.
Chatbot에 국한되지 않고 Bedrock을 통해서 앞으로 어떤 일을 할 수 있는지 고민을 더 해보고 적극적으로 사용해볼 예정이다.
간단한 일은 AI에 맡기도, 나는 고부가가치의 일을 하는것이 AI 시대에 맞는 일하는 방법이라고 생각한다.
처음 시작은 작을지언정 끝은 창대하리라!!
끝!
'기술 이모저모 > [Ops] Devops' 카테고리의 다른 글
[AWS][AI] RAG기반의 생성형 AI Chatbot 성능 끌어올리기 (2) | 2024.11.21 |
---|---|
[AWS][AI] AWS Bedrock KnowledgeBase 사용 방법 (1) | 2024.10.05 |
[Finops] AMD vs ARM, AWS Graviton Node (1) | 2024.09.22 |
[AI] 요즘은 안하는 사람이 없다는 Gen AI, 나도 해보자. (0) | 2024.06.30 |
[LGTM] Observability 기술스택 변경 여정 두번째, PLG 스택 배포 (0) | 2024.03.10 |