HiAPI
博客

教程

如何通过 HiAPI API 使用 grok-4.7:curl、Python 与一次可用的请求

从首次请求到验证响应的实操指南

2026年11月3日
HiAPI 博客教程封面图:多层半透明玻璃平面在浅色背景上折射出克制的冷蓝色带。

首次请求前你需要准备什么

在向 API 发送任何内容之前,请确保四件事已就绪。跳过其中任何一项,是首次调用失败的最常见原因,而失败原因往往与模型本身毫无关系。

一个 HiAPI 账户

你需要一个有效的 HiAPI.ai 账户。登录仪表盘以管理项目、密钥和用量。本教程中的所有操作都通过同一个统一 API 界面完成,因此你在此处创建的密钥可在平台提供的各个模型间通用。

一个 API 密钥

在仪表盘中创建 API 密钥,并将其存放在安全之处——测试时可用 shell 环境变量,任何将投入生产运行的东西则用密钥管理器。切勿将密钥提交到代码仓库,也不要粘贴到客户端应用中。

对于本地测试,每个 shell 会话导出一次即可:

export HIAPI_API_KEY="your-api-key-here"

基础 URL

基础 URL 是 HiAPI API 的根地址。本教程中的所有请求都相对于它。请查阅你的仪表盘,确认你的账户应使用的确切基础 URL,并将其存入变量,以便脚本和应用代码引用同一个值:

export HIAPI_BASE_URL="https://api.hiapi.ai"

模型标识符

本教程使用的模型标识符是 grok-4.7。它以纯字符串形式在请求体中传递。如果标识符有误,你通常会收到明确的错误返回,而不是静默回退,因此拼写错误很容易被发现。

一旦这四项——账户、密钥、基础 URL、模型 ID——齐备,请求形态所需的一切就都有了。curl 方式无需安装任何 SDK,Python 方式也只需要你大概率已具备的 HTTP 客户端。

快速环境检查

确认密钥和基础 URL 对你即将使用的 shell 可见:

[ -n "$HIAPI_API_KEY" ] && echo "key set"
[ -n "$HIAPI_BASE_URL" ] && echo "base url set"

如果两行都打印出来,你就可以进入下一节了。

HiAPI 上 grok-4.7 请求的形态

本教程中的每个请求都共享同样的四个要素:端点、认证头、模型字段和 messages 数组。分别理解它们,会让之后理解流式传输和工具调用容易得多,因为这些功能只改变此形态的一部分。

端点

该调用是向基础 URL 下的聊天补全端点发送 POST 请求。本教程中我们将其表示为:

POST {HIAPI_BASE_URL}/v1/chat/completions

如果你的仪表盘显示的路径不同,请使用仪表盘中的路径;无论哪种方式,请求体都相同。

认证头

认证方式是 Authorization 头中的 bearer token:

Authorization: Bearer $HIAPI_API_KEY

由于它是请求头而非查询参数,密钥永远不会出现在 URL、访问日志或浏览器历史中。

内容类型

请求体是 JSON,因此发送 Content-Type: application/json。curl 和任何 Python HTTP 客户端都能为你设置它,但明确写出这一点是值得的,这样请求头集合就没有歧义。

请求体:model 与 messages

请求体是一个至少包含两个字段的 JSON 对象:

  • model — 模型标识符字符串,此处为 grok-4.7。
  • messages — 有序的消息对象数组。每个对象有 role 和 content。常用角色有:system 用于框定对话的指令,user 用于请求本身,assistant 用于你在延续对话时提供先前的模型轮次。

最小请求体如下所示:

{
  "model": "grok-4.7",
  "messages": [
    { "role": "system", "content": "You are a concise technical assistant." },
    { "role": "user", "content": "Explain what an idempotent HTTP method is in two sentences." }
  ]
}

这就是基本调用的全部约定。其他任何内容——流式传输、工具定义——都是同一个对象上的附加字段,这正是前面几节重要的原因:一旦此形态正确,其余都是附加的。

响应长什么样

响应是一个 JSON 对象。你几乎总是想要的部分在 choices 下,它是一个数组;每个条目有一个包含 role 和 content 的 message。此外还有元数据,例如处理请求的模型以及描述 token 数量的 usage 块。读取 choices[0].message.content,你就得到了答案文本。其他字段对日志记录和成本跟踪有用,但入门并不需要它们。

一个可用的 curl 请求

密钥已导出、请求形态已理解之后,curl 调用就很简短。当你想把问题从应用代码中隔离出来时,这就是该复制的版本。

curl -sS "$HIAPI_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-4.7",
    "messages": [
      { "role": "system", "content": "You are a concise technical assistant." },
      { "role": "user", "content": "In one sentence, what is a bearer token?" }
    ]
  }'

