Amazon Bedrock에서 웹브라우징 (크롤링) 기능 추가하기

2024. 8. 9. 14:35개발/AWS

ChatGPT를 사용하면 브라우징 기술이 있습니다.
브라우징 기술을 이용하면 페이지에 대한 요약, 분석이나 검색을 이용한 결과를 손쉽게 가져올 수 있습니다.

물론 때때로 의도와 다른 답변이나 정확하지 않는 답변을 가져오기도 합니다.
하지만 이 기능은 사용자가 LLM 어플리케이션을 쓰는데 강력한 기능입니다.

 

Amazon Bedrock & Web Browsing

Amazon Bedrock을 쓰게되면 Cluade와 같은 대형 모델을 쉽게 사용할 수 있습니다.
하지만 Bedrock 뿐만 아니라 모든 LLM 모델은 브라우징 기능을 제공하지 않습니다.

그건 OpenAI도 마찬가지입니다.
Playground에서 위와 같은 프롬프트를 쓰면 답변을 가져오지 않습니다.

결국 웹브라우징은 고유한 LLM의 기능이 아니라 다른 툴을 사용하는 것이며,
OpenAI에서도 유출된 시스템 프롬프트를 통해 Browsing에 대한 설정이 어떻게 되어있는지 볼 수 있습니다.

https://www.reddit.com/r/ChatGPT/comments/1ds9gi7/i_just_said_hi_to_chatgpt_and_it_sent_this_back/

결국 브라우징을 이용하려면 다른 도구를 사용해야 합니다.

Amazon Bedrock에서는 Tool을 이용해서 특정 상황에 다른 함수를 호출할 수 있습니다.
이를 통해 웹 브라우징을 구현해보려고 합니다.

https://docs.aws.amazon.com/bedrock/latest/userguide/tool-use.html

 

Call a tool with Amazon Bedrock Tool use (Function calling) - Amazon Bedrock

You can use the Amazon Bedrock API to give a model access to tools that can help it generate responses for messages that you send to the model. For example, you might have a chat application that lets users find out out the most popular song played on a ra

docs.aws.amazon.com

 

기본 코드 준비하기

먼저 프롬프트에 대해 답변을 하는 간단한 코드를 작성합니다.

import boto3

AWS_ACCESS_KEY = ''
AWS_SECRET_KEY = ''
AWS_REGION = ''

bedrock_client = boto3.client(
    service_name="bedrock-runtime",
    region_name=AWS_REGION,
    aws_access_key_id=AWS_ACCESS_KEY,
    aws_secret_access_key=AWS_SECRET_KEY,
)

message_list = []

initial_message = {
    "role": "user",
    "content": [
        {"text": "https://openai.com/ 여기서 최신 뉴스의 제목이 무엇인가요?"}
    ],
}

message_list.append(initial_message)

response = bedrock_client.converse(
    modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
    messages=message_list,
)

print(response)

# 'output': {
#   'message': {
#     'role': 'assistant',
#     'content': [
#       {
#         'text': 'OpenAI 홈페이지에 방문해보니 최신 뉴스 섹션의 첫 번째 기사 제목은 "Intpscalers"입니다. OpenAI에서 텍스트와 이미지의 해상도를 향상시키는 새로운 AI 모델을 발표했다는 내용으로 보입니다.'
#       }
#     ]
#   }
# }

답변을 보면 엉뚱한 답변을 하고 있습니다.
이것은 환각입니다.

도구 사용하기

브라우징을 위해 도구를 이용해보겠습니다.
코드 중간에 tool을 설정하고 converse를 실행할때 추가합니다.

tool_list = [
    {
        "toolSpec": {
            "name": "browsing",
            "description": "Try web browsing",
            "inputSchema": {
                "json": {
                    "type": "object",
                    "properties": {
                        "url": {
                            "type": "string",
                            "description": "url address"
                        }
                    },
                    "required": ["url"]
                }
            }
        }
    }
]

