[κ°•μ˜λ…ΈνŠΈ] RAG From Scratch : Query Routing & Structuring

Posted by Euisuk's Dev Log on September 14, 2024

[κ°•μ˜λ…ΈνŠΈ] RAG From Scratch : Query Routing & Structuring

원본 κ²Œμ‹œκΈ€: https://velog.io/@euisuk-chung/RAG-From-Scratch-10-11

  • ν•΄λ‹Ή λΈ”λ‘œκ·Έ ν¬μŠ€νŠΈλŠ” RAG From Scratch : Coursework κ°•μ˜ 파트 10 - 11 λ‚΄μš©μ„ 닀루고 μžˆμŠ΅λ‹ˆλ‹€.
λΉ„λ””μ˜€ μš”μ•½ κ°•μ˜ 링크 μŠ¬λΌμ΄λ“œ
Part 10 (λΌμš°νŒ…) 쿼리λ₯Ό κ΄€λ ¨ 데이터 μ†ŒμŠ€λ‘œ μœ λ„ν•˜κΈ° μœ„ν•œ 논리적 및 의미적 쿼리 λΌμš°νŒ…μ„ λ‹€λ£Ήλ‹ˆλ‹€. πŸ“Œ κ°•μ˜ πŸ“– μŠ¬λΌμ΄λ“œ
Part 11 (쿼리 ꡬ쑰화) μžμ—°μ–΄ 쿼리λ₯Ό κ΅¬μ‘°ν™”λœ 쿼리둜 λ³€ν™˜ν•˜μ—¬ λ°μ΄ν„°λ² μ΄μŠ€ μƒν˜Έμž‘μš©μ„ νš¨μœ¨ν™”ν•˜λŠ” 방법을 λ‹€λ£Ήλ‹ˆλ‹€. πŸ“Œ κ°•μ˜ πŸ“– 참고자료

Part 10 (λΌμš°νŒ…)

  • μœ„ 그림의 단계에 따라 각 κ³Όμ •μ˜ μ—­ν• κ³Ό κ°œλ…μ„ κ°„λž΅ν•˜κ²Œ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€:

    1. Question (질문) : μ‚¬μš©μžκ°€ μ‹œμŠ€ν…œμ— μž…λ ₯ν•˜λŠ” μžμ—°μ–΄ ν˜•νƒœμ˜ μ§ˆλ¬Έμž…λ‹ˆλ‹€. μ΄λŠ” 전체 ν”„λ‘œμ„ΈμŠ€μ˜ μ‹œμž‘μ μ΄ λ©λ‹ˆλ‹€.
    2. Query Translation (쿼리 λ²ˆμ—­) : μ‚¬μš©μžμ˜ μžμ—°μ–΄ μ§ˆλ¬Έμ„ μ‹œμŠ€ν…œμ΄ 이해할 수 μžˆλŠ” ν˜•μ‹μœΌλ‘œ λ³€ν™˜ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. μ΄λŠ” μžμ—°μ–΄ 처리 κΈ°μˆ μ„ ν™œμš©ν•˜μ—¬ μˆ˜ν–‰λ©λ‹ˆλ‹€.
    3. Routing (λΌμš°νŒ…, 이번 μ±•ν„°πŸ“Œ) : λ³€ν™˜λœ 쿼리λ₯Ό μ μ ˆν•œ 처리 κ²½λ‘œλ‚˜ 데이터 μ†ŒμŠ€λ‘œ μ•ˆλ‚΄ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. 질문의 νŠΉμ„±μ— 따라 졜적의 처리 방법을 κ²°μ •ν•©λ‹ˆλ‹€.
    4. Query Construction (쿼리 ꡬ성) : λΌμš°νŒ…λœ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ μ‹€μ œ λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ 검색 μ—”μ§„μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” ν˜•νƒœμ˜ 쿼리λ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€.
    5. Indexing (인덱싱) : λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ λ¬Έμ„œ μ»¬λ ‰μ…˜μ—μ„œ 효율적인 검색을 μœ„ν•΄ 데이터λ₯Ό κ΅¬μ‘°ν™”ν•˜κ³  μ‘°μ§ν™”ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. μ΄λŠ” 주둜 μ‹œμŠ€ν…œ ꡬ좕 λ‹¨κ³„μ—μ„œ μˆ˜ν–‰λ©λ‹ˆλ‹€.
    6. Retrieval (검색) : κ΅¬μ„±λœ 쿼리λ₯Ό μ‚¬μš©ν•˜μ—¬ μΈλ±μ‹±λœ λ°μ΄ν„°μ—μ„œ κ΄€λ ¨ 정보λ₯Ό μΆ”μΆœν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. 이 λ‹¨κ³„μ—μ„œ 질문과 κ°€μž₯ κ΄€λ ¨μ„± 높은 정보λ₯Ό μ°Ύμ•„λƒ…λ‹ˆλ‹€.
    7. Generation (생성) : κ²€μƒ‰λœ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ μ§ˆλ¬Έμ— λŒ€ν•œ 닡변을 μƒμ„±ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. 이 λ‹¨κ³„μ—μ„œλŠ” 주둜 μžμ—°μ–΄ 생성 기술이 μ‚¬μš©λ©λ‹ˆλ‹€.
    8. Answer (λ‹΅λ³€) : μ΅œμ’…μ μœΌλ‘œ μƒμ„±λœ 닡변을 μ‚¬μš©μžμ—κ²Œ μ œκ³΅ν•©λ‹ˆλ‹€. μ΄λŠ” μ›λž˜ μ§ˆλ¬Έμ— λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ, μžμ—°μ–΄ ν˜•νƒœλ‘œ ν‘œν˜„λ©λ‹ˆλ‹€.
  • 이 과정은 질문 응닡 μ‹œμŠ€ν…œμ˜ μ „ν˜•μ μΈ νŒŒμ΄ν”„λΌμΈμ„ λ‚˜νƒ€λ‚΄λ©°, 각 λ‹¨κ³„λŠ” μ‚¬μš©μžμ˜ μ§ˆλ¬Έμ— λŒ€ν•΄ μ •ν™•ν•˜κ³  κ΄€λ ¨μ„± 높은 닡변을 μ œκ³΅ν•˜κΈ° μœ„ν•΄ 유기적으둜 μž‘λ™ν•©λ‹ˆλ‹€.
  • 이번 κ°•μ˜λŠ” 3. Routing(λΌμš°νŒ…)μ΄λΌλŠ” κ°œλ…μ„ μ„€λͺ…ν•˜κ³ , 두 κ°€μ§€ μ£Όμš” λΌμš°νŒ… 방법인 β‘  논리적 λΌμš°νŒ…(Logical Routing)κ³Ό β‘‘ 의미적 λΌμš°νŒ…(Semantic Routing)을 λ‹€λ£Ήλ‹ˆλ‹€.

