☰
Qwen-Agent 流式输出实战:3 步把 vLLM 响应从“憋大招“变“边说边想“
2026/10/15 16:08:43 网站建设 项目流程

Qwen-Agent 流式输出实战:3 步把 vLLM 响应从"憋大招"变"边说边想"

【免费下载链接】Qwen-AgentAgent framework and applications built upon Qwen>=3.0, featuring Function Calling, MCP, Code Interpreter, RAG, Chrome extension, etc.项目地址: https://gitcode.com/GitHub_Trending/qw/Qwen-Agent

对话界面卡在第 5 秒还没吐出一个字——大概率是模型在"憋大招":整段生成完才一次性返回。Qwen-Agent 作为 Qwen 生态的 Agent 框架(内置 Function Calling、代码解释器、RAG 等能力),只要把模型服务切到 vLLM 后端并走流式输出,就能把首字延迟从"整段生成时间"压到"首个 token 的时间",本文讲清原理并给你一套 3 步跑通的实操流程。

场景:一次代码解释器任务的体感对比

别急,先建立一个直观印象。拿 Qwen-Agent 里的代码解释器场景举例:你问它统计各大洲人口分布并画图。

批处理模式下,你要盯着光标转圈,等几十行 Python、执行日志、饼图全部生成完,界面才"啪"地刷出一整块。

流式模式下,"Thought: 我需要……" 先出来,紧接着代码一行行落下,图表渲染完再追加结论——每个 token 到手即显示,过程可见,焦虑感直接减半。

维度整段批处理vLLM 流式输出
首字延迟等于整段生成时间约等于首 token 时间
输出过程一次性刷新逐 token 递增渲染
中断感知卡死感随时可打断、可见进度

图 1:代码解释器中流式生成的过程记录,思考、代码与执行结果逐段出现

这种差别在长回复里最扎眼,回答越短,两种模式的体感越接近。

核心机制:数据到底怎么流

一句话概括:vLLM 负责"逐 token 吐",openai SDK 负责"逐 chunk 收",Qwen-Agent 负责"逐帧渲染"。

拆开看有四层:

  1. 推理引擎:vLLM 本身是 LLM 推理引擎,靠 PagedAttention 和连续批处理把生成吞吐拉上去,并对外暴露 OpenAI 兼容协议——也就是说,任何会说 OpenAI 方言的客户端都能直接接上。
  2. LLM 抽象层:qwen_agent/llm/base.py里注册了统一的 chat 接口,model_type指定后端即可切换。
  3. 适配层:qwen_agent/llm/oai.py中的TextChatAtOAI把配置里的model_server作为 base_url 传给 OpenAI 客户端,vLLM 不需要任何专属代码就能被 Qwen-Agent 消费。
  4. 上层渲染:Agent 拿到增量 Message 后逐帧推给 Web UI。

流式的核心就在_chat_stream,看这两段关键逻辑(qwen_agent/llm/oai.py):

response = self._chat_complete_create(model=self.model, messages=messages, stream=True, **generate_cfg) if delta_stream: for chunk in response: if chunk.choices and chunk.choices[0].delta.content: yield [Message(role=ASSISTANT, content=chunk.choices[0].delta.content)] # 只推增量 else: full_response = '' for chunk in response: full_response += chunk.choices[0].delta.content # 累积完整内容 yield [Message(role=ASSISTANT, content=full_response)]

这里有个关键点:delta_stream决定上层每次收到的是"新增片段"还是"累积全文"。全流模式还能顺手把碎片化的 tool_calls 拼回完整函数调用——Function Calling 走流式时靠的就是这段。基类里甚至有句自嘲:delta 模式给后处理和重试带来麻烦,现在默认推荐全流模式。

图 2:Qwen-Agent 对话界面,模型按用户选定的上下文流式作答

动手:3 步从配置到跑通

第 1 步:起一个 vLLM 服务

pip install vllm python -m vllm.entrypoints.openai.api_server \ --model Qwen2-7B-Instruct \ --host 0.0.0.0 \ --port 8000

✅ 验证点:看到Uvicorn running on ...:8000后,另开终端执行curl http://127.0.0.1:8000/v1/models,能列出模型名即说明协议层通了。

第 2 步:把 Qwen-Agent 指向 vLLM

改qwen_server/server_config.json,或直接给run_server.py传参,后者会替你写回配置文件:

python run_server.py \ -m http://127.0.0.1:8000/v1 \ -k EMPTY \ -l Qwen2-7B-Instruct

注意-m要写到/v1结尾,这是 OpenAI 兼容协议的路径约定。

✅ 验证点:终端会依次拉起 database、workstation、assistant 三个子进程,日志里打印的 server 配置应包含你的model_server地址。

第 3 步:打开 Web UI 验流式

访问http://127.0.0.1:7864,在对话里抛一个需要长回答的问题。

✅ 验证点:首 token 到达时文字就开始出现,而不是转圈几秒后整段刷出——这一刻你就确认流式链路是通的。

图 3:Web UI 中问答的流式呈现效果

性能怎么验证

先给一张定性对比表,方便你建立预期(具体数字依赖模型与硬件,请以自测为准):

指标整段批处理vLLM 流式说明
首字延迟等于整段生成时间约等于首 token 时间收益核心
输出过程一次性渲染逐 token 追加可随时打断
客户端内存压力全量缓存后渲染增量持有长回复更明显

想拿硬数据,自己在_chat_stream首尾各打一个时间戳,对比stream=True和stream=False两种调用:前者首个 yield 的耗时就是 TTFT。收益在长回复、代码解释器这类场景最明显;如果你只问"今天星期几",两种模式的差别基本感知不到——流式优化救的是"长",不是"短"。

进阶与避坑

三个最常见的翻车现场:

  • 服务起来了但 Qwen-Agent 连不上→ 确认-m结尾是/v1,且 vLLM 端--port与地址一致;跨机器访问时记得--host 0.0.0.0并把server_host设为0.0.0.0。
  • 流式中途断流→ 多半是 GPU 显存不够或上下文超--max-model-len,服务端 OOM 会直接掐断 SSE 流,调小 max-model-len 或降低并发即可。
  • 工具调用解析不出来→ vLLM 侧要开--enable-auto-tool-choice与对应的--tool-call-parser,Qwen-Agent 侧oai后端才能收到完整 tool_calls。

想再挖深一点:抓一段 SSE 原始流看看 token 间隔分布是否稳定;或者把--gpu-memory-utilization从 0.9 往下调,观察吞吐与显存占用的取舍曲线。

参考资源

  • 官方文档:qwen-agent-docs/website/content/en/guide/get_started/configuration.md(配置说明)、qwen-agent-docs/website/content/en/guide/core_moduls/llm.md(LLM 层介绍)
  • 核心源码入口:qwen_agent/llm/base.py(统一接口)、qwen_agent/llm/oai.py(OpenAI 兼容适配)
  • 示例脚本:examples/function_calling.py(流式函数调用最小用例)

试试把批处理请求的"发请求到出首字"和流式请求各记一个时间戳,跑 10 轮取平均——这条曲线会比我写的任何表格都更有说服力。

【免费下载链接】Qwen-AgentAgent framework and applications built upon Qwen>=3.0, featuring Function Calling, MCP, Code Interpreter, RAG, Chrome extension, etc.项目地址: https://gitcode.com/GitHub_Trending/qw/Qwen-Agent

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询