인용 형식

인용 형식 (Citation Formatting)

믿을 수 있는 인용은 신뢰를 쌓고 독자가 응답의 정확성을 검증하는 데 도움을 줘요. 이 가이드는 OpenAI 모델에 익숙한 패턴을 사용해, 인용 가능한 자료를 준비하고 모델에게 효과적으로 인용을 형식화하도록 지시하는 실용적인 방법을 제공해요.

출처: 문서

본문

개요 (Overview)

인용 시스템은 여러 부분으로 구성돼요. 무엇을 인용할 수 있는지 정하고, 그 자료를 명확하게 표현하고, 모델에게 어떻게 인용할지 지시하고, 사용자에게 렌더링하기 전에 결과를 검증하세요.

이 가이드는 모델이 직접 경험하는 다섯 가지 핵심 요소를 다뤄요.

  1. 인용 가능 단위 (Citable units): 모델이 인용할 수 있는 것을 정의해요.
  2. 자료 표현 (Material representation): 원본 자료를 명확하고 구조화된 형식으로 제시해요.
  3. 인용 형식 (Citation format): 모델이 인용에 사용해야 하는 정확한 형식을 지정해요.
  4. 프롬프트 지침 (Prompt instructions): 모델에게 언제 인용하고 어떻게 올바르게 할지 알려줘요.
  5. 인용 파싱 (Citation parsing): 후속 사용을 위해 모델 응답에서 인용을 추출해요.

인용 가능 단위 선택하기

프롬프트를 작성하기 전에 모델이 무엇을 인용할 수 있는지 명확히 정의하세요. 일반적인 옵션은:

인용 단위 가장 좋은 용도 단점 예시
문서 (Document) 답이 어느 문서에서 왔는지만 보여주면 될 때. 그다지 정밀하지 않음. 주장을 지지하는 문서가 어느 것인지만 보여주면 될 때 전체 직원 핸드북을 인용.
블록 / 청크 (Block / chunk) 단순함과 정밀성의 좋은 균형을 원할 때. 줄 단위까지 정확하진 않음. 절이 들어 있는 특정 계약 문단이나 검색된 청크를 인용.
줄 범위 (Line range) 정확한 지지 텍스트를 보여줘야 할 때. 모델에게 더 어려움. 사용자가 정확한 구절을 검증해야 할 때 L42-L47 줄을 인용.

좋은 인용 단위는:

  • 일관적이어야 해요: 같은 출처가 실행 간에 같은 ID를 유지해야 해요.
  • 검사하기 쉬워야 해요: 사람이 읽고 주변 컨텍스트를 이해할 수 있어야 해요.
  • 크기가 알맞아야 해요: 의미가 통할 만큼 크지만, 정밀성을 유지할 만큼 작아야 해요.

대부분의 시스템에서 블록 수준 인용이 최선의 기본값이에요. 줄 수준 인용보다 모델에게 보통 더 쉽고, 문서 수준 인용보다 사용자에게 더 유용해요.

인용 가능 자료 표현하기

모델은 명확히 제시되지 않은 자료를 인용할 수 없어요. 자료가 툴에서 오든 직접 주입되든, 다음이 있어야 해요.

  • 안정적인 Source ID: file1이나 block1 같은 일관된 식별자.
  • 읽을 수 있는 텍스트: 명확하게 형식화된 원본 자료.
  • 메타데이터(선택): URL, 타임스탬프, 제목 같은 주변 정보.

인용 가능 자료 예시

Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}file0{CITATION_STOP}
Title: Employee Handbook
URL: https://company.example/handbook
Updated: 2026-03-01

[L1] Employees may work remotely up to three days per week.
[L2] Additional remote days require manager approval.
[L3] Exceptions may apply for approved accommodations.

Source ID vs. locator: Source ID는 block1 같은 안정적이고 모델 생성된 식별자예요. locator는 lines L8-L13이나 Paragraph 21 같은 UI에 렌더링되는 정확한 하이라이트예요. 일반적으로 모델은 source ID를 내보내고, 시스템이 locator를 해석하거나 렌더링해요. 둘을 너무 일찍 섞으면 형식 오류가 늘어나는 경향이 있어요.