1. λΌμš°νŒ… κ°œλ…

  • λΌμš°νŒ…(Routing)은 μ§ˆλ¬Έμ„ μ μ ˆν•œ 데이터 μ†ŒμŠ€λ‘œ μ „λ‹¬ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

    • RAG(질문-λ‹΅λ³€ 생성 λͺ¨λΈ)μ—μ„œ λΌμš°νŒ…μ€ νŠΉμ • μ§ˆλ¬Έμ„ μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μ μ ˆν•œ λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ ν”„λ‘¬ν”„νŠΈμ— μ—°κ²°ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€.
  • λ‹€λ₯΄κ²Œ μ •μ˜ν•΄λ³Έλ‹€λ©΄, λΌμš°νŒ…μ„ μ•„λž˜μ™€ 같이 μ •μ˜ν•΄λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€:

    • μ •μ˜: μž…λ ₯된 μΏΌλ¦¬λ‚˜ μž‘μ—…μ„ μ μ ˆν•œ λͺ¨λΈμ΄λ‚˜ 처리 경둜둜 μ•ˆλ‚΄ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€.
    • λͺ©μ : μ£Όμ–΄μ§„ μž…λ ₯에 κ°€μž₯ μ ν•©ν•œ LLMμ΄λ‚˜ 처리 λͺ¨λ“ˆμ„ μ„ νƒν•©λ‹ˆλ‹€.
    • μž‘λ™ 방식: μž…λ ₯의 νŠΉμ„±μ„ λΆ„μ„ν•˜μ—¬ 미리 μ •μ˜λœ κ·œμΉ™μ΄λ‚˜ ν•™μŠ΅λœ μ•Œκ³ λ¦¬μ¦˜μ„ 톡해 졜적의 처리 경둜λ₯Ό κ²°μ •ν•©λ‹ˆλ‹€.
    • 적용: λ‹€μ–‘ν•œ LLM을 효율적으둜 ν™œμš©ν•˜κ±°λ‚˜, νŠΉμ • 도메인에 νŠΉν™”λœ λͺ¨λΈλ‘œ 쿼리λ₯Ό μ „λ‹¬ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€.
  • μ˜ˆμ‹œ μ‹œλ‚˜λ¦¬μ˜€: μ‚¬μš©μžκ°€ μ½”λ”© κ΄€λ ¨ μ§ˆλ¬Έμ„ ν•  λ•Œ, μ‹œμŠ€ν…œμ€ κ·Έ μ§ˆλ¬Έμ„ μ μ ˆν•œ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄ λ¬Έμ„œ(예: Python, JS, Golang)둜 λΌμš°νŒ…ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
  • λΌμš°νŒ… 방법은 크게 논리적 λΌμš°νŒ…(Logical Routing)κ³Ό 의미적 λΌμš°νŒ…(Semantic Routing)으둜 λ‚˜λˆŒ 수 μžˆμŠ΅λ‹ˆλ‹€. 이 두 방법은 λ‹€μŒκ³Ό 같이 μ •μ˜λ˜κ³  κ΅¬λΆ„λ©λ‹ˆλ‹€:

2.1. 논리적 λΌμš°νŒ… (Logical Routing) μ„€λͺ…

논리적 λΌμš°νŒ… κ°œλ…

  • 논리적 λΌμš°νŒ…μ€ μ‹œμŠ€ν…œμ΄ λ‹€μ–‘ν•œ 데이터 μ†ŒμŠ€ 쀑 μ–΄λ–€ μ†ŒμŠ€λ₯Ό μ‚¬μš©ν• μ§€ 미리 μ„€μ •λœ κ·œμΉ™μ— 따라 κ²°μ •ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
  • μ‚¬μš©μžκ°€ μ§ˆλ¬Έμ„ μž…λ ₯ν•˜λ©΄ LLM(Large Language Model)은 κ·Έ 질문이 μ–΄λŠ λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ λ¬Έμ„œ μ†ŒμŠ€μ™€ κ°€μž₯ 관련이 μžˆλŠ”μ§€ κ²°μ •ν•˜κ³ , ν•΄λ‹Ή μ†ŒμŠ€λ‘œ λΌμš°νŒ…ν•˜μ—¬ 닡변을 μƒμ„±ν•©λ‹ˆλ‹€.

νŠΉμ§•

  • 주둜 β€œκ΅¬μ‘°ν™”λœ 좜λ ₯”을 μ‚¬μš©ν•˜μ—¬ λΌμš°νŒ…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€. 즉, μ‹œμŠ€ν…œμ€ μ§ˆλ¬Έμ„ 미리 μ •μ˜λœ κ·œμΉ™μ— 따라 λΆ„λ₯˜ν•˜κ³  그에 λ§žλŠ” 데이터 μ†ŒμŠ€λ₯Ό μ„ νƒν•©λ‹ˆλ‹€.
  • 질문이 λͺ…ν™•νžˆ ꡬ뢄 κ°€λŠ₯ν•œ μ£Όμ œλ‚˜ λ°μ΄ν„°λ² μ΄μŠ€μ™€ 관련이 μžˆμ„ λ•Œ 맀우 μ ν•©ν•œ λ°©λ²•μž…λ‹ˆλ‹€.

