본문 바로가기
데이터&AI/LLM

openai 의 response_format (Structured_outputs의 원조)

by 일등박사 2024. 11. 6.
728x90

지난 포스팅에서는 Structured_outputs 의 기능에 대하여 알아보았습니다!~

 

2024.11.04 - [데이터&AI/LLM] - Openai 패키지에서 원하는 결과를 output으로 받기(Structured outputs)

 

Openai 패키지에서 원하는 결과를 output으로 받기(Structured outputs)

GPT API를 활용하여 텍스트 생성은 이제 기본중에 기본인데요!!,이에 더해서 작업에서 필요한 정보만 명확하게 뽑아내고 싶을떄가있습니다!!예를 들면!!뉴스기사에서 중요성이 얼만큼인지, 긍정

drfirst.tistory.com

 

 

사전에 필요한 객채를 선언하고, 해당 형식에 맞게 받는 방법이지만!!

client.beta.chat.completions.parse

 

beta의 형식으로 앞으로 어떻게 발전할지 혹은 없어질 지 알수 가 없습니다.

이 관점에서 현재의 표준인 response_format  에 대하여 알아봅시다!!

 

1. Basic - 기본!!!

openai 패키지를 통하여  openapi와 데이터를 주고받는 표준은 아래와 같습니다!!

from openai import OpenAI

client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "동북아시아의 국가들을 알려줘"}
    ]
)
response.choices[0]

그런데!!사실 여기에는 한가지가 숨어있는데요!! 바로 response_format입니다!!

아래의 코드를 볼까요!?

 

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "동북아시아의 국가들을 알려줘"}
    ],
    response_format={ "type": "text",                          
                        }
)
response.choices[0]

 

보시는 바와 같이

    response_format={ "type": "text",   }

 

가 추가되었습니다! 즉 기존에 저희는 텍스트로 response하고있었다는것이지요~!@

2. json_object - json 결과물 받기!!!!

그래서!! 이 response_format 부분을 살짝만 바꿔주면~~

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a helpful assistant designed to output JSON."},
        {"role": "user", "content": "동북아시아의 국가들을 알려줘"}
    ],
    response_format={"type": "json_object"}
)

openai 패키지를 통하여  openapi와 데이터를 주고받는 표준은 아래와 같습니다!!

response_format={"type": "json_object"}

이 것 하나만 추가된것이구요~!!

 

system 의 프롬포트에 json으로 뽑으라는 말과 함꼐 response_format을 바꾸어주면!! 이렇게 제이슨으로 바라는 결과를 받게됩니다~!!

이렇게 지원되는 type은 text json_object와 json_schema 입니다!

그래서! 마지막으로 json_schema에 대하여 알아봅시가!!

 

3. json_schema : json 결과물이지만 형식에 더 중점을 둠!!

json_object가 데이터의 내용에 중점을 두고, 직접적으로 결과를 반환하는 방식이었다면

json_schema는 구조/형식을 정의하고 일관적인 데이터를 받는 방법입니다!!

이번 예시는 조선시대에 발생했던 "이괄의 난"에 대하여 알아봅시다!!

 

저희가 알고싶은것은!!

1. 이괄의 난의 경과 2. 이괄의 난에서의 주요인물 3. 최종 결과

세가지인데요~~

이를 json schema로 아래와 같이 설계합니다!!

response_format= {
    "type": "json_schema",
    "json_schema": {
      "name": "history_response",
      "strict": True,
      "schema": {
        "type": "object",
        "properties": {
          "경과": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "연도.월": {
                  "type": "string"
                },
                "주요사건": {
                  "type": "string"
                }
              },
              "required": ["연도.월", "주요사건"],
              "additionalProperties": False
            }
          },
          "주요인물": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "이름": {
                  "type": "string"
                },
                "주요역할": {
                  "type": "string"
                }
              },
              "required": ["이름", "주요역할"],
              "additionalProperties": False
            }
          },            
          "최종결과": {
            "type": "string"
          },

        },
        "required": ["경과","주요인물","최종결과"],
        "additionalProperties": False
      }
    }
  }

 

그리하여 GPT-4o모델로 호출해보면!!

client = OpenAI()

response_format= {
    "type": "json_schema",
    "json_schema": {
      "name": "history_response",
      "strict": True,
      "schema": {
        "type": "object",
        "properties": {
          "경과": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "연도.월": {
                  "type": "string"
                },
                "주요사건": {
                  "type": "string"
                }
              },
              "required": ["연도.월", "주요사건"],
              "additionalProperties": False
            }
          },
          "주요인물": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "이름": {
                  "type": "string"
                },
                "주요역할": {
                  "type": "string"
                }
              },
              "required": ["이름", "주요역할"],
              "additionalProperties": False
            }
          },            
          "최종결과": {
            "type": "string"
          },

        },
        "required": ["경과","주요인물","최종결과"],
        "additionalProperties": False
      }
    }
  }

completion = client.chat.completions.create(
  model="gpt-4o",
  messages=[
    {
      "role": "system",
      "content": "You are a helpful history tutor."
    },
    {
      "role": "user",
      "content": "이괄의 난 관하여 한국어로 소개해줘"
    }
  ],
  response_format=response_format
)

print(completion.choices[0].message.content)

결과로 우리가 의도한 대로 예븐 json 양식을 return 해 줍니다!

 

 

마지막으로!! 결과물이 너무 간략한것이 아쉬워서 나무위키의 데이터도 추가하고 또 해보았습니다!!

 

client = OpenAI()

namu_wiki = """시기
1624년 1월 24일 ~ 4월 1일
장소
한반도 북부 일대
원인
인조반정 이후 공신 책봉에 불만을 품은 이괄의 봉기
교전국
조선 어기 조선
이괄의 반란군
지휘관
인조
장만
정충신
남이흥
이시발
이중로†
이원익
박효립†
김충선[1]
임경업
심기원 등
이괄†
기익헌
한명련†
흥안군 이제†
이수백
이흥립†
한윤
김효신†
서아지†
사쇄문†
고효내† 등
병력
관군 30,000여명[2]
정충신, 남이흥의 별동대 2,000여명
항왜 300명
관서군 12,000여명
관군 포로 5,000여명
항왜 120여명[3]
피해
지방군 와해 및 퇴각
베테랑 지휘관 다수 사망
전 군 병력 전멸 및 도주
결과
관군의 반란군 진압
영향
조선의 북방 방어선 약화
정묘호란, 병자호란 당시 청나라 팔기군의 신속한 조선 침략 진군 성공의 원인

1. 개요
2. 배경
2.1. 김류와 논공행상에 대한 불만이 원인?
3. 전개
3.1. 반란 고변
3.2. 금부도사를 죽이다
3.3. 반란 초기, 양측의 삽질
3.4. 황주 전투
3.5. 마탄 전투
3.6. 임진강을 넘어 한양으로
3.7. 단 하룻밤 동안의 한양 생활
3.8. 안령(무악재) 전투
4. 결말
5. 평가
5.1. 이괄의 난과 호란 관련
6. 관련 인물
6.1. 이괄 군
6.2. 조정
6.3. 관군
7. 관련 링크
8. 대중매체에서
9. 둘러보기

1. 개요[편집]
1624년 1월(조선 인조 2년)에 인조반정 공신들의 정치적인 혼란으로 일어난 대규모 반란.

조선 역사에서 한성(현 서울특별시)과 경기도가 아닌 지역에서 일어난 반란군이 한성을 점거한 유일무이한 반란이다.[4] 또한 도성을 점거하고 새로운 왕을 옹립하고도 실패한 유일한 반란이다. 다행히 반란을 진압에 성공한 덕분에 조선 후기 왕실이 전조(고려)처럼 무신정권이 세워져서 허수아비 신세로 전락할 운명을 면했다.
2. 배경[편집]
조선 중기의 무신 이괄은 인조반정 때 광해군을 실각시키는 데 동참하여 큰 공을 인정받아 2등 공신의 첫 자리에 오른다. 비록 무관이고 초기부터 결사한 인물이 아니었지만, 반정 당시에 칼을 잡고 갑옷을 입고 나서서 사기를 드높였기에 그만한 대우를 받은 것이다. 심지어 대장 김류가 늦는 동안 잠시 임시로 대장을 맡기도 했다.

본래 병마절도사로서 북방을 지키는 무장이었던 이괄은, 공신을 도성에 둬야 마땅하다는 김류의 주장에 따라 한성에서 벼슬을 하게 된다. 인조는 북방을 지킬 수 있는 것은 이괄뿐이라며 내키지 않아 했으나, 김류만이 아닌 이귀까지 주청하자 받아들여 이괄을 불러들였다. 이후 한성판윤에 임명되었으나 1달 만에 무슨 이유인지 사직을 청했다가 인조가 거부하여 반려되었으며,[5] 그 외에는 좌포도대장을 지냈다.

그러나 북방 후금의 낌새가 심상치 않자 인조는 도원수 장만에게 대책을 물었고, 장만은 이괄 혹은 이서를 부원수로 보내달라고 요청한다. 인조는 이를 허락하여 이괄이 부원수로 임명된다. 6월 비변사가 후금의 정세가 심상치 않다며 부원수 이괄을 미리 내려보낼 것을 요청하여 인조가 받아들여 1만 5천 명의 대군을 내리고 방비에 임하게 한다. 군량 문제 때문에 인조는 1만 5천을 다 데리고 갈 거냐고 넌지시 감축할 것을 제안했으나 이괄은 방비를 소홀히 할 수 없다고 거부하였다. 다음날인 8월 17일, 인조는 출발하는 이괄에게 "도원수와 자네가 가니 서쪽의 근심을 전부 잊을 수 있다."라며 굳건한 신뢰를 보내며 격려했고, 이괄은 "신이 중책을 맡아 떨리고 두렵습니다. 올해 적군이 쳐들어오면 숫자와 강함의 차이가 확실하니 어찌 당해내겠습니까. 그러나 한 번 죽기로 싸워 나라의 은혜를 어찌 갚지 않겠습니까."라며 두려움과 동시에 결사의 각오와 충성심을 내비치며 작별했다.

약 2개월 뒤인 10월 15일, 이괄의 요청으로 전라도 군사가 추가로 더 보내진다.
"""

