반응형
반응형

RAG (검색 증강 생성) 설명

**RAG (Retrieval-Augmented Generation)**는 **"검색 증강 생성"**의 줄임말이에요. 대규모 언어 모델(LLM)의 한계를 보완하고 성능을 높이기 위한 강력한 기술이죠.


왜 RAG가 필요할까요?

ChatGPT 같은 LLM은 엄청난 양의 데이터로 학습되어 유창한 글을 잘 만들어요. 하지만 몇 가지 아쉬운 점이 있습니다.

  • 환각(Hallucination): LLM이 학습하지 않은 정보나 잘못된 내용을 마치 사실인 양 지어낼 수 있어요.
  • 정보의 최신성 부족: LLM은 특정 시점까지의 데이터로 학습되므로, 그 이후의 최신 정보는 알지 못합니다.
  • 특정 도메인 지식 부족: 일반적인 지식은 풍부하지만, 특정 기업의 내부 문서나 전문 분야 논문 같은 깊이 있는 지식은 부족할 수 있어요.
  • 투명성 부족: 왜 그런 답변을 생성했는지 그 근거를 제시하기 어렵습니다.

이런 문제들을 해결하기 위해 RAG가 등장했습니다.


RAG는 어떻게 작동할까요?

RAG는 질문에 답변을 만들기 전에, 외부에서 관련성 높은 정보를 검색(Retrieval)해서 가져온 뒤, 이 정보를 바탕으로 답변을 생성(Generation)하는 방식이에요. 쉽게 말해, LLM에게 "답변하기 전에 관련 자료를 찾아보고 대답해줘"라고 시키는 것과 같죠.

RAG의 핵심 과정은 다음과 같습니다.

  1. 질문 입력: 사용자가 질문을 입력합니다.
  2. 관련 문서 검색:
    • 질문을 분석하고 핵심 키워드나 의도를 파악해요.
    • 미리 구축해 둔 외부 지식 베이스 (데이터베이스, 문서 저장소, 웹 등)에서 질문과 가장 관련 깊은 **문서 조각(Chunk)**들을 찾아냅니다. 이때 벡터 데이터베이스 같은 기술이 사용되어 질문과 문서의 의미적 유사성을 기반으로 효율적인 검색이 이루어져요.
  3. 정보 증강 및 프롬프트 구성:
    • 검색된 관련 문서 조각들을 LLM에게 전달할 **프롬프트(Prompt)**에 추가합니다.
    • 보통 "다음 문서들을 참고하여 질문에 답변해 줘: [검색된 문서들 내용] 질문: [원래 질문]"과 같은 형식으로 프롬프트를 만들어요.
  4. 답변 생성:
    • 증강된 프롬프트(질문 + 관련 문서)를 LLM에 전달합니다.
    • LLM은 이제 자신의 학습 데이터만으로 답변하는 게 아니라, 제공된 최신 또는 특정 도메인의 정보를 참고하여 더 정확하고 근거 있는 답변을 생성해요.
  5. 답변 출력: LLM이 만든 답변을 사용자에게 보여줍니다.

RAG의 장점

  • 정확성 향상: 최신 정보나 특정 도메인 지식을 참조하여 잘못된 정보를 줄이고 답변의 정확도를 높여요.
  • 최신 정보 반영: LLM을 다시 학습(fine-tuning)할 필요 없이, 외부 데이터만 업데이트하면 실시간으로 최신 정보를 반영할 수 있어 비용 효율적입니다.
  • 투명성 및 신뢰성: 답변의 근거가 된 원본 문서를 함께 제시함으로써 답변에 대한 신뢰도를 높일 수 있어요.
  • 비용 효율성: LLM 자체를 재학습시키는 것보다 훨씬 적은 비용과 시간으로 모델의 지식을 확장할 수 있습니다.
  • 유연성: 다양한 외부 지식 베이스(데이터베이스, 문서, 웹 등)와 연결하여 사용할 수 있어요.

RAG의 활용 사례

  • 기업 내부 지식 챗봇: 회사의 내부 문서나 규정을 기반으로 직원들의 질문에 정확히 답변합니다.
  • 고객 서비스 챗봇: 기업의 최신 제품 정보나 FAQ를 기반으로 고객 문의에 응대해요.
  • 법률 및 의료 정보 시스템: 최신 법률이나 의학 논문 등을 참고하여 전문적인 질문에 답변합니다.
  • 개인화된 학습 도구: 특정 학습 자료를 기반으로 학생들의 질문에 맞춤형 답변을 제공해요.
  • 실시간 데이터 분석: 실시간으로 업데이트되는 데이터를 참조하여 질문에 대한 답변을 생성합니다.

