danbibibi
article thumbnail

Retrieval Augmented Generation (RAG)

LLM이 더 신뢰할 수 있고 사실 기반의 답변을 생성하도록 돕기 위해 고안된 기술로, 단순히 모델이 "기억"에만 의존하지 않고, 외부 지식 소스(문서, DB 등)로부터 관련 정보를 검색한 뒤, 이를 기반으로 텍스트를 생성함

  • Retrieval (검색) : 외부 문서나 데이터베이스에서 질문과 관련된 정보를 찾아옴
  • Augmentation (보강) : 검색된 문서를 모델 입력에 포함시켜, 모델이 사실 기반으로 답변할 수 있도록 유도
  • Generation (생성) : LLM이 보강된 정보를 바탕으로 자연어 응답을 생성

🔄 작동 흐름
사용자 입력 ex) “허리 통증에 좋은 스트레칭 방법은?”
질문 임베딩 (Query Embedding) 질문을 의미 벡터로 변환
문서 검색 (Retrieval) 벡터 DB 등에서 의미적으로 가까운 문서(또는 chunk) 검색
프롬프트 구성 (Augmentation) 질문 + 검색된 문서를 함께 모델에 입력
LLM 응답 생성 (Generation) 관련 문서를 바탕으로 신뢰도 높은 답변 생성
# 필요한 라이브러리 설치
!pip install openai tiktoken chromadb pypdf2

# 비밀번호(혹은 API Key)를 입력받기 위한 모듈
import getpass
import os

# 사용자로부터 OpenAI API 키를 입력받아 환경 변수로 저장
os.environ["OPENAI_API_KEY"] = getpass.getpass()

# OpenAI API 클라이언트 불러오기
from openai import OpenAI

# 사용할 OpenAI 모델 정의
EMBEDDING_MODEL = "text-embedding-3-small"  # 문장/문서 임베딩에 사용
GPT_MODEL = "gpt-4o-mini"  # 텍스트 생성용 LLM

# OpenAI API 클라이언트 객체 생성
client = OpenAI()

# 분석할 PDF 파일 경로
pdf_path = "/content/drive/MyDrive/Project_data/game_rule/blumable.pdf"

import PyPDF2

# PDF 파일 열기 및 텍스트 추출
with open(pdf_path, 'rb') as file:
    pdf_reader = PyPDF2.PdfReader(file)  # PDF 리더 객체 생성

    text = ""  # 전체 텍스트 저장용 변수

    # 페이지 순회하며 텍스트 추출
    for page in range(len(pdf_reader.pages)):
        pdf_page = pdf_reader.pages[page]  # 각 페이지 가져오기
        page_text = pdf_page.extract_text()  # 텍스트 추출
        page_text = page_text.replace('\n', ' ').replace('\r', '')  # 줄바꿈 제거
        page_text = ' '.join(page_text.split())  # 공백 정리
        text += page_text + '\n'  # 페이지별 텍스트 추가

# 추출한 전체 텍스트 출력 (디버깅용)
print(text)

# 긴 문자열을 일정한 크기로 나누는 함수
def split_string_into_chunks(input_string, chunk_size):
    return [input_string[i:i+chunk_size] for i in range(0, len(input_string), chunk_size)]
    
# 추출된 텍스트를 512자씩 잘라 리스트로 변환
chunks = split_string_into_chunks(text, 512)

import chromadb
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction

# OpenAI 임베딩 함수 설정
embedding_function = OpenAIEmbeddingFunction(
    api_key=os.getenv("OPENAI_API_KEY"),  # API 키 사용
    model_name=EMBEDDING_MODEL            # 지정한 임베딩 모델 사용
)

# Chroma 클라이언트 생성 (기본은 메모리 기반 ephemeral)
chroma_client = chromadb.Client()

# 'game_rule'이라는 이름의 문서 컬렉션 생성
corpus_collection = chroma_client.create_collection(
    name='game_rule',
    embedding_function=embedding_function
)

