4️⃣Chains

LangChain: Chains

import os
from dotenv import load_dotenv  

load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")

Generic Chain

1. LLMChain

from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate

# 템플릿 생성
template = """Q: {question}
A:"""

# 프롬프트 템플릿 생성
prompt = PromptTemplate(
    input_variables=["question"],
    template=template
)

# LLMChain 생성
llm_chain = LLMChain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    prompt=prompt,
    verbose=True
)

# LLMChain 실행
question = "기타를 잘 치는 방법은?"
print(llm_chain.predict(question=question))
> Entering new LLMChain chain...
Prompt after formatting:
Q: 기타를 잘 치는 방법은?
A:

> Finished chain.
 기타를 잘 치는 방법은 많은 연습과 노력이 필요합니다. 먼저 기타를 잘 다루기 위해서는 기본적인 코드와 화음을 익히는 것이 중요합니다. 이를 위해 기타 교본이나 온라인 강의를 활용할 수 있습니다. 또한, 손가락의 움직임과 손목의 자세를 익히는 것도 중요합니다. 이를 위해 기타를 연습할 때는 정확한 자세를 유지하고, 천천히 연습하는 것이 좋습니다. 또한, 다양한 곡을 연습하고 다양한 장르의 음악을 들어보는 것도 도움이 됩니다. 마지막으로, 꾸준한 연습과 열정을 가지고 재미있게 연주하는 것이
# 템플릿 생성
template = """{subject}를 주제로 {target}를 작성해 주세요."""

# 프롬프트 템플릿 생성
prompt = PromptTemplate(
    template=template,
    input_variables=["subject", "target"]
)

# LLMChain 생성
llm_chain = LLMChain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    prompt=prompt,
    verbose=True
)

# LLMChain 실행
print(llm_chain.predict(subject="고양이", target="시"))
> Entering new LLMChain chain...
Prompt after formatting:
고양이를 주제로 시를 작성해 주세요.

> Finished chain.


나는 고양이를 좋아해
귀여운 모습에 반해
털실을 쥐고 놀아주며
행복한 시간을 보내

고양이는 깜찍한 눈빛으로
나를 보며 살며시 다가와
나의 마음을 따뜻하게 녹여주며
나를 위로해주는 친구

고양이는 자유로운 영혼
마음대로 뛰어다니며
나를 따라 다니며
나의 곁을 지켜주는 친구

고양이는 귀여운 모습 뿐만 아니라
지혜로운 존재이기도 해
나에게 많은 것을 가르쳐주며
나를 성장시켜주는 친구

나는 고양이와 함께하는 시간이
가장

2. SimpleSequentialChain

from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate


# 템플릿 준비
template = """당신은 극작가입니다. 연극 제목이 주어졌을 때, 그 줄거리를 작성하는 것이 당신의 임무입니다.

제목:{title}
시놉시스:"""

# 프롬프트 템플릿 준비
prompt = PromptTemplate(
    input_variables=["title"],
    template=template
)

# LLMChain 준비
chain1 = LLMChain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    prompt=prompt
)
# 템플릿 생성
template = """당신은 연극 평론가입니다. 연극의 시놉시스가 주어지면 그 리뷰를 작성하는 것이 당신의 임무입니다.

시놉시스:
{synopsis}
리뷰:"""

# 프롬프트 템플릿 준비
prompt = PromptTemplate(
    input_variables=["synopsis"],
    template=template
)

# LLMChain 준비
chain2 = LLMChain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    prompt=prompt
)
from langchain.chains import SimpleSequentialChain

# SimpleSequentialChain으로 두 개의 체인을 연결
overall_chain = SimpleSequentialChain(
    chains=[chain1, chain2],
    verbose=True
)
# SimpleSequentialChain 실행
print(overall_chain.run("서울 랩소디"))
> Entering new SimpleSequentialChain chain...
 서울의 도시적인 분위기와 다양한 문화를 담은 랩 뮤지컬