RAG는 LLM의 한계를 극복하고 실제 환경에서 더욱 유용하게 쓰일 수 있도록 돕는 핵심 기술로 자리매김하고 있어요. 질문의 맥락과 외부 데이터를 함께 고려하여 더 스마트하고 신뢰할 수 있는 답변을 제공하는 것이 RAG의 궁극적인 목표라고 할 수 있습니다.

반응형
반응형

텃밭

반응형
반응형

https://www.data.go.kr/data/15044350/fileData.do

 

한국산업은행_금융 관련 용어_20151231

리스크 개요 및 유형별 측정 방법과 관련된 용어 정의, 퇴직연금 관련 용어 정의

www.data.go.kr

반응형
반응형

세상에 영원한 것은 없다.
변화 혹은 흐름만이 영속적이다.
유장하기 이를 데 없는 산도 바다도 변한다.
산은 계절에 따라 다른 옷을 입고 세상과 마주한다.
바다는 끊임없이 출렁임으로 싱싱함을 유지한다.
굳건해 보이는 바위가 허물어져 모래가 되고
그것이 변하여 토양이 되기도 한다.
늙은 바위는 자기 위에 떨어진
씨앗을 위해 자기 몸 일부를
열어준다.


- 김기석의 《최소한의 품격》 중에서 -  


* 세상의 모든 것은
지속적이지 않습니다. 늘 변합니다.
사람도 자연도 단단한 바위도 변합니다.
'영원히 변하지 않겠다'는 맹세도 변합니다.
조건 따라 상황 따라 모든 것은 있다가도 사라집니다.
놀라운 것은 그 과정에서 새로운 생명이 탄생하는
것입니다. 언젠가는 흙으로 돌아갈 늙은 바위는
자기 몸으로 씨앗을 키웁니다.
위대한 변화입니다.

반응형

'아침편지' 카테고리의 다른 글

단 한 표 차로 역사가 바뀌었다  (0) 2025.05.29
아버지를 이해할 수 있는 나이  (0) 2025.05.28
진짜 마법 같은 일  (0) 2025.05.26
공분  (0) 2025.05.26
94세 할머니 화가  (0) 2025.05.23
반응형

2025-05-26. 팔굽혀펴기 100개

반응형
반응형

[python] 유튜브 자막 가져오기 

 

 

""" 유튜브 자막 가져오기 
    pip install youtube-transcript-api
    
    -- 최신 버전으로 업데이트
    pip install --upgrade youtube-transcript-api

    https://www.youtube.com/watch?v=XyljmT8dGA4
    
    자막있는 동영상 : https://www.youtube.com/watch?v=zRz9q8dPjC4
"""


from youtube_transcript_api import YouTubeTranscriptApi
# youtube_transcript_api._errors 에서 TooManyRequests를 제외하고 임포트합니다.
# TooManyRequests는 더 이상 직접 임포트할 수 없는 것으로 보입니다.
from youtube_transcript_api._errors import NoTranscriptFound, TranscriptsDisabled, VideoUnavailable

