Skip to content

feat(ai-proxy): add provider-aware max_tokens override with priority control#13251

Merged
Baoyuantop merged 12 commits intoapache:masterfrom
nic-6443:nic/ai-proxy-body-override
Apr 21, 2026
Merged

feat(ai-proxy): add provider-aware max_tokens override with priority control#13251
Baoyuantop merged 12 commits intoapache:masterfrom
nic-6443:nic/ai-proxy-body-override

Conversation

@nic-6443
Copy link
Copy Markdown
Member

@nic-6443 nic-6443 commented Apr 17, 2026

Description

Add override.request_body.max_tokens to ai-proxy and ai-proxy-multi plugins. Users set a single max_tokens value and APISIX automatically maps it to the correct field name for each provider via rewrite_request_body hooks in provider capabilities.

Config example

{
  "override": {
    "request_body": { "max_tokens": 500 },
    "request_body_force_override": false
  }
}

Provider field mapping

Provider openai-chat openai-responses
openai max_completion_tokens max_output_tokens
openai-compatible max_tokens max_output_tokens
deepseek max_tokens
anthropic max_tokens
gemini max_completion_tokens
azure-openai max_tokens
openrouter max_tokens
aimlapi max_tokens
vertex-ai max_completion_tokens

Priority control

  • request_body_force_override: false (default): client request fields take priority, override only fills missing fields
  • request_body_force_override: true: override forcefully overwrites client fields

Design

Each provider capability entry has an optional rewrite_request_body(body, override, force) hook function. This is called in build_request() after protocol conversion and prepare_outgoing_request(). The hook directly mutates the request body, making it easy to extend for nested objects or future fields.

Copilot AI review requested due to automatic review settings April 17, 2026 15:06
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Apr 17, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new override.request_body configuration to ai-proxy and ai-proxy-multi to allow protocol-specific, deep-merged request body overrides after protocol conversion (and after options), enabling operators to set nested/provider-specific parameters reliably.

Changes:

  • Introduces a deep-merge helper and applies per-target-protocol request body patches in the provider request build path.
  • Extends ai-proxy schemas to validate override.request_body keys against the registered protocol set (dynamic via ai-protocols.names()).
  • Adds a dedicated test suite covering schema validation, deep-merge semantics, precedence, multi-instance behavior, and converter (client→target protocol) behavior; updates EN/ZH docs.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
apisix/plugins/ai-proxy/merge.lua Adds deep-merge helper used for request body overrides.
apisix/plugins/ai-proxy/schema.lua Adds override.request_body schema and reuses a shared override_schema.
apisix/plugins/ai-proxy/base.lua Passes override.request_body into provider build options (extra_opts).
apisix/plugins/ai-providers/base.lua Applies protocol-keyed deep-merge into outgoing request body after options.
apisix/plugins/ai-protocols/init.lua Exposes names() to enumerate registered protocol names.
t/plugin/ai-proxy-request-body-override.t Adds coverage for schema rejection, merge semantics, precedence, converter path, and backward compatibility.
docs/en/latest/plugins/ai-proxy.md Documents override.request_body for ai-proxy.
docs/en/latest/plugins/ai-proxy-multi.md Documents instances.override.request_body for ai-proxy-multi.
docs/zh/latest/plugins/ai-proxy.md Documents override.request_body for ai-proxy (ZH).
docs/zh/latest/plugins/ai-proxy-multi.md Documents instances.override.request_body for ai-proxy-multi (ZH).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apisix/plugins/ai-providers/base.lua Outdated
Comment thread apisix/plugins/ai-providers/base.lua
Comment thread apisix/plugins/ai-proxy/schema.lua Outdated
Adds override.request_body to ai-proxy and ai-proxy-multi, letting
operators set arbitrary nested fields on the outgoing request body,
keyed by target protocol.

The existing options field can only overwrite top-level fields and
is protocol-agnostic, so it cannot express protocol-specific params
like max_tokens vs max_output_tokens vs generationConfig.maxOutputTokens.

request_body is keyed by target protocol (openai-chat, openai-responses,
openai-embeddings, anthropic-messages) because converters only do
structural format conversion, not per-parameter semantic normalization.
The override is applied after converter + options, deep-merged into
the body: objects recursive, scalars/arrays replace wholesale.