서울 랩소디는 서울의 다양한 문화와 도시적인 분위기를 담은 랩 뮤지컬이다. 이 작품은 서울을 배경으로 한 랩 뮤지컬로, 서울의 다양한 지역과 사람들의 이야기를 담고 있다. 서울의 번화한 거리에서는 랩을 통해 도시의 활기와 열정을 느낄 수 있고, 한적한 공원에서는 서울의 자연과 조화로운 면을 느낄 수 있다. 또한 서울의 다양한 문화를 담은 공연장에서는 서울의 다양한 문화를 즐기며 서로 다른 사람들과의

서울 랩소디는 도시적인 분위기와 다양한 문화를 담은 랩 뮤지컬로서, 서울의 다양한 지역과 사람들의 이야기를 다채롭게 담아냅니다. 이 작품은 서울을 배경으로 한 랩 뮤지컬로서, 서울의 번화한 거리에서는 랩을 통해 도시의 활기와 열정을 느낄 수 있고, 한적한 공원에서는 서울의 자연과 조화로운 면을 느낄 수 있습니다. 또한 서울의 다양한 문화를 담은 공연장에서는 서울의 다양한 문화를 즐기며 서로 다른 사람들과의 만남을 통해 새로운 경험을 할 수 있습니다.

서울

> Finished chain.

서울 랩소디는 도시적인 분위기와 다양한 문화를 담은 랩 뮤지컬로서, 서울의 다양한 지역과 사람들의 이야기를 다채롭게 담아냅니다. 이 작품은 서울을 배경으로 한 랩 뮤지컬로서, 서울의 번화한 거리에서는 랩을 통해 도시의 활기와 열정을 느낄 수 있고, 한적한 공원에서는 서울의 자연과 조화로운 면을 느낄 수 있습니다. 또한 서울의 다양한 문화를 담은 공연장에서는 서울의 다양한 문화를 즐기며 서로 다른 사람들과의 만남을 통해 새로운 경험을 할 수 있습니다.

서울

3. SequentialChain

from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate


# 템플릿 생성
template = """당신은 극작가입니다. 극의 제목과 시대적 배경이 주어졌을 때, 그 줄거리를 작성하는 것이 당신의 임무입니다.

제목:{title}
시대:{era}
시놉시스:"""

# 프롬프트 템플릿 생성
prompt = PromptTemplate(
    input_variables=["title", "era"], 
    template=template
)

# LLMChain 생성
chain1 = LLMChain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    prompt=prompt, 
    output_key="synopsis"
)
# 템플릿 생성
template = """당신은 연극 평론가입니다. 연극의 시놉시스가 주어지면 그 리뷰를 작성하는 것이 당신의 임무입니다.

시놉시스:
{synopsis}
리뷰:"""

# 프롬프트 템플릿 생성
prompt = PromptTemplate(
    input_variables=["synopsis"], 
    template=template
)

# LLMChain 준비
chain2 = LLMChain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    prompt=prompt, 
    output_key="review"
)
from langchain.chains import SequentialChain

# SequentialChain으로 두 개의 체인을 연결
overall_chain = SequentialChain(
    chains=[chain1, chain2],
    input_variables=["title", "era"],
    output_variables=["synopsis", "review"],
    verbose=True
)
# SequentialChain 실행
print(overall_chain({"title":"서울 랩소디", "era": "100년 후의 미래"}))

Index Chain

인덱스는 LLM이 문서와 가장 잘 상호작용할 수 있도록 문서를 구조화하는 방법을 말합니다. 이 모듈에는 문서 작업을 위한 유틸리티 함수, 다양한 유형의 인덱스, 그리고 이러한 인덱스를 체인에서 사용하는 예시가 포함되어 있습니다.

인덱스가 체인에서 사용되는 가장 일반적인 방법은 ‘검색’ 단계입니다. 이 단계는 사용자의 쿼리를 받아 가장 관련성이 높은 문서를 반환하는 것을 말합니다. 이렇게 구분하는 이유는 (1) 인덱스는 검색 외에 다른 용도로도 사용될 수 있고, (2) 검색은 인덱스 외에 다른 로직을 사용하여 관련 문서를 찾을 수 있기 때문입니다. 따라서 우리는 “검색” 인터페이스라는 개념을 가지고 있으며, 이것이 대부분의 체인이 사용하는 인터페이스입니다.

