[κ°μλ ΈνΈ] 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 (λΌμ°ν )
-
μ κ·Έλ¦Όμ λ¨κ³μ λ°λΌ κ° κ³Όμ μ μν κ³Ό κ°λ μ κ°λ΅νκ² μ€λͺ νκ² μ΅λλ€:
- Question (μ§λ¬Έ) : μ¬μ©μκ° μμ€ν μ μ λ ₯νλ μμ°μ΄ ννμ μ§λ¬Έμ λλ€. μ΄λ μ 체 νλ‘μΈμ€μ μμμ μ΄ λ©λλ€.
- Query Translation (쿼리 λ²μ) : μ¬μ©μμ μμ°μ΄ μ§λ¬Έμ μμ€ν μ΄ μ΄ν΄ν μ μλ νμμΌλ‘ λ³ννλ κ³Όμ μ λλ€. μ΄λ μμ°μ΄ μ²λ¦¬ κΈ°μ μ νμ©νμ¬ μνλ©λλ€.
- Routing (λΌμ°ν , μ΄λ² μ±ν°π) : λ³νλ 쿼리λ₯Ό μ μ ν μ²λ¦¬ κ²½λ‘λ λ°μ΄ν° μμ€λ‘ μλ΄νλ κ³Όμ μ λλ€. μ§λ¬Έμ νΉμ±μ λ°λΌ μ΅μ μ μ²λ¦¬ λ°©λ²μ κ²°μ ν©λλ€.
- Query Construction (쿼리 ꡬμ±) : λΌμ°ν λ μ 보λ₯Ό λ°νμΌλ‘ μ€μ λ°μ΄ν°λ² μ΄μ€λ κ²μ μμ§μμ μ¬μ©ν μ μλ ννμ 쿼리λ₯Ό ꡬμ±ν©λλ€.
- Indexing (μΈλ±μ±) : λ°μ΄ν°λ² μ΄μ€λ λ¬Έμ 컬λ μ μμ ν¨μ¨μ μΈ κ²μμ μν΄ λ°μ΄ν°λ₯Ό ꡬ쑰ννκ³ μ‘°μ§ννλ κ³Όμ μ λλ€. μ΄λ μ£Όλ‘ μμ€ν κ΅¬μΆ λ¨κ³μμ μνλ©λλ€.
- Retrieval (κ²μ) : ꡬμ±λ 쿼리λ₯Ό μ¬μ©νμ¬ μΈλ±μ±λ λ°μ΄ν°μμ κ΄λ ¨ μ 보λ₯Ό μΆμΆνλ κ³Όμ μ λλ€. μ΄ λ¨κ³μμ μ§λ¬Έκ³Ό κ°μ₯ κ΄λ ¨μ± λμ μ 보λ₯Ό μ°Ύμλ λλ€.
- Generation (μμ±) : κ²μλ μ 보λ₯Ό λ°νμΌλ‘ μ§λ¬Έμ λν λ΅λ³μ μμ±νλ κ³Όμ μ λλ€. μ΄ λ¨κ³μμλ μ£Όλ‘ μμ°μ΄ μμ± κΈ°μ μ΄ μ¬μ©λ©λλ€.
- 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)μ κ·Έ μ§λ¬Έμ΄ μ΄λ λ°μ΄ν°λ² μ΄μ€λ λ¬Έμ μμ€μ κ°μ₯ κ΄λ ¨μ΄ μλμ§ κ²°μ νκ³ , ν΄λΉ μμ€λ‘ λΌμ°ν νμ¬ λ΅λ³μ μμ±ν©λλ€.
νΉμ§
- μ£Όλ‘ βꡬ쑰νλ μΆλ ₯βμ μ¬μ©νμ¬ λΌμ°ν μ μνν©λλ€. μ¦, μμ€ν μ μ§λ¬Έμ 미리 μ μλ κ·μΉμ λ°λΌ λΆλ₯νκ³ κ·Έμ λ§λ λ°μ΄ν° μμ€λ₯Ό μ νν©λλ€.
- μ§λ¬Έμ΄ λͺ νν κ΅¬λΆ κ°λ₯ν μ£Όμ λ λ°μ΄ν°λ² μ΄μ€μ κ΄λ ¨μ΄ μμ λ λ§€μ° μ ν©ν λ°©λ²μ λλ€.
κ³Όμ
-
μ¬μ©μκ° μ§λ¬Έμ μ λ ₯ν©λλ€.
-
LLMμ΄ κ·Έ μ§λ¬Έμ λΆμνμ¬ λ―Έλ¦¬ μ€μ λ λ°μ΄ν° μμ€ λͺ©λ‘(μ: Python λ¬Έμ, JS λ¬Έμ λ±) μ€μμ κ°μ₯ μ ν©ν μμ€λ₯Ό κ²°μ ν©λλ€.
-
μ νλ λ°μ΄ν° μμ€λ₯Ό λ°νμΌλ‘ λ΅λ³μ μμ±ν©λλ€.
μ½λ μ€λͺ
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
λ‘ λΌμ°ν λ©λλ€.
- μ΄ μμμμ μ¬μ©μλ μ§λ¬Έμ μ
λ ₯νκ³ , μμ€ν
μ μ΄λ₯Ό λΆμνμ¬ μ μ ν λ°μ΄ν° μμ€λ₯Ό μ νν©λλ€. μλ₯Ό λ€μ΄, Pythonκ³Ό κ΄λ ¨λ μ§λ¬Έμ΄λΌλ©΄
2.2. μλ―Έμ λΌμ°ν (Semantic Routing) μ€λͺ
μλ―Έμ λΌμ°ν κ°λ
- μλ―Έμ λΌμ°ν μ μ§λ¬Έκ³Ό μ¬λ¬ ν둬ννΈ κ°μ μλ―Έμ μ μ¬μ±μ κΈ°λ°μΌλ‘ μ ν©ν ν둬ννΈλ₯Ό μ ννλ λ°©μμ λλ€.
- μ¬κΈ°μ μ§λ¬Έκ³Ό ν둬ννΈλ μλ² λ©(벑ν°ν)λ ν μ μ¬λλ₯Ό κ³μ°νμ¬, κ°μ₯ μ μ¬ν ν둬ννΈλ₯Ό μ νν©λλ€.
νΉμ§
- μ§λ¬Έκ³Ό ν둬ννΈ κ°μ μλ―Έμ μ μ¬μ±μ λ°νμΌλ‘ λΌμ°ν μ μνν©λλ€.
- 미리 μ μλ λ°μ΄ν°λ² μ΄μ€κ° μλλΌ, μ§λ¬Έμ μλ―Έλ₯Ό νμ ν΄ κ°μ₯ μ ν©ν ν둬ννΈλ₯Ό μ ννλ λ°©μμ λλ€.
- μ§λ¬Έμ΄ λ¨μν μ 보 μ‘°νκ° μλλΌ, μλ―Έμ μΌλ‘ μ μ¬ν μ¬λ¬ κ°λ₯μ±μ κ³ λ €ν΄μΌ ν λ μ ν©ν©λλ€.
κ³Όμ
-
μ¬μ©μκ° μ§λ¬Έμ μ λ ₯νλ©΄ μμ€ν μ΄ κ·Έ μ§λ¬Έμ μλ² λ©(벑ν°ν)ν©λλ€.
-
μμ€ν μ μ¬λ¬ ν둬ννΈ μ€μμ μ§λ¬Έκ³Ό κ°μ₯ μ μ¬ν ν둬ννΈλ₯Ό μ νν©λλ€.
-
μ νλ ν둬ννΈμ λ°λΌ λ΅λ³μ μ 곡ν©λλ€.
μ½λ μ€λͺ
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 (쿼리 ꡬ쑰ν)
-
μ κ·Έλ¦Όμ λ¨κ³μ λ°λΌ κ° κ³Όμ μ μν κ³Ό κ°λ μ κ°λ΅νκ² μ€λͺ νκ² μ΅λλ€:
- Question (μ§λ¬Έ) : μ¬μ©μκ° μμ€ν μ μ λ ₯νλ μμ°μ΄ ννμ μ§λ¬Έμ λλ€. μ΄λ μ 체 νλ‘μΈμ€μ μμμ μ΄ λ©λλ€.
- Query Translation (쿼리 λ²μ) : μ¬μ©μμ μμ°μ΄ μ§λ¬Έμ μμ€ν μ΄ μ΄ν΄ν μ μλ νμμΌλ‘ λ³ννλ κ³Όμ μ λλ€. μ΄λ μμ°μ΄ μ²λ¦¬ κΈ°μ μ νμ©νμ¬ μνλ©λλ€.
- Routing (λΌμ°ν ) : λ³νλ 쿼리λ₯Ό μ μ ν μ²λ¦¬ κ²½λ‘λ λ°μ΄ν° μμ€λ‘ μλ΄νλ κ³Όμ μ λλ€. μ§λ¬Έμ νΉμ±μ λ°λΌ μ΅μ μ μ²λ¦¬ λ°©λ²μ κ²°μ ν©λλ€.
- Query Construction (쿼리 ꡬμ±, μ΄λ² μ±ν°π) : λΌμ°ν λ μ 보λ₯Ό λ°νμΌλ‘ μ€μ λ°μ΄ν°λ² μ΄μ€λ κ²μ μμ§μμ μ¬μ©ν μ μλ ννμ 쿼리λ₯Ό ꡬμ±ν©λλ€.
- Indexing (μΈλ±μ±) : λ°μ΄ν°λ² μ΄μ€λ λ¬Έμ 컬λ μ μμ ν¨μ¨μ μΈ κ²μμ μν΄ λ°μ΄ν°λ₯Ό ꡬ쑰ννκ³ μ‘°μ§ννλ κ³Όμ μ λλ€. μ΄λ μ£Όλ‘ μμ€ν κ΅¬μΆ λ¨κ³μμ μνλ©λλ€.
- Retrieval (κ²μ) : ꡬμ±λ 쿼리λ₯Ό μ¬μ©νμ¬ μΈλ±μ±λ λ°μ΄ν°μμ κ΄λ ¨ μ 보λ₯Ό μΆμΆνλ κ³Όμ μ λλ€. μ΄ λ¨κ³μμ μ§λ¬Έκ³Ό κ°μ₯ κ΄λ ¨μ± λμ μ 보λ₯Ό μ°Ύμλ λλ€.
- Generation (μμ±) : κ²μλ μ 보λ₯Ό λ°νμΌλ‘ μ§λ¬Έμ λν λ΅λ³μ μμ±νλ κ³Όμ μ λλ€. μ΄ λ¨κ³μμλ μ£Όλ‘ μμ°μ΄ μμ± κΈ°μ μ΄ μ¬μ©λ©λλ€.
- 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()
ν둬ννΈ μμ±
: μ¬μ©μ μ§λ¬Έμ ν둬ννΈμ μ½μ ν©λλ€.LLM μ²λ¦¬
: LLMμ΄ ν둬ννΈλ₯Ό μ½κ³ TutorialSearch ꡬ쑰μ λ§λ μΆλ ₯μ μμ±ν©λλ€.ꡬ쑰νλ μΆλ ₯
: κ²°κ³Όλ₯Ό 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. μΆκ° μμ
- μμ°μ΄ μ§λ¬Έ: β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
- μ§μλ¬Έ:
- μμ°μ΄ μ§λ¬Έ: β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
- μ§μλ¬Έ:
- μμ°μ΄ μ§λ¬Έ: β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
- μ§μλ¬Έ: