RAG and data · 2026-10-22

Long-document extraction with Atria-Dawn and JSON Schema

Send a long document to Atria-Dawn's 524,288-token context in one request and extract fields with json_schema: the steps, token math and validation.

Diagram: one box under https://llmtr.com/v1, internlm/atria-dawn-free.

Short answer: put the document in one message, ask for json_schema, turn reasoning off

LLMTR is a gateway that gives access to language models from different providers through one OpenAI-compatible API. Shanghai AI Lab's Atria-Dawn (internlm/atria-dawn-free) is called on the /v1/chat/completions endpoint at https://llmtr.com/v1, offers a 524,288-token context window and is free until 31 October 2026, 23:59 (TRT). Put a long document in the user message and send a schema in response_format with "type": "json_schema" and "strict": true, and the answer arrives in the content field as a JSON object following that schema; for extraction, turn reasoning off with :fast or "reasoning": false. Atria-Dawn Preview (internlm/atria-dawn-preview-free) accepts the same settings. Agents-A1 (internlm/agents-a1-free) and Sage-A1.5 (internlm/sage-a1.5-free) support json_schema but have a 262,144-token context; Intern-S2 (internlm/intern-s2-free) has no response_format. From 1 November 2026, use Agnes 2.5 Flash (agnes/agnes-2.5-flash), Nemotron 3 Ultra (nvidia/nemotron-3-ultra-550b-a55b) or the paid DeepSeek V4.1 Flash (deepseek/deepseek-flash).

According to the row's data notice, requests are processed through a third-party provider; prompts and completions may be logged by the provider and used to improve the model. So do not send customer contracts, personal data or confidential documents. A public technical specification, a template contract or meeting minutes without personal data are suitable examples.

How do you extract data from a long document with JSON Schema using a 524,288-token context?

Three steps are enough: put the whole document in a single user message, send the fields you want as a JSON Schema with strict: true inside response_format, and parse the answer's content field with json.loads and validate it against the schema. List every field under required and use additionalProperties: false; for a value the document may not contain, ask for an empty string ("") in the system message, so your code can tell a missing value apart.

Keep the system instruction short and name the fields. Put all fields in one schema and send one request per document; no cache discount is listed on these rows, so a document sent again counts as full input every time.

The table compares the five Shanghai AI Lab rows for this job.

Shanghai AI Lab rows for long-document extraction, LLMTR catalog, as of 22 October 2026
ModelContextJSON (response_format)Image inputFor this job
Atria-Dawn524,288 tokensjson_object and json_schemano, a request with an image returns 400fits; stable release
Atria-Dawn Preview524,288 tokensjson_object and json_schemano, a request with an image returns 400fits; MIT-licensed open preview
Agents-A1262,144 tokensjson_object and json_schemayesif the document fits in 262,144 tokens or has page images
Sage-A1.5262,144 tokensjson_object and json_schemayessame as Agents-A1
Intern-S2262,144 tokensnone; ask for JSON in the promptyesdoes not fit when output must follow a schema

How much of the daily allowance does one request use?

Input, output and reasoning share the same 524,288-token window, and all three come out of the daily allowance. The allowance is 500,000 tokens a day for each account and for each model, reasoning included; new accounts start with a smaller allowance on their first day. Because the window is larger than the allowance, one request's prompt and answer cannot exceed what is left for the day: a prompt larger than that returns 429 rate_limit_error, and the error tells you to send a shorter request.

For example, take a 450,000-token specification, 2,000 tokens of instructions and schema, and a 3,000-token JSON answer, with reasoning off: the request costs 450,000 + 2,000 + 3,000 = 455,000 tokens, that is 91% of the daily allowance of 500,000 tokens in one request; new accounts start with a smaller allowance on their first day, and on that day this request may not fit at all. The 45,000 tokens left that day cannot carry the same document again; a second request has to wait until the allowance renews at 00:00 (TRT).

Reasoning tokens are added to the same count, so turning reasoning off for extraction frees room in both the allowance and the window. If you do not know your document's token count, send a part first and estimate the whole from usage.prompt_tokens.

Python example: text from a file, fields with json_schema

The example below reads a text file, sends the document to Atria-Dawn in one message and asks for six fields of a specification with strict json_schema. Reasoning is turned off with extra_body={"reasoning": False}; appending :fast to the model id gives the same result. The example checks finish_reason first: "length" means the answer was cut off and the JSON is incomplete. It then parses with json.loads, checks that all six fields exist with the right type, and stops with the names of any missing or mistyped fields.

OpenAI Python SDK example that reads a text file, sends it to Atria-Dawn through https://llmtr.com/v1/chat/completions with strict json_schema and reasoning off, then parses and validates the answer with json.loads.

import json
import os
from pathlib import Path

from openai import OpenAI

client = OpenAI(base_url="https://llmtr.com/v1", api_key=os.environ["LLMTR_API_KEY"])

# A public specification or a template contract; no customer or personal data.
document = Path("specification.txt").read_text(encoding="utf-8")

