This is an automated email from the ASF dual-hosted git repository.

membphis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new df0a28425 feat(ai-proxy): include AI observability vars in llm_summary
df0a28425 is described below

commit df0a28425350541b3ac09c4403688d5f11b6ab8f
Author: Nic <[email protected]>
AuthorDate: Fri Jun 26 14:23:49 2026 +0800

    feat(ai-proxy): include AI observability vars in llm_summary
---
 apisix/plugins/ai-proxy/base.lua         |  8 +++++
 docs/en/latest/plugins/ai-proxy-multi.md | 13 ++++++-
 docs/en/latest/plugins/ai-proxy.md       | 13 ++++++-
 docs/zh/latest/plugins/ai-proxy-multi.md | 13 ++++++-
 docs/zh/latest/plugins/ai-proxy.md       | 13 ++++++-
 t/plugin/ai-proxy-kafka-log.t            | 61 ++++++++++++++++++++++++++++++++
 6 files changed, 117 insertions(+), 4 deletions(-)

diff --git a/apisix/plugins/ai-proxy/base.lua b/apisix/plugins/ai-proxy/base.lua
index cb258ff30..97c980dc5 100644
--- a/apisix/plugins/ai-proxy/base.lua
+++ b/apisix/plugins/ai-proxy/base.lua
@@ -80,6 +80,14 @@ function _M.set_logging(ctx, summaries, payloads)
             completion_tokens = ctx.var.llm_completion_tokens,
             total_tokens = ctx.var.llm_total_tokens,
             upstream_response_time = ctx.var.apisix_upstream_response_time,
+            stream = ctx.var.llm_stream,
+            tool_count = ctx.var.llm_tool_count,
+            has_tool_calls = ctx.var.llm_has_tool_calls,
+            end_user_id = ctx.var.llm_end_user_id,
+            cache_read_input_tokens = ctx.var.llm_cache_read_input_tokens,
+            cache_creation_input_tokens = 
ctx.var.llm_cache_creation_input_tokens,
+            reasoning_tokens = ctx.var.llm_reasoning_tokens,
+            content_risk_level = ctx.var.llm_content_risk_level,
         }
     end
     if payloads then
diff --git a/docs/en/latest/plugins/ai-proxy-multi.md 
b/docs/en/latest/plugins/ai-proxy-multi.md
index d95f9c26e..a91b0f43b 100644
--- a/docs/en/latest/plugins/ai-proxy-multi.md
+++ b/docs/en/latest/plugins/ai-proxy-multi.md
@@ -2605,7 +2605,18 @@ The following example demonstrates how you can log LLM 
request related informati
 * `llm_time_to_first_token`: Duration from request sending to the first token 
received from the LLM service, in milliseconds.
 * `llm_model`: LLM model.
 * `llm_prompt_tokens`: Number of tokens in the prompt.
-* `llm_completion_tokens`: Number of chat completion tokens in the prompt.
+* `llm_completion_tokens`: Number of chat completion tokens in the response.
+* `llm_total_tokens`: Total number of tokens used (prompt plus completion).
+* `llm_cache_read_input_tokens`: Number of input tokens read from cache.
+* `llm_cache_creation_input_tokens`: Number of input tokens written to cache.
+* `llm_reasoning_tokens`: Number of reasoning tokens generated.
+* `llm_stream`: Whether the request is a streaming request (`true` or `false`).
+* `llm_tool_count`: Number of tools provided in the request.
+* `llm_has_tool_calls`: `true` when the response contains tool calls.
+* `llm_end_user_id`: End user identifier extracted from the request (e.g., the 
OpenAI `user` field).
+* `llm_content_risk_level`: Content risk level reported by content moderation.
+
+When `logging.summaries` is enabled, these variables are also emitted in the 
`llm_summary` log object (using the names without the `llm_` prefix), so logger 
plugins can consume them without additional configuration.
 
 Update the access log format in your configuration file to include additional 
LLM related variables:
 