Examples:

    override:
      request_body:
        openai-chat:        { max_tokens: 500 }
        openai-responses:   { max_output_tokens: 500 }
        anthropic-messages: { max_tokens: 500, stop_sequences: ['Human:'] }
@nic-6443 nic-6443 force-pushed the nic/ai-proxy-body-override branch from 6258162 to 0210be4 Compare April 18, 2026 01:17
Add override.request_body_force_override (boolean, default false) to control
whether override values or client request body fields take priority:

- false (default): client fields win, override fills missing fields only
- true: override values forcefully overwrite client fields
@nic-6443 nic-6443 changed the title feat(ai-proxy): add protocol-aware request body override feat(ai-proxy): add protocol-aware request body override with priority control Apr 18, 2026
Instead of swapping deep_merge arguments and deepcopy-ing the patch table,
pass a force boolean directly into deep_merge. This way we always iterate
over the (smaller) patch table and decide at the leaf level whether patch
or target wins, avoiding the overhead of deepcopy entirely.
moonming
moonming previously approved these changes Apr 20, 2026
Copy link
Copy Markdown
Member

@membphis membphis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this this plugin design is bad, it is not easy to control and understand

      request_body:
        openai-chat:        { max_tokens: 500, temperature: 0.2 }
        openai-responses:   { max_output_tokens: 500 }

The better one:

      request_body: { max_tokens: 500, temperature: 0.2 }

APISIX intelligently sets the corresponding fields based on the different upstream protocols.

We can include the mappings for which fields APISIX has built-in in the documentation to inform users.

(Using OpenAI's field naming conventions is recommended.)

…rovider capability hooks

Replace the per-protocol keyed request_body override design with a simpler
flat schema where users set max_tokens and APISIX automatically maps it to
the correct field name via rewrite_request_body hooks in provider capabilities.

Config changes from:
  request_body: { "openai-chat": { max_tokens: 500 } }
to:
  request_body: { max_tokens: 500 }

Each provider's capability entry now has a rewrite_request_body(body, override, force)
hook that sets the provider-native field:
- OpenAI: max_completion_tokens
- OpenAI Responses: max_output_tokens
- Gemini/Vertex-AI: max_completion_tokens
- DeepSeek/Anthropic/OpenRouter/AIMLAPI/Azure/Compatible: max_tokens

Removed:
- merge.lua (deep merge no longer needed)
- protocols.names() (no longer needed by schema)
@nic-6443 nic-6443 changed the title feat(ai-proxy): add protocol-aware request body override with priority control feat(ai-proxy): add provider-aware max_tokens override with priority control Apr 20, 2026
Rename local helper functions in providers with direct (non-factory)
implementations for consistency with the capability field name.
Comment thread apisix/plugins/ai-providers/aimlapi.lua Outdated
@nic-6443 nic-6443 force-pushed the nic/ai-proxy-body-override branch 2 times, most recently from aad6ac8 to 45e5df4 Compare April 20, 2026 07:32
@nic-6443 nic-6443 force-pushed the nic/ai-proxy-body-override branch from 45e5df4 to 963d1e9 Compare April 20, 2026 08:27
@nic-6443
Copy link
Copy Markdown
Member Author

CI failures are all unrelated to this PR:

  • t/plugin/log-rotate.t, t/plugin/openwhisk.t — log rotation and OpenWhisk tests
  • t/admin/plugins-reload.t, t/discovery/nacos2.t — admin reload and Nacos discovery
  • linux_apisix_current_luarocks_in_customed_nginx — prometheus stream subsystem (pre-existing)

The t/plugin/[a-k]*.t job (which contains our ai-proxy-request-body-override.t) is still running.

@nic-6443 nic-6443 requested a review from membphis April 20, 2026 10:09
membphis
membphis previously approved these changes Apr 20, 2026
@nic-6443 nic-6443 requested review from membphis and moonming April 20, 2026 12:06
@Baoyuantop Baoyuantop merged commit 0c0fa80 into apache:master Apr 21, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants