블로그 이미지
Peter Note
Web & LLM FullStacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2024. 8. 9. 13:25 [LLM FullStacker]/Python

importfrom 키워드는 파이썬에서 모듈과 그 모듈 내의 특정 항목을 가져오는 데 사용됩니다. 각각의 기능과 사용할 수 있는 것들을 정리하면 다음과 같습니다:

import 키워드

import는 전체 모듈을 가져옵니다. 가져온 모듈의 이름을 통해 해당 모듈에 정의된 함수, 클래스, 변수 등을 사용할 수 있습니다.

import module_name

import로 가져올 수 있는 것들:

  • 파이썬 표준 라이브러리 모듈: 예를 들어, import os, import sys, import math 등.
  • 사용자 정의 모듈: 사용자가 만든 .py 파일을 가져올 수 있습니다. 예를 들어, import my_module.
  • 서드 파티 라이브러리 모듈: 설치된 서드 파티 패키지를 가져올 수 있습니다. 예를 들어, import numpy, import pandas.

from 키워드

from은 모듈 내의 특정 항목을 직접 가져올 때 사용됩니다. 이를 통해 모듈 이름 없이도 해당 항목을 직접 사용할 수 있습니다.

from module_name import specific_item

from으로 정의할 수 있는 것들:

  • 모듈 내의 특정 함수: 예를 들어, from math import sqrtsqrt 함수를 직접 사용할 수 있게 합니다.
  • 모듈 내의 특정 클래스: 예를 들어, from datetime import datetimedatetime 클래스를 직접 사용할 수 있게 합니다.
  • 모듈 내의 특정 변수: 예를 들어, from config import config_valueconfig_value라는 변수를 가져올 수 있게 합니다.
  • 모듈 내의 모든 항목: from module_name import *를 사용하면 모듈 내의 모든 공개된 항목을 가져올 수 있습니다. 하지만, 이 방식은 권장되지 않습니다.

예시

import math  # math 모듈을 가져옴
print(math.sqrt(16))  # math 모듈을 통해 sqrt 함수 호출

from math import sqrt  # math 모듈에서 sqrt 함수만 가져옴
print(sqrt(16))  # 모듈 이름 없이 sqrt 함수 호출

from my_module import my_function  # my_module 모듈에서 my_function 함수만 가져옴
my_function()  # 직접 함수 호출

importfrom 키워드를 적절히 사용하면 코드의 가독성과 효율성을 높일 수 있습니다. written by GPT

posted by Peter Note

임베딩을 통해 실수(float) 벡터값은 Vector Store에 저장을 한다. 그리고 사용자의 Query에 대해서도 벡터로 변환하여 Vector Store에 Sematic Search를 한다.

출처: DeepLearning.ai

 

유사도가 높은 문서뭉치들을 프롬프트에 담아 LLM에 요청한다. 

출처: DeepLearning.ai

 

 

패키지

vectorstores 패키지는 langchain.vectorstores 패키지에서 langchain_community.vectorstores 패키지의 모듈을 re-export 하고 있다. 

 

- 70 개가량의 벡터 저장소 구현체를 제공한다. https://python.langchain.com/v0.2/docs/integrations/vectorstores/

 

Vector stores | 🦜️🔗 LangChain

📄️ Hippo Transwarp Hippo is an enterprise-level cloud-native distributed vector database that supports storage, retrieval, and management of massive vector-based datasets. It efficiently solves problems such as vector similarity search and high-densit

python.langchain.com

 

- 가장 많이 사용하는 것은 FAISS, Chroma 등이다. 

 

Chroma 패키지는 내부적으로 chromadb 패키지를 사용하여 LangChain과 연동시켜주는 인터페이스이다.

- VectoreStore 생성시 "embedding_function", "collection_name"을 지정할 수 있다. 

from chromadb import Client
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# 1. OpenAI Embeddings 초기화
openai_embedding = OpenAIEmbeddings()

# 2. Chroma 벡터스토어 클라이언트 생성
client = Client()

# 3. Chroma 벡터스토어 생성
vectorstore = Chroma(
    embedding_function=openai_embedding,  # OpenAI Embedding 사용
    collection_name="my_openai_collection",  # 컬렉션 이름
    client=client                           # Chroma 클라이언트
)

# 4. 데이터 추가
documents = ["This is a test document.", "Another document for testing."]
vectorstore.add_texts(texts=documents)

# 5. 데이터 검색
query = "test"
results = vectorstore.similarity_search(query, k=2)

# 6. 검색 결과 출력
for result in results:
    print(f"Document: {result.page_content}, Score: {result.score}")

 

또는 from_documents 클래스메서드를 이용하여 호출한다. 

- SentenceTransformerEmbeddings 는 내부적으로 HuggingFaceEmbeddings 을 사용하고 디폴디 임베딩 모델로 "BAAI/bge-large-en"을 사용한다. 

- load() --> split_documents() --> from_documents() 를 통해서 

# import
from langchain_community.document_loaders import TextLoader
from langchain_community.embeddings.sentence_transformer import (
    SentenceTransformerEmbeddings,
)
from langchain_community.vectorstores import Chroma
from langchain_text_splitters import CharacterTextSplitter

# 문서를 로드하고 청크로 분할합니다.
loader = TextLoader("./data/appendix-keywords.txt")
documents = loader.load()

# 문서를 청크로 분할합니다.
text_splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

# 오픈 소스 임베딩 함수를 생성합니다.
stf_embeddings = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")

# Chroma에 로드합니다.
db = Chroma.from_documents(docs, stf_embeddings)

# 질의합니다.
query = "What is Word2Vec?"
docs = db.similarity_search(query)

# 결과를 출력합니다.
print(docs[0].page_content)

 

API

VectorStore 드라이버 구현체는 langchain_core의 VectoreStore를 상속받아 구현한다. 

 

