Skip to main content
Version: 1.4.0

Reasoning Effort Mapping

Reasoning-capable models do not always use the same effort vocabulary. A client might send medium, while a selected upstream model accepts only high or max. Configure effort_mapping on a direct model to rewrite those values at the gateway.

The mapping is disabled by default, and a request whose effort matches no entry is sent unchanged. Besides rewriting one value into another, a mapping can supply an effort for requests that set none, cover every value that has no entry of its own, and remove the effort entirely. See Reserved Entries.

How Mapping Works

AISIX reads the effort from the normalized endpoint the caller uses:

EndpointRequest field
POST /v1/chat/completionsreasoning_effort
POST /v1/responsesreasoning.effort
POST /v1/messagesoutput_config.effort
POST /v1/messages/count_tokensoutput_config.effort

After selecting the final direct model and before serializing the provider request, AISIX looks the requested effort up once: the exact, case-sensitive entry first, then the * entry. The result is never looked up again. The same behavior applies to streaming and non-streaming requests and when AISIX translates between OpenAI and Anthropic request formats.

For this mapping:

{
"medium": "high",
"high": "max"
}
  • medium becomes high. AISIX does not look up the resulting high again, so it does not become max.
  • high becomes max.
  • An unmapped value such as low remains low.
  • A request with no effort field remains unchanged. This mapping has no "" entry, so nothing is added.

The mapping belongs to the direct target, not the alias the caller addressed. When a routing model or semantic router selects a direct model, that target's mapping applies. Each ensemble panel member uses its own mapping, and the direct judge model uses its own mapping for the synthesis request. Configure no mapping on routing, semantic, ensemble, or embedding model resources; AISIX rejects it on those kinds.

Provider and model support still applies after the rewrite. Use only target values that the selected upstream model accepts. A provider adapter can translate, omit, or reject an unsupported value according to that provider's normalized endpoint behavior. Passthrough routes do not use model resources and do not apply effort mapping.

Reserved Entries

Three entries mean something other than one literal effort value:

EntryMeaning
Key "" (empty string)Matches a request that sets no effort at all — the endpoint's effort field is absent, null, or empty. The entry's value is added to the outbound request.
Key *Matches any other present value that has no entry of its own. It never matches a request that sets no effort.
Value nullRemoves the effort field from the outbound request, so the provider's own default applies.

The two keys are independent lookups: "" only ever matches an unset effort, and * only ever matches a set one. Mapping * to null therefore strips the effort from every request whose value has no entry of its own, while leaving requests that set no effort alone.

Two forms are rejected when you save the model:

  • "": null — a request that sets no effort has no field to remove.
  • An empty value for any key.

This mapping uses all three:

{
"": "low",
"medium": "high",
"xhigh": null,
"*": null
}
  • A request that sets no effort is sent with low.
  • medium is sent as high.
  • xhigh is sent with no effort field at all, so the provider's default applies.
  • Any other present value — minimal, high, anything else — also loses its effort field, because of the * entry.

Anthropic Requests That Carry thinking

On POST /v1/messages and POST /v1/messages/count_tokens, AISIX reads and rewrites only output_config.effort. A thinking block is not an effort setting for this mapping. A request that carries thinking but no output_config.effort therefore sets no effort, and the "" entry applies to it.

This is the common shape of Claude Code traffic: it sends thinking unconditionally and output_config.effort only when an effort level is configured. With a "" entry, those requests get the effort you configured instead of none.

When such a request is dispatched to a provider that does not accept the Anthropic protocol, the upstream effort comes from the mapped output_config.effort when one is present, and from thinking otherwise — except that an entry that removed the effort sends no effort at all.

A request that sets thinking.type: disabled is never given an effort by this mapping. On the Anthropic protocol no entry writes a tier to it, although an entry that removes the effort still removes it. On any other protocol it always sends the none effort.

Upgrade Compatibility

The reserved keys and null values require a gateway release that understands them. While any gateway registered in the target environment runs an older release, saving a mapping that uses "", *, or a null value fails with HTTP 422 and the error code DP_INCOMPATIBLE, and nothing is written. Upgrade those gateways, or leave the entries out until they are upgraded. See What the Control Plane Checks During the Window for how this check works.

Configure AISIX Cloud

In the Dashboard, create or edit a direct model and expand Reasoning effort mapping. Each row has a selector on both sides:

  • Requested effortSpecific value (type the caller's value), Not set (the "" entry), or Any other value (the * entry).
  • Upstream effortSpecific value (type the value to send), or Remove (use the provider default) (the null value).

At most one Not set row and one Any other value row are allowed, and a Not set row cannot use Remove. Type the caller's value into the text box only for Specific value; * typed there is rejected, because it is the Any other value rule. Remove every row and save to disable the mapping.

You can also set the mapping with the Admin API. The following request creates a direct model that supplies low when the caller sets no effort, changes medium to high, and removes the effort from every other request:

curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"kind": "direct",
"display_name": "reasoning-prod",
"model_name": "YOUR_UPSTREAM_MODEL",
"provider_key_id": "'"$PROVIDER_KEY_ID"'",
"effort_mapping": {
"": "low",
"medium": "high",
"*": null
}
}'

On update, omit effort_mapping to leave it unchanged. Send null or an empty object to clear it:

curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/models/$MODEL_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"effort_mapping": null}'

Configure the Open-Source Gateway

Add effort_mapping to a direct model in the complete resources.yaml snapshot:

resources.yaml (direct model)
models:
- display_name: reasoning-prod
provider: openai
model_name: YOUR_UPSTREAM_MODEL
provider_key: openai-prod
effort_mapping:
"": low
medium: high
xhigh: null
"*": null

Quote the "" and "*" keys in YAML so they are read as the reserved entries, and write a removal as null. Omit effort_mapping, or set it to an empty object, to disable the rewrite.

Send a Request

Call the model normally. Applications do not need provider-specific effort settings:

# AISIX_PROXY has no trailing slash or endpoint path
# The local quickstarts use http://127.0.0.1:3000
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"

curl -sS "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer $AISIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "reasoning-prod",
"messages": [{"role": "user", "content": "Solve this problem."}],
"reasoning_effort": "medium"
}'

AISIX sends high to the selected direct model for this request. Omit reasoning_effort entirely and AISIX sends low, from the "" entry.