response_format= {
    "type": "json_schema",
    "json_schema": {
      "name": "history_response",
      "strict": True,
      "schema": {
        "type": "object",
        "properties": {
          "경과": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "연도.월": {
                  "type": "string"
                },
                "주요사건": {
                  "type": "string"
                }
              },
              "required": ["연도.월", "주요사건"],
              "additionalProperties": False
            }
          },
          "주요인물": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "이름": {
                  "type": "string"
                },
                "주요역할": {
                  "type": "string"
                }
              },
              "required": ["이름", "주요역할"],
              "additionalProperties": False
            }
          },            
          "최종결과": {
            "type": "string"
          },

        },
        "required": ["경과","주요인물","최종결과"],
        "additionalProperties": False
      }
    }
  }

completion = client.chat.completions.create(
  model="gpt-4o",
  messages=[
    {
      "role": "system",
      "content": "You are a helpful history tutor."
    },
    {
      "role": "user",
      "content": "이괄의 난 관하여 한국어로 소개해줘" + namu_wiki
    }
  ],
  response_format=response_format
)

json.loads(completion.choices[0].message.content)

 

결과물이 마음에 쏙 드네요~!^^

{'경과': [{'연도.월': '1624.01', '주요사건': '이괄, 공신 책봉에 대한 불만으로 반란 시도'},
  {'연도.월': '1624.01', '주요사건': '이괄의 반란군, 한성을 점거'},
  {'연도.월': '1624.01', '주요사건': '금부도사를 살해하는 등 초반 혼란'},
  {'연도.월': '1624.02', '주요사건': '황주 전투 등에서 관군과 교전'},
  {'연도.월': '1624.03', '주요사건': '임진강을 넘어 한성으로 진격'},
  {'연도.월': '1624.04', '주요사건': '반란 진압, 이괄 사망'},
  {'연도.월': '1624.04', '주요사건': '반란으로 인한 조선 북방 방어선 약화'}],
 '주요인물': [{'이름': '인조', '주요역할': '조선의 국왕, 반란 진압 주도'},
  {'이름': '장만', '주요역할': '관군 지휘, 반란 진압 참여'},
  {'이름': '정충신', '주요역할': '관군 지휘, 반란 진압 참여'},
  {'이름': '이괄', '주요역할': '반란군 지휘관, 불만으로 봉기'},
  {'이름': '기익헌', '주요역할': '이괄 지원, 반란군 참여'},
  {'이름': '흥안군 이제', '주요역할': '이괄 지원, 반란군 참여'}],
 '최종결과': '이괄의 난은 관군의 성공적인 진압으로 마무리되었으나 조선 북방 방어선이 약화되어 앞으로 있을 청나라의 공격에 취약해지는 결과를 가져왔다.'}
728x90

댓글