- VectorStore 를 상속받아 __init__ 구현 

 class Chroma(VectorStore):  
   def __init__(
        self,
        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,
        embedding_function: Optional[Embeddings] = None,
        persist_directory: Optional[str] = None,
        client_settings: Optional[chromadb.config.Settings] = None,
        collection_metadata: Optional[Dict] = None,
        client: Optional[chromadb.Client] = None,
        relevance_score_fn: Optional[Callable[[float], float]] = None,
    ) -> None:
        """Initialize with a Chroma client."""
        try:
            import chromadb
            import chromadb.config
        except ImportError:
            raise ImportError(
                "Could not import chromadb python package. "
                "Please install it with `pip install chromadb`."
            )

        if client is not None:
            self._client_settings = client_settings
            self._client = client
            self._persist_directory = persist_directory
        else:
            if client_settings:
                # If client_settings is provided with persist_directory specified,
                # then it is "in-memory and persisting to disk" mode.
                client_settings.persist_directory = (
                    persist_directory or client_settings.persist_directory
                )
                if client_settings.persist_directory is not None:
                    # Maintain backwards compatibility with chromadb < 0.4.0
                    major, minor, _ = chromadb.__version__.split(".")
                    if int(major) == 0 and int(minor) < 4:
                        client_settings.chroma_db_impl = "duckdb+parquet"

                _client_settings = client_settings
            elif persist_directory:
                # Maintain backwards compatibility with chromadb < 0.4.0
                major, minor, _ = chromadb.__version__.split(".")
                if int(major) == 0 and int(minor) < 4:
                    _client_settings = chromadb.config.Settings(
                        chroma_db_impl="duckdb+parquet",
                    )
                else:
                    _client_settings = chromadb.config.Settings(is_persistent=True)
                _client_settings.persist_directory = persist_directory
            else:
                _client_settings = chromadb.config.Settings()
            self._client_settings = _client_settings
            self._client = chromadb.Client(_client_settings)
            self._persist_directory = (
                _client_settings.persist_directory or persist_directory
            )

        self._embedding_function = embedding_function
        self._collection = self._client.get_or_create_collection(
            name=collection_name,
            embedding_function=None,
            metadata=collection_metadata,
        )
        self.override_relevance_score_fn = relevance_score_fn

 

- from_documents 는 classmethod 이면서 벡터객체를 반환한다.

   - documents: splitted 된 document 리스트

   - embedding: embedding model 인스턴스

    @classmethod
    def from_documents(
        cls: Type[VST],
        documents: List[Document],
        embedding: Embeddings,
        **kwargs: Any,
    ) -> VST:
        """Return VectorStore initialized from documents and embeddings.

        Args:
            documents: List of Documents to add to the vectorstore.
            embedding: Embedding function to use.
            **kwargs: Additional keyword arguments.

        Returns:
            VectorStore: VectorStore initialized from documents and embeddings.
        """
        texts = [d.page_content for d in documents]
        metadatas = [d.metadata for d in documents]
        return cls.from_texts(texts, embedding, metadatas=metadatas, **kwargs)

내부에서 클래스메서드인 from_texts를 호출한다. from_texts는 abstractmethod로 각 vectorstore에서 구현한다. 

    @classmethod
    @abstractmethod
    def from_texts(
        cls: Type[VST],
        texts: List[str],
        embedding: Embeddings,
        metadatas: Optional[List[dict]] = None,
        **kwargs: Any,
    ) -> VST:
        """Return VectorStore initialized from texts and embeddings.

        Args:
            texts: Texts to add to the vectorstore.
            embedding: Embedding function to use.
            metadatas: Optional list of metadatas associated with the texts.
                Default is None.
            kwargs: Additional keyword arguments.

        Returns:
            VectorStore: VectorStore initialized from texts and embeddings.
        """

 

 

- similarity_search 는 abstractmethod로 각 vectorstore에서 구현을 해야 한다. 

    @abstractmethod
    def similarity_search(
        self, query: str, k: int = 4, **kwargs: Any
    ) -> List[Document]:
        """Return docs most similar to query.

        Args:
            query: Input text.
            k: Number of Documents to return. Defaults to 4.
            **kwargs: Arguments to pass to the search method.

        Returns:
            List of Documents most similar to the query.
        """

 

- search 는 검색 타입을 선택한다. "similarity", "similarity_score_threshold", "mmr" 등이 있다. 

  - 반환값은 List[Document] 이다. 

    def search(self, query: str, search_type: str, **kwargs: Any) -> List[Document]:
        """Return docs most similar to query using a specified search type.

        Args:
            query: Input text
            search_type: Type of search to perform. Can be "similarity",
                "mmr", or "similarity_score_threshold".
            **kwargs: Arguments to pass to the search method.

        Returns:
            List of Documents most similar to the query.

        Raises:
            ValueError: If search_type is not one of "similarity",
                "mmr", or "similarity_score_threshold".
        """
        if search_type == "similarity":
            return self.similarity_search(query, **kwargs)
        elif search_type == "similarity_score_threshold":
            docs_and_similarities = self.similarity_search_with_relevance_scores(
                query, **kwargs
            )
            return [doc for doc, _ in docs_and_similarities]
        elif search_type == "mmr":
            return self.max_marginal_relevance_search(query, **kwargs)
        else:
            raise ValueError(
                f"search_type of {search_type} not allowed. Expected "
                "search_type to be 'similarity', 'similarity_score_threshold'"
                " or 'mmr'."
            )

 

 

- as_retriever 는 VectorStore 에는 VectorStoreRetriever 를 생성하여 반환한다. 

def as_retriever(self, **kwargs: Any) -> VectorStoreRetriever:

 

Retriever 에 대해 다음 글에서 살펴보자. 

 

 

<참조>

- API: https://api.python.langchain.com/en/latest/community_api_reference.html#module-langchain_community.vectorstores

- 공식문서: https://python.langchain.com/v0.2/docs/integrations/vectorstores/

 

Vector stores | 🦜️🔗 LangChain

📄️ Hippo Transwarp Hippo is an enterprise-level cloud-native distributed vector database that supports storage, retrieval, and management of massive vector-based datasets. It efficiently solves problems such as vector similarity search and high-densit

python.langchain.com

- LangChain KR: https://wikidocs.net/234013

 

01. 벡터저장소(VectorStore) 사용법 톺아보기