# 각 chunk를 임베딩 후 Chroma 컬렉션에 추가
for i, chunk in enumerate(chunks):
    corpus_collection.add(
        ids=[str(i)],       # 각 chunk에 고유한 문자열 ID 부여
        documents=chunk     # 실제 텍스트 문서
    )

# 검색된 문맥(context)과 질문을 바탕으로 ChatGPT에게 줄 프롬프트 생성
def build_prompt_with_context(text, context):
    # context가 2차원 배열로 들어올 경우 1차원으로 펼치기
    if isinstance(context[0], list):
        context = [item for sublist in context for item in sublist]

    return [
        {'role': 'system', 'content': "부루마블 게임 규칙을 참고하여 답변해주세요."},
        {'role': 'user', 'content': f"""
            부루 마블 보드 게임 규칙 :
            {context}

            위 규칙을 참고하여 아래 질문에 답변해주세요
            {text}

            Answer:
            """
         }
    ]

# context를 포함한 질문에 대해 OpenAI Chat Completion 실행
def assess_claims_with_context(text, context):
    responses = []
    response = client.chat.completions.create(
        model='gpt-4o-mini',  # 생성에 사용할 LLM
        messages=build_prompt_with_context(text=text, context=context)
    )
    # 첫 번째 응답 메시지를 리스트에 저장
    responses.append(response.choices[0].message.content)
    return responses

# 전체 RAG 기반 질의 함수
def RAG_chat(prompt):
    # 유사한 문서 5개 검색 (벡터 검색)
    query_result = corpus_collection.query(query_texts=prompt, n_results=5)

    # 검색된 문서를 context로 사용해 질문에 답변 생성
    res = assess_claims_with_context(prompt, query_result['documents'])

    # 검색된 문서 내용 출력 (디버깅용)
    print(query_result['documents'])

    return res

# 실제 질의 수행
response = RAG_chat("게임에서 땅 증서가 5~6장만 남았을 때 경매는 어떻게 진행되나요?")
print(response)

 

Chroma

  • 대형 언어 모델(LLM)과 함께 사용할 수 있는 오픈소스 벡터 데이터베이스
  • 간단히 말해, 문서나 문장을 의미 벡터(Embedding)로 변환해 저장하고, 나중에 유사한 내용을 빠르게 검색할 수 있게 도와주는 데이터베이스
  • LLM을 위한 검색 기반 시스템(RAG)에서, "문맥을 기억하고 불러오기 위한 벡터 DB 역할"을 하는 도구
기존의 키워드 기반 검색은 "단어가 같아야" 찾아낼 수 있었음
하지만 LLM과 함께 쓰려면 "의미적으로 비슷한 문장"도 찾을 수 있어야 함
그래서 필요한 게 문장을 수치 벡터(Embedding)로 바꾸고, 이걸 저장하고 검색할 수 있는 벡터 데이터베이스
특징 설명
🆓 오픈소스 MIT 라이선스로 자유롭게 사용 가능
빠른 인메모리 검색 초기에는 메모리 기반으로 작동 (빠르지만 휘발성)
💾 디스크 기반 퍼시스턴트 모드 SQLite 기반으로 데이터 영구 저장도 가능
🤝 LLM 친화적 설계 LangChain, LlamaIndex, OpenAI 등과 쉽게 통합
🧩 간단한 API .add(), .query() 등 직관적인 함수 구성
🧠 임베딩 함수 연동 OpenAI, HuggingFace, 자체 모델 등과 연동 가능

 

 

Llama-Index

  • 대형 언어 모델(LLM)이 외부 데이터(문서, PDF, 데이터베이스 등)에 접근하고 이를 효율적으로 검색(Retrieval)하고 활용할 수 있도록 연결해주는 프레임워크
  • LLM과 개인/기업의 사적 지식을 연결해주는 인터페이스 역할
  • 핵심 개념
    • 문서 로딩 (Ingestion) 다양한 형식(PDF, HTML, CSV 등)의 데이터를 읽어 들임
    • 인덱싱 (Indexing) 문서를 잘게 나누고(Chunking), 벡터로 변환하여 검색 가능하게 함
    • 질문-응답 (Querying) 사용자의 질문에 대해 적절한 문서를 검색하고, LLM을 통해 자연어 응답 생성
    • RAG 구성 Retrieval Augmented Generation 구현을 위한 전 과정 지원