每个标志的作用

  • -sS 保持输出安静,但仍会打印错误。没有它,失败的请求可能看起来像空响应。
  • URL 由基础 URL 变量加上聊天补全路径构成,因此你永远不用在脚本中硬编码主机。
  • -H "Authorization: ..." 发送 bearer token。变量由 shell 展开,这就是之前导出它很重要的原因。
  • -H "Content-Type: application/json" 告诉服务器请求体是 JSON。
  • -d '...' 是请求体。JSON 外围的单引号可防止 shell 解释其中的大括号和引号。

如果你更愿意把请求体放在文件中,将其写入 body.json,并将 -d 参数替换为 -d @body.json。一旦 messages 数组变长,这通常更清晰。

读取原始 JSON

响应以 JSON 对象形式到达标准输出。当你想用肉眼检查时,通过格式化工具管道处理:

curl -sS "$HIAPI_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json | python -m json.tool

你应能看到一个 choices 数组,其第一个元素包含一个带有 content 字符串的 message 对象——该字符串就是模型的答案。与之并列的通常还有响应的标识符、回显的模型名称,以及包含提示和补全 token 计数的 usage 对象。现在就把一次成功响应记录下来:当你验证 Python 客户端时,它就是你要对比的参照。

此阶段的常见失败

401 几乎总是意味着 bearer token 缺失、格式错误,或未真正在当前 shell 中导出。400 若伴随关于请求体的消息,通常意味着 JSON 格式错误——尾随逗号或从文档中粘贴的智能引号是常见元凶。在查看其他任何东西之前,先修复这两项。

同样的请求用 Python 实现

Python 版本用相同的请求体做同样的事。重写它的意义在于,从 shell 测试转为可放入应用的代码,请求体是数据结构而非带引号的字符串。

使用标准库

如果你不想添加依赖,urllib 就足够了:

import json
import os
import urllib.request

api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "grok-4.7",
    "messages": [
        {"role": "system", "content": "You are a concise technical assistant."},
        {"role": "user", "content": "In one sentence, what is a bearer token?"},
    ],
}

request = urllib.request.Request(
    f"{base_url}/v1/chat/completions",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    method="POST",
)

with urllib.request.urlopen(request) as response:
    body = json.loads(response.read().decode("utf-8"))

print(body["choices"][0]["message"]["content"])

使用 requests

如果 requests 已在你的环境中,调用更简短:

import os
import requests

response = requests.post(
    f"{os.environ['HIAPI_BASE_URL']}/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
    json={
        "model": "grok-4.7",
        "messages": [
            {"role": "system", "content": "You are a concise technical assistant."},
            {"role": "user", "content": "In one sentence, what is a bearer token?"},
        ],
    },
    timeout=60,
)
response.raise_for_status()
print(response.json()["choices"][0]["message"]["content"])

为什么这个版本对应用更安全

请注意三个刻意的选择。密钥和基础 URL 来自环境变量,绝不来自源码中的字面量。请求体是 Python 字典,因此放错位置的引号会立即产生 SyntaxError,而不是令人困惑的服务器端拒绝。并且调用设置了超时:没有超时,停滞的连接可能无限期挂起一个工作进程。

用你在 curl 中使用的相同提示词运行 Python 版本。答案的措辞在多次运行间可能略有不同——模型并非确定性的——但响应的结构应完全一致:一个 choices 数组、一个带 content 的 message,以及一个 usage 块。如果结构匹配,你的客户端就连接正确,其余各节都是可选的增强。

开启流式传输

流式传输改变的是 token 到达的方式,而不是你请求的内容。你不必等待完整答案,而是逐步收到它,这正是聊天界面感觉响应迅速的原因。

请求的改动

在你已有的请求体中添加一个字段:

{
  "model": "grok-4.7",
  "stream": true,
  "messages": [
    { "role": "user", "content": "Count from one to five, one number per line." }
  ]
}

端点、请求头或 messages 的其他部分都没有变化。这正是先学习基础形态的全部意义:流式传输是一个附加标志,而不是第二个 API。

返回什么

启用 stream 后,响应不再是单个 JSON 对象。它是一系列服务器发送事件(SSE)。每个事件携带一行 data:,其载荷是一个 JSON 片段,形态与普通响应相同,只是 choices[0] 中包含的是 delta 对象而非完整的 message。早期片段可能只包含角色;中间片段携带内容片段;流以哨兵行 data: [DONE] 结束。

作为客户端,你的任务是将 delta.content 字符串按顺序拼接起来,并在哨兵处停止。将任何缺少 content 的片段视为无操作而非错误。

在 Python 中消费数据块

import json
import os
import requests

with requests.post(
    f"{os.environ['HIAPI_BASE_URL']}/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
    json={
        "model": "grok-4.7",
        "stream": True,
        "messages": [{"role": "user", "content": "Count from one to five."}],
    },
    stream=True,
    timeout=60,
) as response:
    response.raise_for_status()
    for line in response.iter_lines():
        if not line:
            continue
        line = line.decode("utf-8")
        if not line.startswith("data: "):
            continue
        data = line[len("data: "):]
        if data == "[DONE]":
            break
        delta = json.loads(data)["choices"][0].get("delta", {})
        text = delta.get("content")
        if text:
            print(text, end="", flush=True)