κ³Όμ •

  1. μ‚¬μš©μžκ°€ μ§ˆλ¬Έμ„ μž…λ ₯ν•©λ‹ˆλ‹€.

  2. LLM이 κ·Έ μ§ˆλ¬Έμ„ λΆ„μ„ν•˜μ—¬ 미리 μ„€μ •λœ 데이터 μ†ŒμŠ€ λͺ©λ‘(예: Python λ¬Έμ„œ, JS λ¬Έμ„œ λ“±) μ€‘μ—μ„œ κ°€μž₯ μ ν•©ν•œ μ†ŒμŠ€λ₯Ό κ²°μ •ν•©λ‹ˆλ‹€.

  3. μ„ νƒλœ 데이터 μ†ŒμŠ€λ₯Ό λ°”νƒ•μœΌλ‘œ 닡변을 μƒμ„±ν•©λ‹ˆλ‹€.

μ½”λ“œ μ„€λͺ…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI

# Data model
class RouteQuery(BaseModel):
    """Route a user query to the most relevant datasource."""
    datasource: Literal["python_docs", "js_docs", "golang_docs"] = Field(
        ..., description="Given a user question choose which datasource would be most relevant for answering their question",
    )

# LLM with function call 
llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
structured_llm = llm.with_structured_output(RouteQuery)

# Prompt μ •μ˜
system = """
You are an expert at routing a user question to the appropriate data source.

Based on the programming language the question is referring to, route it to the relevant data source.
"""

prompt = ChatPromptTemplate.from_messages(
    [("system", system), ("human", "{question}")])

# Define router 
router = prompt | structured_llm
  • RouteQueryλŠ” μ‚¬μš©μž μ§ˆλ¬Έμ„ μ μ ˆν•œ 데이터 μ†ŒμŠ€λ‘œ λΌμš°νŒ…ν•˜κΈ° μœ„ν•΄ 미리 μ •μ˜λœ datasource μ˜΅μ…˜μ„ ν¬ν•¨ν•˜λŠ” ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
    • Field(...)μ—μ„œ …은 Python의 pydantic λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ μ‚¬μš©λ˜λŠ” νŠΉλ³„ν•œ ν‘œν˜„μœΌλ‘œ, ν•„λ“œλ₯Ό ν•„μˆ˜ ν•„λ“œλ‘œ μ§€μ •ν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.
    • μœ„ μ½”λ“œμ—μ„œ datasource ν•„λ“œλŠ” ν•„μˆ˜λ‘œ μ œκ³΅λ˜μ–΄μ•Ό ν•˜λ©°, 값이 μ—†λ‹€λ©΄ λͺ¨λΈ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.
  • structured_llm은 LLM이 κ΅¬μ‘°ν™”λœ 좜λ ₯ ν˜•μ‹μ„ μ‚¬μš©ν•˜λ„λ‘ μ„€μ •λœ LLMμž…λ‹ˆλ‹€.
  • promptλŠ” μ‹œμŠ€ν…œμ΄ μ§ˆλ¬Έμ„ μ²˜λ¦¬ν•˜κ³  데이터 μ†ŒμŠ€λ₯Ό κ²°μ •ν•˜λŠ” 방법을 μ •μ˜ν•˜λŠ” ν…œν”Œλ¦Ώμž…λ‹ˆλ‹€.
1
2
3
4
5
6
7
8
9
10
11
12
13
# 질문 μ˜ˆμ‹œ
question = """
Why doesn't the following code work:

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages(["human", "speak in {language}"])
prompt.invoke("french")

"""

# LLM이 μ§ˆλ¬Έμ„ λΆ„μ„ν•˜μ—¬ μ μ ˆν•œ 데이터 μ†ŒμŠ€λ₯Ό λ°˜ν™˜
result = router.invoke({"question": question})
  • resultμ—λŠ” RouteQuery(datasource=’python_docs’)값이 λ“€μ–΄κ°€ μžˆλŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
    • μ‚¬μš©μžλŠ” Python μ½”λ“œμ™€ κ΄€λ ¨λœ μ§ˆλ¬Έμ„ μž…λ ₯ν–ˆμŠ΅λ‹ˆλ‹€. (question)
    • LLM은 미리 μ„€μ •λœ 지침에 따라 μ§ˆλ¬Έμ„ λΆ„μ„ν•©λ‹ˆλ‹€. (router.invoke({β€œquestion”: question}))
    • LLM은 질문의 λ§₯락이 Pythonκ³Ό κ΄€λ ¨λ˜μ–΄ μžˆμŒμ„ κ°μ§€ν•˜κ³ , (router = prompt structured_llm)
    • RouteQuery(datasource=’python_docs’)λΌλŠ” κ΅¬μ‘°ν™”λœ 좜λ ₯을 μƒμ„±ν•˜μ—¬ μ μ ˆν•œ 데이터 μ†ŒμŠ€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
1
2
3
4
5
6
7
8
9
10
11
12
13
# μ„ νƒλœ 데이터 μ†ŒμŠ€μ— 따라 좔가적인 처리 μˆ˜ν–‰
def choose_route(result):
    if "python_docs" in result.datasource.lower():
        return "chain for python_docs"
    elif "js_docs" in result.datasource.lower():
        return "chain for js_docs"
    else:
        return "chain for golang_docs"

# μ΅œμ’…μ μœΌλ‘œ μ„ νƒλœ κ²½λ‘œμ— 따라 λΌμš°νŒ…
full_chain = router | RunnableLambda(choose_route)

