跳到主要内容

OpenCSG AI Gateway:auto 模型使用指南

💡 说明:本文示例中的 $AIGW 代表 AI Gateway 的服务入口地址,实际调用时请替换为您的网关域名(例如 SaaS 平台对外地址或私有化部署服务 Endpoint)。

一、请求头的作用​

Header作用格式要求
CSG-Router-Session-IdRouter 会话 ID,用来保证同一会话的上下文能连贯地做排序必须是 ses_<32位hex>
CSG-Router-Turn-Id同一轮内复用已保存的排序结果,让模型固定不变必须是 turn_<32位hex>,而且必须同时带 Session
X-Session-ID① 上游亲和:按一致性哈希固定到同一个上游,复用 KV/prefix cache;② 值是 ses_ 格式时,同时当作 Router Session 的别名任意值都可用于①,只有 ses_ 格式才生效于②

关键规则:

  • 这些 ID 由 Router 生成,客户端不能自己编。网关会在响应头里返回 CSG-Router-Session-Id 和 CSG-Router-Turn-Id,客户端保存后在后续请求里带回去。
  • 格式不对的值会被静默丢弃,不会报错,Router 会当作新会话重新生成 ID。只带 Turn、不带 Session 时,Turn 也会被丢弃。
  • 网关转发给上游模型之前会删掉 CSG-Router-* 头;X-Session-ID 会保留,因为上游亲和要用。

二、正确的调用方式(以 Agent 多轮为例)​

第 1 轮,用户提问:不带任何 Router 头。

curl -i $AIGW/v1/chat/completions \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"model":"auto","messages":[{"role":"user","content":"帮我写个快排"}],"tools":[...]}'
# 响应头:
# CSG-Router-Session-Id: ses_8f3a...(32hex)
# CSG-Router-Turn-Id: turn_1c9e...(32hex)

同一轮内的工具调用循环(tool_call → tool 结果 → 再次请求):Session 和 Turn 都带上。

curl $AIGW/v1/chat/completions \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "CSG-Router-Session-Id: ses_8f3a..." \
-H "CSG-Router-Turn-Id: turn_1c9e..." \
-d '{"model":"auto","messages":[ user, assistant(tool_calls), tool(result) ],"tools":[...]}'

Router 会返回这一轮保存好的排序结果,所以模型不会在工具循环中途切换。

第 2 轮,用户发了新消息:只带 Session,不带 Turn。

curl -i $AIGW/v1/chat/completions \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "CSG-Router-Session-Id: ses_8f3a..." \
-d '{"model":"auto","messages":[ ...历史..., {"role":"user","content":"再改成非递归"}]}'
# Router 结合会话上下文重新排序,并返回一个新的 Turn-Id

Python(OpenAI SDK)示例:

from openai import OpenAI

client = OpenAI(base_url=f"{AIGW}/v1", api_key=KEY)
sid = tid = None

def call(messages, new_turn):
global sid, tid
headers = {}
if sid:
headers["CSG-Router-Session-Id"] = sid
if not new_turn and tid:
headers["CSG-Router-Turn-Id"] = tid
raw = client.chat.completions.with_raw_response.create(
model="auto", messages=messages, extra_headers=headers)
sid = raw.headers.get("CSG-Router-Session-Id") or sid
tid = raw.headers.get("CSG-Router-Turn-Id") or tid
return raw.parse()

# 用户发新消息 -> call(msgs, new_turn=True)
# 工具结果回填后继续 -> call(msgs, new_turn=False)

三、带不带 Header 的区别​

场景行为后果
完全不带每个请求都是一个新会话,独立排序单轮问答没问题。Agent 场景下,同一个工具循环里模型可能换来换去,tool_call 格式和推理风格都不连贯;每次还要多一次完整的排序,延迟更高
只带 Session(新一轮)在同一会话内重新排序,生成新 Turn每个新用户问题都应该这么发
Session + Turn(同一轮内)直接复用这一轮的排序结果,模型不变工具循环、重试时应该这么发
只带 Turn网关把 Turn 丢掉,等于不带不报错,但会悄悄失去粘性
ID 是自己编的、格式不对静默丢弃,生成新会话同上,排查起来很隐蔽
X-Session-ID: <任意值>不作为 Router Session,只用于上游亲和;同时会关闭容量感知的上游重选,只检查固定的那个上游选模型时没有粘性,但选中模型后的上游固定,cache 命中率更高
X-Session-ID: ses_xxx同时作为 Router Session 和上游亲和的 key适合已经在发 X-Session-ID 的老客户端,不用再加一个头;有 CSG-Router-Session-Id 时以它为准
Responses API 带 previous_response_id会话已经绑定到某个上游,直接复用拥有该上游的模型,不调用 Router不排序、没有降级候选、不返回 Router 头;绑定的上游不可用时直接报错

一句话总结​

model 填 auto。从响应头里拿到 Session 和 Turn 后,同一轮内两个都带,新一轮只带 Session。不要自己编 ID。

相关文档​

接入与调用模型 · 路由与调用稳定性 · 性能与成本优化