인용 형식 정의하기

모델이 생성할 인용 형식을 정의해야 해요. 명시적이고 일관적이며 모델이 안정적으로 재현하기 쉬운 형식을 사용하세요.

아래는 우리가 권장하는 인용 형식과 마커예요. 이 인용 마커는 모델이 학습한 마커와 아주 밀접하게 일치하므로 강력히 권장해요. 다른 마커 값을 선택한다면 전체 인용 형식을 가능한 한 비슷하게 유지하세요.

조각 역할 권장값
CITATION_START 인용 마커를 연다. \ue200
인용 패밀리 인용 유형을 식별. 모든 지원 출처에 cite 사용. cite
CITATION_DELIMITER 마커 안의 필드를 구분. \ue202
Source ID 인용 단위를 식별. turn#은 턴 번호, item#은 특정 파일·블록·URL. turn0file1, turn0block1, turn0url1
Locator (선택) 인용을 정확한 구간으로 좁힘. L8-L13
CITATION_STOP 인용 마커를 닫는다. \ue201

툴 호출의 경우 turnN은 개별 결과마다가 아니라 툴 호출 한 번마다 증가해요. 한 번의 호출 안에서 출처는 file0, file1 같은 접미사로 구분돼요. 단일 응답 시스템에서는 모델이 답하기 전에 툴 호출을 정확히 한 번만 하면 모든 참조가 turn0...이 돼요. 여러 번 툴 호출을 한다면 turn0fileX, turn1fileX 같은 참조가 나타날 수 있어요.

템플릿

{CITATION_START}<citation_family>{CITATION_DELIMITER}<source_id>{CITATION_DELIMITER}<locator>{CITATION_STOP}

예시

{CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_DELIMITER}L8-L13{CITATION_STOP}

시스템이 locator를 쓰지 않는다면 그 필드를 생략해요.

{CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_STOP}

효과적인 인용 지침 작성하기

최대 정확도를 유지하려면 익숙한 인용 패턴을 사용하세요. 커스텀이나 낯선 형식은 모델의 인지 부하를 높여 인용 오류를 유발해요. 특히:

  • 낮은 reasoning effort에서는 모델이 형식 실수에서 회복할 예산이 적어요.
  • 고복잡도 작업에서는 대부분의 추론 예산을 인용 문법 정리보다 작업 해결에 써요.

아래에서 모델이 익숙한 패턴에 가까운 인용 형식을 권장해요. 그대로 쓰거나 자체 시스템에 맞게 적응할 수 있어요.

자체 프롬프트를 정의하고 싶다면 다음을 정의하세요.

  • 정확한 마커 문법.
  • 인용이 들어가는 위치.
  • 언제 인용하고 언제 하지 않을지.
  • 여러 지지를 인용하는 방법.
  • 금지된 형식.
  • 지지 자료가 없을 때 할 일.

권장 프롬프트 지침

다음 형식으로 모델에 명확히 지시하세요.

## Citations

Results are returned by "tool_1". Each message from `tool_1` is called a "source" and identified by its reference ID, which is the first occurrence of 【turn\d+\w+\d+】 (e.g. 【turn2file1】). In this example, the string "turn2file1" would be the source reference ID.

Citations are references to `tool_1` sources. Citations may be used to refer to either a single source or multiple sources.

Citations to a single source must be written as {CITATION_START}cite{CITATION_DELIMITER}turn\d+\w+\d+{CITATION_STOP} (e.g. {CITATION_START}cite{CITATION_DELIMITER}turn2file5{CITATION_STOP}).

Citations to multiple sources must be written as {CITATION_START}cite{CITATION_DELIMITER}turn\d+\w+\d+{CITATION_DELIMITER}turn\d+\w+\d+{CITATION_DELIMITER}...{CITATION_STOP} (e.g. {CITATION_START}cite{CITATION_DELIMITER}turn2file5{CITATION_DELIMITER}turn2file1{CITATION_DELIMITER}...{CITATION_STOP}).

