CLOVA Studio ์ด์์ Posted November 8 ๊ณต์ ํ๊ธฐ Posted November 8 ๋ณธ ๊ฐ์ด๋๋ ํด๋ก๋ฐ ์คํ๋์ค(CLOVA Studio)์ ๋ญ์ฒด์ธ(Langchain)์ ์ด์ฉํด RAG(Retrieval Augmented Generation; ๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์์คํ ์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค. NCP ๊ฐ์ด๋: https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain LangChain ๊ณต์ ๋ฌธ์: https://python.langchain.com/docs/integrations/providers/naver/ RAG๋ AI๊ฐ ์ฃผ์ด์ง ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ๋ ์ ํํ๊ณ ๊ด๋ จ์ฑ ๋์ ๋ต๋ณ์ ์์ฑํ๋๋ก ๋๋ ๊ธฐ์ ์ ๋๋ค. ์ด ์์ ์์ ์ฐ๋ฆฌ๋ HTML ํ์์ ๋ฐ์ดํฐ(ํด๋ก๋ฐ ์คํ๋์ค ๊ฐ์ด๋)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ ์ถ๋ ฅํ๋ RAG ์์คํ ์ ๋ญ์ฒด์ธ์ ํ์ฉํด ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค.ย ๊ตฌํํ๊ณ ์ ํ๋ RAG ์์คํ ์ ๊ตฌ์กฐ๋๋ ์๋์ ๊ฐ์ต๋๋ค. ํด๋ก๋ฐ ์คํ๋์ค์ HyperCLOVA X ๋ชจ๋ธ (์ฑ ๋ชจ๋), ์๋ฒ ๋ฉ API, ๋ฌธ๋จ ๋๋๊ธฐ API๋ฅผ ์ฌ์ฉํ๋ฉฐ, ๋ญ์ฒด์ธ์ ํตํด ์๋์ ๊ฐ์ ๋จ๊ณ๋ก ์งํํด ๊ฐ๋จํ RAG ์์คํ ์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค. ย ๋ฒ์ ์ ๋ณด ์๋ ์์ ์ฝ๋๋ Python 3.12.4์์ ์คํ ํ์ธํ์์ผ๋ฉฐ, ์ต์ Python3.9๋ฅผ ํ์๋ก ํฉ๋๋ค.ย ์๋ ํ์ผ์ ์ฐธ๊ณ ํด ํ์ํ ๋ชจ๋์ ๋ชจ๋ ์ค์นํด์ค๋๋ค. requirements.txt ย 1. ์ฌ์ ์ค๋น 1)ย Langchain ํจํค์ง ์ค์น langchain-community >= 0.3.4๋ถํฐ langchain_community ์์ ChatClovaX, ClovaXEmbeddings๊ฐ ํฌํจ๋์์ต๋๋ค.ย ๋ญ์ฒด์ธ์ ์๋ ๋ช ๋ น๋ฌธ์ ํตํด ์ค์นํ ์ ์์ต๋๋ค.ย pip install langchain pip install langchain-community~=0.3.4 ย 2) ์ฐธ์กฐํ ๋ฌธ์ (HTML ๋ฐ์ดํฐ) ์ค๋น ๋ณธ ์์ ์์๋ ๋ค์ด๋ฒํด๋ผ์ฐ๋ํ๋ซํผ(NCP)์ ํด๋ก๋ฐ ์คํ๋์ค ์ฌ์ฉ ๊ฐ์ด๋์คย CLOVA Studio ๊ฐ๋ ,ย CLOVA Studio ์๋๋ฆฌ์คย ํ์ด์ง๋ฅผ HTML ๋ฐ์ดํฐ๋ก ํ์ฉํฉ๋๋ค. ์ฐธ๊ณ ํ ์น์ฌ์ดํธ์ ๋งํฌ๋ฅผ ์๋์ ๊ฐ์ด txt ํ์ผ๋ก ์ค๋นํ์ผ๋ฉฐ, ํด๋น ๋ด์ฉ์ ํ์ํ ๋ฐ์ดํฐ์ ๋ง๊ฒ ์์ ๋์ด๋ ๋ฌด๋ฐฉํฉ๋๋ค. (์ฃผ์)ย ย txtํ์ผ์ ์์ฑํ ๋๋ ํ ์ค์ ํ๋์ URL์ ์์ฑํด์ผ ํฉ๋๋ค. ์ฆ, ๊ฐ URL์ ์ค๋ฐ๊ฟ์ผ๋ก ๊ตฌ๋ถ๋์ด์ผ ํฉ๋๋ค. https://guide.ncloud-docs.com/docs/clovastudio-info https://guide.ncloud-docs.com/docs/clovastudio-procedure ย 3) ์ฝ๋์ ๊ณตํต์ ์ผ๋ก ๋ค์ด๊ฐ๋ ํ์ ๋ชจ๋ import importย json importย getpass importย os fromย tqdmย importย tqdm importย requests importย time importย uuid fromย uuidย importย uuid4 fromย pathlibย importย Path ย 4) ํ ์คํธ์ฑ ๋ฐ APIํค ๋ฏธ๋ฆฌ ๋ฐ๊ธ ๋ฐ๊ธฐ ๊ฐ ๋ชจ๋ ํธ์ถ์ ํ์ํ ํ ์คํธ์ฑ ๋ฐ APIํค๋ฅผ ๋ฏธ๋ฆฌ ๋ฐ๊ธ๋ฐ๊ณ ํ๊ฒฝ ๋ณ์๋ก ์ ์ฅํด๋์ธ์. Quote ํค ๊ฐ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ (ํด๋ก๋ฐ ์คํ๋์ค ์ฑ ์ ์ฒญ ํํฉ ํ์ด์ง) 1.APIํค, Gatewayํค ์ค์ ํ๊ธฐ ํ ์คํธ ์ฑ์ ์ด์ฉํ๋ ๊ฒฝ์ฐ, APIํค์ Gatewayํค๋ ๊ณ์ ๋น ๋ฐ๊ธ๋๊ธฐ ๋๋ฌธ์ ์ด๋ค ํ ์คํธ์ฑ์ผ๋ก ๋ฐ๊ธ๋ฐ์๋ ํค ๊ฐ์ด ๋์ผํฉ๋๋ค. ๋ณธ ์์ ์์ ํ ์คํธ ์ฑ์ ์ฌ์ฉํ๋ฏ๋ก API ํค์ Gateway ํค๋ฅผ ์ฌ์ ๋ฐ๊ธ๋ฐ์ ์ ์ํด๋๊ณ , ๊ฐ ๋ชจ๋ ํธ์ถ์ ๋ถ๋ฌ์ค๊ฒ ์ต๋๋ค.ย ๋จ, ์ฑ์ API Key/API GW Key๊ฐย ์ ๋ถ ๋์ผํ ๊ฑด ํ ์คํธ์ฑ๋ง ํด๋น๋ฉ๋๋ค.ย ์๋น์ค ์ฑ์ ์ด์ฉํ๊ณ ์ ํ ๊ฒฝ์ฐ ์ฌ์ ์ค์ ์ด ์๋๋ผ ๊ฐ๋ณ ๋ชจ๋ ์ ์ ์๋ง๋ค ํด๋น API Key๋ฅผ ์ ๋ ฅํด์ผํฉ๋๋ค. NCP_CLOVASTUDIO_API_KEY NCP_APIGW_API_KEY ย 2.๋ฌธ๋จ๋๋๊ธฐ ํ ์คํธ ์ฑ ๋ฐ๊ธ๋ฐ๊ณ , app_id ๊ฐ์ ์ค์ ํ๊ธฐ (ClovaStudio > ์ต์คํ๋ก๋ฌ > ๋ฌธ๋จ ๋๋๊ธฐ > ํ ์คํธ์ฑ ๋ฐ๊ธ) NCP_CLOVASTUDIO_APP_ID_SEGMENTATION 3. ์๋ฒ ๋ฉV2 ํ ์คํธ์ฑ ๋ฐ๊ธ๋ฐ๊ณ ,ย app_id ๊ฐ์ ์ค์ ํ๊ธฐ (ClovaStudio > ์ต์คํ๋ก๋ฌ > ์๋ฒ ๋ฉV2 > ํ ์คํธ์ฑ ๋ฐ๊ธ) *์๋ฒ ๋ฉ ๋ชจ๋ธ emb,sts๋ฅผ ์ฐ๋๊ฒฝ์ฐ V1์ผ๋ก ๋ฐ๊ธ ๋ฐ์์ผํฉ๋๋ค. NCP_CLOVASTUDIO_APP_ID ย # 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> 2. Load RAG์ ์ฒซ๋ฒ์งธ ์์ ์ ์ถํ LLM์ด ์๋ต์ ๋ฌธ๋งฅ์ผ๋ก ์ฌ์ฉํ ๋ RAG ์์คํ ์ด ์ฐธ๊ณ ํ HTML ๋ฐ์ดํฐ๋ฅผ ์ค๋นํ๋ ๋จ๊ณ์ ๋๋ค. txt ํ์ผ(clovastudiourl.txt)์ ์ฌ์ฉํ๊ณ ์ถ์ ์ฌ์ดํธ URL์ ์์ฑํ ํ, wget ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ LangChain์ Document Loader ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ HTML ๋ฐ์ดํฐ๋ฅผ ์์ ์ ํธํ ํํ๋ก ๋ณํํ์ต๋๋ค. ๋ํ, ๋ก๋ฉํ ๋ฐ์ดํฐ ์์ ์ฌ์ดํธ URL์ ๋ฃ์ด ์ถํ ๋ต๋ณ๊ณผ ํจ๊ป ์ฌ์ดํธ ์ฃผ์๊ฐ ์ถ๋ ฅ๋๊ฒ ํ์ฌ ์ง๋ฌธํ ์ฌ์ฉ์๊ฐ ๋ต๋ณ์ ๋ด์ฉ์ด ์๋ ์ค์ URL์ ํจ๊ป ์ฐธ์กฐํ ์ ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์์ ํ์ต๋๋ค. ย 1)ย txtย โย html ๋ณํ ๋ฐ ์๋ณธ ์ฌ์ดํธ ์ฃผ์ mapping importย subprocess ย url_to_filename_mapย =ย {} ย ย withย open("clovastudiourl.txt",ย "r") asย file: ย ย ย ย urlsย =ย [url.strip()ย forย urlย inย file.readlines()] ย ย folder_pathย =ย "clovastudioguide" ย ย ifย notย os.path.exists(folder_path): ย ย ย ย os.makedirs(folder_path) ย ย forย urlย inย urls: ย ย ย ย filenameย =ย url.split("/")[-1]ย +ย ".html" ย ย ย ย file_pathย =ย os.path.join(folder_path, filename) ย ย ย ย subprocess.run(["wget",ย "--user-agent=RAGCookbook-Crawler/1.0",ย "-O", file_path, url], check=True) ย ย ย ย url_to_filename_map[url]ย =ย filename ย ย withย open("url_to_filename_map.json",ย "w") as map_file: ย ย ย ย json.dump(url_to_filename_map, map_file) #Output --2024-08-26ย 13:37:02--ย https://guide.ncloud-docs.com/docs/clovastudio-info Resolving guide.ncloud-docs.com (guide.ncloud-docs.com)...ย 104.18.6.159,ย 104.18.7.159 Connecting to guide.ncloud-docs.com (guide.ncloud-docs.com)|104.18.6.159|:443... connected. HTTP request sent, awaiting response...ย 200ย OK Length: unspecified [text/html] Saving to: โclovastudioguide_0822/clovastudio-info.htmlโ ย ย ย ย ย 0K .......... .......... .......... .......... ..........ย 21.4M ย ย ย ย 50K .......... .......... .......... ..........ย ย ย ย ย ย ย ย ย ย ย ย 83.3M=0.003s 2024-08-26ย 13:37:02ย (32.1ย MB/s) - โclovastudioguide_0822/clovastudio-info.htmlโ saved [92957] --2024-08-26ย 13:37:02--ย https://guide.ncloud-docs.com/docs/clovastudio-procedure Resolving guide.ncloud-docs.com (guide.ncloud-docs.com)...ย 104.18.6.159,ย 104.18.7.159 Connecting to guide.ncloud-docs.com (guide.ncloud-docs.com)|104.18.6.159|:443... connected. HTTP request sent, awaiting response...ย 200ย OK Length: unspecified [text/html] Saving to: โclovastudioguide_0822/clovastudio-procedure.htmlโ ย ย ย ย ย 0K .......... .......... .......... .......... ..........ย 18.0M ย ย ย ย 50K .......... .......... ..........ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย 21.6M=0.004s 2024-08-26ย 13:37:03ย (19.2ย MB/s) - โclovastudioguide_0822/clovastudio-procedure.htmlโ saved [82265] LangChain์ ํ์ฉํด ๋ก๋ฉํ html์, ํ์ผ์ ์ ์ฅํ ๋๋ ํ ๋ฆฌ์ ์ฃผ์๋ฅผ metadata์ 'source'๋ก ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค. ์ถํ ๋ต๋ณ ์ ๊ณต์, ๋๋ ํ ๋ฆฌ ์ฃผ์๊ฐ ์๋ ์ค์ URL์ ์ ๊ณตํ๊ธฐ ์ํด, LangChain์ด ๋ก๋ฉํ ๋ฐ์ดํฐ๋ฅผ ์์ ํด์ผํฉ๋๋ค. html์ ๋ก๋ฉํ ๋ ํ์ผ๋ช ์ URL๋ก ํ ๊ฒฝ์ฐ, /์ : ๊ธฐํธ๋ก ์ธํด ํ์ผ๋ช ์ด ๊นจ์ง๊ฒ ๋ฉ๋๋ค.ย ๋ฐ๋ผ์ ์๋ณธ URL๊ณผ ๋ก๋ฉํ HTML ํ์ผ์ ์์ผ๋ก mappingํ๊ณ , ์ด ์ ๋ณด๋ฅผ json ํ์์ผ๋ก "url_to_filename_map"์ ์ ์ฅํฉ๋๋ค.ย ์ดํ,ย html ํ์ผ์ ์ ์ฅ ๊ฒฝ๋ก๊ฐ ๋ด๊ธด 'source'๋ฅผ, ์ด json ํ์ผ์ ์ฐธ๊ณ ํด ์ค์ URL๋ก ๋ณํํด์ค๋๋ค.ย ์ ์ฝ๋๋, json ํ์ผ์ ์ ์ฅํ๋ ๋จ๊ณ๊น์ง์ ๋๋ค.ย ์ธ๋ถ ์ฌ์ดํธ ์ ๊ทผ ํ์ฉ ์ฝ๋ ย wget ๋ช ๋ น์ด๋ฅผ ํตํด HTML ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๊ธฐ ์ , ํด๋น ์น์ฌ์ดํธ์ robots.txt๋ฅผ ํ์ธํ์ฌ ๋ฐ์ดํฐ๋ก ํ์ฉํ ์นํ์ด์ง์ ํฌ๋กค๋ฌ ์ ๊ทผ ํ์ฉ ์ฌ๋ถ๋ฅผ ํ์ธํด์ผํฉ๋๋ค. NCP์ ํด๋ก๋ฐ์คํ๋์ค ์ฌ์ฉ ๊ฐ์ด๋์ ๊ฒฝ์ฐย User-agent: * Allow:/ ๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํฉ๋๋ค. ์ผ๋ถ ์ฌ์ดํธ๋ User-agent๋ฅผ ์ ์ํ๋ ๋ถ๋ถ์ ์ถ๊ฐํด์ ์ฌ์ฉํด์ผ ์น ์๋ฒ์ ์์ฒญ ์ฐจ๋จ์ด๋ ์๋ฌ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.ย ๋๋ถ๋ถ ์๋ฒ์ --user-agent๋ Mozilla/5.0๋ฅผ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.ย ํ์ง๋งย ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ถ๋ฌ์ค๊ณ ์ ํ๋ ์ฌ์ดํธ์ --user-agent ์ ๋ณด๋ฅผ ์ง์ ์ฐพ์์ ์ ์ด์ผํฉ๋๋ค. 2)ย LangChain ํ์ฉ HTML ๋ก๋ฉ 2-1)ย BSHTMLLoader ์ฌ์ฉ #!pip install beautifulsoup4 lxml #ํ์์ beautifulsoup4 ์ค์น fromย langchain_community.document_loadersย importย BSHTMLLoader ย # ํด๋ ์ด๋ฆ์ ๋ง๊ฒ ์์ html_files_dirย =ย Path('clovastudioguide') ย ย html_filesย =ย list(html_files_dir.glob("*.html")) ย ย # ๋ชจ๋ ๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ ์ด๊ธฐํ clovastudiodatasย =ย [] ย ย # ์ฐพ์ HTML ํ์ผ๋ค์ ๋ํด ์ฒ๋ฆฌ forย html_fileย inย html_files: ย ย ย ย # ๊ฐ ํ์ผ์ ๋ํด BSHTMLLoader ์ธ์คํด์ค ์์ฑ ย ย ย ย loaderย =ย BSHTMLLoader(str(html_file)) ย ย ย ย document_dataย =ย loader.load() ย ย ย ย # ๋ก๋๋ ๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌ์คํธ์ ์ถ๊ฐ ย ย ย ย clovastudiodatas.append(document_data) ย ย ย ย print(f"Processed {html_file}") #Output Processed /Users/user/langchain/libs/community/sample/clovastudioguide/clovastudio-info.html Processed /Users/user/langchain/libs/community/sample/clovastudioguide/clovastudio-procedure.html ย 2-2)ย ย UnstructuredHTMLLoader ์ฌ์ฉ ์ด์ ๋จ๊ณ์์ txt ํ์ผ์ HTML๋ก ๋ณํํ ํ, LangChain์ UnstructuredHTMLLoader๋ฅผ ์ฌ์ฉํ์ฌ ์ดํ ๋ฌธ๋จ ๋๋๊ธฐ์ ์๋ฒ ๋ฉ์ ์ํด machine readableํ ํํ๋ก ๋ณํํด ์ค๋๋ค. #!pip install unstructured #ํ์์ unstructured ์ค์น fromย langchain_community.document_loadersย importย UnstructuredHTMLLoader ย # ํด๋ ์ด๋ฆ์ ๋ง๊ฒ ์์ html_files_dirย =ย Path('./clovastudioguide') ย ย 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}") #Output Processed /Users/user/langchain/libs/community/sample/clovastudioguide/clovastudio-info.html Processed /Users/user/langchain/libs/community/sample/clovastudioguide/clovastudio-procedure.html ๊ฐ HTML์๋ page_content์ ๋ชจ๋ ํ ์คํธ๊ฐ, metadata์ 'source'์๋ ์ ์ฅ ๊ฒฝ๋ก๊ฐ ๊ธฐ๋ก๋์ด ์์ต๋๋ค.ย ์๋, ๋ก๋ฉ๋ ๋ฐ์ดํฐ ์ค ํ๋์ธ clovastudio-info.html์ ํํ์ ๋๋ค. metadata์ 'source'์ ์ค์ URL์ด ์๋ html ํ์ผ์ด ์ ์ฅ๋ ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก๊ฐ ๋ด๊ธด ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.ย Mapping์ ํตํด ์ด 'source'๋ฅผ ์ค์ URL๋ก ๋ฐ๊พธ๋ ์์ ์ ๋ค์ ๋จ๊ณ์ ์งํํ๊ฒ ๋ฉ๋๋ค. 3)ย Mapping ์ ๋ณด๋ฅผ ํ์ฉํด 'source'๋ฅผ ์ค์ URL๋ก ๋์ฒด ์๋์ output์ ์์ ์์์ธ clovastudio-info.html์ ํํ์ ๋๋ค.ย Mapping ์ ๋ณด๋ฅผ ํ์ฉํด 'source'๋ฅผ ์ค์ 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์ ์ฐพ์ ์ ์์ต๋๋ค.") print(doc.metadata["source"]) #Output https://guide.ncloud-docs.com/docs/clovastudio-procedure # ์ด์ค ๋ฆฌ์คํธ๋ฅผ ํ์ด์ ํ๋์ ๋ฆฌ์คํธ๋ก ๋ง๋๋ ์์ clovastudiodatas_flattenedย =ย [itemย forย sublistย inย clovastudiodatasย forย itemย inย sublist] HTML๋ฐ์ดํฐ๊ฐ ์ ๋ก๋ฉ๋์๋์ง ๊ฒฐ๊ณผ๋ฌผ์ ์ถ๋ ฅํด ํ์ธํด๋ด ๋๋ค. # ์ฒ์ 3๊ฐ ๋ฌธ์์ URL๊ณผ ๋ด์ฉ ์ผ๋ถ ์ถ๋ ฅ forย docย inย clovastudiodatas_flattened[:2]: ย ย ย ย print(f"URL: {doc.metadata['source']}") ย ย ย ย print(f"{doc.page_content[:100]}...") ย ย ย ย print("-"ย *ย 50) #Output URL: https://guide.ncloud-docs.com/docs/clovastudio-info Login Korean English Ja - ๆฅๆฌ่ช Korean API ๊ฐ์ด๋ (...์ดํ ์ค๋ต) 3. Chunking ์๋ฒ ๋ฉ ๋ชจ๋ธ์ด ์ฒ๋ฆฌํ ์ ์๋ ์ ๋นํ ํฌ๊ธฐ๋ก raw data๋ฅผ ๋๋๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด๋ ์๋ฒ ๋ฉ ๋ชจ๋ธ๋ง๋ค ํ ๋ฒ์ ์ฒ๋ฆฌํ ์ ์๋ ํ ํฐ ์์ ํ๊ณ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.ย CLOVA Studio์ ๋ฌธ๋จ ๋๋๊ธฐ API๋ฅผ ํ์ฉํด ์์ ๋ง๋ raw data๋ฅผ ๋๋ ๋ณด๊ฒ ์ต๋๋ค. ๋ชจ๋ธ์ด ์ง์ ๋ฌธ์ฅ๋ค๊ฐ์ ์๋ฏธ ์ ์ฌ๋๋ฅผ ์ฐพ์ ์ต์ ์ ์ฒญํฌ(chunk) ๊ฐ์์ ์ฌ์ฉ์๊ฐ ์ํ๋ 1๊ฐ ์ฒญํฌ ํฌ๊ธฐ(๊ธ์ ์)๋ฅผ ์ง์ ์ค์ ํ์ฌ ๋ฌธ๋จ์ ๋๋ ์ ์์ต๋๋ค. ์ถ๊ฐ๋ก, ํ์ฒ๋ฆฌ(postProcess = True)๋ฅผ ํตํด chunk๋น ๊ธ์ ์์ ์ํ์ ๊ณผ ํํ์ ์ postProcessMaxSize์ postProcessMinSize๋ก ์กฐ์ ํ ์๋ ์์ต๋๋ค. importย http.client fromย httpย importย HTTPStatus ย ย classย CLOVAStudioExecutor: ย ย ย ย defย __init__(self, host, request_id=None): ย ย ย ย ย ย ย ย self._hostย =ย host ย ย ย ย ย ย ย ย self._api_keyย =ย os.environ["NCP_CLOVASTUDIO_API_KEY"] ย ย ย ย ย ย ย ย self._api_key_primary_valย =ย os.environ["NCP_APIGW_API_KEY"] ย ย ย ย ย ย ย ย self._request_idย =ย request_idย orย str(uuid.uuid4()) ย ย ย ย ย ย 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 ย ย ย ย ย ย defย execute(self, completion_request, endpoint): ย ย ย ย ย ย ย ย res, statusย =ย self._send_request(completion_request, endpoint) ย ย ย ย ย ย ย ย ifย statusย ==ย HTTPStatus.OK: ย ย ย ย ย ย ย ย ย ย ย ย returnย res, status ย ย ย ย ย ย ย ย 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ย SegmentationExecutor(CLOVAStudioExecutor): ย ย ย ย defย execute(self, completion_request): ย ย ย ย ย ย ย ย app_idย =ย os.environ["NCP_CLOVASTUDIO_APP_ID_SEGMENTATION"] ย ย ย ย ย ย ย ย endpointย =ย f'/testapp/v1/api-tools/segmentation/{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}") ย ย ย ย ย ย ย ย ย ifย __name__ย ==ย "__main__": ย ย ย ย # ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ด ์๋์ง ํ์ธ ย ย ย ย required_env_varsย =ย [ ย ย ย ย ย ย ย ย "NCP_CLOVASTUDIO_API_KEY", ย ย ย ย ย ย ย ย "NCP_APIGW_API_KEY", ย ย ย ย ย ย ย ย "NCP_CLOVASTUDIO_APP_ID_SEGMENTATION" ย ย ย ย ] ย ย ย ย ย ย ย ย ย missing_varsย =ย [varย forย varย inย required_env_varsย ifย notย os.environ.get(var)] ย ย ย ย ifย missing_vars: ย ย ย ย ย ย ย ย raiseย ValueError(f"Missing required environment variables: {', '.join(missing_vars)}") ย ย ย ย ย ย ย ย ย segmentation_executorย =ย SegmentationExecutor( ย ย ย ย ย ย ย ย host="clovastudio.apigw.ntruss.com" ย ย ย ย ) ย ย ย ย ย ย chunked_htmlย =ย [] ย ย ย ย ย ย forย htmldataย inย tqdm(clovastudiodatas_flattened): ย ย ย ย ย ย ย ย try: ย ย ย ย ย ย ย ย ย ย ย ย request_dataย =ย { ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "postProcessMaxSize":ย 100, ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "alpha":ย -100, ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "segCnt":ย -1, ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "postProcessMinSize":ย -1, ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "text": htmldata.page_content, ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "postProcess":ย True ย ย ย ย ย ย ย ย ย ย ย ย } ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย response_dataย =ย segmentation_executor.execute(request_data) ย ย ย ย ย ย ย ย ย ย ย ย result_dataย =ย [' '.join(segment)ย forย segmentย inย response_data] ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย forย paragraphย inย result_data: ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย chunked_documentย =ย { ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "metadata": htmldata.metadata["source"], ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย "page_content": paragraph ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย } ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย chunked_html.append(chunked_document) ย ย ย ย ย ย ย ย ย ย ย ย ย ย exceptย Exception as e: ย ย ย ย ย ย ย ย ย ย ย ย print(f"Error processing data from {htmldata.metadata['source']}: {e}") ย ย ย ย ย ย ย ย ย ย ย ย # ์ค๋ฅ ๋ฐ์ ์ ํ์ฌ ๋ฐ๋ณต์ ๊ฑด๋๋ฐ๊ณ ๋ค์์ผ๋ก ์งํ ย ย ย ย ย ย ย ย ย ย ย ย continue ย ย ย ย ย ย ย print(len(chunked_html)) #Output 100%|โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ|ย 2/2ย [00:04<00:00,ย ย 2.06s/it] 108 ์ ์ฝ๋๋ฅผ ์คํํด 108๊ฐ์ chunk๊ฐ ์๊ฒผ์ต๋๋ค.ย ์ํ ์ฒญํฌ๋ฅผ 3๊ฐ ์ถ๋ ฅํด ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ด ์๋ค. # ์ฒญํฌ ๋ถ์ ๋ฐ ์ถ๋ ฅ print(f"\n์ด ์ฒญํฌ ์: {len(chunked_html)}") ย # ์ํ ์ฒญํฌ ์ถ๋ ฅ print("\n์ํ ์ฒญํฌ (์ฒ์ 3๊ฐ):") forย i, chunkย inย enumerate(chunked_html[:3],ย 1): ย ย ย ย print(f"\n์ฒญํฌ {i}:") ย ย ย ย print(f"๋ฉํ๋ฐ์ดํฐ: {chunk['metadata']}") ย ย ย ย print(f"๋ด์ฉ: {chunk['page_content']}") ย ย ย ย print(f"๊ธธ์ด: {len(chunk['page_content'])} ๋ฌธ์") #Output ์ด ์ฒญํฌ ์:ย 108 ์ํ ์ฒญํฌ (์ฒ์ย 3๊ฐ): ์ฒญํฌย 1: ๋ฉํ๋ฐ์ดํฐ: https://guide.ncloud-docs.com/docs/clovastudio-info ๋ด์ฉ: Login Korean English Ja - ๆฅๆฌ่ช Korean API ๊ฐ์ด๋ CLI ๊ฐ์ด๋ ๋ด์ฉ x HOME ํฌํธ ๋ฐ ์ฝ์ ๋ค์ด๋ฒ ํด๋ผ์ฐ๋ ํ๋ซํผ ์ฌ์ฉ ํ๊ฒฝ Compute Containers Storage Networking Database Security ๊ธธ์ด:ย 145ย ๋ฌธ์ ์ฒญํฌย 2: ๋ฉํ๋ฐ์ดํฐ: https://guide.ncloud-docs.com/docs/clovastudio-info ๋ด์ฉ: AI Services AIยทNAVER API Application Services Big Data & Analytics ๊ธธ์ด:ย 66ย ๋ฌธ์ ์ฒญํฌย 3: ๋ฉํ๋ฐ์ดํฐ: https://guide.ncloud-docs.com/docs/clovastudio-info ๋ด์ฉ: Blockchain Business Applications Content Delivery Developer Tools Digital Twin Gaming ๊ธธ์ด:ย 85ย ๋ฌธ์ 4. Embedding ์๋ฒ ๋ฉ ๋จ๊ณ๋ ์์ Chunking ๋จ๊ณ์์ ์์ฑ๋ chunk๋ค์ย ๊ธฐ๊ณ๊ฐ ์ดํดํ ์ ์๋ ์์น์ ํํ์ธ ๋ฒกํฐ ๋ฐ์ดํฐ๋ก ๋ณํํ๋ ๊ณผ์ ์ ๋๋ค. ๋ฌธ์์ ์๋ฏธ๋ฅผ ๋ฒกํฐ(์ซ์์ ๋ฐฐ์ด) ํํ๋ก ํํํจ์ผ๋ก์จ, ์ ์ ์ ์ง๋ฌธ์ ๋ํด ๊ด๋ จ์๋ chunk๋ฅผ ๊ฒ์ํ์ฌ ๊ฐ์ ธ์ค๋ ์ ์ฌ๋ ๊ณ์ฐ์ ํ์ฉ๋ฉ๋๋ค. 1)ย LangChain์ ํตํด CLOVA Studio Embedding ํ์ฉํ๊ธฐ 1-1)ย ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ค์ ํ๊ธฐ ๋ฌธ๋จ ๋๋๊ธฐ API๋ฅผ ํตํด ๋ถํ ๋ ์ฒญํฌ(chunked_html)๋ฅผ CLOVA Studio์ ์๋ฒ ๋ฉ API๋ฅผ ์ฌ์ฉํดย 1024์ฐจ์ ๋ฒกํฐ๋ก ๋ณํํ๋ ๊ณผ์ ์ ๋๋ค. <1. ์ฌ์ ์ค๋น> ๋จ๊ณ์์ ๋ฐ๊ธํ ์๋ฒ ๋ฉ V2 ํ ์คํธ์ฑ์ ์ฌ์ฉํ์ผ๋ฉฐ, ์์ ์ ์ฅํด๋ APIํค ๋ฐ app id ๋ฅผ ํ์ฉํฉ๋๋ค. ์๋ฒ ๋ฉ V2๋ bge-m3 ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉฐ,ย ์ด ๋ชจ๋ธ์ย ์๋ฒ ๋ฉ ๊ณผ์ ์์ ์ ์ฌ๋ ํ๋จ์ ์ํด ์ฝ์ฌ์ธ ๊ฑฐ๋ฆฌ(Cosine)๋ฅผ ๊ฑฐ๋ฆฌ ๋จ์๋ก ์ฌ์ฉํฉ๋๋ค. ๋ชจ๋ธ์ ์ค์ ํ์ง ์์ผ๋ฉด clir-emb-dolphin ๋ชจ๋ธ์ด ๊ธฐ๋ณธ ์ค์ ๋๋ฏ๋ก,ย ย ClovaXEmbeddings์ย ๋ชจ๋ธ์ย bge-m3๋ก ์ค์ ํด์ฃผ์ด์ผ ํฉ๋๋ค. fromย langchain_community.embeddingsย importย ClovaXEmbeddings ย clovax_embeddingsย =ย ClovaXEmbeddings(model='bge-m3')ย # ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ์ค์ ํด์ฃผ์ธ์ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๋์ฆ์ ๋ฐ๋ผ ์ธ๊ฐ์ง ๋ชจ๋ธ ์ค, ์ ํํ์ฌ ์์ ์ ์ํํ ์ ์์ต๋๋ค.ย ๊ฑฐ๋ฆฌ ๋จ์๋ฅผ ์๋ฒ ๋ฉ๋ถํฐ ์ธ๋ฑ์ฑ, ๊ฒ์๊น์ง ์ผ์น์์ผ์ผ ๋ฐ์ดํฐ์ ํ์ง์ด ํฅ์๋๋ฏ๋ก, ์๋ฒ ๋ฉ ๊ณผ์ ์์ ์ฌ์ฉํ ๋ชจ๋ธ(emb / sts / bge-m3)์ด ๋ฌด์์ธ์ง ๊ธฐ์ตํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. (์์ธํ ๋ด์ฉ์ย ํด๋ก๋ฐ ์คํ๋์ค ๊ฐ์ด๋ย ์ฐธ๊ณ )ย ๋๊ตฌ๋ช ๋ชจ๋ธ๋ช ์ต๋ ํ ํฐ ์ ๋ฒกํฐ ์ฐจ์ ๊ถ์ฅ ๊ฑฐ๋ฆฌ ์งํ ์๋ฒ ๋ฉ clir-emb-dolphinย (๋ญ์ฒด์ธ ๊ธฐ๋ณธ์ค์ ) 500 ํ ํฐ 1024 IP (Inner/Dot/Scalar Product; ๋ด์ ) ์๋ฒ ๋ฉ clir-sts-dolphin 500 ํ ํฐ 1024 Cosine Similarity (์ฝ์ฌ์ธ ์ ์ฌ๋) ์๋ฒ ๋ฉ v2 bge-m3 8192 ํ ํฐ 1024 Cosine Similarity (์ฝ์ฌ์ธ ์ ์ฌ๋) ย ย 1-2)ย ์๋ฒ ๋ฉ ๊ฒฐ๊ณผ ํ์ธํ๊ธฐ ๋ค์ ์์ ์ฝ๋๋ "ํด๋ก๋ฐ ์คํ๋์ค"๋ผ๋ ๊ธ์์ ๋ํด CLOVA Studio์ ์๋ฒ ๋ฉ API๋ฅผ ์ฌ์ฉํด ์๋ฒ ๋ฉ์ ์์ฑํ๋ ๊ณผ์ ์ ๋๋ค. ์๋ฒ ๋ฉ์ ํ ์คํธ ๋ฐ์ดํฐ์ ์๋ฏธ๋ฅผ ๋ฒกํฐ ๊ณต๊ฐ์์ ํํํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.ย textย =ย "ํด๋ก๋ฐ ์คํ๋์ค" ย clovax_embeddings.embed_query(text) ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ณด๋ฉด "ํด๋ก๋ฐ ์คํ๋์ค"๋ผ๋ ํ ์คํธ์ ๋ํ ์๋ฒ ๋ฉ ๋ฒกํฐ๊ฐ ์์ฑ๋ฉ๋๋ค. ์ด ๋ฒกํฐ์ ํฌ๊ธฐ๋ 1024๋ก, ์ค์ ๋ฐฐ์ด์ ํํ๋ก ํํ๋ฉ๋๋ค. #Output [-0.13467026, ย -0.54031295, ย -0.5842034, ย 1.6036854, ย -1.2513447, ย -0.8417246, ย -0.51857895, ...์๋ต] 2)ย ๋ฆฌ์คํธ ํ์์ documents๋ก ๋ง๋ค๊ธฐ ์๋ฒ ๋ฉ ์ฒ๋ฆฌ๋ฅผ ์ํด ์์ ๋ง๋ ์ฒญํฌ๋ฅผย Documentย ๊ฐ์ฒด๋ค์ ๋ฆฌ์คํธ ํ์์ย documents๋ก ๋ณํํฉ๋๋ค. fromย langchain_core.documentsย importย Document ย documentsย =ย [] ย forย index, itemย inย enumerate(chunked_html): ย ย ย ย docย =ย Document( ย ย ย ย ย ย ย ย page_content=str(item['page_content']), ย ย ย ย ย ย ย ย 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) #Output Documentย 0: ย ย Page Content: CLOVA Studio ๊ฐ๋ Login Korean English Ja - ๆฅๆฌ่ช Korean API ๊ฐ์ด๋ CLI ๊ฐ์ด๋๋ด์ฉ x HOME ํฌํธ ๋ฐ ์ฝ์ ๋ค์ด๋ฒ ํด๋ผ์ฐ๋ ํ๋ซํผ ์ฌ... ย ย Metadata: {'source':ย 'https://guide.ncloud-docs.com/docs/clovastudio-info',ย 'title':ย 'CLOVA Studio ๊ฐ๋ '} ย ย Page Content Type: <classย 'str'> ย ย Metadata Type: <classย 'dict'> ---------------------------------------- Documentย 1: ย ย Page Content: ์๊ฒฌ์ ๋ณด๋ด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.Classic/VPC ํ๊ฒฝ์์ ์ด์ฉ ๊ฐ๋ฅํฉ๋๋ค.CLOVA Studio๋ฅผ ์ด์ฉํ๋ ์ ์ฒด ์๋๋ฆฌ์ค๋ฅผ ํ์ตํ๊ธฐ์ ์์ CLOVA Studio์ ๋ํ ๋ช ๊ฐ... ย ย Metadata: {'source':ย 'https://guide.ncloud-docs.com/docs/clovastudio-info',ย 'title':ย 'CLOVA Studio ๊ฐ๋ '} ย ย Page Content Type: <classย 'str'> ย ย Metadata Type: <classย 'dict'> ---------------------------------------- ...(์ดํ ์ค๋ต) ย 5. Vector store ์ด ๋จ๊ณ๋ ์์ ์๋ฒ ๋ฉํ ๊ฒฐ๊ณผ๋ฅผ Vector Store์ ํจ์จ์ ์ผ๋ก ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ๋จ๊ณ์ ๋๋ค.ย ย ๋ฒกํฐ DB๋ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๊ฒ์ํ๊ธฐ ์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๋ค.ย ์ด ์์ ์์๋ ๋ก์ปฌ ํ๊ฒฝ์์ ๋ณด๋ค ์ฝ๊ฒ ํ์ฉํ ์ ์๋ Chroma์ FAISS๋ฅผ ์ฌ์ฉํ์ต๋๋ค.ย Langchain์ย Vector DB ๋น๊ต ๋ฌธ์๋ฅผ ๋ณด๊ณ , ์์ ์ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ง๋ ์ ํ์ ํ์ฉํ์ธ์. 1)ย Vector DB์ ์ ์ฅํ๊ธฐ 1-1) Chroma ํ์ฉ Chroma๋ ์คํ์์ค Vector DB์ด๋ฉฐ, ํด๋ผ์ฐ๋๋ฅผ ์ฌ์ฉํ์ง์๊ณ ํด๋ผ์ด์ธํธ์ฉ์ผ๋ก ์ฌ์ฉํ๋ฉดย Apache 2.0 ๋ผ์ด์ผ์ค์ ๋ฌด๋ฃ๋ก ์ด์ฉํ ์ ์์ต๋๋ค.ย ๋ณธ ์์ ์์๋ chroma๋ฅผ ํ์ฉํด ์ปฌ๋ ์ ์ ์์ฑํ๊ณ , ์ปฌ๋ ์ ์ ์์ ๋ง๋ ๋ฌธ์๋ฅผ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค.ย hnsw:space์ ๊ฐ์ ์ค์ ํจ์ผ๋ก์จ ์๋ฒ ๋ฉ ๊ณต๊ฐ์ ๊ฑฐ๋ฆฌ ๋ฐฉ๋ฒ์ ์ฌ์ฉ์ ์ ์ํ ์ ์์ต๋๋ค. ์๋ฒ ๋ฉ์ ์ฌ์ฉํ ๋ชจ๋ธ์ ์ ์ฌ๋ ํ๋จ์ ์ํด ๋ฒกํฐ์ cosine ๊ฑฐ๋ฆฌ ๋จ์๋ก ์ฌ์ฉํ๋ฏ๋ก, ์ปฌ๋ ์ ๋ํ ๋งค๊ฐ๋ณ์๋ฅผ "cosine"์ผ๋ก ์ค์ ํด์ฃผ์์ต๋๋ค.ย *๋งค๊ฐ๋ณ์๋ ip, cosine, l2(๊ธฐ๋ณธ๊ฐ) ์ค์ ์ ํํ ์ ์์ต๋๋ค. ๋ํ, ์๋ฒ ๋ฉ ํด๋์ค์ ์ค๋ฅ๊ฐ ๋ฐ์์ ๋ฉ์ถ๊ฒ๋ ํ๋ ๋ก์ง์ ์ผ๋ถ ์ถ๊ฐํด, ๋ค๋์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ค๋ฅ ๋ฐ์์ ์ฌ์คํ์ ๋ถ๋ด์ ์ค์์ต๋๋ค.ย LangChain ๊ณต์ ๋ฌธ์์์ Chroma๋ฅผ ํ์ฉํ๋ ์์ธํ ๋ด์ฉ์ ํ์ธํ ์ ์์ต๋๋ค. #chroma ๋ค์ด๋ฐ๊ธฐ %pip installย -qUย "langchain-chroma>=0.1.2" 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)ย ย # ์ด์ฉ๋ ์ ์ด๋ฅผ ๊ณ ๋ คํ 1์ด ์ด์์ ๋๋ ์ด, ํ์์ ๋ฐ๋ผ ์กฐ์ ๊ฐ๋ฅ ย ย print("All documents have been added to the vectorstore.") #Output Adding documents:ย 100%|โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ|ย 108/108ย [03:17<00:00,ย ย 2.46s/it] All documents have been added to the vectorstore. Quote emb ๋ชจ๋ธ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ํ์์ ๋ฐ๋ผ ํด๋ก๋ฐ ์คํ๋์ค์ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์คย clir-emb-dolphinย ์ ์ฌ์ฉํ๊ณ ์ ํ๋ ๊ฒฝ์ฐ, ๋ชจ๋ธ์ ์ ํฉํ ๊ฑฐ๋ฆฌ ์งํ์ธ IP(๋ด์ )์ ์ฌ์ฉํ๊ธฐ ์ํด Chroma ์ปฌ๋ ์ ์์ฑ ์ ์ค์ ์ญ์ 'ip'๋ก ๋ณ๊ฒฝ์ด ํ์ํ๋ฉฐ, ๋ญ์ฒด์ธ ์ฐ๋์ ์ํด ์ ๊ทํ๋(normalized) ์๋ฒ ๋ฉ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด ์๋์ ๊ฐ์ด ์ถ๊ฐ์ ์ธ ์กฐ์น๊ฐ ํ์ํฉ๋๋ค. clir-emb-dolphin๋ชจ๋ธ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ ์ฒด์ฝ๋ fromย langchain_community.embeddingsย importย ClovaXEmbeddings fromย langchain_chromaย importย Chroma ย clientย =ย chromadb.PersistentClient(path="./chroma_langchain_db") ย chroma_collectionย =ย client.get_or_create_collection( ย ย ย ย name="clovastudiodatas_rag_cosine", ย ย ย ย metadata={"hnsw:space":ย "ip"}ย # ip๊ฑฐ๋ฆฌ๋ก ์ค์ ) ย # IP๊ฑฐ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ธ(clir-emb-dolphin)์ ์๋ฒ ๋ฉ ๊ฒฐ๊ณผ ์ ๊ทํ ํ์ importย numpy as np classย NormalizedClovaXEmbeddings(ClovaXEmbeddings) : ย ย ย ย defย _embed_text(self, text:ย str) : ย ย ย ย ย ย ย ย # Call the parent class method to get the original embedding ย ย ย ย ย ย ย ย original_embeddingsย =ย super()._embed_text(text) ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย # Postprocessing: apply normalization function to each element ย ย ย ย ย ย ย ย try: ย ย ย ย ย ย ย ย ย ย ย ย normalized_embeddingsย =ย list(original_embeddings/np.linalg.norm(original_embeddings)) ย ย ย ย ย ย ย ย except: ย ย ย ย ย ย ย ย ย ย ย ย raiseย ValueError(f"normalization failed on text: {text}") ย ย ย ย ย ย ย ย returnย normalized_embeddings ย ย ย ย ย ย asyncย defย _aembed_text(self, text:ย str) : ย ย ย ย ย ย ย ย original_embeddingsย =ย awaitย super()._aembed_text(text) ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย try: ย ย ย ย ย ย ย ย ย ย ย ย normalized_embeddingsย =ย list(original_embeddings/np.linalg.norm(original_embeddings)) ย ย ย ย ย ย ย ย except: ย ย ย ย ย ย ย ย ย ย ย ย raiseย ValueError(f"normalization failed on text: {text}") ย ย ย ย ย ย ย ย returnย normalized_embeddings ย clova_embeddingsย =ย ClovaXEmbeddings(model="clir-emb-dolphin") vectorstoreย =ย Chroma( ย ย ย ย client=client, ย ย ย ย collection_name="clovastudiodatas_rag_cosine",ย #collection์ด ๋ฐ๋๋๋ง๋ค ์ด๋ฆ๋ ๊ผญ ๋ณ๊ฒฝํด์ค์ผ ํฉ๋๋ค. ย ย ย ย embedding_function=clova_embeddings ) ย # tqdm์ผ๋ก for ๋ฃจํ ๊ฐ์ธ๊ธฐ forย docย inย tqdm(documents, desc="Adding documents", total=len(documents)) : ย ย ย ย embeddingsย =ย clova_embeddings.embed_documents([doc.page_content])[0] ย ย ย ย # ๋ฌธ์ ์ถ๊ฐ ย ย ย ย chroma_collection.add( ย ย ย ย ย ย ย ย ids=[str(uuid.uuid4())], ย ย ย ย ย ย ย ย documents=[doc.page_content], ย ย ย ย ย ย ย ย embeddings=[embeddings], ย ย ย ย ย ย ย ย metadatas=[doc.metadata] ย ย ย ย ) ย ย ย ย time.sleep(1.4) ย # ์ด์ฉ๋ ์ ์ด๋ฅผ ๊ณ ๋ คํ 1์ด ์ด์์ ๋๋ ์ด, ํ์์ ๋ฐ๋ผ ์กฐ์ ๊ฐ๋ฅ ย ย print("All documents have been added to the vector store.") 1-2) FAISS ํ์ฉ Facebook AI Similarity Search (Faiss)๋ ๋ฐ์ง ๋ฒกํฐ์ ํจ์จ์ ์ธ ์ ์ฌ๋ ๊ฒ์๊ณผ ํด๋ฌ์คํฐ๋ง์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.ย ๋ณธ ์์ ์์๋ FAISS๋ฅผ ํ์ฉํด vectorstore๋ฅผ ์์ฑํ๊ณ , ๋ฌธ์๋ฅผ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค. vectorstrore๋ฅผ ์์ฑํ ๋, ์๋ฒ ๋ฉ ์ฐจ์ ํฌ๊ธฐ๋ฅผ 1024์ฐจ์์ผ๋ก ์ค์ ํ์ต๋๋ค.ย ๋ํ, ์๋ฒ ๋ฉ ํด๋์ค์ ์ค๋ฅ๊ฐ ๋ฐ์์ ๋ฉ์ถ๊ฒ๋ ํ๋ ๋ก์ง์ ์ผ๋ถ ์ถ๊ฐํด, ๋ค๋์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ค๋ฅ ๋ฐ์์ ์ฌ์คํ์ ๋ถ๋ด์ ์ค์์ต๋๋ค.ย Langchain ๊ณต์ ๋ฌธ์์์ 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 ๋ฒกํฐ ์ ์ฅ์ ์์ฑ vectorstore_FAISSย =ย FAISS( ย ย ย ย embedding_function=clovax_embeddings, ย ย ย ย index=faiss.IndexFlatIP(1024),ย # ์๋ฒ ๋ฉ ์ฐจ์ ํฌ๊ธฐ ย ย ย ย docstore=InMemoryDocstore(), ย ย ย ย index_to_docstore_id={}, ) ย # tqdm์ผ๋ก for ๋ฃจํ ๊ฐ์ธ๊ธฐ forย docย inย tqdm(documents, desc="Adding documents", total=len(documents)): ย ย ย ย embeddingsย =ย clovax_embeddings.embed_documents([doc.page_content])[0] ย ย ย ย # ๋ฌธ์ ์ถ๊ฐ ย ย ย ย vectorstore_FAISS.add_documents( ย ย ย ย ย ย ย ย ids=[str(uuid.uuid4())],ย ย # ๊ณ ์ ํ ID ์์ฑ ย ย ย ย ย ย ย ย documents=[doc],ย ย # ๋ฌธ์์ด๋ง ์ ๋ฌ ย ย ย ย ย ย ย ย embeddings=[embeddings] ย ย ย ย ) ย ย ย ย time.sleep(1.4) ย # ์ด์ฉ๋ ์ ์ด๋ฅผ ๊ณ ๋ คํ 1์ด ์ด์์ ๋๋ ์ด, ํ์์ ๋ฐ๋ผ ์กฐ์ ๊ฐ๋ฅ ย ย print("All documents have been added to the vectorstore.") #Output Adding documents: 100%|โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ| 108/108 [03:17<00:00, 2.46s/it] All documents have been added to the vectorstore. 2)ย ๋ค์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ํ์ฉํด Retriever ์์ฑํ๊ธฐ ๊ฒ์๊ธฐ(Retriever) ๋จ๊ณ๋ ์ ์ฅ๋ ๋ฒกํฐ DB์์ย ์ฌ์ฉ์์ ์ง๋ฌธ๊ณผ ๊ด๋ จ๋ ๋ฌธ์๋ฅผ ๊ฒ์ํ๋ ๊ณผ์ ์ ๋๋ค.ย vectorstore.as_retriever()๋ฅผ ํตํด ๊ฒ์๊ธฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด ์์ ์์๋ย retrieverย ํ๋ผ๋ฏธํฐ ์ค์ ์ ํตํดย 3๊ฐ์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด ๋ต๋ณ์ ํ๋๋ก ํด๋ณด๊ฒ ์ต๋๋ค. retrieverย =ย vectorstore.as_retriever(kwargs={"k":ย 3}) ๋ง๋ค๊ณ ์ ํ๋ RAG ์์คํ ์ ๋ชฉ์ ๋ฐ ํ์ฉ์ ๋ง๊ฒย ์๋์ 1~4๋ฒ์ ํญ๋ชฉ์ย ๋ค์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํด ์ปค์คํ ํด๋ณด์ธ์. ํ๋ผ๋ฏธํฐ๋ฅผ ๋ค์ํ๊ฒ ์กฐ์ ํด๊ฐ๋ฉฐ ์ ํ์ ๋ชฉ์ ์ ๊ฐ์ฅ ์ ํฉํ ๋ต๋ณ์ ํ๋ ๋ฐฉ์์ ์ฐพ์๋๊ฐ ์ ์์ต๋๋ค. ย 2-1)ย ์ ์ฌ๋ ์ ์ ์๊ณ๊ฐ ์ค์ ์ด ์ค์ ์ ์ ์ฌ๋ ์ ์๊ฐ 0.5 ์ด์์ธ ๋ฌธ์๋ง ๋ฐํํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ง๋ฌธ๊ณผ ๊ด๋ จ์ฑ์ด ๋์ ๋ฌธ์๋ง์ ์ ํ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์๊ณ๊ฐ์ ๋๊ฒ ์ค์ ํ ์๋ก ๋ ๊ด๋ จ์ฑ ๋์ ๋ฌธ์๋ง ๋ฐํ๋์ง๋ง, ๊ด๋ จ ์ ๋ณด๋ฅผ ๋์น ๊ฐ๋ฅ์ฑ๋ ์์ต๋๋ค. ๋ฐ๋๋ก ์๊ณ๊ฐ์ ๋ฎ์ถ๋ฉด ๋ ๋ง์ ๋ฌธ์๊ฐ ๋ฐํ๋์ง๋ง, ๊ด๋ จ์ฑ์ด ๋จ์ด์ง๋ ๋ฌธ์๋ ํฌํจ๋ ์ ์์ต๋๋ค.ย Langchain ๊ณต์ ๋ฌธ์์์ ๋ ์์ธํ ๋ด์ฉ์ ํ์ธํ ์ ์์ต๋๋ค. retrieverย =ย db.as_retriever( ย ย ย ย # ๊ฒ์ ์ ํ์ "์ ์ฌ๋ ์ ์ ์๊ณ๊ฐ"์ผ๋ก ์ค์ ํฉ๋๋ค. ย ย ย ย search_type="similarity_score_threshold", ย ย ย ย # ๊ฒ์ ์ธ์๋ก ์ ์ ์๊ณ๊ฐ์ 0.5๋ก ์ง์ ํฉ๋๋ค. ย ย ย ย search_kwargs={"score_threshold":ย 0.5}, ) ์ ์ฌ๋ ์๊ณ๊ฐ์ 0์์ 1 ์ฌ์ด์ ๊ฐ์ด์ด์ผ ํฉ๋๋ค.ย ์ด๋ ์ฝ์ฌ์ธ ๊ฑฐ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ `clir-sts-dolphin`ย ๋ชจ๋ธ๊ณผ `bge-m3`ย ๋ชจ๋ธ์ ์ฌ์ฉํ ๋ ์ ํฉํฉ๋๋ค. IP(Inner Product) ๊ฑฐ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ `clir-emb-dolphin`ย ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๊ฒฝ์ฐ ์ ์ฌ๋ ์ ์ ๋ฒ์๊ฐ ๋ฌ๋ผ ์์ ์์ฑ๋ ์ฝ๋๋ฅผ ์ฌ์ฉํด ์ ๊ทํ๊ฐ ํ์ํฉ๋๋ค. ย 2-2)ย ๋ฐํ ๋ฌธ์ ์ ์ ํ ์ด ์ค์ ์ ์์ 3๊ฐ์ ๊ฐ์ฅ ๊ด๋ จ์ฑ ๋์ ๋ฌธ์๋ง ๋ฐํํฉ๋๋ค.ย k ๊ฐ์ ๋ฎ๊ฒ ์ค์ ํ๋ฉด ์ฒ๋ฆฌ ์๋๊ฐ ๋นจ๋ผ์ง๊ณ ๊ฐ์ฅ ๊ด๋ จ์ฑ ๋์ ๋ฌธ์์ ์ง์คํ ์ ์์ง๋ง, ์ค์ํ ์ ๋ณด๋ฅผ ๋์น ์ ์์ต๋๋ค. k ๊ฐ์ ๋๊ฒ ์ค์ ํ๋ฉด ๋ ๋ง์ ๋งฅ๋ฝ์ ์ ๊ณตํ ์ ์์ง๋ง, ์ฒ๋ฆฌ ์๊ฐ์ด ๊ธธ์ด์ง๊ณ ๊ด๋ จ์ฑ์ด ๋ฎ์ ์ ๋ณด๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค. search_kwargs์ k์ kwargs์ k์ ์ฐจ์ด kwargs์ k ๊ฐ์ ์๋ฏธ๋ ๊ฒ์๊ธฐ(retriever)๊ฐ ๋ต๋ณ ์์ฑย ์ต์ข ์ ์ผ๋ก ์ฐธ์กฐํ๋ ์์ ๋ฌธ์์ ๊ฐ์๋ฅผ ์๋ฏธํฉ๋๋ค. ์ฆ, ์๋์ ์์ ์ ๊ฐ์ด '3'์ผ๋ก ์ค์ ํ๋ค๋ฉด ๊ฒ์ํ๋ ๋ฌธ์ ์ค์์ ์ ์ฌ๋๊ฐ ๋์ ์์ 3๊ฐ์ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ฌ ๋ต๋ณ์ ์์ฑํฉ๋๋ค. search_kwargs์ k ๊ฐ์ ์๋ฏธ๋ ๊ฒ์ํ๋ ๋ฌธ์์ ๊ฐ์๋ฅผ ์๋ฏธํฉ๋๋ค. ์ด์ ์ kwargs์ k ๊ฐ์ ๊ฒ์ํ ๋ฌธ์์์ ๋ต๋ณ์ ํ ๋ ์ฐธ์กฐํ๋ ์์ ๋ฌธ์์ ์ ์๋ค๋ฉด search_kwargs์ k๋ ๊ฒ์ํ๋ ค๋ ๋ฌธ์์ ๊ฐ์๋ฅผ ์๋ฏธํฉ๋๋ค. ๋ฐ๋ผ์ search_kwargs์ k๊ฐ์ด kwargs์ k ๊ฐ๋ณด๋ค ์ ์ ์๋ก ์ค์ ๋๋ค๋ฉด, ๊ฒ์ํ๋ ๋ฌธ์์ ์๊ฐ ๋ต๋ณ ์์ฑ ์์ ์ฐธ์กฐํ๋ ๋ฌธ์์ ๊ฐ์๋ณด๋ค ์ ์ ๊ฐ์๋ก ์ค์ ๋ ๊ฒ์ผ๋ก, search_kwargs์ k๊ฐ์ ์๋ก ๋ฌธ์์ ๊ฐ์๊ฐ ์ ํ๋์ด ๋ต๋ณ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, search_kwargs์ k ๊ฐ์ ๋์๊ด์์ ์ ๋ณด๋ฅผ ์ป์ผ๋ ค๊ณ ๋น๋ฆฐ ์ ์ฒด ์ฑ ์ ๊ถ ์๊ฐ ๋๊ณ , kwargs์ k ๊ฐ์ ๋น๋ฆฐ ์ฑ ์ ์ฒด์์ ์ค์ ์ ๋ณด๋ฅผ ์ป์ ์ฑ ์ ๊ถ์๋ผ๊ณ ์ดํดํ ์ ์์ต๋๋ค.ย 2-3)ย MMR (Maximum Marginal Relevance) ๊ฒ์ ๋๋ถ๋ถ์ ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ ๋ฌธ์์ ์ฟผ๋ฆฌ ๊ฐ์ ์ ์ฌ๋๋ฅผ ๊ณ์ฐํ์ฌ ๊ฐ์ฅ ๋์ ์ ์๋ฅผ ๊ฐ์ง ๋ฌธ์๋ค์ ์์๋๋ก ๋ฐํํฉ๋๋ค. ์ด ๊ฒฝ์ฐ, ๋ด์ฉ์ด ๋งค์ฐ ์ ์ฌํ๊ฑฐ๋ ์ฌ์ง์ด ๋์ผํ ๋ฌธ์๋ค์ด ์ฐ์ํด์ ๊ฒ์ ๊ฒฐ๊ณผ์ ๋ํ๋ ์ ์์ต๋๋ค. ์ด ๋ฌธ์ ์ ์ MMR(Maximal Marginal Relevance) ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค. ์ฟผ๋ฆฌ์ ๋ํ ๊ด๋ จ ํญ๋ชฉ์ ๊ฒ์ํ ๋ ๊ฒ์๋ ๋ฌธ์์ ์ค๋ณต์ ํผํ๊ธฐ ์ํด ๋จ์ํ ๊ฐ์ฅ ๊ด๋ จ์ฑ ๋์ ํญ๋ชฉ๋ค๋ง์ ๊ฒ์ํ๋ ๋์ , ์ด๋ฏธ ์ ํ๋ ๋ฌธ์๋ค๊ณผ์ ์ฐจ๋ณ์ฑ๋ ๊ณ ๋ คํด ๋ฌธ์๋ฅผ ๋ฐํํฉ๋๋ค. ๋ฐ๋ผ์, ์ ๋ณด ๊ฒ์์ด๋ ์ถ์ฒ ์์คํ ์ฒ๋ผ ๊ฒ์ ๊ฒฐ๊ณผ์ ๋ค์์ฑ์ด ์ค์ํ๊ฑฐ๋ ์ค๋ณต๋ ์ ๋ณด๋ฅผ ์ค์ด๊ณ ์ถ์ ๋ ์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ์ข์ต๋๋ค. ๋งค๊ฐ๋ณ์(parameters) k:ย ์ด ๋งค๊ฐ๋ณ์๋ ์ต์ข ์ ์ผ๋ก ๋ฐํํ ๋ฌธ์์ ์ด ๊ฐ์์ ๋๋ค. (๊ธฐ๋ณธ๊ฐ: 4) fetch_k:ย MMR ์๊ณ ๋ฆฌ์ฆ์ ์ํํ ๋ ๊ณ ๋ คํ ์ด๊ธฐ ํ๋ณด ๋ฌธ์ ์งํฉ์ ํฌ๊ธฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ๊ด๋ฒ์ํ ํ๋ณด๊ตฐ์์ ๋ฌธ์๋ฅผ ์ ํํ๋ฉด ์ข์ ๋ ์ด ๊ฐ์ ๋์ ๋๋ค. ๋ฐ๋๋ก, ๋น ๋ฅธ ์๋ต ์๊ฐ์ด ์ฐ์ ์ ์ด๋ผ๋ฉด ์ด ๊ฐ์ ๋ฎ์ถ ์ ์์ต๋๋ค.(๊ธฐ๋ณธ๊ฐ: 20) lambda_mult: ์ฟผ๋ฆฌ์์ ์ ์ฌ์ฑ๊ณผ ์ ํ๋ ๋ฌธ์ ๊ฐ์ ๋ค์์ฑ ์ฌ์ด์ ๊ท ํ์ ์กฐ์ ํ๋ ๋ณ์์ ๋๋ค. 1์ ๊ฐ๊น์ธ์๋ก ์ฟผ๋ฆฌ์์ ์ ์ฌ๋ ์ ์๋ง ๊ณ ๋ คํ๊ณ , 0์ ๊ฐ๊น์์ง์๋ก ๋ฌธ์๊ฐ์ ๋ค์์ฑ๋ง ๊ณ ๋ คํฉ๋๋ค. (0~1, ๊ธฐ๋ณธ๊ฐ: 0.5) ย 2-4)ย ๋ฉํ ๋ฐ์ดํฐ ํํฐ๋ง ๋ฉํ ๋ฐ์ดํฐ ํํฐ๋ฅผ ์ด์ฉํ์ฌ ํน์ ํค์๋๊ฐ ํฌํจ๋ ๋ฉํ ๋ฐ์ดํฐ๋ง ํํฐ๋งํ ์ ์์ต๋๋ค. ์์ document์ ์ ์ฅํ ๋, metadata์ title์ ํจ๊ป ์ ์ฅํ์ต๋๋ค. ์ด๋ฅผ ํ์ฉํด ๋ฌธ์๋ฅผ ํํฐ๋งํด ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. # ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง filtered_retrieverย =ย db.as_retriever( ย ย ย ย search_kwargs={"filter": {'title':ย 'CLOVA Studio ์๋๋ฆฌ์ค'}} ) ย 6. RAG ์์คํ ์์ฑ 1)ย LCEL์ ์ฌ์ฉํด Chain ๊ตฌํํ๊ธฐ LCEL(LangChain Expression Language)์ ๋ญ์ฒด์ธ์์ ์ฝ๋๋ฅผ ์์ฑํ๋ ์๋ก์ด ๋ฐฉ๋ฒ์ ๋๋ค. ํ๋กฌํํธ์ LLM ๋ชจ๋ธ์ ์ ์ํด๋๊ณ ,ย |ย ๊ธฐํธ๋ก ๊ฐ ์์๋ฅผ ์ฐ๊ฒฐํด ํ ๊ตฌ์ฑ ์์์ ์ถ๋ ฅ์ ๋ค์ ๊ตฌ์ฑ ์์์ ์ ๋ ฅ์ผ๋ก ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ Chain์ ์์ฑํด ๋ณต์กํ AI ์์คํ ์ ์ํฌํ๋ก์ฐ๋ฅผ ๋ณด๋ค ์ฝ๊ณ ์ง๊ด์ ์ผ๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ย 1-1)ย ์ฌ์ฉํ LLM ๋ชจ๋ธ ์ ์ ๋จผ์ , HyperCLOVA X ๋ชจ๋ธ (HCX-003) ์ ๋ญ์ฒด์ธ Chat model ์ปดํฌ๋ํธ์ ChatClovaX๋ฅผ ํตํด ๋ถ๋ฌ์ ์ ์ํฉ๋๋ค.ย fromย langchain_community.chat_modelsย importย ChatClovaX ย llmย =ย ChatClovaX( ย ย ย ย model="HCX-003", ) ย 1-2)ย Prompt ์ ์ PromptTemplate ์ฌ์ฉํ๊ธฐ ์ฟผ๋ฆฌ์ ์ฌ์ฉํ Prompt๋ StringPromptTemplates ํน์ ChatPromptTemplates์ ์ฌ์ฉํด ์ ์ํ ์ ์์ต๋๋ค.ย Langchain ๊ณต์ ๋ฌธ์์์ ๊ด๋ จ ๋ด์ฉ์ ํ์ธํด๋ณด์ธ์. PromptTemplate์ ๋จ์ผ ๋ฌธ์์ด์ ์์์ ์ง์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋จํ ์ ๋ ฅ์ ์ฌ์ฉ๋๋ ํ ํ๋ฆฟ์ ๋๋ค.ย PromptTemplate์ Python์ ๋ฌธ์์ด ํฌ๋งทํ ์ ์ฌ์ฉํ์ฌ ๋์ ์ผ๋ก ํน์ ํ ์์น์ ์ ๋ ฅ ๊ฐ์ ํฌํจ์ํฌ ์ ์์ด, ๋ค์ํ ์ํฉ์ ๋ง๊ฒ ํ๋กฌํํธ๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์๋ ์์ ์ฒ๋ผ {question}, {context} ์ ๊ฐ์ ์ฌ์ฉ์ ์ ๋ ฅ ๋ฐ ๋งค๊ฐ ๋ณ์๋ฅผ ์ธ์ด ๋ชจ๋ธ์ ์ ๋ฌํ๊ฒ ํ ์ ์์ต๋๋ค. ย fromย langchain_core.promptsย importย PromptTemplate ย prompt1ย =ย PromptTemplate.from_template( ย ย ย ย """๋น์ ์ ์ง๋ฌธ-๋ต๋ณ(Question-Answering)์ ์ํํ๋ ์น์ ํ AI ์ด์์คํดํธ์ ๋๋ค. ๋น์ ์ ์๋ฌด๋ ์๋ ๊ฐ์ง๊ณ ์๋ ์ง์์ ๋ชจ๋ ๋ฐฐ์ ํ๊ณ , ์ฃผ์ด์ง ๋ฌธ๋งฅ(context) ์์ ์ฃผ์ด์ง ์ง๋ฌธ(question) ์ ๋ตํ๋ ๊ฒ์ ๋๋ค. ๊ฒ์๋ ๋ค์ ๋ฌธ๋งฅ(context) ์ ์ฌ์ฉํ์ฌ ์ง๋ฌธ(question) ์ ๋ตํ์ธ์. ๋ง์ฝ, ์ฃผ์ด์ง ๋ฌธ๋งฅ(context) ์์ ๋ต์ ์ฐพ์ ์ ์๋ค๋ฉด, ๋ต์ ๋ชจ๋ฅธ๋ค๋ฉด `์ฃผ์ด์ง ์ ๋ณด์์ ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค` ๋ผ๊ณ ๋ตํ์ธ์. ย #Question: {question} ย #Context: {context} ย #Answer:""" ) ย ChatPromptTemplate ์ฌ์ฉํ๊ธฐ ChatPromptTemplate ์ ๋ํ๋ชฉ๋ก์ ํ๋กฌํํธ๋ก ์ฃผ์ ํ๊ณ ์ ํ ๋ ํ์ฉํ ์ ์์ต๋๋ค.ย ๋ฉ์์ง๋ ํํ(tuple) ํ์์ผ๋ก ๊ตฌ์ฑํ๋ฉฐ, (role, message) ๋ก ๊ตฌ์ฑํ์ฌ ๋ฆฌ์คํธ๋ก ์์ฑํ ์ ์์ต๋๋ค. "system": ์์คํ ์ค์ ๋ฉ์์ง ์ ๋๋ค. ์ฃผ๋ก ์ ์ญ์ค์ ๊ณผ ๊ด๋ จ๋ ํ๋กฌํํธ์ ๋๋ค. "human" : ์ฌ์ฉ์ ์ ๋ ฅ ๋ฉ์์ง ์ ๋๋ค. "ai": AI ์ ๋ต๋ณ ๋ฉ์์ง์ ๋๋ค. ย fromย langchain_core.promptsย importย ChatPromptTemplate ย system_promptย =ย ( ย ย ย ย ย ย ย ย """๋น์ ์ ์ง๋ฌธ-๋ต๋ณ(Question-Answering)์ ์ํํ๋ ์น์ ํ AI ์ด์์คํดํธ์ ๋๋ค. ๋น์ ์ ์๋ฌด๋ ์๋ ๊ฐ์ง๊ณ ์๋ ์ง์์ ๋ชจ๋ ๋ฐฐ์ ํ๊ณ , ์ฃผ์ด์ง ๋ฌธ๋งฅ(context) ์์ ์ฃผ์ด์ง ์ง๋ฌธ(question) ์ ๋ตํ๋ ๊ฒ์ ๋๋ค. ๊ฒ์๋ ๋ค์ ๋ฌธ๋งฅ(context) ์ ์ฌ์ฉํ์ฌ ์ง๋ฌธ(question) ์ ๋ตํ์ธ์. ๋ง์ฝ, ์ฃผ์ด์ง ๋ฌธ๋งฅ(context) ์์ ๋ต์ ์ฐพ์ ์ ์๋ค๋ฉด, ๋ต์ ๋ชจ๋ฅธ๋ค๋ฉด `์ฃผ์ด์ง ์ ๋ณด์์ ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค` ๋ผ๊ณ ๋ตํ์ธ์. """ ย ย ย ย "\n\n" ย ย ย ย "{context}" ) ย prompt2ย =ย ChatPromptTemplate.from_messages( ย ย ย ย [ ย ย ย ย ย ย ย ย ("system", system_prompt), ย ย ย ย ย ย ย ย ("human",ย "{question}"), ย ย ย ย ] ) ย 1-3)ย Chain ์์ฑ ์์ ์ ์ํ LLM ๋ชจ๋ธ๊ณผ prompt๋ฅผ LCEL ํ๊ธฐ๋ฒ์ ์ฌ์ฉํด chain์ผ๋ก ์ฐ๊ฒฐํฉ๋๋ค. ์ด๋,ย Langchain์ย StrOutputParser๋ chain์ผ๋ก ์ฐ๊ฒฐํดย ๋ชจ๋ธ์ ์ถ๋ ฅ์ ๋ฌธ์์ด๋ก ๋ณํํด๋ณด๊ฒ ์ต๋๋ค. ์๋ ์ฝ๋๋ฅผ ์คํํ๋ฉด ์ฐ๊ฒฐ๋ chain์ด ์ฐ์์ ์ผ๋ก ์คํ๋ฉ๋๋ค. retriever๋ฅผ ํตํด ๊ด๋ จ ๋ฌธ์๋ฅผ context๋ก ๋ถ๋ฌ์ค๊ณ , context์ question์ด ํ๋กฌํํธ ํ ํ๋ฆฟ์ผ๋ก ์ ๋ฌ๋๊ณ , llm ๋ชจ๋ธ์ ํตํด ํ๋กฌํํธ๊ฐ ์คํ๋๊ณ , StrOutputParser๋ฅผ ํตํด ๋ต๋ณ๋ง ํ์ฑํด ๋ฌธ์์ด๋ก ์ถ๋ ฅํฉ๋๋ค. fromย langchain_core.runnablesย importย RunnablePassthrough fromย langchain_core.output_parsersย importย StrOutputParser ย # ์ฒด์ธ์ ์์ฑํฉ๋๋ค. rag_chainย =ย ( ย ย ย ย {"context": retriever,ย "question": RunnablePassthrough()} ย ย ย ย | prompt1 ย ย ย ย | llm ย ย ย ย | StrOutputParser() ) rag_chain.invoke("ํ ํฐ์ด ๋ญ๊ฐ์?") #Output ํ ํฐ์ ์์ฐ์ด ์ฒ๋ฆฌ๋ฅผ ์ํด ํ๋์ ๋จ์ด๋ฅผ ์ธ๋ถํํ ๋จ์ด ์กฐ๊ฐ์ ์๋ฏธํฉ๋๋ค. ์๋ฅผ ๋ค์ด, '๋ง์์ด'๋ผ๋ ํํ์ ๊ฐ๊ฐ '๋ง'๊ณผ '์์ด'๋ผ๋ ๋ ๊ฐ์ ํ ํฐ์ผ๋ก ๋๋ ์ ์์ต๋๋ค. ๋ค๋ฅธ ์์๋ก๋ '์์ญ์ด ์๋ฉ์ด๋ ๋นจ๊ฐ' ๋ผ๋ ๋ฌธ์ฅ์ '์์ญ์ด', '์๋ฉ์ด๋', '๋นจ๊ฐ' ์ ๊ฐ์ ์ธ ๊ฐ์ ํ ํฐ์ผ๋ก ๋๋ ์ ์์ต๋๋ค. ย 1-4)ย ์ฐธ์กฐ ๋ฌธ์ ๋งํฌ์ ํจ๊ป ๋ต๋ณ ์ถ๋ ฅํ๊ธฐ ๋ชจ๋ธ์ด ๋ต๋ณ์ ์์ฑํ ๋ ์ฐธ์กฐํ๋ ๋ฌธ์์ ์ถ์ฒ๋ฅผ ํ์ธํ๊ณ ์ถ์ผ์๋ค๋ฉด ์๋์ ์ฝ๋๋ฅผ ์ฐธ์กฐํ์ธ์.ย RunnablePassthrough.assign()์ ์ฌ์ฉํ์ฌ ๊ฒ์ ์ฒด์ธ์์ ์์ค ๋ฌธ์๋ฅผ ๋ฐํํด ์ฐธ์กฐ ๋ฌธ์ ๋งํฌ์ ํจ๊ป ๋ต๋ณ์ ์ถ๋ ฅํด๋ณด๊ฒ ์ต๋๋ค. fromย pprintย importย pprint fromย langchain_core.runnablesย importย RunnablePassthrough fromย langchain.schema.runnableย importย RunnableParallel fromย langchain_core.output_parsersย importย StrOutputParser ย # ์ฟผ๋ฆฌ ํ ์คํธ query_textย =ย "max_token์ ๋ช์ผ๋ก ์ค์ ํด์ผํด?" ย # 1. ์ฟผ๋ฆฌ ์๋ฒ ๋ฉ ์์ฑ clovax_embeddingsย =ย ClovaXEmbeddings(model='bge-m3') query_embeddingย =ย clovax_embeddings.embed_query(query_text) ย # 2. Chroma ์ปฌ๋ ์ ์ ์ฟผ๋ฆฌ ์คํํ์ฌ ์ ์ฌํ ๋ฌธ์ ๊ฒ์ resultsย =ย chroma_collection.query( ย ย ย ย query_embeddings=[query_embedding], ย ย ย ย n_results=5, ย ย ย ย include=["embeddings",ย "documents",ย "metadatas",ย "distances"] ) ย # 3. ์ ์ฌ๋ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฆฌํธ๋ฆฌ๋ฒ ๊ตฌ์ฑ similarity_retrieverย =ย vectorstore.as_retriever( ย ย ย ย kwargs={"k":ย 5}, ย ย ย ย search_type="similarity_score_threshold", ย ย ย ย search_kwargs={"score_threshold":ย 0.1,ย "k":ย 3} ) ย # 4. ๊ฒ์๋ ๋ฌธ์๋ฅผ RAG ์ฒด์ธ์ ์ฐ๊ฒฐํ์ฌ ๋ต๋ณ ์์ฑ rag_chain_from_docsย =ย ( ย ย ย ย RunnablePassthrough.assign(context=(lambdaย x: format_docs(x["context"]))) ย ย ย ย | prompt1 ย ย ย ย | llm ย ย ย ย | StrOutputParser() ) ย defย format_docs(docs): ย ย ย ย returnย "\n\n".join(doc.page_contentย forย docย inย docs) ย ย ย ย ย ย rag_chain_with_sourceย =ย RunnableParallel( ย ย ย ย {"context": similarity_retriever,ย "question": RunnablePassthrough()} ).assign(answer=rag_chain_from_docs) ย ย pprint(rag_chain_with_source) Vector DB์ ์ ์ฅํ ๋ฌธ์๋ค๊ณผ ๊ด๋ จ์๋ ์ง๋ฌธ์ ๋ํด์๋ ๋ชจ๋ธ์ด ์๋์ ๊ฐ์ด ๋ต๋ณ์ ์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. #Output {'answer': '์ผ๋ฐ ๋ชจ๋์์ ์ ๊ณตํ๋ ์ธ์ด ๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ์ต๋ 2048 ํ ํฐ๊น์ง, ์ฑ ๋ชจ๋์์ ์ ๊ณตํ๋ HyperCLOVA X ์ธ์ด ' '๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ์ต๋ 4096 ํ ํฐ๊น์ง ํ์ฉ๋ฉ๋๋ค. Maximum tokens๋ 300~500์ ๊ถ์ฅํ๋ฉฐ ์์ ์ ๋ฐ๋ผ ' '๋ฌ๋ผ์ง ์ ์์ต๋๋ค.', 'context': [Document(metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-info'}, page_content='Maximum tokens Maximum tokens๋ ๊ฒฐ๊ด๊ฐ์ ์์ฑํ ๋ ์ฌ์ฉํ ์ต๋ ํ ํฐ ์์ ๋๋ค. ํ ํฐ ์๋ฅผ ๋๊ฒ ์ค์ ํ ์๋ก ๊ธด ๊ฒฐ๊ด๊ฐ์ ์ถ๋ ฅํฉ๋๋ค.'), Document(metadata={'source': 'clovastudioguide_0822/clovastudio-info.html'}, page_content='Maximum tokens Maximum tokens๋ ๊ฒฐ๊ด๊ฐ์ ์์ฑํ ๋ ์ฌ์ฉํ ์ต๋ ํ ํฐ ์์ ๋๋ค. ํ ํฐ ์๋ฅผ ๋๊ฒ ์ค์ ํ ์๋ก ๊ธด ๊ฒฐ๊ด๊ฐ์ ์ถ๋ ฅํฉ๋๋ค.'), Document(metadata={'source': 'clovastudioguide_0822/clovastudio-info.html'}, page_content='ํ๋กฌํํธ์ ๊ฒฐ๊ด๊ฐ์ ํฌํจํ์ฌ ์ผ๋ฐ ๋ชจ๋์์ ์ ๊ณตํ๋ ์ธ์ด ๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ์ต๋ 2048 ํ ํฐ๊น์ง, ์ฑ ๋ชจ๋์์ ์ ๊ณตํ๋ HyperCLOVA X ์ธ์ด ๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ์ต๋ 4096 ํ ํฐ๊น์ง ํ์ฉ๋ฉ๋๋ค. Maximum tokens๋ 300~500์ ๊ถ์ฅํ๋ฉฐ ์์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.')], 'question': 'max_token์ ๋ช์ผ๋ก ์ค์ ํด์ผํด?'} ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ค ๋ณด๊ธฐ ์ข๊ฒ ํ์ธํ ์ ์์ต๋๋ค. resultย =ย rag_chain_with_source.invoke(query_text) model_answer=result['answer'] urlsย =ย {doc.metadata['source']ย forย docย inย result['context']} ย print("- ์ฌ์ฉ์ ์ง๋ฌธ: {0}\n- ๋ชจ๋ธ์ ๋ต๋ณ: {1}\n- ์ฐธ์กฐํ ๋ฌธ์์ url: {2}".format(query_text, model_answer,ย list(urls))) #Output - ์ฌ์ฉ์ ์ง๋ฌธ: max_token์ ๋ช์ผ๋ก ์ค์ ํด์ผํด? - ๋ชจ๋ธ์ ๋ต๋ณ: ์ผ๋ฐ ๋ชจ๋์์ ์ ๊ณตํ๋ ์ธ์ด ๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ์ต๋ 2048 ํ ํฐ๊น์ง, ์ฑ ๋ชจ๋์์ ์ ๊ณตํ๋ HyperCLOVA X ์ธ์ด ๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ์ต๋ 4096 ํ ํฐ๊น์ง ํ์ฉ๋ฉ๋๋ค. Maximum tokens๋ 300~500์ ๊ถ์ฅํ๋ฉฐ ์์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค. - ์ฐธ์กฐํ ๋ฌธ์์ url: ['clovastudioguide_0822/clovastudio-info.html', 'https://guide.ncloud-docs.com/docs/clovastudio-info'] ์๋์ ๊ฐ์ด ๋ฌธ์์ ๊ด๋ จ ์๋ ์ง๋ฌธ์ ๋ํด์ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์๋ค๊ณ ๋ตํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. rag_chain_with_source.invoke("์ค๋ ๊ธฐ๋ถ์ด ์ด๋?") #Output {'context': [Document(metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-info'}, page_content='Temperature ๊ฐ์ด ๋์ ๊ฒฝ์ฐ'), Document(metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-info'}, page_content='Temperature ๊ฐ์ด ๋์ ๊ฒฝ์ฐ'), Document(metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-procedure'}, page_content='์ด ๋ฌธ์๊ฐ ๋์์ด ๋์์ต๋๊น?')], 'question': '์ค๋ ๊ธฐ๋ถ์ด ์ด๋?', 'answer': '์ฃผ์ด์ง ์ ๋ณด์์ ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.'} 2)ย Built in chain ํ์ฉ ์ํ๋ ๊ฒฝ์ฐ LangChain์๋ RAG ์์คํ ์ ์์ LCEL์ ์ฌ์ฉํ์ง ์๊ณ ํจ์๋ก๋ ๊ตฌํํ ์ ์์ต๋๋ค. create_stuff_documents_chain ๊ฒ์๋ ์ปจํ ์คํธ๊ฐ ํ๋กฌํํธ์ LLM์ ๊ณต๊ธ๋๋ ๋ฐฉ๋ฒ์ ์ง์ ํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ํ๋กฌํํธ์ ๋ฌธ์์ ์์ฝ์ด๋ ๊ธฐํ ์ฒ๋ฆฌ ์์ด ๊ฒ์๋ ๋ชจ๋ ์ปจํ ์คํธ๋ฅผ ํฌํจํฉ๋๋ค. ์ด ํจ์๋ฅผ ํตํด {input}๊ณผ {context}์ ๋ด์ฉ์ด ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค. ์ ๋ ฅ ํค:ย context,ย input create_retrieval_chain ๊ฒ์ ๋จ๊ณ๋ฅผ ์ถ๊ฐํ๊ณ ๊ฒ์๋ ๋ฌธ์๋ฅผ ์ต์ข ๋ต๋ณ๊ณผ ํจ๊ป ์ ๊ณตํฉ๋๋ค. ์ ๋ ฅ ํค:ย input ์ถ๋ ฅ:ย input,ย context,ย answer ย ย 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 ย # chat๋ชจ๋ธ ์ ์ llmย =ย ChatClovaX( ย ย ย ย model="HCX-003", ) ย # ChatPromptTemplate ์ฌ์ฉ system_promptย =ย ( ย ย ย ย ย ย ย ย """๋น์ ์ ์ง๋ฌธ-๋ต๋ณ(Question-Answering)์ ์ํํ๋ ์น์ ํ AI ์ด์์คํดํธ์ ๋๋ค. ๋น์ ์ ์๋ฌด๋ ์๋ ๊ฐ์ง๊ณ ์๋ ์ง์์ ๋ชจ๋ ๋ฐฐ์ ํ๊ณ , ์ฃผ์ด์ง ๋ฌธ๋งฅ(context) ์์ ์ฃผ์ด์ง ์ง๋ฌธ(question) ์ ๋ตํ๋ ๊ฒ์ ๋๋ค. ๊ฒ์๋ ๋ค์ ๋ฌธ๋งฅ(context) ์ ์ฌ์ฉํ์ฌ ์ง๋ฌธ(question) ์ ๋ตํ์ธ์. ๋ง์ฝ, ์ฃผ์ด์ง ๋ฌธ๋งฅ(context) ์์ ๋ต์ ์ฐพ์ ์ ์๋ค๋ฉด, ๋ต์ ๋ชจ๋ฅธ๋ค๋ฉด `์ฃผ์ด์ง ์ ๋ณด์์ ์ง๋ฌธ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค` ๋ผ๊ณ ๋ตํ์ธ์. """ ย ย ย ย "\n\n" ย ย ย ย "{context}" ) ย prompt2ย =ย ChatPromptTemplate.from_messages( ย ย ย ย [ ย ย ย ย ย ย ย ย ("system", system_prompt), ย ย ย ย ย ย ย ย ("human",ย "{input}"), ย ย ย ย ] ) ย # Built-in chains question_answer_chainย =ย create_stuff_documents_chain(llm, prompt2) rag_chainย =ย create_retrieval_chain(retriever, question_answer_chain) ย resultย =ย rag_chain.invoke({"input":ย "ํ ํฐ์ด ๋ญ์ผ?"}) ย print(result) #Output {'input': 'ํ ํฐ์ด ๋ญ์ผ?', 'context': [Document(page_content='ํ ํฐ', metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-info'}), Document(page_content="<์์> '๋ง์์ด'๋ผ๋ ํํ์ ๊ฐ๊ฐ '๋ง'๊ณผ ์์ด'๋ผ๋ ๋ ๊ฐ์ ํ ํฐ์ผ๋ก ๋๋ ์ ์์ต๋๋ค.", metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-info'}), Document(page_content='Temperature๋ฅผ ๋ฎ๊ฒ ์ค์ ํ๋ฉด ํ๋ณด์ ํฌํจ๋ ํ ํฐ์ ์์๋ ๋ฐ๋์ง ์์ง๋ง ํ๋ฅ ์ด ๋์๋ ํ ํฐ์ ๋์ฑ ํ๋ฅ ๊ฐ์ด ๋์์ง๊ณ ๋ฎ์๋ ํ ํฐ์ ํ๋ฅ ๊ฐ์ด ๋์ฑ ๋ฎ์์ง๋๋ค. ๊ฐ์ฅ ๋์ ์์์ ํ ํฐ์ด ์ ํ๋ ๊ฐ๋ฅ์ฑ์ด ํฌ๊ธฐ ๋๋ฌธ์ ์ ํ์ ์ธ ๊ฒฐ๊ด๊ฐ์ ์์ฑํฉ๋๋ค.', metadata={'source': 'https://guide.ncloud-docs.com/docs/clovastudio-info'})], 'answer': 'ํ ํฐ์ ๋ฌธ์ฅ์ด๋ ๋จ์ด๋ฅผ ๊ตฌ์ฑํ๋ ๊ธฐ๋ณธ ๋จ์๋ก, ์๋ฏธ๋ฅผ ๊ฐ์ง๋ ์ต์ ๋จ์์ ๋๋ค. ์๋ฅผ ๋ค์ด, "๋ง์์ด"๋ผ๋ ํํ์ ๊ฐ๊ฐ "๋ง"๊ณผ "์์ด"๋ผ๋ ๋ ๊ฐ์ ํ ํฐ์ผ๋ก ๋๋ ์ ์์ต๋๋ค. ๋ํ ์ธ๊ณต์ง๋ฅ ๋ถ์ผ์์๋ ์์ฐ์ด ์ฒ๋ฆฌ๋ ๊ธฐ๊ณํ์ต์์ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ธฐ ์ํด ํ ํฐํ(tokenization) ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค. ์ด ๋ ๊ฐ ๋จ์ด๋ ๊ธฐํธ ๋ฑ์ ํ ํฐ์ผ๋ก ๋ถ๋ฆฌํ์ฌ ์ฒ๋ฆฌํฉ๋๋ค.'} ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ค ๋ณด๊ธฐ ์ข๊ฒ ํ์ธํ ์ ์์ต๋๋ค. 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) #Output ์ง๋ฌธ: ํ ํฐ์ด ๋ญ์ผ? ๋ต๋ณ: ํ ํฐ์ ๋ฌธ์ฅ์ด๋ ๋จ์ด๋ฅผ ๊ตฌ์ฑํ๋ ๊ธฐ๋ณธ ๋จ์๋ก, ์๋ฏธ๋ฅผ ๊ฐ์ง๋ ์ต์ ๋จ์์ ๋๋ค. ์๋ฅผ ๋ค์ด, "๋ง์์ด"๋ผ๋ ํํ์ ๊ฐ๊ฐ "๋ง"๊ณผ "์์ด"๋ผ๋ ๋ ๊ฐ์ ํ ํฐ์ผ๋ก ๋๋ ์ ์์ต๋๋ค. ๋ํ ์ธ๊ณต์ง๋ฅ ๋ถ์ผ์์๋ ์์ฐ์ด ์ฒ๋ฆฌ๋ ๊ธฐ๊ณํ์ต์์ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ธฐ ์ํด ํ ํฐํ(tokenization) ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค. ์ด ๋ ๊ฐ ๋จ์ด๋ ๊ธฐํธ ๋ฑ์ ํ ํฐ์ผ๋ก ๋ถ๋ฆฌํ์ฌ ์ฒ๋ฆฌํฉ๋๋ค. ์ฐธ์กฐ ๋ฌธ์ URL: https://guide.ncloud-docs.com/docs/clovastudio-info ย 7. ๋งบ์๋ง ์ง๊ธ๊น์ง NAVER Cloud Platform(NCP)์์ Langchain์ ํ์ฉํ์ฌ RAG ์์คํ ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ์ด ๊ฐ์ด๋์์๋ HCX ๋ชจ๋ธ์ ํ์ฉํ์ฌ ๊ฐ๋จํ RAG ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ๋ ๊ณผ์ ์ ๋ค๋ค์ต๋๋ค. ์ด ๊ฐ์ด๋๋ RAG์ ๊ธฐ๋ณธ ๊ตฌ์กฐ์ ํ๋ฆ์ ์ด์ ์ ๋ง์ถ์์ง๋ง, RAG ๊ธฐ์ ์ ๊ณ์ ๋ฐ์ ํ๊ณ ์์ต๋๋ค. ์์ผ๋ก ๋ค์ํ RAG ์์คํ ๊ตฌํ์ ๊ดํ ๋ ๊น์ด ์๋ ์ฃผ์ ๋ค์ ๋ค๋ฃฐ ์์ ์ ๋๋ค. NCP ๊ฐ์ด๋:ย https://guide.ncloud-docs.com/docs/clovastudio-dev-langchain LangChainย ๊ณต์ย ๋ฌธ์:ย https://python.langchain.com/docs/integrations/providers/naver/ ย ย ย ๋งํฌ ๋ณต์ฌ ๋ค๋ฅธ ์ฌ์ดํธ์ ๊ณต์ ํ๊ธฐ More sharing options...
Recommended Posts
๊ฒ์๊ธ ๋ฐ ๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋ก๊ทธ์ธ ํด์ฃผ์ธ์.
๋ก๊ทธ์ธ