Python SDK for the RuoYi AI engine (OpenAI-compatible chat, embeddings, rerank, agent forward, traces, providers).
Project description
ruoyi-ai-sdk
Python SDK for the RuoYi AI engine.
A 1:1 Python port of the Java ruoyi-ai-sdk. Wraps the same OpenAPI surface
(models, embeddings, rerank, agent forward, traces, providers, chat history)
and exposes both synchronous and asynchronous APIs.
Install
pip install ruoyi-ai-sdk
Optional extras:
pip install ruoyi-ai-sdk[nacos] # Nacos discovery via nacos-sdk-python (when available)
pip install ruoyi-ai-sdk[sse] # unused; SDK ships its own SSE parser
pip install ruoyi-ai-sdk[dev] # pytest, respx, ruff, freezegun, ...
Quickstart
from ruoyi_ai_sdk import EngineClient
from ruoyi_ai_sdk.models.openai import ChatRequest, ChatMessage
client = (
EngineClient.builder()
.base_url("https://your-engine.example.com")
.api_key("sk-xxxxxxxx")
.timeout(15.0)
.logging(enabled=True)
.build()
)
info = client.health.check()
print(info.status)
resp = client.chat.block(
ChatRequest(
model="gpt-4o-mini",
messages=[ChatMessage.system("You are helpful."), ChatMessage.user("Hi!")],
)
)
print(resp.choices[0].message.content)
client.close()
Async API
import asyncio
from ruoyi_ai_sdk import AsyncEngineClient
from ruoyi_ai_sdk.models.openai import ChatRequest, ChatMessage
async def main():
async with (
AsyncEngineClient.builder()
.base_url("https://your-engine.example.com")
.api_key("sk-xxxxxxxx")
.build() as client
):
resp = await client.chat.block(
ChatRequest(model="gpt-4o-mini", messages=[ChatMessage.user("hi")])
)
print(resp.choices[0].message.content)
asyncio.run(main())
Endpoints
| Method | Path | Client |
|---|---|---|
GET |
/openapi/health |
client.health.check() |
GET |
/openapi/chat/msg/list |
client.chat_record.list_messages(query, page_num, page_size) |
GET |
/openapi/chat/msg/result |
client.chat_record.get_message_result(msg_id, member_id) |
GET |
/openapi/chat/msg/clear |
client.chat_record.clear_messages(member_id, session_id) |
POST |
/openapi/chat/msg/feedback |
client.chat_record.submit_feedback(feedback) |
GET |
/openapi/model/providers |
client.provider.list_providers() |
GET |
/openapi/model/list |
client.provider.list_models() |
GET |
/openapi/model/tree |
client.provider.get_tree() |
GET |
/openapi/trace/{traceId} |
client.trace.get_chain(trace_id) |
GET |
/openapi/trace/page |
client.trace.page(query, page_num, page_size) |
POST |
/openapi/proxy-model/chat/completions (block) |
client.chat.block(request) |
POST |
/openapi/proxy-model/chat/completions (stream) |
client.chat.stream(request) |
POST |
/openapi/proxy-model/embeddings |
client.embedding.create(request) |
POST |
/openapi/proxy-model/rerank |
client.rerank.rerank(request) |
POST |
/openapi/proxy-agent/chat (block) |
client.agent.forward_block(app_id, body) |
POST |
/openapi/proxy-agent/chat (stream) |
client.agent.forward_stream(app_id, body) |
POST |
/openapi/proxy-agent/chat (async) |
client.agent.forward_async(app_id, body) |
Streaming
Chat (OpenAI-compatible chunks)
for chunk in client.chat.stream(
ChatRequest(model="gpt-4o-mini", messages=[ChatMessage.user("hi")])
):
for choice in chunk.choices:
if choice.delta.content:
print(choice.delta.content, end="", flush=True)
Chat (stream + aggregate into one response)
If you want the live token flow and a single ChatResponse at the end
(the same shape you'd get from chat.block(...)), use stream_block:
from ruoyi_ai_sdk.streaming.chat_accumulator import PartialContent
def on_token(ev):
if isinstance(ev, PartialContent):
print(ev.text, end="", flush=True)
resp = client.chat.stream_block(
ChatRequest(model="gpt-4o-mini", messages=[ChatMessage.user("hi")]),
on_partial=on_token,
)
print()
# resp.choices[0].message.content is the full assembled string
# resp.choices[0].finish_reason / resp.usage are also captured
The accumulator (also exported as ChatChunkAccumulator for callers that
want to drive the iteration themselves) handles tool-call streaming
(grouping deltas by index, joining partial arguments JSON), reasoning
content (DeepSeek / o1 style), and usage on the final chunk. Mirrors
the Java SDK's EventCallBackChat.
Agent forward (custom event types)
from ruoyi_ai_sdk.streaming.agent_events import AgentEvent, AgentEventAdapter
class PrintCallback(AgentEventAdapter):
def on_thinking(self, event: AgentEvent) -> None:
print(f"[thinking] {event.data}")
def on_message(self, event: AgentEvent) -> None:
print(f"[message] {event.data}")
def on_complete(self) -> None:
print("[done]")
for event in client.agent.forward_stream(
"your-app-id", {"question": "hi"}, callback=PrintCallback()
):
pass
Multi-server & discovery
from ruoyi_ai_sdk.discovery import StaticDiscovery, make_nacos_discovery_http
from ruoyi_ai_sdk.loadbalancer import RoundRobinLoadBalancer
from ruoyi_ai_sdk.circuit_breaker import CircuitBreaker
# Static round-robin across three servers:
client = (
EngineClient.builder()
.servers(["https://engine-a", "https://engine-b", "https://engine-c"])
.load_balancer(RoundRobinLoadBalancer())
.circuit_breaker(CircuitBreaker(failure_threshold=5, recovery_interval=60.0))
.api_key("sk-xxx")
.build()
)
# Nacos-backed discovery:
nacos = make_nacos_discovery_http(
server_addr="http://nacos:8848",
namespace="public",
service_name="openapi",
)
client = (
EngineClient.builder()
.discovery(nacos)
.api_key("sk-xxx")
.build()
)
Timeouts
The SDK exposes three knobs (mirrors the Java AiTimeout constants):
| Knob | Default | Used for |
|---|---|---|
connect_timeout |
5s | TCP / TLS handshake (httpx.Timeout(connect=...)) |
call_timeout |
30s | read / write / pool for blocking HTTP calls |
stream_timeout |
120s | read / write / pool for SSE streams |
client = (
EngineClient.builder()
.base_url("https://engine.example.com")
.api_key("sk-xxx")
# Pick any of:
.timeout(15.0) # shortcut for call_timeout
.connect_timeout(2.0)
.call_timeout(15.0)
.stream_timeout(180.0)
.build()
)
EngineTimeoutError is raised on either the connect or read deadline.
Errors
from ruoyi_ai_sdk import (
EngineClientError,
EngineAPIError, # non-2xx HTTP
EngineBusinessError, # server-side business error (R.code != 200)
EngineTimeoutError,
EngineConnectionError,
EngineConfigError,
)
try:
client.chat.block(req)
except EngineBusinessError as e:
print(f"server-side error {e.code}: {e.msg}")
except EngineAPIError as e:
print(f"HTTP {e.status_code}: {e.body}")
Examples
See examples/ for runnable scripts:
01_health.py— health check02_chat_block.py— blocking chat03_chat_stream.py— streaming chat04_embedding.py— embeddings05_rerank.py— rerank06_agent_block.py— agent forward (blocking)07_agent_stream.py— agent forward (streaming)08_async_full.py— async tour09_multi_server_lb.py— multi-server round-robin10_nacos_discovery.py— Nacos discovery
Development
git clone https://github.com/yanzhao/ruoyi-ai
cd ruoyi-ai/ruoyi-ai-sdk
pip install -e ".[dev]"
ruff check src tests
ruff format --check src tests
pytest -q --cov=ruoyi_ai_sdk --cov-report=term-missing
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ruoyi_ai_sdk-0.3.0.tar.gz.
File metadata
- Download URL: ruoyi_ai_sdk-0.3.0.tar.gz
- Upload date:
- Size: 57.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ec075f1a45e5b52e960ffecfb3d51193cc961ae015e77c3076a5ce252dd724e
|
|
| MD5 |
e246d10732c564cab658097fec1961b8
|
|
| BLAKE2b-256 |
80cfedea990019237c29f4df5fbb58c9fe57c1c4fa39856f5e7fb3e4a6aea9c0
|
File details
Details for the file ruoyi_ai_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: ruoyi_ai_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 62.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cfc308a9b724eb6d8a904a39459021aa90a66fb30795f58b431482471a9a6292
|
|
| MD5 |
2a4d41f47f7e4171a3e4e1497a680f6e
|
|
| BLAKE2b-256 |
a5d806433dbad6339fa8a78e131df3e810576f1e00ee407174adc6a92db27395
|