> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 구조화된 출력 복구

> API Key 단위 구조화된 출력 복구: 게이트웨이가 잘못된 JSON을 파싱 가능한 유효한 JSON으로 자동 복구하며, Chat Completions·Responses·Claude·Gemini를 지원합니다.

모델이 [구조화된 출력](/ko/api/Structured-Output) 시나리오에서 반환하는 JSON은 때때로 파싱에 실패합니다: 출력이 `max_tokens`에 의해 잘리거나, 후행 쉼표가 붙어 있거나, 내용이 Markdown 코드 블록으로 감싸져 있는 경우입니다. 애플리케이션 측에서는 이를 위해 재시도나 수동 복구 로직을 작성해야 하는 것이 일반적입니다.

**구조화된 출력 복구**(Structured Output Repair)는 **Key 단위**의 기능으로, 기본적으로 비활성화되어 있습니다. 활성화하면, 구조화된 JSON 출력을 선언한 **비스트리밍** 요청에 대해 모델이 반환한 JSON에 형식 오류가 있을 때 AIHubMix 게이트웨이가 반환 전에 이를 파싱 가능한 유효한 JSON으로 자동 복구합니다. 클라이언트 코드는 변경할 필요가 없습니다.

<Note>
  이 스위치는 기본적으로 비활성화되어 있으며, 활성화하지 않은 경우 모든 응답이 원본 그대로 반환됩니다. 스위치는 Key별로 독립적으로 설정되며, 활성화하면 즉시 적용됩니다.
</Note>

<Card title="Key 관리 페이지에서 설정하기" icon="key" href="https://console.aihubmix.com/token" horizontal>
  Key를 생성하거나 편집하여 「구조화된 출력 복구」(Structured Output Repair) 스위치를 켜세요.
</Card>

<Frame>
  <img src="https://mintcdn.com/aihubmix/qSKYuy2NVPUOModZ/images/api/structured-output-repair/create-key-json-repair.png?fit=max&auto=format&n=qSKYuy2NVPUOModZ&q=85&s=119802fb4114c18581c6e47c1543620a" alt="AIHubMix Key 편집 패널에서 구조화된 출력 복구 스위치 켜기" width="2886" height="1974" data-path="images/api/structured-output-repair/create-key-json-repair.png" />
</Frame>

***

## 1. 적용 조건

복구는 아래 조건이 **모두 충족**될 때에만 수행됩니다:

1. 요청에 사용된 Key가 「구조화된 출력 복구」를 활성화한 상태입니다.
2. 요청이 **비스트리밍**입니다(`stream: true`를 설정하지 않음).
3. 요청이 구조화된 JSON 출력을 선언했습니다(각 프로토콜의 선언 필드는 아래 표 참조).
4. 모델이 반환한 텍스트 내용을 JSON으로 파싱할 수 없습니다.

| 프로토콜             | 엔드포인트                                           | 구조화된 출력 선언 필드                                                                     |
| ---------------- | ----------------------------------------------- | --------------------------------------------------------------------------------- |
| Chat Completions | `/v1/chat/completions`                          | `response_format.type`이 `json_object` 또는 `json_schema`                            |
| Responses        | `/v1/responses`                                 | `text.format.type`이 `json_schema` 또는 `json_object`                                |
| Claude Messages  | `/v1/messages`                                  | `output_config.format.type`이 `json_schema`                                        |
| Gemini           | `/gemini/v1beta/models/{model}:generateContent` | `generationConfig.responseMimeType`이 `application/json`이거나, `responseSchema`가 설정됨 |

내용 자체가 유효한 JSON인 경우 아무런 변경 없이 원본 그대로 반환합니다.

***

## 2. 복구 가능한 형식 오류

**출력 잘림으로 인해 괄호 / 따옴표가 닫히지 않음**(예: `finish_reason`이 `length`):

```text 복구 전 theme={null}
{"items": [{"name": "Widget", "price": 9.99}, {"name": "Gad
```

