
LLM은 많은 스마트폰이 제공하는 자동 완성 기능과 유사하게 동작한다. 텍스트를 입력 받아 다음 텍스트 출력을 예측하고 생성하는 훈련된 알고리즘이다.
LLM의 예측력을 좌우하는 핵심은 트랜스포머 신경망 아키텍처이다.
트랜스포머 구조는 문장이나 코드 등 데이터의 연속체를 처리하며, 연속체에서 가장 가능성이 높은 다음 단어를 예측한다. 트랜스포머는 문장 내의 각 단어와 다른 모든 다언의 관계를 고려해 문맥을 파악한다. 이 방법을 통해 LLM은 문장이나 단락 등이 서로 연결되어 나타내는 의미를 포괄적으로 이해한다.
LLM의 성능을 높이는 좋은 방법은 LLM이 시간을 들여 사고하도록 추가 지시하는 것이다.
이른바 사고의 연쇄 (Chain-of-Thought) 라고 부르는 프롬프트 기법은 프롬프트 앞에 LLM이 답에 도달하는 과정을 설명하도록 지시문을 삽입한다.
예를 들어 프롬프트 앞에 "단계별로 생각해"와 같은 지시문을 붙여서 llm이 답을 추론할때 단계적으로 생각할 수 있도록 한다. 그러나 CoT는 직관적인 생각이 더 빠른 경우(사진을 보고 고양이라고 생각하는 등)에는 비효율적인 프롬프팅 기법이다.
검색 증강 생성 (Retrieval-Augmented Generation)은 관련 있는 텍스트 조각을 찾아내, 해당 텍스트 조각을 컨텍스트라 칭하며 프롬프트에 포함한다.
LLM에게 질문과 정답의 예제를 몇 가지 제공하여, 추가적인 훈련이나 파인튜닝을 거치지 않고도 새로운 작업을 수행하는 방법을 익히게 한다. 파인튜닝을 하기 전에 보통은 항상 퓨샷 프롬프트를 시도한다.
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai.chat_models import ChatOpenAI
model = ChatOpenAI()
system_msg = SystemMessage(
'''당신은 문장 끝에 느낌표를 세 개 붙여 대답하는 친절한 어시스턴트입니다.'''
)
human_msg = HumanMessage('프랑스의 수도는 어디인가요?')
response = model.invoke([system_msg, human_msg])
print(response.content)
from langchain_openai import ChatOpenAI
from pydantic import BaseModel
class AnswerWithJustification(BaseModel):
'''사용자의 질문에 대한 답변과 그에 대한 근거(justification)를 함께 제공하세요.'''
answer: str
'''사용자의 질문에 대한 답변'''
justification: str
'''답변에 대한 근거'''
llm = ChatOpenAI(model='gpt-4o-mini', temperature=0)
structured_llm = llm.with_structured_output(AnswerWithJustification)
result = structured_llm.invoke('''1 킬로그램의 벽돌과 1 킬로그램의 깃털 중 어느 쪽이 더 무겁나요?''')
print(result.model_dump_json())
랭체인은 llm을 호출하기 위해 위 4개의 함수를 제공한다. Runnable 객체는 통일된 인터페이스를 제공하여 위 4개의 함수를 모두 사용할 수 있게 해준다.
@chain
def chatbot(values):
prompt = template.invoke(values)
return model.invoke(prompt)


