[우아한 스터디] OpenAI Chat Completions API 로 Ollama 사용하기

Judy·2024년 7월 8일
0

LLM 에 프롬프트를 '잘 넣는 법' 한 가지를 소개합니다.

LLM을 이용해 원하는 작업 (ex : 질의응답, 추천, 번역) 등을 하기 위해서 프롬프트로 명령을 줄 수 있고,
챗봇 형식을 이용하면 해당 작업을 시킬 수 있는데요,
Ollama 에서 OpenAI compatibility를 지원하게 되어, 즉 OpenAI 와 호환이 가능해져
이번 포스팅에서 소개합니다.

Install Ollama

가장 먼저 ollama 홈페이지에 방문하여 ollama 를 설치합니다.
https://ollama.com/

Setup

ollama 에서 사용할 모델을 pull 합니다.
저는 Llama3 을 pull 했습니다.

ollama pull llama3

Basic Code

다음은 Ollama 공식 블로그에서 제공하는 Ollama 와 OpenAI Chat Completions API 호환 코드입니다.

from openai import OpenAI

client = OpenAI(
	# base_url 은 ollama 의 로컬 주소로, 아래와 같이 입력합니다.
    base_url = 'http://localhost:11434/v1',
    api_key='ollama', # required, but unused (필수이지만 실제 사용되지는 않음)
)

# Completions API
# OpenAI 의 주요 API 중 하나로, 주어진 입력에 대해 자연어 생성(NLG) 를 수행합니다.
예를 들어, 텍스트 프롬프트가 주어지면 모델은 이를 기반으로 자연스러운 텍스트를 생성합니다.
# Chat Completions API (대화 완성 API) 는 사용자가 입력한 텍스트를 기반으로 자연스러운 대화를 생성하고 응답을 제공합니다.
response = client.chat.completions.create(
  model="llama3",
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The LA Dodgers won in 2020."},
    {"role": "user", "content": "Where was it played?"}
  ]
)
print(response.choices[0].message.content)

Output

The 2020 World Series was played at Globe Life Field in Arlington, Texas, and at Dodger Stadium in Los Angeles, California. The series was played in a neutral site format due to the COVID-19 pandemic, with Games 1 and 2 held at Globe Life Field and Games 3, 4, and 7 held at Dodger Stadium.

Json 출력 Code

챗봇만을 구현한다면 위 Output 처럼 string 즉 text 형태여도 무방하지만
LLM을 이용하는 서비스를 개발한다면 json 포맷으로 출력을 받은 뒤에
json 포맷의 key 로부터 value 값을 가져와서 써야 합니다.

LLM의 출력이 json 포맷으로 나올 수 있도록 작업해 보겠습니다.

Response format 추가

가장 간단한 방법으로, response format 을 json 으로 지정하는 방법이 있습니다.

from openai import OpenAI

client = OpenAI(
    base_url = 'http://localhost:11434/v1',
    api_key='ollama',
)

response = client.chat.completions.create(
  model="llama3",
  # 응답 포맷을 json 객체로 지정
  response_format={ "type": "json_object" },
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The LA Dodgers won in 2020."},
    {"role": "user", "content": "Where was it played?"}
  ]
)
print(response.choices[0].message.content)

Output

❯ python llama3_test_openai.py
{}
❯ python llama3_test_openai.py
{}
❯ python llama3_test_openai.py
{}

출력 결과가 잘 나오지 않네요.
이번에는 Prompt 를 이용해 Output format 을 JSON 으로 지정하는 코드를 추가합니다.

Prompt 추가

from openai import OpenAI

client = OpenAI(
    base_url = 'http://localhost:11434/v1',
    api_key='ollama', # required, but unused
)

# 출력이 지정된 json format 으로 나오도록 프롬프트를 지정합니다.
command = f'''
YOU MUST STRICTLY ADHERE TO THE GIVEN FORMAT.
format your response so that is follows a JSON format, for example:
//
{{
"location": "Globe Life Field", "city": "Arlington"
}}

your response should only contain the JSON format and nothing else.
'''

response = client.chat.completions.create(
  model="llama3",
  response_format={ "type": "json_object" },
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The LA Dodgers won in 2020."},
    {"role": "user", "content": "Where was it played?"},
    {"role": "user", "content": f"{command}"}
  ]
)
print(response.choices[0].message.content)

Output

❯ python llama3_test_openai.py
{
"location": "Globe Life Field", "city": "Arlington", "state": "Texas" }

출력은 Json 처럼 생겼지만 실제로는 개행문자(\n) 등이 포함된 온전한 json 객체 포맷은 아닙니다.

Json 포맷 변환

from openai import OpenAI