full_chain.invoke({"question": question})  # 'chain for python_docs'
  • choose_route() ν•¨μˆ˜λŠ” λ°˜ν™˜λœ 데이터 μ†ŒμŠ€λ₯Ό 기반으둜 λ‹€μŒ λ‹¨κ³„μ—μ„œ μ–΄λ–€ 처리λ₯Ό ν• μ§€ κ²°μ •ν•©λ‹ˆλ‹€.
    • 이 μ˜ˆμ‹œμ—μ„œ μ‚¬μš©μžλŠ” μ§ˆλ¬Έμ„ μž…λ ₯ν•˜κ³ , μ‹œμŠ€ν…œμ€ 이λ₯Ό λΆ„μ„ν•˜μ—¬ μ μ ˆν•œ 데이터 μ†ŒμŠ€λ₯Ό μ„ νƒν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, Pythonκ³Ό κ΄€λ ¨λœ 질문이라면 python_docs둜 λΌμš°νŒ…λ©λ‹ˆλ‹€.

2.2. 의미적 λΌμš°νŒ… (Semantic Routing) μ„€λͺ…

의미적 λΌμš°νŒ… κ°œλ…

  • 의미적 λΌμš°νŒ…μ€ 질문과 μ—¬λŸ¬ ν”„λ‘¬ν”„νŠΈ κ°„μ˜ 의미적 μœ μ‚¬μ„±μ„ 기반으둜 μ ν•©ν•œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„ νƒν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
  • μ—¬κΈ°μ„œ 질문과 ν”„λ‘¬ν”„νŠΈλŠ” μž„λ² λ”©(벑터화)된 ν›„ μœ μ‚¬λ„λ₯Ό κ³„μ‚°ν•˜μ—¬, κ°€μž₯ μœ μ‚¬ν•œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„ νƒν•©λ‹ˆλ‹€.

νŠΉμ§•

  • 질문과 ν”„λ‘¬ν”„νŠΈ κ°„μ˜ 의미적 μœ μ‚¬μ„±μ„ λ°”νƒ•μœΌλ‘œ λΌμš°νŒ…μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.
  • 미리 μ •μ˜λœ λ°μ΄ν„°λ² μ΄μŠ€κ°€ μ•„λ‹ˆλΌ, 질문의 의미λ₯Ό νŒŒμ•…ν•΄ κ°€μž₯ μ ν•©ν•œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„ νƒν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
  • 질문이 λ‹¨μˆœν•œ 정보 μ‘°νšŒκ°€ μ•„λ‹ˆλΌ, 의미적으둜 μœ μ‚¬ν•œ μ—¬λŸ¬ κ°€λŠ₯성을 κ³ λ €ν•΄μ•Ό ν•  λ•Œ μ ν•©ν•©λ‹ˆλ‹€.

κ³Όμ •

  1. μ‚¬μš©μžκ°€ μ§ˆλ¬Έμ„ μž…λ ₯ν•˜λ©΄ μ‹œμŠ€ν…œμ΄ κ·Έ μ§ˆλ¬Έμ„ μž„λ² λ”©(벑터화)ν•©λ‹ˆλ‹€.

  2. μ‹œμŠ€ν…œμ€ μ—¬λŸ¬ ν”„λ‘¬ν”„νŠΈ μ€‘μ—μ„œ 질문과 κ°€μž₯ μœ μ‚¬ν•œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„ νƒν•©λ‹ˆλ‹€.

  3. μ„ νƒλœ ν”„λ‘¬ν”„νŠΈμ— 따라 닡변을 μ œκ³΅ν•©λ‹ˆλ‹€.

μ½”λ“œ μ„€λͺ…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from langchain.utils.math import cosine_similarity
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# 두 κ°€μ§€ ν”„λ‘¬ν”„νŠΈ μ •μ˜
physics_template = """You are a very smart physics professor. \
You are great at answering questions about physics in a concise and easy to understand manner. \
When you don't know the answer to a question you admit that you don't know.

Here is a question:
{query}"""

math_template = """You are a very good mathematician. You are great at answering math questions. \
You are so good because you are able to break down hard problems into their component parts, \
answer the component parts, and then put them together to answer the broader question.
  • 물리학 ν”„λ‘¬ν”„νŠΈμ™€ μˆ˜ν•™ ν”„λ‘¬ν”„νŠΈ 두 κ°€μ§€κ°€ μ£Όμ–΄μ§€λ©°, μ‹œμŠ€ν…œμ΄ μ§ˆλ¬Έμ„ λΆ„μ„ν•œ ν›„ μ ν•©ν•œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„ νƒν•©λ‹ˆλ‹€.
1
2
3
4
5
6
7
Here is a question:
{query}"""

# ν”„λ‘¬ν”„νŠΈ μž„λ² λ”©
embeddings = OpenAIEmbeddings()
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates)
  • OpenAIEmbeddings()λ₯Ό μ‚¬μš©ν•˜μ—¬ 질문과 ν”„λ‘¬ν”„νŠΈλ₯Ό μž„λ² λ”©ν•©λ‹ˆλ‹€.
  • cosine_similarity() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 질문과 ν”„λ‘¬ν”„νŠΈ κ°„μ˜ μœ μ‚¬λ„λ₯Ό κ³„μ‚°ν•˜κ³ , κ°€μž₯ μœ μ‚¬ν•œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„ νƒν•©λ‹ˆλ‹€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# μ§ˆλ¬Έμ„ μ ν•©ν•œ ν”„λ‘¬ν”„νŠΈλ‘œ λΌμš°νŒ…
def prompt_router(input):
    query_embedding = embeddings.embed_query(input["query"])
    similarity = cosine_similarity([query_embedding], prompt_embeddings)[0]
    most_similar = prompt_templates[similarity.argmax()]
    print("Using MATH" if most_similar == math_template else "Using PHYSICS")
    return PromptTemplate.from_template(most_similar)

chain = (
    {"query": RunnablePassthrough()}
    | RunnableLambda(prompt_router)
    | ChatOpenAI()
    | StrOutputParser()
)