인덱스와 검색에 대해 이야기할 때는 대부분 텍스트 문서와 같은 비정형 데이터의 인덱싱과 검색에 대해 이야기합니다. 현재 LangChain에서 지원하는 주요 인덱스 및 검색 유형은 벡터 데이터베이스를 중심으로 하고 있으며, 따라서 많은 기능들이 해당 주제에 대해 자세히 다루고 있습니다.

  • 문서 로더(Document Loaders): 다양한 소스에서 문서 로드 작업을 담당하는 클래스입니다.

    • unstructured 패키지를 사용하여 텍스트, 파워포인트, 이미지, HTML, PDF 등 모든 유형의 파일을 텍스트 데이터로 변환할 수 있습니다.

  • 텍스트 분할기(Text Splitters): 텍스트를 더 작은 청크로 분할하는 작업을 담당하는 클래스입니다.

    • 언어 모델이 큰 텍스트를 잘 처리하기 위해서는 해당 텍스트를 더 작은 조각으로 나누어야 합니다.

    • 의미론적으로 관련된 텍스트 조각을 함께 유지해야 합니다.

    • 여기서 "의미론적으로 관련된"이 의미하는 바는 텍스트의 종류에 따라 다를 수 있기 때문에 이에 관한 분할/결합/생성 등이 이뤄져야 합니다.

  • 벡터 저장소(VectorStores): 입력 텍스트를 임베딩을 통해 벡터를 생성하고, 생성된 벡터를 저장/관리/검색할 수 있는 기능을 제공하는 저장소입니다.

    • 가장 일반적인 인덱스 타입은 각 문서에 대해 숫자 임베딩(임베딩 모델 사용)을 생성하는 타입입니다.

    • 임베딩 별로 관련 문서를 빠르게 조회할 수 있고 유사도 검색이 가능합니다.

  • 검색기(Retrievers): 언어 모델과 결합할 관련 문서를 가져오기 위한 인터페이스입니다.

    • 문자열을 받아 문서 목록을 반환하는 get_relevant_documents 메서드를 제공합니다.

4. RetrievalQA

from langchain.text_splitter import CharacterTextSplitter

# 문서 불러오기(현재 폴더에 문서를 넣어둡니다)
with open("akazukin_all.txt") as f:
    test_all = f.read()

# 청크 분할
text_splitter = CharacterTextSplitter(
    separator = "\n\n", # 구분 기호
    chunk_size=300, # 청크의 최대 문자 수
    chunk_overlap=20 # 겹치는 최대 문자 수
)
texts = text_splitter.split_text(test_all)

# 확인
print(len(texts))
for text in texts:
    print(text[:10], ":", len(text))
6
제목: '전뇌 빨간 : 299
제2장: 울프 코퍼 : 162
제3장: 배신과 재 : 273
제4장: 울프 코퍼 : 206
제5장: 결전의 순 : 294
제7장: 새로운 시 : 195
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores.faiss import FAISS

# 벡터 데이터베이스 생성
docsearch = FAISS.from_texts(
    texts=texts, # 청크 배열
    embedding=OpenAIEmbeddings() # 임베딩
)
from langchain.chains import RetrievalQA

# 질의응답 체인 생성
qa_chain = RetrievalQA.from_chain_type(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ), # LLM
    chain_type="stuff", # 체인 종류
    retriever=docsearch.as_retriever(), # 리트리버
)
# 질의응답 체인 실행
print(qa_chain.run("미코의 소꿉친구 이름은?"))

5. RetrievalQAWithSourcesChain

from langchain.text_splitter import CharacterTextSplitter

# 문서 로드
with open("akazukin_all.txt") as f:
    test_all = f.read()

# 청크 분할
text_splitter = CharacterTextSplitter(
    separator = "\n\n", # 구분 기호
    chunk_size=300, # 청크의 최대 문자 수
    chunk_overlap=20, # 최대 오버랩 문자 수
)
texts = text_splitter.split_text(test_all)

# 확인
print(len(texts))
for text in texts:
    print(text[:10], ":", len(text))
