8달 전 · 문종호 님의 새로운 답변
RAG 를 짜는 중에 도무지 어떤 부분이 문제인지 모르겠습니다.
# 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인데) 저장되어있는 답변이 끌어와지질 않네요...
개발자
#llm#rag
답변 1
댓글 0
조회 104
일 년 전 · 포크코딩 님의 새로운 댓글
HTML의 tagName을 모아둔 타입이 있을까요?
content 분류 - sectioning, phrase, metadata... - 에 따라 tagName이 나뉘어져 있으면 좋겠다는 생각...이었지만 검색한 걸로는 아직 오픈 소스나 @type에 그런 정의가 없는 것 같았습니다. 그래서 한땀한땀 직접 만든 것을 사용하고 있었는데, 제가 못 찾고 있을 걸 수도 있어 질문 남겨봅니다.
개발자
#html
#typescript
답변 1
댓글 2
조회 48
일 년 전 · 김태우 님의 새로운 답변
git 협업중 파일 날라감…
팀원들과 깃 브랜치를 나누어 개발하고 develop 브랜치에 올리는 작업을 하고 있습니다(이클립스 사용) develop에 pull request 를 바로 하려다가 팀원이 본인은 pull request 했는데 충돌난다하길래 그럼 저도 충돌이 나겠다 싶어서 제 프로젝트의 .metedate폴더를 다른곳으로 옮기고 .metadata폴더가 없는체로 develop브랜치로 merge 했습니다 그런데 다른 폴더에서 제가 develop으로 올린 프로젝트를 pull 해서 열어보니 프로젝트가 안불러와지더라구요ㅜㅜㅜ 이거 혹시 해결방법이 있을까요… 구글에 찾아보니 .metadata 지우고 push하길래 따라했는데 이러면 안되는거였나요,,ㅠㅠㅠ 혹시 조금이라도 아시는분 있으시면 조언좀 부탁드립니다ㅜㅜ
개발자
#깃
#github
#git
#깃허브
#이클립스
답변 1
댓글 0
조회 139
일 년 전 · 허니 님의 새로운 답변
Next.JS generateMetadata에서 fetch를 한번 진행하면 prefetch를 하지 않아도 되는건가요?
Next.JS generateMetadata에서 fetch를 한번 진행하면 prefetch를 하지 않아도 되는건지 궁금합니다. 현재는 사진과 같은 코드처럼 사용하고 있는데, 문득 generateMetadata가 실행될 때 한번 fetching이 이루어지기 때문에 컴포넌트단에서 prefetch를 시켜주지 않아도 된다고 생각했는데, 맞을까요?
개발자
#next
#react
#react-query
답변 1
댓글 0
조회 132
2년 전 · 김태우 님의 새로운 댓글
[Next.js] 미디어쿼리가 모바일 배포환경에서만 적용되지 않습니다ㅠㅠ
현재 Next.js를 이용해서 프로젝트를 진행하고 있는 대학생입니다! 프론트엔드를 개발하면서 반응형 웹을 계획하고 미디어쿼리를 이용해 반응형 레이아웃을 테스트하는데 데스크탑 개발환경 및 배포(vercel)환경에서는 미디어쿼리가 잘 작동하지만 모바일로 배포환경에 접속하면 미디어쿼리가 적용되지 않습니다. 해결을 위해 시도한 방법 1. "일반 css파일과 css_module파일이 특정 상황에서 충동을 일으킬 수 있다"는 정보를 토대로 모든 스타일 파일을 css_module로 통일했습니다. 2. "metadata에 viewport 구문이 빠져있을 수 있다"는 정보를 토대로 next/Head를 이용해서 viewport를 따로 명시했습니다. 위 방법들을 모두 시도했지만 여전히 데스트톱에서만 미디어쿼리가 작동하고 모바일 배포환경에서는 먹통입니다. 선배님들의 도움이 필요합니다ㅜㅜ
개발자
#react
#next.js
#vercel
#media-query
답변 2
댓글 2
보충이 필요해요 1
조회 1,929