print(chain.invoke("What's a black hole"))
  • μ‹œμŠ€ν…œμ€ μ„ νƒλœ ν”„λ‘¬ν”„νŠΈλ₯Ό 기반으둜 닡변을 μ œκ³΅ν•©λ‹ˆλ‹€.
    • 예λ₯Ό λ“€μ–΄, 질문이 β€œλΈ”λž™ν™€μ€ 무엇인가?”라면 μ•„λž˜μ™€ 같이 물리학 κ΄€λ ¨ ν”„λ‘¬ν”„νŠΈκ°€ μ„ νƒλ˜κ³  닡변을 μ œκ³΅ν•˜κ²Œ λ©λ‹ˆλ‹€.
1
2
3
4
5
6
7
Using PHYSICS
   
A black hole is a region in space where the gravitational pull is so strong that nothing, not even light, can escape from it. This occurs because a significant amount of mass has been compressed into a very small area. 

The boundary around a black hole is called the event horizon, and once something crosses this boundary, it cannot escape. Black holes can be formed from the remnants of massive stars that have ended their life cycles in a supernova explosion and collapsed under their own gravity. 

They are fascinating objects that challenge our understanding of physics, particularly in the realms of general relativity and quantum mechanics.

(정리) 논리적 λΌμš°νŒ… vs 의미적 λΌμš°νŒ… 비ꡐ

ꡬ뢄 논리적 λΌμš°νŒ… (Logical Routing) 의미적 λΌμš°νŒ… (Semantic Routing)
λΌμš°νŒ… κΈ°μ€€ 미리 μ •μ˜λœ 데이터 μ†ŒμŠ€ λͺ©λ‘μ— 기반 질문과 ν”„λ‘¬ν”„νŠΈ κ°„μ˜ 의미적 μœ μ‚¬μ„±μ— 기반
데이터 μ†ŒμŠ€ 선택 LLM이 데이터 μ†ŒμŠ€ λͺ©λ‘μ—μ„œ μ ν•©ν•œ μ†ŒμŠ€λ₯Ό 선택 질문의 의미λ₯Ό 뢄석해 κ°€μž₯ μœ μ‚¬ν•œ ν”„λ‘¬ν”„νŠΈλ‚˜ 데이터λ₯Ό 선택
μ£Όμš” ν™œμš© 데이터 μ†ŒμŠ€λ‚˜ μžλ£Œκ°€ λͺ…ν™•νžˆ κ΅¬λΆ„λ˜μ–΄ μžˆλŠ” 경우 μ‚¬μš© λ‹€μ–‘ν•œ 의미λ₯Ό ν¬ν•¨ν•˜λŠ” μ§ˆλ¬Έμ— λŒ€ν•΄ μœ μ—°ν•œ λ‹΅λ³€ 제곡
μ‹€μ œ μ˜ˆμ‹œ ν”„λ‘œκ·Έλž˜λ° λ¬Έμ„œ, 라이브러리 λ¬Έμ„œ λ“± νŠΉμ • 주제의 DB νŠΉμ • 도메인에 κ΄€λ ¨λœ μ—¬λŸ¬ μ˜λ―Έκ°€ 혼재된 μ§ˆλ¬Έμ— λŒ€ν•œ λ‹΅λ³€ 선택
μ ν•©ν•œ 상황 질문이 μ–΄λŠ DBμ—μ„œ μ²˜λ¦¬λ μ§€ 미리 λͺ…ν™•ν•œ 경우 질문이 λ‹€μ–‘ν•œ 의미둜 해석될 수 μžˆμ„ λ•Œ 적합
  • μœ„ ν…Œμ΄λΈ” 비ꡐλ₯Ό 톡해,
    • 논리적 λΌμš°νŒ…μ€ 미리 μ„€μ •λœ κ·œμΉ™μ— 따라 μ μ ˆν•œ 데이터 μ†ŒμŠ€λ₯Ό μ„ νƒν•˜λŠ” 반면,
    • 의미적 λΌμš°νŒ…μ€ 질문의 의미적 μœ μ‚¬μ„±μ„ 기반으둜 λΌμš°νŒ…μ΄ μ΄λ£¨μ–΄μ§„λ‹€λŠ” 차이점을 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

