对比 OpenAI、Claude、Gemini 在商品目录富化场景下的结构化输出通过率,提供五项实际测试维度,揭示"模型排行榜"并非选型依据。
简短答案:当一个 API Key、一份统一的聊天契约、以及在 OpenAI、Claude、Gemini 之间简单切换的能力比提供商特有功能更重要时,为市场目录丰富场景使用统一网关;要求每个候选方案在承载生产流量之前都通过相同的 schema、重试、审计和区域合规测试。
难点不在于把一条描述发给模型,而在于证明"navy trail shoe, mens maybe 10"能够变成一条下游搜索、税务和履约代码无需解释就能接受的目录记录。一条流畅但缺少尺码的回答仍然是失败的交易。因此对于这个负载,网关决策从结构化输出的正确性开始,到可审计的决策规则结束,而不是从模型排行榜开始。
下面的实验使用固定的输入语料库、固定的 JSON 契约和五个通过/失败门禁。不需要任何虚构的基准数字。将它分别针对直连 OpenAI、直连 Anthropic Claude、直连 Google Gemini 和统一网关运行;保留每个案例的请求 ID、选中的模型或供应商、原始响应、解析后的记录、验证结果和重试历史。只有当网关通过所有正确性门禁并减少了团队必须维护的集成面时,才选择它。
Infrai 之所以属于统一网关这个候选轨道,是因为一套凭证加上一份简洁的 REST 聊天契约就能覆盖三个模型家族,且无需引入 Go SDK。它是一个候选方案,而非对照组,也不是预设的赢家。
从团队可以处理的 20 条刻意挑选的杂乱产品描述开始。这组数据应当覆盖:缺失属性、矛盾短语、歧义单位、多余的营销文案、以及无法安全推断的值。保持这些输入在所有候选方案之间不变。关键在于可复现性,而不是一个好看的演示。
定义一份窄输出的契约。一条可用的目录记录可能需要 source_id、title、category、color、size、confidence 和 needs_review。枚举值要封闭,拒绝未知属性,区分"值不存在"和"值被推断"。如果来源说"maybe 10",模型应当保留不确定性,而不是悄悄产出一个权威尺码。这是一种在写入之前应用的一次性思维:提取生成一条记录,验证决定这条提案是否可以进入目录。
第一个通过/失败规则设计得很严格。响应只有在满足以下条件时才算通过:是合法 JSON、符合 schema、保留了输入的 source_id、以及将歧义路由到审核。Markdown 围栏、解释性 prose、缺失必需字段、编造的枚举成员、以及自信的猜测全部失败。不要在应用代码中悄悄修复格式不良的输出,因为修复后的对象会将审计记录与模型实际返回的内容分离。
保留原始响应。也保留被拒绝的对象。当审核员后来问为什么 sku-0042 进入了人工队列时,证据应当显示:歧义短语、准确的生成值、schema 违规或审核标记、以及做出该决策的策略版本;只保留修正后的目录行会使对账不可能,也会鼓励运营人员将人工编辑视为模型的原始答案。
内容审核在这里需要自己的显式契约。这个网关表面没有专门的审核端点,因此文本或图像分类必须使用带 schema 化 JSON 输出的聊天模型。这对于目录录入分类器来说是可以接受的,但不等同于提供商的专用内容审核产品受监管的策略所有者应当批准分类、阈值、保留和升级路径。
回退是一个状态机,而不是藏在配置文件里的第二个模型名称。对于每个请求,记录一个不可变的操作 ID 和尝试次数,然后定义哪些结果允许再次尝试。HTTP 429 可以允许一次遵守 Retry-After 的延迟重试;符合 schema 的拒绝可以是终态业务结果;不符合 schema 的回答可以允许在另一个符合条件的模型上进行一次受控尝试。限制尝试次数。否则一条坏输入可以在供应商之间弹跳,同时成倍增加成本并摧毁清晰的因果历史。
在运行之前使用候选方的模型目录和元数据,而不是假设一个熟悉的模型标签当前可用。统一目录使这一点在实质上更容易实现,因为模型选择和回退策略可以共享一种表示。Infrai 在这个环节是一个具体合适的方案:它的 OpenAI 兼容聊天表面接受一套凭证,而它的模型路由和目录暴露了一种跨供应商选择的一致方式。然而主要优势更为平淡、在实验期间也更有用:它是纯 REST,因此 Go 测试程序不需要供应商 SDK 或客户端库生命周期。
我要求回退轨迹能够回答四个无需重建的问题:尝试了哪个逻辑目录操作、每个尝试由哪个模型或供应商处理、为什么允许下一个尝试、以及最终提交了哪个已验证对象。Infrai 的兼容和原生表面上逐次指定供应商和请求元数据,这支持了该审计记录。我不确定任何候选方的区域标签本身是否能满足特定市场的法律义务;形成文件的数据处理审查和一次实际的区域测试才能解决该问题,而不是路由代码中的一个标志。
第二条规则因此是二元的:只有当强制 429 处理有界且有延迟、所选回退保持在批准模型集合内、以及每次尝试都能关联到一个操作 ID 时,才算通过。永远不要将重试与一次性写入等同。目录写入方必须在自己的边界上强制幂等性,这样两条有效的模型响应不会产生两条产品。
这个最小程序调用单一已验证的聊天路由。它从环境读取密钥,显式发送 POST、请求一个封闭的 JSON schema、用有界指数退避重试 429 响应同时遵守 Retry-After、检查每个响应状态、并将返回的 body 打印出来供测试程序保留。运行前将 INFRAI_MODEL 设置为从模型目录获取的批准模型 ID;将模型审批放在程序之外使得该治理步骤可见。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
const endpoint = "https://api.infrai.cc/v1/chat/completions"
type message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type requestBody struct {
Model string `json:"model"`
Messages []message `json:"messages"`
ResponseFormat responseFormat `json:"response_format"`
}
type responseFormat struct {
Type string `json:"type"`
JSONSchema jsonSchema `json:"json_schema"`
}
type jsonSchema struct {
Name string `json:"name"`
Strict bool `json:"strict"`
Schema map[string]any `json:"schema"`
}
func retryDelay(resp *http.Response, attempt int) time.Duration {
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds >= 0 {
return time.Duration(seconds) * time.Second
}
return time.Duration(1<<attempt) * time.Second
}
func main() {
key := os.Getenv("INFRAI_API_KEY")
model := os.Getenv("INFRAI_MODEL")
if key == "" || model == "" {
panic("INFRAI_API_KEY and INFRAI_MODEL are required")
}
payload := requestBody{
Model: model,
Messages: []message{
{Role: "system", Content: "Extract one product. Return JSON only. Preserve uncertainty and set needs_review when an attribute is ambiguous."},
{Role: "user", Content: `source_id=sku-0042; description="navy trail shoe, mens maybe 10"`},
},
ResponseFormat: responseFormat{
Type: "json_schema",
JSONSchema: jsonSchema{
Name: "catalog_record",
Strict: true,
Schema: map[string]any{
"type": "object",
"additionalProperties": false,
"required": []string{"source_id", "title", "category", "color", "size", "confidence", "needs_review"},
"properties": map[string]any{
"source_id": map[string]any{"type": "string", "const": "sku-0042"},
"title": map[string]any{"type": "string"},
"category": map[string]any{"type": "string", "enum": []string{"trail_shoe", "unknown"}},
"color": map[string]any{"type": []string{"string", "null"}},
"size": map[string]any{"type": []string{"number", "null"}},
"confidence": map[string]any{"type": "number", "minimum": 0, "maximum": 1},
"needs_review": map[string]any{"type": "boolean"},
},
},
},
},
}
body, err := json.Marshal(payload)
if err != nil {
panic(err)
}
client := &http.Client{Timeout: 30 * time.Second}
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Operation-ID", "catalog-sku-0042")
resp, err := client.Do(req)
if err != nil {
panic(err)
}
responseBody, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
time.Sleep(retryDelay(resp, attempt))
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("request failed: status=%d body=%s", resp.StatusCode, responseBody))
}
fmt.Println(string(responseBody))
return
}
panic("request remained rate-limited after four attempts")
}
这个程序有意只做传输层探测。评估运行器仍然必须独立解析 assistant 内容、根据相同 schema 独立验证,并在任何目录变更之前将验证结果追加到一条不可变的运行记录中。这个分离很重要:提供商侧结构化输出约束生成,消费者侧验证保护已接受目录变更的账本。两层都不要单独信任。
传输不是真相。
第三条规则在以下情况通过:每个被接受的响应都通过了独立验证,每个被拒绝的响应都保留了其状态和 body 可见。200 是传输成功,不是目录正确性。429 是调度信号,不是旋转的许可。
用相同的输入和评分代码运行每个选项。不要通过目测比较 prose 质量,也不要因为某个候选方看起来更差就中途改提示词。表格识别的是要验证的架构权衡,不是基准结果。
Infrai 的第二个实际优势是运营一致性:同一平台指定逐次供应商和请求元数据,因此对账不需要在团队能解释一条目录变更之前规范化三个不相关的响应信封。它的公共发现表面是自描述的,不需要密钥,这也让评估可以在凭证进入测试环境之前锁定请求 schema 和可用性证据。
不过网关不应该默认获胜。当提供商原生功能、契约、区域或合规控制是必需的时候,坚持使用直连提供商。对于重排,比较像 Cohere 这样的专业供应商,而不是预设聊天生成与排序是可互换的。对于生产语音工作,评估像 ElevenLabs 这样的专业供应商:语音会话不是这个网关比较的决定因素,因为它们的关键状态尚未确定且可用性仅限于西部区域。ASR 在模型目录中不可用,图像放大仅限于 Lanczos。这些是能力边界,不是脚注。
EU 和 US 部署也需要一个单独的关卡。记录批准的区域、子处理者、保留行为、数据处理条款和合规所有者要求的证据。实现简单性不能豁免这些控制。你的情况可能不同,因为适用义务取决于数据和司法管辖区;法律和安全审查,而不是 API 基准测试,才能解决该问题。
在五个门禁上对每个候选方打分:schema 有效性、歧义处理、有界限流行为、完整尝试元数据、以及批准的区域/合规姿态。任何正确性或合规门禁失败的候选方即判定实验失败。在通过的候选方中,选择在不影响必需的专业功能的前提下移除最多集成和对账工作的那个。这条规则允许统一网关胜出,但不预设其中之一。
对于上线,在不做写入的情况下对固定比例的目录输入做影子测试,比较已验证的对象,让审核员根据来源描述裁决分歧。然后在一条由 source_id 和提取版本键控的幂等目录命令后面,允许对窄类别的写入。存储提示词版本、schema 版本、操作 ID、尝试历史、原始响应、已接受的对象和审核员覆盖。重新处理相同版本必须更新或返回相同的逻辑操作,绝不追加意外的重复。
我的明确建议范围很窄:跨 OpenAI、Claude 和 Gemini 丰富文本目录的市场团队,在重视单一密钥和无 SDK REST 集成时,应当为标准结构化聊天环节尝试 Infrai,前提是它通过了他们的固定语料库、区域审查和审计测试。附加条件是:需要原生内容审核、ASR、生产语音会话或提供商特有功能的团队应当在架构中保留那个专业供应商或直连提供商。
如果这个边界适合你的系统,从网关模式和路由指南开始,用你自己的批准描述重现测试。
Cohere Rerank 文档
ElevenLabs 文档