6
제목: '전뇌 빨간 : 299
제2장: 울프 코퍼 : 162
제3장: 배신과 재 : 273
제4장: 울프 코퍼 : 206
제5장: 결전의 순 : 294
제7장: 새로운 시 : 195
# 메타데이터 준비
metadatas=[
    {"source": "1장"},
    {"source": "2장"},
    {"source": "3장"},
    {"source": "4장"},
    {"source": "5~6장"},
    {"source": "7장"}
]
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores.faiss import FAISS

# 벡터 데이터베이스 생성
docsearch = FAISS.from_texts(
    texts=texts, # 청크 배열
    embedding=OpenAIEmbeddings(), # 임베딩
    metadatas=metadatas # 메타데이터
)
from langchain.chains import RetrievalQAWithSourcesChain

# 소스가 있는 질의응답 체인 생성
qa_chain = RetrievalQAWithSourcesChain.from_chain_type(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    chain_type="stuff",
    retriever=docsearch.as_retriever(),
)
# 소스가 있는 질의응답 체인 실행
print(qa_chain({"question": "미코의 소꿉친구 이름은?"}))
{'question': '미코의 소꿉친구 이름은?', 'answer': ' 미코의 소꿉친구 이름은 료.\n', 'sources': '2장, 3장'}

6. SummarizeChain

from langchain.text_splitter import CharacterTextSplitter

# 문서 로드
with open("akazukin_all.txt") as f:
    test_all = f.read()

# 청크 분할
text_splitter = CharacterTextSplitter(
    separator = "\n\n", # 구분 기호
    chunk_size=300, # 청크의 최대 문자 수
    chunk_overlap=20, # 최대 오버랩 문자 수
)
texts = text_splitter.split_text(test_all)

# 확인
print(len(texts))
for text in texts:
    print(text[:10], ":", len(text))
6
제목: '전뇌 빨간 : 299
제2장: 울프 코퍼 : 162
제3장: 배신과 재 : 273
제4장: 울프 코퍼 : 206
제5장: 결전의 순 : 294
제7장: 새로운 시 : 195
from langchain.docstore.document import Document

# 청크 배열을 문서 배열로 변환
docs = [Document(page_content=t) for t in texts]
from langchain.chains.summarize import load_summarize_chain
from langchain.llms import OpenAI

# 요약 체인 생성
chain = load_summarize_chain(
    llm=OpenAI(
        model="gpt-3.5-turbo-instruct",
        temperature=0
    ),
    chain_type="map_reduce",
)
# 요약 체인 실행
chain.run(docs)
'\n\n"Red Hooded Brain" is a story about Miko, an illegal data courier, who takes on a mission to expose the corrupt actions of a large corporation. In chapter 2, she evades agents of the corporation and reaches a bar where she meets her childhood friend Ryo. In chapter 3, they team up to expose the corporation\'s conspiracy and save the citizens. In chapter 4, they engage in a final battle and Miko discovers the corporation\'s involvement in her mother\'s illness. In chapter 5, they confront the CEO and expose the corporation\'s wrongdoings. In chapter 6, they successfully free the citizens and find a cure for Miko\'s mother\'s illness. After the corporation\'s collapse, Miko and Ryo reconcile and vow to use their strength to make the city a better place. '

Utility Chain

일반적으로 매우 좁은 목적으로 LLM에서 특정 답변을 추출하는 데 사용

7. OpenAIModerationChain

API와 상호 작용하도록 설계되었으며 OpenAPI 엔드포인트에서 쉽게 사용할 수 있도록 최적화

from langchain.chains import OpenAIModerationChain

# OpenAIModerationChain 준비
chain = OpenAIModerationChain()
# 문제없는 발언
chain.run("This is OK!")
'This is OK!'
# 문제 발언
chain.run("I'll kill you!")
"Text was found that violates OpenAI's content policy."
from langchain.chains import OpenAIModerationChain

# OpenAIModerationChain 준비
chain = OpenAIModerationChain(error=True)

try:
    # 문제 있는 발언
    chain.run("I'll kill you!")
except ValueError as e:
    print("문제 발언입니다!")
    print(e)
문제 발언입니다!
Text was found that violates OpenAI's content policy.

Last updated