用llama.cpp的server模式对接自定义API请求时缺少authorization头:启用api-key并配置适配

文章导读
遇到自定义 API 请求被判定为缺少 authorization 头时,先不要急着改代码。需要判断的是请求是否真正到达了 llama.cpp server,以及 server 是否按预期校验了 token。通常有两层原因:客户端请求没有携带 Authorization 头,或服务端没有启用对应的 api-key 参数。下文按这个顺序给出配置和验证方式。
📋 目录
  1. 先确认请求被拒绝在哪一层
  2. 启用 api-key 并确认启动参数
  3. 自定义请求与网关的 header 适配
  4. 验证清单与边界
A A

遇到自定义 API 请求被判定为缺少 authorization 头时,先不要急着改代码。需要判断的是请求是否真正到达了 llama.cpp server,以及 server 是否按预期校验了 token。通常有两层原因:客户端请求没有携带 Authorization 头,或服务端没有启用对应的 api-key 参数。下文按这个顺序给出配置和验证方式。

如果请求返回 401 或日志出现鉴权失败提示,先用 curl 直连 server 验证端点是否需要 Bearer token。llama.cpp 的 OpenAI 兼容路径通常强制校验 Authorization 头,原生路径存在版本差异;自研网关转发时最容易丢失或改写这个头。建议统一走 /v1 路径、显式设置 api-key、在网关层透传原始请求头。

先确认请求被拒绝在哪一层

不要带着自定义代码排查。直接对 llama-server 用 curl 发起一次最小请求,例如访问 /v1/chat/completions。如果直连也返回 401,问题多半在服务端,比如没有启用 api-key 或 key 不匹配;如果直连正常,但自定义代码请求失败,问题就出在请求构造或中间网关上。

这种分层判断可以省掉大量无效修改。常见的自定义代码缺陷是:只构造了 JSON body 忘了加 header;用 OpenAI SDK 时填了 base_url 却没填 api_key;或者企业网关把 Authorization 视为敏感头直接剥离了。每一条都有不同的改法。

启用 api-key 并确认启动参数

启动 llama.cpp server 时加入 `--api-key` 参数,key 用自己生成的随机字符串即可:

用llama.cpp的server模式对接自定义API请求时缺少authorization头:启用api-key并配置适配
llama-server -m ./model.gguf `--host` 127.0.0.1 `--port` 8080 `--api-key` sk-local-test

部分版本也支持从文件读取 key,例如 `--api-key-file` /path/to/key.txt,具体以本地版本的 `--help` 输出为准。只在本机调试时,建议加上 `--host` 127.0.0.1,避免服务暴露到局域网。需要对外提供服务时,api-key 更不可省略。

有一点需要留意:llama.cpp 的 OpenAI 兼容端点,例如 /v1/chat/completions、/v1/completions,通常希望请求头携带 Authorization: Bearer <key>;而 /health、/slots 这类管理端点一般不需要。不同版本对原生端点的鉴权范围不完全一致,为了减少版本差异带来的困惑,自定义请求应统一走 /v1 路径,并始终带上 Bearer 头。

自定义请求与网关的 header 适配

用 curl 验证时,请求头必须显式写出 Authorization:

用llama.cpp的server模式对接自定义API请求时缺少authorization头:启用api-key并配置适配
curl http://127.0.0.1:8080/v1/chat/completions \
  -H "Authorization: Bearer sk-local-test" \
  -H "Content-Type: application/json" \
  -d '{"model":"local-model","messages":[{"role":"user","content":"hello"}]}'

model 字段在 llama.cpp 兼容端点中不一定要与实际模型名一致,重点是先确认鉴权链路通不通。用 Python 直接构造请求时也一样:

import requests

url = "http://127.0.0.1:8080/v1/chat/completions"
headers = {
    "Authorization": "Bearer sk-local-test",
    "Content-Type": "application/json",
}
payload = {
    "model": "local-model",
    "messages": [{"role": "user", "content": "hello"}],
}
resp = requests.post(url, headers=headers, json=payload)
print(resp.status_code, resp.text)

如果使用 OpenAI SDK,需要把 base_url 指向 llama.cpp 的 /v1 路径,并传入 api_key:

from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8080/v1", api_key="sk-local-test")

这个 api_key 只用于本地服务端比对,并不代表云厂商身份。

用llama.cpp的server模式对接自定义API请求时缺少authorization头:启用api-key并配置适配

若自定义请求经过 Nginx 或自研网关转发,要确认 Authorization 被透传。Nginx 反向代理可显式设置:

location /v1/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Authorization $http_authorization;
}

如果客户端不带 key,而是希望网关统一注入,也可以改为 proxy_set_header Authorization "Bearer sk-local-test";。这只适合内部单一 key 的场景,多用户或外部暴露时不能让所有流量共用一个静态 key。

验证清单与边界

  • 重启 server 后,确认启动参数中确实包含 `--api-key`,或日志中出现对应配置项。
  • 不带 Authorization 请求 /v1/chat/completions,预期返回 401。
  • 带错误 Bearer key 请求,预期返回 401。
  • 带正确 Bearer key 请求,应穿越鉴权;若还有报错,通常是参数或模型加载问题,而不是鉴权问题。
  • 经网关调用失败时,在网关日志或上游访问日志中确认 Authorization 是否还在。

边界情况:/health 探活端点通常不需要鉴权,若你的版本强制校验,需结合本地日志单独确认。服务只监听 127.0.0.1 时风险相对可控;暴露到局域网或公网时,必须启用 api-key,并建议同时限制来源 IP。把请求统一收敛到 /v1/chat/completions,比在原生端点上逐个适配不同版本的鉴权行为更省事。若日志出现 missing authorization 或 access forbidden 之类关键字,优先检查发起端是否真的发送了该头,其次再检查网关透传。