```json 복구 후 theme={null}
{"items": [{"name": "Widget", "price": 9.99}, {"name": "Gad"}]}
```

**Markdown 코드 블록 래핑**:

````text 복구 전 theme={null}
```json
{"status": "ok", "count": 3}
```
````

```json 복구 후 theme={null}
{"status": "ok", "count": 3}
```

**후행 쉼표**:

```text 복구 전 theme={null}
{"a": 1, "b": 2,}
```

```json 복구 후 theme={null}
{"a": 1, "b": 2}
```

**작은따옴표**:

```text 복구 전 theme={null}
{'name': 'Widget'}
```

```json 복구 후 theme={null}
{"name": "Widget"}
```

**키 이름에 따옴표 없음**:

```text 복구 전 theme={null}
{name: "Widget", price: 9.99}
```

```json 복구 후 theme={null}
{"name": "Widget", "price": 9.99}
```

**텍스트와 JSON 혼재**(JSON 앞뒤에 설명 문구가 있음):

```text 복구 전 theme={null}
Here is the JSON you requested: {"name": "Widget", "price": 9.99}
```

```json 복구 후 theme={null}
{"name": "Widget", "price": 9.99}
```

복구는 보수적인 전략을 취합니다:

* 복구는 JSON 문법만 보완하거나 정규화합니다. **수치와 문자열 내용은 원문을 유지하며, 정밀도 손실이나 재작성이 발생하지 않습니다**.
* 복구 결과물은 반드시 유효한 JSON 객체 또는 배열이어야 하며, 원문과의 차이가 합리적인 범위 내에 있어야 합니다. 어느 한 조건이라도 충족되지 않으면 복구를 포기하고 원본 내용을 그대로 반환합니다.

***

## 3. 응답이 복구되었는지 판단하는 방법

복구가 발생하면 프로그래밍 방식으로 읽거나 눈으로 확인할 수 있는 두 가지 신호가 있습니다:

1. **응답 헤더** `X-JSON-Repaired: true`(복구가 발생하지 않은 경우 이 응답 헤더는 없습니다).
2. **호출 로그 비고**: [호출 기록 페이지](https://console.aihubmix.com/logs)의 해당 요청 비고 열에 `This request gateway automatically corrected the JSON format issue in the model output.`가 표시됩니다.

Token 사용량과 과금은 모델의 원본 출력 기준으로 계산되며, 복구는 과금 결과를 변경하지 않습니다.

***

## 4. 전체 예시

상품 정보 생성을 예로 들면, 요청은 `json_schema`로 구조화된 출력을 선언합니다. 스위치를 활성화하면 모델 출력에 위와 같은 형식 오류가 있더라도 받은 `content`를 바로 파싱할 수 있습니다:

<CodeGroup>
  ```python Python theme={null}
  import json
  import os
  import requests

  response = requests.post(
      "https://aihubmix.com/v1/chat/completions",
      headers={
          "Authorization": f"Bearer {os.environ['AIHUBMIX_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "model": "gpt-5.2",
          "messages": [
              {"role": "user", "content": "Generate a product listing for a wireless keyboard."}
          ],
          "response_format": {
              "type": "json_schema",
              "json_schema": {
                  "name": "product",
                  "schema": {
                      "type": "object",
                      "properties": {
                          "name": {"type": "string"},
                          "price": {"type": "number"},
                          "description": {"type": "string"},
                      },
                      "required": ["name", "price"],
                      "additionalProperties": False,
                  },
              },
          },
      },
  )

  repaired = response.headers.get("X-JSON-Repaired") == "true"
  product = json.loads(response.json()["choices"][0]["message"]["content"])
  print(product, "repaired:", repaired)
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://aihubmix.com/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.AIHUBMIX_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-5.2",
      messages: [
        { role: "user", content: "Generate a product listing for a wireless keyboard." },
      ],
      response_format: {
        type: "json_schema",
        json_schema: {
          name: "product",
          schema: {
            type: "object",
            properties: {
              name: { type: "string" },
              price: { type: "number" },
              description: { type: "string" },
            },
            required: ["name", "price"],
            additionalProperties: false,
          },
        },
      },
    }),
  });

  const repaired = response.headers.get("X-JSON-Repaired") === "true";
  const data = await response.json();
  const product = JSON.parse(data.choices[0].message.content);
  console.log(product, "repaired:", repaired);
  ```

  ```shell curl theme={null}
  curl -sD - https://aihubmix.com/v1/chat/completions \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gpt-5.2",
      "messages": [
        {"role": "user", "content": "Generate a product listing for a wireless keyboard."}
      ],
      "response_format": {
        "type": "json_schema",
        "json_schema": {
          "name": "product",
          "schema": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "price": {"type": "number"},
              "description": {"type": "string"}
            },
            "required": ["name", "price"],
            "additionalProperties": false
          }
        }
      }
    }'
  ```
</CodeGroup>

복구를 직접 관찰해 보고 싶다면 `max_tokens`를 작은 값(예: `80`)으로 설정하여 출력이 잘리도록 할 수 있습니다: 응답의 `finish_reason`은 `length`가 되고, `content`는 복구된 유효한 JSON이며, 응답 헤더에는 `X-JSON-Repaired: true`가 붙습니다.

***

## 5. 경계와 유의 사항

<Warning>
  스트리밍 요청(`stream: true`)은 복구하지 않으며, 원본 그대로 전달합니다. 복구 기능이 필요한 경우 비스트리밍 요청을 사용하세요.
</Warning>

<Warning>
  복구는 내용이 JSON으로 파싱될 수 있음을 보장하지만, 잘려서 누락된 데이터는 복원할 수 없습니다. `finish_reason` / `stop_reason`을 함께 확인하고, 출력이 잘린 경우 필요에 따라 `max_tokens`를 늘려 재시도할 것을 권장합니다.
</Warning>

* **문법 복구**: 필드명과 필드 타입이 사용자의 schema에 부합하는지는 여전히 애플리케이션 측에서 검증해야 합니다.
* **도구 호출 파라미터는 복구 범위에 포함되지 않음**: `tool_calls` / `function_call`의 파라미터 JSON은 복구하지 않습니다. 도구 파라미터는 실행 전에 항상 애플리케이션 측에서 검증해야 합니다.
* **다중 텍스트 블록 출력은 복구하지 않음**: 모델 출력에 여러 텍스트 블록이 포함된 경우(예: Gemini가 여러 `parts`를 반환) 원본 그대로 반환합니다.
* **추론 내용은 영향을 받지 않음**: `reasoning_content`, Gemini의 thought 부분 등 추론 텍스트는 복구에 관여하지 않습니다.

***

## 자주 묻는 질문 FAQ

**복구가 반환 내용의 수치나 텍스트를 변경하나요?**

아니요. 복구는 JSON 문법만 보완하거나 정규화하며(닫는 괄호 보완, 후행 쉼표 제거, 따옴표 정규화, 코드 블록 표기 제거), 수치와 문자열 내용은 모델 출력 원문을 유지합니다.

**스위치를 활성화하면 구조화된 출력을 선언하지 않은 일반 요청에도 영향이 있나요?**

아니요. `response_format` 등 구조화된 출력 필드를 선언하지 않은 요청과 모든 스트리밍 요청은 응답이 원본 그대로 반환됩니다.

**복구로 인해 추가 과금이 발생하거나 token 사용량이 변경되나요?**

아니요. Token 사용량과 과금은 모델의 원본 출력 기준으로 계산되며, 복구 과정에서 추가 비용이 발생하지 않습니다.

**복구된 JSON은 반드시 내가 정의한 schema에 부합하나요?**

복구는 내용이 JSON으로 파싱될 수 있음을 보장합니다. 필드명과 필드 타입이 schema에 부합하는지는 모델 출력 자체에 달려 있으므로, 애플리케이션 측에서 schema 검증을 계속 유지할 것을 권장합니다.
