RAG and data · 2026-10-17
JSON output from Arabic text: Jais 3 and json_schema
Turn Arabic customer messages into JSON with Jais 3: response_format json_schema, validating the result in code and Arabic-Indic digits, with Python.
Short answer: send json_schema in response_format
LLMTR is a gateway that gives access to language models from different providers through one OpenAI-compatible API. You call Jais 3 with the id ifm/jais-3-mova-36b-a4b on the /v1/chat/completions endpoint at https://llmtr.com/v1. The row accepts json_object and json_schema in the response_format field; when you send the schema as strict, the answer arrives in the content field as JSON text that fits the schema.
IFM's model card says Jais 3 is designed for Arabic and English assistant and agentic applications. Sorting Arabic customer messages into categories, pulling an order number or a date out of a text and writing a short Arabic summary can all be done in a single request this way.
How do you get JSON output from Arabic text?
The Python example below takes an Arabic complaint and asks for a JSON object with three fields: category is one of four values, order_id is the order number in the text, and summary_ar is a one-sentence Arabic summary. The schema goes in response_format as json_schema, with strict true and additionalProperties false. The answer arrives in choices[0].message.content as JSON text; the example parses it with json.loads.
Keeping keys in English and values in Arabic keeps your code simple: field names stay fixed and the text shown to users is Arabic. Use ensure_ascii=False when you print the output; otherwise Arabic characters show up as escape sequences.
By default the model reasons before it answers. The reasoning comes back in a separate field, reasoning_content, and the content field holds only the JSON. Reasoning tokens count toward max_tokens, which is why the example gives 4,096 tokens.
An OpenAI Python SDK example that turns an Arabic customer message into a category, an order number and an Arabic summary through ifm/jais-3-mova-36b-a4b with a strict json_schema, and validates the category in code.
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://llmtr.com/v1", api_key=os.environ["LLMTR_API_KEY"])
SCHEMA = {
"type": "object",
"properties": {
"category": {"type": "string", "enum": ["shipping", "billing", "product", "other"]},
"order_id": {"type": "string"},
"summary_ar": {"type": "string"},
},
"required": ["category", "order_id", "summary_ar"],
"additionalProperties": False,
}
text = "وصلني الطلب رقم 1042 متأخراً بثلاثة أيام والعلبة كانت مفتوحة."
response = client.chat.completions.create(
model="ifm/jais-3-mova-36b-a4b",
messages=[
{"role": "system", "content": "Classify the customer message. Use an empty order_id if there is none."},
{"role": "user", "content": text},
],
response_format={
"type": "json_schema",
"json_schema": {"name": "ticket", "strict": True, "schema": SCHEMA},
},
max_tokens=4096,
)
data = json.loads(response.choices[0].message.content)
if data["category"] not in SCHEMA["properties"]["category"]["enum"]:
raise ValueError("unexpected category: " + data["category"])
print(json.dumps(data, ensure_ascii=False))
json_object or json_schema?
Both forms are open on this row. Use json_schema when you want the fields and their types fixed; json_object is enough when any valid JSON object will do. With json_object, state the fields you want in the system prompt, because no schema is sent.
| response_format | When | What the prompt says |
|---|---|---|
| json_schema (strict) | Field names, types and allowed values must be fixed | The task; the fields come from the schema |
| json_object | Any valid JSON object will do | The task and the expected fields |
| No field | A free-text answer | The answer's format, in plain words |
Validating the result and handling Arabic values
Even JSON that fits the schema can carry a value that is wrong for your job. The example compares the category with the allowed list; check fields such as the order number against your own system too. If parsing or validation fails, retry the request once, and if it fails again, send the message to a review queue.
In Arabic text, numbers may be written in Arabic-Indic digits such as ١٠٤٢, and the model may return values in those digits. If you use the number in code, normalise the digits, or ask for Western digits in the system prompt. Right-to-left writing does not affect the JSON; the values travel as UTF-8 strings.
When you process a long list of texts, send each text in its own request. Putting many texts into one request makes both the answer and the validation harder.
Batch jobs: processing the messages in a file
When you process hundreds of messages from a CSV file, send each row in its own request, one after another. The model accepts a limited number of requests in a short time; a request that hits the short-term request limit returns 429 with a Retry-After of a few seconds. Wait that long, repeat the same row and carry on from the next one.
Write each row's result to disk straight away, along with the row number. That way, if the job stops halfway, you continue from where it stopped instead of starting over. Write the rows that fail validation to a separate file and review them later.
The 429 that arrives when the daily allowance is used up has a Retry-After measured in hours. In that case stop the job and continue with the remaining rows after 00:00 (TRT).
Free period, daily allowance and the data note
The row is free until 5 November 2026, 23:59 (TRT); input and output both cost $0 per 1M tokens. Every account has an allowance of 200,000 tokens a day for this model, and new accounts start with a smaller allowance on their first day; input and output are added up, and reasoning tokens count as output. In batch jobs, add up usage.total_tokens from each response to follow the daily allowance. When the allowance is used up the API returns 429, the Retry-After header tells you when you can try again, and the allowance renews at 00:00 (TRT). From 6 November 2026, 00:00 the model returns 410 model_retired.
According to the data note on the LLMTR model page, prompts and completions may be logged by the provider and used to improve the model. If customer messages contain personal data such as names, phone numbers or addresses, mask it before sending.
Get JSON output from Arabic text
Define the schema, send it to ifm/jais-3-mova-36b-a4b with response_format json_schema and validate the result in code.
- Define the schema. Write the fields, types and allowed values as JSON Schema and add additionalProperties false.
- Request. Send the Arabic text to ifm/jais-3-mova-36b-a4b with response_format json_schema and strict true.
- Validation. Parse the content field with json.loads and compare the values with the allowed lists and your own system.
Frequently asked questions
Does Jais 3 support JSON Schema?
Yes. On LLMTR, ifm/jais-3-mova-36b-a4b accepts json_schema and json_object through response_format. Send the schema as strict and still validate the result in code.
Does the JSON answer contain the reasoning?
No. The reasoning comes back separately in reasoning_content, and the content field holds only the JSON. Reasoning tokens count toward max_tokens.
How do I handle Arabic digits?
Values may arrive in Arabic-Indic digits such as ١٠٤٢. If you use the number in code, normalise the digits, or ask for Western digits in the system prompt.