구성 요소 역할
Document Loaders 다양한 데이터 소스를 읽어들임 (PDF, Web, Notion 등)
Node Parser / Chunker 문서를 의미 단위로 분할 (문맥 유지하며 자르기)
Storage Context 인덱스, 벡터 DB, 메타데이터 저장소 등 통합 관리
Index (e.g., VectorIndex, TreeIndex) 검색 최적화를 위한 인덱스 구조 제공
Retrievers 유사한 노드를 벡터기반으로 검색
Query Engines 검색된 정보 + 사용자 질문을 기반으로 응답 생성
Callbacks / Logging 디버깅, 성능 측정 도구 내장 (e.g. LangSmith 연동)

 

# 필수 패키지 설치
!pip install openai llama-index llama-index-vector-stores-chroma

# Google Drive 마운트
from google.colab import drive
drive.mount('/content/drive')

# API 키 설정
import getpass
import os
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API Key: ")

# 필요한 모듈 import
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext
from llama_index.embeddings.openai import OpenAIEmbedding
from IPython.display import Markdown, display
import chromadb

# (1) 기본 LlamaIndex만 사용하는 예제 ------------------------------

# 디렉토리 내 문서 전체 불러오기
documents = SimpleDirectoryReader("/content/drive/MyDrive/Project_data/prompt").load_data()

# 메모리 기반 인덱스 생성
index = VectorStoreIndex.from_documents(documents)

# 질의 엔진 생성 및 테스트
query_engine = index.as_query_engine()
response = query_engine.query("프롬프트 엔지니어링이 무엇인가요?")
print("✅ [기본 인덱스 결과] \n", response)

# (2) Chroma 벡터 DB와 연동한 예제 ------------------------------

# Chroma 클라이언트 생성 (메모리 기반, 초기 실행만)
chroma_client = chromadb.Client()
chroma_collection = chroma_client.create_collection("quickstart")

# OpenAI 임베딩 모델 정의
embed_model = OpenAIEmbedding(model="text-embedding-3-small")

# 특정 파일 하나만 불러오기 (예: 프롬프트 엔지니어링 로그)
documents = SimpleDirectoryReader(
    input_files=["/content/drive/MyDrive/Project_data/prompt/lil_log_PE.txt"]
).load_data()

# Chroma 기반 벡터 저장소 설정
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)

# 인덱스 생성 (Chroma + 임베딩 연동)
index = VectorStoreIndex.from_documents(
    documents,
    storage_context=storage_context,
    embed_model=embed_model
)

# 질의 및 결과 출력 (Markdown 포맷으로 보기 좋게)
query_engine = index.as_query_engine()
response = query_engine.query("프롬프트 엔지니어링이 무엇인가요?")
display(Markdown(f"✅ **[Chroma 인덱스 결과]**\n\n{response}"))

 

 

직접 구현 vs LlamaIndex

  직접 구현 코드 LlamaIndex 사용
역할 벡터 DB + LLM 연결을 수작업으로 구성 모든 구성요소를 고수준 API로 통합
코드 복잡도 임베딩, 분할, 검색, 프롬프트 구성까지 직접 구현 필요 함수 몇 줄로 모든 처리 가능
확장성 사용자 정의는 쉽지만 구조가 단단히 고정됨 다양한 Retriever, QueryEngine을 쉽게 교체 가능
호환성 특정 DB(OpenAI + Chroma)만 직접 연동됨 다양한 벡터DB, LLM, 로더, 프롬프트 엔진과 플러그인식 통합 가능
생산성 작은 규모에서는 충분하지만 반복 작업 많음 대규모 서비스나 빠른 프로토타이핑에 적합
디버깅 로우레벨 제어가 가능하지만 디버깅 부담 있음 log/callback 시스템 내장, LangSmith 연동 가능
사용자층 ML/프롬프트 엔지니어링에 익숙한 개발자 초보자~전문가까지 모두 대상

 