.custom { background-color: #008d8d; color: white; padding: 0.25em 0.5…

wikidocs.net

 

posted by Peter Note

출처: langchain embedding

개념

텍스트 임베딩은 텍스트 조각을 벡터 수치로 생성한다. 텍스트 임베딩 구현체는 LLM 관련 업체를 통해 제공된다. 예로 들면 J2EE에서 JDBC 스펙을 정의하면, Oracle에서 Oracle JDBC 구현 드라이브 라이브러리를 제공하는 방식이다. LangChain이 임베팅 스펙 인터페이스를 만들고, 파트너사가 임베딩 구현체를 제공한다. (구현체를 LangChain 에서 직접 만들었을 수도 있다.)

 

텍스트 임베딩 모델을 통해서 백터 공간을 만드는 목적은 "Semantic Search"시에 말뭉치 쿼리에 대해 벡터 공간에서 유사성 검색이 효율적이기 때문이다.

출처: DeepLearning.ai

 

 

먼저 임베딩 모델 과 의미적 검색에 대한 개념을 살펴보자.


임베딩과 임베딩 모델 이해

"임베딩" 과 "임베딩 모델"은 다른 의미를 내포하고 있다. LangChain의 Embedding models 원문 참조

 

Embedding models create a vector representation of a piece of text. You can think of a vector as an array of numbers that captures the semantic meaning of the text. By representing the text in this way, you can perform mathematical operations that allow you to do things like search for other pieces of text that are most similar in meaning. These natural language search capabilities underpin many types of context retrieval, where we provide an LLM with the relevant data it needs to effectively respond to a query.

 

 

1) 임베딩 (Embedding)

 

임베딩은 단어, 문장 또는 문서와 같은 텍스트 데이터를 고정된 크기의 벡터로 변환하는 과정 또는 결과를 의미합니다. 이 벡터는 원본 텍스트의 의미를 숫자 형태로 표현하여 기계 학습 모델이 이해하고 처리할 수 있도록 합니다. 임베딩은 다양한 NLP 작업에서 사용되며, 유사성 계산, 분류, 군집화, 검색 등 여러 응용 분야에서 중요한 역할을 합니다.

 

특징:

 

고정 크기 벡터: 텍스트 데이터를 고정된 크기의 숫자 벡터로 변환합니다.

의미 보존: 텍스트의 의미와 문맥 정보를 벡터에 포함시킵니다.

유사성 계산: 벡터 간의 유사성을 계산하여 텍스트 간의 관계를 파악할 수 있습니다.

 

예시:

embedding = [0.1, 0.2, 0.3, 0.4, 0.5]  # "example"이라는 단어의 임베딩 벡터

 

2) 임베딩 모델 (Embedding Model)

 

임베딩 모델은 텍스트 데이터를 임베딩 벡터로 변환하는 알고리즘이나 기계 학습 모델을 의미합니다. 이 모델은 대량의 텍스트 데이터를 학습하여 각 단어, 문장 또는 문서에 대해 적절한 임베딩을 생성하는 방법을 배웁니다. 임베딩 모델은 일반적으로 기계 학습 또는 딥러닝 기술을 사용하여 구현됩니다.

 

특징:

 

학습된 모델: 대규모 텍스트 데이터셋을 학습하여 임베딩을 생성하는 방법을 배웁니다.

다양한 아키텍처: Word2Vec, GloVe, BERT, GPT 등 다양한 아키텍처가 존재합니다.

응용 분야: 자연어 처리(NLP), 정보 검색, 텍스트 분류 등 다양한 분야에서 사용됩니다.

 

예시:

from transformers import BertModel, BertTokenizer

# BERT 임베딩 모델 로드
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')

# 텍스트를 임베딩 벡터로 변환
text = "example sentence"
inputs = tokenizer(text, return_tensors='pt')
outputs = model(**inputs)
embedding = outputs.last_hidden_state

 

요약

임베딩 (Embedding): 텍스트 데이터를 고정된 크기의 벡터로 변환한 결과. 예를 들어, 단어 “example”의 벡터 표현 [0.1, 0.2, 0.3, 0.4, 0.5].

임베딩 모델 (Embedding Model): 텍스트 데이터를 임베딩 벡터로 변환하는 알고리즘이나 기계 학습 모델. 예를 들어, BERT, Word2Vec 등.

 

임베딩은 데이터를 벡터로 표현하는 결과를 말하고, 임베딩 모델은 이러한 벡터를 생성하는 알고리즘이나 모델을 의미한다.

written by GPT

 

다음글에서 임베딩 모델에 대한 상세 설명을 참조하자. 

https://brunch.co.kr/@harryban0917/209

 

LLM과 자연어처리의 역사(2)

임베딩(Embedding) 모델이란? | 지난 시간(LLM과 자연어처리의 역사(1))에서는 원핫 인코딩(one-hot encoding)과 BoW(Bag-of-Words)라는 개념을 살펴봤다. 이를 통해 컴퓨터가 인간의 언어를 0과 1의 이진수로 변

brunch.co.kr

https://brunch.co.kr/@harryban0917/210

 

LLM과 자연어처리의 역사(3)

통계학의 한계와 딥러닝 기반 언어모델의 등장 | 1. 기존 임베딩 방식의 한계점과 딥러닝 모델의 필요성 지난 시간(LLM과 자연어처리의 역사(2))까지 컴퓨터가 단순히 단어의 등장 횟수와 0과 1의

brunch.co.kr

 

 

의미적 검색(Semantic Search)란?

의미적 검색(Semantic Search)은 단순히 키워드 일치에 기반한 전통적인 검색 방식과 달리, 검색 쿼리와 문서의 의미를 이해하고 이를 기반으로 관련 결과를 반환하는 검색 방식을 말합니다. 이는 자연어 처리와 기계 학습 기술을 활용하여 문장의 맥락과 의미를 파악하고, 사용자 의도를 더 잘 이해하여 보다 정확한 검색 결과를 제공합니다.

 

의미적 검색의 주요 특징

 