EXPECTED_TYPES = {
    "title": str,
    "issuer": str,
    "effective_date": str,
    "deliverables": list,
    "delivery_deadline": str,
    "penalty_clause": str,
}
SCHEMA = {
    "type": "object",
    "properties": {
        "title": {"type": "string"},
        "issuer": {"type": "string"},
        "effective_date": {"type": "string", "description": "YYYY-MM-DD"},
        "deliverables": {"type": "array", "items": {"type": "string"}},
        "delivery_deadline": {"type": "string", "description": "YYYY-MM-DD"},
        "penalty_clause": {"type": "string"},
    },
    "required": list(EXPECTED_TYPES),
    "additionalProperties": False,
}

response = client.chat.completions.create(
    model="internlm/atria-dawn-free",
    messages=[
        {"role": "system", "content": "Extract the fields from the document. Use an empty string when a value is not stated."},
        {"role": "user", "content": document},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {"name": "specification_fields", "strict": True, "schema": SCHEMA},
    },
    extra_body={"reasoning": False},  # or call "internlm/atria-dawn-free:fast"
    max_tokens=8192,
)

choice = response.choices[0]
print("prompt_tokens:", response.usage.prompt_tokens, "completion_tokens:", response.usage.completion_tokens)
if choice.finish_reason == "length":
    raise SystemExit("The answer was cut off: raise max_tokens or send a shorter document.")

data = json.loads(choice.message.content)
missing = [key for key in EXPECTED_TYPES if key not in data]
wrong = [key for key, kind in EXPECTED_TYPES.items() if key in data and not isinstance(data[key], kind)]
if missing or wrong:
    # A retry sends the whole document again and counts toward the daily allowance again.
    raise SystemExit(f"Schema mismatch: missing={missing} wrong_type={wrong}")

print(json.dumps(data, indent=2, ensure_ascii=False))

What to do on a schema mismatch

If json.loads fails or a required field is missing, look at finish_reason first. "length" means the answer was cut off at max_tokens or at the remaining allowance; raise the limit, turn reasoning off or send a shorter part of the document. If finish_reason is "stop" but the answer does not follow the schema, repeat the request once; if it still does not match, simplify the schema, for example with fewer nested objects. Every retry sends the whole document again and counts toward the daily allowance again.

If the document does not fit in one request, split it, send each part with the same schema and merge the results in your own code; each part counts toward the allowance with its own prompt tokens.

Which one when?

The choice depends on the size of the document, whether it contains images and how sensitive the data is; compare output quality with your own documents.

  • The document is over 262,144 tokens and text only: Atria-Dawn; to try the open-weight release, Atria-Dawn Preview.
  • The document fits in 262,144 tokens and also has page images: Agents-A1 or Sage-A1.5; both accept json_schema and images.
  • Output does not have to follow a schema and a scientific table is read from an image: Intern-S2; ask for JSON in the prompt and do not send response_format.
  • A document with sensitive, personal or customer data: use none of these rows; the data notice says prompts may be logged and used to improve the model.

Long-document extraction after 1 November 2026

After 31 October 2026, 23:59 (TRT), that is from 1 November 2026, 00:00, Atria-Dawn returns 410 model_retired and requests are not redirected to another model; you have to change the model id. To keep going at no cost, Agnes 2.5 Flash (agnes/agnes-2.5-flash) offers the same 524,288-token context and json_schema; its quota counts requests, not tokens, and a single response can be at most 65,536 tokens. Nemotron 3 Ultra (nvidia/nemotron-3-ultra-550b-a55b) offers a 1,000,000-token context and JSON mode (json_object) and runs on a daily quota; its card lists no json_schema. The data notice of Nemotron 3 Ultra also says prompts may be logged and used to improve the model.

On the paid side, DeepSeek V4.1 Flash (deepseek/deepseek-flash) offers a 1,000,000-token context and JSON mode, but it does not support json_schema: send only json_object in response_format, describe the schema in the system message and validate the answer in your own code. Its price per 1M tokens outside peak hours is $0.15 input and $0.60 output, with a lower rate for cached input; on weekday peak hours, Chinese public holidays excepted, every item costs double. For example, 450,000 input tokens and 3,000 output tokens cost $0.0693 outside peak hours ($0.0675 input + $0.0018 output) and $0.1386 at peak.

Extracting fields from a long document with Atria-Dawn and JSON Schema

Write the fields as a JSON Schema, send the document to Atria-Dawn in one request and validate the answer.

  1. Schema. Write the fields you will extract as a JSON Schema with strict: true, additionalProperties: false and a complete required list.
  2. Request. Send the document in a single user message, with reasoning off and response_format, to the https://llmtr.com/v1/chat/completions endpoint.
  3. Validation. Check finish_reason, parse the content field with json.loads and check the required fields.

Frequently asked questions

Can I use JSON Schema with Intern-S2?

No. Intern-S2 does not support response_format; ask for JSON in the prompt and validate the answer yourself. For output that must follow a schema, use Atria-Dawn, Atria-Dawn Preview, Agents-A1 or Sage-A1.5.

Can I send a 524,288-token document in one request?

The window is 524,288 tokens, but the prompt and the answer combined cannot exceed what is left of the day's allowance. The allowance is 500,000 tokens a day per model and new accounts start with a smaller allowance on their first day; the document you can send in one request is what is left after the room for the answer.

What should I do if the answer comes back with finish_reason: "length"?

The answer was cut off at max_tokens or at the remaining allowance, and the JSON is incomplete. Raise max_tokens, turn reasoning off with :fast or "reasoning": false, or send the document in parts.

Related posts