LlamaIndex가 해주는 것들 (자동화)

  직접 구현 LlamaIndex
텍스트 전처리 직접 정제하고 나눔 자동으로 의미 단위로 chunking
문서 저장소 Chroma에 직접 add() VectorStoreIndex로 자동 연결
쿼리 수행 .query() → documents → prompt 구성 → LLM 호출 .query() 한 줄로 검색+프롬프트+응답 생성
임베딩 설정 EmbeddingFunction 직접 지정 embed_model=OpenAIEmbedding() 등으로 명시적 구성
결과 가공 출력 문자열 직접 파싱 Markdown 출력, JSON 응답 등 다양한 포맷 제공 가능

 

기술 구조 비교

 

Function calling

  • 언어 모델이 자연어 입력을 해석해, 프로그래밍 함수의 이름과 그 인자 값을 자동으로 생성하는 기능
  • LLM (대규모 언어 모델)과 외부 함수 또는 도구를 연결해주는 강력한 인터페이스
  • OpenAI, LlamaIndex 등 다양한 프레임워크에서 이를 지원하고 있으며, 특히 에이전트 시스템이나 툴 기반 응답 시스템에서 핵심적으로 활용됨
  • 정확한 도구 연결: 모델이 직접 계산하거나 외부 API와 연동 가능
  • 확장성: 수십~수백 개의 함수와 연결해 다기능형 에이전트 구현 가능
  • 자연어 인터페이스의 자동화: 사용자는 “프로그래밍”이 아닌 “말하기”만 하면 됨

 

Function Calling 구현

!pip install openai llama-index

import getpass
import os

os.environ["OPENAI_API_KEY"] = "API KEY"

from openai import OpenAI
import json

client = OpenAI()
client

# 더미 함수 설정
def get_current_weather(location, unit="celsius"):
    """Get the current weather in a given location"""
    if "tokyo" in location.lower():
        return json.dumps({"location": "Tokyo", "temperature": "10", "unit": unit})
    elif "san francisco" in location.lower():
        return json.dumps({"location": "San Francisco", "temperature": "27", "unit": unit})
    elif "paris" in location.lower():
        return json.dumps({"location": "Paris", "temperature": "22", "unit": unit})
    else:
        return json.dumps({"location": location, "temperature": "unknown"})

# Function calling 구현
def run_conversation(prompt):
    # Part 1
    # 사용자의 메세지 (프롬프트)를 입력하고, 사용할 함수를 정의해줍니다.
    # 위에서 정의한 더미 함수가 어떻게 동작하는지 description을 포함해서 작성하고, 인자들에 대한 특징을 입력합니다.
    messages = [{"role": "user", "content": prompt}]
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "Get the current weather in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city and state, e.g. San Francisco, CA",
                        },
                        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                    },
                    "required": ["location"],
                },
            },
        }
    ]

    # 위 메세지와 함수정의를 chat api로 전달합니다.
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )
    response_message = response.choices[0].message
    print(response_message)
    tool_calls = response_message.tool_calls
    print(tool_calls)
    # 사용할 function을 정의해 대응을 준비합니다.

    # Part 2
    # 모델 응답에서 함수 호출이 필요한지 먼저 확인합니다.
    # 이는 tool이 불렸는지 확인하는 변수로 체크합니다.
    # tool_calls가 동작한다면, 아래 message를 전달할 준비를 합니다.
    if tool_calls:
        # 함수가 호출되었으면, 사용할 함수들을 입력합니다.
        # 이 예제에서는 get_current_weather 함수 하나만 사용하지만, 실제로는 여러 함수를 정의할 수 있습니다.
        available_functions = {
            "get_current_weather": get_current_weather,
        }  # 여러 함수 지정도 가능합니다.

        # 이전 대화를 기반으로 답변하도록 메세지를 추가해줍니다.
        messages.append(response_message)  # AI 답변까지 추가
        # Function Call 동작을 위한 data 전달
        for tool_call in tool_calls: #s
            function_name = tool_call.function.name
            """
            {'location': 'San Francisco'}
            {'location': 'Tokyo'}
            {'location': 'Paris'}
            """
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            print(function_args)
            function_response = function_to_call(# get_current_weather('San Francisco')
                location=function_args.get("location"),
                unit=function_args.get("unit"),
            )
            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )  # extend conversation with function response
        second_response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages,
        )  # get a new response from the model where it can see the function response
        print(messages)

        return second_response