1. 의도 이해: 단순한 키워드가 아닌 사용자의 검색 의도를 이해합니다. 예를 들어, “서울에서 맛있는 음식점”을 검색하면 “서울의 맛집 추천”과 같은 유사한 의미의 결과를 반환합니다.

2. 문맥 파악: 검색 쿼리와 문서의 전체 문맥을 분석하여 관련성 높은 결과를 도출합니다. 단어의 위치나 사용 방식에 따라 다른 의미를 가질 수 있는 경우에도 이를 이해합니다.

3. 동의어 및 관련어 처리: 동의어나 유사어를 인식하여 더 포괄적인 검색 결과를 제공합니다. 예를 들어, “자동차”를 검색했을 때 “차량”이라는 단어가 포함된 문서도 검색 결과에 포함될 수 있습니다.

 

의미적 검색의 예시

 

기존의 키워드 검색에서는 “애플 제품”이라는 쿼리에 대해 “애플”과 “제품”이라는 단어가 정확히 포함된 문서만 반환할 가능성이 높습니다. 반면 의미적 검색에서는 “애플이 만든 기기”, “애플이 출시한 최신 제품” 등과 같이 단어는 다르지만 의미가 유사한 문서도 결과에 포함될 수 있습니다.

 

의미적 검색의 구현

 

의미적 검색을 구현하기 위해 일반적으로 다음과 같은 기술이 사용됩니다:

 

1. 임베딩(Embedding): 단어, 문장 또는 문서를 벡터 형태로 변환하여 의미적 유사성을 계산할 수 있도록 합니다.

2. 벡터 검색(Vector Search): 쿼리와 문서의 벡터를 비교하여 유사한 벡터를 가진 문서를 검색합니다.

3. 자연어 처리(NLP) 모델: BERT, GPT 등과 같은 최신 언어 모델을 사용하여 문장의 의미를 이해하고 임베딩을 생성합니다.

 

LangChaind을 사용하여 의미적 검색을 구현한 예시를 보자.

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.document_loaders import TextLoader

# 문서 로드
documents = TextLoader("path_to_documents").load()

# 임베딩 모델 초기화
embeddings = OpenAIEmbeddings()

# 벡터 스토어에 임베딩 저장
# from_documents를 호출하면 내부에서 embed_documents을 호출하고 있다. 
# 참조) https://github.com/langchain-ai/langchain/blob/master/libs/community/langchain_community/vectorstores/faiss.py#L1039
# document_embeddings = embeddings.embed_documents(documents)
vector_store = FAISS.from_documents(documents, embeddings)

# 벡터 스토어 쿼리
query = "서울에서 맛있는 음식점 추천"
query_embedding = embeddings.embed_query(query)
results = vector_store.similarity_search(query_embedding)

print(results)

이 예시에서는 텍스트 문서를 임베딩하여 벡터로 변환하고, 검색 쿼리도 임베딩하여 벡터 스토어에서 유사한 문서를 검색합니다. 이를 통해 쿼리와 의미적으로 관련된 문서를 효율적으로 찾을 수 있다. written by GPT

 

패키지

임베딩 모델 구현체들 https://python.langchain.com/v0.2/docs/integrations/text_embedding/

 

Embedding models | 🦜️🔗 LangChain

Embedding model classes are implemented by inheriting the Embeddings class.

python.langchain.com

 

임베딩 구현체는 3가지 패키지 경로를 통해 import 할 수 있다. 

1)  langchain.embedding 패키지를 통한 방법: 내부적으로 langchain_community.embeddings 패키지를 re-export 한다.

from typing import TYPE_CHECKING, Any

from langchain._api import create_importer

if TYPE_CHECKING:
    from langchain_community.embeddings import OllamaEmbeddings

# Create a way to dynamically look up deprecated imports.
# Used to consolidate logic for raising deprecation warnings and
# handling optional imports.
DEPRECATED_LOOKUP = {"OllamaEmbeddings": "langchain_community.embeddings"}

_import_attribute = create_importer(__package__, deprecated_lookups=DEPRECATED_LOOKUP)


def __getattr__(name: str) -> Any:
    """Look up attributes dynamically."""
    return _import_attribute(name)


__all__ = [
    "OllamaEmbeddings",
]

 

2) langchain_community.embeddings 패키지를 통한 방법: 커뮤니티를 통해 구현된 구현체

3) partners 에서 제공하는 임베딩으로 예로 langchain_ollama.embeddings 모듈을 통한 방법: ollama 업체에서 구현한 구현체


참조) OllamaEmbeddings 의 2) 와 3) 에서 community와 partners에서 제공하는 구현체의 내용이 다르다. 

 

Langchain의 OllamaEmbeddings 모듈은 두 가지 다른 패키지에서 제공되며, 각기 다른 기능과 구현 방식을 가질 수 있습니다. 이 두 패키지는 langchain_communitylangchain_ollama입니다. 여기에서는 이 두 가지 모듈의 차이점을 설명하겠습니다.

 

1. langchain_community의 OllamaEmbeddings

 

langchain_community 패키지의 OllamaEmbeddings는 커뮤니티에서 개발된 통합을 포함합니다. 이 패키지는 다양한 써드파티 통합을 제공하며, 사용자가 필요에 맞게 쉽게 활용할 수 있도록 설계되었습니다. 이 패키지의 OllamaEmbeddings는 다음과 같은 특징을 가질 수 있습니다:

 

다양한 통합: 여러 벡터 스토어 및 임베딩 모델과의 통합을 제공합니다.

커뮤니티 지원: 오픈 소스 커뮤니티에 의해 유지 관리되며, 다양한 사용자 요구사항을 반영합니다.

 

2. langchain_ollama의 OllamaEmbeddings

 

langchain_ollama 패키지의 OllamaEmbeddings는 특정 벤더나 API와의 통합을 염두에 두고 설계된 경우가 많습니다. 이 패키지는 보다 특정한 기능이나 최적화를 제공할 수 있습니다. 예를 들어, 특정한 임베딩 모델이나 벡터 스토어에 최적화된 구현이 포함될 수 있습니다.

 

벤더 특화: 특정 벤더의 기술 스택에 최적화된 기능을 제공합니다.

