Search

On-Premises Llama 2 및 SingleStoreDB 를 이용한 생성형 AI 프로그램 예제

문서번호 : 11-1641185

Document Information

최초 작성일 : 2025.04.07
최종 수정일 : 2025.04.07
이 문서는 아래 버전을 기준으로 작성되었습니다.
Singlestore DB : 9.0.18
Python: 3.11.11

Goal

이번 글에서는 On-Premises 환경에서 Llama 2 및 SingleStoreDB 를 각각 LLM 및 Vector Store 로 사용하는 간단한 예제를 소개하려고 합니다.
Llama 는 Meta 에서 공개한 Open LLM 으로 API 를 이용하는 OpenAI 의 ChatGPT 와 달리 온프레미스에서 로컬 서버에 설치가 가능해 많은 인기를 누리고 있습니다.
예제에서는 GPU 없이 CPU 만으로도 모델을 실행해 볼 수 있도록 양자화된 작은 크기의 Llama 모델을 사용할 것이며 Embedding 모델 역시 HuggingFace 에서 많이 사용하는 일반적인 모델을 이용할 것입니다.
전체적으로는 Python 의 langchain 패키지를 이용해 예제를 구성할 것입니다.
이번 예제의 데이터 흐름은 다음과 같습니다.
Document 를 Chunk 단위로 나누어 SingleStoreDB 의 Vector Embedding 으로 저장해 놓습니다.
사용자의 질의는 Embedding 하여 SingleStoreDB 에서 KNN 유사도 검색을 통해 Data Text Chunk 로 반환받습니다.
원래 사용자 질의와 반환 받은 Data Context 를 함께 Llama 2 LLM 에 전달합니다.
Llama 2 LLM 으로부터 받은 답변을 출력합니다.

시스템 정보

구분
설명
OS
Oracle Linux 8.10

Solution

1) Llama 2 모델 다운로드 및 테스트

