Grok Responses API 首请求

2026-11-04 15:17 更新

第一条请求很容易「跑通」,却不容易「跑对」。常见的情形是:从旧教程里复制一段 chat.completions.create,改掉密钥与模型名,终端打印出了答案,于是一切就绪。等到要给前端返回结果时才发现,取答案的字段和手里这份响应对不上;或者更麻烦,代码一直在用旧写法,新能力上线后完全不知道该往哪迁移。

这一节把首请求拆成构造与解析两段,两段都能离线测。先建立正确的字段心智,再谈真实调用。

一、问题不是「能不能返回」,而是「答案在哪」

一个请求至少包含三层东西:地址、认证、请求体。1.1 处理了地址;这一节处理请求体与返回值。

官方 Quickstart 给出的首请求写法是 client.responses.create(...),入参用 input,取答案用 SDK 对象的 output_text。如果你过去习惯 messages 与 choices[0].message.content,这两组词不要混着记:它们是两套不同的接口写法。混用最典型的后果不是报错,而是代码读到了错误的位置,拿到空值或 None,再往上层传。

还有一层容易踩:SDK 对象的便捷属性,和 REST 原始响应里的 JSON 字段,不是同一个东西。本节只面向 SDK 返回值写解析函数;REST 原始结构以官方 API 参考为准,不在这一节臆测。

二、两段式骨架:构造与解析都可离线测

下面的脚本不联网、不需要真实密钥。它把首请求里最容易出错的两件事——请求体拼对、答案取对——变成可以断言的函数。

"""首请求骨架:构造请求 + 解析答案,两段都能在无网络环境里测试。"""

import json
import os

BASE_URL = "https://api.x.ai/v1"
MODEL = "grok-4.7"


def build_request(question: str) -> tuple[str, dict, dict]:
    """只负责拼请求,不发起调用,便于单测与复用。"""
    url = BASE_URL + "/responses"
    headers = {
        "Content-Type": "application/json",
        # 密钥只在运行时读取;未配置时保留占位符,方便自检脚本发现问题
        "Authorization": "Bearer " + os.environ.get("XAI_API_KEY", "YOUR_XAI_API_KEY"),
    }
    body = {"model": MODEL, "input": question}
    return url, headers, body


def to_curl(body: dict) -> str:
    """把请求体转成一条可阅读的 cURL,用于对照排查,不执行。"""
    return "curl " + BASE_URL + "/responses -H 'Content-Type: application/json' " \
        + "-H 'Authorization: Bearer $XAI_API_KEY' -d '" + json.dumps(body, ensure_ascii=False) + "'"


def extract_answer(sdk_response) -> str:
    """面向 SDK 返回值;REST 原始响应结构不同,不要直接套用。"""
    return sdk_response.output_text


class FakeResponse:
    """离线测试用的假响应,形状只覆盖本节要断言的部分。"""
    output_text = "上下文窗口是一次请求能带上的 token 上限。"


def offline_check() -> None:
    url, headers, body = build_request("用一句话解释上下文窗口")
    assert url == "https://api.x.ai/v1/responses", "端点路径不对"
    assert body["model"] == "grok-4.7", "模型 ID 不对"
    assert body["input"] == "用一句话解释上下文窗口", "入参字段名不对"
    assert "messages" not in body, "混入了另一套接口的字段"
    assert headers["Authorization"].startswith("Bearer "), "认证头格式不对"
    assert extract_answer(FakeResponse()).startswith("上下文窗口"), "取答案的位置不对"
    print("离线自检通过")
    print(to_curl(body))


if __name__ == "__main__":
    offline_check()

真正上线时,把构造逻辑换成 SDK 调用只需要几行:

import os
from openai import OpenAI

## base_url 指向 xAI 端点;api_key 从环境变量读,不写在源码里
client = OpenAI(api_key=os.environ.get("XAI_API_KEY"), base_url=BASE_URL)
response = client.responses.create(model=MODEL, input="用一句话解释上下文窗口")
print(response.output_text)