def get_youtube_transcript(video_id, languages=['ko', 'en']):
    """
    주어진 YouTube 동영상 ID와 언어 목록에 대해 자막을 가져옵니다.
    자동 생성 자막과 공식 자막을 모두 시도합니다.
    """
    try:
        # 우선 공식 자막을 시도
        transcript_list = YouTubeTranscriptApi.list_transcripts(video_id)

        # 사용 가능한 언어 목록에서 요청한 언어 중 하나를 찾아 가져옵니다.
        chosen_transcript = None
        for lang_code in languages:
            for transcript in transcript_list:
                if transcript.language_code == lang_code:
                    chosen_transcript = transcript
                    break
            if chosen_transcript:
                break

        if chosen_transcript:
            print(f"[{video_id}] {chosen_transcript.language} ({chosen_transcript.language_code}) 자막을 가져옵니다.")
            # fetch()는 이제 FetchedTranscript 객체를 반환하며, 이는 이터러블합니다.
            transcript_segments = chosen_transcript.fetch()
            return transcript_segments
        else:
            raise NoTranscriptFound(
                f"No suitable official transcript found for video {video_id} in languages {languages}.",
                video_id
            )

    except NoTranscriptFound:
        print(f"[{video_id}] 공식 자막을 찾을 수 없습니다. 자동 생성 자막을 시도합니다.")
        try:
            for lang_code in languages:
                try:
                    # get_transcript() 역시 이터러블한 객체를 반환하는 것으로 가정합니다.
                    transcript_segments = YouTubeTranscriptApi.get_transcript(video_id, languages=[lang_code], preserve_formatting=True)
                    print(f"[{video_id}] {lang_code} 자동 생성 자막을 가져왔습니다.")
                    return transcript_segments
                except NoTranscriptFound:
                    continue # 다음 언어로 시도
            print(f"[{video_id}] 요청된 언어 ({languages})로 자동 생성 자막도 찾을 수 없습니다.")
            return None # 적합한 자막을 찾지 못함
        except TranscriptsDisabled:
            print(f"[{video_id}] 이 동영상은 자막이 비활성화되어 있습니다.")
            return None
        except VideoUnavailable:
            print(f"[{video_id}] 동영상을 사용할 수 없거나 비공개/삭제되었습니다.")
            return None
        except Exception as e: # TooManyRequests를 포함한 모든 예외를 잡습니다.
            # 이 부분에서 TooManyRequests 에러를 포함하여 일반적인 오류를 처리합니다.
            print(f"[{video_id}] 자막을 가져오는 중 예기치 않은 오류가 발생했습니다: {e}")
            return None

    except TranscriptsDisabled:
        print(f"[{video_id}] 이 동영상은 자막이 비활성화되어 있습니다.")
        return None
    except VideoUnavailable:
        print(f"[{video_id}] 동영상을 사용할 수 없거나 비공개/삭제되었습니다.")
        return None
    except Exception as e: # TooManyRequests를 포함한 모든 예외를 잡습니다.
        # 이 부분에서 TooManyRequests 에러를 포함하여 일반적인 오류를 처리합니다.
        print(f"[{video_id}] 자막을 가져오는 중 예기치 않은 오류가 발생했습니다: {e}")
        return None


if __name__ == "__main__":
    # 예시 동영상 ID (실제 존재하는 동영상 ID로 변경해야 합니다)
    # 제가 추천해 드렸던 URL에서 ID를 추출했습니다.
    video_id_with_subtitle = "XyljmT8dGA4" # "모바일 유튜브 자동번역 한글자막 보는 방법"
    video_id_auto_caption = "XyljmT8dGA4" # 짧은 영상 (자동 생성 자막 가능성)
    #video_id_invalid = "invalid_video_id_123"
    video_id_invalid = "XyljmT8dGA4"

    print("--- 예제 1: 자막이 있는 동영상 ---")
    transcript_data = get_youtube_transcript(video_id_with_subtitle, languages=['ko', 'en'])
    if transcript_data:
        # segment.start, segment.duration, segment.text와 같이 속성으로 접근합니다.
        for i, segment in enumerate(transcript_data[:5]): # 슬라이싱은 여전히 가능해야 합니다.
            print(f"[{segment.start:.2f}-{segment.start + segment.duration:.2f}] {segment.text}")
        print(f"... (총 {len(list(transcript_data))}개 세그먼트)") # len()을 위해 list로 변환

        # 전체 자막 텍스트만 추출하고 싶다면:
        full_text = " ".join([segment.text for segment in transcript_data])
        print("\n--- 전체 자막 텍스트 (예제 1) ---")
        print(full_text[:500] + "...")
    else:
        print("자막을 가져오지 못했습니다.")

    print("\n--- 예제 2: 자동 생성 자막을 시도할 수 있는 동영상 ---")
    transcript_data_auto = get_youtube_transcript(video_id_auto_caption, languages=['en', 'ko'])
    if transcript_data_auto:
        for i, segment in enumerate(transcript_data_auto[:5]):
            print(f"[{segment.start:.2f}-{segment.start + segment.duration:.2f}] {segment.text}")
        print(f"... (총 {len(list(transcript_data_auto))}개 세그먼트)")
    else:
        print("자막을 가져오지 못했습니다.")

    print("\n--- 예제 3: 존재하지 않는 동영상 ID ---")
    transcript_data_invalid = get_youtube_transcript(video_id_invalid)
    if transcript_data_invalid:
        print("자막을 가져왔습니다.")
    else:
        print("자막을 가져오지 못했습니다.")
반응형

+ Recent posts