WebBaseLoader
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader('https://www.langchain.com/')
docs = loader.load()
print(docs)
RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import (
Language,
RecursiveCharacterTextSplitter,
)
loader = WebBaseLoader('https://namu.wiki/w/%EC%9E%90%ED%8F%90%EC%84%B1%20%EC%9E%A5%EC%95%A0')
docs = loader.load()
# print(docs)
print(docs[0].page_content)
for i in range(10, docs) :
print(f"=== Document {i+1} ===")
print(docs[i])
print("=" * 50)
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splitted_docs = splitter.split_documents(docs)
for i in range(min(10, len(splitted_docs))):
print(f"=== Document {i+1} ===")
print(splitted_docs[i])
print("=" * 50)
python_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON, chunk_size=50, chunk_overlap=0
)
# =============== 1 =================== #
prompt = ChatPromptTemplate.from_template(prompt_text)
llm = ChatOpenAI(temperature=0, model='gpt-4o-mini')
summarize_chain = {
'doc': lambda x: x.page_content} | prompt | llm | StrOutputParser()
summaries = summarize_chain.batch(chunks, {'max_concurrency': 5})
# =============== 2 =================== #
# 벡터 저장소는 하위 청크를 인덱싱하는 데 사용
vectorstore = PGVector(
embeddings=embeddings_model,
collection_name=collection_name,
connection=connection,
use_jsonb=True,
)
retriever = MultiVectorRetriever(
vectorstore=vectorstore,
docstore=store,
id_key=id_key,
)
# =============== 3 =================== #
doc_ids = [str(uuid.uuid4()) for _ in chunks]
# =============== 4 =================== #
# 각 요약은 doc_id를 통해 원본 문서와 연결
summary_docs = [
Document(page_content=s, metadata={id_key: doc_ids[i]})
for i, s in enumerate(summaries)
]
retriever.vectorstore.add_documents(summary_docs)
# =============== 5 =================== #
sub_docs = retriever.vectorstore.similarity_search(
'chapter on philosophy', k=2)
라그 시스템은 단일 문서에 존재하는 특정 사실을 참조하는 하위 수준의 질문과 여러 문서에 걸쳐 산출된 아이디어를 도출하는 상위 수준의 질문을 모두 처리할 수 있어야 한다.

BERT
Bi-Encoder
검색어 → 인코더 A → 검색어 벡터
문서 → 인코더 B → 문서 벡터
모든 문서를 미리 벡터로 저장해두고 검색 시에는 검색어만 벡터로 만들어서 두 개의 코사인 유사도를 비교하므로 매우 빠름
검색어와 문서가 서로의 문맥을 직접 비교하지 않고 독립적으로 해석된 결과를 나중에 비교하기에 정확도가 낮음
Cross-Encoder
[검색어 + 문서] → 하나의 인코더 → 유사도 점수 (0~1)
두 텍스트 간의 의미 관계까지 파악할 수 있어, 가장 관련성 높은 결과를 찾아내므로 정확도가 매우 높음
검색할 때마다 모든 문서 후보와 검색어를 일일이 쌍으로 묶어 모델에 넣어야 함, 즉 미리 계산해 둘 수 없기 때문에 매우 느림
ColBERT
문서 → 인코더 A → 모든 단어의 의미를 담은 문서 벡터
검색어 → 인코더 B → 모든 단어의 의미를 담은 검색어 벡터
검색어, 문서의 각 단어 벡터 비교
Bi-Encoder처럼 다른 인코더를 사용해서 문서를 미리 인코딩 해놓을 수 있어서 빠름
Cross-Encoder처럼 문서와 검색어를 단어 단위로 하나하나 비교해서 더 정확한 결과를 가져올 수 있음
문서와 검색어가 모두 독립적으로 인코딩 된 후에 나중에 서로를 비교하기 때문에 인코딩 전이나 인코딩 도중에 비교하는 이전 '조기 상호작용' 모델들 보다 빠름
| ⌈책 리뷰⌋ 메이오 오신 ⎹ 러닝 랭체인 ⎹ 2부 (1) | 2025.10.03 |
|---|---|
| ⌈책 리뷰⌋ 로버트 C. 마틴 ⎹ 클린 아키텍처 ⎹ ⭐️ (0) | 2025.09.15 |
| ⌈책 리뷰⌋ 찰스 두히그 ⎹ 습관의 힘 ⎹ ⭐️ (4) | 2025.07.29 |
| ⌈책 리뷰⌋ 제임스 클리어 ⎹ 아주 작은 습관의 힘 ⎹ (4) | 2025.07.08 |
| ⌈책 리뷰⌋ 미하이 칙센트미하이, ⎹ 몰입의 기술 ⎹ ⭐️ (0) | 2025.04.22 |