[LangChain 실전 프로그래밍: ChatGPT 이용한 개발할때 필수 라이브러리]-코드분
2023. 9. 28.

LangChain이란?

  • Chain: 모듈들을 체인으로 연결하여 다른 툴의 출력다음 툴의 입력으로 연결하는방식
  • LLM을 이용해서 만들 수 있는 라이브러리 모음.
  • 파이썬/ 자바스크립트 사용
  • 검색, 메모리, 계산, 요약, 색인, 에이전트 기능 제공
  • 모듈화로 쉽게 조작 가능

 

 

Text-davinci-003 쓰는 법

"text-davinci-003은 open ai의 LLM이다."

!pip install openai
!pip install langchain
import os

OPENAI_API_KEY = "" 

os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY

 

비교

  GPT-3.5-turbo text-davinci-003
학습 데이터 3개월 더 김 -
출력 토큰 수 96개 더 많음 -
가격 10배 저렴 -


GPT-3.5-turbo 쓰는 법

!pip install openai
!pip install langchain
import os

OPENAI_API_KEY = "" 

os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)

chat = ChatOpenAI(model_name='gpt-3.5-turbo', temperature=0.9)
sys = SystemMessage(content="당신은 음악 추천을 해주는 전문 AI입니다.")
msg = HumanMessage(content='1980년대 메탈 음악 5곡 추천해줘.')

aimsg = chat([sys, msg])
aimsg.content

 

 

분석 1
from langchain.chat_models import ChatOpenAI

import ChatopenAI
: import(명령어=키워드)는 chat_models(모듈)에서 ChatopenAI(클래스)를 가져옵니다.
    ChatopenAI ← GPT-3.5-turbo 기반으로 한 모델

from langchain.chat_models import ChatOpenAI
: from(명령어=키워드)는 다른 모듈에서 가져올 클래스를 지정 
    from은 langchain(모듈)에서 chat_models(모듈)을 가져옵니다.
    

from 모듈명 import 클래스명, 함수명, 변수명

 

 

참고자료
from langchain import ChatOpenAI

- langchain(모듈)에서 ChatOpenAI(클래스)를 가져오려고 하지만,
  langchain(모듈)에는 ChatOpenAI(클래스)가 없습니다.
  그래서, 오류발생
  그래서, 마침표"를 사용해서 모듈 안의 묘듈(계층구조)을 표현

 

분석 2
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)

from이 langchain(모듈) 안의 schma(모듈)을 지정하고, import가 AIMessage, HumanMessage, SystemMessage(클래스)들을 가져온다.

참고자료
schema 모듈은 챗봇의 메시지를 나타내는 클래스를 제공
AIMessage(클래스) content 메시지 내용
metadata 메시지 메타데이터
HumanMessage content 메시지 내용
source 메시지 출처
SystemMessage content 메시지 내용
* AIMessage는 챗봇이 생성하는 메시지
* HumanMessage는 사용자가 입력하는 메시지
* SystemMessage는 챗봇이 시스템에서 생성하는 메시지(챗봇의 현재 상태)

* 메타데이터는 메시지에 대한 추가 정보를 제공하는 데 사용

분석 3
chat = ChatOpenAI(model_name='gpt-3.5-turbo', temperature=0.9)
sys = SystemMessage(content="당신은 음악 추천을 해주는 전문 AI입니다.")
msg = HumanMessage(content='1980년대 메탈 음악 5곡 추천해줘.')

aimsg = chat([sys, msg])
aimsg.content

* 구글 코랩은 ipywidgets 모듈이 설치되어 있음
   ipywidgets  모듈은 display() 함수가 설치되어 있음
   display() 함수는 print문을 안써도, 결과가 나옴

 

* 변수_인스턴=클래스=(변수_클래스, 변수_클래스)
* (sys, msg)는 두 개의 객체를 튜플로 묶은 것입니다.
* sysSystemMessage 클래스의 인스턴스이고, msgHumanMessage 클래스의 인스턴스

* 인스턴스는 객체의 실체이고, 변수는 객체를 참조하는 값입니다.
* 인스턴스는 클래스로부터 생성된 객체(인스턴스 변수)
  인스턴스는 객체의 데이터와 메서드


* 변수는 인스턴스를 참조하는 값
  변수는 객체의 주소를 저장

* aimsgChatOpenAI 클래스의 talk() 메서드의 반환값으로, 딕셔너리입니다. 
  contentaimsgmessage 키에 해당하는 값으로, 문자열입니다.
  aimsg.contentaimsg 객체의 content 속성에 접근하여 값을 반환
  b =a.copy()

 

참고자료

변수 종류 설명
전역 변수 함수 내부에서 선언되지 않고 프로그램 전체에서 사용할 수 있는 변수
지역 변수 함수 내부에서 선언되어 함수 내부에서만 사용할 수 있는 변수
정적 변수 함수 내부에서 선언되지만 함수가 호출될 때마다 초기화되는 변수
매개변수 함수 호출 시 전달되는 변수
리턴 값 함수 내부에서 계산된 결과를 반환하는 변수

 

변수 종류 선언 위치 사용 범위
인스턴스 변수 클래스 내부 클래스의 인스턴스
함수 변수(클래스 변수) 함수 내부 함수 내부
전역 변수 프로그램 내부 프로그램 전체
지역 변수 함수 내부 함수 내부
정적 변수 함수 내부 함수 호출될 때마다 초기화됨
매개변수 함수 호출 시 함수 내부
리턴 값 함수 내부 함수 호출 시

 

지역변수

#include <stdio.h>

void print(){
	int a = 30, b = 40;
	printf("%d %d \n", a, b);
}
int main(){
	int a = 10, b = 20;
	printf("%d %d \n", a, b);
	print();
    return 0;
}

/* 결과값 */
// 10 20
// 30 40

매개변수

#include <stdio.h>

void print(int a, int b){
	printf("%d %d \n", a, b);
}

int main(){
	int a = 10, b = 20;
	printf("%d %d \n", a, b);
	print(30, 40);
	return 0;
}

/* 결과값 */
// 10 20
// 30 40

* print 함수의 지역변수를 매개변수로 바꿈

 

전역변수

#include <stdio.h>
int global;
	
int main(){
	printf("%d", global);
	return 0;
}
	
/* 결과값 */
// 0

* 전역변수의 기본값은 0
* 전역변수의 초기화(새로운 값을 넣어주는 것)는 반드시 숫자

정적변수(정적 지역변수)

#include <stdio.h>

void increaseNumber(){
    static int num1;     // 정적 변수 선언 및 값 초기화 (디폴트값 0)
    printf("%d \n", num1);    // 정적 변수 num1의 값을 출력
    num1++;    // 정적 변수 num1의 값을 1 증가시킴
}

int main(){
    increaseNumber();    // 0
    increaseNumber();    // 1
    increaseNumber();    // 2
    increaseNumber();    // 3: 정적 변수가 사라지지 않고 유지되므로 값이 계속 증가함
    
    return 0;
}

* 특정 1회용
* 정적 전역변수는 안쓸 것 같아서 pass~

인스턴스 변수

class Myclass:
	def __init__(self, text) : # 초기화 : 인스턴스 작성시에 자동적으로 호출된다.
		self.vlaue = text # 인스턴스 변수 value를 선언한다.
        
    def print_value(self): # 인스턴스 변수 value의 값을 표시하는 함수
    	print(self.value) # 인스턴스 변수 value에 접근하고 표시한다.

if __name__ = "__main__":
	a = MyClass("123") # 인스턴스 a를 작성
    b = MyClass("abc") # 인스턴스 b를 작성
    
    print(a.value) # 123
    print(b.value) # abc
    
    a.print_value() # 123
    b.print_value() # abc
self.인스턴스변수 = 값

클래스 변수

class MyClass:
	vlaue = 0 # 클래스 변수를 선언

    def __init__(self): # 초기화 : 인스턴스 생성
    	MyClass.value += 1

if __name__ == "__main__":
	a = MyClass() # 인스턴스 a를 생성한다.
    print MyClass.vlaue # 1
    
    b = MyClass() # 인스턴스 b를 생성한다.
    print MyClass.value # 2