res = run_conversation("What's the weather like in San Francisco, Tokyo, and Paris?")

 

Llama-index 구현

!pip install llama-index-agent-openai
!pip install llama-index-llms-openai

from llama_index.agent.openai import OpenAIAgent
from llama_index.llms.openai import OpenAI
from llama_index.core.tools import BaseTool, FunctionTool

# FunctionTool 생성
weather_tool = FunctionTool.from_defaults(fn=get_current_weather)

# OpenAI LLM 설정
llm = OpenAI(model="gpt-4o")

# OpenAIAgent 생성
agent = OpenAIAgent.from_tools(
    [weather_tool],
    llm=llm,
    verbose=True
)

# 단일 도시 날씨 쿼리
response = agent.chat("도쿄의 현재 날씨는 어떤가요?")
print("질문 1: 도쿄의 현재 날씨는 어떤가요?")
print("답변:", response)

# 여러 도시 날씨 비교 쿼리
response = agent.chat("샌프란시스코, 도쿄, 파리의 날씨를 비교해주세요.")
print("\n질문 2: 샌프란시스코, 도쿄, 파리의 날씨를 비교해주세요.")
print("답변:", response)

# 알 수 없는 도시 쿼리
response = agent.chat("뉴욕의 날씨는 어떤가요?")
print("\n질문 3: 뉴욕의 날씨는 어떤가요?")
print("답변:", response)

 

 

YouTube QnA Chatbot

!pip install openai llama-index llama-index-vector-stores-chroma yt-dlp

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass()

from llama_index.llms.openai import OpenAI
from llama_index.core import Settings

Settings.llm = OpenAI(model="gpt-4o")

from openai import OpenAI as OpenAIClient
import yt_dlp
import os

client = OpenAIClient()

# YouTube 비디오에서 오디오 다운로드
def download_audio_from_youtube(url, output_path='audio'):
    ydl_opts = {
        'format': 'bestaudio/best',
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '192',
        }],
        'outtmpl': output_path,
        'quiet': True,
    }
    try:
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            ydl.download([url])
        return output_path + ".mp3"
    except Exception as e:
        print(f"An error occurred: {e}")
    return None

# OpenAI의 Whisper를 사용하여 오디오 텍스트 변환
def transcribe_audio(file_path):
    try:
        with open(file_path, 'rb') as audio_file:
            transcription = client.audio.transcriptions.create(
                model="whisper-1",
                file=audio_file
            )
        return transcription.text
    # except openai.error.InvalidRequestError as e:
    #     print(f"Invalid request error: {e}")
    # except openai.error.APIError as e:
    #     print(f"API error: {e}")
    # except openai.error.OpenAIError as e:
    #     print(f"OpenAI error: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
    return None

# 오디오 다운로드 및 변환 메인 함수
def get_youtube_transcription(youtube_url, save_path="transcription.txt"):
    audio_path = download_audio_from_youtube(youtube_url)
    if audio_path:
        transcription = transcribe_audio(audio_path)
        if transcription:
            print(transcription)
            os.makedirs(os.path.dirname(save_path), exist_ok=True)
            with open(save_path, "w", encoding="utf-8") as file:
                file.write(transcription)
        else:
            print("Transcription failed.")
        os.remove(audio_path)  # 변환 후 오디오 파일 삭제

        return transcription
    else:
        print("Audio download failed.")