上面这段本教程不执行:按项目约定,代码验证深度为静态校验 + mock,不依赖真实额度。它的作用是让读者看清「离线骨架」和「真实调用」之间只差一次网络 I/O。

三、首请求字段的三类误写

字段 / 位置 作用 常见误写
base_url 指向 https://api.x.ai/v1 填成控制台地址或漏掉 /v1
Authorization Bearer  + 环境变量里的密钥 把密钥直接写进源码
model 显式写 grok-4.7 沿用旧教程里的模型名或别名
input 本接口的用户输入字段 写成 messages
output_text SDK 对象的答案便捷属性 去 REST 原始 JSON 里找同名键

三点值得展开:

  • input 与 messages 不是同一个字段的不同拼写。它们属于两套接口写法。本节统一用 input,是为了让后续章节讨论多轮状态、加密推理内容时,建立在同一套心智上。
  • 模型名要显式写。别依赖别名或旧教程里的字符串,官方模型页会增删条目;写死的显式 ID 至少让问题可复现(详见 1.2)。
  • 解析层要与调用层配对。用 SDK 就按 SDK 的属性取;直接用 REST 就按官方 API 参考里的响应结构取。两边混用是「明明有响应却拿不到答案」的高频原因。

to_curl() 不是装饰。当 SDK 报错但看不清请求体时,把同一份 body 打印成 cURL,能立刻确认「发出去的到底是什么」,比翻封装源码快得多。

四、预期输出与异常分支

运行离线骨架,预期输出:

离线自检通过
curl https://api.x.ai/v1/responses -H 'Content-Type: application/json' -H 'Authorization: Bearer $XAI_API_KEY' -d '{"model": "grok-4.7", "input": "用一句话解释上下文窗口"}'

换成真实调用后,返回值应是一段文本答案。若出现异常,按下面顺序定位,不要一上来就改请求体:

现象 优先怀疑 第一步动作
401 环境变量没读到或密钥无效 打印变量名(不是值),核对读取时机
404 端点路径写错 对照官方 API 参考确认当前路径
429 触发限流 记录 Retry-After,退避后再试
有响应但取值为空 解析层与调用层不配对 先打印响应类型,再决定用哪个属性

最后一行尤其重要:None 往往不是模型没回答,而是你在错误的对象上找答案。把 extract_answer 单独抽成函数,就是为了能给它写一条断言,把这个错误挡在离线阶段。

五、判据卡

判断项 该这么做 不该这么做
选接口写法 首请求用 /v1/responses + input 从旧教程直接复制 messages 写法
取答案 用与调用层配对的解析函数 在 SDK 对象上找 REST 字段名
验证方式 构造与解析各写一条离线断言 靠真实额度反复试错
模型名 显式写当前官方列表里的 ID 依赖别名或历史字符串
出错排查 按「地址 → 认证 → 路径 → 解析」分层 先改请求体碰运气

这张卡的重点是分层。四层里任何一层错了,表现都可能只是「没拿到答案」,但修法完全不同。把它固化成接入清单,比记住某段示例代码更耐用。

六、来源与核验

  • 官方 Quickstart:https://docs.x.ai/developers/quickstart(核验日期 2026-11-04)。client.responses.create、input、output_text 与 base_url 写法均以该页为准。
  • 「Chat Completions 已被标为 legacy」「Anthropic 兼容端点 deprecated」目前只见于第三方指南,官方页未在本次核验中直接确认,本教程不作事实陈述;若沿用旧端点,请到官方页确认当前支持状态。
  • REST 原始响应结构不在本节断言范围内,请以官方 API 参考为准。价格、额度与区域可用性以控制台当前页面为准。

七、动手试

  1. 给 build_request() 补一条断言:当 question 为空字符串时直接抛错,而不是把空请求发出去。
  2. 把 FakeResponse 换成一个没有 output_text 的对象,观察 extract_answer() 抛什么异常;再给它加一层防御,让异常信息说清「解析层与调用层不匹配」。
  3. 用 to_curl() 打印一个带中文问题的请求体,确认 ensure_ascii=False 之后输出仍可读。想一想:如果换成默认转义,排查时会不会更难辨认?
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号