Part 11 (쿼리 ꡬ쑰화)

  • μœ„ 그림의 단계에 따라 각 κ³Όμ •μ˜ μ—­ν• κ³Ό κ°œλ…μ„ κ°„λž΅ν•˜κ²Œ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€:

    1. Question (질문) : μ‚¬μš©μžκ°€ μ‹œμŠ€ν…œμ— μž…λ ₯ν•˜λŠ” μžμ—°μ–΄ ν˜•νƒœμ˜ μ§ˆλ¬Έμž…λ‹ˆλ‹€. μ΄λŠ” 전체 ν”„λ‘œμ„ΈμŠ€μ˜ μ‹œμž‘μ μ΄ λ©λ‹ˆλ‹€.
    2. Query Translation (쿼리 λ²ˆμ—­) : μ‚¬μš©μžμ˜ μžμ—°μ–΄ μ§ˆλ¬Έμ„ μ‹œμŠ€ν…œμ΄ 이해할 수 μžˆλŠ” ν˜•μ‹μœΌλ‘œ λ³€ν™˜ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. μ΄λŠ” μžμ—°μ–΄ 처리 κΈ°μˆ μ„ ν™œμš©ν•˜μ—¬ μˆ˜ν–‰λ©λ‹ˆλ‹€.
    3. Routing (λΌμš°νŒ…) : λ³€ν™˜λœ 쿼리λ₯Ό μ μ ˆν•œ 처리 κ²½λ‘œλ‚˜ 데이터 μ†ŒμŠ€λ‘œ μ•ˆλ‚΄ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. 질문의 νŠΉμ„±μ— 따라 졜적의 처리 방법을 κ²°μ •ν•©λ‹ˆλ‹€.
    4. Query Construction (쿼리 ꡬ성, 이번 μ±•ν„°πŸ“Œ) : λΌμš°νŒ…λœ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ μ‹€μ œ λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ 검색 μ—”μ§„μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” ν˜•νƒœμ˜ 쿼리λ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€.
    5. Indexing (인덱싱) : λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ λ¬Έμ„œ μ»¬λ ‰μ…˜μ—μ„œ 효율적인 검색을 μœ„ν•΄ 데이터λ₯Ό κ΅¬μ‘°ν™”ν•˜κ³  μ‘°μ§ν™”ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. μ΄λŠ” 주둜 μ‹œμŠ€ν…œ ꡬ좕 λ‹¨κ³„μ—μ„œ μˆ˜ν–‰λ©λ‹ˆλ‹€.
    6. Retrieval (검색) : κ΅¬μ„±λœ 쿼리λ₯Ό μ‚¬μš©ν•˜μ—¬ μΈλ±μ‹±λœ λ°μ΄ν„°μ—μ„œ κ΄€λ ¨ 정보λ₯Ό μΆ”μΆœν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. 이 λ‹¨κ³„μ—μ„œ 질문과 κ°€μž₯ κ΄€λ ¨μ„± 높은 정보λ₯Ό μ°Ύμ•„λƒ…λ‹ˆλ‹€.
    7. Generation (생성) : κ²€μƒ‰λœ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ μ§ˆλ¬Έμ— λŒ€ν•œ 닡변을 μƒμ„±ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€. 이 λ‹¨κ³„μ—μ„œλŠ” 주둜 μžμ—°μ–΄ 생성 기술이 μ‚¬μš©λ©λ‹ˆλ‹€.
    8. Answer (λ‹΅λ³€) : μ΅œμ’…μ μœΌλ‘œ μƒμ„±λœ 닡변을 μ‚¬μš©μžμ—κ²Œ μ œκ³΅ν•©λ‹ˆλ‹€. μ΄λŠ” μ›λž˜ μ§ˆλ¬Έμ— λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ, μžμ—°μ–΄ ν˜•νƒœλ‘œ ν‘œν˜„λ©λ‹ˆλ‹€.
  • 이번 κ°•μ˜μ—μ„œλŠ” Query Construction (or Structuring)(쿼리 ꡬ쑰화)에 λŒ€ν•΄ λ‹€λ£Ήλ‹ˆλ‹€. 쿼리 κ΅¬μ‘°ν™”λŠ” μžμ—°μ–΄λ‘œ 된 μ§ˆλ¬Έμ„ νŠΉμ • λ°μ΄ν„°λ² μ΄μŠ€λ‚˜ 도메인에 λ§žλŠ” κ΅¬μ‘°ν™”λœ 쿼리둜 λ³€ν™˜ν•˜λŠ” 과정을 μ„€λͺ…ν•©λ‹ˆλ‹€. 특히 벑터 μŠ€ν† μ–΄μ—μ„œ 메타데이터 ν•„ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬ 질의λ₯Ό μ²˜λ¦¬ν•˜λŠ” 방법에 쀑점을 λ‘‘λ‹ˆλ‹€.

1. 쿼리 ꡬ쑰화 κ°œλ…

  • 쿼리 κ΅¬μ‘°ν™”λŠ” μ‚¬μš©μžκ°€ μžμ—°μ–΄λ‘œ λ¬»λŠ” μ§ˆλ¬Έμ„ 메타데이터 ν•„ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬ 보닀 ꡬ체적으둜 λ³€ν™˜ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€.
  • 예λ₯Ό λ“€μ–΄, μ‚¬μš©μžκ°€ β€œ2024λ…„ 이후에 κ²Œμ‹œλœ Lang Chain κ΄€λ ¨ λΉ„λ””μ˜€λ₯Ό μ°Ύμ•„μ£Όμ„Έμš”β€λΌκ³  μ§ˆλ¬Έν•  경우, 이 μ§ˆλ¬Έμ€ 메타데이터 ν•„ν„°λ‘œ λ³€ν™˜λ˜μ–΄ 벑터 μŠ€ν† μ–΄μ— μ ν•©ν•œ 쿼리둜 λ§Œλ“€μ–΄μ§‘λ‹ˆλ‹€.

2. 쿼리 κ΅¬μ‘°ν™”μ˜ μ£Όμš” 흐름

2.1. μžμ—°μ–΄ 질문 β†’ κ΅¬μ‘°ν™”λœ 쿼리:

  • μ‚¬μš©μžκ°€ μžμ—°μ–΄λ‘œ μ§ˆλ¬Έμ„ μž…λ ₯ν•˜λ©΄, LLM이 ν•΄λ‹Ή μ§ˆλ¬Έμ„ λΆ„μ„ν•˜μ—¬ 메타데이터 ν•„ν„°(예: λ‚ μ§œ, 쑰회수, λΉ„λ””μ˜€ 길이)λ₯Ό μ‚¬μš©ν•΄ λ°μ΄ν„°λ² μ΄μŠ€ 검색에 μ ν•©ν•œ κ΅¬μ‘°ν™”λœ 쿼리둜 λ³€ν™˜ν•©λ‹ˆλ‹€.

    • μ˜ˆμ‹œ: 유튜브 λΉ„λ””μ˜€ 데이터λ₯Ό λ‘œλ“œν•˜κ³  메타데이터 ν•„ν„° 적용
    • 링크 : Self-reflective RAG with LangGraph: Self-RAG and CRAG

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      from langchain_community.document_loaders import YoutubeLoader
      # https://youtu.be/pbAd8O1Lvm4
        
      docs = YoutubeLoader.from_youtube_url(
      "https://www.youtube.com/watch?v=pbAd8O1Lvm4",
      add_video_info=True
      ).load()
        
      docs[0].metadata
    
    • μœ„ μ½”λ“œλŠ” YouTubeμ—μ„œ λΉ„λ””μ˜€λ₯Ό λ‘œλ“œν•˜κ³  ν•΄λ‹Ή λΉ„λ””μ˜€μ˜ 메타데이터(예: 제λͺ©, 쑰회수, κ²Œμ‹œμΌ)λ₯Ό κ°€μ Έμ˜€λŠ” μ˜ˆμ‹œμž…λ‹ˆλ‹€.

