{"id":25009931,"url":"https://github.com/kyopark2014/llm-streamlit","last_synced_at":"2025-04-12T19:33:40.750Z","repository":{"id":271161282,"uuid":"903189161","full_name":"kyopark2014/llm-streamlit","owner":"kyopark2014","description":"It shows how to implement security best practices when using Streamlit for chatbot development.","archived":false,"fork":false,"pushed_at":"2025-04-04T12:30:42.000Z","size":1262,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T13:36:03.856Z","etag":null,"topics":["agent","aws","cdk","claude","nova","streamlit"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kyopark2014.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-14T00:27:46.000Z","updated_at":"2025-04-04T12:30:45.000Z","dependencies_parsed_at":"2025-01-06T00:28:32.612Z","dependency_job_id":"a48eeaf9-f7c7-4088-9b47-14008e571fa5","html_url":"https://github.com/kyopark2014/llm-streamlit","commit_stats":null,"previous_names":["kyopark2014/llm-streamlit"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyopark2014%2Fllm-streamlit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyopark2014%2Fllm-streamlit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyopark2014%2Fllm-streamlit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyopark2014%2Fllm-streamlit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kyopark2014","download_url":"https://codeload.github.com/kyopark2014/llm-streamlit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248621155,"owners_count":21134762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","aws","cdk","claude","nova","streamlit"],"created_at":"2025-02-05T04:52:12.553Z","updated_at":"2025-04-12T19:33:40.743Z","avatar_url":"https://github.com/kyopark2014.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Streamlit을 이용한 GenAI Application 배포 및 활용\n\n\u003cp align=\"left\"\u003e\n    \u003ca href=\"https://hits.seeyoufarm.com\"\u003e\u003cimg src=\"https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fkyopark2014%2Fllm-streamlit\u0026count_bg=%2379C83D\u0026title_bg=%23555555\u0026icon=\u0026icon_color=%23E7E7E7\u0026title=hits\u0026edge_flat=false)](https://hits.seeyoufarm.com\"/\u003e\u003c/a\u003e\n    \u003cimg alt=\"License\" src=\"https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square\"\u003e\n\u003c/p\u003e\n\n\n\n여기서는 [Streamlit](https://streamlit.io/)을 이용해 개발한 GenAI application을 쉽게 배포하고 안전하게 활용할 수 있는 방법에 대해 설명합니다. 한번에 배포하고 바로 활용할 수 있도록 [CDK](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html)를 이용하였고, ALB - EC2의 구조를 이용해서 필요시 scale out도 구현할 수 있습니다. 또한, [CloudFront](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html) - ALB 구조를 이용해 배포후 HTTPS로 안전하게 접속할 수 있습니다. Streamlit이 설치되는 EC2의 OS는 EKS/ECS와 같은 컨테이너 서비스에 주로 사용되는 [Amazon Linux](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html)을 사용하여 트래픽이 증가하여 ECS/EKS로 전환할 때에 수고를 줄일 수 있도록 하였습니다.\n\n## System Architecture \n\n전체적인 architecture는 아래와 같습니다. 여기서에서는 streamlit이 설치된 EC2는 private subnet에 둬서 안전하게 관리합니다. [Amazon S3는 Gateway Endpoint](https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html)를 이용하여 연결하고 Bedrock은 [Private link](https://docs.aws.amazon.com/ko_kr/bedrock/latest/userguide/usingVPC.html)를 이용하여 연결하였으므로 EC2의 트래픽은 외부로 나가지 않고 AWS 내부에서 처리가 됩니다. 인터넷 및 날씨의 검색 API는 외부 서비스 공급자의 API를 이용하므로 [NAT gateway](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)를 이용하여 연결하였습니다.\n\n\u003cimg width=\"800\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2fd4a38c-170c-401a-8103-e5641ed25378\" /\u003e\n\n### CDK로 배포 환경 구현\n\nEC2를 아래와 같이 정의합니다. 상세한 내용은 [cdk-llm-streamlit-stack.ts](./cdk-llm-streamlit/lib/cdk-llm-streamlit-stack.ts)을 참조합니다.\n\n```java\nconst appInstance = new ec2.Instance(this, `app-for-${projectName}`, {\n    instanceName: `app-for-${projectName}`,\n    instanceType: new ec2.InstanceType('t2.small'), // m5.large\n    machineImage: new ec2.AmazonLinuxImage({\n        generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023\n    }),\n    vpc: vpc,\n    vpcSubnets: {\n        subnets: vpc.privateSubnets \n    },\n    securityGroup: ec2Sg,\n    role: ec2Role,\n    userData: userData,\n    blockDevices: [{\n        deviceName: '/dev/xvda',\n        volume: ec2.BlockDeviceVolume.ebs(8, {\n            deleteOnTermination: true,\n            encrypted: true,\n        }),\n    }],\n    detailedMonitoring: true,\n    instanceInitiatedShutdownBehavior: ec2.InstanceInitiatedShutdownBehavior.TERMINATE,\n});\nappInstance.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);\n```\n\nEC2의 userdata는 아래와 같이 설정합니다. 필요한 패키지를 설치하고 streamlit을 서비스로 배포합니다. Streamlit의 기본 포트는 8501이나 여기서는 config.toml을 이용하여 포트를 8080으로 변경하였습니다. App이 ec2-user 계정에 있어야 하므로 아래와 같이 필요한 패키지를 설치합니다.\n\n```java\nconst userData = ec2.UserData.forLinux();\n\nconst commands = [\n  'yum install git python-pip -y',\n  'pip install pip --upgrade',            \n  `sh -c \"cat \u003c\u003cEOF \u003e /etc/systemd/system/streamlit.service\n[Unit]\nDescription=Streamlit\nAfter=network-online.target\n\n[Service]\nUser=ec2-user\nGroup=ec2-user\nRestart=always\nExecStart=/home/ec2-user/.local/bin/streamlit run /home/ec2-user/${projectName}/application/app.py\n\n[Install]\nWantedBy=multi-user.target\nEOF\"`,\n    `runuser -l ec2-user -c \"mkdir -p /home/ec2-user/.streamlit\"`,\n    `runuser -l ec2-user -c \"cat \u003c\u003cEOF \u003e /home/ec2-user/.streamlit/config.toml\n[server]\nport=${targetPort}\nEOF\"`,\n  `runuser -l ec2-user -c 'cd \u0026\u0026 git clone https://github.com/kyopark2014/${projectName}'`,\n  `runuser -l ec2-user -c 'pip install streamlit streamlit_chat'`,        \n  `runuser -l ec2-user -c 'pip install boto3 langchain_aws langchain langchain_community langgraph'`,\n  `runuser -l ec2-user -c 'pip install beautifulsoup4 pytz tavily-python'`,\n  'systemctl enable streamlit.service',\n  'systemctl start streamlit'\n];\nuserData.addCommands(...commands);\n```\n\nALB를 준비합니다.\n\n```java\nconst alb = new elbv2.ApplicationLoadBalancer(this, `alb-for-${projectName}`, {\n  internetFacing: true,\n  vpc: vpc,\n  vpcSubnets: {\n    subnets: vpc.publicSubnets\n  },\n  securityGroup: albSg,\n  loadBalancerName: `alb-for-${projectName}`\n})\nalb.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);\n```\n\nHTTPS로 streamlit을 이용하기 위해서는 ALB에 인증서를 추가하거나 CloudFront를 이용할 수 있습니다. Streamlit은 주로 PoC나 테스트 앱 용도로 활용하므로 별도 인증서를 받지 않고 CloudFront로 손쉽게 HTTPS 커텍션을 제공합니다. 이를 위해, CloudFront가 ALB의 HTTP 80포트와 연결가능하도록 사용하도록 준비합니다. \n\n```java\nconst CUSTOM_HEADER_NAME = \"X-Custom-Header\"\nconst CUSTOM_HEADER_VALUE = `xxxx`\nconst origin = new origins.LoadBalancerV2Origin(alb, {      \n  httpPort: 80,\n  customHeaders: {[CUSTOM_HEADER_NAME] : CUSTOM_HEADER_VALUE},\n  originShieldEnabled: false,\n  protocolPolicy: cloudFront.OriginProtocolPolicy.HTTP_ONLY      \n});\nconst distribution = new cloudFront.Distribution(this, `cloudfront-for-${projectName}`, {\n  comment: \"CloudFront distribution for Streamlit frontend application\",\n  defaultBehavior: {\n    origin: origin,\n    viewerProtocolPolicy: cloudFront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n    allowedMethods: cloudFront.AllowedMethods.ALLOW_ALL,\n    cachePolicy: cloudFront.CachePolicy.CACHING_DISABLED,\n    originRequestPolicy: cloudFront.OriginRequestPolicy.ALL_VIEWER        \n  },\n  priceClass: cloudFront.PriceClass.PRICE_CLASS_200\n}); \n```\n\nALB의 Listener가 stremlit이 설치되는 EC2로 라우팅 되도록 설정합니다. \n    \n```java\nconst listener = alb.addListener(`HttpListener-for-${projectName}`, {   \n  port: 80,\n  open: true\n});     \nconst targetGroup = listener.addTargets(`WebEc2Target-for-${projectName}`, {\n  targetGroupName: `TG-for-${projectName}`,\n  targets: targets,\n  protocol: elbv2.ApplicationProtocol.HTTP,\n  port: targetPort,\n  conditions: [elbv2.ListenerCondition.httpHeader(CUSTOM_HEADER_NAME, [CUSTOM_HEADER_VALUE])],\n  priority: 10      \n});\nlistener.addTargetGroups(`addTG-for-${projectName}`, {\n  targetGroups: [targetGroup]\n})\nconst defaultAction = elbv2.ListenerAction.fixedResponse(403, {\n    contentType: \"text/plain\",\n    messageBody: 'Access denied',\n})\nlistener.addAction(`RedirectHttpListener-for-${projectName}`, {\n  action: defaultAction\n});  \n```\n\n## 상세 구현\n\nAgentic workflow (tool use)는 아래와 같이 구현할 수 있습니다. 상세한 내용은 [chat.py](./application/chat.py)을 참조합니다.\n\n```python\ndef buildAgentExecutor():\n    workflow = StateGraph(State)\n\n    workflow.add_node(\"agent\", execution_agent_node)\n    workflow.add_node(\"action\", tool_node)\n    workflow.add_node(\"final_answer\", final_answer)\n    \n    workflow.add_edge(START, \"agent\")\n    workflow.add_conditional_edges(\n        \"agent\",\n        should_continue,\n        {\n            \"continue\": \"action\",\n            \"end\": \"final_answer\",\n        },\n    )\n    workflow.add_edge(\"action\", \"agent\")\n    workflow.add_edge(\"final_answer\", END)\n\n    return workflow.compile()\n```\n\n번역하기는 아래와 같이 한/영이 변환 가능하도록 구성하였습니다. XML tag를 이용해 답변만 추출하는 방식을 사용하였습니다. XML tag는 anthropic의 claude 모델에서 추천하는 방식인데, Nova pro에서도 유용하게 사용할 수 있습니다. \n\n```python\ndef translate_text(text):\n    chat = get_chat()\n\n    system = (\n        \"You are a helpful assistant that translates {input_language} to {output_language} in \u003carticle\u003e tags. Put it in \u003cresult\u003e tags.\"\n    )\n    human = \"\u003carticle\u003e{text}\u003c/article\u003e\"\n    \n    prompt = ChatPromptTemplate.from_messages([(\"system\", system), (\"human\", human)])\n    # print('prompt: ', prompt)\n    \n    if isKorean(text)==False :\n        input_language = \"English\"\n        output_language = \"Korean\"\n    else:\n        input_language = \"Korean\"\n        output_language = \"English\"\n                        \n    chain = prompt | chat    \n    try: \n        result = chain.invoke(\n            {\n                \"input_language\": input_language,\n                \"output_language\": output_language,\n                \"text\": text,\n            }\n        )\n        msg = result.content\n        print('translated text: ', msg)\n    except Exception:\n        err_msg = traceback.format_exc()\n        print('error message: ', err_msg)                    \n        raise Exception (\"Not able to request to LLM\")\n\n    return msg[msg.find('\u003cresult\u003e')+8:msg.find('\u003c/result\u003e')] \n```\n\n이미지 분석하는 방법은 아래와 같습니다. 이미지 분석을 요청할때 \"사진속 사람들의 행동을 분석해주세요\"와 같이 base64로 encoding된 이미지의 내용에 대해 힌트를 제공하면 훨씬 더 좋은 결과를 얻을 수 있습니다. 여기에서는 아래와 같이 사용자가 입력한 메시지를 힌트로 사용하여 이미지를 분석하고 있습니다.\n\n```python\ndef use_multimodal(img_base64, query):    \n    multimodal = get_chat()\n    \n    messages = [\n        SystemMessage(content=\"답변은 500자 이내의 한국어로 설명해주세요.\"),\n        HumanMessage(\n            content=[\n                {\n                    \"type\": \"image_url\",\n                    \"image_url\": {\n                        \"url\": f\"data:image/png;base64,{img_base64}\", \n                    },\n                },\n                {\n                    \"type\": \"text\", \"text\": query\n                },\n            ]\n        )\n    ]\n    \n    try: \n        result = multimodal.invoke(messages)\n        \n        summary = result.content\n        print('result of code summarization: ', summary)\n    except Exception:\n        err_msg = traceback.format_exc()\n        print('error message: ', err_msg)                    \n        raise Exception (\"Not able to request to LLM\")\n    \n    return summary\n```\n\n### Basic Chat\n\n일반적인 대화는 아래와 같이 stream으로 결과를 얻을 수 있습니다. 여기에서는 LangChain의 ChatBedrock과 Nova Pro의 모델명인 \"us.amazon.nova-pro-v1:0\"을 활용하고 있습니다.\n\n```python\nmodelId = \"us.amazon.nova-pro-v1:0\"\nbedrock_region = \"us-west-2\"\nboto3_bedrock = boto3.client(\n    service_name='bedrock-runtime',\n    region_name=bedrock_region,\n    config=Config(\n        retries = {\n            'max_attempts': 30\n        }\n    )\n)\nparameters = {\n    \"max_tokens\":maxOutputTokens,     \n    \"temperature\":0.1,\n    \"top_k\":250,\n    \"top_p\":0.9,\n    \"stop_sequences\": [\"\\n\\n\u003cthinking\u003e\", \"\\n\u003cthinking\u003e\", \" \u003cthinking\u003e\"]\n}\n\nchat = ChatBedrock(  \n    model_id=modelId,\n    client=boto3_bedrock, \n    model_kwargs=parameters,\n    region_name=bedrock_region\n)\n\nsystem = (\n    \"당신의 이름은 서연이고, 질문에 대해 친절하게 답변하는 사려깊은 인공지능 도우미입니다.\"\n    \"상황에 맞는 구체적인 세부 정보를 충분히 제공합니다.\" \n    \"모르는 질문을 받으면 솔직히 모른다고 말합니다.\"\n)\n\nhuman = \"Question: {input}\"\n\nprompt = ChatPromptTemplate.from_messages([\n    (\"system\", system), \n    MessagesPlaceholder(variable_name=\"history\"), \n    (\"human\", human)\n])\n            \nhistory = memory_chain.load_memory_variables({})[\"chat_history\"]\n\nchain = prompt | chat | StrOutputParser()\nstream = chain.stream(\n    {\n        \"history\": history,\n        \"input\": query,\n    }\n)  \nprint('stream: ', stream)\n```\n\n### Agentic Workflow: Tool Use\n\n아래와 같이 activity diagram을 이용하여 node/edge/conditional edge로 구성되는 \btool use 방식의 agent를 구현할 수 있습니다.\n\n\u003cimg width=\"261\" alt=\"image\" src=\"https://github.com/user-attachments/assets/31202a6a-950f-44d6-b50e-644d28012d8f\" /\u003e\n\nTool use 방식 agent의 workflow는 아래와 같습니다. Fuction을 선택하는 call model 노드과 실행하는 tool 노드로 구성됩니다. 선택된 tool의 결과에 따라 cycle형태로 추가 실행을 하거나 종료하면서 결과를 전달할 수 있습니다.\n\n```python\nworkflow = StateGraph(State)\n\nworkflow.add_node(\"agent\", call_model)\nworkflow.add_node(\"action\", tool_node)\nworkflow.add_edge(START, \"agent\")\nworkflow.add_conditional_edges(\n    \"agent\",\n    should_continue,\n    {\n        \"continue\": \"action\",\n        \"end\": END,\n    },\n)\nworkflow.add_edge(\"action\", \"agent\")\n\napp = workflow.compile()\n\ninputs = [HumanMessage(content=query)]\nconfig = {\n    \"recursion_limit\": 50\n}\nmessage = app.invoke({\"messages\": inputs}, config)\n\nprint(event[\"messages\"][-1].content)\n```\n\n\n### 활용 방법\n\nEC2는 Private Subnet에 있으므로 SSL로 접속할 수 없습니다. 따라서, [Console-EC2](https://us-west-2.console.aws.amazon.com/ec2/home?region=us-west-2#Instances:)에 접속하여 \"app-for-llm-streamlit\"를 선택한 후에 Connect에서 sesseion manager를 선택하여 접속합니다. \n\nGithub에서 app에 대한 코드를 업데이트 하였다면, EC2에 session manager를 이용해 접속한 후에 아래 명령어로 업데이트 합니다. \n\n```text\nsudo runuser -l ec2-user -c 'cd /home/ec2-user/llm-streamlit \u0026\u0026 git pull'\n```\n\nStreamlit의 재시작이 필요하다면 아래 명령어로 service를 stop/start 시키고 동작을 확인할 수 있습니다.\n\n```text\nsudo systemctl stop streamlit\nsudo systemctl start streamlit\nsudo systemctl status streamlit -l\n```\n\nLocal에서 디버깅을 빠르게 진행하고 싶다면 [Local에서 실행하기](https://github.com/kyopark2014/llm-streamlit/blob/main/deployment.md#local%EC%97%90%EC%84%9C-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0)에 따라서 Local에 필요한 패키지와 환경변수를 업데이트 합니다. 이후 아래 명령어서 실행합니다.\n\n```text\nstreamlit run application/app.py\n```\n\nEC2에서 debug을 하면서 개발할때 사용하는 명령어입니다.\n\n먼저, 시스템에 등록된 streamlit을 종료합니다.\n\n```text\nsudo systemctl stop streamlit\n```\n\n이후 EC2를 session manager를 이용해 접속한 이후에 아래 명령어를 이용해 실행하면 로그를 보면서 수정을 할 수 있습니다. \n\n```text\nsudo runuser -l ec2-user -c \"/home/ec2-user/.local/bin/streamlit run /home/ec2-user/llm-streamlit/application/app.py\"\n```\n\n\n\n## 직접 실습 해보기\n\n### 사전 준비 사항\n\n이 솔루션을 사용하기 위해서는 사전에 아래와 같은 준비가 되어야 합니다.\n\n- [AWS Account 생성](https://repost.aws/ko/knowledge-center/create-and-activate-aws-account)에 따라 계정을 준비합니다.\n\n### CDK를 이용한 인프라 설치\n\n본 실습에서는 us-west-2 리전을 사용합니다. [인프라 설치](./deployment.md)에 따라 CDK로 인프라 설치를 진행합니다. \n\n## 실행결과\n\n왼쪽의 메뉴에서 아래와 같이 일상적인 대화, Agentic Workflow (Tool Use), 번역하기, 문법 검토하기, 이미지 분석을 제공합니다. 각 메뉴를 선택하여 아래와 같이 활용할 수 있습니다. \n\n![image](https://github.com/user-attachments/assets/7ab0d2e7-3bd0-44b9-b2be-f4d68a6ff60b)\n\n\n\n### 일상적인 대화\n\n메뉴에서 일상적인 대화를 선택하고 아래와 같이 인사와 함께 날씨 질문을 합니다. Prompt에 따라서 챗봇의 이름이 서연이라고 얘기하고 있으며, 일상적인 대화에서는 API를 호출할수 없으므로 날씨 정보는 제공할 수 없습니다. \n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/a0c305a0-34ca-450f-9cd5-5689aca9a0f9\" /\u003e\n\n### Agentic Workflow\n\nAgentic Workflow(Tool Use) 메뉴를 선택하여 오늘 서울의 날씨에 대해 질문을 하면, 아래와 같이 입력하고 결과를 확인합니다. LangGraph로 구현된 Tool Use 패턴의 agent는 날씨에 대한 요청이 올 경우에 openweathermap의 API를 요청해 날씨정보를 조회하여 활용할 수 있습니다. \n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/4693c1ff-b7e9-43f5-b7b7-af354b572f07\" /\u003e\n\n\n아래와 같은 질문은 LLM이 가지고 있지 않은 정보이므로, 인터넷 검색을 수행하고 그 결과로 아래와 같은 답변을 얻었습니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8f8d2e94-8be1-4b75-8795-4db9a8fa340f\" /\u003e\n\n\n### 번역하기\n\n메뉴에서 \"번역하기\"를 선택하고 아래와 같이 한국어를 입력하면 영어로 번역을 수행합니다. 만약 입력이 영어였다면 한국어로 번역하도록 프롬프트를 구성하였습니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8649b4c9-3f9d-45ab-8bb2-5693501972cd\" /\u003e\n\n### 문법 검토하기\n\n문법 검토하기를 선택후 문장을 입력하면 아래와 같이 수정이 필요한 부분을 알려주고 수정된 문장도 함께 제시합니다. \n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/0afc2778-772c-4505-b901-67eae5beeb90\" /\u003e\n\n### 이미지 분석\n\n이미지를 분석할 수 있는 프롬프트를 테스트해 볼 수 있습니다. 왼쪽의 \"Browse files\"를 선택하고, \"ReAct의 장점에 대해 설명해주세요.\"라고 입력합니다. \n\n이때 [사용한 이미지](./contents/example-table.png)는 아래와 같습니다. 이 이미지는 ReAct와 CoT를 비교하고 있습니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ec22508a-1569-49a1-a6fb-6442bc972d2a\" /\u003e\n\n이때의 결과는 아래와 같습니다. 입력한 메시지에 맞는 의미를 그림파일에서 찾고 아래와 같이 먼저 결과를 제시합니다. 실제 LLM이 인식한 표를 아래와 같이 확인할 수 있습니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/39fb2235-c6ef-42e0-8f43-f158cb088db4\" /\u003e\n\n\n메뉴에서 [이미지 분석]과 모델로 [Claude 3.5 Sonnet]을 선택한 후에 [기다리는 사람들 사진](./contents/waiting_people.jpg)을 다운받아서 업로드합니다. 이후 \"사진속에 있는 사람들은 모두 몇명인가요?\"라고 입력후 결과를 확인하면 아래와 같습니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/3e1ea017-4e46-4340-87c6-4ebf019dae4f\" /\u003e\n\n### Code Interpreter를 이용한 그래프 그리기\n\nLLM에 \"strawberry에 R은 몇개야?\"로 질문하면 tokenizer의 특징으로 R은 2개라고 답변합니다. 이 경우에 code interpreter를 사용하면 R이 3개라고 정확한 답변을 구할 수 있습니다. 메뉴에서 \"Agent (Tool Use)\"를 선택하고 아래와 같이 질문합니다. \n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/5e5b6e8e-bbca-4401-b971-65a733c51f2f\" /\u003e\n\nAgent의 정확한 동작을 LangSmith 로그를 이용해 확인합니다. Agent는 아래와 같은 code를 생성하여 code_interpreter를 실행시켰고, 결과적으로 정답인 3을 얻을 수 있었습니다.\n\n\u003cimg width=\"700\" alt=\"image\" src=\"https://github.com/user-attachments/assets/f8f79e0a-710d-4db2-b201-03ee393f10d6\" /\u003e\n\n\n\n\n\n메뉴에서 \"Agent\"를 선택하고 \"2000년 이후에 한국의 GDP 변화를 일본과 비교해서 그래프로 그려주세요. 그래프는 영어로 작성합니다.\"라고 입력하고 결과를 확인합니다. 이때 agent는 인터넷을 검색하여 얻어온 GDP정보를 code interpreter를 이용해 그래프로 표시합니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/c8b6f42a-4b4c-4b1a-ae6e-66adce7956cd\" /\u003e\n\n\n메뉴에서 \"Agent\"를 선택하고 \"네이버와 카카오의 주가 동향을 비교하여 그래프를 그려주세요. 그래프는 영어로 작성하고 향후 투자 방법에 대해서도 조언해주세요\"라고 입력후 결과를 확인하면 아래와 같습니다.\n\n\u003cimg width=\"600\" alt=\"image\" src=\"https://github.com/user-attachments/assets/26ea6bc9-3dcb-48e7-81ec-0c535d98c3a8\" /\u003e\n\n\n\n### Amazon S3와 Bedrock Endpoint의 동작 확인\n\n[cdk-llm-streamlit-stack.ts](./cdk-llm-streamlit/lib/cdk-llm-streamlit-stack.ts)의 VPC 설정은 아래와 같습니다. 여기에서 natGateways을 0으로 설정하면 private subnet에 있는 streamlit은 외부로 요청을 보낼수 없습니다. 하지만, 여기에서는 Amazon S3에 대한 gateway endpoint와 Bedrock-runtime을 위한 interface endpoint를 설정하였으므로, NAT 없이 Amazon S3와 Bedrock에 대한 요청 및 처리가 가능합니다. 이와같이 메시지 전송 또는 이미지 업로드를 외부 연결없이 endpoint를 이용하여 처리할 수 있습니다.\n\n```java\nconst vpc = new ec2.Vpc(this, `vpc-for-${projectName}`, {\n  vpcName: `vpc-for-${projectName}`,\n  maxAzs: 2,\n  ipAddresses: ec2.IpAddresses.cidr(\"10.20.0.0/16\"),\n  natGateways: 1,\n  createInternetGateway: true,\n  subnetConfiguration: [\n    {\n      cidrMask: 24,\n      name: `public-subnet-for-${projectName}`,\n      subnetType: ec2.SubnetType.PUBLIC\n    }, \n    {\n      cidrMask: 24,\n      name: `private-subnet-for-${projectName}`,\n      subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS\n    }\n  ]\n}); \n```\n\n### Reference \n\n[deploy-streamlit-app](https://github.com/aws-samples/deploy-streamlit-app/tree/main)\n\n[Serverless Streamlit app on AWS with HTTPS](https://kawsaur.medium.com/serverless-streamlit-app-on-aws-with-https-b5e5ff889590)\n\n[frontend_stack.py](https://github.com/kawsark/streamlit-serverless/blob/main/streamlit_serverless_app/frontend_stack.py)\n\n[Running streamlit as a System Service](https://medium.com/@stevenjlm/running-streamlit-on-amazon-ec2-with-https-f20e38fffbe7)\n\n[Amazon Bedrock Knowledge base로 30분 만에 멀티모달 RAG 챗봇 구축하기 실전 가이드](https://aws.amazon.com/ko/blogs/tech/practical-guide-for-bedrock-kb-multimodal-chatbot/)\n\n[CDK-Ubuntu Steamlit](https://github.com/aws-samples/kr-tech-blog-sample-code/tree/main/cdk_bedrock_rag_chatbot/lib)\n\n[Github - Welcome to Streamlit](https://github.com/streamlit/streamlit)\n\n[Streamlit cheat sheet](https://daniellewisdl-streamlit-cheat-sheet-app-ytm9sg.streamlit.app/)\n\n[CDK-Instance](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Instance.html)\n\n[CDK-LoadBalancer](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_elasticloadbalancing.LoadBalancer.html)\n\n[CDK-VPC](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html)\n\n[CDK-VpcEndpoint](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.VpcEndpoint.html)\n\n[EC2에 간단한 Streamlit 웹 서비스 올리기](https://everenew.tistory.com/317)\n\n[Deploying Streamlit Application on AWS EC2 Instance with NGINX Server](https://medium.com/@borghareshubham510/deploying-streamlit-application-on-aws-ec2-instances-with-nginx-server-d20c83bf150a)\n\n[How to Deploy a Streamlit Application on Amazon Linux EC2](https://towardsaws.com/how-to-deploy-a-streamlit-application-on-amazon-linux-ec2-9a71593b434)\n\n[Running Streamlit on Amazon EC2 with HTTPS](https://medium.com/@stevenjlm/running-streamlit-on-amazon-ec2-with-https-f20e38fffbe7)\n\n[Setting up a VPC Endpoint for yum with AWS CDK](https://dev.to/jhashimoto/setting-up-a-vpc-endpoint-for-yum-with-aws-cdk-3a8o)\n\n[CloudFront - ALB 구성 시 보안 강화 방안](https://everenew.tistory.com/317)\n\n[자습서: Amazon ECS 서비스에 대한 프라이빗 통합을 통해 HTTP API 생성](https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/http-api-private-integration.html)\n\n[API Gateway to ECS Fargate cluster](https://serverlessland.com/patterns/apigw-vpclink-pvt-alb?ref=search)\n\n### History\n\n[How to add thread-level persistence to your graph](https://langchain-ai.github.io/langgraph/how-tos/persistence/)\n\n[Part 3: Adding Memory to the Chatbot](https://langchain-ai.github.io/langgraph/tutorials/introduction/#requirements)\n\n[LangGrpah-Memory](https://langchain-ai.github.io/langgraph/concepts/memory/)\n\n[LangGraph with Streamlit Intersection](https://shiv248.medium.com/langgraph-with-streamlit-intersection-0687995d1287)\n\n[Streamlit-Authenticator, Part 1: Adding an authentication component to your app](https://blog.streamlit.io/streamlit-authenticator-part-1-adding-an-authentication-component-to-your-app/)\n\n[Claude의 System Prompt](https://docs.anthropic.com/en/release-notes/system-prompts#feb-24th-2025)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyopark2014%2Fllm-streamlit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyopark2014%2Fllm-streamlit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyopark2014%2Fllm-streamlit/lists"}