# 사용 예제
youtube_url = "https://www.youtube.com/watch?v=l6n6ap9q0oY"
save_path = 'youtube/script.txt'
text = get_youtube_transcription(youtube_url, save_path)

# import
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext
from llama_index.embeddings.openai import OpenAIEmbedding
from IPython.display import Markdown, display
import chromadb

# create client and a new collection
chroma_client = chromadb.EphemeralClient() #on memory
chroma_collection = chroma_client.create_collection("quickstart") # 1번만 실행합니다!

from llama_index.core.node_parser import SentenceSplitter

# define embedding function
embed_model = OpenAIEmbedding(
    model = "text-embedding-3-small",
)

# load documents (text)
documents = SimpleDirectoryReader(input_files=[save_path]).load_data()

# set up ChromaVectorStore and load in data
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
    documents,
    storage_context=storage_context,
    embed_model=embed_model,
    transformations=[SentenceSplitter(chunk_size=1024, chunk_overlap=20)]
)

from typing import List
from llama_index.core.bridge.pydantic import BaseModel, Field, field_validator

class QAItem(BaseModel):
    question: str = Field(description="작성된 문제를 해당 파트에 저장")
    answer: str = Field(description="작성된 문제의 정답 내용을 저장")

class QABank(BaseModel):
    qa_list: List[QAItem] = Field(description="작성된 모든 QA 항목 리스트")

# Query Data
query_engine = index.as_query_engine(similarity_top_k=7, output_cls=QABank)

prompt = """"
다음 텍스트를 바탕으로 학습용 퀴즈 문제를 3개 생성해줘.
각 문제는 질문(question)과 그에 대한 정답(answer)을 포함해야 해.
질문은 정보 이해를 평가하는 수준이어야 하며, 가능한 명확하게 만들어줘.
"""

response_class = query_engine.query(prompt)
print(response_class.response)

import json
import os

def get_qa_info(question, qa_bank_instance=qa_bank_instance):
    """
    주어진 질문(question)에 대해 QABank 인스턴스(qa_bank_instance)에서 답변을 찾아 반환합니다.
    만약 질문과 일치하는 항목이 없다면 "unknown"을 반환합니다.
    qa_bank_instance의 경우 기존의 인스턴스를 사용하기 때문에 따로 인자로 넣지 않습니다.
    """

    for item in qa_bank_instance.qa_list:
        if item.question == question:
            return {"question": question, "answer": item.answer}
    return {"question": question, "answer": "unknown"}

from llama_index.agent.openai import OpenAIAgent
from llama_index.core.tools import FunctionTool

# FunctionTool 생성
qa_tool = FunctionTool.from_defaults(
    fn=get_qa_info,
    name="get_qa_info",
    description="""
    주어진 질문에 대해 QABank 인스턴스에서 답변을 찾아 반환합니다.
    만약 질문과 일치하는 항목이 없다면 "unknown"을 반환합니다.
    """
)

# OpenAI LLM 설정
llm = OpenAI(model="gpt-4o")

# OpenAIAgent 생성
agent = OpenAIAgent.from_tools(
    [qa_tool],
    llm=llm,
    verbose=True
)

import random

def print_question_and_get_user_answer(qa_bank_instance):
    """
    QABank 인스턴스를 받아, 저장된 문제들 중 하나를 랜덤하게 선택하여 출력하고
    사용자로부터 답변을 입력받아 반환합니다.
    """
    # QABank 인스턴스에서 '문제' 리스트 추출
    questions = [item.question for item in qa_bank_instance.qa_list if hasattr(item, 'question')]

    if questions:
        random_question = random.choice(questions)
        print(f"question: {random_question}")

        # 사용자로부터 답변 입력 받기
        user_answer = input("answer: ")
        return random_question, user_answer
    else:
        print("QABank 인스턴스에 문제가 없습니다.")
        return None, None

