流式传输
什么是流式传输?
令牌流式传输是一种模式,服务器在模型生成令牌时逐个返回令牌。这使得用户能够看到渐进的生成,而不是等待整个生成完成。流式传输是最终用户体验的重要方面,因为它可以减少延迟,而延迟是流畅体验的最关键方面之一。
使用令牌流式传输,服务器可以在必须生成整个响应之前开始逐个返回令牌。用户可以在生成结束之前了解生成的质量。这会产生不同的积极影响
- 对于非常长的查询,用户可以比非流式设置快几个数量级地获得结果。
- 看到正在进行的操作可以让用户在生成结果不符合预期方向时停止生成。
- 在生成结果的早期阶段显示结果时,感知延迟更低。
- 在对话式 UI 中使用时,体验感觉更自然。
例如,一个系统每秒可以生成 100 个令牌。如果系统生成 1000 个令牌,在非流式设置中,用户需要等待 10 秒才能获得结果。另一方面,在流式设置中,用户会立即获得初始结果,尽管端到端延迟将保持一致,但他们可以在五秒钟后看到一半的生成。您可以在下面看到一个交互式演示,它并排显示了非流式与流式。单击下面的“生成”。
如何使用流式传输?
使用 Python 进行流式传输
要使用 `InferenceClient` 流式传输令牌,只需传递 `stream=True` 并迭代响应。
from huggingface_hub import InferenceClient
client = InferenceClient(base_url="http://127.0.0.1:8080")
output = client.chat.completions.create(
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Count to 10"},
],
stream=True,
max_tokens=1024,
)
for chunk in output:
print(chunk.choices[0].delta.content)
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
如果需要并发处理请求,`huggingface_hub` 库还提供了一个 `AsyncInferenceClient`。
from huggingface_hub import AsyncInferenceClient
client = AsyncInferenceClient(base_url="http://127.0.0.1:8080")
async def main():
stream = await client.chat.completions.create(
messages=[{"role": "user", "content": "Say this is a test"}],
stream=True,
)
async for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")
asyncio.run(main())
# This
# is
# a
# test
#.
使用 cURL 进行流式传输
要使用与 OpenAI Chat Completions 兼容的 Messages API `v1/chat/completions` 端点与 curl,可以添加 `-N` 标志,它将禁用 curl 默认缓冲并显示从服务器到达的数据。
curl localhost:8080/v1/chat/completions \
-X POST \
-d '{
"model": "tgi",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "What is deep learning?"
}
],
"stream": true,
"max_tokens": 20
}' \
-H 'Content-Type: application/json'
使用 JavaScript 进行流式传输
首先,我们需要安装 `@huggingface/inference` 库。`npm install @huggingface/inference`
如果您使用的是免费的 Inference API,可以使用 `HfInference`。如果您使用的是推理端点,可以使用 `HfInferenceEndpoint`。
我们可以通过提供端点 URL 和凭据来创建一个 `HfInferenceEndpoint`。
import { HfInferenceEndpoint } from '@huggingface/inference'
const hf = new HfInferenceEndpoint('https://YOUR_ENDPOINT.endpoints.huggingface.cloud', 'hf_YOUR_TOKEN')
// prompt
const prompt = 'What can you do in Nuremberg, Germany? Give me 3 Tips'
const stream = hf.textGenerationStream({ inputs: prompt })
for await (const r of stream) {
// yield the generated token
process.stdout.write(r.token.text)
}
流式传输的工作原理是什么?
在后台,TGI 使用了 Server-Sent Events (SSE)。在 SSE 设置中,客户端发送带有数据的请求,打开 HTTP 连接并订阅更新。之后,服务器会将数据发送到客户端。无需进一步请求;服务器会继续发送数据。SSE 是单向的,这意味着客户端不会向服务器发送其他请求。SSE 通过 HTTP 发送数据,使其易于使用。
SSE 与以下内容不同
- 轮询:客户端不断调用服务器以获取数据。这意味着服务器可能会返回空响应并造成开销。
- Webhook:存在双向连接。服务器可以将信息发送到客户端,但客户端也可以在第一次请求后向服务器发送数据。Webhook 操作起来更复杂,因为它们不仅使用 HTTP。
如果同时存在太多请求,TGI 将返回带有 `overloaded` 错误类型的 HTTP 错误(`huggingface_hub` 返回 `OverloadedError`)。这允许客户端管理过载的服务器(例如,它可以向用户显示繁忙错误或重试新的请求)。要配置最大并发请求数,可以指定 `--max_concurrent_requests`,允许客户端处理背压。
< > 在 GitHub 上更新