Linux 에서 Llama 2 모델을 실행하기 위한 환경인 llama.cpp 를 설치합니다. GGUF 형식을 지원하는 버전으로 Git Branch 를 reset 합니다.
파라미터 7B 짜리 Llama 2 모델 하나를 다운로드 받고 필요한 경우 g++ 컴파일러도 설치합니다.
$ git clone https://github.com/ggerganov/llama.cpp $ cd llama.cpp $ git reset --hard d0cee0d36d5be95a0d9088b674dbb27354107221 $ curl -L "https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_S.gguf" -o models/llama-2-7b-chat.Q4_K_S.gguf $ sudo yum install -y gcc-c++ git $ sudo yum install gcc-toolset-12 $ scl enable gcc-toolset-12 bash $ make
SQL
복사
컴파일이 정상적으로 끝났으면 Llama LLM 에 질의를 전달해 봅니다.
2023 년 현재 태풍 카눈과 잼버리 대회와의 관계에 대해 물어 보겠습니다.
$ ./main -m ./models/llama-2-7b-chat.Q4_K_S.gguf -p "[INST] <<SYS>>\nYou are a helpful assistant.\n<</SYS>>\nTell me about the relations between Typhoon Khanun and Jamboree in South Korea[/INST]" -n 512 main: build = 1087 (d0cee0d36) main: seed = 1775538028 ... llm_load_print_meta: format = GGUF V2 (latest) llm_load_print_meta: arch = llama llm_load_print_meta: vocab type = SPM llm_load_print_meta: n_vocab = 32000 llm_load_print_meta: n_merges = 0 llm_load_print_meta: n_ctx_train = 4096 llm_load_print_meta: n_ctx = 512 llm_load_print_meta: n_embd = 4096 llm_load_print_meta: n_head = 32 llm_load_print_meta: n_head_kv = 32 llm_load_print_meta: n_layer = 32 llm_load_print_meta: n_rot = 128 llm_load_print_meta: n_gqa = 1 llm_load_print_meta: f_norm_eps = 1.0e-05 llm_load_print_meta: f_norm_rms_eps = 1.0e-06 llm_load_print_meta: n_ff = 11008 llm_load_print_meta: freq_base = 10000.0 llm_load_print_meta: freq_scale = 1 llm_load_print_meta: model type = 7B llm_load_print_meta: model ftype = mostly Q4_K - Small llm_load_print_meta: model size = 6.74 B llm_load_print_meta: general.name = LLaMA v2 llm_load_print_meta: BOS token = 1 '<s>' llm_load_print_meta: EOS token = 2 '</s>' llm_load_print_meta: UNK token = 0 '<unk>' llm_load_print_meta: LF token = 13 '<0x0A>' llm_load_tensors: ggml ctx size = 0.09 MB llm_load_tensors: mem required = 3677.46 MB (+ 256.00 MB per state) .................................................................................................. llama_new_context_with_model: kv self size = 256.00 MB llama_new_context_with_model: compute buffer total size = 71.91 MB system_info: n_threads = 4 / 4 | AVX = 1 | AVX2 = 1 | AVX512 = 1 | AVX512_VBMI = 1 | AVX512_VNNI = 1 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 | sampling: repeat_last_n = 64, repeat_penalty = 1.100000, presence_penalty = 0.000000, frequency_penalty = 0.000000, top_k = 40, tfs_z = 1.000000, top_p = 0.950000, typical_p = 1.000000, temp = 0.800000, mirostat = 0, mirostat_lr = 0.100000, mirostat_ent = 5.000000 generate: n_ctx = 512, n_batch = 512, n_predict = 512, n_keep = 0 [INST] <<SYS>>\nYou are a helpful assistant.\n<</SYS>>\nTell me about the relations between Typhoon Khanun and Jamboree in South Korea[/INST] I'm happy to help! However, I must inform you that there is no relation between Typhoon Khanun and Jamboree in South Korea. Our records show no information regarding the two weather phenomena or their possible interactions. Typhoon Khanun is a tropical cyclone that typically affects the Pacific region, particularly the Philippines and Taiwan. It is important to note that typhoons can have severe impacts on these regions, including strong winds, heavy rainfall, and storm surge. Jamboree, on the other hand, is not a weather phenomenon but rather a type of event. Jamboree is a large-scale gathering or celebration that brings together people from various backgrounds to share experiences, knowledge, and culture. While jamborees can be fun and exciting events, they are unrelated to weather phenomena like typhoons. I hope this information helps clarify any confusion! If you have any other questions, please feel free to ask. [end of text] llama_print_timings: load time = 430.55 ms llama_print_timings: sample time = 132.19 ms / 216 runs ( 0.61 ms per token, 1634.01 tokens per second) llama_print_timings: prompt eval time = 5765.72 ms / 48 tokens ( 120.12 ms per token, 8.33 tokens per second) llama_print_timings: eval time = 32379.64 ms / 215 runs ( 150.60 ms per token, 6.64 tokens per second) llama_print_timings: total time = 38326.87 ms
SQL
복사
2023 년 현재 태풍 카눈과 잼버리 대회와의 관계에 대해 물어봤는데 일반적인 내용만 정리해 줍니다.
당연히 최근에 진행중인 데이터를 학습하지 않았기 때문입니다.

2) SingleStoreDB 에 데이터 벡터 저장

2023년 태풍 카눈에 대한 내용을 wikipedia 에서 복사하여 텍스트 파일로 만들고 이를 SingleStoreDB 의 Vector Embedding 으로 저장하겠습니다. 파일은 아래에 첨부했습니다.
khanun.txt
9.7KB
먼저 Embedding 및 Llama 에 사용할 Python Package 들을 설치합니다.
$ python -m venv .venv $ source .venv/bin/activate $ pip install llama-cpp-python $ pip install langchain-community $ pip install langchain-text-splitters $ pip install langchain-singlestore $ pip install langchain-classic $ pip install sentence-transformers
SQL
복사
다음 Python 프로그램을 이용하여 Embedding 모델 및 Vector Store 를 각각 all-MiniLM-L6-v2, SingleStoreDB 로 선택합니다.
그 후 khanun.txt 파일을 chunk 단위로 분리한 다음 SingleStoreDB 로 업로드합니다.
import os from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_singlestore.vectorstores import SingleStoreVectorStore embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={'device': 'cpu'}) loader = DirectoryLoader('./', glob='khanun.txt', loader_cls=TextLoader) documents = loader.load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50) texts = text_splitter.split_documents(documents) os.environ["SINGLESTOREDB_URL"] = "user:pass@127.0.0.1:3306/vectordb" vectorstore = SingleStoreVectorStore.from_documents(texts, embeddings, distance_strategy="DOT_PRODUCT", table_name="demo")
SQL
복사
자동으로 demo 라는 테이블이 만들어 졌으며 content 컬럼에 데이터 텍스트, vector 에 embedding, metadata 에 source 파일명이 저장되었습니다.