# 함수 호출 예시:
r_question, user_response = print_question_and_get_user_answer(qa_bank_instance)

response = agent.chat(f"""
아래 문제와 답변이 맞는지 확인해줘.

문제: {r_question}
정답: {user_response}

실제 정답과 제출한 정답을 다시 한번 분석해서
어떤 부분이 맞고 틀렸는지 해설을 해줘.

""")
print("답변:", response)

 

gpt-4o Multimodal Structured Outputs

이미지 기반 뉴스 정보 추출

# 📦 필요한 패키지 설치
%pip install -q llama-index-llms-openai llama-index-multi-modal-llms-openai \
                llama-index-readers-file llama-index-core

# 🔐 OpenAI API 키 설정
import os
os.environ["OPENAI_API_KEY"] = "your API KEY"  # ← 본인의 OpenAI 키로 교체하세요

# 📂 드라이브 마운트 (Google Colab 전용)
from google.colab import drive
drive.mount('/content/drive')

# 📚 기본 라이브러리 및 llama-index 모듈 import
from PIL import Image
import matplotlib.pyplot as plt
from llama_index.core import SimpleDirectoryReader
from llama_index.core.multi_modal_llms.generic_utils import load_image_urls
from llama_index.core.program import MultiModalLLMCompletionProgram
from llama_index.multi_modal_llms.openai import OpenAIMultiModal
from llama_index.core.bridge.pydantic import BaseModel, Field
from enum import Enum
from typing import List

# 📁 이미지 경로 및 로딩
image_path = "/content/drive/MyDrive/Project_data/Multimodal/"  # 뉴스 이미지 폴더 경로
image_documents = SimpleDirectoryReader(image_path).load_data()

# 🖼️ 첫 번째 이미지 시각화
img_doc = image_documents[0]
image = Image.open(img_doc.image_path).convert("RGB")
plt.figure(figsize=(8, 8))
plt.axis("off")
plt.imshow(image)
plt.show()

# 📊 추출할 뉴스 정보 구조 정의 (Pydantic 사용)
class Subject(str, Enum):
    정치 = "정치"
    사회 = "사회"
    경제 = "경제"
    기타 = "기타"

class NEWS(BaseModel):
    """이미지에서 추출할 뉴스 데이터 스키마"""
    title: List[str] = Field(description="뉴스의 제목입니다.")
    comment: List[str] = Field(description="뉴스 기사 옆 댓글 수 입니다.")
    subject: List[Subject] = Field(description="뉴스의 주제입니다. 정치/사회/경제 중 하나여야 합니다.")

# 📝 모델에게 전달할 프롬프트 정의
news_extraction_prompt = """
첨부된 이미지에서 데이터를 추출하고, 이를 제공된 NEWS 데이터 클래스에 저장해줘
"""

# 🤖 GPT-4o 멀티모달 모델 초기화
gpt_4o = OpenAIMultiModal(model="gpt-4o", max_new_tokens=4096)

# 🧠 멀티모달 프로그램 정의 (프롬프트 + 모델 + 출력 구조)
program = MultiModalLLMCompletionProgram.from_defaults(
    output_cls=NEWS,
    prompt_template_str=news_extraction_prompt,
    multi_modal_llm=gpt_4o,
)

# 🚀 첫 번째 이미지에 대해 뉴스 정보 추출 실행
news = program(image_documents=[image_documents[0]])

# 📋 추출된 뉴스 항목 출력
for i in range(len(news.title)):
    print(f"Title: {news.title[i]}, Comment: {news.comment[i]}, Subject: {news.subject[i]}")

'AI' 카테고리의 다른 글

Llama index Agents  (1) 2025.05.28
RAG를 활용한 챗봇 개발 - Agentic Prompt  (0) 2025.05.26
Multi-Agent with LangGraph  (1) 2025.05.16
VectorDB와 RAG  (0) 2025.05.16
프롬프트와 LLM 엔지니어링  (0) 2025.05.16
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로