박주니 개발 정리

python search ai 만드는 방법 본문

AI

python search ai 만드는 방법

박주니 2024. 8. 26. 17:23
728x90
반응형

먼저 시작하기 전에 faiss 및 embedding 설정을 하시길 바랍니다. 

https://junhee6773.tistory.com/entry/python-faiss-%EB%B2%A1%ED%84%B0%ED%99%94-%EC%9E%84%EB%B0%B0%EB%94%A9-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B0%A9%EB%B2%95-faiss-%EB%B0%8F-embedding-model-%EC%A4%80%EB%B9%84

 

python faiss 벡터화 임배딩 만드는 방법 (faiss 및 embedding model 준비)

python에서 openai 및 faiss 환경을 설정하기 위해서는 먼저 가상환경부터 구축부터 진행을 해야합니다.  1. miniconda에서 python 가상환경을 설정합니다. https://junhee6773.tistory.com/entry/miniconda-%EC%84%A4%EC%B

junhee6773.tistory.com

1. faiss 벡터화한 것을 읽기 위해 텍스트를 임베딩합니다. 

def get_embedding(text):
    response = openai.Embedding.create(
        model="text-embedding-3-large",
        input=text
    )
    embedding = response['data'][0]['embedding']
    return embedding

추가 설명)

처음 faiss 임베딩 벡터화할 때 적용했던 model과 동일한 model을 적용해야합니다. 

2. 전체 데이터를 임베딩 벡터화했던 것을 불러와서 현재 query 임배딩했던것을 매개변수로 해서 k에 설정된 갯수만큼 불러옵니다. 

index = faiss.read_index("product_index.faiss")

def search():
    query = request.json.get("query", "")
    query_embedding = get_embedding(query)

    # FAISS를 이용해 가장 유사한 상위 10개의 제품 검색
    distances, indices = index.search(np.array([query_embedding]), k=10)

추가 설명)

전체 데이터를 임베딩한것에서 distances기준으로 상위 10개를 가지고 오고 그 상위 10개에 해당되는 id는 indices로 설정합니다. 

 

3. 상위 10개에 해당되는 indices기준으로 상품명을 배열로 넣습니다. 

    candidates = []

    # 검색된 상위 제품을 후보 리스트에 추가
    for i, idx in enumerate(indices[0]):
        if 0 <= idx < len(products):
            product = products[idx]
            candidates.append((product, distances[0][i]))

4. 상위 10개중에서도 일정 비율 이상의 유사도가 일치하는 것만 따로 배열의 관리합니다. 

    query_lower = query.lower()

    # 사용자가 입력한 쿼리의 단어를 기준으로 후처리
    query_words = set(query_lower.split())

    filtered_results = []
    for product, distance in candidates:
        product_name_words = set(product.get("product_name", "").lower().split())
        
        # 쿼리의 단어가 제품명에 얼마나 많이 포함되는지를 계산
        common_words = query_words.intersection(product_name_words)
        
        # 일정 비율 이상의 단어가 일치하는 경우에만 결과에 포함
        if len(common_words) / len(query_words) >= 0.7:  # 70% 이상의 단어가 일치해야 함
            filtered_results.append((product, distance))

추가 설명)

product.get("product_name")은 제가 data 전체 임베딩했을때 상품명 기준으로 했기때문에 설정했던 name을 지정한 것입니다. 처음에 faiss 임베딩 벡터화진행했을때 넣었던 값을 입력하시면 됩니다. 

현재 유사도 체크 기준은 문자 길이이기 때문에 유사도 세부조정을 하실려면 한글 기준으로 유사도 체크 예외처리로 변경하시면 됩니다. 

5. 유사도에 따라 정렬해서 가지고 옵니다. 

    if filtered_results:
        # 유사도에 따라 정렬
        filtered_results.sort(key=lambda x: x[1], reverse=True)
        final_results = [product["product_name"] for product, _ in filtered_results]
        logger.debug(f"Matched Products: {final_results}")
        return jsonify({"status": "yes", "title": final_results})

 

☆가장 중요한 흐름

1. 임베딩했던 것을 가지고 오기위해서는 처음 임베딩했던 model 그대로 create 진행하는 것

2. 처음 임베딩 벡터화를 진행했을 때 product_index.faiss는 유사 검색을 하기 위한 것이고 그렇게 상위 id를 기반으로 products.npy에서 찾는것

3. 그 이후 유사도 검증을 함으로써 원하는 범주내 결과물을 가지고 올 수 있는것

입니다. 

 

느낀점)

gpt-3.5 model로 유사한것을 finetunning으로 진행했을때 어떻게든 답을 내보낼려고하다보니 정확도가 좀 떨어졌는데 faiss 및 embedding model 활용해서 진행하니깐 정확도도 높아지고 따로 파일을 만들어서 재사용성을 높일 수 있었습니다. 좀 더 search ai 고도화를 진행하게 되면 pinccone vector db 활용할 예정입니다. 

 

728x90
반응형
Comments