模型流式处理返回的 result 是否是生成器?
模型流式返回(如大模型逐字输出、数据分批处理)的核心需求是"边生成边返回",生成器的"惰性计算、逐次产出"特性完美匹配此场景。
大概率是生成器或类生成器对象。除原生生成器外,也可能是 asyncio 异步生成器(async def + yield),或框架封装对象(如 OpenAI SDK 的 AsyncStream)。
生成器函数(最常用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| def stream_data():
for i in range(3):
yield f"流式数据 {i}" # 暂停执行,返回值;下次调用时从此处继续
# 遍历(推荐)
gen = stream_data()
for data in gen:
print(data) # 流式数据 0 → 流式数据 1 → 流式数据 2
# 手动调用 next()
gen = stream_data()
print(next(gen)) # 流式数据 0
print(next(gen, "无数据")) # 流式数据 1(带默认值避免 StopIteration)
# 转为列表(失去流式优势)
print(list(stream_data())) # ['流式数据 0', '流式数据 1', '流式数据 2']
|
生成器表达式
1
2
3
4
5
6
7
| # 语法:(表达式 for 变量 in 可迭代对象)
gen = (x * 2 for x in range(3))
# 内存对比
import sys
lst = [x * 2 for x in range(10000)] # ~80040 字节
gen = (x * 2 for x in range(10000)) # ~112 字节(仅保存生成逻辑)
|
异步生成器
1
2
3
4
5
6
7
8
9
10
11
12
| import asyncio
async def async_stream_data():
for i in range(3):
await asyncio.sleep(0.5) # 模拟异步 IO
yield f"异步流式数据 {i}"
async def main():
async for data in async_stream_data():
print(data)
asyncio.run(main())
|
核心特性
| 特性 | 说明 |
|---|
| 惰性计算 | 仅在 next()/遍历时执行到 yield 才产出值 |
| 一次性遍历 | 遍历后"耗尽",再次遍历无输出 |
| 无索引/长度 | 不支持 gen[0]、len(gen) |
| 非线程安全 | 单个生成器不能被多线程同时调用 |
实战:模拟模型流式返回
1
2
3
4
5
6
7
8
| def llm_stream_response(prompt):
"""模拟大模型流式返回"""
response = "您好!很高兴为您解答问题。"
for char in response:
yield char
for char in llm_stream_response("你好"):
print(char, end="", flush=True) # 逐字输出
|
yield from:简化嵌套生成器
1
2
3
4
5
6
7
8
9
10
| def sub_gen():
yield 1
yield 2
def main_gen():
yield 0
yield from sub_gen() # 等价于 for x in sub_gen(): yield x
yield 3
list(main_gen()) # [0, 1, 2, 3]
|
生成器关闭
1
2
3
4
5
6
7
8
9
10
| def gen_with_cleanup():
try:
yield 1
yield 2
except GeneratorExit:
print("生成器被关闭,清理资源")
gen = gen_with_cleanup()
print(next(gen)) # 1
gen.close() # 输出:生成器被关闭,清理资源
|
生成器是处理流式数据(大模型输出、分批读取文件/数据库)的首选方案,兼顾响应速度与内存效率。
Comments