3) SingleStoreDB 의 Vector 우선 검색 후 LLM 호출

langchain 의 Retrieval QA 를 만들어 Vector Store 를 SingleStoreDB 로 지정하여 질의를 수행하도록 하겠습니다.
qa_template 은 SingleStoreDB 로부터 전달받은 Data Context 를 이용해 사용자의 질의에 정확하고 의미있는 답변을 요청하도록 질문 템플릿이 구성되어 있습니다.
import os from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.llms import LlamaCpp from langchain_singlestore.vectorstores import SingleStoreVectorStore from langchain_classic.chains import RetrievalQA from langchain_core.prompts import PromptTemplate embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={'device': 'cpu'}) os.environ["SINGLESTOREDB_URL"] = "user:pass@127.0.0.1:3306/vectordb" vectorstore = SingleStoreVectorStore(embeddings, distance_strategy="DOT_PRODUCT", table_name="demo") qa_template = """[INST] <<SYS>> Use the context provided to answer the user's question. Be direct and concise. Do not say you don't know if the answer is in the context. <</SYS>> Context: {context} Question: {question} [/INST] """ prompt = PromptTemplate(template=qa_template, input_variables=['context', 'question'])
SQL
복사
langchain 의 llm 을 다운로드 받은 모델로 선택하고 이를 이용해 RetrievalQA 를 생성합니다.
이 때 SingleStoreDB 를 retriever 로 지정하고 5개의 KNN 유사도 검색 결과를 사용하도록 설정합니다.
llm = LlamaCpp(model_path="/home/opc/llama.cpp/models/llama-2-7b-chat.Q4_K_S.gguf", n_gpu_layers=1, n_batch=512, n_ctx=2048, f16_kv=True, verbose=False) dbqa = RetrievalQA.from_chain_type(llm=llm, chain_type='stuff', retriever=vectorstore.as_retriever(search_kwargs={'k': 5}), return_source_documents=True, chain_type_kwargs={'prompt': prompt})
SQL
복사
이제 다시 태풍 카눈과 잼버리 대회의 관계에 대해 질의해 보겠습니다.
카눈의 변경된 진로 및 예상되는 영향으로 인해 정부와 스카우트 조직이 대회를 빨리 끝냈다고 정확한 대답을 해 줍니다.
response = dbqa.invoke({'query':'Tell me about the relations between Typhoon Khanun and Jamboree in South Korea'}) print(f'\nAnswer: {response["result"]}') Answer: In response to the user's question, Typhoon Khanun had an impact on the 25th World Scout Jamboree in South Korea. Due to the changed path and expected impact of the typhoon, the Korean government, in cooperation with the World Organization of the Scout Movement, decided to end the ongoing jamboree early. All attendees will be relocated to hotels and accommodation in Seoul or whatever the contingent has decided on.
SQL
복사

마무리

외부에 공개할 수 없거나 LLM 이 학습하지 못한 최신 데이터의 벡터 저장 및 검색을 위해서는 On-Premises 에 SingleStoreDB 를 설치하여 빠른 벡터 연산 및 유사도 검색 기능을 활용할 수 있습니다.
다른 Vector Database 에 비해 SingleStoreDB 는 대용량 실시간 처리, Native Vector 연산, JSON 메타 데이터와의 Join 및 Aggregation 등 벡터 기능 뿐만 아니라 RDBMS 만의 데이터 처리 및 분석 기능을 함께 사용할 수 있어 더욱 활용도가 높습니다.
참고로 예제에서 사용한 모델은 GPU 없이 CPU 만으로도 사용할 수 있도록 양자화된 모델이므로 Linux, Windows, Mac 에서 모두 간단하게 테스트해 볼 수는 있으나 속도가 매우 느립니다.
느린 속도에도 불구하고 On-premises 환경에서 LLM, Embedding 모델, VectorDB 로써의 SingleStoreDB 를 모두 로컬 환경에 구성하고 사용해 보기에는 충분하리라고 생각합니다.

History

일자
작성자
비고
2026.04.07
mike
수정: GGUF 마이그레이션, langchain 패키지 업데이트, SingleStoreDB → SingleStoreVectorStore 변경, gcc-toolset-12 추가, 프롬프트 템플릿 변경, retriever k=3→5 변경