2.2. 메타데이터 ν•„ν„° μ‚¬μš©:

  • 벑터 μŠ€ν† μ–΄μ—μ„œ μ‚¬μš© κ°€λŠ₯ν•œ 메타데이터 ν•„ν„°λ₯Ό 기반으둜 μžμ—°μ–΄ μ§ˆλ¬Έμ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€.
  • ν•„ν„°λ‘œλŠ” 쑰회수, κ²Œμ‹œμΌ, λΉ„λ””μ˜€ 길이 등이 있으며, 이λ₯Ό 톡해 보닀 μ„Έλ°€ν•œ 검색을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (view_count, publish_date, length 등을 ν•„ν„°λ‘œ μ‚¬μš©ν•˜μ—¬ 검색할 수 μžˆμŠ΅λ‹ˆλ‹€.)

    • μ•„λž˜λŠ” μœ„μ—μ„œ ν˜ΈμΆœν•œ μ˜μƒμ˜ μ •λ³΄μž…λ‹ˆλ‹€.

      1
      2
      3
      4
      5
      6
      7
      8
      
      {'source': 'pbAd8O1Lvm4',
       'title': 'Self-reflective RAG with LangGraph: Self-RAG and CRAG',
       'description': 'Unknown',
       'view_count': 23406,
       'thumbnail_url': 'https://i.ytimg.com/vi/pbAd8O1Lvm4/hq720.jpg',
       'publish_date': '2024-02-07 00:00:00',
       'length': 1058,
       'author': 'LangChain'}
      

2.3. LLMκ³Ό ν•¨μˆ˜ 호좜:

  • κ΅¬μ‘°ν™”λœ 쿼리의 μŠ€ν‚€λ§ˆ: 이 μŠ€ν‚€λ§ˆλŠ” 검색할 λΉ„λ””μ˜€μ˜ 메타데이터 ν•„ν„°(예: 쑰회수, κ²Œμ‹œμΌ, λΉ„λ””μ˜€ 길이)λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    
    import datetime
    from typing import Literal, Optional, Tuple
    from langchain_core.pydantic_v1 import BaseModel, Field
      
    class TutorialSearch(BaseModel):
        """Search over a database of tutorial videos about a software library."""
      
        content_search: str = Field(
            ...,
            description="Similarity search query applied to video transcripts.",
        )
        title_search: str = Field(
            ...,
            description=(
                "Alternate version of the content search query to apply to video titles. "
                "Should be succinct and only include key words that could be in a video "
                "title."
            ),
        )
        min_view_count: Optional[int] = Field(
            None,
            description="Minimum view count filter, inclusive. Only use if explicitly specified.",
        )
        max_view_count: Optional[int] = Field(
            None,
            description="Maximum view count filter, exclusive. Only use if explicitly specified.",
        )
        earliest_publish_date: Optional[datetime.date] = Field(
            None,
            description="Earliest publish date filter, inclusive. Only use if explicitly specified.",
        )
        latest_publish_date: Optional[datetime.date] = Field(
            None,
            description="Latest publish date filter, exclusive. Only use if explicitly specified.",
        )
        min_length_sec: Optional[int] = Field(
            None,
            description="Minimum video length in seconds, inclusive. Only use if explicitly specified.",
        )
        max_length_sec: Optional[int] = Field(
            None,
            description="Maximum video length in seconds, exclusive. Only use if explicitly specified.",
        )
      
        def pretty_print(self) -> None:
            for field in self.__fields__:
                if getattr(self, field) is not None and getattr(self, field) != getattr(
                    self.__fields__[field], "default", None
                ):
                    print(f"{field}: {getattr(self, field)}")
    
    • LLM은 ν•¨μˆ˜ ν˜ΈμΆœμ„ μ‚¬μš©ν•˜μ—¬ μžμ—°μ–΄ μ§ˆλ¬Έμ„ μ²˜λ¦¬ν•˜κ³ , 이λ₯Ό JSON ν˜•μ‹μ˜ κ΅¬μ‘°ν™”λœ 객체둜 λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€. 이 κ°μ²΄λŠ” 검색 쿼리둜 λ°”λ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

      • structured_llm = llm.with_structured_output(TutorialSearch)에 μ•žμ— μ„€μ •ν•΄λ‘” TutorialSearch으둜 좜λ ₯ν•˜λ„λ‘ μ •μ˜ν•΄λ‘‘λ‹ˆλ‹€. ``` from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI

    Create the Prompt Template:

    system = β€œ"”You are an expert at converting user questions into database queries. You have access to a database of tutorial videos about a software library for building LLM-powered applications. Given a question, return a database query optimized to retrieve the most relevant results.”””

    prompt = ChatPromptTemplate.from_messages([(β€œsystem”, system), (β€œhuman”, β€œ{question}”)])

    Initialize the Language Model (LLM)

    llm = ChatOpenAI(model=”gpt-3.5-turbo-0125”, temperature=0) structured_llm = llm.with_structured_output(TutorialSearch)

    Prompt and LLM into a Query Analyzer

    query_analyzer = prompt | structured_llm

    ```