两个细节决定了流式传输是正常工作还是看似挂起。向 HTTP 客户端传入 stream=True,这样它不会缓冲整个响应体,并逐行迭代而非一次性读取响应。print 上的 flush=True 只关乎你在屏幕上看到的内容;没有它,即使数据块是随到随处理的,输出也可能看起来在最后突然爆发。

单独验证流式传输

不要在同一测试中同时验证流式传输和工具调用。先确认拼接后的文本对简单提示词给出了合理答案,然后逐个添加功能。如果流结束时没有哨兵,那是检查连接的信号,而不是检查模型。

工具调用选项

工具调用让模型可以请求你代码中定义的函数,而不只是生成文本。请求侧的附加方式与流式传输完全相同。

选项放在哪里

工具定义是请求体上的 tools 数组。每个条目描述一个可调用项:名称、何时使用它的描述,以及其参数的 JSON schema 描述。描述比看上去更重要——它是模型判断工具何时适用的唯一指引。

{
  "model": "grok-4.7",
  "messages": [
    { "role": "user", "content": "What is the weather in Lisbon right now?" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a named city.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": { "type": "string", "description": "City name, e.g. Lisbon" }
          },
          "required": ["city"]
        }
      }
    }
  ]
}

要记住的形态是 type 加 function,其中嵌套 name、description 和 parameters。如果你已有 JSON schema 定义,parameters 块就是它们该放的地方。

模型如何回复

当模型决定需要工具时,choices[0] 中的 assistant 消息不是普通文本。其 content 通常为空,并携带一个 tool_calls 数组。每个条目有一个标识符、一个与你某个定义匹配的函数名,以及一个包含 JSON 的 arguments 字符串。请解析该 arguments 字符串——它是字符串而非对象,把它当作对象是常见的错误来源。

你的代码随后运行该函数,并发送一个后续请求:原始对话、带 tool_calls 的 assistant 消息,以及一条角色为 tool 的新消息,包含调用标识符和结果。模型使用该结果生成最终答案。tool_call_id 必须与 assistant 消息中的标识符匹配;没有它,后续请求就是含糊的。

实用防护措施

  • 用你发送的同一 schema 验证解析出的参数。模型受 schema 引导,但并不受其约束。
  • 将返回的函数名视为不可信输入,只路由到明确的函数允许列表。
  • 不要在首次测试时同时启用 stream 和工具。先端到端确认非流式工具往返,然后如果你的用例需要两者,再组合使用。

上线前验证响应

在终端中能工作的一次调用,不等同于已验证的集成。请完整走一遍这份清单,然后保留脚本作为冒烟测试。

确认传输层

在解析任何内容之前,检查 HTTP 状态为 200。先解析的客户端会在真正问题为 401 时产生令人困惑的 KeyError。显式断言状态,失败时连同响应体一起记录——服务器通常会说明哪里出错了。

确认响应结构

要断言,不要假设。在成功的非流式调用中,验证三件事:choices 存在且非空,choices[0].message.content 是非空字符串,响应中回显的模型与你发送的一致。最后这项检查能捕获数量惊人的配置错误——默认模型覆盖了你请求的模型。

刻意演练错误路径

不要等到故障发生才了解代码的行为。运行三个快速负面测试:

  • 移除认证头后调用,确认你的代码暴露出明确的认证错误,而不是无限重试。
  • 发送缺少 model 字段的请求体,确认你得到客户端错误,而不是挂起。
  • 发送一个刻意很长的提示词,确认你的超时和截断处理行为符合预期。

每一项都应产生具体的、已记录的失败——而不是笼统的“出了点问题”。

单独验证增强功能

如果你启用了流式传输,确认拼接后的数据块形成连贯的答案,且哨兵结束了循环。如果你启用了工具,确认往返完成:工具调用被解析、函数被执行、结果带着匹配的标识符返回,并产生最终文本答案。将每项验证放在各自的小脚本中,这样失败会指向某一个功能。

让检查可重复

将整个序列放入一个文件,任何断言失败即以非零码退出,并在每次部署前针对你的暂存配置运行它。它应该只需几秒钟,覆盖基本调用、一次流式调用,如果你使用工具,再覆盖一次工具往返。当它通过时,你就可以相信生产中的失败在于你发送的请求,而非底层管道。

检查通过后,再运行一次 curl 调用。如果原始 JSON 与你的应用输出一致,集成就完成了。

立即开始构建持久 AI 产物

获取 API 密钥,通过一个基于任务(task)的 API 调用图像、视频和音频模型。

阅读 API 文档