클래스.클래스변수
# 파이썬 기재법
차이점 클래스 변수 인스턴스 변수
사용 구분 모든 인스턴스에서 공유하는 값 그 인스턴스만 사용하는 값
정의하는 곳 클래스 정의문 바로 아래에 대입된 변수 함수 정의문 바로 아래에 대입된 self의 속성
클래스 객체로부터 참고 가능 불가능
인스턴스 객체로부터 참고 가능 가능
변경 모든 인스턴스가 변경 그 인스턴스의 속성만 변경

 

Prompt Template & chain 원리

from langchain.prompts import PromptTemplate

prompt = PromptTemplate(
    input_variables=["상품"],
    template="{상품} 만드는 회사 이름 추천해줘. 기억에 남는 한글 이름으로",
)

prompt.format(상품="AI 여행 추천 서비스")
from langchain.chains import LLMChain

chain = LLMChain(llm=chat, prompt=prompt)

chain.run(상품="AI 여행 추천 서비스")

from은 langchain(모듈)에서 prompts(모듈)에서 클래스를 지정하고,
import는 promptTemplate(클래스)를 가져온다.

promptTemplate(클래스)에서 (클래스 변수(메서드), 클래스 변수)(튜플)

from은 langchain(모듈)에서 chains(모듈)에서 클래스를 지정하고,
LLMChain(클래스)를 가져온다.

chain(인스턴스)는 LLMchain(클래스) chat(API)와 prompt(promptTemplate)

chain.run(문장)이 prompt로 들어가서 위의 prompt.format()에 나올 것이다. 그걸 chatgpt llm으로 보내서 실행

0928

ChatPromptTemplate & chain 원리(나중에 하자)

from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

chat = ChatOpenAI(temperature=0)

template="You are a helpful assisstant that tranlates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])


chatchain = LLMChain(llm=chat, prompt=chat_prompt)
chatchain.run(input_language="English", output_language="Korean", text="I love programming.")

 

Agents and Tools

from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType

 

# tools = load_tools(["serpapi", "llm-math"], llm=chat)
tools = load_tools(["wikipedia", "llm-math"], llm=chat)

agent = initialize_agent(tools, llm=chat, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("페이스북 창업자는 누구인지? 그의 현재(2023년) 나이를 제곱하면?")
agent.tools
print(agent.tools[0].description)
print(agent.tools[1].description)

 

Memory

from langchain import ConversationChain

conversation = ConversationChain(llm=chat, verbose=True)
conversation.predict(input="인공지능에서 Transformer가 뭐야?")
conversation.predict(input="RNN하고 차이 설명해줘.")
conversation.memory

 

Document Loaders

from langchain.document_loaders import WebBaseLoader

loader = WebBaseLoader(web_path="https://ko.wikipedia.org/wiki/NewJeans")

documents = loader.load()

 

from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
len(docs)

# 4096 token = 3000 English word
print(docs[1].page_content)

 

Summarization

#@title 8. Summarization
from langchain.chains.summarize import load_summarize_chain
chain = load_summarize_chain(chat, chain_type="map_reduce", verbose=True)
chain.run(docs[:3])

 

Embeddings and VectorStore

#@title 9. Embeddings and VectorStore
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.embeddings import OpenAIEmbeddings

# embeddings = OpenAIEmbeddings()
embeddings = HuggingFaceEmbeddings()

from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import FAISS

# from langchain.text_splitter import RecursiveCharacterTextSplitter
# text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)

index = VectorstoreIndexCreator(
    vectorstore_cls=FAISS,
    embedding=embeddings,
    # text_splitter=text_splitter,
    ).from_loaders([loader])

# 파일로 저장
index.vectorstore.save_local("faiss-nj")
index.query("뉴진스의 데뷔곡은?", llm=chat, verbose=True)
index.query("뉴진스의 데뷔 멤버는?", llm=chat, verbose=True)
index.query("멤버의 나이는?", llm=chat, verbose=True)
index.query("멤버의 나이는? (오늘은 2023년 4월 18일)", llm=chat, verbose=True)

 

FAISS 벡터DB 디스크에서 불러오기

index2.query("뉴진스의 데뷔 멤버는?", llm=chat, verbose=True)