Skip to content

fix: sort AI proxy upstream request JSON keys#13461

Merged
nic-6443 merged 4 commits into
apache:masterfrom
nic-6443:nic/fix-ai-proxy-sort-json-keys
Jun 2, 2026
Merged

fix: sort AI proxy upstream request JSON keys#13461
nic-6443 merged 4 commits into
apache:masterfrom
nic-6443:nic/fix-ai-proxy-sort-json-keys

Conversation

@nic-6443

@nic-6443 nic-6443 commented Jun 1, 2026

Copy link
Copy Markdown
Member

Description

When the AI proxy (ai-transport/http.lua) forwards a request body to the upstream LLM provider, it currently serializes the body with core.json.encode, which does not guarantee a stable key order. Because many providers key their server-side prompt cache on the exact request bytes, a non-deterministic key order lowers the cache hit rate for otherwise-identical requests.

This PR encodes the upstream request body with rapidjson using sort_keys = true, producing a deterministic key order. Details:

  • Empty arrays are preserved as [] (via core.json.array_mt) and core.json.null is mapped to JSON null, so the payload is semantically unchanged — only key order becomes stable.
  • Encoding falls back to cjson on any rapidjson error and logs it, so a serialization edge case can never fail the request.
  • Adds rapidjson = 0.7.2-1 as a dependency.

A second commit makes the new dependency build portably: lua-rapidjson enables -march=native by default, which can bake the build host's CPU features into the shipped rapidjson.so and crash on older CPUs. ci/install-lua-rapidjson.sh strips that flag and is wired into the Makefile / CI runner / dev image build.

New test: t/plugin/ai-transport-http.t asserts sorted keys, empty-array preservation, and the cjson fallback path.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (falls back to cjson; payload semantics unchanged)

Note for reviewers: this introduces a new C dependency (rapidjson), built without -march=native for portable binaries. Verified locally: build succeeds with the flag stripped, and the encoder yields sorted / empty-array-preserving / null-preserving deterministic output.

🤖 Generated with Claude Code

nic-6443 and others added 2 commits June 1, 2026 16:40
Encode the AI proxy upstream request body with rapidjson using
sort_keys=true so the serialized payload has a deterministic key order,
improving provider-side LLM cache hit rate. Empty arrays are preserved
via the json array metatable, and encoding falls back to cjson on any
error.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
lua-rapidjson enables -march=native by default, which can leak the build
host's CPU features into the shipped rapidjson.so and crash on older
CPUs. Install it via a helper that strips that flag, and wire the
dependency into the Makefile/CI/dev-image build paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Copilot AI review requested due to automatic review settings June 1, 2026 08:43
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jun 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR makes AI proxy upstream JSON serialization deterministic (stable key ordering) by switching from core.json.encode to rapidjson.encode(..., { sort_keys = true }), improving upstream LLM prompt-cache hit rates. It also adds the rapidjson dependency and wiring so the C module builds portably (avoiding -march=native), plus tests covering key ordering and fallback behavior.

Changes:

  • Encode ai-transport/http.lua upstream request bodies with rapidjson sorted keys, with a cjson fallback on encoding failure.
  • Add rapidjson = 0.7.2-1 dependency and a CI/dev install script to strip -march=native from the build.
  • Add tests asserting sorted keys, empty-array/null preservation, and fallback behavior.

Reviewed changes

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

Show a summary per file
File Description
apisix/plugins/ai-transport/http.lua Switch request body encoding to rapidjson w/ sorted keys and fallback logic.
apisix-master-0.rockspec Add rapidjson dependency.
ci/install-lua-rapidjson.sh Install/patch lua-rapidjson to avoid -march=native portability issues.
ci/linux_apisix_current_luarocks_runner.sh Run the rapidjson install/patch step in CI.
Makefile Run the rapidjson install/patch step during make deps.
docker/debian-dev/Dockerfile Add cmake for building lua-rapidjson in the dev image.
t/plugin/ai-transport-http.t Add test coverage for sorted encoding, preservation semantics, and fallback.

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

Comment thread apisix/plugins/ai-transport/http.lua
Comment thread apisix/plugins/ai-transport/http.lua Outdated
Comment thread ci/install-lua-rapidjson.sh Outdated
nic-6443 and others added 2 commits June 1, 2026 16:56
rapidjson is a CMake/C++ rock, so the clean source-install environments
(ubuntu runner and the redhat/centos containers) need cmake and a C++
compiler to build it. Also add the Apache license header to the
rapidjson install helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Move the table-to-rapidjson conversion inside the pcall so a conversion
error also falls back to cjson instead of failing the request. Make the
-march=native removal fail loudly if the line is gone (so a native build
can't silently ship), use a portable sed -i, and drop the ambiguous
--local when installing into an explicit tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@nic-6443
nic-6443 merged commit 52d9d92 into apache:master Jun 2, 2026
29 checks passed
@nic-6443
nic-6443 deleted the nic/fix-ai-proxy-sort-json-keys branch June 2, 2026 04:09
wistefan pushed a commit to wistefan/apisix that referenced this pull request Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants