OpenAI 流式的代碼:
首選一般請使用os.getenv 去讀環境變量的內容
注意使用pip install python-dotenv 的安裝方法
load_dotenv 是這個庫提供的一個函數,用于讀取 .env 文件并將其中定義的鍵值對設置為系統的環境變量。
默認情況下,load_dotenv() 會自動查找當前目錄下的 .env 文件。如果文件不在默認路徑,可以通過參數指定,例如 load_dotenv(‘/path/to/.env’)。
為什么代碼里用 dotenv 而不是 python_dotenv?
在 Python 中,導入模塊時使用的是庫的模塊名,而不是 PyPI 上的包名。python-dotenv 這個包安裝后,提供了一個名為 dotenv 的模塊供導入。這是由庫開發者決定的命名約定。例如:
- PyPI 包名:python-dotenv
- 導入時的模塊名:dotenv
流式代碼 類 (一鍵運行)
from openai import AsyncOpenAI
from dotenv import load_dotenv
import osload_dotenv()class AsyncOpenAIOut:def __init__(self):self.api_key = os.getenv("OPENAI_API_KEY")self.base_url = os.getenv("OPENAI_BASE_URL")self.oai_client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url)self.model = os.getenv("OPENAI_MODEL")async def gpt_stream(self, user_message: str,model: str = os.getenv("OPENAI_MODEL"),history: list[dict] = [],system_prompt: str = "") :messages = []if history:messages.extend(history)if system_prompt:messages.extend([{"role": "system", "content": system_prompt}])messages.append({"role": "user", "content": user_message})response = await self.oai_client.chat.completions.create(model=model,messages=messages,stream=True)async for chunk in response:if chunk.choices[0].delta.content:yield chunk.choices[0].delta.contentasync_openai_out = AsyncOpenAIOut()if __name__ == "__main__":async def test_gpt_stream():async for chunk in async_openai_out.gpt_stream(user_message="寫300字作文",system_prompt="You are a helpful assistant."):print(chunk)import asyncioasyncio.run(test_gpt_stream())
這里面有幾點需要注意:
簡短回答:print(chunk) 是 同步操作,會在當前事件循環中執行完畢后才繼續,但它不是 I/O 密集型操作,所以不會造成實際的“阻塞”問題,特別是在異步函數中逐步輸出內容的場景下,它是可接受的。
想確保異步非阻塞輸出:
async for chunk in async_openai_out.gpt_stream(user_message="寫300字作文",system_prompt="You are a helpful assistant."):# print(chunk)await asyncio.to_thread(print, chunk) # 在后臺線程執行 print
異步生成器(Async Generator) 的用法,結合了 Python 的異步編程(async for)和生成器(yield)機制。
在異步迭代 response 中的每個 chunk,如果它有內容,就通過 yield 一塊一塊地“流式返回”。
async for chunk in response:if chunk.choices[0].delta.content:yield chunk.choices[0].delta.content
對比for : 普通for是同步迭代
async for是異步迭代,比如網絡流、WebSocket、OpenAI 的 Stream 響應等。
yield 是生成器的關鍵,它不是“返回”值,而是“產出”值(可以被迭代一次)。