openai-io
轻量级的 OpenAI 大模型 IO 库:只保留 chat.completions / completions / embeddings
三件套,同步(OpenAI)与异步(AsyncOpenAI)双客户端,传输层基于 httpx,
数据模型基于 pydantic v2。
为什么不用官方 SDK
官方 SDK 功能全,但用起来有几处不太顺手:
- 太重。模型 IO 只占它的一小部分,
images、audio、files、batch、assistants这些资源平时根本用不到,依赖和包体积都跟着上去了。 messages是 TypedDict,{"role": "user", "content": "..."}全靠手写,没有对象、 没有自动补全,多轮对话拼起来很啰嗦。- 类型太绕:
NotGiven哨兵、一长串 Union、各种*_Param,IDE 提示经常是几行 联合类型,报错也不好读。
这个库只做 chat / completions / embeddings 三件事,messages 换成 langchain 风格的
对象,接口和官方 SDK 保持一致,迁移成本低。
特性
- 轻量:只依赖
httpx和pydantic - 同步
OpenAI与异步AsyncOpenAI双客户端 - langchain 风格 message:
SystemMessage/HumanMessage/AIMessage/ToolMessage/FunctionMessage/ChatMessage(不依赖 langchain-core) - 流式输出(SSE):
stream=True返回可迭代的Stream/AsyncStream - 异常体系与 openai SDK 对齐,自动重试(指数退避 + 抖动)
安装
pip install -e .
要求 Python >= 3.12。
快速开始
同步
from openai_io import OpenAI
from openai_io.messages import HumanMessage, SystemMessage
client = OpenAI() # 或 OpenAI(api_key="sk-...")
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
SystemMessage(content="你是一个友好的助手"),
HumanMessage(content="你好"),
],
)
print(resp.choices[0].message.content)
# embeddings
vectors = client.embeddings.create(model="text-embedding-3-small", input="你好")
print(vectors.data[0].embedding[:5])
# 旧版文本补全
comp = client.completions.create(model="gpt-3.5-turbo-instruct", prompt="1+1=?")
print(comp.choices[0].text)
异步
import asyncio
from openai_io import AsyncOpenAI
from openai_io.messages import HumanMessage
async def main() -> None:
client = AsyncOpenAI()
resp = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[HumanMessage(content="你好")],
)
print(resp.choices[0].message.content)
asyncio.run(main())
流式输出
stream = client.chat.completions.create(
model="gpt-4o-mini",
messages=[HumanMessage(content="讲个故事")],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="")
异步流式使用 async for chunk in await client.chat.completions.create(..., stream=True)。
Message 体系(与原生 openai 的差异)
原生 openai SDK 的 messages 参数是 TypedDict 风格({"role": ..., "content": ...}),
本库改为 langchain 风格的类:
from openai_io import AIMessage, FunctionCall, HumanMessage, SystemMessage, ToolCall, ToolMessage
messages = [
SystemMessage(content="你是助手"),
HumanMessage(content="北京天气如何?"),
AIMessage(
content=None,
tool_calls=[ToolCall(id="call_1", function=FunctionCall(name="get_weather", arguments='{"city": "北京"}'))],
),
ToolMessage(content="晴,25°C", tool_call_id="call_1"),
]
BaseMessage抽象基类:content/additional_kwargs/response_metadata/name/id,type为类别标识("human"/"ai"/"tool"…)content支持多模态 part 列表([{"type": "text", ...}, {"type": "image_url", ...}])- 兼容原始 dict:
messages可以混合传入BaseMessage与{"role": ..., "content": ...}, 迁移时无需一次性替换全部代码 - pydantic 2.13 起构造参数为关键字形式:
HumanMessage(content="你好")
与 openai SDK 的对应关系
| openai SDK | openai-io |
|---|---|
from openai import OpenAI |
from openai_io import OpenAI |
client.chat.completions.create(...) |
client.chat.completions.create(...) |
client.completions.create(...) |
client.completions.create(...) |
client.embeddings.create(...) |
client.embeddings.create(...) |
from openai import AsyncOpenAI |
from openai_io import AsyncOpenAI |
openai.OpenAIError 等异常 |
openai_io.OpenAIError 等,类名一致 |
请求参数(temperature / max_tokens / tools / …) |
同名同语义;未传参不写入请求体(NotGiven 哨兵语义一致) |
| TypedDict messages | langchain 风格 BaseMessage(也可传 dict) |
create 的入口参数与 openai SDK 对齐,含 stream / stream_options / tools /
tool_choice / response_format / seed 等;未显式传参的字段不会出现在请求体中。
开发
uv sync --extra dev
uv run ruff check src tests && uv run ruff format --check src tests
uv run pyright
uv run pytest
测试使用 httpx.MockTransport 注入 mock 响应,无需真实 API key。
许可证
Apache-2.0
Metadata
Release files for openai-io 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openai_io-0.1.3.tar.gz | 24.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openai_io-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.1 kB
Release files / openai_io-0.1.3.tar.gz
| Download URL | openai_io-0.1.3.tar.gz |
|---|---|
| Size | 24.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9cc159587f4b185f4ee595afb9c8baa90d8ab4ab1129986ff5e857b893ae352c
|
|
BLAKE2b-256 checksum How to use checksums |
79a0c973ac5890ce5c8705c02a6c4772f96e4c326c3e872e35e392077bbd0217
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / openai_io-0.1.3-py3-none-any.whl
| Download URL | openai_io-0.1.3-py3-none-any.whl |
|---|---|
| Size | 28.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8cd8e76a6d3fd0519acfd8fba88b0e7da696e3897ca20d48e404c520a93de7e3
|
|
BLAKE2b-256 checksum How to use checksums |
a993b57483ae9aaf3cf02aa6f8fc8d908e339cbf644d9dcc0f985ccea372d322
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|