你已经用 Ollama、vLLM 或 LM Studio 把 llama 跑起来了,也想让它像官方那样用 openai 库直接调,但真动手就会卡在几个地方:Base URL 该拼到哪一层、要不要随便填个 Key、流式回来的东西为什么断在半路、并发一上去就排队。这篇不讲协议原理,只给工程侧的做法:怎么把服务起成兼容形态、客户端怎么接、超时并发日志和降级怎么设,以及什么样的场景下这条路不该走。
本地 llama 跑起来只是第一步。你想用 openai 那套 SDK 直接调它,中间还差一层「兼容形态」的包装:服务端要暴露成 /v1 这种路径,客户端要按 OpenAI 的请求体发。这两头对不上,最常见的结果就是 404、401 或者请求发出去石沉大海。
下面按工程落地顺序讲四件事:怎么把服务起成兼容形态、客户端怎么接、超时并发怎么卡、日志和降级怎么留后路。每节都给判断标准和能直接试的动作,不讲协议原理。
先把本地服务起成兼容形态
两条路线:一是 Ollama 这类自带兼容层,启动后本身就暴露 /v1 路径,你几乎不用额外配;二是 vLLM 这类推理框架,需要显式指定对外模型名,把本地权重路径藏起来,避免客户端里写死一串本地目录。选定路线后先别急着写客户端代码。
- 确认服务端认的模型名启动后看服务端日志,找出它注册的对外模型名。客户端传的名字必须跟它一致,不一致通常直接 404 或 400。
- 确认监听地址默认可能只绑 127.0.0.1,容器内或局域网另一台机器会连不上。需要显式绑到 0.0.0.0,并确认端口没被别的进程占。
- 确认鉴权方式Key 多数情况是占位值,但不是没有鉴权。如果服务开了 token 校验,客户端环境变量必须对上,否则表现成 401,别和网络问题混着查。
- 用 curl 打一发非流式先拿到一段完整 JSON 再往下走,这一步过了才说明服务端形态是对的。
- 兼容层
- 把本地推理服务包装成 OpenAI 请求体形状的中间层,Ollama 自带,vLLM 靠启动参数指定
- 对外模型名
- 客户端请求里填的那个名字,必须和服务端注册的一致,和本地权重文件路径无关
- 占位 Key
- 多数本地服务不校验内容,但字段不能少,少了会直接 401
客户端这边怎么接才算接对
接错最集中的地方是 Base URL 写到哪一层。只写到 /v1,后面由 SDK 自己拼 /chat/completions;多写一段或少写一段都会 404。具体到各家兼容接口的 Base URL 写法,可以去 /tools 里对照说明核对,别凭记忆抄。
- base_url 和 api_key 两个都要给,只改其中一个是最常见的半截配置
- 先用 curl 打一次非流式请求确认能拿到 JSON,再换 SDK,再开流式;顺序反了会把服务问题和客户端问题搅在一起
- 同一台机器上同时跑多个本地服务时,端口和环境变量容易串,建议一个服务一个终端会话
- 开启流式后如果内容断在半路,先看服务端日志里这条请求的结束原因,再判断是不是客户端读取超时
from openai import OpenAI;client = OpenAI(base_url="http://127.0.0.1:端口/v1", api_key="占位串");resp = client.chat.completions.create(model="服务端认的模型名", messages=[{"role":"user","content":"你好"}], stream=False);print(resp.choices[0].message.content)| 现象 | 先查哪里 | 常见原因 |
|---|---|---|
| 404 | Base URL 层级 / 模型名 | 多写或少写一段路径,或模型名和服务端不一致 |
| 401 | api_key 与鉴权配置 | 字段漏填,或服务端 token 校验没对上 |
| 连不上 | 监听地址与端口 | 只绑了 127.0.0.1,或端口被占 |
| 流式断开 | 服务端结束原因 + 客户端读取超时 | 读取超时设太短,或服务端被并发挤停 |
超时、并发与排队怎么设
本地推理的首字延迟天生比云端高,超时不能照抄云端的默认值。要分成连接超时和读取超时两段设:连接超时短一点没关系,读取超时设太短,长回答必然被自己掐断。判断标准是——把读取超时设到你本地最长一次回答耗时的两倍以上。
并发这块,单卡服务的并行能力有限。客户端并发数要按显存和服务端并发上限来卡,超了就排队,卡住时的表现是「没报错但一直不返回」。这种比直接报 429 更难查,所以宁可提前在客户端侧限流。
- 用队列或信号量在客户端侧限流,比等服务端报 429 再退避体验更好
- 退避要带随机抖动,不然多个客户端会形成整齐的二次冲击
- 流式场景保留重试开关,长回答被截断时至少能区分是网络断了还是模型停了
- 把并发上限写进配置而不是散在代码里,方便按机器换配置
本地服务卡住时,最危险的状态不是报错,而是没有报错却一直不返回。
日志、降级与自测
日志要能回答三个问题:这条请求排队了多久、模型出首字用了多久、最后为什么结束。每次请求至少记下模型名、总耗时、首字时间、是否流式、结束原因。本地服务出问题时,这几项能快速区分是排队、显存不够还是客户端超时。
| 记录项 | 用途 | 异常时的指向 |
|---|---|---|
| 模型名 | 核对请求打到哪个模型 | 和服务端注册名对不上 |
| 总耗时 | 看整体是否超预期 | 排队或显存不足 |
| 首字时间 | 区分加载慢还是生成慢 | 模型首次加载未预热 |
| 结束原因 | 看是正常结束还是中断 | 客户端超时或服务端被挤停 |
给本地服务准备一个降级出口。本机排队过长或服务挂了,就切到云端同协议接口,只要两边请求体形状一致,切换成本很低。这段切换逻辑最好在调用方封装一层,别散在业务代码各处。至于价格和可用性数字,到 /price-watch 看当时的情况再决定切不切。
上线前用固定的一小组用例跑一遍回归,比对改动前后的返回,别只看单次能不能通。用例怎么组织可以参考站内评测的做法。适用边界也说清楚:单机 llama 适合开发调试、内网低并发和断网场景;要求高并发、多副本一致性或稳定对外服务时,这条路不该走,直接上托管接口更省事。
下一步想横向比各家 API 的调用形态和价格,去 /rankings 看当时的对比;本地服务跑起来后,也可以到 /tools/speed-test 量一下首字和吞吐再决定要不要长期用。→常见问题
本地 llama 用 openai 库调,api_key 随便填行不行?
多数本地服务的兼容层不校验 Key,填个占位字符串就能过。但如果服务端开了 token 校验,或者你后面把请求转到了中转网关,就必须填对。稳妥做法是先看服务启动参数里有没有鉴权项,再用 curl 打一次确认,避免把 401 当成网络问题查。
为什么请求一直不返回,也不报错?
常见是并发排队:服务端在处理别的请求,你的请求进了队列。其次是显存吃满导致推理极慢。先看服务端日志有没有排队或显存警告,再把客户端并发降到 1 试一次;如果单个请求正常,就是并发数设高了,不是接口坏了。
单机部署的 llama 能直接拿来对外做服务吗?
小范围内网自用可以,对外服务要谨慎:单点没有高可用,并发一上来就排队,显存和机器一挂就全停。要对外的话,至少得考虑多副本加网关转发,或者干脆用托管接口,把稳定性交给有冗余的一方。