diff --git a/docs/en/latest/plugins/ai-proxy.md 
b/docs/en/latest/plugins/ai-proxy.md
index e0d78e102..17992d03f 100644
--- a/docs/en/latest/plugins/ai-proxy.md
+++ b/docs/en/latest/plugins/ai-proxy.md
@@ -2081,7 +2081,18 @@ The following example demonstrates how you can log LLM 
request related informati
 * `llm_time_to_first_token`: Duration from request sending to the first token 
received from the LLM service, in milliseconds.
 * `llm_model`: LLM model.
 * `llm_prompt_tokens`: Number of tokens in the prompt.
-* `llm_completion_tokens`: Number of chat completion tokens in the prompt.
+* `llm_completion_tokens`: Number of chat completion tokens in the response.
+* `llm_total_tokens`: Total number of tokens used (prompt plus completion).
+* `llm_cache_read_input_tokens`: Number of input tokens read from cache.
+* `llm_cache_creation_input_tokens`: Number of input tokens written to cache.
+* `llm_reasoning_tokens`: Number of reasoning tokens generated.
+* `llm_stream`: Whether the request is a streaming request (`true` or `false`).
+* `llm_tool_count`: Number of tools provided in the request.
+* `llm_has_tool_calls`: `true` when the response contains tool calls.
+* `llm_end_user_id`: End user identifier extracted from the request (e.g., the 
OpenAI `user` field).
+* `llm_content_risk_level`: Content risk level reported by content moderation.
+
+When `logging.summaries` is enabled, these variables are also emitted in the 
`llm_summary` log object (using the names without the `llm_` prefix), so logger 
plugins can consume them without additional configuration.
 
 In addition, the following standard nginx upstream variables are automatically 
populated when `ai-proxy` sends requests via cosocket transport:
 
diff --git a/docs/zh/latest/plugins/ai-proxy-multi.md 
b/docs/zh/latest/plugins/ai-proxy-multi.md
index 1a6bd5ee6..8f3ea99dc 100644
--- a/docs/zh/latest/plugins/ai-proxy-multi.md
+++ b/docs/zh/latest/plugins/ai-proxy-multi.md
@@ -2715,7 +2715,18 @@ curl "http://127.0.0.1:9080/anything"; -X POST \
 * `llm_time_to_first_token`:从发送请求到从 LLM 服务接收第一个令牌的持续时间(毫秒)。
 * `llm_model`:LLM 模型。
 * `llm_prompt_tokens`:提示中的令牌数量。
-* `llm_completion_tokens`:提示中的聊天完成令牌数量。
+* `llm_completion_tokens`:响应中的聊天完成令牌数量。
+* `llm_total_tokens`:使用的总令牌数(提示加完成)。
+* `llm_cache_read_input_tokens`:从缓存读取的输入令牌数量。
+* `llm_cache_creation_input_tokens`:写入缓存的输入令牌数量。
+* `llm_reasoning_tokens`:生成的推理令牌数量。
+* `llm_stream`:请求是否为流式请求(`true` 或 `false`)。
+* `llm_tool_count`:请求中提供的工具数量。
+* `llm_has_tool_calls`:当响应包含工具调用时为 `true`。
+* `llm_end_user_id`:从请求中提取的终端用户标识(例如 OpenAI 的 `user` 字段)。
+* `llm_content_risk_level`:内容审核报告的内容风险等级。
+
+当启用 `logging.summaries` 时,这些变量也会写入 `llm_summary` 日志对象(使用去掉 `llm_` 
前缀的名称),日志插件无需额外配置即可使用。
 
 在配置文件中更新访问日志格式以包含其他 LLM 相关变量:
 
diff --git a/docs/zh/latest/plugins/ai-proxy.md 
b/docs/zh/latest/plugins/ai-proxy.md
index 2bbe940dd..aa5d0cce9 100644
--- a/docs/zh/latest/plugins/ai-proxy.md
+++ b/docs/zh/latest/plugins/ai-proxy.md
@@ -2081,7 +2081,18 @@ curl "http://127.0.0.1:9080/anything"; -X POST \
 * `llm_time_to_first_token`:从发送请求到从 LLM 服务接收第一个令牌的持续时间(毫秒)。
 * `llm_model`:LLM 模型。
 * `llm_prompt_tokens`:提示中的令牌数量。
