Python 脚本调用本地大模型,vLLM 流式输出实战代码分享
环境就绪后的第一步:用 Python 连接本地大模型
当你在 AMD Instinct GPU 上成功跑通 vLLM 服务,看到终端里跳出"Uvicorn running on…"的那一刻,最让人兴奋的其实是接下来这一步:用自己的代码去“唤醒”它。很多教程止步于服务启动,但作为应用层开发者,我们更关心如何把这个推理能力集成到业务里。今天我们就跳过理论,直接上手写一段 Python 脚本,实现真正的流式文本输出,让你体验那种“打字机”般的实时响应感。
构造标准的 API 请求
vLLM 的一大优势是原生兼容 OpenAI API 格式,这意味着你不需要学习新的协议,只需使用熟悉的 requests 库即可。在编写调用代码前,先确保你的服务正在运行(默认监听 0.0.0.0:8000)。
我们需要构造一个标准的 POST 请求。关键在于 headers 和 payload 的设置。Content-Type 必须指定为 application/json,否则服务端会拒绝解析。而在 payload 中,除了常规的 model、messages 和 max_tokens 外,想要实现流式输出,必须显式设置 "stream": True。
import requests
import json
url = "http://localhost:8000/v1/chat/completions"
headers = {"Content-Type": "application/json"}
payload = {
"model": "meta-llama/Meta-Llama-3-8B-Instruct",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "简述 ROCm 生态在大模型推理中的优势。"}
],
"max_tokens": 512,
"temperature": 0.7,
"stream": True # 关键参数:开启流式模式
}
这段配置看似简单,却决定了后续的交互模式。如果不加 stream 参数,客户端会一直阻塞等待直到模型生成完所有 token,对于长文本生成,用户可能面对几十秒的空白屏幕,体验极差。而开启流式后,服务端会建立一条持久连接,边生成边推送数据。
处理分块数据与逐字打印逻辑
开启 stream=True 后,requests.post 的返回对象不再是一个完整的 JSON 响应,而是一个迭代器。我们需要通过 iter_lines() 方法逐行读取服务端推送的数据块。这里有一个细节需要注意:SSE(Server-Sent Events)协议返回的每一行通常以 data: 开头,且最后会有一个 [DONE] 标记表示结束。
下面的代码展示了如何解析这些流式数据,并实现逐字打印的效果:
try:
response = requests.post(url, headers=headers, json=payload, stream=True)
response.raise_for_status() # 检查 HTTP 状态码
print("模型开始生成:\n", end="", flush=True)
for line in response.iter_lines():
if line:
decoded_line = line.decode('utf-8')
# 过滤掉非数据行
if decoded_line.startswith("data: "):
content = decoded_line[6:] # 去掉 "data: " 前缀
if content.strip() == "[DONE]":
break
try:
data = json.loads(content)
# 提取增量生成的 token
token = data['choices'][0]['delta'].get('content', '')
if token:
print(token, end='', flush=True)
except json.JSONDecodeError:
continue
print("\n\n生成完毕。")
except requests.exceptions.ConnectionError:
print("错误:无法连接到服务端,请检查 vLLM 是否已启动且端口正确。")
except requests.exceptions.Timeout:
print("错误:请求超时,可能是模型加载过慢或网络拥堵。")
except Exception as e:
print(f"发生未知错误:{e}")
finally:
if 'response' in locals():
response.close() # 确保关闭连接,释放资源
这段代码的核心在于 print(token, end='', flush=True)。flush=True 强制立即刷新缓冲区,让每个 token 一到达就显示在终端上,从而营造出流畅的打字机效果。同时,try-except-finally 结构保证了即使中途出错或用户中断,网络连接也能被正确关闭,避免资源泄漏。
同步与流式:体验差异与场景选择
为了直观感受两者的区别,我们可以对比一下两种模式的执行逻辑。在同步模式下(stream=False),客户端发送请求后进入休眠状态,直到服务端完成全部计算并返回几 KB 甚至更大的 JSON 包。如果生成 500 个 token 耗时 10 秒,用户就要干等 10 秒才能看到结果。
而在流式模式下,首字延迟(TTFT)通常只有几百毫秒。用户几乎在发送请求的瞬间就能看到第一个字,随后的内容源源不断地涌现。这种“即时反馈”在聊天机器人、代码辅助生成或长篇文档摘要场景中至关重要,它能显著降低用户的等待焦虑感。
当然,流式调用对网络的稳定性要求稍高。如果在传输过程中连接断开,客户端需要具备一定的重连或错误提示机制,上面的代码已经做了基础示范。对于内部局域网部署的 vLLM 服务,网络波动较小,流式输出几乎是首选方案。
常见 HTTP 状态码排查指南
在实际调试过程中,你可能会遇到各种 HTTP 状态码,快速定位问题能节省大量时间:
- 404 Not Found:通常是 URL 路径写错了。vLLM 的标准接口是
/v1/chat/completions或/v1/completions,请检查是否有拼写错误,或者服务端是否修改了默认路由。 - 503 Service Unavailable:这往往意味着服务端正在忙碌或模型尚未加载完成。如果是刚启动服务,稍等片刻再试;如果是高并发场景,可能需要调整 vLLM 的
--max-num-seqs参数。 - 500 Internal Server Error:大概率是服务端崩溃了。此时应立刻回到 vLLM 启动的终端窗口查看日志,常见原因包括显存溢出(OOM)或算子不支持。如果是 OOM,尝试调低
--gpu-memory-utilization参数。 - Connection Refused:最基础的网络问题。确认 vLLM 进程是否在运行,监听地址是否为
0.0.0.0(允许外部访问),以及防火墙是否放行了 8000 端口。
通过这段实战代码,你应该已经掌握了在 Python 中调用本地大模型的核心技巧。无论是构建智能客服还是自动化写作工具,这套流式交互逻辑都能为用户提供更自然、更高效的体验。接下来,你可以尝试将这段逻辑封装成类或异步函数,进一步融入你的项目架构中。
200小时GPU算力已就位,快来领取:https://marketing.csdn.net/questions/Q2604140858304426315?utm_source=AIpaper

更多推荐
所有评论(0)