고성능 최적화: 특정 사용 사례에 맞춘 최적화가 포함될 수 있습니다.

 

주요 차이점 요약

 

1. 목적과 통합 대상:

langchain_community는 다양한 통합을 지원하며, 커뮤니티에서 널리 사용되는 기능을 제공합니다.

langchain_ollama는 특정 벤더나 API와의 통합을 염두에 두고 설계되어, 특정 사용 사례에 최적화된 기능을 제공합니다.

2. 사용자 기반:

langchain_community는 오픈 소스 커뮤니티에 의해 유지 관리되며, 다양한 사용자 요구사항을 반영합니다.

langchain_ollama는 특정 벤더나 기술 스택을 사용하는 사용자에게 더 적합할 수 있습니다.

 

이와 같은 차이점 때문에, 사용자는 자신의 요구사항에 맞는 패키지를 선택하여 사용할 수 있습니다. 예를 들어, 다양한 임베딩 모델과의 통합이 필요하다면 langchain_community를, 특정 벤더의 최적화된 기능이 필요하다면 langchain_ollama를 선택하는 것이 좋습니다.

written by GPT

 

주의할 점)

langchain_community 의 OllamaEmbeddings 는 아직 deprecated 명시가 없지만, langchain_community에 있는 OpenAIEmbeddings는 deprecated 명시가 있기 때문에 langchain_openai 패키지를 설치하여 사용한다. 

// langchain_community
@deprecated(
    since="0.0.9",
    removal="0.3.0",
    alternative_import="langchain_openai.OpenAIEmbeddings",
)
class OpenAIEmbeddings(BaseModel, Embeddings):
  ...
  
// langchain_openai 패키지를 사용한다. 
class OpenAIEmbeddings(BaseModel, Embeddings):
    """OpenAI embedding models.

    To use, you should have the
    environment variable ``OPENAI_API_KEY`` set with your API key or pass it
    as a named parameter to the constructor.

    In order to use the library with Microsoft Azure endpoints, use
    AzureOpenAIEmbeddings.

    Example:
        .. code-block:: python

            from langchain_openai import OpenAIEmbeddings

            model = OpenAIEmbeddings(model="text-embedding-3-large")
    """

API

구현체의 이름은 <name>Embeddings 복수로 한다.

 

LangChain 에서는 langchain_core 패키지에 있는 Embedding 클래스에서 두가지 추상메소드를 구현토록 한다.

  - embed_documents : List[str] -> List[List[float]]

  - embed_query : str -> List[float]

class Embeddings(ABC):
    @abstractmethod
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """Embed search docs.

        Args:
            texts: List of text to embed.

        Returns:
            List of embeddings.
        """

    @abstractmethod
    def embed_query(self, text: str) -> List[float]:
        """Embed query text.

        Args:
            text: Text to embed.

        Returns:
            Embedding.
        """
    ... 중략 ...

 

 

다음 글에서는 임베딩 모델을 거쳐 벡터화된 값을 저장하는 VectorStore에 대해 살펴본다.

 

<참조>

- API: https://api.python.langchain.com/en/latest/langchain_api_reference.html#module-langchain.embeddings

- langchain_core의 Embedding 클래스: https://github.com/langchain-ai/langchain/blob/master/libs/core/langchain_core/embeddings/embeddings.py

 

langchain/libs/core/langchain_core/embeddings/embeddings.py at master · langchain-ai/langchain

🦜🔗 Build context-aware reasoning applications. Contribute to langchain-ai/langchain development by creating an account on GitHub.

github.com

- LangChain embedding 설명글: https://python.langchain.com/v0.2/docs/concepts/#embedding-models

 

Conceptual guide | 🦜️🔗 LangChain

This section contains introductions to key parts of LangChain.

python.langchain.com

- text embedding 사용법: https://python.langchain.com/v0.2/docs/how_to/embed_text/

 

Text embedding models | 🦜️🔗 LangChain

Head to Integrations for documentation on built-in integrations with text embedding model providers.

python.langchain.com

- LangChain Tutorial 코스: https://python.langchain.com/v0.2/docs/additional_resources/tutorials/

 

3rd Party Tutorials | 🦜️🔗 LangChain

Tutorials

python.langchain.com

- 임베딩의 이해: https://www.syncly.kr/blog/what-is-embedding-and-how-to-use

 

Embedding이란 무엇이고, 어떻게 사용하는가? - 싱클리(Syncly)

본 글에서는, AI에서 중요하게 취급되는 개념 중 하나인 embedding에 대해서 알아보고자 합니다. 현재 Syncly에서도 Feedback Auto-Categorization, Sentiment Classification 등의 기능에 embedding이 활용되고 있습니

www.syncly.kr

- LangChain KR: https://wikidocs.net/233815

 

01. OpenAIEmbeddings