Citations must not be placed inside markdown bold, italics, or code fences, as they will not display correctly. Instead, place the citations outside the markdown block. Citations outside code fences may not be placed on the same line as the end of the code fence.

You must NOT write reference ID turn\d+\w+\d+ verbatim in the response text without putting them between {CITATION_START}...{CITATION_STOP}.

- Place citations at the end of the paragraph, or inline if the paragraph is long, unless the user requests specific citation placement.
- Citations must be placed after punctuation.
- Citations must not be all grouped together at the end of the response.
- Citations must not be put in a line or paragraph with nothing else but the citations themselves.

모델이 L1-L22 같은 줄 locator도 출력하게 하려면 프롬프트에 이렇게 지정하세요.

You *must* cite any results you use from this tool using the:
`\ue200cite\ue202turn0file0\ue202L8-L13\ue201` format ONLY if the item has a corresponding citation marker.
  • 해당 인용 마커가 없는 항목은 인용하지 마세요. 인용되도록 의도된 게 아니에요.
  • 인용에는 줄 범위를 반드시 포함해야 해요.

더 높은 품질의 접지를 위한 선택적 지침

높은 품질의 접지(grounding) 동작이 필요할 때 다음 규칙을 포함할 가치가 있어요. 사용 사례 요구 사항에 맞게 이 섹션을 적응하세요.

<extra_considerations_for_citations>
- **Relevance:** Include only search results and citations that support the cited response text. Irrelevant sources permanently degrade user trust.
- **Diversity:** You must base your answer on sources from diverse domains, and cite accordingly.
- **Trustworthiness:** To produce a credible response, you must rely on high quality domains, and ignore information from less reputable domains unless they are the only source.
- **Accurate Representation:** Each citation must accurately reflect the source content. Selective interpretation of the source content is not allowed.

Remember, the quality of a domain/source depends on the context.
- When multiple viewpoints exist, cite sources covering the spectrum of opinions to ensure balance and comprehensiveness.
- When reliable sources disagree, cite at least one high-quality source for each major viewpoint.
- Ensure more than half of citations come from widely recognized authoritative outlets on the topic.
- For debated topics, cite at least one reliable source representing each major viewpoint.
- Do not ignore the content of a relevant source because it is low quality.
</extra_considerations_for_citations>

인용 파싱하기

모델이 인용을 내보내면 응답 텍스트에서 추출해서 source ID를 해석하거나, 링크를 렌더링하거나, 답을 사용자에게 보여주기 전에 원시 마커를 제거해야 해요.

아래 헬퍼는 애플리케이션에 그대로 복사해 쓰도록 설계됐어요. 단일 출처 인용, 다중 출처 인용, 선택적 줄 범위 locator를 파싱하면서 원본 텍스트의 문자 오프셋을 보존해요.

이 예시는 줄 locator만 지원하며, 시스템이 다른 locator 형식을 쓰면 적응해야 해요.

후처리기 예시

import re
from collections.abc import Iterable
from typing import TypedDict

CITATION_START = "\ue200"
CITATION_DELIMITER = "\ue202"
CITATION_STOP = "\ue201"

SOURCE_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$")
LINE_LOCATOR_RE = re.compile(r"^L\d+(?:-L\d+)?$")


class Citation(TypedDict):
    raw: str
    family: str
    source_ids: list[str]
    locator: str | None
    start: int
    end: int


