카테고리 없음

llm엔진은 내부가 어떻게 구성되어 있나? 그리고 rag 구축시 vectordb와 llm은 어떻게 연결되고 수정하여 저장하는가?

3604 2026. 3. 18. 12:00
728x90

 

LLM 엔진의 내부 구성과 RAG 시스템에서 Vector DB와의 연결 방식에 대해 설명해 드리겠습니다.

1. LLM 엔진의 내부 구성

핵심 아키텍처 레이어

plain
┌─────────────────────────────────────────────────────────┐
│                    Application Layer                      │
│         (Chat Interface, API, Plugins, etc.)           │
├─────────────────────────────────────────────────────────┤
│                   Inference Engine                        │
│    (Token Generation, Sampling, Decoding Strategy)     │
├─────────────────────────────────────────────────────────┤
│                    Model Core                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐ │
│  │   Tokenizer │  │  Transformer│  │  Attention      │ │
│  │   (BPE/SPM) │  │   Blocks    │  │  Mechanism      │ │
│  └─────────────┘  └─────────────┘  └─────────────────┘ │
├─────────────────────────────────────────────────────────┤
│                   Model Weights                           │
│    (Parameters: 7B/13B/70B+ stored in GPU/TPU Memory)   │
├─────────────────────────────────────────────────────────┤
│                    Hardware Layer                         │
│         (GPU/TPU/CPU Compute + High-bandwidth Memory)   │
└─────────────────────────────────────────────────────────┘

주요 구성 요소 상세

구성 요소 설명
Tokenizer 텍스트 → 토큰 ID 변환 (BPE, SentencePiece, TikToken 등)
Embedding Layer 토큰 ID → 고차원 벡터 (차원: 768~8192)
Transformer Blocks Multi-Head Attention + Feed-Forward Network 반복
Attention Mechanism Self-Attention, Cross-Attention, KV-Cache 관리
LM Head 최종 출력을 vocabulary 확률 분포로 변환
Sampling Engine Temperature, Top-p, Top-k 등으로 토큰 선택

2. RAG 시스템: Vector DB ↔ LLM 연결 구조

전체 아키텍처 플로우

plain
┌─────────────────────────────────────────────────────────────────┐
│                         User Query                               │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 1: Query Embedding (Same model used for document indexing) │
│  ┌─────────────┐    ┌─────────────────┐    ┌─────────────────┐ │
│  │   Query     │───▶│  Embedding      │───▶│  Dense Vector   │ │
│  │   Text      │    │  Model (384/768/│    │  (Query Vector) │ │
│  │             │    │  1024/1536 dim) │    │                 │ │
│  └─────────────┘    └─────────────────┘    └─────────────────┘ │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 2: Vector Search (Similarity Retrieval)                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    Vector Database                       │    │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │    │
│  │  │   HNSW      │  │   IVF/PQ    │  │   Metadata      │  │    │
│  │  │   Index     │  │   Index     │  │   Store         │  │    │
│  │  └─────────────┘  └─────────────┘  └─────────────────┘  │    │
│  │                                                           │    │
│  │  Operation: ANN Search (Approximate Nearest Neighbor)     │    │
│  │  Metric: Cosine Similarity / Euclidean / Dot Product        │    │
│  │  Return: Top-K similar vectors + metadata                 │    │
│  └─────────────────────────────────────────────────────────┘    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 3: Context Assembly (Retrieved Documents)                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  Retrieved Chunks:                                        │    │
│  │  [Chunk A] "Relevant text segment 1..." (score: 0.92)    │    │
│  │  [Chunk B] "Relevant text segment 2..." (score: 0.87)    │    │
│  │  [Chunk C] "Relevant text segment 3..." (score: 0.81)    │    │
│  │                                                           │    │
│  │  Assembly Strategy:                                       │    │
│  │  • Reranking (Cross-encoder for precision)               │    │
│  │  • Context window fitting (respect token limit)          │    │
│  │  • Metadata injection (source, date, etc.)               │    │
│  └─────────────────────────────────────────────────────────┘    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 4: Prompt Engineering (Augmented Input)                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  System Prompt: "You are a helpful assistant. Use the   │    │
│  │  following context to answer accurately."                 │    │
│  │                                                           │    │
│  │  Context:                                                 │    │
│  │  ┌─────────────────────────────────────────────────┐      │    │
│  │  │ [Document 1] Title: ... Content: ...            │      │    │
│  │  │ [Document 2] Title: ... Content: ...            │      │    │
│  │  │ [Document 3] Title: ... Content: ...            │      │    │
│  │  └─────────────────────────────────────────────────┘      │    │
│  │                                                           │    │
│  │  User Question: {original_query}                          │    │
│  └─────────────────────────────────────────────────────────┘    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 5: LLM Generation                                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    LLM Engine                            │    │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐    │    │
│  │  │  Input  │─▶│Attention│─▶│  FFN    │─▶│ Output  │    │    │
│  │  │Embedding│  │ Layers  │  │ Layers  │  │  Head   │    │    │
│  │  │         │  │(Context+│  │         │  │         │    │    │
│  │  │         │  │ Query)  │  │         │  │         │    │    │
│  │  └─────────┘  └─────────┘  └─────────┘  └─────────┘    │    │
│  │                                                           │    │
│  │  Output: "Based on the provided documents..."            │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