-* `llm_completion_tokens`:提示中的聊天完成令牌数量。
+* `llm_completion_tokens`:响应中的聊天完成令牌数量。
+* `llm_total_tokens`:使用的总令牌数(提示加完成)。
+* `llm_cache_read_input_tokens`:从缓存读取的输入令牌数量。
+* `llm_cache_creation_input_tokens`:写入缓存的输入令牌数量。
+* `llm_reasoning_tokens`:生成的推理令牌数量。
+* `llm_stream`:请求是否为流式请求(`true` 或 `false`)。
+* `llm_tool_count`:请求中提供的工具数量。
+* `llm_has_tool_calls`:当响应包含工具调用时为 `true`。
+* `llm_end_user_id`:从请求中提取的终端用户标识(例如 OpenAI 的 `user` 字段)。
+* `llm_content_risk_level`:内容审核报告的内容风险等级。
+
+当启用 `logging.summaries` 时,这些变量也会写入 `llm_summary` 日志对象(使用去掉 `llm_` 
前缀的名称),日志插件无需额外配置即可使用。
 
 在配置文件中更新访问日志格式以包含其他 LLM 相关变量:
 
diff --git a/t/plugin/ai-proxy-kafka-log.t b/t/plugin/ai-proxy-kafka-log.t
index 757bbe178..a6fddc052 100644
--- a/t/plugin/ai-proxy-kafka-log.t
+++ b/t/plugin/ai-proxy-kafka-log.t
@@ -137,6 +137,10 @@ X-AI-Fixture: openai/chat-basic.json
 send data to kafka:
 llm_request
 llm_summary
+tool_count
+cache_read_input_tokens
+cache_creation_input_tokens
+reasoning_tokens
 You are a mathematician
 gpt-35-turbo-instruct
 llm_response_text
@@ -413,3 +417,60 @@ send data to kafka:
 llm_request
 llm_summary
 some content
+
+
+
+=== TEST 9: set_logging records every observability field in llm_summary
+--- config
+    location /t {
+        content_by_lua_block {
+            local base = require("apisix.plugins.ai-proxy.base")
+            local ctx = {
+                var = {
+                    request_llm_model = "m-req",
+                    llm_model = "m",
+                    llm_time_to_first_token = 12,
+                    llm_prompt_tokens = 11,
+                    llm_completion_tokens = 22,
+                    llm_total_tokens = 33,
+                    apisix_upstream_response_time = 1.5,
+                    llm_stream = "true",
+                    llm_tool_count = 2,
+                    llm_has_tool_calls = "true",
+                    llm_end_user_id = "user-1",
+                    llm_cache_read_input_tokens = 5,
+                    llm_cache_creation_input_tokens = 6,
+                    llm_reasoning_tokens = 7,
+                    llm_content_risk_level = "low",
+                }
+            }
+            base.set_logging(ctx, true, false)
+            local s = ctx.llm_summary
+            local keys = {
+                "request_model", "model", "duration", "prompt_tokens",
+                "completion_tokens", "total_tokens", "upstream_response_time",
+                "stream", "tool_count", "has_tool_calls", "end_user_id",
+                "cache_read_input_tokens", "cache_creation_input_tokens",
+                "reasoning_tokens", "content_risk_level",
+            }
+            for _, k in ipairs(keys) do
+                ngx.say(k, "=", tostring(s[k]))
+            end
+        }
+    }
+--- response_body
+request_model=m-req
+model=m
+duration=12
+prompt_tokens=11
+completion_tokens=22
+total_tokens=33
+upstream_response_time=1.5
+stream=true
+tool_count=2
+has_tool_calls=true
+end_user_id=user-1
+cache_read_input_tokens=5
+cache_creation_input_tokens=6
+reasoning_tokens=7
+content_risk_level=low

Reply via email to