设置页AI Tab:网关设置入库、保险丝改维度与grok工具注入
CI / test (push) Successful in 33s

This commit is contained in:
2026-07-16 12:31:36 +08:00
parent 99b551401e
commit da7b29d2e3
11 changed files with 600 additions and 38 deletions
+57 -4
View File
@@ -320,10 +320,63 @@ func respToolDrop(tool map[string]any) (string, bool) {
return "", false
}
// RespStreamUpgradeLimit 是流式直通的请求体安全上限。实测(2026-07,xai 面):
// 超过 ~82KB 的流式请求上游会在推理阶段掐断流(非流式不受影响,纯体积触发,
// 与工具构成无关),预留余量取 76KB;超限时网关改走非流式上游并合成 SSE
const RespStreamUpgradeLimit = 76 * 1024
// RespGuardBytes 返回请求体中 instructions 与 tools 两字段的原始字节数之和,
// 流式保险丝据此判定。上游对二者合计 >≈64.5KB 的流式请求会在推理阶段静默断流
// (纯 EOF,input 正文不计入;2026-07-16 实测仍存在),阈值由设置页 AI Tab 配置
// 解析失败返回 0(放行,交由上游正常报错)。
func RespGuardBytes(body []byte) int {
var probe struct {
Instructions json.RawMessage `json:"instructions"`
Tools json.RawMessage `json:"tools"`
}
if err := json.Unmarshal(body, &probe); err != nil {
return 0
}
return len(probe.Instructions) + len(probe.Tools)
}
// RespInjectGrokTools 为 xai. 前缀模型默认注入服务端搜索工具:开关开启且请求
// tools 中不存在同名工具时追加 {"type":"web_search"} / {"type":"x_search"};
// 已存在(含任意参数形态)不覆盖。返回改写后 body 与注入清单(观测日志用);
// 模型不匹配、两开关全关或解析失败时原样返回。
func RespInjectGrokTools(body []byte, model string, web, x bool) ([]byte, []string) {
if !strings.HasPrefix(model, "xai.") || (!web && !x) {
return body, nil
}
dec := json.NewDecoder(strings.NewReader(string(body)))
dec.UseNumber()
var m map[string]any
if err := dec.Decode(&m); err != nil {
return body, nil
}
tools, _ := m["tools"].([]any)
missing := map[string]bool{"web_search": web, "x_search": x}
for _, t := range tools {
tool, ok := t.(map[string]any)
if !ok {
continue
}
if typ, _ := tool["type"].(string); missing[typ] {
missing[typ] = false
}
}
var injected []string
for _, typ := range []string{"web_search", "x_search"} {
if missing[typ] {
tools = append(tools, map[string]any{"type": typ})
injected = append(injected, typ)
}
}
if len(injected) == 0 {
return body, nil
}
m["tools"] = tools
out, err := json.Marshal(m)
if err != nil {
return body, nil
}
return out, injected
}
// RespDisableStream 把请求体的 stream 改为 false(流式升级回退用),其余字段
// 原样保留。