3. Vector DB 데이터 수정 및 저장 메커니즘

데이터 흐름 다이어그램

plain

 

┌─────────────────────────────────────────────────────────────────┐
│                    Data Ingestion Pipeline                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐ │
│  │   Raw       │───▶│   Chunking  │───▶│   Embedding         │ │
│  │   Documents │    │   Strategy  │    │   Generation        │ │
│  │  (PDF/HTML/ │    │             │    │                     │ │
│  │   TXT/JSON) │    │ • Fixed size│    │ • Sentence-Transform│ │
│  │             │    │ • Semantic  │    │ • OpenAI text-      │ │
│  │             │    │ • Recursive │    │   embedding-3       │ │
│  │             │    │ • Sliding   │    │ • Custom models      │ │
│  └─────────────┘    │   window    │    │                     │ │
│                     └─────────────┘    └─────────────────────┘ │
│                                                   │              │
│                                                   ▼              │
│                              ┌────────────────────────────────┐ │
│                              │      Vector DB Write Path       │ │
│                              │  ┌──────────────────────────┐  │ │
│                              │  │  1. Vector Validation    │  │ │
│                              │  │     (dimension check)    │  │ │
│                              │  ├──────────────────────────┤  │ │
│                              │  │  2. Index Update           │  │ │
│                              │  │     • HNSW graph update  │  │ │
│                              │  │     • IVF cluster assign │  │ │
│                              │  ├──────────────────────────┤  │ │
│                              │  │  3. Metadata Persistence   │  │ │
│                              │  │     • ID mapping         │  │ │
│                              │  │     • Source tracking    │  │ │
│                              │  │     • Timestamp          │  │ │
│                              │  └──────────────────────────┘  │ │
│                              └────────────────────────────────┘ │
│                                                   │              │
│                                                   ▼              │
│                              ┌────────────────────────────────┐ │
│                              │    Storage Backend (Persistent)  │ │
│                              │  ┌────────────┐ ┌────────────┐ │ │
│                              │  │  Parquet/  │ │   WAL/     │ │ │
│                              │  │  Arrow     │ │   Journal  │ │ │
│                              │  │  (Vectors) │ │   (Logs)   │ │ │
│                              │  └────────────┘ └────────────┘ │ │
│                              └────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

주요 Vector DB별 수정 API

Vector DB 삽입 업데이트 삭제 특징
Pinecone upsert() upsert() (same ID) delete() 관리형, 실시간
Weaviate data_object.create() data_object.update() data_object.delete() GraphQL 지원
Chroma collection.add() collection.update() collection.delete() 로컬 임베디드
Milvus insert() upsert() delete() 분산형, 대규모
Qdrant upsert_points() 같은 API delete_points() Rust 기반, 고성능
pgvector INSERT UPDATE DELETE PostgreSQL 확장

