개발자
# JSON 파일에서 FAQ 데이터를 로드하는 함수 def load_faq_data_from_json(file_path): with open(file_path, 'r', encoding='utf-8') as f: faq_data = json.load(f) return faq_data # FAQ 데이터 로드 json_file_path = '' faq_data = load_faq_data_from_json(json_file_path) # ChromaDB 클라이언트 및 Embedding 설정 chroma_client = chromadb.Client() # ChromaDB 클라이언트 생성 # 고유한 컬렉션 이름 생성 collection_name = "faq_data_" + datetime.datetime.now().strftime("%Y%m%d_%H%M%S") collection = chroma_client.create_collection(collection_name) # LangChain의 Text Splitter 설정 text_splitter = RecursiveCharacterTextSplitter( chunk_size=512, chunk_overlap=50 ) # OpenAI 임베딩 설정 openai_api_key = '' embedding_function = OpenAIEmbeddings( model="text-embedding-ada-002", openai_api_key=openai_api_key ) # 텍스트 스플리팅 및 임베딩 생성 함수 def split_and_embed_text(text): splitted_texts = text_splitter.split_text(text) print(f"Splitted texts: {splitted_texts}") try: # OpenAIEmbeddings는 embed_documents를 사용합니다. embeddings = embedding_function.embed_documents(splitted_texts) except Exception as e: print(f"임베딩 생성 중 오류 발생: {e}") return None # 임베딩이 제대로 생성되었는지 확인합니다. if embeddings is None or len(embeddings) == 0: print("임베딩 생성 실패") return None # 임베딩을 numpy 배열로 변환 embeddings = np.array(embeddings) print(f"Embeddings shape: {embeddings.shape}") # 임베딩 벡터의 차원을 확인하고 처리합니다. if embeddings.ndim == 1 and embeddings.shape[0] == 1536: # 임베딩이 1차원 배열이고 길이가 1536인 경우 final_embedding = embeddings elif embeddings.ndim == 2 and embeddings.shape[1] == 1536: # 임베딩이 2차원 배열이고 두 번째 차원이 1536인 경우 final_embedding = np.mean(embeddings, axis=0) else: print("임베딩 벡터의 차원이 예상과 다릅니다.") return None print(f"Final embedding shape: {final_embedding.shape}") return final_embedding # FAQ 데이터를 Vector DB에 저장 def store_faq_data_in_vector_db(faq_data, collection): for faq in faq_data: # 'question'과 'answer'가 있는지 확인하고, 'answer'가 None이 아닌지 확인 if 'question' not in faq or 'answer' not in faq or faq['answer'] is None: print(f"누락된 'question' 또는 'answer'로 인해 항목을 건너뜁니다: {faq}") continue # 다음 항목으로 넘어감 # 텍스트 스플리팅 및 임베딩 생성 question_embedding = split_and_embed_text(faq['question']) if question_embedding is None: print(f"Embedding generation failed for question: {faq['question']}") continue # 임베딩이 없으면 다음 질문으로 넘어감 print(f"Generated embedding for question '{faq['question']}': {question_embedding}") # 각 질문에 고유한 ID 생성 faq_id = str(uuid.uuid4()) # 메타데이터에서 None 값을 제거 metadata = {k: v for k, v in {"answer": faq['answer']}.items() if v is not None} # Vector DB에 저장 collection.add( documents=[faq['question']], metadatas=[metadata], ids=[faq_id], embeddings=[question_embedding] ) # 추가 후 임베딩 확인 (저장된 후 곧바로 확인) stored_results = collection.get(ids=[faq_id], include=["embeddings"]) if stored_results['embeddings'] is not None and len(stored_results['embeddings']) > 0: print(f"Embedding for question '{faq['question']}' successfully stored.") else: print(f"Failed to store embedding for question '{faq['question']}'") # FAQ 데이터를 JSON에서 로드하고 저장 store_faq_data_in_vector_db(faq_data, collection) 이렇게 데이터를 저장하고 # 환경 변수에서 API 키 로드 openai_api_key = os.getenv("OPENAI_API_KEY") if not openai_api_key: raise ValueError("OpenAI API 키가 설정되지 않았습니다. 환경 변수 OPENAI_API_KEY를 설정하세요.") # OpenAI 임베딩 설정 embedding_function = OpenAIEmbeddings( model="text-embedding-ada-002", openai_api_key=openai_api_key ) # LangChain의 Text Splitter 설정 (일관성 유지) text_splitter = RecursiveCharacterTextSplitter( chunk_size=512, chunk_overlap=50 ) # ChromaDB 클라이언트 및 컬렉션 설정 chroma_client = chromadb.Client() collection_name = "faq_data_collection" try: # 이미 존재하는 컬렉션인지 확인하고, 있으면 가져옴 collection = chroma_client.get_collection(name=collection_name) except chromadb.errors.CollectionNotFoundError: # 컬렉션이 존재하지 않을 경우에만 생성 collection = chroma_client.create_collection(name=collection_name) # Vector DB에서 유사 질문 검색 (ChromaDB) def find_similar_question_in_vector_db(new_question_embedding, collection, k=5): results = collection.query(query_embeddings=[new_question_embedding], n_results=k, include=['documents', 'metadatas', 'embeddings']) best_similarity = 0 best_question = None best_answer = None # 검색 결과에서 각 질문의 유사도와 답변을 처리합니다. if 'documents' in results and 'metadatas' in results: documents = results['documents'][0] metadatas = results['metadatas'][0] embeddings = results['embeddings'][0] for i in range(len(documents)): stored_embedding = embeddings[i] metadata = metadatas[i] if stored_embedding is not None: # 코사인 유사도를 통해 유사도를 계산합니다. similarity = cosine_similarity([new_question_embedding], [stored_embedding])[0][0] print(f"유사도: {similarity} for {documents[i]}") # 유사도가 가장 높은 결과를 선택하며, 임계값 이상일 경우에만 선택 if similarity > best_similarity and similarity >= SIMILARITY_THRESHOLD: best_similarity = similarity best_question = documents[i] if isinstance(metadata, list): metadata = metadata[0] best_answer = metadata.get('answer') if isinstance(metadata, dict) else None return best_question, best_answer # Fine-tuned GPT를 사용해 새로운 답변 생성 def gpt_generate_response_from_finetuned_gpt(question, style="의사 A 말투"): prompt = f"다음은 환자의 질문입니다: \"{question}\". 아래 말투를 사용하여 질문에 대해 성실하고 정확한 답변을 작성해주세요.\n\ 말투: {style}" response = client.chat.completions.create( model="", # Fine-tuned된 GPT 모델 ID messages=[ {"role": "system", "content": "You are a helpful medical assistant."}, {"role": "user", "content": prompt}, ], max_tokens=300, temperature=0.7, # 답변의 다양성을 조절합니다. ) return response.choices[0].message.content.strip() # 새로운 질문 처리 및 최종 응답 생성 def generate_final_response(new_question, collection): # 텍스트 스플리팅 및 임베딩 생성 splitted_texts = text_splitter.split_text(new_question) new_question_embedding = np.mean(embedding_function.embed_documents(splitted_texts), axis=0) # ChromaDB에서 유사 질문 검색 similar_question, answer = find_similar_question_in_vector_db(new_question_embedding, collection) if similar_question and answer: final_response = f"질문: {new_question}\n유사 질문: {similar_question}\n기본 답변: {answer}" else: generated_answer = gpt_generate_response_from_finetuned_gpt(new_question) final_response = f"질문: {new_question}\nGPT로 생성된 답변: {generated_answer}\n(이 답변은 벡터데이터에서 유사한 답변을 찾을 수 없어 GPT에 의해 생성되었습니다.)" return final_response # 사용자로부터 새로운 질문 입력 받기 new_question = input("새로운 질문을 입력하세요: ") # 최종 응답 생성 response = generate_final_response(new_question, collection) print(response) 로 데이터베이스에서 유사한 질문-답변 쌍을 끌어오려는데 정확히 같은 질문을 넣어도 (이러면 유사도가 1인데) 저장되어있는 답변이 끌어와지질 않네요...
답변 1
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!