.custom { background-color: #008d8d; color: white; padding: 0.25em …

wikidocs.net

- 한글 임베딩 모델: https://github.com/Atipico1/Kor-IR

 

GitHub - Atipico1/Kor-IR: Kor-IR: Korean Information Retrieval Benchmark

Kor-IR: Korean Information Retrieval Benchmark. Contribute to Atipico1/Kor-IR development by creating an account on GitHub.

github.com

 

- 데이터셋: https://github.com/HeegyuKim/open-korean-instructions

 

GitHub - HeegyuKim/open-korean-instructions: 언어모델을 학습하기 위한 공개 한국어 instruction dataset들을 모

언어모델을 학습하기 위한 공개 한국어 instruction dataset들을 모아두었습니다. - HeegyuKim/open-korean-instructions

github.com

 

posted by Peter Note
2024. 8. 6. 23:13 [LLM FullStacker]/Python

클래스의 속성을 정의하는 여러 가지 방법을 소개해 드리겠습니다. 파이썬에서 클래스의 속성을 정의하는 방법에는 몇 가지가 있습니다. 각 방법은 특정 상황에서 유용할 수 있습니다.

클래스 변수와 속성의미

1. 클래스 변수 (Class Variables)

클래스 변수는 클래스 자체에 속하며, 모든 인스턴스에서 공유됩니다.

   class MyClass:
       class_variable = "I am a class variable"

   print(MyClass.class_variable)
   obj1 = MyClass()
   obj2 = MyClass()
   print(obj1.class_variable)
   print(obj2.class_variable)

2. 인스턴스 변수 (Instance Variables)

인스턴스 변수는 각 객체마다 개별적으로 유지되며, __init__ 메서드에서 초기화됩니다.

   class MyClass:
       def __init__(self, value):
           self.instance_variable = value

   obj1 = MyClass(1)
   obj2 = MyClass(2)
   print(obj1.instance_variable)  # 1
   print(obj2.instance_variable)  # 2

3. 프로퍼티 (Properties)

프로퍼티는 getter와 setter 메서드를 사용하여 속성의 접근 및 수정 방법을 제어할 수 있습니다.

   class MyClass:
       def __init__(self, value):
           self._value = value

       @property
       def value(self):
           return self._value

       @value.setter
       def value(self, new_value):
           if new_value < 0:
               raise ValueError("Value cannot be negative")
           self._value = new_value

   obj = MyClass(10)
   print(obj.value)  # 10
   obj.value = 20
   print(obj.value)  # 20
   # obj.value = -10  # ValueError 발생

4. 데코레이터를 사용한 클래스 속성 정의

@classmethod@staticmethod 데코레이터를 사용하여 클래스 메서드 및 정적 메서드를 정의할 수 있습니다.

   class MyClass:
       class_variable = 0

       @classmethod
       def increment_class_variable(cls):
           cls.class_variable += 1

       @staticmethod
       def static_method():
           print("This is a static method")

   MyClass.increment_class_variable()
   print(MyClass.class_variable)  # 1
   MyClass.static_method()  # This is a static method

5. 데이터 클래스 (Data Classes)

파이썬 3.7부터 도입된 데이터 클래스는 기본적인 속성 및 메서드를 자동으로 생성해줍니다.

   from dataclasses import dataclass

   @dataclass
   class MyClass:
       attribute1: int
       attribute2: str

   obj = MyClass(1, "hello")
   print(obj.attribute1)  # 1
   print(obj.attribute2)  # hello

이와 같은 방법들을 통해 파이썬 클래스의 속성을 정의하고 사용할 수 있습니다. 각 방법은 특정 상황에서 유용하며, 필요에 따라 적절한 방법을 선택하여 사용할 수 있습니다.


인스턴스 변수 와 속성의 차이점

클래스의 인스턴스 변수와 속성은 비슷하지만, 약간의 차이점이 있습니다. 인스턴스 변수는 클래스의 각 인스턴스에서 개별적으로 유지되는 데이터를 의미하며, 속성은 주로 접근 제어 및 추가적인 로직을 포함하는 특수한 메서드를 통해 접근되는 데이터를 의미합니다. 여기서 두 개념의 차이점을 더 자세히 설명하겠습니다.

인스턴스 변수 (Instance Variables)

인스턴스 변수는 클래스의 각 인스턴스마다 독립적으로 존재하는 변수를 의미합니다. 이는 보통 __init__ 메서드 내에서 정의되며, 직접적으로 접근하고 수정할 수 있습니다.

예시:

class MyClass:
    def __init__(self, value):
        self.instance_variable = value  # 인스턴스 변수

obj = MyClass(10)
print(obj.instance_variable)  # 10
obj.instance_variable = 20
print(obj.instance_variable)  # 20

속성 (Properties)

속성은 메서드를 통해 간접적으로 접근하고 수정할 수 있는 인스턴스 변수와 비슷한 개념입니다. 속성은 @property 데코레이터를 사용하여 정의되며, 이로 인해 getter, setter, deleter 메서드를 통해 접근과 수정이 가능합니다. 속성은 접근 제어, 유효성 검사, 추가 로직을 추가하는 데 유용합니다.

예시:

class MyClass:
    def __init__(self, value):
        self._value = value  # 실제 데이터를 저장하는 변수 (보통 이름 앞에 _를 붙임)

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        if new_value < 0:
            raise ValueError("Value cannot be negative")
        self._value = new_value

obj = MyClass(10)
print(obj.value)  # 10
obj.value = 20
print(obj.value)  # 20
# obj.value = -10  # ValueError 발생

주요 차이점

  1. 직접 접근 vs 간접 접근:
    • 인스턴스 변수는 직접 접근하고 수정할 수 있습니다 (obj.instance_variable).
    • 속성은 간접적으로 접근하고 수정할 수 있으며, 접근 메서드를 통해 제어됩니다 (obj.value).
  2. 추가 로직:
    • 인스턴스 변수는 단순히 데이터를 저장합니다.
    • 속성은 getter, setter 메서드를 통해 접근 로직을 추가할 수 있습니다 (예: 유효성 검사, 로그 작성).
  3. 읽기 전용 속성:
    • 인스턴스 변수는 읽기/쓰기가 자유롭습니다.
    • 속성은 @property만 정의하면 읽기 전용으로 만들 수 있습니다. (setter를 정의하지 않음)

결론

인스턴스 변수는 클래스 인스턴스의 데이터를 저장하는 데 사용되며, 속성은 데이터를 보호하고 접근을 제어하기 위해 사용됩니다. 속성은 특히 추가적인 로직이 필요한 경우 유용합니다.

posted by Peter Note

 

개념

문서를 로딩했으면 의미조각(Chunk)으로 쪼개는 splitting 작업을 한다. 이는 LLM에 인풋으로 들어가는 프롬프트 길이의 제약이 있기 때문에 문서가 길 경우 의미조각으로 나눠서 저장 후 사용자 쿼리에 가장 유사한 의미조각을 찾기 위한 용도이다. 따라서 문서의 특성에 따른 Splitter를 잘 선택해야 한다.

 

 

패키지

langchain_text_splitters 패키지가 별도로 분리되어 있다. 두가지 방법으로 import 할 수 있다. 

from langchain.document_loaders import PyPDFLoader
from langchain_text_splitter import RecursiveCharacterTextSplitter
// 또는
// from langchain_text_splitters import RecursiveCharacterTextSplitter

// 예1) 문서 splitting
loader = PyPDFLoader(FILE_PATH)
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=50)
splitted_docs = text_splitter.split_documents(docs)