4. 코드 예시: RAG 파이프라인 구현

Python 구현 예시 (LangChain + Chroma)

Python
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# 1. 임베딩 모델 초기화
embedding_model = OpenAIEmbeddings(model="text-embedding-3-large")

# 2. Vector DB 생성/연결
vectorstore = Chroma(
    collection_name="my_knowledge",
    embedding_function=embedding_model,
    persist_directory="./chroma_db"  # 로컬 저장 경로
)

# 3. 문서 추가 (자동 임베딩 + 저장)
texts = ["문서 내용 1...", "문서 내용 2...", "문서 내용 3..."]
metadatas = [{"source": "doc1.pdf"}, {"source": "doc2.pdf"}]
ids = ["chunk_001", "chunk_002", "chunk_003"]

vectorstore.add_texts(
    texts=texts,
    metadatas=metadatas,
    ids=ids
)

# 4. 문서 업데이트 (동일 ID로 upsert)
vectorstore.update_document(
    document_id="chunk_001",
    document="수정된 새로운 내용..."
)

# 5. 검색-증강-생성 체인 구성
llm = ChatOpenAI(model="gpt-4", temperature=0)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # 또는 "map_reduce", "refine"
    retriever=vectorstore.as_retriever(
        search_type="similarity",
        search_kwargs={"k": 5}  # Top-5 검색
    ),
    return_source_documents=True
)

# 6. 실행
result = qa_chain({"query": "사용자 질문?"})
print(result["result"])
print(result["source_documents"])  # 출처 문서 확인

고급 RAG 패턴: Self-Query + Rerank

Python
from langchain.retrievers import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo

# 메타데이터 필터링 자동화
metadata_field_info = [
    AttributeInfo(
        name="source",
        description="문서 출처 파일명",
        type="string",
    ),
    AttributeInfo(
        name="date",
        description="문서 생성 날짜",
        type="string",
    ),
]

self_query_retriever = SelfQueryRetriever.from_llm(
    llm=llm,
    vectorstore=vectorstore,
    document_contents="기술 문서 내용",
    metadata_field_info=metadata_field_info,
)

# Reranking (Cross-encoder로 정밀도 향상)
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')

# 검색 → 재정렬 → 상위 3개 선택
docs = self_query_retriever.get_relevant_documents(query)
pairs = [[query, doc.page_content] for doc in docs]
scores = reranker.predict(pairs)
top_docs = [doc for _, doc in sorted(zip(scores, docs), reverse=True)[:3]]

5. 핵심 연결 포인트 요약

단계 Vector DB 역할 LLM 역할 데이터 흐름
Indexing 벡터 + 메타데이터 저장 임베딩 모델 제공 Doc → Embedding → Vector DB
Retrieval 유사도 검색 실행 - Query Vector → ANN Search → Chunks
Augmentation 검색 결과 제공 컨텍스트 조립 Chunks + Query → Prompt
Generation - 답변 생성 Prompt → LLM → Response
이 구조를 통해 LLM은 학습하지 않은 최신 정보나 사설 문서를 Vector DB에서 검색하여 활용할 수 있으며, 문서가 업데이트되면 Vector DB만 갱신하면 즉시 반영됩니다.
 
 
 
 
 
[참고] Tokenizer란
 

Tokenizer는 LLM의 입력 게이트 역할을 하는 핵심 구성 요소입니다. 자연어 텍스트를 모델이 이해할 수 있는 숫자 형태(토큰 ID)로 변환하는 인코더입니다.


Tokenizer의 핵심 역할

plain
Copy
┌─────────────────────────────────────────────────────────────┐
│  자연어 텍스트  ──▶  Tokenizer  ──▶  토큰 ID 시퀀스  ──▶  LLM  │
│                                                             │
│  "Hello world"    [15496, 995]      Embedding Layer       │
│  "안녕하세요"      [12345, 6789]      ↓                     │
│                                    Transformer 처리        │
└─────────────────────────────────────────────────────────────┘

동작 원리: 3단계 파이프라인

