CLOVA Studio 운영자 Posted November 26, 2024 공유하기 Posted November 26, 2024 본 Cookbook은 기존 🦜🔗 랭체인(Langchain)으로 Naive RAG 구현하기 cookbook에서 한 단계 더 나아가, 다양한 CLOVA Studio API와 오픈소스 도구들을 활용해 고급 검색 및 생성 기능을 구현하는 방법을 소개합니다 주요 컴포넌트로는 LangChain과 연동되는 bge-m3 기반의 임베딩 v2 API와 Chat Completions API를 중심으로, 토큰 계산기, 문단 나누기 API, 요약 v2 API가 포함되며, 성능 향상을 위해 reranking, summarization, multi-query 등의 고급 모듈들이 추가되었습니다. 전체 파이프라인은 데이터 전처리부터 시작하여 문단 분할, 임베딩 생성, 벡터 DB 구축, 고도화된 검색 로직 구현, 그리고 HyperCLOVA X를 통한 최종 응답 생성까지 체계적으로 구성되어 있습니다. 각 모듈은 독립적으로 설계되어 있어 사용자의 필요에 따라 유연하게 조합할 수 있으며, 이를 통해 더욱 정확하고 맥락에 맞는 응답을 생성할 수 있는 Advanced RAG 시스템을 구축할 수 있습니다. NCP 가이드: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain LangChain 공식 문서: https://python.langchain.com/docs/integrations/providers/naver/ 버전 정보 아래 예제 코드는 Python 3.12.4에서 실행 확인하였으며, 최소 Python3.9를 필요로 합니다. langchain-community >= 0.3.4부터 langchain_community 안에 ChatClovaX, ClovaXEmbeddings가 포함되었습니다. 아래 파일을 참고해 필요한 모듈을 모두 설치해줍니다. requirements.txt 1. 사전 준비 1) Langchain 패키지 설치 아래 파일을 참고해 필요한 모듈을 모두 설치해줍니다. pip install langchain pip install langchain-community~=0.3.4 2) 코드에 공통적으로 들어가는 필요 모듈 import import json import os import subprocess from langchain_community.document_loaders import UnstructuredHTMLLoader from pathlib import Path import http.client from http import HTTPStatus from tqdm import tqdm import time import os import getpass import uuid from uuid import uuid4 3) API Key 및 테스트앱 발급 CLOVA Studio에서 문단 나누기, 임베딩V2, 요약 테스트앱을 미리 발급받습니다. 서비스 앱을 이용하고자 할 경우 사전 설정이 아니라 개별 모듈 정의 시마다 해당 API Key를 입력해야합니다. 따라서 각 모듈 호출 시 필요한 API Key와 App ID를 환경 변수로 미리 저장해두는 것이 좋습니다. Quote # API 키와 Gateway API 키를 넣습니다. os.environ["NCP_CLOVASTUDIO_API_KEY"] = getpass.getpass("NCP CLOVA Studio API Key: ") os.environ["NCP_APIGW_API_KEY"] = getpass.getpass("NCP API Gateway API Key: ") NCP CLOVA Studio API Key: ········ NCP API Gateway API Key: ········ # 문단나누기 테스트앱의 앱 ID를 넣습니다. os.environ["NCP_CLOVASTUDIO_APP_ID_SEGMENTATION"] = input("NCP CLOVA Studio Segmentation App ID: ") NCP CLOVA Studio Segmentation App ID: <your Segmentation App ID> # 임베딩 테스트앱의 앱 ID를 넣습니다. os.environ["NCP_CLOVASTUDIO_APP_ID"] = input("NCP CLOVA Studio App ID: ") NCP CLOVA Studio App ID: <your App ID> # 요약 테스트앱의 앱 ID를 넣습니다. os.environ["NCP_CLOVASTUDIO_APP_ID_SUMMARIZATION"] = input("NCP CLOVA Studio Summarization App ID: ") NCP CLOVA Studio App ID: <your Summarization App ID> 2. 상위 클래스 정의 "CLOVAStudioExecutor"라는 상위 클래스로 각 API의 공통 양식을 묶고, 각 API의 부가적인 로직을 하위 클래스로 추가 정의합니다. 임베딩 V2와 Chat Completions는 랭체인 패키지에서 바로 불러와 클래스 설정이 필요 없습니다. 아래의 두 코드를 실행한 이후에는 모든 코드에서 별도의 클래스 선언 없이, main 코드만 실행하면 됩니다. 또한, CLOVA Studio API들의 기존 파이썬 스펙에서의 클래스 이름을 API의 성질에 맞게 변경했으며, 대응하는 클래스의 이름은 주석으로 확인 가능합니다. CLOVAStudioExecutor Quote import backoff class RateLimitException(Exception): pass class CLOVAStudioExecutor: def __init__(self, host): self._host = host self._api_key = os.environ.get("NCP_CLOVASTUDIO_API_KEY") self._api_key_primary_val = os.environ.get("NCP_APIGW_API_KEY") self._request_id = str(uuid.uuid4()) # Validate required environment variables if not self._api_key: raise ValueError("NCP_CLOVASTUDIO_API_KEY environment variable is not set") if not self._api_key_primary_val: raise ValueError("NCP_APIGW_API_KEY environment variable is not set") def _send_request(self, completion_request, endpoint): headers = { 'Content-Type': 'application/json; charset=utf-8', 'X-NCP-CLOVASTUDIO-API-KEY': self._api_key, 'X-NCP-APIGW-API-KEY': self._api_key_primary_val, 'X-NCP-CLOVASTUDIO-REQUEST-ID': self._request_id } conn = http.client.HTTPSConnection(self._host) conn.request('POST', endpoint, json.dumps(completion_request), headers) response = conn.getresponse() status = response.status result = json.loads(response.read().decode(encoding='utf-8')) conn.close() return result, status @backoff.on_exception(backoff.expo, RateLimitException, max_tries=5, max_time=120, base=10) def execute(self, completion_request, endpoint): res, status = self._send_request(completion_request, endpoint) if status == HTTPStatus.OK: return res, status elif status == HTTPStatus.TOO_MANY_REQUESTS: raise RateLimitException else: raise Exception(f"API Error: {res}, {status}") 개별 클래스 추가 정의 Quote class SegmentationExecutor(CLOVAStudioExecutor): def __init__(self, host): super().__init__(host) self.app_id = os.environ.get("NCP_CLOVASTUDIO_APP_ID_SEGMENTATION") if not self.app_id: raise ValueError("NCP_CLOVASTUDIO_APP_ID_SEGMENTATION environment variable is not set") def execute(self, completion_request): endpoint = f'/testapp/v1/api-tools/segmentation/{self.app_id}' res, status = super().execute(completion_request, endpoint) if status == HTTPStatus.OK and "result" in res: return res["result"]["topicSeg"] else: error_message = res.get("status", {}).get("message", "Unknown error") if isinstance(res, dict) else "Unknown error" raise ValueError(f"오류 발생: HTTP {status}, 메시지: {error_message}") class SummarizationExecutor(CLOVAStudioExecutor): def __init__(self, host): super().__init__(host) self.app_id = os.environ.get("NCP_CLOVASTUDIO_APP_ID_SUMMARIZATION") if not self.app_id: raise ValueError("NCP_CLOVASTUDIO_APP_ID_SUMMARIZATION environment variable is not set") def execute(self, completion_request): endpoint = f'/testapp/v1/api-tools/summarization/v2/{self.app_id}' res, status = super().execute(completion_request, endpoint) if status == HTTPStatus.OK and "result" in res: return res["result"]["text"] else: error_message = res.get("status", {}).get("message", "Unknown error") if isinstance(res, dict) else "Unknown error" raise ValueError(f"오류 발생: HTTP {status}, 메시지: {error_message}") class EmbeddingTokenizerExecutor(CLOVAStudioExecutor): def execute(self, completion_request): endpoint = '/v1/api-tools/embedding/v2/tokenize' res, status = super().execute(completion_request, endpoint) if status == HTTPStatus.OK and "result" in res: return res["result"]["numTokens"] else: error_message = res.get("status", {}).get("message", "Unknown error") if isinstance(res, dict) else "Unknown error" raise ValueError(f"오류 발생: HTTP {status}, 메시지: {error_message}") 3. Raw Data → Connecting 🦜🔗 랭체인(Langchain)으로 Naive RAG 구현하기 cookbook에서 거쳤던 동일한 과정으로, 아래와 같이 진행됩니다. 1. txt 파일에 데이터로 활용할 사이트 주소 작성 2. txt 파일 내 URL을 HTML로 변환 3. mapping 정보가 담긴 json 파일 생성 4. LangChain Document Loader를 활용한 로딩 5. json 파일을 통해 실제 URL로 교체 보다 다양한 데이터를 활용하기 위해 파일에 포함된 가이드 문서를 전체 범위로 넓혔으며, 변경된 txt 파일과 전체 코드는 다음과 같습니다. 1) txt → html 변환 및 원본 사이트 주소 mapping files_path = os.getcwd() url_to_filename_map = {} # ipynb 파일 위치에 files 폴더를 만들어 관련 파일을 일괄 관리합니다. # 위에서 다운받은 clovastudiourl.txt 파일 역시 해당 폴더 안에 위치시켜주세요. folder_path = "files" if not os.path.exists(folder_path): os.makedirs(folder_path) with open(f"{folder_path}/clovastudiourl.txt", "r") as file: urls = [url.strip() for url in file.readlines()] for url in urls: filename = url.split("/")[-1] + ".html" file_path = os.path.join(folder_path+'/clovastudio-guide', filename) subprocess.run(["wget", "--user-agent=RAGCookbook-Crawler/1.0", "-O", file_path, url], check=True) url_to_filename_map[url] = filename with open(f"{folder_path}/url_to_filename_map.json", "w") as map_file: json.dump(url_to_filename_map, map_file) --2024-11-01 00:00:00-- https://guide.ncloud-docs.com/docs/clovastudio-overview guide.ncloud-docs.com (guide.ncloud-docs.com) 해석 중... xxx.xx.x.xxx, xxx.xx.x.xxx 다음으로 연결 중: guide.ncloud-docs.com (guide.ncloud-docs.com)|xxx.xx.x.xxx|:xxx... 연결했습니다. HTTP 요청을 보냈습니다. 응답 기다리는 중... 200 OK 길이: 지정하지 않음 [text/html] 저장 위치: `clovastudio-guide/clovastudio-overview.html' 0K .......... .......... .......... .......... .......... 40.8M 50K .......... .......... .......... . 106M=0.001s (이하 중략) 2) LangChain 활용 HTML 로딩 # 폴더 이름에 맞게 수정 html_files_dir = Path(f'{folder_path}/clovastudio-guide') html_files = list(html_files_dir.glob("*.html")) clovastudiodatas = [] for html_file in html_files: loader = UnstructuredHTMLLoader(str(html_file)) document_data = loader.load() clovastudiodatas.append(document_data) print(f"Processed {html_file}") Processed .../clovastudio-guide/clovastudio-info.html (이하 중략) 3. Json 파일 적용, 실제 URL로 대체 및 후처리 with open("url_to_filename_map.json", "r") as map_file: url_to_filename_map = json.load(map_file) filename_to_url_map = {v: k for k, v in url_to_filename_map.items()} # clovastudiodatas 리스트의 각 Document 객체의 'source' 수정 for doc_list in clovastudiodatas: for doc in doc_list: extracted_filename = doc.metadata["source"].split("/")[-1] if extracted_filename in filename_to_url_map: doc.metadata["source"] = filename_to_url_map[extracted_filename] else: print(f"Warning: {extracted_filename}에 해당하는 URL을 찾을 수 없습니다.") clovastudiodatas_flattened = [item for sublist in clovastudiodatas for item in sublist] 4. Chunking 임베딩 모델이 처리할 수 있는 적당한 크기로 raw data를 나누기 위해 CLOVA Studio의 문단 나누기 API를 활용했습니다. 이 API를 이용하면 문장들 간의 의미 유사도에 기반하여 최적의 청크(chunk) 개수로 문단을 나누고, 추가로 후처리(postProcess=True)를 통해 사용자가 원하는 1개 청크 크기(글자 수)를 설정하여 문단을 나눌 수 있습니다. 자세한 내용은 문단 나누기 API 관련 문서를 참고해주세요. (사용 가이드, API 가이드) segmentation_executor = SegmentationExecutor( host='clovastudio.apigw.ntruss.com' ) chunked_html = [] # 문단으로 나눈 결과와 페이지 번호를 저장할 리스트 for htmldata in tqdm(clovastudiodatas_flattened): request_data = { "text": htmldata.page_content, "alpha": -100, "segCnt": -1, "postProcess": True, "postProcessMaxSize": 1000, "postProcessMinSize": 300 } response_data = segmentation_executor.execute(request_data) for paragraph in response_data: chunked_document = { "source": htmldata.metadata['source'], # 문단의 주소 "text": paragraph # 문단의 텍스트 } chunked_html.append(chunked_document) for item in chunked_html: item['text'] = "".join(item['text']) print(len(chunked_html)) chunked_html[50] chunked_html[50] {'source': 'https://guide.ncloud-docs.com/docs/clovastudio-skillset', 'text': '스킬셋: 스킬셋 이름.영문자, 한글, 숫자, 공백을 허용하며...'} 본 cookbook에서는 alpha와 SegCnt 모두 모델이 알아서 최적값으로 결정하도록 했습니다. 후처리 모듈인 postProcess를 활용했고, postProcessMaxSize와 postProcessMinSize 모두 기본값인 1000자와 300자가 임베딩 v2 API의 처리 한도 내에 들어올 수 있기 때문에 별도로 변경하지 않았습니다. 문단 나누기를 진행할 전체 텍스트의 내용, 기호, 언어등에 따라 약간의 차이는 있을 수 있지만, 모델이 의미 기반으로 문단 나누기를 진행하는 만큼 처리 한도를 초과할 만큼의 큰 chunk를 생성하는 경우는 매우 드뭅니다. 5. Vector DB 1) 리스트 형식의 documents로 만들기 임베딩 처리를 위해 앞서 만든 청크를 Document 객체들의 리스트 형식의 documents로 변환합니다. from langchain_core.documents import Document documents = [] for index, item in enumerate(chunked_html): doc = Document( page_content=str(item['text']), metadata={"source": item['metadata']}, id=str(uuid4()) ) documents.append(doc) 아래 코드를 통해 변환된 documents의 구조를 확인할 수 있습니다. # documents 구조 체크 for i, doc in enumerate(documents): print(f"Document {i}:") print(f" Page Content: {doc.page_content[:100]}...") # 첫 100자만 출력 print(f" Metadata: {doc.metadata}") print(f" Page Content Type: {type(doc.page_content)}") print(f" Metadata Type: {type(doc.metadata)}") print("-" * 40) Document 0: Page Content: 스킬셋: 스킬셋 이름.영문자, 한글, 숫자, 공백을 허용하며 30자 이내로 입력스킬셋 설명: 해당 스킬셋이 제공할 기능에 대한 설명.1,000자 이내로 입력서비스 분야: 생성할 스... Metadata: {'source': 'https://guide.ncloud-docs.com/docs/clovastudio-skillset'} Page Content Type: <class 'str'> Metadata Type: <class 'dict'> ---------------------------------------- ...(이하 중략) 2) Chroma에 임베딩 값 저장하기 본 예제에선 Chroma를 사용합니다. Chroma는 오픈소스 Vector DB이며, 클라우드를 사용하지않고 클라이언트용으로 사용하면 Apache 2.0 라이센스에 무료로 이용할 수 있습니다. 본 예제에서는 chroma를 활용해 컬렉션을 생성하고, 컬렉션에 앞서 만든 문서를 추가해보겠습니다. hnsw:space의 값을 설정함으로써 임베딩 공간의 거리 방법을 사용자 정의할 수 있습니다. 임베딩에 사용할 모델은 유사도 판단을 위해 벡터의 cosine 거리 단위로 사용하므로, 컬렉션 또한 매개변수를 "cosine"으로 설정해주었습니다. *매개변수는 ip, cosine, l2(기본값) 중에 선택할 수 있습니다. 또한, 임베딩 클래스에 오류가 발생시 멈추게끔 하는 로직을 일부 추가해, 다량의 데이터를 처리할 때 오류 발생시 재실행의 부담을 줄였으며, 이에 따라 전체 문서를 처리하는데 약 4~5분 정도 소요될 수 있습니다. LangChain 공식 문서에서 Chroma를 활용하는 자세한 내용을 확인할 수 있습니다. 벡터 DB는 문서의 의미를 담은 임베딩 데이터를 저장하고 유사도 검색을 수행하는 데이터베이스입니다. LangChain과 함께 사용할 수 있는 벡터 DB는 본 예제에서 사용한 Chroma 이외에도 Pinecone, FAISS, Milvus Lite 등 다양한 옵션이 있으며, 개발 환경(로컬/클라우드)과 목적(확장성/관리 용이성)에 따라 적절한 선택이 필요합니다. Langchain 공식 문서를 참고해 사용 목적에 맞는 VectorDB를 선택하세요. (링크) import chromadb from langchain_chroma import Chroma # 임베딩 모델 정의 clovax_embeddings = ClovaXEmbeddings(model='bge-m3') # 로컬 클라이언트 경로 지정 client = chromadb.PersistentClient(path="./chroma_langchain_db") #저장할 로컬 경로 # Chroma 컬렉션 생성 chroma_collection = client.get_or_create_collection( name="clovastudiodatas_docs", #collection이 바뀔때마다 이름도 꼭 변경해줘야 합니다. metadata={"hnsw:space": "cosine"} #사용하는 임베딩 모델에 따라 ‘l2’, 'ip', ‘cosine’ 중에 사용 ) # Chroma 벡터 저장소 생성 vectorstore = Chroma( client=client, collection_name="clovastudiodatas_docs", embedding_function=clovax_embeddings ) # tqdm으로 for 루프 감싸기 for doc in tqdm(documents, desc="Adding documents", total=len(documents)): embeddings = clovax_embeddings.embed_documents([doc.page_content])[0] # 문서 추가 chroma_collection.add( ids=[str(uuid.uuid4())], # 고유한 ID 생성 documents=[doc.page_content], embeddings=[embeddings], metadatas=[doc.metadata] ) time.sleep(1) # 이용량 제어를 고려한 1초 이상의 딜레이, 필요에 따라 조정 가능 print("All documents have been added to the vectorstore.") Adding documents: 100%|██████████| 238/238 [04:55<00:00, 1.24s/it]All documents have been added to the vectorstore. 6. Retrieval → HyperCLOVA X (naive) 랭체인에서 ChatClovaX를 불러와 최종적인 답변을 생성하는 단계입니다. 우선 Advanced RAG 방법론과의 비교를 위해 아래와 같이 Naive RAG 체인을 구성해보았습니다. 사용자의 질문 임베딩 → Vector DB 내에서 유사도 높은 데이터 검색 → HyperCLOVA X에게 전달("context") → 최종적인 답변 생성 이와 같은 기본적인 RAG의 답변 생성 로직을 사전에 정의함으로서 Advanced RAG 방법론을 위한 Retrieval 전/후에 여러 기능 및 모듈을 연결해볼 수 있습니다. (Retrieval 전/후에 연결할 수 있는 부가적인 기능들은 아래의 Advanced module 파트에서 담았습니다.) 1) 답변 생성 Retrieval 정의 및 Chain 구현 답변 생성 함수에 사용된 프롬프트는 다음과 같습니다. # 답변 생성 함수 프롬프트 전문 당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 원래 가지고 있는 지식은 모두 배제하고, 주어진 문맥(context) 만을 참고하여 주어진 질문(question) 에 답하는 것입니다. 검색된 다음 문맥(context) 만을 사용하여 질문(question) 에 답하세요. 만약, 주어진 문맥(context) 에서 답을 찾을 수 없다면, 답을 모른다면 `주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다` 라고 답하세요. from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate from langchain_community.chat_models import ChatClovaX # retriever retriever = vectorstore.as_retriever(kwargs={"k": 3}) # chat모델 정의 chat = ChatClovaX( model="HCX-003", temperature=0.2 ) # ChatPromptTemplate 사용 system_prompt = ( """당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 원래 가지고 있는 지식은 모두 배제하고, 주어진 문맥(context) 만을 참고하여 주어진 질문(question) 에 답하는 것입니다. 검색된 다음 문맥(context) 만을 사용하여 질문(question) 에 답하세요. 만약, 주어진 문맥(context) 에서 답을 찾을 수 없다면, 답을 모른다면 `주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다` 라고 답하세요. """ "\n\n" "{context}" ) prompt = ChatPromptTemplate.from_messages( [ ("system", system_prompt), ("human", "{input}"), ] ) # Built-in chains question_answer_chain = create_stuff_documents_chain(chat, prompt) rag_chain = create_retrieval_chain(retriever, question_answer_chain) result = rag_chain.invoke({"input": "클로바 스튜디오에서 어떤 모델 엔진을 쓸 수 있나요?"}) print("질문:") print(result['input']) print("\n답변:") print(result['answer']) print("\n참조 문서 URL:") unique_urls = set(doc.metadata['source'] for doc in result['context']) for url in unique_urls: print(url) 질문: 클로바 스튜디오에서 어떤 모델 엔진을 쓸 수 있나요? 답변: 클로바 스튜디오에서는 한국어 엔진인 LK-B, LK-D2, 그리고 HyperCLOVA X 엔진인 HCX-003, HCX-DASH-001을 사용할 수 있습니다. 참조 문서 URL: https://guide.ncloud-docs.com/docs/clovastudio-info 7. Advanced module 다음은 Naive RAG와 Advanced RAG의 주요 차별점이 될 수 있는, RAG의 검색 및 답변 정확도를 높이기 위한 몇 가지 방법들입니다. 데이터의 양이 많고 질문이 복잡하거나 모호할수록 retrieval(검색) 전후에 부가적인 기능들을 추가하여 RAG의 완성도를 높일 필요가 있습니다. 이러한 필요성에 따라 관련 방법론들이 활발히 연구되고 있으며, CLOVA Studio가 제공하는 기능들 또는 오픈소스를 통해 연계할 수 있는 대표적인 예시들을 아래에 소개했습니다. 1) Reranking Reranking은 사용자 질문에 대한 검색 결과(reference)의 유사도 순위를 재조정하는 과정입니다. 이는 Vector DB에 저장된 벡터들의 맥락 보존 정도와 검색 성능을 보완하는 추가적인 안전 장치 역할을 합니다. 본 cookbook에선 한국어를 지원하는 reranking 모델 중 무료로 사용할 수 있는 버전인 bge-m3 multilingual reranker를 사용합니다. Bge-m3 multilingual reranker CLOVA Studio의 임베딩 v2 모델의 기반인 bge-m3의 reranker입니다. 이 모델은 HuggingFace 허브에서 제공되며, LangChain HuggingFaceCrossEncoder 클래스를 통해 쉽게 사용할 수 있습니다. LLM 기반이 아닌 bge-m3 embedding 기반의 Reranking을 사용할 경우, rate limit의 제한이 없습니다.아래 코드에서는 학습 데이터셋 업로드를 다루고 있는 문서와 함께 관련 있는 쿼리, 관련이 없는 쿼리에 대해 reranker로 매긴 점수(유사도)를 비교해보면 연관성이 있는 쿼리에서 더 높은 점수를 출력하는 것을 확인할 수 있습니다. 점수가 높을수록 두 텍스트가 의미적으로 더 관련이 있다는 것을 나타냅니다. from langchain_community.cross_encoders import HuggingFaceCrossEncoder # reranker 정의 reranker = HuggingFaceCrossEncoder( model_name='BAAI/bge-reranker-v2-m3', ) # 실행 예시 score_similar = reranker.score([chunked_html[50]['text'], '학습을 위한 데이터셋 업로드 방법']) score_different = reranker.score([chunked_html[50]['text'], '오늘 점심 메뉴']) print(score_similar, score_different) # 유사도 점수 추출 0.82105595 0.13086149 HuggingFaceCrossEncoder는 HuggingFace의 cross encoder 모델들을 사용할 수 있게 해주는 랭체인의 래퍼 클래스입니다. 이 클래스를 통해 문서 쌍의 유사도를 계산할 수 있습니다. model_name으로 'BAAI/bge-reranker-v2-m3'를 지정했는데, 이는 BAAI에서 제공하는 reranking 전용 모델입니다. 기본값인 'BAAI/bge-reranker-base'보다 더 큰 모델을 사용하여 성능이 더 좋은 것으로 알려져 있습니다. 이 함수는 Retrieval 결과인 "context"를 추가로 reranking한 후, HyperCLOVA X에 전달하여 답변을 생성하는 전체 과정을 구현합니다. 기존의 답변 생성 함수인 html_chat_naive에 bge-m3 reranker를 통합한 구조로, 검색 결과의 정확도를 높이고 더 관련성 있는 정보를 기반으로 답변을 생성합니다. from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate from langchain_community.chat_models import ChatClovaX def html_chat(query: str): """RAG 검색 및 응답 생성 함수""" global reference reference = [] # 초기 검색 수행 docs_with_scores = vectorstore.similarity_search_with_score( query, k=10 ) # Reranking 및 점수 저장 (중복 제거 포함) unique_docs = set() reranked_docs = [] for doc, vector_score in docs_with_scores: if doc.page_content not in unique_docs: rerank_score = reranker.score([query, doc.page_content]) reranked_docs.append({ 'document': doc, 'vector_score': vector_score, 'rerank_score': rerank_score }) unique_docs.add(doc.page_content) # Rerank 점수로 정렬하고 상위 3개 선택 top_docs = sorted(reranked_docs, key=lambda x: x['rerank_score'], reverse=True)[:3] # Reference 정보 저장 reference.extend([{ 'distance': 1 - item['vector_score'], 'relevance_score': item['rerank_score'], 'source': item['document'].metadata['source'], 'text': item['document'].page_content } for item in top_docs]) # RAG Chain 설정 및 실행 # chat모델 정의 llm = ChatClovaX( model="HCX-003", max_tokens=200 ) # ChatPromptTemplate 사용 system_prompt = ( """당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 원래 가지고있는 지식은 모두 배제하고, 주어진 문맥(context) 에서 주어진 질문(question) 에 답하는 것입니다. 검색된 다음 문맥(context) 을 사용하여 질문(question) 에 답하세요. 만약, 주어진 문맥(context) 에서 답을 찾을 수 없다면, 답을 모른다면 `주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다` 라고 답하세요. """ "\n\n" "{context}" ) prompt = ChatPromptTemplate.from_messages( [ ("system", system_prompt), ("human", "{input}"), ] ) chain = create_stuff_documents_chain(llm, prompt) # 최종 응답 생성 result = chain.invoke({ "input": query, "context": [item['document'] for item in top_docs] }) return result # 직접 result 반환 답변을 생성할 때마다 reference에 참고한 문서, 문서의 링크, 유사도 점수, 거리가 함께 저장됩니다. 아래 코드를 통해 reference에 저장된 정보를 확인할 수 있습니다. response = html_chat("Maximum tokens 파라미터는 몇으로 설정하는 게 좋을까? 최대값으로 설정했을 떄 무슨 문제가 있을 수 있지?") print(response, "\n") print("-"*10+"Reference"+"-"*10) # reference 확인 for ref in reference: print(f"Source: {ref['source']}") print(f"Distance: {ref['distance']}") print(f"Relevance Score: {ref['relevance_score']}") print(f"Content: {ref['text'][:200]}...") # 처음 200자만 출력 Maximum tokens는 결괏값을 생성할 때 사용할 최대 토큰 수입니다. 프롬프트와 결괏값을 포함하여 일반 모드에서 제공하는 언어 모델인 경우에는 최대 2048 토큰까지, 챗 모드에서 제공하는 HyperCLOVA X 언어 모델인 경우에는 최대 4096 토큰까지 허용됩니다. 일반적으로 Maximum tokens는 300~500을 권장하며 작업에 따라 달라질 수 있습니다. 그러나 이 값을 최대값으로 설정하면 여러 가지 문제가 발생할 수 있습니다. * **예상치 못한 과금**: 너무 길게 설정되면 그만큼 많은 자원이 소모되어 예상보다 많은 비용이 발생할 수 있습니다. * **처리 시간 증가**: 길어질수록 계산해야 하는 데이터 양이 많아지기 때문에 응답 속도가 느려질 수 있습니다. * **요청 미처리**: 이용량 제어 정책의 TPM 최대 이용량 초과로 이어질 수 있어 이로인한 요청 미처리가 더욱 빈번하게 발생할 수 있습니다. ----------Reference---------- Source: https://guide.ncloud-docs.com/docs/clovastudio-info Distance: 0.6760624051094055 Relevance Score: 0.9393323659896851 Content: Top KTop K는 자연어 처리 모델이 예측한 토큰의 선택 확률 분포에서 확률 값이 가장 높은 K개 중에서 하나를 선택할 때 사용하는 기준 값입니다.Top K는 특수한 경우가 아니라면 0으로 설정하는 것을 권장합니다.<예시> Top K=5인 경우, 가장 확률 값이 높은 5개의 토큰 중에서 하나의 토큰이 선택됩니다.이때, 가장 확률 값이 높은 토큰이 선택될... Source: https://guide.ncloud-docs.com/docs/clovastudio-info Distance: 0.6855939626693726 Relevance Score: 0.9207711219787598 Content: Maximum tokens가 실제 필요한 결괏값 토큰 수 대비 과도하게 설정될 경우, 불필요한 출력 길이로 인해 예상치 못한 과금이 발생하거나 처리 시간이 길어질 수 있습니다.... Source: https://guide.ncloud-docs.com/docs/clovastudio-info Distance: 0.6923664808273315 Relevance Score: 0.7897565960884094 Content: Maximum tokensMaximum tokens는 결괏값을 생성할 때 사용할 최대 토큰 수입니다.토큰 수를 높게 설정할 수록 긴 결괏값을 출력합니다.... 기존 retrieval 과정에서는 사용자 질문과 관련도가 높은 10개의 chunk를 추출했습니다. 이후 reranking을 통해 이 중 relevance_score가 가장 높은 상위 3개의 chunk만을 선별하여 HyperCLOVA X에 전달합니다. 실행 화면 속 "reference"에서 relevance_score를 확인할 수 있습니다. 2) Summarization 요약은 retrieval 결과인 reference들의 내용을 압축하여 LLM이 근거 데이터를 쉽게 참고할 수 있게 돕습니다. 이는 Multi-query로 생성된 여러 질문들의 reference나 원본 질문만으로 구성된 naive RAG에서도 유용하며, 질문에 대한 근거의 맥락을 강화합니다. Reference가 복잡하거나 그 수가 많을 때, 요약을 통해 압축된 맥락을 전달하거나 부족한 설명을 보충할 수 있습니다. CLOVA Studio는 두 가지 요약 API를 제공하여 목적에 맞게 선택해 RAG의 정확도를 높일 수 있습니다. 이 cookbook에서는 긴 문장 요약에 강점이 있는 요약 v2 API를 활용했습니다. 요약 V2 함수 정의 이 코드는 주어진 쿼리로 검색된 결과물들의 참조 텍스트를 각각 요약하는 함수입니다. 중복된 텍스트는 건너뛰고, 각 텍스트는 설정된 크기로 분할되어 요약되며, 요약 실패 시 에러 처리를 하고 5초 후 다음 작업을 진행합니다. 이 함수는 단독으로 실행하지 않고, 뒤에 설명할 Multi-query 기능과 함께 실행할 예정입니다. 요약 v2 실행 결과, reference의 'text'를 요약한 내용을 'summary' 객체에 저장하고 final_references에 추가합니다. def summarize_each_ref(self, realquery): combined_results = self.retrieval(realquery) final_references = [] seen_texts = set() # 중복을 확인하기 위한 집합 for result in combined_results: for reference in result['references']: if reference['text'] not in seen_texts: seen_texts.add(reference['text']) try: summary_request = { "texts": [reference['text']], "autoSentenceSplitter": True, "segCount": -1, "segMaxSize": 200, "segMinSize": 50, "includeAiFilters": False } summarized_text = self.summarization_executor.execute(summary_request) if summarized_text is None or 'Error' in summarized_text: raise ValueError("요약 실패") final_references.append({ 'query': result['query'], 'text': reference['text'], 'summary': summarized_text, 'source': reference['source'] }) except Exception as e: print(f"요약 에러: {reference['text']}, 오류: {str(e)}") time.sleep(5) return final_references summarize_each_ref() 함수는 단독으로 실행되는 것이 아닌 다음 목차에서 설명될 Multi-query를 연계해서 만든 Multiquery(mq) 클래스에 속한 함수입니다. 따라서 아래의 실행 결과도 클래스에 속한 함수의 실행 결과이며 예제 코드의 들여쓰기도 클래스 내부에 있기 때문에 존재하는 것입니다. "summarization_executor"는 아래 목차의 Multiquery(mq)클래스에 정의되어 있습니다. 요약 v2 API의 파라미터 설정은 클로바스튜디오 내 익스플로러에 상세히 기재되어 있습니다. 3) Multi-Query Multi-query는 사용자의 원래 질문 의미를 유지하면서 유사한 질문들을 생성하고, 각 질문에 대해 병렬적으로 retrieval을 수행합니다. 이후 모든 유사 query의 retrieval 결과를 종합하여 LLM에 전달하고, 원본 질문에 답변하도록 합니다. 이 방법은 데이터양이 방대하거나 질문이 복잡하고 모호한 경우, 단일 질문만으로는 사용자의 의도에 맞는 retrieval이 어려울 때 정확도를 높이기 위한 맥락 강화 기법입니다. 이번 cookbook에서는 비용 효율적이고 적절한 성능을 보장하는 HCX-DASH-001 모델을 Chat Completion API를 통해 multi-query 생성기로 활용하며, Langchain의 MultiQueryRetriever 컴포넌트를 활용해 구현합니다. MultiQuery Retriever는 사용자의 하나의 질문을 LLM이 여러 관점의 질문들로 자동 확장해주는 도구입니다. 각각의 확장된 질문에 대해 문서를 검색하고 그 결과들을 합쳐서, 더 포괄적이고 정확한 답변을 제공할 수 있게 해줍니다. Multi Query Retriever 정의 생성하고 싶은 질문의 개수는 프롬프트를 자유롭게 구성해 사용자가 직접 정할 수 있습니다. 본 예제에서는 system 프롬프트로 AI에게 paraphrasing 지침을 주고 다섯가지 버전의 질문을 생성하도록 했습니다. 또한 응답에서 각 질문을 리스트로 변환하기 쉽도록 줄바꿈으로 구분하도록 합니다. Multiquery 생성 시스템 프롬프트 전문 주어진 사용자 질문의 다섯 가지 버전을 생성하는 AI입니다. 사용자의 질문을 paraphrasing해서 질문의 의도와 의미가 동일한 새로운 질문을 만들어냅니다. 질문 속 핵심 단어는 유지하고 조사나 수식어와 같은 부가적인 표현을 paraphrasing합니다. 응답은 새 줄로 구분된 값의 목록이어야 합니다(예: 'foo\nbar\nbaz\n'). #사용자 질문: {question} from langchain_core.runnables import RunnablePassthrough from langchain_core.prompts import PromptTemplate from langchain_core.output_parsers import StrOutputParser # 프롬프트 템플릿 prompt = PromptTemplate.from_template( """주어진 사용자 질문의 다섯 가지 버전을 생성하는 AI입니다. 사용자의 질문을 paraphrasing해서 질문의 의도와 의미가 동일한 새로운 질문을 만들어냅니다. 질문 속 핵심 단어는 유지하고 조사나 수식어와 같은 부가적인 표현을 paraphrasing합니다. 응답은 새 줄로 구분된 값의 목록이어야 합니다(예: 'foo\nbar\nbaz\n'). #사용자 질문: {question} """ ) # chat 모델 llm = ChatClovaX( model="HCX-DASH-001" ) # LLMChain custom_multiquery_chain = ( {"question": RunnablePassthrough()} | prompt | llm | StrOutputParser() ) # 질문 question = "토큰이 뭔가요?" # 체인을 실행하여 생성된 다중 쿼리를 확인합니다. multi_queries = custom_multiquery_chain.invoke(question) # 파싱을 위한 처리 queries_list = multi_queries.strip().split('\n') # 숫자와 점, 공백 제거 queries_list = [q.split('. ', 1)[1] if '. ' in q else q for q in queries_list] print(queries_list) 위 코드를 실행하면, 아래와 같이 5개의 다른 질문을 리스트 형식으로 출력해 볼 수 있습니다. ['토큰이란 무엇인가요?', '용어로서의 토큰에 대해 알려주세요.', '토큰이라는 개념에 대해 설명해주세요.', '토큰 정의에 대해 알고 싶습니다.', '토큰의 뜻이 궁금합니다.'] Multiquery 클래스 정의 Multi-query module을 기반으로 생성된 여러 질문에 대한 retrieval 결과를 요약 v2나 reranker와 연계할 수 있도록 모든 모듈을 하나의 클래스에 통합했습니다. 이를 통해 필요한 module들을 선택적으로 조합하여 RAG를 구성할 수 있습니다. 클래스 내 주요 함수는 다음과 같습니다. multiquery_generator() : HCX-DASH-001을 활용해 원본 질문과 유사한 질문 생성 retrieval() : html_chat_raw를 기반으로 여러 유사 질문에 대해 개별 검색 수행 rerank_diff() : bge-m3 기반 reranker를 사용해 retrieval 결과 재정렬 summarize_each_ref() : 요약 v2 API를 사용해 reference 요약 answer() : Chat Completion API를 활용해 여러 모듈의 결과를 참고하여 최종 답변 생성 from langchain_core.runnables import RunnablePassthrough from langchain_core.prompts import PromptTemplate, ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_community.chat_models import ChatClovaX from langchain_core.documents import Document import time from typing import List, Dict, Any, Optional class MultiqueryRetrieval: def __init__( self, vectorstore, reranker, summarization_executor, multiquery_model: str = "HCX-DASH-001", answer_model: str = "HCX-003" ) : self.vectorstore = vectorstore self.reranker = reranker self.summarization_executor = summarization_executor self.multiquery_model = multiquery_model self.answer_model = answer_model def multiquery_generator(self, question: str) -> List[str]: """원본 질문으로부터 다중 쿼리를 생성합니다.""" prompt = PromptTemplate.from_template( """주어진 사용자 질문의 세가지 버전을 생성하는 AI입니다. 사용자의 질문을 paraphrasing해서 질문의 의도와 의미가 동일한 새로운 질문을 만들어냅니다. 질문 속 핵심 단어는 유지하고 조사나 수식어와 같은 부가적인 표현을 paraphrasing합니다. 응답은 새 줄로 구분된 값의 목록이어야 합니다(예: 'foo\\nbar\\nbaz\\n'). #사용자 질문: {question} """ ) llm = ChatClovaX(model=self.multiquery_model) # LLMChain 생성 custom_multiquery_chain = ( {"question": RunnablePassthrough()} | prompt | llm | StrOutputParser() ) # 체인 실행 multi_queries = custom_multiquery_chain.invoke(question) # 결과 파싱 queries_list = multi_queries.strip().split('\n') # 숫자와 점, 공백 제거 queries_list = [q.split('. ', 1)[1] if '. ' in q else q for q in queries_list] return queries_list def html_chat_raw(self, realquery: str, k: int = 10) : """단일 쿼리에 대한 검색을 수행합니다.""" # 초기 검색 수행 docs_with_scores = self.vectorstore.similarity_search_with_score( realquery, k=k ) # Reranking 및 점수 저장 reranked_docs = [] for doc, vector_score in docs_with_scores: rerank_score = self.reranker.score([realquery, doc.page_content]) reranked_docs.append({ 'document': doc, 'vector_score': vector_score, 'rerank_score': rerank_score }) # Rerank 점수로 정렬하고 상위 3개 선택 top_docs = sorted(reranked_docs, key=lambda x: x['rerank_score'], reverse=True)[:3] # Reference 정보 반환 references = [{ 'distance': 1 - item['vector_score'], 'relevance_score': item['rerank_score'], 'source': item['document'].metadata['source'], 'text': item['document'].page_content } for item in top_docs] return references def retrieval(self, realquery: str) -> List[Dict]: """각 쿼리에 대한 검색을 수행합니다.""" similar_queries = self.multiquery_generator(realquery) all_results = [] for query in similar_queries: references = self.html_chat_raw(query) all_results.append({ 'query': query, 'references': references }) return all_results def rerank_diff(self, realquery: str, combined_results: List[Dict]) -> List[Dict]: """중복을 제거하는 reranking을 수행합니다.""" all_references = [] for result in combined_results: all_references.extend(result['references']) for reference in all_references: score = self.reranker.score( [realquery, reference['text']] ) reference['relevance_score'] = score sorted_references = sorted( all_references, key=lambda x: x['relevance_score'], reverse=True ) final_references = [] added_texts = set() for reference in sorted_references: if reference['text'] not in added_texts: final_references.append(reference) added_texts.add(reference['text']) if len(final_references) == 3: break return final_references def summarize_each_ref(self, realquery: str) -> List[Dict]: """중복이 제거된 참조 문서들을 요약합니다.""" combined_results = self.retrieval(realquery) final_references = [] seen_texts = set() for result in combined_results: for reference in result['references']: if reference['text'] not in seen_texts: seen_texts.add(reference['text']) try: # API 스펙에 맞게 요청 데이터 구성 summary_request = { "texts": [reference['text']], # texts는 배열이어야 함 "autoSentenceSplitter": True, "segCount": -1 } summarized_text = self.summarization_executor.execute(summary_request) if summarized_text is None: raise ValueError("요약 실패") final_references.append({ 'query': result['query'], 'text': reference['text'], 'summary': summarized_text, 'source': reference['source'] }) except Exception as e: print(f"요약 에러: {reference['text']}, 오류: {str(e)}") time.sleep(5) return final_references def answer(self, realquery: str, final_references: List[Dict]) -> str: """최종 답변을 생성합니다.""" # chat 모델 정의 llm = ChatClovaX(model=self.answer_model) # ChatPromptTemplate 사용 system_prompt = """당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 원래 가지고있는 지식은 모두 배제하고, 주어진 문맥(context)에서 주어진 질문(question)에 답하는 것입니다. 검색된 다음 문맥(context)을 사용하여 질문(question)에 답하세요. 만약, 주어진 문맥(context)에서 답을 찾을 수 없다면, '주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다'라고 답하세요. \n\n{context}""" prompt = ChatPromptTemplate.from_messages([ ("system", system_prompt), ("human", "{input}") ]) # Chain 생성 chain = create_stuff_documents_chain(llm, prompt) # Document 객체 생성을 위한 컨텍스트 준비 context_docs = [ Document( page_content=ref.get('summary', ref['text']), metadata={'source': ref['source']} ) for ref in final_references ] # 최종 응답 생성 result = chain.invoke({ "input": realquery, "context": context_docs }) return result['answer'] if isinstance(result, dict) else result 8. Module 실행 예시 앞서 Multiquery 클래스를 통해 정의한 유사 질문 생성, 요약, reranking 모듈들을 엮어서 어떻게 활용할 수 있는지 예시를 통해 살펴보겠습니다. 1) Multi-query 생성 → bge-m3 reranker → 답변 retrieval()을 통해 realquery에 대한 유사 질문들을 생성하고 이에 대한 개별 retrieval을 진행 각 유사 질문에 대한 reference를 realquery에 대해 bge-m3 기반 reranking 진행 최종적으로 답변 생성 # 초기화 mq = MultiqueryRetrieval( vectorstore=vectorstore, reranker = HuggingFaceCrossEncoder(model_name='BAAI/bge-reranker-v2-m3'), summarization_executor = SummarizationExecutor( host='clovastudio.apigw.ntruss.com' ) ) # 실행 query = "클로바 스튜디오와 랭체인을 연동하여 사용할 수 있나요?" combined_results = mq.retrieval(query) final_references = mq.rerank_diff(query, combined_results) final_answer = mq.answer(query, final_references) print(final_answer) print("-"*10+"Reference"+"-"*10) for reference in final_references: print(f"Source: {reference['source']}") print(f"Content: {reference['text']}") 네, CLOVA Studio의 HyperCLOVA X 모델과 임베딩 도구를 손쉽게 연동하여 사용하기 위해 LangChain을 활용할 수 있습니다. LangChain은 언어 모델 기반 애플리케이션 개발을 지원하는 오픈소스 프레임워크로, HyperCLOVA X를 포함한 여러 언어 모델과 벡터 데이터베이스, 검색 엔진 등의 여러 도구를 사슬(Chain)처럼 엮어 연결할 수 있어 기능 간 연결 및 통합 개발 과정을 간소화할 수 있습니다. Quote ----------Reference---------- Source: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Content: LangChain 연동인쇄공유PDF기사 요약이 요약이 도움이 되었나요?의견을 보내 주셔서 감사합니다.Classic/VPC 환경에서 이용 가능합니다.CLOVA Studio의 HyperCLOVA X 모델과 임베딩 도구를 손쉽게 연동하여 사용하기 위해 LangChain을 활용할 수 있습니다.LangChain은 언어 모델 기반 애플리케이션 개발을 지원하는 오픈소스 프레임워크입니다.HyperCLOVA X를 포함한 여러 언어 모델과 벡터 데이터베이스, 검색 엔진 등의 여러 도구를 사슬(Chain)처럼 엮어 연결할 수 있어 기능 간 연결 및 통합 개발 과정을 간소화할 수 있습니다.따라서 CLOVA Studio를 서드 파티 모델 및 도구와 함께 이용할 경우, LangChain을 연동하여 좀 더 간편한 애플리케이션 개발이 가능합니다.LangChain 연동 가이드에서는 LangChain 설치 방법과 CLOVA Studio 연동 설정 방법을 설명합니다.또한 LangChain을 통해 CLOVA Studio의 HyperCLOVA X 모델과 임베딩 도구를 이용하는 예제 코드를 제공하여 실제 개발에 참고할 수 있도록 안내합니다.참고LangChain은 Python 또는 JavaScript 및 TypeScript 언어로 구현되어 있습니다.CLOVA Studio에서는 Python 기반의 LangChain을 지원하며, 이 가이드 역시 Python을 기준으로 설명합니다.LangChain은 LangChain Inc.의 상표입니다.상표의 권리는 LangChain Inc.에 있습니다.네이버클라우드는 이 가이드에서 참조 목적으로만 사용하며, 이는 LangChain과 네이버클라우드 간 후원, 보증, 제휴를 의미하지 않습니다.LangChain은 오픈 소스 소프트웨어로서 네이버클라우드는 LangChain의 품질, 성능을 보증하거나 책임지지 않습니다.LangChain에 대한 자세한 설명은 공식 문서를 참조해 주십시오.LangChain 설치 및 확인 Source: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Content: CLOVA Studio에 연동하여 LangChain을 사용하려면 버전 3.9 이상의 Python 설치가 필요합니다.Python 설치를 완료한 후에는 다음 명령어를 사용하여 LangChain을 설치한 후 연동에 필요한 langchain-community 패키지를 설치해 주십시오.pip install langchain # install LangChainpip install langchain-community # install langchain-community package설치되어 있는 LangChain이 CLOVA Studio와 연동 가능한 버전인지 확인하려면 다음 명령어를 사용해 주십시오.pip show langchain-community버전 확인 결과 langchain-community 패키지 버전이 0.3.3 이하인 경우에는 다음과 같이 연동 가능한 LangChain 버전을 명시하여 설치하는 것이 필요할 수 있습니다.pip install langchain-community~=0.3.4연동 범위 확인LangChain을 통해 이용 가능한 CLOVA Studio의 기능은 다음과 같습니다.CLOVA Studio 플레이그라운드 메뉴의 챗 모드 모델모델: 기본 모델(<예시> HCX-003), 기본 모델을 튜닝한 모델연관 API: Chat Completions연동 예제: HyperCLOVA X 모델 이용 Source: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Content: single_vector = embeddings.embed_query(query)embed_documentstext1 = "CLOVA Studio는 HyperCLOVA X 언어 모델을 활용하여 AI 서비스를 손쉽게 만들 수 있는 개발 도구입니다."text2 = "LangChain은 언어 모델 기반 애플리케이션 개발을 지원하는 오픈소스 프레임워크입니다."document = [text1, text2]multiple_vector = embeddings.embed_documents(document)참고LangChain을 통해 CLOVA Studio의 임베딩(임베딩 v2) 도구를 이용하는 방법에 대한 자세한 설명은 공식 문서를 참조해 주십시오. (이하 중략) 2) Multi-query 생성 → 요약 → 답변 summarize_each_ref()를 통해 realquery에 대한 유사 질문들을 생성, 개별 retrieval 진행 후 각 retrieval 내용 요약 'summary'가 추가된 final_references를 바탕으로 답변 생성 # 초기화 mq = MultiqueryRetrieval( vectorstore=vectorstore, reranker = HuggingFaceCrossEncoder(model_name='BAAI/bge-reranker-v2-m3'), summarization_executor = SummarizationExecutor( host='clovastudio.apigw.ntruss.com' ) ) # 실행 query = "클로바 스튜디오와 랭체인을 연동하여 사용할 수 있나요?" combined_results = mq.retrieval(query) final_references = mq.rerank_diff(query, combined_results) final_answer = mq.answer(query, final_references) print(final_answer) print("-"*10+"Reference"+"-"*10) for reference in final_references: print(f"Source: {reference['source']}") print(f"Content: {reference['text']}") 네, CLOVA Studio의 HyperCLOVA X 모델과 임베딩 도구를 손쉽게 연동하여 사용하기 위해 LangChain을 활용할 수 있습니다. LangChain은 언어 모델 기반 애플리케이션 개발을 지원하는 오픈소스 프레임워크로, CLOVA Studio를 서드 파티 모델 및 도구와 함께 이용 할 경우 LangChain을 연동하여 좀 더 간편한 애플리케이션 개발이 가능합니다. Quote ----------Reference---------- Source: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Content: LangChain 연동인쇄공유PDF기사 요약이 요약이 도움이 되었나요?의견을 보내 주셔서 감사합니다.Classic/VPC 환경에서 이용 가능합니다.CLOVA Studio의 HyperCLOVA X 모델과 임베딩 도구를 손쉽게 연동하여 사용하기 위해 LangChain을 활용할 수 있습니다.LangChain은 언어 모델 기반 애플리케이션 개발을 지원하는 오픈소스 프레임워크입니다.HyperCLOVA X를 포함한 여러 언어 모델과 벡터 데이터베이스, 검색 엔진 등의 여러 도구를 사슬(Chain)처럼 엮어 연결할 수 있어 기능 간 연결 및 통합 개발 과정을 간소화할 수 있습니다.따라서 CLOVA Studio를 서드 파티 모델 및 도구와 함께 이용할 경우, LangChain을 연동하여 좀 더 간편한 애플리케이션 개발이 가능합니다.LangChain 연동 가이드에서는 LangChain 설치 방법과 CLOVA Studio 연동 설정 방법을 설명합니다.또한 LangChain을 통해 CLOVA Studio의 HyperCLOVA X 모델과 임베딩 도구를 이용하는 예제 코드를 제공하여 실제 개발에 참고할 수 있도록 안내합니다.참고LangChain은 Python 또는 JavaScript 및 TypeScript 언어로 구현되어 있습니다.CLOVA Studio에서는 Python 기반의 LangChain을 지원하며, 이 가이드 역시 Python을 기준으로 설명합니다.LangChain은 LangChain Inc.의 상표입니다.상표의 권리는 LangChain Inc.에 있습니다.네이버클라우드는 이 가이드에서 참조 목적으로만 사용하며, 이는 LangChain과 네이버클라우드 간 후원, 보증, 제휴를 의미하지 않습니다.LangChain은 오픈 소스 소프트웨어로서 네이버클라우드는 LangChain의 품질, 성능을 보증하거나 책임지지 않습니다.LangChain에 대한 자세한 설명은 공식 문서를 참조해 주십시오.LangChain 설치 및 확인 Source: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Content: CLOVA Studio에 연동하여 LangChain을 사용하려면 버전 3.9 이상의 Python 설치가 필요합니다.Python 설치를 완료한 후에는 다음 명령어를 사용하여 LangChain을 설치한 후 연동에 필요한 langchain-community 패키지를 설치해 주십시오.pip install langchain # install LangChainpip install langchain-community # install langchain-community package설치되어 있는 LangChain이 CLOVA Studio와 연동 가능한 버전인지 확인하려면 다음 명령어를 사용해 주십시오.pip show langchain-community버전 확인 결과 langchain-community 패키지 버전이 0.3.3 이하인 경우에는 다음과 같이 연동 가능한 LangChain 버전을 명시하여 설치하는 것이 필요할 수 있습니다.pip install langchain-community~=0.3.4연동 범위 확인LangChain을 통해 이용 가능한 CLOVA Studio의 기능은 다음과 같습니다.CLOVA Studio 플레이그라운드 메뉴의 챗 모드 모델모델: 기본 모델(<예시> HCX-003), 기본 모델을 튜닝한 모델연관 API: Chat Completions연동 예제: HyperCLOVA X 모델 이용 Source: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain Content: single_vector = embeddings.embed_query(query)embed_documentstext1 = "CLOVA Studio는 HyperCLOVA X 언어 모델을 활용하여 AI 서비스를 손쉽게 만들 수 있는 개발 도구입니다."text2 = "LangChain은 언어 모델 기반 애플리케이션 개발을 지원하는 오픈소스 프레임워크입니다."document = [text1, text2]multiple_vector = embeddings.embed_documents(document)참고LangChain을 통해 CLOVA Studio의 임베딩(임베딩 v2) 도구를 이용하는 방법에 대한 자세한 설명은 공식 문서를 참조해 주십시오. (이하 중략) 9. 맺음말 기존의 cookbook이 CLOVA Studio를 활용한 기본적인 naive RAG 구현에 초점을 맞췄다면, 이번 cookbook은 CLOVA Studio의 신규 API들과 오픈소스를 이용한 Advanced RAG 구현법을 안내합니다. 각 API로 개발된 기능들을 모듈화하여 필요에 따라 선별적으로 활용함으로써, 용도에 부합하는 효과적인 RAG 시스템을 구성할 수 있습니다. 본 cookbook에서는 기초적인 모듈들만 다루었지만, RAG의 성능을 끌어올리기 위한 보다 복잡하고 다채로운 방법론들이 활발히 연구되고 있다는 점을 참고해 주시기 바랍니다. NCP 가이드: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain LangChain 공식 문서: https://python.langchain.com/docs/integrations/providers/naver/ 1 링크 복사 다른 사이트에 공유하기 More sharing options...
Recommended Posts
게시글 및 댓글을 작성하려면 로그인 해주세요.
로그인