for i, document in enumerate(splitted_docs):
    print(f"Document {i+1}:\n{document}\n")


// 예2) 텍스트 splitting
text = """
LangChain은 대규모 언어 모델(LLM)을 활용하여 복잡한 응용 프로그램을 구축하기 위한 도구입니다. 
이 도구는 프롬프트 템플릿, 모델, 출력 파서 등을 포함한 다양한 컴포넌트를 제공하여, 
사용자가 쉽게 체인을 구성할 수 있도록 도와줍니다.
"""

chunks = text_splitter.split_text(text)
for i, chunk in enumerate(chunks):
    print(f"Chunk {i+1}:\n{chunk}\n")

 

Splitter의 종류

1. RecursiveCharacterTextSplitter:

분할 기준: 사용자 정의 문자를 기준으로 재귀적으로 분할합니다.

특징: 관련된 텍스트 조각을 최대한 근접하게 유지하려고 합니다. 텍스트를 나누는 기본 방법으로 권장됩니다.

2. CharacterTextSplitter:

분할 기준: 단순히 특정 문자(예: 공백, 줄 바꿈 등)를 기준으로 분할합니다.

특징: 간단한 분할 작업에 적합합니다.

3. TokenTextSplitter:

분할 기준: 토큰 단위로 텍스트를 분할합니다.

특징: 언어 모델의 토큰화 방식에 따라 텍스트를 나눌 수 있어, 모델의 최대 토큰 길이에 맞춰 텍스트를 분할할 때 유용합니다.

4. SentenceTextSplitter:

분할 기준: 문장 단위로 텍스트를 분할합니다.

특징: 문장을 기준으로 텍스트를 나누기 때문에 자연스러운 분할이 가능합니다.

5. MarkdownTextSplitter:

분할 기준: 마크다운 문서의 구조(헤더, 리스트, 코드 블록 등)를 기준으로 분할합니다.

특징: 마크다운 문서를 처리할 때 유용하며, 문서의 논리적 구조를 유지하면서 분할할 수 있습니다.

6. HTMLTextSplitter:

분할 기준: HTML 태그를 기준으로 텍스트를 분할합니다.

특징: HTML 문서를 처리할 때 유용하며, 문서의 시각적 구조를 유지하면서 분할할 수 있습니다.

7. LanguageSpecificTextSplitter:

분할 기준: 특정 언어의 구문을 기준으로 텍스트를 분할합니다.

특징: 언어별로 특화된 분할 방식을 사용할 수 있어, 코드나 특정 언어로 작성된 텍스트를 효과적으로 분할할 수 있습니다.

 

 

API

 

주로 다루는 것이 문자일 경우 TextSplitter를 상속받은 RecursiveCharacterTextSplitter를 많이 사용한다. 

  - split_text 메소드는 주로 문자 스트링을 List[str] 로 반환할 때 사용한다. abstractmethod 이다. 

  - create_documents 는 List[str] 을 List[Document] 로 반환할 때 사용한다.
  - split_documents 주로 문서 파일을 load한 후 다시 작은 단위조각의 List[Document] 로 반환할 때 사용한다.

      - Document의 page_content를 List[str] 로 만들어 create_documents를 호출하고 있다.

      - create_documents는 chunk_size, chunk_overlap에 따라 텍스트 조각을 만드는 split_text를 호출하고 있다.

// TextSplitter
class TextSplitter(BaseDocumentTransformer, ABC):
    """Interface for splitting text into chunks."""

    def __init__(
        self,
        chunk_size: int = 4000,
        chunk_overlap: int = 200,
        length_function: Callable[[str], int] = len,
        keep_separator: Union[bool, Literal["start", "end"]] = False,
        add_start_index: bool = False,
        strip_whitespace: bool = True,
    ) -> None:
        """Create a new TextSplitter.

        Args:
            chunk_size: Maximum size of chunks to return
            chunk_overlap: Overlap in characters between chunks
            length_function: Function that measures the length of given chunks
            keep_separator: Whether to keep the separator and where to place it
                            in each corresponding chunk (True='start')
            add_start_index: If `True`, includes chunk's start index in metadata
            strip_whitespace: If `True`, strips whitespace from the start and end of
                              every document
        """
        if chunk_overlap > chunk_size:
            raise ValueError(
                f"Got a larger chunk overlap ({chunk_overlap}) than chunk size "
                f"({chunk_size}), should be smaller."
            )
        self._chunk_size = chunk_size
        self._chunk_overlap = chunk_overlap
        self._length_function = length_function
        self._keep_separator = keep_separator
        self._add_start_index = add_start_index
        self._strip_whitespace = strip_whitespace

    @abstractmethod
    def split_text(self, text: str) -> List[str]:
        """Split text into multiple components."""

    def create_documents(
        self, texts: List[str], metadatas: Optional[List[dict]] = None
    ) -> List[Document]:
        """Create documents from a list of texts."""
        _metadatas = metadatas or [{}] * len(texts)
        documents = []
        for i, text in enumerate(texts):
            index = 0
            previous_chunk_len = 0
            for chunk in self.split_text(text):
                metadata = copy.deepcopy(_metadatas[i])
                if self._add_start_index:
                    offset = index + previous_chunk_len - self._chunk_overlap
                    index = text.find(chunk, max(0, offset))
                    metadata["start_index"] = index
                    previous_chunk_len = len(chunk)
                new_doc = Document(page_content=chunk, metadata=metadata)
                documents.append(new_doc)
        return documents

    def split_documents(self, documents: Iterable[Document]) -> List[Document]:
        """Split documents."""
        texts, metadatas = [], []
        for doc in documents:
            texts.append(doc.page_content)
            metadatas.append(doc.metadata)
        return self.create_documents(texts, metadatas=metadatas)
    ...

 

RecursiveCharaterTextSplitter 의 split_text 구현 내역

  - abstract method 인 split_text를 구현함.

