返回结果¶
MOI Catalog Service 的常规 JSON 响应使用 code、msg、data 和 request_id 信封。SDK 会检查 HTTP 状态与业务 code,成功时只把解码后的 data 返回给调用者。因此业务代码通常直接处理资源对象,不需要再拆一层信封。
处理普通结果与错误¶
Python 的 RawClient 多数方法返回字典、列表或 None:
from moi.errors import APIError, HTTPError
try:
catalog = client.get_catalog({"id": 101})
print(catalog["name"])
except APIError as exc:
print(exc.code, exc.message, exc.request_id)
except HTTPError as exc:
print(exc.status_code)
Go 方法返回公开的响应类型和 error:
catalog, err := client.GetCatalog(ctx, &sdk.CatalogInfoRequest{
CatalogID: 101,
})
if err != nil {
var apiErr *sdk.APIError
var httpErr *sdk.HTTPError
switch {
case errors.As(err, &apiErr):
log.Printf("code=%s request_id=%s", apiErr.Code, apiErr.RequestID)
case errors.As(err, &httpErr):
log.Printf("http_status=%d", httpErr.StatusCode)
default:
log.Printf("request failed: %v", err)
}
return
}
fmt.Println(catalog.CatalogName)
非 2xx 响应是 HTTPError;2xx 响应中业务 code 不表示成功时是 APIError。Go SDK 不区分 OK 的大小写,Python SDK 当前精确匹配 OK。解码失败、超时和取消属于其它错误。重试前应先分类:认证、权限、参数和确定性的业务错误不应盲目重试。
LLM Proxy 方法是已确认的例外:它们直接解码返回内容,不使用上述信封。调用这组方法时应按其公开类型处理。
按具体接口分页¶
SDK 没有统一的自动分页迭代器。多数 Catalog 列表在请求体的 common_condition 中使用从 1 开始的 page 和 page_size,响应返回资源列表与 total;部分方法使用顶层分页字段或查询参数。
下面示例按角色列表的已公开结构翻页:
page = 1
page_size = 100
while True:
result = client.list_roles({
"keyword": "",
"common_condition": {
"page": page,
"page_size": page_size,
"order": "desc",
"order_by": "created_at",
"filters": [],
},
})
roles = result.get("role_list") or result.get("list") or []
for role in roles:
print(role["name"])
total = result.get("total", 0)
if len(roles) < page_size or (total and page * page_size >= total):
break
page += 1
实现分页时应同时设置最大页数,防止异常返回造成无限循环。不要把 common_condition 机械套到所有方法:例如工作流作业列表使用顶层 page / page_size,知识条目使用 page_number / page_size,LLM 消息列表还可以使用 after / limit。以对应公开请求类型和方法文档为准。
下载 FileStream¶
表数据、文件预览和 GenAI 结果等下载方法返回 FileStream,不会把整个响应自动读入内存。调用者必须关闭流。
Python 可以使用上下文管理器:
with client.download_table_data({"id": 301}) as stream:
written = stream.write_to_file("/tmp/orders.csv")
print(f"wrote {written} bytes")
也可以用 iter_content(chunk_size) 分块处理。Go 使用 defer:
stream, err := client.DownloadTableData(ctx, &sdk.TableDownloadDataRequest{
ID: 301,
})
if err != nil {
return err
}
defer stream.Close()
written, err := stream.WriteToFile("/tmp/orders.csv")
FileStream 暴露响应状态和头信息。文件很大时优先流式写入,不要先 read() / io.ReadAll 全部载入内存。
消费数据分析 SSE¶
analyze_data_stream / AnalyzeDataStream 返回数据分析的 Server-Sent Events。事件可能包含初始化、问题分类、处理步骤和完成信息;以事件对象的 type、step_type、step_name 和 data 为准。
Python:
from moi import with_stream_read_timeout
stream = client.analyze_data_stream(
{
"question": "按地区汇总销售额",
"config": {
"data_category": "admin",
"data_source": {"type": "all"},
},
},
with_stream_read_timeout(60.0),
)
try:
while True:
event = stream.read_event()
if event is None:
break
print(event.type, event.step_type, event.data)
finally:
stream.close()
流读取超时表示两条消息之间允许等待的时间,默认 30 秒;它不同于普通 HTTP 请求的总超时。Go 对应使用 WithStreamReadTimeout 和流的 ReadEvent,并通过 context 取消整个调用。
EOF 只说明连接已结束。应用应根据收到的完成事件决定业务是否成功;若超时、取消或解析错误发生在完成事件之前,把结果标记为中断,而不是成功。