s00jin 님의 블로그

4. [FastAPI + OpenAI API] 사전 공부 | OpenAI API 구조화된 출력 본문

프로젝트/AI 분석 가계부

4. [FastAPI + OpenAI API] 사전 공부 | OpenAI API 구조화된 출력

s00jin 2025. 6. 26. 00:54

사전 준비

우리 프로젝트는 대화를 통해 사용 내역을 기록하는 기능을 제공하려고 한다.

 

사용자 : “오늘 카페에서 4000원 썼어!” → [카페] 카테고리에 [4,000]원 저장

 

 

대략적으로 이런식으로 저장하려고 한다.

한번도 OpenAI API를 써본 적이 없는 사람으로서… just 막막

정말 오랫동안 고민했다. 그리고 찾아봤다. 그러던중 공식 문서에 구조화된 출력이라는 문서가 있었다.

아래 공식 문서들을 참고했다.

 

https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses

https://platform.openai.com/docs/guides/function-calling?api-mode=responses

 


 

필드  
type 항상 function 으로 작성해야함
name 함수의 이름
description 해당 기능을 언제, 어떻게 사용할지에 대한 세부 정보
parameters 함수의 입력 인수를 정의하는 JSON 스키마
strict 함수 호출에 대해 엄격 모드를 적용할지

위 표는 위에 첨부한 공식 문서를 한 번 읽어보면 알 수 있을거다.


구현

처음 코드는 아래와 같이 작성했다. 근데 이 코드를 실행하면 오류가 발생한다..!

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.environ.get("OPENAI_API_KEY")
)

tools = [{
    "type": "function",
    "name": "save_expense",
    "description": "사용자의 소비 내역을 파싱하여 금액과 카테고리, 날짜를 저장",
    "parameters": {
        "category": {
            "type": "string",
            "enum": ["카페", "식비", "교통", "의류", "문화", "공과금", "기타"],
            "description": "정해진 소비 카테고리 중 하나"
        },
        "amount": {
            "type": "integer",
            "description": "금액 (숫자만, 원단위)"
        },
        "date": {
            "type": "string",
            "description": "발생한 날짜(날짜에 대한 입력이 없으면 당일 날짜로 설정, 문자열로)"
        }
    },
    "required": ["category", "amount", "date"]
}]

response = client.responses.create(
    model="gpt-4.1-nano",
    input="오늘 카페에서 4000원 썼어",
    # messages=[
    #     {"role": "system", "content": "너는 가계부 어시스턴트야."},
    #     {"role": "user", "content": "오늘 카페에서 4000원 썼어"}
    # ],
    tools=tools
)

# 함수 코드 실행 - 모델의 응답을 구문 분석하고 함수 호출을 처리
import json
tool_call = response.output[0]
args = json.loads(tool_call.arguments)

print(args)

 

오류 내용은 더보기를 누르면 확인할 수 있다.

더보기
Traceback (most recent call last): File "/Users/one/Study/LLM_FastAPI/app/api/endpoints/chat.py", line 28, in <module> response = client.responses.create( model="gpt-4.1-nano", ...<5 lines>... tools=tools ) File "/Users/one/Study/LLM_FastAPI/venv/lib/python3.13/site-packages/openai/_utils/_utils.py", line 287, in wrapper return func(*args, **kwargs) File "/Users/one/Study/LLM_FastAPI/venv/lib/python3.13/site-packages/openai/resources/responses/responses.py", line 671, in create return self._post( ~~~~~~~~~~^ "/responses", ^^^^^^^^^^^^^ ...<31 lines>... stream_cls=Stream[ResponseStreamEvent], ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/Users/one/Study/LLM_FastAPI/venv/lib/python3.13/site-packages/openai/_base_client.py", line 1239, in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/one/Study/LLM_FastAPI/venv/lib/python3.13/site-packages/openai/_base_client.py", line 1034, in request raise self._make_status_error_from_response(err.response) from None openai.BadRequestError: Error code: 400 - {'error': {'message': 'Invalid schema for function \'save_expense\': schema must be a JSON Schema of \'type: "object"\', got \'type: "None"\'.', 'type': 'invalid_request_error', 'param': 'tools[0].parameters', 'code': 'invalid_function_parameters'}}

이 오류는 코드에 빠진 부분이 있어서 생겼다!!

 

바로 아래 코드를 추가해줘야 한다.

"additionalProperties": False

 

최종 수정된 전체 코드는 아래와 같다.

from openai import OpenAI
import os
import json

client = OpenAI(
    api_key=os.environ.get("OPENAI_API_KEY")
)

tools = [{
    "type": "function",
    "name": "save_expense",
    "description": "사용자의 소비 내역을 파싱하여 금액과 카테고리, 날짜를 저장",
    "parameters": {
        "type": "object",
        "properties": {
            "category": {
            "type": "string",
            "enum": ["카페", "식비", "교통", "의류", "문화", "공과금", "기타"],
            "description": "정해진 소비 카테고리 중 하나"
            },
            "amount": {
                "type": "integer",
                "description": "금액 (숫자만, 원단위)"
            },
            "date": {
                "type": "string",
                "description": "발생한 날짜(날짜에 대한 입력이 없으면 당일 날짜로 설정, 문자열로)"
            }
        },
        "required": ["category", "amount", "date"],
        "additionalProperties": False
    },
    "strict": True
}]

response = client.responses.create(
    model="gpt-4.1-nano",
    input="오늘 카페에서 4000원 썼어",
    # messages=[
    #     {"role": "system", "content": "너는 가계부 어시스턴트야."},
    #     {"role": "user", "content": "오늘 카페에서 4000원 썼어"}
    # ],
    tools=tools
)

# 함수 코드 실행 - 모델의 응답을 구문 분석하고 함수 호출을 처리
tool_call = response.output[0]
args = json.loads(tool_call.arguments)

print(args)

 

위에 코드 실행 시 출력은

{'category': '카페', 'amount': 4000, 'date': '2023-10-29'}

이렇게 잘 나와준다

(사실 여기에도 옥의 티가 있다.)

 


현재 코드의 문제점

위에 코드를 실행하면 결과물이 반환된다. 근데 결과물에 옥의 티가 있다 ㅎㅎ

date가 이상하다. 현재 2025년인데 2023년의 다른 날짜를 반환해준다... 아직까지도 gpt가 왜 저 날짜를 뺃었는지 모르겠다..?

 

이 문제는 다음 블로그에서 볼 수 있다!!