Repository Public
1# Citation Formatting23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45Reliable citations build trust and help readers verify the accuracy of responses. This guide provides practical guidance on how to prepare citable material and instruct the model to format citations effectively, using patterns that are familiar to OpenAI models.67## Overview89A citation system has many parts: you decide what can be cited, represent that material clearly, instruct the model how to cite it, and validate the result before it renders to the user.1011This guide covers five core elements experienced directly by the model:12131. Citable units: Define what the model is allowed to cite.142. Material representation: Present the source material in a clear, structured format.153. Citation format: Specify the exact format the model should use for citations.164. Prompt instructions: Tell the model when to cite and how to do it correctly.175. Citation parsing: Extract the citations from the model’s response for downstream use.1819## Choose citable units2021Before writing prompts, clearly define what the model can cite. Common options include:2223| Citable unit | Best used for | Downside | Example |24| ------------- | ---------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------- |25| Document | You only need to show which document the answer came from. | Not very precise. | Cite the entire employee handbook when you only need to show which document supports the claim. |26| Block / chunk | You want a good balance between simplicity and precision. | Still not exact down to the line. | Cite the specific contract paragraph or retrieved chunk that contains the clause. |27| Line range | You need to show the exact supporting text. | More difficult for the model. | Cite lines `L42-L47` when the user needs to verify the precise passage. |2829A good citable unit should be:3031- Consistent: the same source should keep the same ID across runs.32- Easy to inspect: a person should be able to read it and understand the surrounding context.33- The right size: large enough to make sense, but small enough to stay precise.3435For most systems, block-level citations are the best default. They are usually easier for the model than line-level citations and more useful to users than document-level citations.3637## Represent citable material3839The model cannot cite material that has not been presented clearly. Whether material comes from a tool or is injected directly, ensure it has:4041- Stable Source ID: Consistent identifier like `file1` or `block1`.42- Readable Text: Clearly formatted source material.43- Metadata (optional): URLs, timestamps, titles, and similar context.44454647### Example citable material48495051```text52Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}file0{CITATION_STOP}53Title: Employee Handbook54URL: https://company.example/handbook55Updated: 2026-03-015657[L1] Employees may work remotely up to three days per week.58[L2] Additional remote days require manager approval.59[L3] Exceptions may apply for approved accommodations.60```616263646566**Source IDs vs. locators:** A source ID is a stable,67 model-generated identifier such as `block1`. A locator is the68 precise UI-rendered highlight, such as `lines L8-L13` or 69 `Paragraph 21`. In general, the model should emit the source ID,70 while your system resolves or renders the locator. Mixing the two too early71 tends to increase formatting errors.7273## Define citation format7475You need to define the citation format that the model will generate. Use a76format that is explicit, consistent, and easy for the model to reproduce77reliably.7879Below is our recommended citation format and the markers we recommend. These80citation markers are highly recommended because they closely match the markers81our models are trained on. If you choose different marker values, keep the overall citation format as similar as possible.8283| Piece | What it does | Recommended |84| -------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------- |85| `CITATION_START` | Opens the citation marker. | `\ue200` |86| Citation family | Identifies the citation type. Use `cite` for all supported sources. | `cite` |87| `CITATION_DELIMITER` | Separates fields inside the marker. | `\ue202` |88| Source ID | Identifies the cited unit. `turn#` is the turn number. `item#` is the specific file, block, or URL. | `turn0file1`, `turn0block1`, `turn0url1` |89| Locator (optional) | Narrows the citation to a precise span. | `L8-L13` |90| `CITATION_STOP` | Closes the citation marker. | `\ue201` |9192For tool calls, `turnN` increments once per tool invocation, not93 once per individual result. Within a single invocation, sources are94 distinguished by suffixes such as `file0`, `file1`, and95 so on. In a single-response system, all references will be 96 `turn0...` only if the model makes exactly one tool call before97 answering. If it makes multiple tool calls, you may instead see references98 like `turn0fileX`, `turn1fileX`, and so on.99100### Template101102```text103{CITATION_START}<citation_family>{CITATION_DELIMITER}<source_id>{CITATION_DELIMITER}<locator>{CITATION_STOP}104```105106### Example107108```text109{CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_DELIMITER}L8-L13{CITATION_STOP}110```111112If your system does not use locators, omit that field:113114```text115{CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_STOP}116```117118## Write effective citation instructions119120To maintain maximum accuracy, use familiar citation patterns. Custom or unfamiliar formats increase cognitive load on the model, leading to citation errors, especially in:121122- low reasoning effort, where the model has less budget to recover from formatting mistakes.123- high-complexity tasks, where most of the reasoning budget is spent on solving the task itself rather than cleaning up citation syntax.124125Below, we recommend a citation format that is close to patterns the model is familiar with. You can use it as-is or adapt it to fit your own system.126127If you want to define your own prompt, define:128129- the exact marker syntax.130- where citations go.131- when to cite and when not to cite.132- how to cite multiple supports.133- what formats are forbidden.134- what to do when support is missing.135136137138### Recommended prompt instructions139140141142Clearly instruct the model using the following format:143144```md145## Citations146147Results 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.148149Citations are references to `tool_1` sources. Citations may be used to refer to either a single source or multiple sources.150151Citations 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}).152153Citations 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}).154155Citations 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.156157You must NOT write reference ID turn\d+\w+\d+ verbatim in the response text without putting them between {CITATION_START}...{CITATION_STOP}.158159- Place citations at the end of the paragraph, or inline if the paragraph is long, unless the user requests specific citation placement.160- Citations must be placed after punctuation.161- Citations must not be all grouped together at the end of the response.162- Citations must not be put in a line or paragraph with nothing else but the citations themselves.163```164165If you want the model to also output locators such as lines (`L1-L22`), specify it in the prompt like this:166167```text168You *must* cite any results you use from this tool using the:169`\ue200cite\ue202turn0file0\ue202L8-L13\ue201` format ONLY if the item has a corresponding citation marker.170```171172- Do not attempt to cite items without a corresponding citation marker, as they are not meant to be cited.173- You MUST include line ranges in your citations.174175176177178179180181### Optional instructions for higher-quality grounding182183184185The following rules are often worth including when you need higher-quality grounding behavior. Adapt this section based on your use case requirements.186187```xml188<extra_considerations_for_citations>189- **Relevance:** Include only search results and citations that support the cited response text. Irrelevant sources permanently degrade user trust.190- **Diversity:** You must base your answer on sources from diverse domains, and cite accordingly.191- **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.192- **Accurate Representation:** Each citation must accurately reflect the source content. Selective interpretation of the source content is not allowed.193194Remember, the quality of a domain/source depends on the context.195- When multiple viewpoints exist, cite sources covering the spectrum of opinions to ensure balance and comprehensiveness.196- When reliable sources disagree, cite at least one high-quality source for each major viewpoint.197- Ensure more than half of citations come from widely recognized authoritative outlets on the topic.198- For debated topics, cite at least one reliable source representing each major viewpoint.199- Do not ignore the content of a relevant source because it is low quality.200</extra_considerations_for_citations>201```202203204205206207## Parse citations208209Once the model emits citations, you need to extract them from the response text210so you can resolve source IDs, render links, or remove the raw markers before211showing the answer to users.212213The helper below is designed to be copied directly into your application. It214parses single-source citations, multi-source citations, and optional line-range215locators while preserving character offsets in the original text.216217This example supports line locators only and should be adapted if your system218uses a different locator format.219220221222### Post-processor examples223224225Citation parsing helpers226227```javascript228const CITATION_START = "\uE200";229const CITATION_DELIMITER = "\uE202";230const CITATION_STOP = "\uE201";231232const SOURCE_ID_RE = /^[A-Za-z0-9_-]+$/;233const LINE_LOCATOR_RE = /^L\d+(?:-L\d+)?$/;234235// Extract citations such as:236//237// {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}238// {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_DELIMITER}L8-L13{CITATION_STOP}239// {CITATION_START}cite{CITATION_DELIMITER}turn0search0{CITATION_DELIMITER}turn1news2{CITATION_STOP}240function extractCitations(text, { families = ["cite"] } = {}) {241 if (families.length === 0) {242 return [];243 }244245 const familyPattern = families246 .map((family) => family.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))247 .join("|");248249 const tokenRe = new RegExp(250 `${CITATION_START}(?<family>${familyPattern})${CITATION_DELIMITER}(?<body>[\\s\\S]*?)${CITATION_STOP}`,251 "g"252 );253254 const citations = [];255256 for (const match of text.matchAll(tokenRe)) {257 const body = match.groups?.body ?? "";258 const parts = body259 .split(CITATION_DELIMITER)260 .map((part) => part.trim())261 .filter(Boolean);262263 if (parts.length === 0) {264 continue;265 }266267 let locator = null;268 const lastPart = parts[parts.length - 1];269 if (LINE_LOCATOR_RE.test(lastPart)) {270 locator = parts.pop() ?? null;271 }272273 if (parts.length === 0 || parts.some((part) => !SOURCE_ID_RE.test(part))) {274 continue;275 }276277 citations.push({278 raw: match[0],279 family: match.groups?.family ?? "",280 source_ids: parts,281 locator,282 start: match.index ?? 0,283 end: (match.index ?? 0) + match[0].length,284 });285 }286287 return citations;288}289290function stripCitations(text, citations) {291 let cleanText = text;292 const sortedCitations = Array.from(citations).sort(293 (left, right) => right.start - left.start294 );295296 for (const citation of sortedCitations) {297 cleanText =298 cleanText.slice(0, citation.start) + cleanText.slice(citation.end);299 }300301 return cleanText;302}303```304305```python306import re307from collections.abc import Iterable308from typing import TypedDict309310CITATION_START = "\ue200"311CITATION_DELIMITER = "\ue202"312CITATION_STOP = "\ue201"313314SOURCE_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$")315LINE_LOCATOR_RE = re.compile(r"^L\d+(?:-L\d+)?$")316317318class Citation(TypedDict):319 raw: str320 family: str321 source_ids: list[str]322 locator: str | None323 start: int324 end: int325326327def extract_citations(328 text: str,329 *,330 families: tuple[str, ...] = ("cite",),331) -> list[Citation]:332 """333 Extract citations such as:334335 {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}336 {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_DELIMITER}L8-L13{CITATION_STOP}337 {CITATION_START}cite{CITATION_DELIMITER}turn0search0{CITATION_DELIMITER}turn1news2{CITATION_STOP}338 """339 if not families:340 return []341342 family_pattern = "|".join(re.escape(family) for family in families)343 token_re = re.compile(344 rf"{re.escape(CITATION_START)}"345 rf"(?P<family>{family_pattern})"346 rf"{re.escape(CITATION_DELIMITER)}"347 rf"(?P<body>.*?)"348 rf"{re.escape(CITATION_STOP)}",349 re.DOTALL,350 )351352 citations: list[Citation] = []353354 for match in token_re.finditer(text):355 parts = [part.strip() for part in match.group("body").split(CITATION_DELIMITER)]356 parts = [part for part in parts if part]357358 if not parts:359 continue360361 locator = None362 if LINE_LOCATOR_RE.fullmatch(parts[-1]):363 locator = parts.pop()364365 if not parts or any(not SOURCE_ID_RE.fullmatch(part) for part in parts):366 continue367368 citations.append(369 {370 "raw": match.group(0),371 "family": match.group("family"),372 "source_ids": parts,373 "locator": locator,374 "start": match.start(),375 "end": match.end(),376 }377 )378379 return citations380381382def strip_citations(text: str, citations: Iterable[Citation]) -> str:383 """384 Remove raw citation markers from text using offsets returned by385 extract_citations().386 """387 clean_text = text388389 for citation in sorted(citations, key=lambda item: item["start"], reverse=True):390 clean_text = clean_text[: citation["start"]] + clean_text[citation["end"] :]391392 return clean_text393```394395```ruby396CITATION_START = "\u{E200}"397CITATION_DELIMITER = "\u{E202}"398CITATION_STOP = "\u{E201}"399400SOURCE_ID_RE = /\A[A-Za-z0-9_-]+\z/401LINE_LOCATOR_RE = /\AL\d+(?:-L\d+)?\z/402403def extract_citations(text, families: ["cite"])404 return [] if families.empty?405406 family_pattern = families.map { |family| Regexp.escape(family) }.join("|")407 token_re = Regexp.new(408 "#{Regexp.escape(CITATION_START)}" \409 "(?<family>#{family_pattern})" \410 "#{Regexp.escape(CITATION_DELIMITER)}" \411 "(?<body>.*?)" \412 "#{Regexp.escape(CITATION_STOP)}",413 Regexp::MULTILINE414 )415416 text.enum_for(:scan, token_re).map do417 match = Regexp.last_match418 next unless match419420 body = match[:body]421 next unless body422423 parts = body.split(CITATION_DELIMITER).map(&:strip).reject(&:empty?)424 locator = parts.pop if parts.last&.match?(LINE_LOCATOR_RE)425 next if parts.empty? || parts.any? { |part| !part.match?(SOURCE_ID_RE) }426427 {428 raw: match[0],429 family: match[:family],430 source_ids: parts,431 locator: locator,432 start: match.begin(0),433 end: match.end(0)434 }435 end.compact436end437438def strip_citations(text, citations)439 citations.sort_by { |citation| -citation.fetch(:start) }.each_with_object(text.dup) do |citation, clean|440 clean[citation.fetch(:start)...citation.fetch(:end)] = ""441 end442end443```444445446447448449450If your source IDs use a different shape, update `SOURCE_ID_RE` to match your451system.452453## Examples454455The examples below show two common citation patterns:456457- Retrieved tool context, where your tool returns citable material and IDs.458- Injected context, where you provide citable blocks directly in the prompt.459460### Format citations for retrieved tool context461462Use this pattern when the model retrieves context through a tool and cites that retrieved context in its answer.463464#### Define citable units465466You should choose the citable units based on the precision required for your use case. The examples below show a few possible tool outputs.467468The examples below show a few recommended tool output formats. The underlying tool may vary by application, but what matters most is that the output is presented in a clear, stable structure like these examples.469470471472##### Line-level example473474475476The following is an example of the tool call output:477478```text479Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}480[L1] The service agreement states that termination for convenience requires thirty (30) days’ written notice, unless superseded by a customer-specific addendum.481[L2] In practice, renewal terms auto-extend for successive one-year periods when no written non-renewal notice is received before the deadline.482[L3] Appendix B further clarifies that pricing exceptions must be approved in writing by both Finance and the account owner.483484Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_STOP}485...486```487488Here, `turn0file0` is the stable source ID. The line numbers are the locators.489490491492493494495496##### Block-level example497498499500The following is an example of the tool call output:501502```text503Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}504[Block1]505The service agreement states that termination for convenience requires thirty (30) days’ written notice, unless superseded by a customer-specific addendum.506In practice, renewal terms auto-extend for successive one-year periods when no written non-renewal notice is received before the deadline.507Appendix B further clarifies that pricing exceptions must be approved in writing by both Finance and the account owner.508509Citation Marker: {CITATION_START}cite{CITATION_DELIMITER}turn0file1{CITATION_STOP}510[Block2]511...512```513514If you want block-level citations instead of line-level citations, the recommended option is to make each retrieved block its own stable source ID and still cite it with the same two-field cite shape, for example `{CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}`, rather than inventing a completely different citation family.515516517518519520#### Write prompt instructions521522```md523## Citations524525Results 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.526527Citations are references to `tool_1` sources. Citations may be used to refer to either a single source or multiple sources.528529A citation to a single source must be written as:530{CITATION_START}cite{CITATION_DELIMITER}turn\d+file\d+{CITATION_STOP}531532If line-level citations are supported, a citation to a specific line range must be written as:533{CITATION_START}cite{CITATION_DELIMITER}turn\d+file\d+{CITATION_DELIMITER}L\d+-L\d+{CITATION_STOP}534535Citations to multiple sources must be written by emitting multiple citation markers, one for each supporting source.536537You must NOT write reference IDs like `turn0file0` verbatim in the response text without putting them between {CITATION_START}...{CITATION_STOP}.538539- Place citations at the end of the supported sentence, or inline if the sentence is long and contains multiple supported clauses.540- Citations must be placed after punctuation.541- Cite only retrieved sources that directly support the cited text.542- Never invent source IDs, line ranges, or block locators that were not returned by the tool.543- If multiple retrieved sources materially support a proposition, cite all of them.544- If the retrieved sources disagree, cite the conflicting sources and describe the disagreement accurately.545```546547Example output:548549```text550The on-call handoff process is documented in the weekly support sync notes. \ue200cite\ue202turn0file0\ue202L8-L13\ue201551```552553### Format citations for injected context554555Use this pattern when you retrieve or prepare the context ahead of time and inject it directly into the prompt.556557#### Define citable units558559For injected context, a common pattern is to wrap source segments in explicit tags with stable reference IDs.560561```xml562563564The service agreement states that termination for convenience requires thirty (30) days’ written notice, unless superseded by a customer-specific addendum.565In practice, renewal terms auto-extend for successive one-year periods when no written non-renewal notice is received before the deadline.566Appendix B further clarifies that pricing exceptions must be approved in writing by both Finance and the account owner.567568569570571572Syllabus573574575...576```577578This makes the citable unit explicit and easy for the model to reference.579580#### Write prompt instructions581582```md583## Citations584585Supporting 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 `586587...588589`. In this example, `block5` would be the source reference ID.590591Because 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.592593Citations are references to these provided citable units. Citations may be used to refer to either a single source or multiple sources.594595A citation to a single source must be written as:596{CITATION_START}cite{CITATION_DELIMITER}<block_id>{CITATION_STOP}597598For example:599{CITATION_START}cite{CITATION_DELIMITER}block5{CITATION_STOP}600601Citations to multiple sources must be written by emitting multiple citation markers, one for each supporting block.602603You must NOT write block IDs verbatim in the response text without putting them between {CITATION_START}...{CITATION_STOP}.604605- Place citations at the end of the supported sentence, or inline if the sentence is long and contains multiple supported clauses.606- Citations must be placed after punctuation.607- Cite only blocks that appear in the provided context.608- Never invent new block IDs.609- Never cite outside knowledge or outside authorities.610- If multiple blocks materially support a proposition, cite all of them.611- If the provided blocks conflict, cite the conflicting blocks and describe the conflict accurately.612```613614Example output:615616```text617The Court held that the District Court lacked personal jurisdiction over the petitioner. \ue200cite\ue202block5\ue201618```619620**Note:** OpenAI-hosted tools such as web search provide621 automatic inline citations. If you want to use hosted tools instead, see the 622 [tools overview](https://developers.openai.com/api/docs/guides/tools), 623 [web search guide](https://developers.openai.com/api/docs/guides/tools-web-search), and 624 [file search guide](https://developers.openai.com/api/docs/guides/tools-file-search).