Phản hồi dạng luồng
Phản hồi dạng luồng (Streaming) cho phép bạn nhận đầu ra theo thời gian thực trong quá trình mô hình tạo nội dung, giúp nâng cao trải nghiệm người dùng và tốc độ cảm nhận.
Nguyên lý hoạt động#
诺玛AI sử dụng giao thức Server-Sent Events (SSE) để triển khai phản hồi dạng luồng:
- Khi gửi yêu cầu, client đặt `stream: true`
- Máy chủ trả về từng đoạn nội dung được tạo (chunk) một cách tuần tự
- Mỗi chunk được gửi qua SSE với tiền tố `data: `
- Khi tạo xong sẽ gửi `data: [DONE]`
Luồng giao thức OpenAI#
cURL
Mã
curl https://as.apinoma.com/v1/chat/completions \
-H "Authorization: Bearer $APINOMA_API_KEY" \
-H "Content-Type: application/json" \
-N \
-d '{
"model": "openai/gpt-4o",
"messages": [{"role": "user", "content": "Viết một bài thơ về lập trình"}],
"stream": true
}'Python
TypeScript
Luồng giao thức Anthropic#
Python
Mã
import anthropic
client = anthropic.Anthropic(
base_url="https://as.apinoma.com/anthropic",
api_key="<APINOMA_API_KEY của bạn>"
)
with client.messages.stream(
model="anthropic/claude-sonnet-4.6",
max_tokens=1024,
messages=[{"role": "user", "content": "Viết một bài thơ về lập trình"}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)TypeScript
Luồng + Function Calling#
Phản hồi dạng luồng cũng hỗ trợ tình huống gọi hàm. Mô hình sẽ trước tiên xuất theo luồng yêu cầu gọi công cụ, sau khi bạn xử lý xong thì tiếp tục cuộc hội thoại:
Mã
stream = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Hôm nay thời tiết Bắc Kinh thế nào?"}],
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"description": "Lấy thời tiết của thành phố được chỉ định",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "Tên thành phố"}
},
"required": ["city"]
}
}
}],
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.tool_calls:
# Xử lý lệnh gọi công cụ
print(f"Gọi công cụ: {delta.tool_calls[0].function}")
elif delta.content:
print(delta.content, end="", flush=True)Xử lý lỗi và kết nối lại#
Kết nối dạng luồng có thể bị gián đoạn do sự cố mạng. Khuyến nghị triển khai logic kết nối lại.
Mã
import time
def stream_with_retry(client, max_retries=3, **kwargs):
for attempt in range(max_retries):
try:
stream = client.chat.completions.create(stream=True, **kwargs)
for chunk in stream:
yield chunk
return # Hoàn tất thành công
except Exception as e:
if attempt < max_retries - 1:
wait = 2 ** attempt # Lùi theo cấp số nhân
print(f"\nKết nối bị gián đoạn, thử lại sau {wait}s...")
time.sleep(wait)
else:
raise eThực hành tốt nhất#
- Luôn đặt thời gian chờ — Tránh chờ đợi vô hạn
- Xử lý chunk không hoàn chỉnh — Một số chunk có thể không có content
- Triển khai cơ chế kết nối lại — Sử dụng chiến lược lùi theo cấp số nhân
- Phía frontend sử dụng `flush` — Đảm bảo nội dung hiển thị ngay lập tức
Cập nhật lần cuối vào 23 tháng 6, 2026