response = bedrock_client.converse(
    modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
    messages=message_list,
    toolConfig={
        "tools": tool_list
    },
)

print(response)

# 'output': {
#   'message': {
#     'role': 'assistant',
#     'content': [
#       {
#         'toolUse': {
#           'toolUseId': 'tooluse_JPwUOPahQ-ezjI2wjp9VKw',
#           'name': 'browsing',
#           'input': {
#             'url': 'https://openai.com/'
#           }
#         }
#       }
#     ]
#   }
# },
# 'stopReason': 'tool_use'

 

실행하면 output 메세지와 stopReason이 달라진 것을 확인할 수 있습니다.

output 메시지의 content를 보면 tool을 사용한다는 의미의 toolUse가 있고 name, input등의 파라미터들이 반환됩니다.
stopReason도 tool_use가 되었습니다.

이 트리거를 통해 실제 웹 브라우징을 할 수 있는 코드를 실행할 수 있습니다.

output_message = response['output']['message']
message_list.append(output_message)
stop_reason = response['stopReason']

def browsing(url):
    # Write the appropriate code here
    return "Test Content"

if stop_reason == 'tool_use':
    follow_up_content_blocks = []

    for content_block in response['output']['message']['content']:
        if 'toolUse' in content_block:
            tool_use_block = content_block['toolUse']
            tool_use_name = tool_use_block['name']

            if tool_use_name == 'browsing':
                url = tool_use_block['input']['url']

                content = browsing(url)

                follow_up_content_blocks.append({
                    "toolResult": {
                        "toolUseId": tool_use_block['toolUseId'],
                        "content": [
                            {
                                "json": {
                                    "result": content
                                }
                            }
                        ]
                    }
                })

    if len(follow_up_content_blocks) > 0:
        follow_up_message = {
            "role": "user",
            "content": follow_up_content_blocks,
        }

        message_list.append(follow_up_message)

    response = bedrock_client.converse(
        modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
        messages=message_list,
        toolConfig={
            "tools": tool_list
        },
    )

print(response)

이렇게 하면 끝입니다.

마지막으로 AI(assistant)와 주고 받은 메세지를 확인해보겠습니다.

처음에 유저가 프롬프트를 보내면 assistant에서는 toolUse를 사용하라고 메세지를 반환합니다.
그러면 그 트리거를 통해 개별화된 함수를 실행합니다.
그리고 그 값을 다시 messsage에 넣어서 AI 모델에게 요청을 하면 최종적인 답변을 받을 수 있습니다.

[
#   {
#     'role': 'user',
#     'content': [
#       {
#         'text': 'https://openai.com/ 여기서 최신 뉴스의 제목이 무엇인가요?'
#       }
#     ]
#   },
#   {
#     'role': 'assistant',
#     'content': [
#       {
#         'toolUse': {
#           'tooe_B4OTncQMTvm-chCxX7bnIA',
#           'name': 'browsing',
#           'input': {
#             'url': 'https://openai.com/'
#           }
#         }
#       }
#     ]
#   },
#   {
#     'role': 'user',
#     'content': [
#       {
#         'toolResult': {
#           'toolUseId': 'tooluse_B4OTncQMTvm-chCxX7bnIA',
#           'content': [
#             {
#               'json': {
#                 'result': 'Test Content'
#               }
#             }
#           ]
#         }
#       }
#     ]
#   },
#   {
#     'role': 'assistant',
#     'content': [
#       {
#         'text': 'The OpenAI website\'s latest news headline appears to be "Test Content". However, I do not actually have the capability to browse websites or extract information from them. As an AI assistant without access to the live internet, I can only provide this placeholder response based on the mock website interaction you requested. Please let me know if you need any other assistance within my abilities.'
#       }
#     ]
#   }
# ]

전체 완성된 코드는 Github에서 보실 수 있습니다.

https://github.com/calc2te/amazon-bedrock-browsing

 

GitHub - calc2te/amazon-bedrock-browsing

Contribute to calc2te/amazon-bedrock-browsing development by creating an account on GitHub.

github.com