1. 정규화 (Normalization)

Python
Copy
# 입력 텍스트 전처리
"Hello!" → "hello"  # 소문자화, 특수문자 처리
"  여러   공백  " → "여러 공백"  # 공백 정규화

2. 토큰화 (Tokenization)

텍스트를 서브워드 단위로 분할합니다:
알고리즘 방식 예시
BPE (Byte-Pair Encoding) 빈도 기반 병합 low  low, lower  low + er
WordPiece 확률 기반 병합 playing  play + ##ing
SentencePiece 공백 독립 처리 _Hello  _ + He + ll + o
Unigram 확률 모델 기반 후보 중 최적 선택
TikToken (GPT-4) BPE 최적화 바이트 기반 정규 BPE
실제 분할 예시:
plain
Input:  "Tokenization"
BPE:     ["Token", "ization"]           # 2 토큰
TikToken: ["Token", "iz", "ation"]       # 3 토큰

3. 인덱싱 (Indexing)

분할된 토큰을 고유 정수 ID로 매핑:
Python
vocab = {
    "Token": 15496,
    "ization": 328,
    "iz": 892,
    "ation": 441,
    "<|endoftext|>": 50256  # 특수 토큰
}

주요 Tokenizer 비교

모델 Tokenizer 어휘 크기 특징
GPT-2/3 BPE 50,257 바이트 기반, 영어 최적화
GPT-4 TikToken (cl100k_base) 100,256 다국어 개선, 효율적
BERT WordPiece 30,522 양방향, ## 접두사
T5 SentencePiece 32,000 공백 보존, _ 표시
LLaMA 2 BPE (SentencePiece 기반) 32,000 다국어 확장
LLaMA 3 TikToken 유사 128,256 15개 언어 최적화
Claude BPE 변형 미공개 안전 토큰 포함
KoGPT BPE + 한국어 52,000 한국어 형태소 고려

토큰화 실제 예시

Python
import tiktoken

# GPT-4 Tokenizer
enc = tiktoken.encoding_for_model("gpt-4")

text = "Tokenizer는 텍스트를 숫자로 변환합니다."
tokens = enc.encode(text)
print(f"토큰 IDs: {tokens}")
print(f"토큰 수: {len(tokens)}")

# 디코딩 확인
decoded = [enc.decode_single_token_bytes(t) for t in tokens]
print(f"토큰 분할: {decoded}")
출력:
plain
토큰 IDs: [31347, 119, 243, 108, 255, 245, 102, 11, 251, 114, ...]
토큰 수: 14
토큰 분할: [b'Token', b'izer', b'\xeb\x8a\x94', b' \xed\x85\x8d', ...]

중요 개념: 토큰 vs 문자

구분 설명 예시
문자 글자 단위 "가" = 1 문자
토큰 의미 단위 "Tokenization" = 3~4 토큰
바이트 최소 단위 "가" = 3 바이트 (UTF-8)
주의: 영어는 1단어 ≈ 1.3토큰, 한국어/중국어는 1글자 ≈ 2~3토큰 (비효율적)

특수 토큰 (Special Tokens)

plain
<|endoftext|>     : 문서 종료 (GPT)
[CLS]             : 분류 시작 (BERT)
[SEP]             : 문장 구분 (BERT)
[MASK]            : 마스킹 위치 (BERT)
[PAD]             : 시퀀스 패딩
<s>, </s>         : 문장 시작/끝 (T5, LLaMA)
<|im_start|>      : 대화 시작 (ChatML)
<|tool_call|>     : 도구 호출 (함수 호출)

Tokenizer 선택의 영향

측면 영향
어휘 크기 클수록 희귀어 처리 ↑, 메모리 ↑
토큰 길이 짧을수록 처리 속도 ↑, 의미 손실 ↑
언어 커버리지 다국어 토큰화 효율성 차이
비용 API 과금 = 토큰 수 기준
핵심: Tokenizer는 LLM의 "입력 알파벳"을 정의합니다. 같은 모델이라도 Tokenizer가 다르면 완전히 다른 입력이 됩니다.
728x90