def extract_citations(
    text: str,
    *,
    families: tuple[str, ...] = ("cite",),
) -> list[Citation]:
    """
    Extract citations such as:

      {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}
      {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_DELIMITER}L8-L13{CITATION_STOP}
      {CITATION_START}cite{CITATION_DELIMITER}turn0search0{CITATION_DELIMITER}turn1news2{CITATION_STOP}
    """
    if not families:
        return []

    family_pattern = "|".join(re.escape(family) for family in families)
    token_re = re.compile(
        rf"{re.escape(CITATION_START)}"
        rf"(?P<family>{family_pattern})"
        rf"{re.escape(CITATION_DELIMITER)}"
        rf"(?P<body>.*?)"
        rf"{re.escape(CITATION_STOP)}",
        re.DOTALL,
    )

    citations: list[Citation] = []

    for match in token_re.finditer(text):
        parts = [part.strip() for part in match.group("body").split(CITATION_DELIMITER)]
        parts = [part for part in parts if part]

        if not parts:
            continue

        locator = None
        if LINE_LOCATOR_RE.fullmatch(parts[-1]):
            locator = parts.pop()

        if not parts or any(not SOURCE_ID_RE.fullmatch(part) for part in parts):
            continue

        citations.append(
            {
                "raw": match.group(0),
                "family": match.group("family"),
                "source_ids": parts,
                "locator": locator,
                "start": match.start(),
                "end": match.end(),
            }
        )

    return citations


def strip_citations(text: str, citations: Iterable[Citation]) -> str:
    """
    Remove raw citation markers from text using offsets returned by
    extract_citations().
    """
    clean_text = text

    for citation in sorted(citations, key=lambda item: item["start"], reverse=True):
        clean_text = clean_text[: citation["start"]] + clean_text[citation["end"] :]

    return clean_text

JavaScript(extractCitations/stripCitations)와 Ruby(extract_citations/strip_citations)에도 같은 로직의 헬퍼가 있어요. 둘 다 CITATION_START/DELIMITER/STOP 상수와 SOURCE_ID_RE, LINE_LOCATOR_RE 정규식을 쓰고, 추출된 인용의 원시 텍스트·패밀리·source_ids·locator·start·end 오프셋을 반환해요.

source ID가 다른 모양을 쓴다면 SOURCE_ID_RE를 시스템에 맞게 업데이트하세요.

예시

아래 예시는 두 가지 일반적인 인용 패턴을 보여줘요.

  • 검색된 툴 컨텍스트: 툴이 인용 가능한 자료와 ID를 반환하는 경우.
  • 주입된 컨텍스트: 프롬프트에 인용 가능한 블록을 직접 제공하는 경우.

검색된 툴 컨텍스트의 인용 형식

모델이 툴을 통해 컨텍스트를 검색하고 답에서 그 검색된 컨텍스트를 인용할 때 이 패턴을 사용해요.

인용 가능 단위 정의하기

사용 사례에 필요한 정밀도에 기반해 인용 단위를 선택하세요. 아래 예시는 몇 가지 가능한 툴 출력을 보여줘요. 근본 툴은 애플리케이션마다 다를 수 있지만, 가장 중요한 것은 출력이 이런 예시처럼 명확하고 안정적인 구조로 제시되는 거예요.

줄 수준 예시

툴 호출 출력의 예시:

Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}
[L1] The service agreement states that termination for convenience requires thirty (30) days’ written notice, unless superseded by a customer-specific addendum.
[L2] In practice, renewal terms auto-extend for successive one-year periods when no written non-renewal notice is received before the deadline.
[L3] Appendix B further clarifies that pricing exceptions must be approved in writing by both Finance and the account owner.

Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_STOP}
...

여기서 turn0file0은 안정적인 source ID이고, 줄 번호가 locator예요.

블록 수준 예시

블록 수준 인용을 원한다면 각 검색 블록을 자체 안정적인 source ID로 만들고, 완전히 다른 인용 패밀리를 발명하는 대신 같은 2필드 cite 모양(예: {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP})으로 여전히 인용하는 것을 권장해요.

프롬프트 지침 작성하기

## Citations

Results are returned by "tool_1". Each message from `tool_1` is called a "source" and identified by its reference ID, which is the first occurrence of `turn\d+file\d+` (for example, `turn0file0` or `turn2file1`). In this example, the string `turn0file0` would be the source reference ID.