import json

client = OpenAI(
    base_url = 'http://localhost:11434/v1',
    api_key='ollama', # required, but unused
)

command = f'''
YOU MUST STRICTLY ADHERE TO THE GIVEN FORMAT.
format your response so that is follows a JSON format, for example:
//
{{
"location": "Globe Life Field", "city": "Arlington"
}}

your response should only contain the JSON format and nothing else.
'''

response = client.chat.completions.create(
  model="llama3",
  response_format={ "type": "json_object" },
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The LA Dodgers won in 2020."},
    {"role": "user", "content": "Where was it played?"},
    {"role": "user", "content": f"{command}"}
  ]
)

# string 을 json format 으로 변환
result = json.loads(response.choices[0].message.content)

print(result)

Output

❯ python llama3_test_openai.py
{'location': 'Globe Life Field', 'city': 'Arlington', 'state': 'Texas'}

출력이 Json format 으로 잘 나오는 것을 확인했으니 위 코드를 사용하기 쉽게 함수로 변환합니다.

함수 변환

from openai import OpenAI

import json

client = OpenAI(
    base_url = 'http://localhost:11434/v1',
    api_key='ollama', # required, but unused
)

def chatbot(question:str):
    command = f'''
    YOU MUST STRICTLY ADHERE TO THE GIVEN FORMAT.
    format your response so that is follows a JSON format, for example:
    //
    {{
    "location": "Globe Life Field", "city": "Arlington"
    }}

    your response should only contain the JSON format and nothing else.
    '''

    response = client.chat.completions.create(
    model="llama3",
    response_format={ "type": "json_object" },
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": f"{question}"},
        {"role": "user", "content": f"{command}"}
    ]
    )

    result = json.loads(response.choices[0].message.content)
    return result

question = "Where was the world series in 2020 played?"
print(chatbot(question))

Output

❯ python llama3_test_openai.py
{'location': 'Globe Life Field', 'city': 'Arlington', 'state': 'Texas'}
❯ python llama3_test_openai.py
{'location': 'Globe Life Field', 'city': 'Arlington', 'state': 'Texas'}
❯ python llama3_test_openai.py
{'location': 'Globe Life Field', 'city': 'Arlington', 'state': 'Texas'}

추가 예제

'virus' 라는 키워드를 주고, 연관된 키워드들을 추천받는 추가 예제 코드입니다.

import openai
from typing import List
import json
 
llama_client = openai.OpenAI(
    # All of your local models are automatically served on localhost:11434
    base_url = "http://localhost:11434/v1",
    api_key='ollama'
)
 
def make_prompt(keyword:str) -> List:
    command = f'''
    I need you to generate related a given keyword based on the following information:
    given keyword: "{keyword}"
    YOU MUST STRICTLY ADHERE TO THE GIVEN FORMAT.
 
    DO NOT INCLUDE ANY KEYWORDS OTHER THAN THE GIVEN KEYWORD.
    format your response so that is follows a JSON format, for example:
    //
    {{
        "virus" : ["corona", "death", "influenza"]
    }}

    your response should only contain the JSON format and nothing else.
    '''
    prompt = [
        {"role": "system", "content": "You are an advanced language model designed to generate related keywords based on a given keyword. Your task is to analyze the given keyword and produce a list of related words or phrases. Ensure that the related words are relevant and commonly associated with the given keyword."},
        {"role": "user", "content": f"Please generate a list of related keywords for the following word: \"{keyword}\""},
        {"role": "user", "content": f"{command}"}
    ]
 
    return prompt
 
# https://platform.openai.com/docs/guides/text-generation/json-mode 
def inference(account: openai.OpenAI, model: str, prompt: str) -> str:
    response = account.chat.completions.create(
        model = model,
        response_format={"type": "json_object"},
        temperature = 0.2,
        messages = prompt,
    )
 
    return response.choices[0].message.content
 
def recommend_keywords(keyword:str) -> str:
    result = inference(llama_client, "llama3", make_prompt(keyword))
    json_data = json.loads(result)
    return json_data


print(recommend_keywords('virus'))

Reference

https://ollama.com/blog/openai-compatibility
https://fornewchallenge.tistory.com/entry/Ollama-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EC%9D%B4%EC%A0%9C-OpenAI-API%EB%A5%BC-%EB%AC%B4%EB%A3%8C%EB%A1%9C-%EC%A6%90%EA%B8%B0%EC%84%B8%EC%9A%94

profile
NLP Researcher

1개의 댓글

comment-user-thumbnail
2024년 7월 31일

https://ollama.com/blog/tool-support
OpenAI compatibility 수정되어서 남깁니다

답글 달기