langchain을 사용하여 기본적인 openai를 사용하는 방법이다.
OpenAI API 키 발급
OpenAI API를 사용하기 위해서는 우선 API 키를 발급해야 한다. API 키를 발급하는 방법은 테디팀 사이트에 잘 정리되어 있으니 참고하기 바란다.
https://teddylee777.github.io/openai/openai-api-key/
환경 세팅
pipenv 사용
python에서는 가상환경을 사용하는 방법은 여러가지가 있는데 여기서는 가상환경을 위해 pipenv
를 사용한다.
Pipenv 매뉴얼: https://pipenv.pypa.io/en/latest/
pipenv가 설치되지 않았다면
pip install pipenv
를 통해 설치를 한다.
프로젝트 루트에 Pipfile 파일을 생성한다. (파일명: Pipfile)
Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
langchain = "==0.1.16"
openai = "==1.21.2"
langchain-openai = "==0.1.3"
langchain-community = "==0.0.33"
python-dotenv = "==1.0.0"
black = "*"
[dev-packages]
[requires]
python_version = "3.12"
아래 명령어로 패키지를 설치한다.
pipenv install
openai api key 준비
api를 호출하기 전에 위에서 발급한 API를 .env 파일에 넣어준다. openai를 호출할 때 사용할 api key이다.
OPENAI_API_KEY=sk-xxx
기본 호출
langchain의 최소한 기능을 openai api를 호출해보자.
- api key 로딩
- ChatOpenAI() 생성
- 프롬프트 생성
- 응답 출력
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
# api key 로딩
load_dotenv()
# open ai chat 생성
llm = ChatOpenAI()
# 질의 내용
question = "Java로 1부터 10까지 출력하는 함수 만들어줘"
# 실행
result = llm.invoke(question)
print(result)
실행 결과
content='Sure! 아래는 Java로 1부터 10까지 출력하는 함수의 예시입니다.\n\n```java\npublic class Main {\n public static void printNumbers() {\n for (int i = 1; i <= 10; i++) {\n System.out.println(i);\n }\n }\n\n public static void main(String[] args) {\n printNumbers();\n }\n}\n```\n\n위의 코드를 실행하면 1부터 10까지의 숫자가 한 줄씩 출력됩니다.' response_metadata={'token_usage': {'completion_tokens': 115, 'prompt_tokens': 26, 'total_tokens': 141}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-65c3871c-1bb5-423c-b3a5-b8912582fdab-0'
.env에 들어갈 api 키 이름은 정확히 OPENAI_API_KEY
이어야 하며 이름이 다르다면 아래와 같이 할 수도 있다.
import os
load_dotenv()
llm = ChatOpenAI(openai_api_key=os.environ["MY_KEY"])
이를 경우 MY_KEY
이름으로 api key를 가져오는 방식이다.
디버깅
호출되는 과정을 디버깅하려면 아래와 같이 debug=True
로 하면 된다.
import langchain
langchain.debug=True
디버그를 활성화하고 실행하면 아래 디버그 코드가 표시된다.
[llm/start] [llm:ChatOpenAI] Entering LLM run with input:
{
"prompts": [
"Human: Java로 1부터 10까지 출력하는 함수 만들어줘"
]
}
[llm/end] [llm:ChatOpenAI] [2.45s] Exiting LLM run with output:
{
"generations": [
[
...
]
],
"llm_output": {
"token_usage": {
"completion_tokens": 115,
"prompt_tokens": 26,
"total_tokens": 141
},
"model_name": "gpt-3.5-turbo",
"system_fingerprint": null
},
"run": null
}
프롬프트의 내용, llm에서 사용된 토큰, 모델명 등이 표시된다.
PromptTemplate 사용
위의 question에서 질의 내용은 항상 동일(하드코딩)한데, 실제로 이렇게 사용하는 경우는 없을 것이다. 질의 내용을 변수처리를 해서 요청하고 싶을 때 PromptTemplate
을 사용할 수 있다.
from dotenv import load_dotenv
from langchain.chains.llm import LLMChain
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
load_dotenv()
llm = ChatOpenAI()
# 질의내용
template = "{language}로 1부터 10까지 출력하는 함수 만들어줘"
prompt = PromptTemplate.from_template(template=template)
chain = LLMChain(prompt=prompt, llm=llm)
result = chain.invoke({"language": "Java"})
print(result)
PromptTemplate은 template에서 지정한 변수({})를 문자열로 만드는데 사용되는 템플릿이다. 템플릿의 입력된 변수는 {}로 나타내고 {}안에 있는 문자가 변수(input_variables)로 정의된다.
template = "{language}로 1부터 10까지 출력하는 함수 만들어줘"
prompt = PromptTemplate.from_template(template=template)
위와 같이 template을 PromptTemplate으로 지정하면 아래와 같이 값이 지정이 된다.
input_variables=['language']
template='{language}로 1부터 10까지 출력하는 함수 만들어줘'
실행 결과
{
"language": "Java",
"text": "Sure! 아래는 Java로 1부터 10까지 출력하는 함수의 예시입니다.\n\n```java\npublic class PrintNumbers {\n public static void printNumbers() {\n for (int i = 1; i <= 10; i++) {\n System.out.println(i);\n }\n }\n \n public static void main(String[] args) {\n printNumbers();\n }\n}\n```\n\n위 코드를 실행하면 1부터 10까지의 숫자가 한 줄씩 출력됩니다. 함수를 호출하면 됩니다."
}
또는 아래와 같이
template = "{language}로 1부터 10까지 출력하는 함수 만들어줘"
prompt_template = PromptTemplate.from_template(template)
prompt = prompt_template.format(language="Python")
llm = ChatOpenAI()
result = llm.invoke(prompt)
print(result)
여러 개의 값을 넘기는 경우
language 변수에 여러 개의 값을 넘기는 경우 아래와 같이 apply
를 적용하면 된다.
from dotenv import load_dotenv
from langchain.chains.llm import LLMChain
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
load_dotenv()
llm = ChatOpenAI()
# 질의내용
input_variables = [{"language": "Java"}, {"language": "python"}]
template = "{language}로 1부터 10까지 출력하는 함수 만들어줘"
prompt = PromptTemplate.from_template(template=template)
chain = LLMChain(prompt=prompt, llm=llm)
result = chain.apply(input_variables)
print(result)
실행결과
[
{
"text": "```java\npublic class Main {\n public static void printNumbers() {\n for (int i = 1; i <= 10; i++) {\n System.out.println(i);\n }\n }\n\n public static void main(String[] args) {\n printNumbers();\n }\n}\n```"
},
{
"text": "Sure! 아래는 Python으로 1부터 10까지 출력하는 함수의 예시입니다.\n\n```python\ndef print_numbers():\n for i in range(1, 11):\n print(i)\n\nprint_numbers()\n```\n\n이 함수를 호출하면 1부터 10까지의 숫자가 한 줄에 하나씩 출력됩니다."
}
]
변수를 2개 이상 지정하는 경우
만일 변수를 여러개 넣고 싶다면 아래와 같이 {}를 필요한 만큼 만들면 된다.
template = "{language}로 {task} 만들어줘"
prompt = PromptTemplate.from_template(template=template)
print(prompt)
chain = LLMChain(prompt=prompt, llm=llm)
result = chain.invoke(
{"language": "Java", "task": "1부터 10까지 출력하는 함수 만들어줘"}
)
print(result)
streaming 사용
호출 결과를 한번에 받는 대신 스트림으로 받아 텍스트가 타이핑되는 것처럼 표시되게 하려면 아래와 같이 하면 된다.
ChatOpenAI를 생성할 때 streaming=True를 하고 StreamingStdOutCallbackHandler()를 callback으로 지정을 한다.
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
load_dotenv()
llm = ChatOpenAI(
streaming=True,
callbacks=[StreamingStdOutCallbackHandler()],
)
# 질의내용
template = "{language}로 1부터 10까지 출력하는 함수 만들어줘"
prompt = PromptTemplate.from_template(template=template)
chain = LLMChain(prompt=prompt, llm=llm)
result = chain.invoke({"language": "Java"})
print(result)