Citations are references to `tool_1` sources. Citations may be used to refer to either a single source or multiple sources.

A citation to a single source must be written as:
{CITATION_START}cite{CITATION_DELIMITER}turn\d+file\d+{CITATION_STOP}

If line-level citations are supported, a citation to a specific line range must be written as:
{CITATION_START}cite{CITATION_DELIMITER}turn\d+file\d+{CITATION_DELIMITER}L\d+-L\d+{CITATION_STOP}

Citations to multiple sources must be written by emitting multiple citation markers, one for each supporting source.

You must NOT write reference IDs like `turn0file0` verbatim in the response text without putting them between {CITATION_START}...{CITATION_STOP}.

- Place citations at the end of the supported sentence, or inline if the sentence is long and contains multiple supported clauses.
- Citations must be placed after punctuation.
- Cite only retrieved sources that directly support the cited text.
- Never invent source IDs, line ranges, or block locators that were not returned by the tool.
- If multiple retrieved sources materially support a proposition, cite all of them.
- If the retrieved sources disagree, cite the conflicting sources and describe the disagreement accurately.

출력 예시:

The on-call handoff process is documented in the weekly support sync notes. \ue200cite\ue202turn0file0\ue202L8-L13\ue201

주입된 컨텍스트의 인용 형식

컨텍스트를 미리 검색하거나 준비해서 프롬프트에 직접 주입할 때 이 패턴을 사용해요.

인용 가능 단위 정의하기

주입된 컨텍스트의 일반적인 패턴은 출처 세그먼트를 안정적인 참조 ID가 있는 명시적 태그로 감싸는 거예요.


The service agreement states that termination for convenience requires thirty (30) days’ written notice, unless superseded by a customer-specific addendum.
In practice, renewal terms auto-extend for successive one-year periods when no written non-renewal notice is received before the deadline.
Appendix B further clarifies that pricing exceptions must be approved in writing by both Finance and the account owner.

...

이렇게 하면 인용 단위가 명시적이고 모델이 참조하기 쉬워져요.

프롬프트 지침 작성하기

## Citations

Supporting context is provided directly in the prompt as citable units. Each citable unit is identified by the value of its `id` attribute in the first occurrence of a tag such as `<citable_unit id="...">...`. In this example, `block5` would be the source reference ID.

Because this pattern does not invoke tools, there is no tool turn counter to increment. That means you do not need to use a `turn#` prefix for the citation marker. You can keep IDs in a `turn0block5` style if that matches the rest of your system, or use plain IDs like `block5` as shown here. The key requirement is that the citation marker matches the injected context ID exactly and consistently.

Citations are references to these provided citable units. Citations may be used to refer to either a single source or multiple sources.

A citation to a single source must be written as:
{CITATION_START}cite{CITATION_DELIMITER}<block_id>{CITATION_STOP}

For example:
{CITATION_START}cite{CITATION_DELIMITER}block5{CITATION_STOP}

Citations to multiple sources must be written by emitting multiple citation markers, one for each supporting block.

You must NOT write block IDs verbatim in the response text without putting them between {CITATION_START}...{CITATION_STOP}.

- Place citations at the end of the supported sentence, or inline if the sentence is long and contains multiple supported clauses.
- Citations must be placed after punctuation.
- Cite only blocks that appear in the provided context.
- Never invent new block IDs.
- Never cite outside knowledge or outside authorities.
- If multiple blocks materially support a proposition, cite all of them.
- If the provided blocks conflict, cite the conflicting blocks and describe the conflict accurately.

출력 예시:

The Court held that the District Court lacked personal jurisdiction over the petitioner. \ue200cite\ue202block5\ue201

참고: 웹 검색 같은 OpenAI 호스팅 툴은 자동 인라인 인용을 제공해요. 호스팅 툴을 쓰고 싶다면 tools 개요, 웹 검색 가이드, 파일 검색 가이드를 참고하세요.

더 알아보기 (Learn more)