-
게시글
281 -
첫 방문
-
최근 방문
-
Days Won
51
CLOVA Studio 운영자's Achievements
-
안녕하세요, @Axel님, HyperCLOVA X에 많은 관심 가져주셔서 감사드립니다. HyperCLOVA X SEED는 오픈소스 모델로, CLOVA Studio에서는 제공하고 있지 않습니다. 번거로우시더라도, 허깅페이스의 커뮤니티를 통해서 문의를 부탁드립니다. https://huggingface.co/naver-hyperclovax/HyperCLOVAX-SEED-Vision-Instruct-3B/discussions 감사합니다.
-
안녕하세요, @jason님, 말씀 주신 내용은 모델이 자체적인 safety 기준에 따라 응답한 것으로 보입니다. 시스템 프롬프트를 활용하여 정보 추출 작업이 원활히 이루어지도록 유도할 수 있으나, 모든 케이스에서 일관되게 잘 동작하는지에 대해서는 반복적인 테스트가 필요합니다. 감사합니다. 주어진 텍스트에서 이름, 전화번호, 주소를 인식하여 모두 추출하세요. # Steps 1. 주어진 텍스트에서 이름, 전화번호, 주소를 식별합니다. 2. 각 정보를 개별적으로 추출합니다. 3. 추출된 정보를 목록 형태로 정리합니다. # Output Format - JSON으로 추출된 정보를 나타내야 합니다. - 각 항목에 대해 JSON 객체의 속성 이름으로 "name", "phone_number", "address"를 사용하십시오. - 각 속성의 값은 추출된 정보의 문자열이어야 합니다. 예시: ```json { "name": "[이름]", "phone_number": "[전화번호]", "address": "[주소]" } ``` # Notes - 예시에서는 실제 이름, 전화번호, 주소를 제공하지 않으며, 마스킹으로 하기 전에 정확한 추출이 이루어지도록 합니다. - 형식이 다양할 수 있으니 유연하게 파싱하도록 주의합니다.
-
안녕하세요, 네이버 클라우드 플랫폼입니다. 네이버 클라우드 플랫폼을 이용해주셔서 감사합니다. CLOVA Studio는 안정적인 서비스와 더 나은 모델 제공을 위해 지속적으로 개선하고 있습니다. 그 일환으로, 성능이 개선된 HyperCLOVA X 모델들이 새롭게 출시되었습니다. 이에 맞춰 LK-B, LK-D2 모델은 제공이 종료될 예정이며, 먼저 해당 모델을 사용한 신규 작업 생성이 제한됩니다. 기존 모델 이용 고객께서는 신규 모델로 전환을 검토해주시길 권장드립니다. 자세한 일정과 대체 모델 정보를 아래에서 확인해 주시기 바랍니다. ※ 적용 일시 : 2025년 7월 17일(목)부터 ※ 대상 서비스 : CLOVA Studio ※ 영향 범위 플레이그라운드, 튜닝, 익스플로러에서 LK-B, LK-D2 모델 신규 이용 불가 플레이그라운드 : 일반 모드 미제공, LK 모델 선택 불가 튜닝 : 웹 튜닝 지원 종료 익스플로러 : LK 모델 선택 불가 LK 모델로 저장된 작업은 제공 종료일 이후에도 챗 모드로 불러오기 및 프롬프트 확인 가능 단, 튜닝 작업은 불러오기 불가하며 Completions API로 호출만 가능 Completions API는 제공 종료일까지만 지원하며 종료 시점 이후부터는 해당 API 호출이 불가능합니다. <제공 종료> 모델 신규 이용 불가 제공 종료 대체 모델 LK-B 25년 7월 17일부터 25년 11월 20일 HCX-DASH-002, HCX-005 LK-D2 25년 7월 17일부터 25년 11월 20일 HCX-DASH-002, HCX-005 관련된 문의는 "고객지원 문의하기" 로 연락주십시오. 더욱 편리한 서비스 제공을 위하여 항상 노력하겠습니다. 감사합니다. 네이버 클라우드 플랫폼 드림
-
들어가며 AI 에이전트 기술은 단순한 대화형 모델을 넘어, 외부 도구(Tool)를 활용하여 필요한 정보를 직접 찾아 응답하는 방식으로 빠르게 진화하고 있습니다. 특히, 모델 단독으로는 한계가 있는 실시간 정보 검색과 같은 작업을 효과적으로 지원하기 위해, 검색 API를 연동한 '웹 검색 AI 에이전트'가 큰 주목을 받고 있습니다. 이 Cookbook에서는 LangGraph를 활용하여 검색 API를 도구로 사용하는 AI 에이전트 시스템을 단계별로 구축하는 과정을 상세히 안내합니다. 본 가이드를 따라 차근차근 실습하며 여러분만의 강력하고 맞춤화된 웹 검색 에이전트를 개발해 보세요. Agent System 작동 원리 웹 검색 AI 에이전트의 작동 방식을 먼저 살펴보겠습니다. 에이전트시스템은 사용자의 질문을 입력받아 그 의도를 파악하고, 필요시 가장 적절한 도구(Tool)를 선택하여 실행하는 방식으로 작동합니다. 여러 도구 중 현재 상황에 가장 적합한 것을 선택하여 사용하고, 얻어진 결과를 바탕으로 AI 모델이 자연스러운 언어로 정리하여 사용자에게 최종 응답을 제공합니다. 예를 들어, 사용자가 "오늘 서울 날씨 알려줘"라고 질문하면, 에이전트는 검색 API를 호출하여 최신 날씨 정보를 가져온 뒤, 이를 바탕으로 자연스러운 답변을 생성하는 원리입니다. LangGraph AI Agent 구현 시작하기 이제 LangGraph를 이용하여 Tool을 연동한 AI 에이전트를 직접 구현해 보겠습니다. 검색 API를 도구로 활용하면, LLM이 자체 지식만으로는 답변하기 어려운 질문에 대해서도 더욱 정확하고 신뢰도 높은 답변을 제공할 수 있습니다. ① 기본 환경 설정 필요한 패키지 라이브러리 설치 LangChain은 AI 에이전트 구축에 필요한 다양한 기능을 손쉽게 활용할 수 있게 해주는 파이썬 오픈소스 라이브러리입니다. 먼저 pip 명령어를 사용해 필요한 패키지들을 설치해보겠습니다. %pip install -U langchain langchain-openai langchain-naver langgraph langchain-community langchain-naver-community CLOVA Studio API KEY 발급 네이버 클라우드 플랫폼에서 CLOVA Studio 이용 신청을 해야 합니다. 이용 신청이 완료되면, CLOVA Studio 사이트에 로그인해 API 키를 발급받을 수 있습니다. CLOVA Studio 환경 변수 설정 HCX-005 모델을 사용하기 위해, CLOVA Studio API 키를 환경 변수로 등록합니다. 아래 셀을 실행하면 API 키 입력란이 표시됩니다. 사이트에서 발급받은 API 키를 입력하여 환경 변수로 설정해 주세요. import os import getpass os.environ["CLOVASTUDIO_API_KEY"] = getpass.getpass( "CLOVA Studio API Key 입력: " ) ② LLM 모델 구현 HCX 모델 정의 Langchain-naver ChatClovaX를 통해 HCX-005 모델을 초기화합니다. from langchain_naver import ChatClovaX llm = ChatClovaX( model="HCX-005", max_tokens=1024, # Tool 사용시 max_tokens은 1024이상 필수 ) HCX 모델 테스트 모델 초기화 이후, "안녕, 너는 누구야?"와 같은 입력으로 간단한 테스트를 진행해 정상 작동 여부를 확인할 수 있습니다. llm.invoke("안녕,너는 누구야?") AIMessage(content='안녕하세요! 저는 CLOVA X입니다.\n\n사용자님의 생산성 향상을 도울 수 있도록 개발된 인공지능 언어모델로 다음과 같은 역할을 수행할 수 있습니다.\n\n1. 질의 응답: 사용자님이 궁금하신 내용을 질문해 주시면, 이에 대해 학습한 데이터를 기반으로 최대한 정확하고 유용한 답변을 제공하도록 노력합니다.\n2. 글쓰기 지원: 이메일 작성이나 문서 초안을 잡을 때 필요한 아이디어를 제시하거나 문장을 다듬어 드릴 수 있습니다.\n3. 번역: 다양한 언어로 텍스트를 번역하는 데 도움을 줄 수 있습니다.\n4. 요약 및 분석: 원문을 간략하게 요약하거나 특정 주제와 관련된 콘텐츠를 분석하여 인사이트를 제공합니다.\n\n궁금하신 내용이나 도움이 필요하시면 언제든지 말씀해 주세요. 최선을 다해 도와드리겠습니다. ', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 164, 'prompt_tokens': 13, 'total_tokens': 177, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'HCX-005', 'system_fingerprint': None, 'id': '1b6d8c4819b04e70bde29e40d7d2068a', 'finish_reason': 'stop', 'logprobs': None}, id='run-b74541be-2b13-4c4b-b31f-40385f929ec2-0', usage_metadata={'input_tokens': 13, 'output_tokens': 164, 'total_tokens': 177, 'input_token_details': {}, 'output_token_details': {}}) ③ Tool 구현 검색 도구(Tool) API 이용신청 검색 API를 사용하려면 먼저 Tavily에서 API 키를 발급받아야 합니다. Tavily 웹사이트에 로그인하면 아래 이미지와 같이 API 키가 자동으로 발급됩니다. 발급된 키는 오른쪽 복사 버튼(빨간색 박스)을 클릭해 안전하게 저장해두세요. 다양한 검색 API 도구 본 Cookbook에서는 Tavily API를 도구(Tool)로 사용하지만, 이 외에도 DuckDuckGo, Brave, Jina 등 다양한 무료 검색 API가 존재합니다. 각 검색 API의 특징과 사용 조건은 아래 표를 참고해 주세요. Tool/Toolkit Free/Paid Return Data Bing Search Paid URL, Snippet, Title Brave Search Free URL, Snippet, Title DuckDuckgoSearch Free URL, Snippet, Title Exa Search 1000 free searches/month URL, Author, Title, Published Date Google Search Paid URL, Snippet, Title Google Serper Free URL, Snippet, Title, Search Rank, Site Links Jina Search 1M Response Tokens Free URL, Snippet, Title, Page Content Mojeek Search Paid URL, Snippet, Title SearchApi 100 Free Searches on Sign Up URL, Snippet, Title, Search Rank, Site Links, Authors SearxNG Search Free URL, Snippet, Title, Category SerpAPI 100 Free Searches/Month Answer Tavily Search 1000 free searches/month URL, Content, Title, Images, Answer You.com Search Free for 60 days URL, Title, Page Content 검색 도구(Tool) 환경 변수 설정 검색 도구를 사용하기 위해서는 API KEY가 필요합니다. API KEY를 환경 변수에 등록하여, 안전하고 편리하게 이용할 수 있습니다. os.environ["TAVILY_API_KEY"] = getpass.getpass( "Tavily API Key 입력: " ) 검색 도구 정의 LangChain에서 제공하는 검색 도구를 불러와 tool이라는 이름으로 함수 객체를 정의합니다. 이때 max_results 파라미터를 사용해 최대 검색 결과 수를 지정할 수 있습니다. from langchain_community.tools.tavily_search import TavilySearchResults tool = TavilySearchResults(max_results=5) 검색 도구 테스트 검색 도구가 정상적으로 동작하는지 확인하려면, tool.invoke() 함수를 실행합니다. tool.invoke("정자역") Agent 도구 정의 Agent가 활용할 수 있는 도구는 자유롭게 정의할 수 있습니다. Tavily 검색 API 외에도 다양한 외부 API나 커스텀 함수를 함께 등록할 수 있으며, 모델은 상황에 따라 가장 적절한 도구를 자동으로 선택해 호출합니다. 이를 통해 보다 정밀하고 신뢰도 높은 응답을 생성할 수 있습니다. 아래 예시는 Tavily 외에 현재 시간을 반환하는 함수를 추가 도구로 구성한 사례입니다. tools = [tool] # tools = [tool1, tool2, tool3, etc... ] 여러 도구(Tool) 설정 방법 from datetime import datetime from langchain_core.tools import Tool def get_current_time(dummy: str = "now") -> dict: print("[tool2 호출] 현재 시간 조회\n") """현재 시간을 ISO 8601 형식으로 반환합니다.""" return {"current_time": datetime.now().isoformat()} tool2 = Tool.from_function( func=get_current_time, name="get_current_time", description="사용자가 현재 시간을 ISO 8601 포맷으로 반환합니다. 입력은 무시됩니다." ) tools = [tool1, tool2] ④ Agent Workflow 구축 LangGraph Agent 구현 langgraph.prebuilt 라이브러리의 create_react_agent 함수를 사용하면, 간단한 코드 한 줄로 에이전트를 정의할 수 있습니다. 이 함수는 LangGraph에서 미리 정의한 REACT 기반 에이전트를 손쉽게 활용할 수 있도록 제공되는 강력한 모듈입니다. LLM 파라미터에는 앞서 정의한 언어 모델을, tools 파라미터에는 구성한 도구 목록을 각각 전달하여 설정합니다. ※ 나만의 커스텀 Agentic Workflow를 직접 구현하고 싶다면, 본 문서의 마지막 챕터를 참고해 주세요. from langgraph.prebuilt import create_react_agent agent_executor = create_react_agent( llm, tools, ) Agent 실행 함수 정의 사용자의 입력을 받아 Agent Executor에 전달하고, 처리된 최종 응답 결과를 반환합니다. def agent_run(query): result = agent_executor.invoke({"messages": [("human", query)]}) return result["messages"][-1].content 에이전트 시스템 실행 while True 루프를 사용하여 앞서 정의한 agent_run 함수를 반복 호출합니다. 이를 통해 에이전트 시스템이 사용자의 입력을 지속적으로 받아 처리할 수 있도록 구성합니다. 대화를 종료하려면 quit, exit, 또는 q를 입력하면 루프가 종료됩니다. while True: query = input("User: ") print("User: "+query+"\n") if query.lower() in ["quit", "exit", "q"]: print("Goodbye!") break print("Assistant: "+agent_run(query)) 랭그래프 Agent Workflow 시각화 에이전트의 워크플로우 구조는 Mermaid 형식의 다이어그램을 통해 시각적으로 확인할 수 있습니다. from IPython.display import Image, display display(Image(agent_executor.get_graph().draw_mermaid_png())) GUI로 쉽게 나만의 커스텀 Agentic Workflow 구현 LangGraph Builder는 초보자도 쉽게 워크플로우를 GUI로 구성할 수 있도록 지원하는 도구입니다. 시각적으로 구현한 워크플로우는 버튼 클릭 한 번으로 Python 또는 TypeScript 코드로 변환할 수 있습니다. 마무리 이번 Cookbook에서는 LangGraph와 LangChain-naver를 활용하여 웹 검색 AI 에이전트를 구축하는 전 과정을 단계별로 살펴보았습니다. LangGraph와 Clova Studio, 다양한 검색 Tool을 조합하면, 실시간 정보를 이해하고 응답할 수 있는 강력한 AI Agent를 누구나 구현할 수 있습니다. 이제 여러분의 아이디어와 상상력이 더해질 차례입니다. 🚀
-
들어가며 본 가이드는 클로바 스튜디오와 랭체인(Langchain)을 활용하여 Multimodal RAG(멀티모달 검색 증강 생성) 시스템을 구축하는 방법을 안내합니다. 최근 비전 모델의 상용화가 가속화되면서 기업들은 내부의 다양한 이미지 기반 데이터를 효율적으로 검색하고 활용하려는 니즈가 증가하고 있습니다. 특히 기존 텍스트 중심 RAG 시스템을 이미지 데이터까지 포함하도록 확장하는 사례가 늘어나는 추세입니다. 이 글에서는 PDF 형식의 데이터를 기반으로 질의응답 기능을 제공하는 Multimodal RAG 시스템을 랭체인을 통해 구현해보겠습니다. 구현하고자 하는 Multimodal RAG 시스템의 구조도는 아래와 같습니다. 멀티모달 임베딩 없이도 구현 가능한 Multimodal RAG 구조를 소개합니다. 이 방식은 비전 모델을 활용해 이미지를 텍스트로 변환한 후, 해당 텍스트를 임베딩하여 검색에 활용하는 접근법입니다. LangChain 프레임워크를 통해 CLOVA Studio의 모델과 Chroma, FAISS와 같은 외부 벡터 데이터베이스를 효과적으로 연동할 수 있습니다. 전체 과정은 셀 단위로 실습할 수 있도록 구성되어 있습니다(파일명: multimodal_RAG.ipynb). 이 가이드의 핵심은 이미지 기반 문서를 다루는 기업들이 쉽게 도입할 수 있는 범용적인 멀티모달 RAG 구현 방식을 소개하는 데 있습니다. 1. 사전준비 ① Langchain 패키지 설치 멀티모달 RAG 시스템 구현을 위해서는 LangChain 프레임워크와 CLOVA Studio API 연동이 필요합니다. 최근 출시된 langchain-naver 패키지를 통해 CLOVA Studio의 최신 비전 모델 HCX-005를 LangChain과 원활하게 연동할 수 있습니다. 아래 명령어로 LangChain 관련 패키지를 설치하세요. %pip install -qU openai langchain langchain-naver ② 코드 공통 모듈 imports 필요한 기본 모듈들을 미리 import합니다. import os import getpass import uuid import re from urllib.parse import urlparse import http import json import time ③ API 키 발급 받기 CLOVA Studio의 API 키 발급이 필요합니다. "프로필 > API 키 > 테스트 > 테스트 앱 발급" 경로를 통해 키를 발급받을 수 있습니다. 발급된 키는 한 번만 표시되어 재확인이 불가능하므로, 반드시 복사하여 별도로 안전하게 보관해야 합니다 ④ 참조할 문서 (PDF 데이터) 준비 본 예제에서는 'AI 모델 튜닝하기: 학습 데이터 활용부터 성능 향상까지'과 '당신의 AI에게 행동을 맡겨라: 스킬과 Function Calling' 페이지를 PDF 형식으로 변환하여 데이터로 활용합니다. 이 문서들은 단순 텍스트뿐만 아니라 표, 그래프, 다이어그램, 코드 등 다양한 형태의 이미지가 포함되어 있어, 이미지 기반 정보가 실제 검색에 어떻게 활용되는지 테스트하기에 적합합니다. 필요에 따라 PDF 문서를 교체하거나 내용을 편집하여 사용할 수 있습니다. 준비한 PDF 문서는 data/ 폴더에 저장하여 준비합니다. 📁 cookbook/ ├── multimodal_RAG.ipynb/ ├── data/ │ ├── 모델튜닝.pdf │ ├── 스킬.pdf 2. 문서 전처리하기 멀티모달 RAG 시스템에서는 텍스트뿐만 아니라 이미지 등 다양한 형태의 데이터를 분할하고, 이를 벡터로 변환하여 검색에 활용해야 합니다. PDF 문서는 일반 텍스트 외에도 그래프, 테이블과 같은 시각적 요소가 포함되어 있어, 텍스트 기반 RAG보다 더 정교하고 복합적인 전처리 과정이 요구됩니다. ① PDF 문서에서 텍스트와 이미지 추출하기 (Load) PDF 파일에서 텍스트와 이미지를 각각 추출하는 과정이 필요합니다. 현재 멀티모달 문서의 정보 추출을 지원하는 대표적인 라이브러리로는 PyPDF, PyMuPDF, LlamaParse, Unstructured.io, TorchMultimodal 등이 있습니다. 각 라이브러리는 텍스트 추출 정확도, 이미지 처리 방식, 구조 보존 여부 등 구현 방식에서 차이를 보입니다. 따라서 특정 라이브러리가 절대적으로 우수하다고 보긴 어렵습니다. 본 예제에서는 PyMuPDF를 활용하여 페이지별로 이미지를 저장하고 텍스트를 구조화하는 방식을 채택했습니다. %pip install pymupdf 아래 코드는 PDF 파일에서 추출한 이미지와 텍스트를 상대 경로 기준의 지정된 폴더(output_dir)에 저장하도록 구성되어 있습니다. 이 과정을 통해 각 페이지에 포함된 이미지와 텍스트 추출 결과를 직접 확인할 수 있습니다. 실행 후 전체 디렉토리 구조는 다음과 같이 구성됩니다. 📁 cookbook/ ├── multimodal_RAG.ipynb/ ├── data/ │ ├── 모델튜닝.pdf │ ├── 스킬.pdf │ └── extracted_images_문서/ │ ├── merged_text.txt │ ├── page_1_img_1.png │ ├── page_2_img_1.png │ ├── page_9_img_1.png │ ├── page_10_img_1.png │ ├── page_11_img_1.png │ ├── page_12_img_1.png │ ├── page_15_img_1.png │ ├── page_15_img_2.png │ └── page_16_img_1.png 텍스트는 페이지 단위로 정리되며, 이후 LangChain의 Document 객체로 변환되어 임베딩 처리에 활용됩니다. 이미지는 "page_{page_number}img{img_index}.{image_ext}" 형식으로 저장됩니다. 이러한 명명 규칙은 이미지가 어느 페이지에서 추출되었는지 쉽게 추적할 수 있게 하며, 이후 메타데이터로 활용하기에도 매우 효과적입니다. 이렇게 구성된 문서는 향후 검색 기반 질의응답(RAG) 시스템의 컨텍스트로 활용됩니다. import fitz # PyMuPDF from langchain_core.documents import Document def extract_documents_from_pdf(pdf_path: str, output_dir: str = "data/extracted_images_문서"): os.makedirs(output_dir, exist_ok=True) merged_text_path = os.path.join(output_dir, "merged_text.txt") merged_text = "" doc = fitz.open(pdf_path) documents = [] for i, page in enumerate(doc): page_number = i + 1 page_text = page.get_text("text").strip() images_info = [] # 이미지 추출 for img_index, img in enumerate(page.get_images(full=True)): xref = img[0] base_image = doc.extract_image(xref) image_bytes = base_image["image"] image_ext = base_image["ext"] image_filename = f"page_{page_number}_img_{img_index+1}.{image_ext}" image_path = os.path.join(output_dir, image_filename) with open(image_path, "wb") as img_file: img_file.write(image_bytes) images_info.append(image_path) # LangChain Document로 변환 documents.append(Document( page_content=page_text, metadata={ "source": os.path.basename(pdf_path), "page": page_number, "images": ", ".join(images_info) } )) # 병합 텍스트 저장용 merged_text += f"\n\n--- Page {page_number} ---\n\n{page_text}" # 전체 텍스트 저장 with open(merged_text_path, "w", encoding="utf-8") as f: f.write(merged_text) return documents, merged_text_path pdf_path = "data/모델튜닝.pdf" # 다른 파일로 테스트할 경우 알맞은 경로 입력 docs, merged_path = extract_documents_from_pdf(pdf_path) print(f"추출된 문서 페이지 수: {len(docs)}") print(f"병합된 텍스트 경로: {merged_path}") print(docs[0]) # 하나 확인 결과 ② 이미지 → 텍스트 요약하기 (Convert) PDF에서 추출한 이미지는 단순히 저장하는 것만으로는 검색이나 응답 생성에 즉시 활용하기 어렵습니다. 이미지 내용을 검색 가능한 정보로 변환하기 위해, CLOVA Studio의 비전 모델을 활용하여 시각 정보를 텍스트로 요약합니다. 이렇게 생성된 설명은 이후 RAG 시스템에서 문맥(Context)으로 활용될 수 있도록 구성됩니다. 2.1) HyperCLOVA X 비전 모델을 위한 이미지 전처리 CLOVA 비전 모델 사용 시 다음과 같은 이미지 제한 사항이 있습니다. PDF에서 추출한 이미지는 해상도가 매우 크거나 가로·세로 비율이 비정상적으로 긴 경우가 많습니다. 이러한 이미지를 CLOVA Studio에 그대로 입력하면 'Invalid image ratio' 에러가 발생할 수 있습니다. 이러한 오류를 사전에 방지하기 위해 이미지를 검사하고 리사이즈하는 전처리 과정을 수행하는 것이 필요합니다. %pip install -qU Pillow 아래 함수는 하나의 로컬 이미지 경로를 입력받아 조건을 만족하면 output_dir에 그대로 복사하고, 조건에 맞지 않으면 리사이즈 후 output_dir에 저장하는 역할을 수행합니다. from PIL import Image from pathlib import Path import shutil def check_and_resize_image_to_outdir( path: Path, outdir: Path, allowed_formats=("PNG", "JPEG", "WEBP", "BMP"), max_bytes=20 * 1024 * 1024, max_length=2240, max_ratio=4.5, save_format="PNG" ): try: # 용량 초과 확인 if path.stat().st_size > max_bytes: print(f"[✘] 용량 초과: {path.name}") return with Image.open(path) as image: format = image.format.upper() if format not in allowed_formats: print(f"[✘] 포맷 불가: {path.name} ({format})") return w, h = image.size ratio = max(w, h) / min(w, h) needs_resize = max(w, h) > max_length or ratio > max_ratio if not needs_resize: # 조건 만족 → 그대로 복사 dest = outdir / path.name shutil.copy(path, dest) print(f"[✓] 조건 만족 → 복사됨: {path.name}") return # 리사이즈 크기 계산 if ratio > max_ratio: if w > h: new_w = min(w, max_length) new_h = int(new_w / max_ratio) else: new_h = min(h, max_length) new_w = int(new_h / max_ratio) else: if w >= h: new_w = min(w, max_length) new_h = int(h * (new_w / w)) else: new_h = min(h, max_length) new_w = int(w * (new_h / h)) resized = image.resize((new_w, new_h), Image.LANCZOS).convert("RGB") dest = outdir / path.name resized.save(dest, format=save_format, optimize=True) print(f"[✔] 리사이즈됨 → 저장됨: {dest.name} ({new_w}x{new_h})") except Exception as e: print(f"[✘] 처리 실패: {path.name} → {e}") 아래 메인 실행 코드를 통해 CLOVA Studio의 비전 모델 기준에 적합한 안전한 이미지 셋을 구성할 수 있습니다. 📁 cookbook/ ├── multimodal_RAG.ipynb/ ├── data/ │ ├── 모델튜닝.pdf │ ├── 스킬.pdf │ ├── extracted_images_문서/ ← PDF에서 추출된 원본 이미지 │ └── filtered_images/ ← 조건에 맞는 이미지가 저장되는 곳 (output_dir) from pathlib import Path input_dir = Path("data/extracted_images_문서") output_dir = Path("data/filtered_images") output_dir.mkdir(parents=True, exist_ok=True) valid_exts = [".png", ".jpg", ".jpeg", ".webp", ".bmp"] image_files = [p for p in input_dir.glob("*") if p.suffix.lower() in valid_exts] print(f"총 {len(image_files)}개의 이미지 처리 시작") for img_path in image_files: check_and_resize_image_to_outdir(img_path, outdir=output_dir) 결과 2.2) Ncloud Storage 사용해서 이미지 저장하기 CLOVA Studio의 비전 모델은 로컬 경로의 이미지 파일이 아닌, 웹 URL 형태의 이미지를 입력값으로 지원합니다. 따라서 모델을 활용하기 위해서는 먼저 추출한 이미지를 객체 스토리지(Ncloud Storage, S3, 구글 드라이브 등)에 업로드한 후, 해당 URL을 수집하여 정리하는 작업이 필요합니다. 이번 cookbook에서는 Ncloud Storage 를 사용하겠습니다. (참고 : Ncloud Storage 가이드) 포털 마이페이지 > 계정 관리 > 인증키 관리에서 API 인증키를 생성합니다. 생성한 Access Key와 Secret Key는 환경 변수로 설정해줍니다. # 네이버 클라우드에서 발급받은 키를 입력하세요 os.environ["AWS_ACCESS_KEY_ID"] = getpass.getpass("NCP Access Key: ") os.environ["AWS_SECRET_ACCESS_KEY"] = getpass.getpass("NCP Secret Key: ") # 기본 리전 설정 os.environ["AWS_DEFAULT_REGION"] = "kr" Ncloud Object Storage는 Amazon S3 API와 호환되며, Python에서는 이를 제어하기 위해 'boto3' 라이브러리를 사용합니다. %pip install boto3 다음은 새로운 버킷을 생성하고 전처리한 이미지를 모두 업로드하는 코드입니다. 버킷 이름은 최소 3자에서 최대 63자로 구성할 수 있으며, 소문자, 숫자 및 하이픈(-)만 포함해야 합니다. 예시에서는 'multi-rag'를 버킷 이름으로 사용했습니다. from glob import glob import boto3 from botocore.client import Config from botocore.exceptions import ClientError import mimetypes # 설정 BUCKET_NAME = "multi-rag" LOCAL_FOLDER = "data/filtered_images" ENDPOINT_URL = "https://kr.ncloudstorage.com" REGION = os.environ["AWS_DEFAULT_REGION"] ACCESS_KEY = os.environ["AWS_ACCESS_KEY_ID"] SECRET_KEY = os.environ["AWS_SECRET_ACCESS_KEY"] # boto3 클라이언트 초기화 s3 = boto3.client( "s3", aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY, endpoint_url=ENDPOINT_URL, region_name=REGION, config=Config(signature_version="s3v4") ) # 1. 버킷 생성 try: s3.head_bucket(Bucket=BUCKET_NAME) print(f"이미 존재하는 버킷입니다: {BUCKET_NAME}") except ClientError as e: if e.response['Error']['Code'] == '404': print(f"버킷이 존재하지 않아 생성합니다: {BUCKET_NAME}") s3.create_bucket(Bucket=BUCKET_NAME) else: raise # 2. 이미지 수집 IMAGE_EXTENSIONS = ("*.jpeg", "*.jpg", "*.png", "*.bmp", "*.webp") image_files = [] for ext in IMAGE_EXTENSIONS: image_files.extend(glob(os.path.join(LOCAL_FOLDER, ext))) print(f"총 {len(image_files)}개 이미지 파일을 찾았습니다.") # 3. 이미지 업로드 및 URL 저장 url_list = [] # 결과 저장할 리스트 for file_path in image_files: file_name = os.path.basename(file_path) try: # 업로드 s3.upload_file(file_path, BUCKET_NAME, file_name) # MIME 타입 추정 mime_type, _ = mimetypes.guess_type(file_name) if not mime_type: mime_type = "application/octet-stream" # Signed URL 생성 signed_url = s3.generate_presigned_url( "get_object", Params={ "Bucket": BUCKET_NAME, "Key": file_name, "ResponseContentDisposition": "inline", "ResponseContentType": mime_type }, ExpiresIn=3600 #1시간만 ) print(f"URL: {signed_url}") url_list.append({signed_url}) except ClientError as e: print(f"업로드 실패: {e}") print("모든 이미지 업로드 및 링크 생성 완료!") 결과 2.3) 비전 모델 사용해서 이미지 요약 하기 PDF 문서를 분석하다 보면 인포그래픽, 그래프, 테이블, 코드 캡처와 같은 다양한 형태의 이미지들이 등장합니다. 이미지가 담고 있는 정보의 형식과 내용이 이미지별로 상이하기 때문에, 요약 단계에서도 이미지 유형에 맞는 접근법이 필요합니다. 프롬프트뿐만 아니라 함께 사용하는 파라미터 설정(config) 또한 요약 품질에 큰 영향을 미칩니다. 실험을 통해 비교적 안정적이고 일관된 결과를 보여준 설정값을 함께 제시했지만, 이미지 특성이나 문서 도메인에 따라 적절한 조합은 달라질 수 있습니다. 따라서 사용하는 프롬프트와 이미지 유형에 맞게 config 값을 직접 조정해보는 것을 권장합니다. 아래는 문서 내 이미지를 다룰 때 일반적으로 활용되는 범용 프롬프트와 파라미터 값의 예시입니다. from langchain_core.messages import SystemMessage, HumanMessage from langchain_naver import ChatClovaX chat_llm = ChatClovaX( model="HCX-005" ) # 이미지 URL image_url = url_list[-1] # System, User prompt 구성 system_message = SystemMessage( content=( "당신은 문서 내 다양한 형태의 이미지를 분석하여, 검색 기반 질문응답 시스템(RAG)에 활용 가능한 텍스트 설명을 생성하는 AI입니다." "이미지는 인포그래픽, 표, 그래프, 코드 캡처, 다이어그램, 화면 구성 등 다양한 유형일 수 있으며, 다음 기준에 따라 요약을 작성하세요." "- 이미지의 주제와 목적을 명확하게 파악하고 자연어로 요약합니다." "- 이미지가 전달하는 구조나 흐름이 있다면 순차적으로 설명합니다. (예: 단계, 관계, 비교 등)" "- 표, 그래프, 수치 정보는 전체 흐름과 특징적인 차이만 요약하고, 수치 나열은 피합니다." "- 코드 캡처인 경우 기능과 역할 중심으로 요약하며, 함수/변수/모듈명 등 핵심 정보만 포함합니다." "- 시각적 요소(색상, 도형, 배치 등)는 정보 전달에 필요할 경우에만 간단히 설명합니다." "- OCR로 추출된 텍스트가 있다면 핵심 내용 위주로 정리하여 포함합니다." "- 설명은 검색 가능한 핵심 키워드를 포함하고, 감상이나 해석 없이 사실 중심 문장으로 구성해야 합니다." "- 최종 출력은 3~5문장 이내의 단일 문단으로 구성되며, RAG 시스템의 컨텍스트로 직접 활용 가능해야 합니다." ) ) human_message = HumanMessage(content=[ {"type": "text", "text": "이 이미지는 문서 내 시각 자료입니다. 핵심 정보를 요약해 주세요."}, {"type": "image_url", "image_url": {"url": image_url}} ]) # 메시지 구성 messages = [ system_message, human_message ] # 파라미터 설정 config={ "generation_config": { "temperature": 0.25, "repetition_penalty": 1.1 } } # 모델 호출 response = chat_llm.invoke(messages,config) print("[CLOVA 응답]\n", response.content) 결과 [CLOVA 응답] 이 이미지는 'Tuning'이라는 제목 아래 파란색 계열의 그래픽으로 구성된 시각 자료를 보여줍니다. 배경은 짙은 남색이며 상단에는 한글로 된 설명문이 있습니다. 이 설명문은 프롬프트만으로 성능 향상에 한계가 있어 자체 조달한 커스텀 데이터를 활용한 모델 튜닝(Tuning) 과정을 거쳐 성능을 더욱 향상시킬 수 있다는 내용을 담고 있습니다. 하단의 파동 모양 그래프는 시간에 따른 성능 향상을 나타내며, 각 지점마다 '1차', '2차', '3차'라는 텍스트가 표시되어 여러 번의 개선 단계를 의미합니다. 또한 하단에는 원형의 아이콘이 세 개 있으며 각각 '엔지니어링'이라는 단어와 화살표가 연결되어 있어, 이러한 엔지니어링 작업이 반복되면서 성능이 점차 향상됨을 시각적으로 표현했습니다. 오른쪽 끝부분에는 '튜닝'이라고 적힌 큰 원형 버튼이 강조되어 있으며 이는 최종적인 성능 최적화를 상징합니다. 전체적으로 이 이미지는 특정 과정에서의 지속적인 개선 및 최적화의 중요성을 나타내는 것으로 보입니다. 아래는 각 이미지 유형에 특화된 프롬프트를 적용해 생성한 예시 결과로, 이미지의 유형에 따라 요약 방식이 어떻게 달라지는지 비교해볼 수 있도록 구성했습니다. 아래 코드는 모든 이미지에 대해 요약을 생성하는 코드입니다. # 결과를 저장할 딕셔너리 image_summary_results = [] # URL 반복 → 프롬프트 생성 → 모델 호출 → 딕셔너리 저장 for url in url_list: file_name = os.path.basename(url) clean_filename = file_name.split("?")[0] try: # URL만 바꿔서 human_message 재생성 human_message.content[1]["image_url"]["url"] = url messages = [system_message, human_message] response = chat_llm.invoke(messages,config) # 결과 딕셔너리에 저장 image_summary_results.append({clean_filename: response.content}) print(f"[✔] 저장 완료: {url}") except Exception as e: print(f"[✘] 실패: {url} → {e}") 결과 2.4) 이미지 요약 텍스트를 Document 형식으로 변환하기 아래 코드는 이미지로부터 생성된 설명 텍스트(content)와 이미지의 위치 정보 등 메타데이터를 함께 담아 LangChain의 Document 형식으로 변환하는 과정입니다. 이전 이미지 추출 단계에서 파일명에 페이지 번호가 포함되도록 구성했습니다. 이를 활용해 이미지의 위치 정보를 메타데이터로 구성할 수 있습니다. 이렇게 변환된 Document는 텍스트 문단과 동일한 방식으로 벡터 임베딩이 가능하며, 이미지에서 추출된 정보 역시 텍스트 기반 질의처럼 검색되고 응답에 반영될 수 있습니다. 이는 멀티모달 RAG 구조의 핵심적인 전처리 단계입니다. image_docs = [] for item in image_summary_results: # 각 딕셔너리에서 파일명과 요약 텍스트 추출 file_name = list(item.keys())[0] summary = item[file_name] # 정규식으로 페이지 번호 추출 match = re.search(r'page_(\d+)_img_\d+\.\w+', file_name) page_number = int(match.group(1)) if match else None # LangChain Document 생성 image_docs.append(Document( page_content=summary, metadata={ "source": "모델튜닝.pdf", "page": page_number, "images": file_name } )) print(f"총 {len(image_docs)}개의 Document 생성 완료") print(image_docs[0].page_content) print(image_docs[0].metadata) # 하나 확인 결과 ③ 문단 나누기 (Chunking) 텍스트와 이미지 각각의 정보를 검색에 적합한 단위로 분할하는 것이 매우 중요합니다. 너무 긴 텍스트는 검색 정확도를 저하시키고, 지나치게 잘게 쪼개면 문맥이 단절될 수 있어 적절한 분할 기준이 필요합니다. 이번에는 Clova Studio에서 제공하는 문단 나누기 API를 활용하여 자연스럽고 의미 단위로 구분된 문서 청크를 생성합니다. 남은 3개의 단계(chunking, Embedding, Vector Store)에 대한 더 자세한 내용은 🦜🔗 랭체인(Langchain)으로 Naive RAG 구현하기 cookbook 를 참고 해주세요. 3.1) 문서 chunking # -*- coding: utf-8 -*- class CompletionExecutor: def __init__(self, host, api_key, request_id): self._host = host self._api_key = api_key self._request_id = request_id def _send_request(self, completion_request): headers = { 'Content-Type': 'application/json; charset=utf-8', 'Authorization': self._api_key, 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id } conn = http.client.HTTPSConnection(self._host) conn.request('POST', '/testapp/v1/api-tools/segmentation', json.dumps(completion_request), headers) response = conn.getresponse() result = json.loads(response.read().decode(encoding='utf-8')) conn.close() return result def execute(self, completion_request): res = self._send_request(completion_request) if res['status']['code'] == '20000': return res['result']['topicSeg'] else: print("[CLOVA 응답 오류]", res['status']) return 'Error' file_path = "data/extracted_images_문서/merged_text.txt" with open(file_path, "r", encoding="utf-8") as f: text_content = f.read() if __name__ == '__main__': completion_executor = CompletionExecutor( host='clovastudio.stream.ntruss.com', api_key="Bearer "+os.environ["CLOVASTUDIO_API_KEY"], request_id=str(uuid.uuid4()) ) chunked_docs = [] for doc in docs: # docs는 페이지별로 추출한 Document 리스트 segments = completion_executor.execute( # 이전 블로그 참고해 파라미터 설정 {"postProcessMaxSize": 100, # 후처리 시 하나의 문단이 가질 수 있는 최대 글자 수 (예: 1000자 이하로 잘라줌) "alpha": -100, # 문단 나누기 민감도 조절 파라미터 (기본: 0.0 / -100으로 두면 자동 조정) - 값이 클수록 더 잘게 나뉘고, 작을수록 덜 나뉨 "segCnt": -1, # 원하는 문단 개수 설정 (-1이면 자동 분할, 1 이상의 정수 입력 시 해당 개수로 고정) "postProcessMinSize": -1, # 후처리 시 하나의 문단이 가져야 할 최소 글자 수 (예: 300자 이상 유지) "text": doc.page_content, # 실제 분할할 원본 텍스트 "postProcess": True} # 후처리 여부 설정 (True: 문단 길이 균일화 / False: 모델 출력 그대로 사용) ) for seg in segments: chunked_docs.append(Document( page_content=' '.join(seg), metadata=doc.metadata )) print(chunked_docs) print("chunk 개수 :",len(chunked_docs)) 결과 3.2) 이미지 chunking 이미지 설명에 대해서는 일반 텍스트와 달리 별도로 chunking을 하지 않고 한 덩어리로 그대로 유지하는 것이 효과적입니다. 그 이유는 간단합니다. 이미지 설명 텍스트는 일반적으로 길이가 짧고, 하나의 이미지가 하나의 의미 단위를 담고 있기 때문입니다. 이러한 내용을 잘라서 나누면 오히려 문맥이 단절되거나 의미가 모호해질 수 있습니다. 한 개의 독립적인 청크로 처리하는 것이 검색 정확도 측면에서도 더 안정적인 결과를 보여줍니다. 따라서 이미지 설명은 별도 분할 없이, 1 이미지 요약 = 1 Document 형태로 구성하여 기존 텍스트 청크들과 함께 병합하여 사용합니다. # image_docs를 chunked_docs에 추가 (원본은 그대로 유지) combined_docs = chunked_docs + image_docs print(f"전체 chunk 개수: {len(combined_docs)}") 텍스트와 이미지에 대해 chunking 작업을 수행한 결과, 총 19개의 청크(텍스트 10개 + 이미지 9개)가 생성되었습니다. 이제 실제로 생성된 청크 중 일부를 출력하여 어떤 형태로 구성되어 있는지 확인해보겠습니다. 아래는 생성된 청크 중 처음 3개의 샘플입니다. # 샘플 청크 출력 print("\n샘플 청크 (처음 3개):") for i, chunk in enumerate(combined_docs[:3], 0): print(f"\n청크 {i+1}:") print(f"내용: {chunk.page_content}") print(f"metadata: {chunk.metadata}") print(f"길이: {len(chunk.page_content)}자") 결과 ④ 벡터 데이터 변환 (Embedding) 이제 문단 단위로 잘게 나눠진 텍스트와 이미지 설명을 벡터로 변환할 차례입니다. 이번 예제에서는 CLOVA Studio의 텍스트 임베딩 모델을 활용해 벡터를 생성합니다. langchain-naver의 ClovaXEmbeddings를 통해 CLOVA Studio의 임베딩 및 임베딩 v2 API를 손쉽게 활용할 수 있습니다. 임베딩 V2는 bge-m3 모델을 사용하며, 이 모델은 임베딩 과정에서 유사도 판단을 위해 코사인 거리(Cosine)를 거리 단위로 사용합니다. 모델을 설정하지 않으면 clir-emb-dolphin 모델이 기본값으로 지정되므로, ClovaXEmbeddings의 모델을 bge-m3로 명시적으로 설정해주어야 합니다. from langchain_naver import ClovaXEmbeddings clovax_embeddings = ClovaXEmbeddings(model='bge-m3') # 임베딩 모델을 설정 text = "임베딩 사용 예제입니다~" clovax_embeddings.embed_query(text) 결과 ⑤ 벡터 데이터 저장 (Vector Store) 임베딩된 벡터 데이터를 저장하고 나중에 효율적으로 검색하기 위해서는 벡터 저장소가 필요합니다. 이 예제에서는 로컬 환경에서 보다 쉽게 활용할 수 있는 Chroma와 FAISS를 사용했습니다. Langchain의 Vector DB 비교 문서를 참고하여 자신의 개발 환경에 적합한 솔루션을 선택하면 됩니다. 전체 문서를 add_documents()로 한 번에 추가하면 내부적으로 많은 개별 임베딩 API 요청이 병렬로 실행되어 에러가 발생할 수 있습니다. 이를 방지하기 위해 요청 사이에 time.sleep() 간격을 두어 처리 속도를 조절함으로써 에러 발생률을 낮췄습니다. 5.1) Chroma Chroma는 Python 기반의 오픈소스 벡터 데이터베이스로, 사용이 간편하고 빠른 프로토타이핑에 적합합니다. 특히 로컬 환경에서도 빠르게 실행할 수 있어 개발 초기 단계에서 많이 활용됩니다. #chroma 다운받기 %pip install -qU langchain-chroma import chromadb from langchain_chroma import Chroma # 임베딩 모델 정의 clovax_embeddings = ClovaXEmbeddings(model='bge-m3') # 로컬 클라이언트 생성 client = chromadb.PersistentClient(path="./chroma_langchain_db") # 컬렉션 준비 (이름 중복 주의!) collection_name = "clovastudiodatas_docs" client.get_or_create_collection( name=collection_name, metadata={"hnsw:space": "cosine"} ) # 벡터스토어 객체 생성 vectorstore_Chroma = Chroma( client=client, collection_name=collection_name, embedding_function=clovax_embeddings ) # 문서 추가: 최신 방식은 vectorstore.add_documents 사용 print("Adding documents to Chroma vectorstore...") for doc in combined_docs: try: vectorstore_Chroma.add_documents([doc]) time.sleep(0.5) except Exception as e: print(f"[✘] 실패: {doc.metadata} → {e}") print("All documents have been added to the vectorstore.") 결과 5.2) FAISS FAISS는 대규모 벡터 검색을 위한 라이브러리로, 속도와 확장성 측면에서 매우 강력한 성능을 제공합니다. 특히 대용량 문서를 처리할 때 효율적이며, 검색 정확도도 뛰어난 편입니다. #FAISS 다운로드 %pip install -qU langchain-community faiss-cpu import faiss from langchain_community.vectorstores import FAISS from langchain_community.docstore.in_memory import InMemoryDocstore # 임베딩 모델 정의 clovax_embeddings = ClovaXEmbeddings(model='bge-m3') # FAISS 인덱스 생성 (1024는 bge-m3 차원 수에 맞춰야 함) index = faiss.IndexFlatIP(1024) # 내적 기반 검색 # FAISS 벡터스토어 생성 vectorstore_FAISS = FAISS( embedding_function=clovax_embeddings, index=index, docstore=InMemoryDocstore(), index_to_docstore_id={} ) # 문서 일괄 추가 (자동 임베딩 처리) print("Adding documents to FAISS vectorstore...") for doc in combined_docs: try: vectorstore_FAISS.add_documents([doc]) time.sleep(0.5) except Exception as e: print(f"[✘] 실패: {doc.metadata} → {e}") print("All documents have been added to FAISS vectorstore.") 결과 3. 질의 응답해보기 ① 질문하기 문서 임베딩과 벡터 저장소 구성이 완료되었다면, 이제 실제 질문을 입력하고 관련 내용을 찾아 답변을 생성하는 과정을 진행해보겠습니다. LangChain에서는 RetrievalQA 체인을 통해 이 흐름을 간단하게 구현할 수 있습니다. 1.1) Retriever 생성하기 먼저 사용자 질문에 따라 연관 문서를 검색하고, 해당 문서를 기반으로 답변을 생성하는 체인을 구성합니다. 아래 코드는 시스템 프롬프트와 사용자 프롬프트를 구분하여 설정합니다. 시스템 프롬프트에서는 LLM이 기존 지식을 사용하지 않고 검색된 문서(context)에 기반하여 답변하도록 안내합니다. 사용자 프롬프트에는 문서 내용과 질문이 함께 전달됩니다. 질문을 입력하면 관련 문서를 검색한 후 답변을 생성합니다. 결과에는 답변뿐만 아니라 어떤 문서가 참조되었는지도 확인할 수 있습니다. from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate from langchain.chains import RetrievalQA # System 및 User 메시지를 나눠 구성 system_template = ( "당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 원래 가지고있는 지식은 모두 배제하고, 주어진 문맥(context) 에서 주어진 질문(question) 에 답하는 것입니다." "만약, 주어진 문맥(context) 에서 답을 찾을 수 없다면, 답을 모른다면 `주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다` 라고 답하세요." ) user_template = ( "다음은 검색된 문서 내용입니다:\n\n{context}\n\n" "위 정보를 바탕으로 다음 질문에 답해주세요:\n{question}" ) prompt_template = ChatPromptTemplate.from_messages([ SystemMessagePromptTemplate.from_template(system_template), HumanMessagePromptTemplate.from_template(user_template), ]) # 원하는 vectorstore 선택해서 사용 retriever = vectorstore_Chroma.as_retriever( search_type="similarity_score_threshold", search_kwargs={"score_threshold": 0.1, "k": 3} ) # retriever = vectorstore_FAISS.as_retriever( # search_type="similarity_score_threshold", # search_kwargs={"score_threshold": 0.1, "k": 3} # ) # Retrieval QA 체인 구성 qa_chain = RetrievalQA.from_chain_type( llm=chat_llm, chain_type="stuff", retriever=retriever, chain_type_kwargs={"prompt": prompt_template}, return_source_documents=True ) # 실행 question = "데이터셋 규모가 커질수록 2대륙의 오류 발생 확률은 어떻게 돼?" result = qa_chain.invoke({"query": question}) print("질문:", question) print("응답:", result["result"]) # 모델의 실제 응답 for i, doc in enumerate(result["source_documents"]): # 답변시 참고 한 문서 print(f"\n[출처 문서 {i+1}]\n내용: {doc.page_content}\n메타데이터: {doc.metadata}") ② 답변확인 텍스트만 사용했을 때는 모델이 관련 정보를 찾지 못해 제한적인 답변을 제공했지만, 이미지 요약 텍스트까지 함께 활용했을 때는 훨씬 구체적이고 관련성 높은 답변을 생성할 수 있었습니다. 멀티모달 RAG 시스템이 어떻게 검색 품질과 응답 정확도를 향상시키는지 확인하실 수 있습니다. 맺음말 이번 cookbook에서는 텍스트뿐만 아니라 이미지 기반 정보를 함께 활용해 검색 정확도를 높일 수 있는 Multimodal RAG 시스템을 구성해보았습니다. 단순히 문서를 임베딩하는 단계를 넘어, 이미지 속 시각 정보를 비전 모델을 통해 요약하고 벡터 DB에 저장하여 검색에 활용함으로써 더욱 풍부한 질의응답이 가능해졌습니다. 특히 텍스트만으로는 충분히 대응하기 어려웠던 질문에도 이미지 기반 문서를 통해 정확한 답변을 도출할 수 있었던 예시를 통해, 비정형 데이터를 효과적으로 구조화하고 활용하는 방법의 가능성을 확인할 수 있었습니다. 이 가이드를 통해 멀티모달 RAG 시스템을 쉽게 구축하고 비전 모델의 실제 활용 흐름을 이해할 수 있기를 기대합니다. LangChain 공식 문서: https://python.langchain.com/docs/integrations/providers/naver/ LangChain 연동 사용 가이드: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Python용 AWS SDK (Boto3) 가이드 : https://guide.ncloud-docs.com/docs/storage-storage-8-2
-
- multimodal
- rag
-
(and 1 more)
Tagged with:
-
글로벌 AI 모델 API 생태계와의 연결성 AI 서비스 개발에서 OpenAI API, 특히 Chat Completions API 형식은 사실상 업계 표준으로 자리 잡았습니다. 수많은 오픈소스 프레임워크와 개발 도구들이 OpenAI 호환 API(OpenAI Compatible API)를 기본 인터페이스로 채택하고 있으며, 개발자들 역시 이 환경에 익숙해져 있습니다. CLOVA Studio가 이번에 OpenAI 호환 API를 제공하는 것 역시 이런 흐름을 반영한 결과입니다. OpenAI 중심의 글로벌 AI 생태계와 손쉽게 연결되도록 지원해 HyperCLOVA X 모델을 더 쉽게 쓸 수 있게 하는 것이죠. 실제로 오픈소스 커뮤니티를 살펴보면 LLM 서빙 프레임워크인 vLLM, Ollama, LM Studio 등에서 OpenAI 호환 API를 지원하는 것을 볼 수 있고, AI 어플리케이션 및 에이전트 개발 프레임워크인 LlamaIndex, AutoGen, CrewAI 등은 OpenAI 호환 API가 있는 경우 별도의 연동 구현 없이도 활용이 가능합니다. LangChain이나 LangGraph 역시 마찬가지이지만, 이 경우 최근 출시한 CLOVA Studio 공식 연동 패키지인 langchain-naver 이용을 권장합니다. (링크) CLOVA Studio가 OpenAI 호환 API를 지원함으로써 사용자들은 이처럼 광범위한 생태계에 곧바로 연결할 수 있습니다. 덕분에 기존 환경을 최대한 유지하면서도 HyperCLOVA X 기반의 AI 서비스와 애플리케이션을 손쉽게 개발할 수 있게 된 것이죠. 개발 편의성: 손쉬운 통합 및 이전 개발 CLOVA Studio의 OpenAI 호환 API를 사용하면 OpenAI가 공식 제공하는 SDK는 물론, 오픈소스 커뮤니티에서 제공하는 다양한 SDK도 그대로 활용할 수 있습니다. OpenAI는 Python, JavaScript, Java, Go, .NET 등 여러 언어용 SDK를 공식 지원하고 있으며, CLOVA Studio 역시 일부 정보만 수정하면 동일한 코드 베이스에서 바로 적용할 수 있습니다. 또한 오픈소스 커뮤니티에는 Kotlin, C++, PHP 등 더 다양한 언어용 SDK도 준비돼 있으니, 필요하다면 지원 언어 및 SDK 목록을 참고해 보시기 바랍니다. 아래를 참고하여 기존 OpenAI SDK 기반의 코드 그대로 API 키, 엔드포인트, 모델명만 변경하여 HyperCLOVA X 모델을 호출해보세요! python import openai # SDK 설치가 필요한 경우, 터미널에서 'pip install openai' 실행 # OpenAI Client 인스턴스화 (CLOVA Studio 정보 설정) client = OpenAI( api_key=<CLOVASTUDIO-API-KEY>, # CLOVA Studio API 키 입력 base_url="https://clovastudio.stream.ntruss.com/v1/openai" # CLOVA Studio 오픈AI 호환 API 엔드포인트 입력 ) # 기존 OpenAI 코드 그대로 사용 가능 completion = client.chat.completions.create( model="HCX-005", # CLOVA Studio 모델명 입력 messages=[ {"role": "system", "content": "- 해적처럼 말하기"}, { "role": "user", "content": "파이썬 객체가 클래스의 인스턴스인지 어떻게 확인할 수 있지?", }, ], ) print(completion["choices"][0]["message"]["content"]) javascript/typescript import OpenAI from "openai"; // SDK 설치가 필요한 경우, 터미널에서 'npm install openai' 실행 const client = new OpenAI({ apiKey: <CLOVASTUDIO-API-KEY>, // CLOVA Studio API 키 입력 baseURL: "https://clovastudio.stream.ntruss.com/v1/openai" // CLOVA Studio OpenAI 호환 API 엔드포인트 입력 }); const completion = await client.chat.completions.create({ model: "HCX-005", messages: [ { role: 'system', content: '- 해적처럼 말하기' }, { role: 'user', content: '자바스크립트에서 세미콜론을 꼭 써야 할까?' }, ], }); console.log(completion.choices[0].message.content); 이처럼 CLOVA Studio의 OpenAI 호환 API를 활용하면 해당 API를 기반으로 구축된 서비스에서 최소한의 수정으로 CLOVA Studio의 HyperCLOVA X 모델을 바로 호출할 수 있습니다. 기존 코드 베이스를 거의 그대로 유지할 수 있기 때문에, 새로 개발하거나 전환할 때 개발 부담이 최소화됩니다. 이러한 호환성 덕분에 쿼리별로 모델을 선택하거나 장애 발생 시 다른 LLM으로 우회하는 등 멀티 LLM 기반의 서비스 구조도 쉽게 구현할 수 있습니다. 즉, 단순히 새로운 모델을 쓰는 데 그치지 않고, 운영 환경에서도 탄력적이고 유연한 아키텍처를 구성할 수 있게 됩니다. 지원 범위 CLOVA Studio는 아래와 같이 Chat Completions, 임베딩 등 주요 API에서 OpenAI 호환성을 제공합니다. CLOVA Studio API OpenAI API URI (Method) Chat Completions, Chat Completions v3 Chat Completions /chat/completions (POST) 임베딩, 임베딩 v2 Embeddings /embeddings (POST) 모델 조회 Models /models (GET) 아래는 Chat Completions API의 호환성 표입니다. CLOVA Studio의 OpenAI 호환 Chat Completion API에서 사용 가능한 필드 목록을 확인할 수 있습니다. (2025년 5월 기준) 앞으로도 새로운 기능이 지속적으로 추가되면서 지원 범위가 확장될 예정이니 참고해 주시기 바랍니다. 지원 필드 미지원 필드 CLOVA Studio 전용 필드 model messages stream tools tool_choice temperature max_tokens (기본값: 512) max_completion_tokens (기본값: 512) top_p stop seed frequency_penalty presence_penalty response_format store reasoning_effort metadata logit_bias logprobs top_logprobs n modalities prediction audio service_tier stream_options parallel_tool_calls user top_k repeat_penalty repetition_penalty 비즈니스 관점: 경쟁력 강화와 고객 선택지 확대 CLOVA Studio의 OpenAI 호환 API 지원은 새로운 AI 플랫폼을 검토하거나 기존 서비스를 유지보수하는 경우 실질적인 이점을 제공합니다. 특히 OpenAI API로 이미 구축된 시스템의 경우, API 키와 엔드포인트, 모델명만 변경하면 CLOVA Studio의 HyperCLOVA X 모델로 바로 전환할 수 있어 재개발 비용과 리스크를 크게 줄일 수 있습니다. 새로운 모델을 도입하면서 코드 전체를 뜯어고칠 필요 없이 기존 코드 베이스를 그대로 유지할 수 있다는 점은 실무에서 커다란 장점입니다. 또한 이 호환성 덕분에 멀티 LLM 기반의 서비스도 손쉽게 구성할 수 있습니다. 예를 들어 OpenAI의 모델과 CLOVA Studio의 HyperCLOVA X를 동시에 활용해 쿼리별로 최적의 모델을 선택하거나, 특정 상황에서 자동으로 다른 모델로 우회하는 폴백(fallback) 시나리오를 구현할 수도 있습니다. API 스펙이 동일하기 때문에 로직 상 분기 처리만 추가하면 이런 구조를 빠르게 적용할 수 있고, 한쪽 모델에 문제가 생겼을 때 서비스 연속성을 유지할 수 있다는 점에서 운영 안정성도 크게 향상됩니다. 데이터 프라이버시 이슈나 비용 문제 등으로 OpenAI 모델이 아닌 다른 모델을 고려해야 하는 경우에도 CLOVA Studio는 HyperCLOVA X라는 한국어 특화 모델을 제공하며, OpenAI와 거의 동일한 방식으로 사용할 수 있어 전환 부담이 적습니다. 결과적으로 이 호환성은 단순히 API 연동 편의를 넘어, 전환과 도입 리스크를 낮추고 서비스 구조의 유연성을 확보하며, 장기적인 유지보수 효율성까지 높여주는 실질적인 이점을 제공합니다. 개발팀 입장에서는 더 많은 선택지를 확보하고 상황에 맞게 빠르게 대응할 수 있다는 점이 큰 강점으로 작용할 것입니다. 마치며 이번 OpenAI 호환 API 지원은 결국 더 많은 개발자가 HyperCLOVA X를 손쉽게 활용할 수 있도록 마련됐습니다. 전 세계적으로 통용되는 표준에 맞춰 생태계와의 연결성을 확보하고, 기존 코드를 거의 그대로 활용할 수 있게 하여 개발 편의성을 극대화했습니다. 이를 통해 새로운 AI 플랫폼 도입에 따르는 부담을 낮추고, 서비스 전환이나 멀티 LLM 구성도 훨씬 유연하게 대응할 수 있게 되었습니다. 결국 이 호환성은 개발자의 시간을 아끼고 더 빠르게 실험하고 혁신할 수 있는 환경을 만들어 줍니다. CLOVA Studio는 앞으로도 개방성과 실용성을 바탕으로 개발자와 서비스 운영자 모두에게 매력적인 플랫폼으로 자리 잡아갈 것입니다. 오픈AI 호환성 가이드 링크 : https://api.ncloud-docs.com/docs/clovastudio-openaicompatibility
-
안녕하세요, @insighter님, CLOVA Studio의 Chat Completions API는 Stateless (무상태) 특성을 갖고 있으며, 따라서 테스트 앱 등록 시 입력된 프롬프트는 따로 저장되거나 특정 테스트/서비스 앱에 자동으로 입력되지 않습니다 (시스템 프롬프트 포함). 특정 프롬프트를 기준으로 테스트/서비스 앱을 발급하는 이유는 서비스 앱 신청 시 이용 목적 등의 서비스 관련 정보를 확인하기 위함이며, 매 요청을 보낼 때 data > messages에 작성한 프롬프트만을 대상으로 처리됩니다. 따라서 다른 모델을 이용하지 않는 경우 신규 API 키를 발급받을 필요는 없습니다. 참고로 HCX-003 모델은 출시 이후 별도의 변경 사항이 없습니다. 언어 모델은 특성상 외부 데이터를 알 수 없기 때문에, 관련 질의에 대해 할루시네이션이 발생할 수 있습니다.이를 보완하려면 Function calling 등을 활용해 외부 API를 호출하는 방법을 검토해 보시기 바랍니다. 감사합니다.
-
1. 임베딩이란 무엇인가요? 임베딩은 자연어 처리(NLP)와 기계학습의 핵심 개념으로, 텍스트 데이터를 인공지능이 이해할 수 있는 숫자 벡터로 변환합니다. 의미적으로 유사한 "멍멍이"와 "강아지" 같은 단어들은 벡터 공간에서도 가까운 위치에 배치됩니다. 임베딩의 가장 큰 특징은 단어나 문장의 의미적 관계를 수학적으로 표현할 수 있다는 점입니다. "왕 - 남자 + 여자 = 여왕"과 같은 벡터 연산이 가능하여 자연어의 의미 관계를 수치적으로 포착합니다. 단순한 단어 수준을 넘어 문장과 문단 전체의 의미까지 포착할 수 있는 임베딩은 검색 시스템, 추천 시스템, 감정 분석 등 다양한 자연어 처리 작업에서 핵심적인 역할을 합니다. 특히 최근 transformer 기반 사전학습 모델의 등장으로 더욱 정교한 임베딩이 가능해졌으며, 이는 기계 번역과 질의응답 시스템 같은 고도화된 AI 서비스의 성능 향상에 크게 기여하고 있습니다. CLOVA Studio의 임베딩 API(v2 포함)를 통해 텍스트 데이터를 1,024차원의 벡터로 변환할 수 있습니다. 이제 화장품 리뷰 데이터를 예시로 활용하여, CLOVA Studio 임베딩v2 API로 텍스트의 의미를 벡터 공간에 표현하고 분석하는 과정을 진행해보겠습니다. 분석 데이터 : review-cosmetic_raw.csv (데이터 출처 : AI Hub 속성기반 감정분석 데이터) 2. 임베딩 시각화를 통한 데이터 분포 확인 리뷰 텍스트 데이터 시각화는 다음 네 단계로 진행됩니다. 화장품 리뷰 텍스트 데이터를 수집하고 전처리합니다. 리뷰의 감정은 긍정(Positive), 중립(Neutral), 부정(Negative)으로 분류되어 있습니다. CLOVA Studio의 임베딩v2 API를 활용하여 각 리뷰 텍스트의 1,024차원 임베딩 벡터를 생성합니다. 고차원의 임베딩 벡터를 t-SNE 알고리즘을 통해 2차원으로 차원 축소합니다. 감정 분류에 따라 색상을 다르게 적용하여 시각화함으로써, 감정별 군집화 패턴을 확인할 수 있습니다. 이러한 과정을 통해 화장품에 대한 고객들의 감정적 반응이 벡터 공간에서 어떻게 분포하는지 파악할 수 있습니다. ① 필요한 모듈 import import time from tqdm import tqdm import pandas as pd from sklearn.manifold import TSNE import numpy as np import matplotlib.pyplot as plt from matplotlib import rcParams from sklearn.utils import resample ② 데이터 불러오기 df = pd.read_csv('review-cosmetic_raw.csv', encoding = 'utf-8-sig') # 같은 디렉토리 상의 데이터 불러오기 df.info() # 데이터 정보 확인 print(df.head()) # 데이터 상단 부분 출력 <class 'pandas.core.frame.DataFrame'> RangeIndex: 14835 entries, 0 to 14834 Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Index 14835 non-null int64 1 Aspects 14835 non-null object 2 Domain 14835 non-null object 3 GeneralPolarity 14835 non-null int64 4 Text 14835 non-null object dtypes: int64(2), object(3) memory usage: 579.6+ KB Index Aspects Domain \ 0 1 [{'Aspect': '기능/효과', 'SentimentText': ' 거품이 풍부... 화장품 1 2 [{'Aspect': '기능/효과', 'SentimentText': '여드름 피부에... 화장품 2 3 [{'Aspect': '보습력/수분감', 'SentimentText': '유분기도 ... 화장품 3 4 [{'Aspect': '기능/효과', 'SentimentText': '이 제품 쓴다... 화장품 4 5 [{'Aspect': '향', 'SentimentText': '박하향이 처음에는 자... 화장품 GeneralPolarity Text 0 1 거품이 풍부해서 사용하기 편하고, 사용하기 편하고, 세정력도 좋습니다. 피부에 ... 1 0 여드름 피부에 잘 맞는 듯합니다. 좁쌀 여드름이 많이 좋아졌어요. 용량이 작고 사... 2 1 유분기도 여드름도 많이 좋아졌어요. 여드름도 많이 좋아졌어요. 세일할 때 구매하니 ... 3 1 이 제품 쓴다고 여드름이 안 생기는 건 아니지만 자극적이지 않아서 촉촉하지도 않지만... 4 1 박하향이 처음에는 자극적이라 생각했는데 풍부한 거품으로 부드럽게 잘 세정되는것 같아... ③ 임베딩 구하기 본 분석에서는 빠르게 임베딩 값을 구하고 시각화하기 위해 240개의 데이터 포인트 (부정 -1, 중립 0, 긍정 1 : 각 80개씩)를 샘플링하여 사용합니다. def process_batch(batch, executor, max_retries, retry_delay_seconds): results = [] for text in tqdm(batch, desc="Processing Requests"😞 retries = 0 while retries <= max_retries: try: response = executor.execute({"text": text}) if isinstance(response, list😞 results.append(response) break raise ValueError(f"Unexpected response format: {response}") except Exception as e: retries += 1 if retries > max_retries: print(f"Skipping text: {text} due to repeated errors.") results.append(None) else: time.sleep(retry_delay_seconds) return results def main(): executor = CompletionExecutor( host='clovastudio.apigw.ntruss.com', api_key='****', # 올바른 값으로 변경해줘야합니다 api_key_primary_val='***', # 올바른 값으로 변경해줘야합니다 request_id='****' # 올바른 값으로 변경해줘야합니다. ) # 데이터 포인트 240개 샘플링 data = pd.concat([ resample(df[df['GeneralPolarity'] == 1], n_samples=80, random_state=0), resample(df[df['GeneralPolarity'] == 0], n_samples=80, random_state=0), resample(df[df['GeneralPolarity'] == -1], n_samples=80, random_state=0) ]).reset_index(drop=True) batches = [data['Text'][i:i + 60] for i in range(0, len(data), 60)] embeddings = [] for i, batch in enumerate(batches, start=1😞 print(f"Processing batch {i}/{len(batches)}") embeddings.extend(process_batch(batch, executor, max_retries=5, retry_delay_seconds=10)) if i < len(batches): time.sleep(30) # 429에러 발생 방지를 위한 딜레이, 필요시 조정 data['Embedding'] = embeddings print(data) if __name__ == '__main__': main() Processing batch 1/4 Processing Requests: 100%|██████████| 60/60 [00:08<00:00, 7.36it/s] Processing batch 2/4 Processing Requests: 100%|██████████| 60/60 [00:39<00:00, 1.52it/s] Processing batch 3/4 Processing Requests: 100%|██████████| 60/60 [00:44<00:00, 1.35it/s] Processing batch 4/4 Processing Requests: 100%|██████████| 60/60 [00:30<00:00, 1.95it/s] Index Aspects \ 0 3905 [{'Aspect': '자극성', 'SentimentText': '순하고 ', 'S... 1 13891 [{'Aspect': '기능/효과', 'SentimentText': '잡티, 멜라닌... 2 4789 [{'Aspect': '기능/효과', 'SentimentText': '세정력이 뛰어... 3 7049 [{'Aspect': '보습력/수분감', 'SentimentText': '얼굴에 너... 4 13036 [{'Aspect': '제형', 'SentimentText': '제형이 생크림 입자... .. ... ... 235 4639 [{'Aspect': '흡수력', 'SentimentText': '너무 무거운 느낌... 236 5757 [{'Aspect': '편의성/활용성', 'SentimentText': '사용하기 ... 237 9963 [{'Aspect': '기능/효과', 'SentimentText': '주름이 옅어지... 238 5514 [{'Aspect': '피부타입', 'SentimentText': '이 제품은 건성... 239 7696 [{'Aspect': '보습력/수분감', 'SentimentText': '촉촉함이 ... GeneralPolarity Text \ 0 1 순하고 저렴하고 양이 많아요. 촉촉함도 오래가고, 오래가고, 끈적이지 않아요. ... 1 1 잡티, 멜라닌 색소 억제 및 잡티 제거와 커버에도 도움이 되는 것 같아요. 잡티 ... 2 1 세정력이 뛰어난 것 같습니다. 세안하고 나면 뽀득거리면서도 자극적이지 않고 깨끗한 ... 3 1 얼굴에 너무 촉촉하고 ~~ 와~얼굴에 윤기가 광이 나요~~굿 4 1 제형이 생크림 입자 느낌으로 쫀쫀하게 피부에 문지르면 깨끗하게 잘 지워져요. .. ... ... 235 -1 너무 무거운 느낌이라 자주 손이 안가네요. 피부에 팩한 것 처럼 한꺼풀 덮여 있는 ... 236 -1 사용하기 불편합니다. 리프팅 효과도 없는 것 같고 피부에 트러블이 생깁니다. 237 -1 주름이 옅어지는 느낌 안 드네요. 피부는 약간 간질거리고, 붉은 트러블도 생겼어... 238 -1 이 제품은 건성인 분들에게는 뻑뻑하게 발리고 건조한 것 같습니다. 뻑뻑하게 발리고... 239 -1 촉촉함이 덜하고 끈적임이 있어 건조할때 OOO 바르고 건조함이 완화가 되기를 기대했... Embedding 0 [-1.0322266, 1.0615234, -1.0039062, 0.02919006... 1 [-0.70654297, 0.68603516, -1.1757812, -0.28100... 2 [-0.7182617, 1.0566406, -1.0390625, -0.2807617... 3 [0.38183594, 1.3720703, -1.1142578, -0.8857422... 4 [-0.5258789, 0.52441406, -1.1601562, -1.410156... .. ... 235 [0.22509766, 1.0605469, -1.3222656, -0.7373047... 236 [-0.87353516, 1.6015625, -1.5839844, -0.878417... 237 [-1.1142578, 0.8383789, -1.4892578, -0.6748047... 238 [-0.049591064, 1.4492188, -0.671875, -1.814453... 239 [-0.41479492, 1.0751953, -1.3623047, -0.305419... [240 rows x 5 columns] # 임베딩값을 포함한 데이터프레임 저장 data.to_csv('review-cosmetic_emb.csv', index=False, encoding='utf-8-sig') 리뷰데이터에 대해 임베딩 값을 추가하여 저장한 결과 파일은 다음과 같습니다. review-cosmetic_emb.csv matplot, t-SNE 차원 축소를 통해 임베딩 시각화하기 t-SNE(t-Distributed Stochastic Neighbor Embedding)는 고차원 데이터를 저차원으로 변환하여 시각화하는 데 매우 효과적인 비선형 차원 축소 기법입니다. 1024차원의 데이터 포인트의 임베딩값 간의 유사도 관계를 최대한 보존하여 2차원 공간으로 차원 축소하면 데이터 포인트들을 시각화할 수 있습니다. 비슷한 의미를 가진 데이터 포인트들은 2차원 평면상에서 서로 가깝게 위치하게 되어, 임베딩 공간의 구조를 직관적으로 이해할 수 있게 됩니다. 본 분석에서는 빠르게 임베딩 값을 구하고 시각화하기 위해 240개의 데이터 포인트 (부정 -1, 중립 0, 긍정 1 : 각 80개씩)를 샘플링하여 사용합니다. rcParams['font.family'] = 'AppleGothic' plt.rcParams['axes.unicode_minus'] = False embeddings = np.array(data['Embedding'].tolist()) tsne = TSNE(n_components=2, random_state=0, perplexity=30) # 2차원으로 시각화, perplexity는 데이터의 고차원 공간에서 가까운 이웃을 선택하는 방법과 관련이 있으며, 이 값이 크면 더 넓은 범위의 이웃을 고려한다는 의미이고, 작으면 더 국소적인 관계를 이웃으로 고려한다는 의미입니다 # 데이터포인트의 개수가 많을수록 큰 값을 사용하는 것이 일반적이며, 보통 5~50 사이의 값을 선택합니다. tsne_results = tsne.fit_transform(embeddings) data['t-SNE Dimension 1'] = tsne_results[:, 0] data['t-SNE Dimension 2'] = tsne_results[:, 1] polarity_to_color = {1: 'green', 0: 'blue', -1: 'red'} # 1: 긍정, 0: 중립, -1: 부정 colors = data['GeneralPolarity'].map(polarity_to_color) plt.figure(figsize=(10, 10)) plt.scatter( data['t-SNE Dimension 1'], data['t-SNE Dimension 2'], c=colors, alpha=0.5 ) plt.title('t-SNE 시각화: 임베딩 감성 분석') plt.xlabel('t-SNE 차원 1') plt.ylabel('t-SNE 차원 2') plt.legend(handles=[ plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='green', markersize=10, label='긍정 (1)'), plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='blue', markersize=10, label='중립 (0)'), plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='red', markersize=10, label='부정 (-1)') ]) plt.show() 감정 별(긍정, 중립, 부정)로 t-SNE 시각화한 결과입니다. 긍정(1, 초록색)은 주로 하단부에 군집화되었고 부정(-1, 빨간색)은 상단부에 주로 분포한 것으로 확인할 수 있습니다. 또한 중립(0, 파란색)은 중앙에 넓게 분포하여 다른 감정들과 일부 겹치는 영역이 있습니다. 리뷰 텍스트가 감정 별로 구분이 되는 군집으로 형성되어 있고 CLOVA Studio의 임베딩 모델이 감정의 의미적 차이를 잘 포착했다는 것을 확인할 수 있습니다. 일부 영역에서 감정 간 겹칩이 발생하는 것은 리뷰 텍스트의 미묘한 감정표현이나 복잡한 표현이 포함된 경우로 해석할 수 있습니다. plotly, t-SNE 차원 축소를 통해 임베딩 시각화하기: 데이터포인트 내용 확인하기 import plotly.express as px import pandas as pd data['Text'] = data['Text'] df_tsne = pd.DataFrame({ 't-SNE Dimension 1': data['t-SNE Dimension 1'], 't-SNE Dimension 2': data['t-SNE Dimension 2'], 'GeneralPolarity': data['GeneralPolarity'], 'Text': data['Text'] }) df_tsne['GeneralPolarity'] = df_tsne['GeneralPolarity'].astype(str) fig = px.scatter( df_tsne, x='t-SNE Dimension 1', y='t-SNE Dimension 2', color='GeneralPolarity', hover_data=['Text'], color_discrete_map={ "-1": "red", # 부정 "0": "blue", # 중립 "1": "green" # 긍정 }, title='t-SNE 시각화: 감성 분석', width=1200, # 그래프 가로 길이, 필요시 조정 height=800 # 그래프 세로 길이, 필요시 조정 ) fig.update_layout( font=dict( family="AppleGothic", size=16 ), title=dict( font=dict(size=16) ), xaxis_title="t-SNE 차원 1", yaxis_title="t-SNE 차원 2" ) fig.show() plot에 표시된 데이터 포인트의 내용을 인터랙티브하게 바로 확인할 수 있도록 'plotly'를 이용하여 시각화하였습니다. 이를 통해 개별 데이터 포인트에 대한 자세한 정보 확인이 가능하여 실제 리뷰 텍스트의 내용이 어떤지 확인할 수 있습니다. 왼쪽 영역에 위치한 초록색 데이터 포인트를 확인해보니 "제품이 셋 세트라 완전 풍성합니다. 제형이 쫀쫀하게 성분이 콜라겐으로 더 행복한 시간 될 것 같아요"라는 내용의 긍정적인 리뷰 내용을 확인할 수 있습니다. 반면, 오른쪽 영역에 위치한 빨간색 데이터포인트를 확인해보면 "눈시림이 너무 심해서 얼굴에 바를 수가 없네요 자극이 너무 심하네요"라는 내용의 부정적인 리뷰 내용을 확인할 수 있습니다. 3. 임베딩 값을 활용한 분류기 구축과 성능평가 지금까지 우리는 이미 감정 분류가 되어있는, 즉 분류 레이블이 있는 데이터의 임베딩을 구하고 시각화를 해보았습니다. 하지만 실제 대부분의 데이터는 레이블이 없는 데이터를 다루게 되는데요, 이런 상황에서 텍스트 임베딩은 분석에 유용한 도구로 활용될 수 있습니다. 임베딩은 텍스트의 의미적 유사성을 수치화하여 표현된 값이기 때문에, 이를 기반으로 비슷한 의미를 가진 데이터들을 그룹화할 수 있습니다. 유사한 텍스트는 다차원의 임베딩 공간에서 가까운 거리에 위치하게 되기 때문입니다. 이러한 임베딩의 특성을 활용하여, K-means 클러스터링을 통해 비슷한 의미를 가진 텍스트 데이터들을 레이블 없이도 분류가 가능합니다. K-means 클러스터링은 다음과 같은 상황에서 특히 유용합니다. 텍스트로 이루어진 대량의 문서(ex. 고객 cs/리뷰 데이터)를 주제 별로 분류할 때 텍스트 데이터의 의미있는 패턴을 찾고 싶을 때 화장품 리뷰 데이터는 이미 분류 레이블(감정), 즉 분류에 대한 정답을 가지고 있지만 클러스터링 분석의 결과를 실제와 비교해보면서 임베딩 기반 클러스터링의 활용은 어떻게 할 수 있는지 알아보겠습니다. 임베딩 값을 활용한 분류기 구축/성능 평가 과정은 다음과 같습니다. K-means 클러스터링 클러스터링 성능평가하기 ① 필요한 모듈 import import numpy as np import pandas as pd from sklearn.cluster import KMeans from sklearn.feature_extraction.text import TfidfVectorizer import matplotlib.pyplot as plt from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score from scipy.stats import entropy from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from xgboost import XGBClassifier from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay from sklearn.model_selection import GridSearchCV K-Means 클러스터링이란? 텍스트 데이터의 t-SNE 차원 축소 결과를 활용하여 K-Means 클러스터링을 수행하고, 클러스터별 카테고리(ex. 감정) 분포와 주요 키워드를 분석하겠습니다. 이를 통해 데이터의 특성별로 데이터를 나눠서 군집화하고 군집화된 데이터들의 내용으로 데이터의 특징을 파악할 수 있습니다. 코드 설명에 앞서, K-Means 클러스터링 알고리즘에 대해 알아봅시다. K-means는 데이터의 특징을 기반으로 하여 k개의 그룹으로 나누는 비지도 학습 알고리즘입니다. K-means 클러스터링 알고리즘을 도식화 하면 다음과 같습니다. 각 클러스터는 하나의 중심점을 가져야 합니다. 1. 초반에는 데이터 포인트 중 무작위로 k개의 중심점이 정해집니다. 이 초기 중심점들이 각 클러스터의 시작점이 됩니다. 2. 각 데이터 포인트들은 초반에 정해진 시작점을 기준으로 가장 가까운 클러스터에 할당됩니다. 3. 정해진 각 클러스터 내 평균을 계산하여 평균값이 새로운 중심값으로 설정됩니다. 4. 더이상 평균값에 변경이 없이 수렴할 때가지 클러스터를 재할당하는 과정을 거칩니다. ② K-Means 클러스터링 실행하기 앞서 t-SNE로 차원 축소한 데이터를 기준으로 3개의 클러스터를 생성합니다. 각 클러스터에서 부정(-1), 중립(0), 긍정(1) 감정이 얼마나 분포하는 확인해보고, 클러스터 별로 데이터의 특징이 어떻게 나타나는지 확인해보겠습니다. 클러스터링 실행 #1. t-SNE 결과 기반으로 클러스터링 kmeans = KMeans(n_clusters=3, random_state=42) data['Cluster'] = kmeans.fit_predict(data[['t-SNE Dimension 1', 't-SNE Dimension 2']]) # 2. 클러스터별 감성 비율 분석 sentiment_distribution = data.groupby('Cluster')['GeneralPolarity'].value_counts(normalize=True).unstack().fillna(0) print("클러스터별 감성 분포:") print(sentiment_distribution) # 3. 주요 키워드 분석 vectorizer = TfidfVectorizer(max_features=15) # 상위 15개 확인, 필요시 변경 가능 cluster_keywords = {} for cluster_id in data['Cluster'].unique(): cluster_texts = data[data['Cluster'] == cluster_id]['Text'] tfidf_matrix = vectorizer.fit_transform(cluster_texts) keywords = vectorizer.get_feature_names_out() cluster_keywords[cluster_id] = keywords print("클러스터별 주요 키워드:") for cluster_id, keywords in cluster_keywords.items(): print(f"Cluster {cluster_id}: {keywords}") ③ 결과 확인하기 클러스터별 감성 분포: GeneralPolarity -1 0 1 Cluster 0 0.076923 0.646154 0.276923 1 0.707547 0.283019 0.009434 2 0.000000 0.115942 0.884058 클러스터별 주요 키워드: Cluster 2: ['꾸준히' '너무' '만족합니다' '많이' '바르고' '얼굴에' '오래지속되어' '정말''좋네요' '좋습니다' '좋아요' '촉촉하고' '피부가' '피부에' '효과가'] Cluster 0: ['같습니다' '같아요' '느낌이' '들어요' '발림성' '발림성이' '않고' '오래' '좋고' '좋네요' '좋습니다' '좋아요' '향은' '향이' '효과는'] Cluster 1: ['가격대비' '가격도' '같아요' '구성이' '너무' '아쉽네요' '아직' '않네요' '않아요' '용량이' '촉촉하지' '피부가' '효과' '효과가' '효과는'] 클러스터 별 감성 분포 결과를 확인해보니, 각 Cluster 0,1,2마다 부정(-1), 중립(0), 긍정(1) 리뷰 내용이 모여있는 것을 확인할 수 있습니다. Cluster 부정(-1) 중립(0) 긍정(1) 0 7.7% 64.6% 27.7% 1 70.8% 28.3% 0.9% 2 0.0% 11.6% 88.4% Cluster 0는 중립, Cluster 1은 부정, Cluster 2는 긍정적인 리뷰가 다수로 차지하고 있습니다. 각 클러스터의 감정 비율을 통해, 화장품에 대한 리뷰가 부정, 중립, 긍정적으로 잘 나뉘는지를 알 수 있습니다. 클러스터 별 주요 키워드를 확인해보면, 긍정적인 리뷰가 많이 포함된 Cluster 2에서는 "좋아요", "촉촉하고"와 같은 단어가 많이 포함되었습니다. 반면, 부정적인 리뷰가 많이 포함된 Cluster 1에서는 "가격대비", "아쉽네요"와 같은 단어의 빈도가 많습니다. 이러한 결과를 확인해서 긍정적인 클러스터에 자주 언급되는 장점은 이를 강조한 마케팅과 같은 비즈니스 인사이트로 활용하거나 부정적인 클러스터에서 나타난 문제점은 개선점으로 인사이트를 얻을 수 있습니다. ④ 클러스터링 품질 평가하기 클러스터의 품질과 데이터 분포를 다양한 지표를 통해 평가하는 방법에 대해 설명하겠습니다. 먼저 데이터의 클러스터링이 잘 되었는지를 알 수 있는 양적 평가 지표에 대해 알아봅시다. # 지표 함수 정의 def evaluate_clustering(data): # 1. Silhouette silhouette_avg = silhouette_score(data[['t-SNE Dimension 1', 't-SNE Dimension 2']], data['Cluster']) print(f"Silhouette Score: {silhouette_avg}") # 2. Calinski-Harabasz ch_score = calinski_harabasz_score(data[['t-SNE Dimension 1', 't-SNE Dimension 2']], data['Cluster']) print(f"Calinski-Harabasz Score: {ch_score}") # 3. Davies-Bouldin db_score = davies_bouldin_score(data[['t-SNE Dimension 1', 't-SNE Dimension 2']], data['Cluster']) print(f"Davies-Bouldin Score: {db_score}") # 평가 실행 print("### Clustering Quality Evaluation ###") evaluate_clustering(data) ### Clustering Quality Evaluation ### Silhouette Score: 0.3865170180797577 Calinski-Harabasz Score: 262.519196880911 Davies-Bouldin Score: 0.9567987699215011 Silhouette 점수는 0.38로 클러스터링 품질이 양호한 수준입니다. 클러스터 내 데이터 포인트가 서로 밀접하게 모여있으면서 다른 클러스터와 적당히 분리된 상태를 의미하며, 점수가 0.5 이상일 경우 클러스터링 품질이 높다고 평가할 수 있습니다. Calinski-Harabasz 점수와 Davies-Bouldin 점수는 상대적 클러스터링 비교에 사용하기 적절하기 때문에 K값을 적절하게 바꿔가면서 비교하며 더 좋은 클러스터링을 찾는데 적절합니다. 3. 맺음말 1024차원의 임베딩 벡터를 2차원으로 시각화하면 리뷰 텍스트 간의 의미적 관계를 시각적으로 이해할 수 있습니다. 이를 통해 데이터 포인트들이 임베딩 벡터 공간에서 어떻게 분포하는지 파악할 수 있으며, 특정 라벨(긍정, 중립, 부정 등)로 분류된 데이터들이 서로 가깝게 위치하는 경향을 확인할 수 있습니다. 이 과정은 데이터의 라벨링 품질과 임베딩 모델의 성능을 확인하는 데 유용합니다. 예를 들어, 데이터 군집 간의 경계가 명확하지 않다면 임베딩 모델이 텍스트 간의 차이를 충분히 학습하지 못했거나, 라벨링된 데이터에 오류가 있을 가능성을 의미합니다. 이를 통해 오분류된 데이터 포인트를 탐지할 수 있으며, 잘못된 라벨링을 수정하거나 모델 성능을 개선하는 데 활용할 수 있습니다. 또한, K-Means 클러스터링과 XGBoost 모델을 활용하여 데이터를 정량적으로 분석했습니다. K-Means는 임베딩 벡터를 군집화하여 데이터 포인트 간의 유사성을 기준으로 각 클러스터의 특성을 파악하는 데 사용할 수 있습니다. 이 분석 방법은 감정 분석뿐만 아니라 다양한 도메인에서 분류 태스크를 정의하거나 데이터의 라벨링 품질을 확인하는 작업에도 활용될 수 있습니다. 예를 들어, 의료 데이터에서 질병 분류를 하거나 고객 리뷰 데이터를 기반으로 제품 추천을 할 때에도 데이터의 의미적 관계를 확인하고 모델 성능을 개선하는 데 기여할 수 있습니다. 따라서 도메인에 따라 임베딩 모델과 시각화 및 분류 방법을 적절히 조정하여 유용하게 활용할 수 있습니다. 지금까지 우리는 임베딩을 활용한 시각화와, 레이블이 없는 데이터를 가정하고 어떻게 분석하고 군집화할 수 있는지 K-means 클러스터링을 통해 알아봤습니다. 그러나, K-means 클러스터링말고도 더 정교한 분류가 필요할 수 있습니다. 이러한 요구사항을 충족하기 위해, 우리는 XGBoost와 같은 고급 머신러닝 알고리즘을 활용할 수 있습니다. 관련 내용은 "임베딩을 활용한 고급 분류 기법: XGBoost" 문서에서 자세히 다루도록 하겠습니다.
-
안녕하세요, @박태호님, 비전 모델을 활용하면 제품의 형태를 파악할 수는 있지만, LLM 특성상 최신 정보나 특정 제품에 대한 전문성은 보장되지 않기 때문에, 단독 구성보다는 이미지 임베딩 등과 결합한 방식으로 구현을 고려하시는 것이 좋습니다. 모델 요금은 아래 링크에서 확인하실 수 있습니다. 비전 모델을 사용하시는 경우에는 HCX-005 모델을 참고해 주세요. 이용 요금 : https://www.ncloud.com/product/aiService/clovaStudio#pricing 클로바 스튜디오 이용을 참고하실 수 있는 가이드 링크를 함께 전달드립니다. 사용 가이드 : https://guide.ncloud-docs.com/docs/clovastudio-overview API 가이드 : https://api.ncloud-docs.com/docs/ai-naver-clovastudio-summary 감사합니다.
-
안녕하세요, @intube님, 클로바 스튜디오가 비전 모델 및 신규 기능 업데이트 되어 안내드립니다. CLOVA Studio 업데이트 내용 보기 많은 이용 부탁드립니다. 감사합니다.
-
안녕하세요, 네이버 클라우드 플랫폼입니다. AI 기반의 특화된 서비스를 손쉽게 만들 수 있는 개발 도구, CLOVA Studio의 새로운 모델을 소개합니다. 이미지를 이해하는 HCX-005 비전 모델을 제공합니다 ✨ HCX-005 비전 모델의 도입으로 서비스 활용 가능성이 크게 확장되었습니다. 텍스트, 이미지, 표 등 다양한 형태의 데이터를 처리하고 이해할 수 있게 되어, 서비스 영역을 크게 확장하고 더욱 지능적이고 유용한 서비스 제공이 가능해졌습니다. 더욱 강력하고 효율적인 HCX-DASH-002 모델을 만나보세요 ⚡️ 다양한 영역에서 성능이 강화된 HCX-DASH-002 모델은, 비즈니스 로직에 최적화된 모델을 더욱 유연하게 선택할 수 있도록 지원합니다. 긴 길이의 문서도 활용 가능합니다 📚 HCX-005 모델은 128k, HCX-DASH-002 모델은 32k로 context length가 확장되어, 더 긴 문서를 활용할 수 있습니다. (모델 가이드 보기)
-
비전 모델을 활용한 비정형 업무 자동화 “이건 사람이 해야만 했잖아요?” 지난 10년간 기업 환경에서는 RPA와 문서 자동화 도구를 통해 정형화된 업무 프로세스의 자동화가 상당한 성과를 거두었습니다. 정해진 화면을 클릭하고, 엑셀에서 데이터를 복사하고, 반복되는 문서 양식을 채우는 일은 이제 대부분 자동화됐습니다. 그러나 주목할 점은 여전히 많은 업무 환경에서 직원들이 이미지, 문서, 그래프 등을 직접 검토하고 분석하여 보고서를 작성하는 데 상당한 시간을 소비하고 있다는 것입니다. 이러한 현상은 주로 '비정형 정보'라는 장벽 때문입니다. 복잡한 문서 구조, 다양한 형태의 시각 자료, 손글씨 메모, 다국어 혼합 콘텐츠 등은 전통적인 자동화 도구로는 처리하기 어려워 여전히 인간의 개입이 필수적이었습니다. 해당 업무들은 자동화의 마지막 난제로 남아 있었습니다. 비전 모델(Vision-Language Model)은 바로 이 지점에서 중요한 돌파구가 될 것입니다. HCX-005와 같은 모델은 이미지와 텍스트를 동시에 이해하며, 인간 수준의 문서 인식, 차트 해석, UI 분석, 손글씨 판별 능력을 갖추고 있습니다. 비전 모델의 도입으로 기존에 자동화되지 못했던 영역에서도 혁신적인 변화가 가능해졌습니다. 이러한 작업들은 기존에는 "사람이 직접 해야 한다"고 여겨졌던 분야들이지만, 비전 모델의 적용으로 효율적인 자동화가 실현됩니다. 사례 검토를 통해 많은 이들이 "이 업무도 자동화가 가능하구나!"라는 새로운 관점을 발견하게 될 것입니다. 본문에서는 익숙한 일상 업무가 혁신적으로 처리되는 실제 사례들을 함께 살펴보며, 자동화의 새로운 가능성을 탐구해보겠습니다. 1. RPA의 새로운 파트너, 비전 모델 RPA(Robotic Process Automation)는 기업 업무 자동화의 강력한 기반이며, 정형화된 입력과 고정된 UI 흐름, 반복 가능한 규칙에서는 여전히 가장 효과적입니다. 하지만 실제 현업의 복잡한 업무는 RPA만으로 처리하기에는 한계가 있습니다. 예를 들어, 양식이 조금만 변경되어도 RPA 시스템이 작동하지 않거나, 스캔 문서나 이미지에서 정보를 추출하는 데 어려움을 겪으며, UI 화면이 업데이트될 때마다 수동으로 재설계해야 합니다. 이러한 문제로 인해 RPA 시스템은 안정적일지라도 예외 상황에서 효율성이 떨어집니다. 여기서 비전 모델이 중요한 역할을 할 수 있습니다. 비전 모델은 RPA가 처리하기 어려운 비정형 정보 해석, 문맥 이해, 예외 상황 대응 등을 담당하여 자동화 프로세스를 더욱 유연하고 실제 업무 환경에 적합하게 만듭니다. ▼ RPA는 정형 업무의 속도를, VLM은 비정형 데이터의 유연성을 제공하며, 두 기술의 결합으로 완전한 자동화 워크플로우가 구축됩니다. ▼ 아래는 '다양한 형식의 인보이스 자동화'의 구체적 사례입니다. 기업에서 자주 다루는 문서들의 형식이 조금씩 다르거나, 다양한 레이아웃을 가진 경우에도 비전 모델이 정확하게 정보를 추출할 수 있는지 테스트해보았습니다. 2. 복잡한 회의 메모 자동 정리 회의 후의 번거로운 과정들 회의 후 화이트보드를 가득 채운 복잡한 그림과 메모. 사진으로는 찍었지만, 막상 다시 보면 어디서부터 정리해야 할지 막막해집니다. 손글씨 메모, 복잡한 도식, 흩어진 키워드들은 일일이 사람이 해석하고 정리해야 했습니다. 회의 자료는 비정형적이고, 흐름을 파악하기 어렵습니다. 기존의 자동화 기술은 화이트보드에 적힌 글자를 단순히 텍스트로 변환할 뿐, 그 안의 맥락을 이해하지 못했습니다. 하지만 이제는 비전 모델을 통해 이러한 비정형적인 회의 이미지 자료를 단순히 ‘읽어내는 것’이 아니라, ‘이해하고 판단해 정리하는 것’까지 가능합니다. 이제 비전 모델은 회의 이미지의 시각적 요소를 분석하고 자연스러운 문서와 행동을 계획하는 전 과정을 지원합니다. 이러한 과정을 자세히 살펴보겠습니다. 화이트보드에 남은 도식과 키워드를 사람이 해석해 작성하던 회의록은 비전 모델을 통해 자동으로 구성되어, 사람의 개입 없이도 완성도 높은 회의록 확보가 가능합니다. 또는 회의 메모에서 액션 아이템을 수동으로 정리하던 과정을 자동화하여, 회의 직후 바로 협업 도구와 연동 가능한 할 일 리스트를 확보할 수 있을 것입니다. ▼ 아래는 회의 중 작성된 복잡한 화이트보드의 예시 입니다. 회의가 끝난 후, 복잡한 화이트보드와 손글씨 메모는 더 이상 정리의 부담이 아닙니다. 대신, 비전 모델이 이러한 시각 자료에서 구조, 흐름 및 맥락을 지능적으로 인식하여 핵심 정보를 체계적으로 정리합니다. 이로써 팀원들은 반복적인 정리 작업에서 벗어나 보다 중요한 논의와 의사결정에 집중할 수 있는 환경을 마련하게 됩니다. 3. 발표 대본 자동 생성하기 슬라이드 작성을 마쳤지만, 발표할 내용을 어떻게 구성해야 할지 막막해지는 순간이 있습니다. 이미지와 도표, 키워드 등을 잘 정리했음에도 불구하고, 발표를 앞두고 나면 어디서부터 시작해야 할지, 어떤 말투로 전달해야 할지에 대한 고민이 깊어지기 마련입니다. 결국 발표 전날 밤, 슬라이드를 한 장씩 넘기며 문장을 하나씩 구상하게 되죠. "이 부분은 이렇게 표현할까?", "여기는 좀 더 설득력 있게 말해야 하는데...", "이 슬라이드는 별도의 설명 없이 넘어가도 괜찮을까?" 슬라이드는 일정한 형식을 따르지만, 발표 대본 작성은 매우 비정형적인 작업입니다. 정해진 형식이나 정답이 없으며, 각 문장은 적절한 톤과 맥락을 고려하여 작성되어야 합니다. 지금까지의 기술로는 이러한 비정형적인 영역에 효과적으로 접근하기 어려웠습니다. 기존 기술은 이미지를 인식할 수 있었지만, 슬라이드가 왜 필요한지, 어떤 내용을 강조해야 하는지, 그리고 청중에게 어떤 흐름으로 설명해야 하는지까지 판단하는 데에는 한계가 있었습니다. 이런 문제를 해결하기 위해 비전 모델을 활용할 수 있습니다. 슬라이드 내용을 가지고 자동으로 발표 대본을 생성하는 기술이 되는거죠. ▼ 발표자료 화면(예: PPT)을 입력으로 받아 비전 모델이 시각적 요소를 분석하고, 언어 모델이 자연어로 대본을 완성하는 전 과정을 보여줍니다. ▼ 아래는 슬라이드(제목, 본문, 그래프 포함)를 비전 모델에 입력하여 자동 발표 대본 생성 성능을 테스트했습니다. 비전 모델의 성능은 매우 인상적이었습니다. 슬라이드의 주제와 배경 맥락을 정확히 이해하고, 본문 핵심 내용을 발표에 적합한 언어로 재구성했을 뿐 아니라, 그래프 요소를 인식하여 자연스럽게 포함시키고 다음 슬라이드와의 연결성까지 고려해 전체 흐름을 매끄럽게 만들었습니다. 이제 대본을 처음부터 작성할 필요 없이 하이퍼클로바X가 제공하는 기본 대본을 활용하여 톤과 길이를 쉽게 조정할 수 있습니다. 백지 상태에서 시작하는 부담을 덜고, 대본 작성부터 예상 질문 준비, 톤 조절까지 효율적인 프레젠테이션 준비가 가능해졌습니다. 4. 외국어 문서의 텍스트 추출/번역/요약을 한 번에 해외 출장 중 현지 파트너로부터 받은 외국어로 된 계약서 부록을 급히 검토해야 하는 상황을 상상해보세요. 수십 페이지에 이르는 법률 용어와 기술 명세로 가득 찬 문서를 마감 시간 내에 이해하고 중요한 변경 사항을 파악해야 합니다. 과거에는 이러한 상황에서 여러 단계의 작업이 필요했습니다. 문서를 스캔하거나 사진으로 찍은 뒤, 텍스트 추출 도구를 사용하고, 번역 프로그램을 통해 번역한 다음, 중요한 내용을 직접 찾아 요약해야 했습니다. 이러한 '문서 획득 → 텍스트 추출 → 번역 → 내용 분석'의 복잡한 과정은 많은 시간을 소모할 뿐만 아니라, 각 단계마다 정보의 정확성이 떨어질 위험이 있었습니다. 그러나 이제 비전 모델 덕분에 이 과정이 획기적으로 간소화되었습니다. 계약서 이미지를 업로드 하면 HCX-005 모델이 텍스트를 정확하게 인식하고, 맥락을 고려하여 번역하며, 중요한 조항과 변경 사항을 효과적으로 요약해 한 번에 제공할 수 있을 것입니다. 시간에 쫓기는 상황에서도 언어 장벽 없이 복잡한 문서의 핵심을 신속하고 정확하게 파악할 수 있게 되었습니다. 숙소 안내문 이미지와 함께 "내용을 정리해줘"라고 요청하면 비전 모델이 정보를 인식하여 체계적으로 구조화된 요약을 제공합니다. 이 기술은 여행 중 마주치는 다양한 공지사항, 음식점 메뉴판, 공공시설 안내문 등을 실시간으로 해석하여 언어 장벽을 효과적으로 해소합니다. 이를 통해 사용자는 낯선 환경에서도 핵심 정보를 신속하게 파악하고 더 나은 여행 경험을 누릴 수 있습니다. 5. 복잡한 표/차트/그래프 분석은 더이상 그만! 이동평균선, 저항선, 추세선, 거래량… 주가 차트를 이해하는 일이 어렵게 느껴지신 적 있으신가요? 각 용어의 정의는 익혔지만, 차트가 전달하는 전체 흐름과 의미를 읽어내는 것은 또 다른 과제였습니다. 특히 여러 보조지표가 한 화면에 겹쳐져 있을 때, 시장이 보내는 신호를 정확히 읽고 해석하는 일은 쉽지 않았을 것입니다. 이제는 비전 모델을 통해 이미지 기반 주식 차트에서도 유의미한 인사이트를 얻을 수 있습니다. 단순한 숫자의 나열을 넘어, 시장 흐름의 핵심 메시지와 변곡점, 그리고 기술적 분석에 기반한 해석까지 도출할 수 있습니다. 이 기술은 주가 차트 분석을 비롯해 논문 내 실험 그래프 자동 요약, 매출/비용 차트의 자동 분석 및 이상 탐지, 그리고 회사 KPI 기반의 대시보드 자동 리포트 생성 등 여러 분야로 확장 가능합니다. 비전 모델을 활용한 분석은 단순한 데이터 인식을 넘어, 다양한 산업에서 의미 있는 의사결정을 자동으로 지원하는 인사이트 도구로 자리잡을 수 있을 것입니다. 6. 학생의 손글씨 시험지 채점, 이제는 비전모델로 학생보다 교사가 더 오래 붙잡고 있어야 했던 시험지, 이제는 AI가 채점합니다 시험이 끝나면 학생들은 자유를 얻지만, 교사에게는 또 다른 업무가 시작됩니다. 특히 수학이나 과학 과목처럼 풀이 과정이 중요한 시험지의 경우, 단순 정답 확인을 넘어 학생의 사고 흐름을 면밀히 검토해야 합니다. 이 과정에서 다양한 글씨체와 표기법 해석, 장시간 집중력 유지의 어려움, 그리고 휴먼 에러로 인한 채점 오류 가능성 등 여러 과제에 직면하게 됩니다. 비전 모델이 이러한 문제들에 실질적인 해결책을 제공합니다. 손글씨 시험지를 이미지로 업로드하면, 비전 언어 모델이 학생의 손글씨를 정확히 인식하고, 대규모 언어 모델이 모범 답안과 비교 분석하여 자동 채점을 완료합니다. 이러한 시스템은 교사의 시간을 절약할 뿐만 아니라, 일관된 평가 기준을 적용해 채점의 공정성과 정확성을 높여줍니다. 이는 교육 현장에서 실질적인 문제를 해결하는 AI 기술의 대표적인 적용 사례가 될 수 있을 것입니다. 시험지 이미지와 정답 이미지를 함께 입력하고 "채점해줘"라고 요청하면 복잡한 개발 과정 없이도 깔끔하게 채점된 결과를 즉시 확인할 수 있어 교육 현장의 실용성이 높습니다. 이 채점 자동화 기술은 칠판 필기 자동 요약, 스마트 학원 시스템, 교사용 학생 관리 리포트 생성, 손글씨 메모 정리 등 다양한 교육 분야로 확장 가능합니다. 7. 비전 모델이 열어가는 제품 마케팅의 새로운 가능성 언어 모델은 마케팅 문구 생성에 혁신적인 변화를 가져왔지만, 제품을 정확히 묘사하기 위해서는 여전히 상세한 설명이 필요했습니다. 제품의 특성, 디자인, 색상, 질감 등을 글로 표현해야만 적절한 마케팅 문구를 얻을 수 있었습니다. 이 과정은 시간이 많이 소요되고 때로는 핵심 특징을 놓치기도 했습니다. 그러나 이제 비전 모델의 등장으로 이러한 한계를 극복할 수 있게 되었습니다. 제품 사진 하나만 업로드하면 비전 모델이 시각적 요소를 분석하고, 제품의 특징을 정확히 파악하여 매력적인 마케팅 문구를 자동으로 생성합니다. 이미지에서 직접 정보를 추출하는 능력 덕분에 마케팅 작업 흐름이 획기적으로 간소화될 것입니다. 이 기술은 단순한 시간 절약을 넘어 제품의 시각적 특성 색상의 미묘한 차이 디자인의 특별한 요소 사용 환경 등을 기반으로 더욱 정확하고 매력적인 카피를 생성합니다. 이 외에도 썸네일 기반 쇼츠 제목 추천, 이메일 제목과 푸시 메시지 자동화, 릴스 스크립트 자동 생성 등으로 다양하게 활용할 수 있어 단시간에 저비용으로 고품질 마케팅 컨텐츠를 생성할 수 있습니다. 마치며 과거에는 불가능하거나 여러 단계를 거쳐야 했던 일들이 많았습니다. 복잡한 문서 구조, 이미지 속 정보, 손글씨, 차트와 같은 비정형 데이터는 자동화의 사각지대에 머물러 있었습니다. 그러나 이제 HCX-005를 통해 이러한 한계가 점차 사라질 것으로 기대됩니다. 더 단순화된 방식으로, 더 빠르고 정확하게, 그리고 무엇보다 현실적인 비용과 품질로 이전에는 시도조차 어려웠던 작업들이 가능해졌습니다. 비전 모델의 등장으로 업무 자동화는 단순 반복 작업을 넘어 이해, 판단, 생성이 필요한 고차원적 영역까지 확장되었습니다. 이는 단순히 기존 기능을 대체하는 도구가 아니라, 산업 전반의 업무 방식을 근본적으로 재정의하고 새로운 가치 창출의 토대가 됩니다. 교육, 마케팅, 행정, 제조, 금융 등 비정형 데이터가 존재하는 다양한 분야에서 이러한 기술의 활용 가능성이 점차 현실화되고 있습니다. 복잡했던 일은 이제 더 이상 복잡하지 않으며, 어렵던 자동화는 누구나 활용할 수 있는 기술이 되었습니다. 비전 모델, HCX-005와 함께 여러분의 비즈니스를 마음껏 성장시켜보세요.
-
안녕하세요, @HongSamToneGold님, 요청하신 내용을 확인해 보니, max_tokens로 요청을 주신 것으로 보입니다. 해당 파라미터명은 지원되지 않기 때문에, 기본값인 100으로 요청이 처리된 것으로 확인됩니다. 가이드 문서에 안내된 것처럼 maxTokens로 요청해 주셔야 하며, 필요에 따라 해당 값을 조정해 주시면 됩니다. 가이드: https://api.ncloud-docs.com/docs/clovastudio-chatcompletions 확인 부탁드립니다. 감사합니다.
-
안녕하세요, @봄애나 님, 고객센터를 통해서 문의 접수해주신 것으로 알고 있습니다. 만약 그렇지 않다면, 보다 정확한 내용 파악을 위해 https://www.ncloud.com/support/question/service 에서 이용 문의를 접수 부탁드립니다. 감사합니다.
-
안녕하세요, @intube님, 클로바 스튜디오에 많은 관심을 가져주셔서 감사합니다. 이미지를 이해하는 비전 모델과 관련 신규 기능 출시를 준비 중에 있습니다. 빠른 시일 내에 업데이트 소식을 전해드릴 수 있도록 하겠습니다. 감사합니다.