class RecursiveCharacterTextSplitter(TextSplitter):
    """Splitting text by recursively look at characters.

    Recursively tries to split by different characters to find one
    that works.
    """

    def __init__(
        self,
        separators: Optional[List[str]] = None,
        keep_separator: bool = True,
        is_separator_regex: bool = False,
        **kwargs: Any,
    ) -> None:
        """Create a new TextSplitter."""
        super().__init__(keep_separator=keep_separator, **kwargs)
        self._separators = separators or ["\n\n", "\n", " ", ""]
        self._is_separator_regex = is_separator_regex

    def _split_text(self, text: str, separators: List[str]) -> List[str]:
        """Split incoming text and return chunks."""
        final_chunks = []
        # Get appropriate separator to use
        separator = separators[-1]
        new_separators = []
        for i, _s in enumerate(separators):
            _separator = _s if self._is_separator_regex else re.escape(_s)
            if _s == "":
                separator = _s
                break
            if re.search(_separator, text):
                separator = _s
                new_separators = separators[i + 1 :]
                break

        _separator = separator if self._is_separator_regex else re.escape(separator)
        splits = _split_text_with_regex(text, _separator, self._keep_separator)

        # Now go merging things, recursively splitting longer texts.
        _good_splits = []
        _separator = "" if self._keep_separator else separator
        for s in splits:
            if self._length_function(s) < self._chunk_size:
                _good_splits.append(s)
            else:
                if _good_splits:
                    merged_text = self._merge_splits(_good_splits, _separator)
                    final_chunks.extend(merged_text)
                    _good_splits = []
                if not new_separators:
                    final_chunks.append(s)
                else:
                    other_info = self._split_text(s, new_separators)
                    final_chunks.extend(other_info)
        if _good_splits:
            merged_text = self._merge_splits(_good_splits, _separator)
            final_chunks.extend(merged_text)
        return final_chunks

    def split_text(self, text: str) -> List[str]:
        return self._split_text(text, self._separators)

 

 

Custom Text Splitter 만들기 

Custom text splitter를 만들려면 TextSplitter 클래스를 상속받아 자신만의 분할 로직을 구현할 수 있습니다. 다음은 간단한 예제로, 특정 구분자(예: 줄 바꿈 문자)를 기준으로 텍스트를 분할하는 custom text splitter를 만드는 방법을 보여드립니다.

 

1. CustomTextSplitter 클래스 정의:

TextSplitter 클래스를 상속받아 CustomTextSplitter 클래스를 정의합니다. 생성자에서 구분자, 청크 크기, 겹침 크기를 설정할 수 있습니다.

2. split_text 메서드 구현:

split_text 메서드는 주어진 텍스트를 구분자를 기준으로 분할한 다음, 지정된 청크 크기와 겹침 크기를 기준으로 청크를 생성합니다.

3. 청크 겹침 처리:

청크 간에 겹침을 추가하여 텍스트가 자연스럽게 이어지도록 합니다.

4. CustomTextSplitter 사용:

CustomTextSplitter 인스턴스를 생성하고, split_text 메서드를 호출하여 텍스트를 분할한 후 결과를 출력합니다.

 

이 예제는 간단한 구분자를 사용한 텍스트 분할을 보여주지만, 실제로는 더 복잡한 분할 로직을 구현할 수 있습니다. 예를 들어, 문단 단위로 분할하거나, 특정 패턴을 기준으로 분할하는 등 다양한 요구에 맞춰 커스터마이징할 수 있습니다.

from langchain.text_splitter import TextSplitter
from typing import List

class CustomTextSplitter(TextSplitter):
    def __init__(self, separator: str = "\n", chunk_size: int = 100, chunk_overlap: int = 20):
        self.separator = separator
        self.chunk_size = chunk_size
        self.chunk_overlap = chunk_overlap

    def split_text(self, text: str) -> List[str]:
        # 구분자를 기준으로 텍스트를 분할
        splits = text.split(self.separator)
        
        chunks = []
        current_chunk = ""
        
        for split in splits:
            if len(current_chunk) + len(split) + len(self.separator) > self.chunk_size:
                chunks.append(current_chunk)
                current_chunk = split
            else:
                if current_chunk:
                    current_chunk += self.separator
                current_chunk += split
        
        # 마지막 남은 텍스트 조각 추가
        if current_chunk:
            chunks.append(current_chunk)
        
        # 겹침 처리
        if self.chunk_overlap > 0 and len(chunks) > 1:
            overlapped_chunks = []
            for i in range(len(chunks)):
                if i > 0:
                    overlap = chunks[i-1][-self.chunk_overlap:] + self.separator
                    overlapped_chunks.append(overlap + chunks[i])
                else:
                    overlapped_chunks.append(chunks[i])
            chunks = overlapped_chunks
        
        return chunks

# CustomTextSplitter 사용 예제
text = """
LangChain은 대규모 언어 모델(LLM)을 활용하여 복잡한 응용 프로그램을 구축하기 위한 도구입니다.
이 도구는 프롬프트 템플릿, 모델, 출력 파서 등을 포함한 다양한 컴포넌트를 제공하여,
사용자가 쉽게 체인을 구성할 수 있도록 도와줍니다.
"""

splitter = CustomTextSplitter(separator="\n", chunk_size=100, chunk_overlap=20)
chunks = splitter.split_text(text)

for i, chunk in enumerate(chunks):
    print(f"Chunk {i+1}:\n{chunk}\n")

 

written by GPT for custom splitter

 

<참조>

- API: https://api.python.langchain.com/en/latest/text_splitters_api_reference.html

- 소스: https://github.com/langchain-ai/langchain/tree/master/libs/text-splitters/langchain_text_splitters

 

langchain/libs/text-splitters/langchain_text_splitters at master · langchain-ai/langchain

🦜🔗 Build context-aware reasoning applications. Contribute to langchain-ai/langchain development by creating an account on GitHub.

github.com

- LangChain KR: https://wikidocs.net/233998

 

01. 문자 텍스트 분할(CharacterTextSplitter)

.custom { background-color: #008d8d; color: white; padding: 0.25em 0.5…

wikidocs.net

 

posted by Peter Note