2.4. User Question 처리:

  • μ•žμ—μ„œ μ •μ˜ν•œ prompt와 query_analyzerλ₯Ό λ°”νƒ•μœΌλ‘œ User Question을 μ²˜λ¦¬ν•©λ‹ˆλ‹€.

    • prompt = ChatPromptTemplate.from_messages([(β€œsystem”, system), (β€œhuman”, β€œ{question}”)])
    • query_analyzer = prompt structured_llm
  • μ•„λž˜μ™€ 같은 ν˜•νƒœλ‘œ question을 μ²˜λ¦¬ν•΄μ€λ‹ˆλ‹€.

    1
    
      query_analyzer.invoke({"question": "your question"}).pretty_print()
    
    1. ν”„λ‘¬ν”„νŠΈ 생성: μ‚¬μš©μž μ§ˆλ¬Έμ„ ν”„λ‘¬ν”„νŠΈμ— μ‚½μž…ν•©λ‹ˆλ‹€.
    2. LLM 처리: LLM이 ν”„λ‘¬ν”„νŠΈλ₯Ό 읽고 TutorialSearch ꡬ쑰에 λ§žλŠ” 좜λ ₯을 μƒμ„±ν•©λ‹ˆλ‹€.
    3. κ΅¬μ‘°ν™”λœ 좜λ ₯: κ²°κ³Όλ₯Ό TutorialSearch 객체둜 νŒŒμ‹±ν•˜κ³  좜λ ₯ν•©λ‹ˆλ‹€.

μ˜ˆμ‹œ: μ‚¬μš©μžκ°€ λ‹€μŒκ³Ό 같은 μ§ˆλ¬Έμ„ ν•œλ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€:

1
"2023λ…„ 6μ›” 이후에 κ²Œμ‹œλœ LangChain에 κ΄€ν•œ μ˜μƒ 쀑 10λΆ„ μ΄ν•˜μ˜ μ˜μƒμ„ λ³΄μ—¬μ€˜."
  • 이 μžμ—°μ–΄ μ§ˆλ¬Έμ„ LLM(λŒ€ν˜• μ–Έμ–΄ λͺ¨λΈ)κ³Ό 쿼리 뢄석 체인(query analyzer)을 μ‚¬μš©ν•΄, TutorialSearch와 같은 데이터 λͺ¨λΈλ‘œ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    class TutorialSearch(BaseModel):
        content_search: str = None
        title_search: str = None
        earliest_publish_date: Optional[date] = None
        latest_publish_date: Optional[date] = None
        min_length_sec: Optional[int] = None
        max_length_sec: Optional[int] = None
        min_view_count: Optional[int] = None
        max_view_count: Optional[int] = None
    
  • μ—¬κΈ°μ„œ μ‚¬μš©μž μ§ˆλ¬Έμ„ λ³€ν™˜ν•˜λ©΄ λ‹€μŒκ³Ό 같은 TutorialSearch 객체가 생성될 수 μžˆμŠ΅λ‹ˆλ‹€:

    1
    2
    3
    4
    5
    6
    
    TutorialSearch(
        content_search='LangChain',
        title_search='LangChain',
        earliest_publish_date=datetime.date(2023, 6, 1),
        max_length_sec=600  # 10뢄을 초 λ‹¨μœ„λ‘œ λ³€ν™˜ν•œ κ°’
    )
    
  • 이 κ΅¬μ‘°ν™”λœ μΏΌλ¦¬λŠ” 이제 메타데이터 필터링에 μ‚¬μš©λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄:

    • earliest_publish_date ν•„λ“œλŠ” 2023λ…„ 6μ›” 1일 이후에 κ²Œμ‹œλœ μ˜μƒλ§Œ ν•„ν„°λ§ν•©λ‹ˆλ‹€.
    • max_length_sec ν•„λ“œλŠ” 10λΆ„ μ΄ν•˜μ˜ μ˜μƒλ§Œ ν•„ν„°λ§ν•©λ‹ˆλ‹€.
    • content_search와 title_search ν•„λ“œλŠ” LangChainμ΄λΌλŠ” ν‚€μ›Œλ“œκ°€ ν¬ν•¨λœ μ½˜ν…μΈ λ‚˜ 제λͺ©μ„ μ°ΎμŠ΅λ‹ˆλ‹€.
  • 이 쿼리λ₯Ό μ‚¬μš©ν•˜μ—¬ 메타데이터 필터링을 μ μš©ν•˜λ©΄, 쑰건에 λ§žλŠ” μ˜μƒλ§Œμ„ λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

2.5. μΆ”κ°€ μ˜ˆμ‹œ

  1. μžμ—°μ–΄ 질문: β€œ2023년에 κ²Œμ‹œλœ chat langchain λΉ„λ””μ˜€β€
    • 질의문:
      1
      2
      3
      
      query_analyzer.invoke(
          {"question": "videos on chat langchain published in 2023"}
      ).pretty_print()
      
    • κ΅¬μ‘°ν™”λœ 쿼리 좜λ ₯:
      1
      2
      3
      4
      
      content_search: chat langchain
      title_search: 2023
      earliest_publish_date: 2023-01-01
      latest_publish_date: 2023-12-31
      
  2. μžμ—°μ–΄ 질문: β€œ2024λ…„ 이전에 κ²Œμ‹œλœ chat langchain λΉ„λ””μ˜€β€
    • 질의문:
      1
      2
      3
      
      query_analyzer.invoke(
          {"question": "videos that are focused on the topic of chat langchain that are published before 2024"}
      ).pretty_print()
      
    • κ΅¬μ‘°ν™”λœ 쿼리 좜λ ₯:
      1
      2
      3
      
      content_search: chat langchain
      title_search: chat langchain
      latest_publish_date: 2023-12-31
      
  3. μžμ—°μ–΄ 질문: β€œ5λΆ„ μ΄ν•˜μ˜ λ©€ν‹°λͺ¨λ‹¬ λͺ¨λΈ κ΄€λ ¨ λΉ„λ””μ˜€β€
    • 질의문:
      1
      2
      3
      
      query_analyzer.invoke(
          {"question": "how to use multi-modal models in an agent, only videos under 5 minutes"}
      ).pretty_print()
      
    • κ΅¬μ‘°ν™”λœ 쿼리 좜λ ₯:
      1
      2
      3
      
      content_search: multi-modal models agent
      title_search: multi-modal models agent
      max_length_sec: 300
      



-->