SDK 与代码示例
从 OpenAPI 规范生成类型化客户端并调用 API
Clouisle 不发布官方 SDK(Python、JavaScript、Go、Ruby 等均无)。API 是标准的 REST + JSON 接口,所有请求使用 https://your-domain.com/api/v1 基础路径、JSON 请求/响应体,并在 Authorization 请求头中携带 Bearer JWT 或 clou_ 开头的 API Key。响应使用统一信封 {"code": 0, "data": ..., "msg": "success"},使用 data 前先检查 code。
获取 OpenAPI 规范
| 入口 | 地址 |
|---|---|
| Swagger UI | https://your-domain.com/docs |
| OpenAPI JSON | https://your-domain.com/api/v1/openapi.json |
需要类型化客户端时,用 openapi-generator 或 openapi-typescript 从 OpenAPI JSON 自行生成:
# TypeScript 类型
npx openapi-typescript https://your-domain.com/api/v1/openapi.json -o api.d.ts
# Python 客户端
openapi-generator generate -i https://your-domain.com/api/v1/openapi.json -g python -o ./client认证
登录接口 POST /api/v1/login/access-token 使用表单编码的 username 与 password,返回的 Token 有效期由站点设置 session_timeout_days 决定(默认 30 天),没有刷新端点,临近过期重新登录即可。服务端之间的调用建议使用 API Key(通过界面或 POST /api/v1/api-keys 创建),同样以 Bearer 方式发送:
export CLOUISLE_API_KEY="clou_your_full_key_here"
curl -X GET "https://your-domain.com/api/v1/agents" \
-H "Authorization: Bearer $CLOUISLE_API_KEY"TypeScript 最小示例
const API_BASE = 'https://your-domain.com/api/v1';
const headers = {
Authorization: `Bearer ${process.env.CLOUISLE_API_KEY}`,
'Content-Type': 'application/json',
};
// 列出 Agent(分页信封见 ./conventions)
const listRes = await fetch(`${API_BASE}/agents?page=1&page_size=20`, { headers });
const listBody = await listRes.json();
if (listBody.code !== 0) throw new Error(listBody.msg);
for (const agent of listBody.data.items) console.log(agent.id, agent.name);
// 运行工作流(异步返回 run_id + stream_url)
const runRes = await fetch(`${API_BASE}/workflows/${workflowId}/run`, {
method: 'POST',
headers,
body: JSON.stringify({ inputs: { customer_email: 'customer@example.com' } }),
});
const runBody = await runRes.json();
console.log(runBody.data.run_id, runBody.data.stream_url);Python 最小示例
import os
import requests
API_BASE = "https://your-domain.com/api/v1"
headers = {"Authorization": f"Bearer {os.getenv('CLOUISLE_API_KEY')}"}
# 登录换取 JWT(表单编码)
login = requests.post(
f"{API_BASE}/login/access-token",
data={"username": "your_username", "password": "your_password"},
).json()
token = login["data"]["access_token"]
# 用 JWT 聊天(会话隐式创建,传 conversation_id 继续同一会话)
chat = requests.post(
f"{API_BASE}/agents/{agent_id}/chat",
headers={"Authorization": f"Bearer {token}"},
json={"message": "Hello! I need help with my order.", "conversation_id": None, "variables": {}},
).json()
print(chat["data"]["conversation_id"], chat["data"]["message"]["content"])
# 检索知识库
search = requests.post(
f"{API_BASE}/knowledge-bases/{kb_id}/search",
headers=headers,
json={"query": "How to reset password?", "search_mode": "hybrid", "top_k": 5},
).json()
for item in search["data"]["results"]:
print(item["document_name"], item["score"])流式聊天(SSE)
POST /api/v1/agents/{agent_id}/chat/stream 返回 text/event-stream,事件含 content_delta 与 message_end。完整事件表见 流式事件:
const response = await fetch(
`https://your-domain.com/api/v1/agents/${agentId}/chat/stream`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
Accept: 'text/event-stream',
},
body: JSON.stringify({ message: 'Tell me a story', conversation_id: null, variables: {} }),
}
);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
let eventType = '';
for (const line of lines) {
if (line.startsWith('event: ')) eventType = line.slice(7);
else if (line.startsWith('data: ') && eventType) {
const data = JSON.parse(line.slice(6));
if (eventType === 'content_delta') process.stdout.write(data.delta);
if (eventType === 'message_end') console.log('\n[Done]');
eventType = '';
}
}
}错误处理
校验失败返回 HTTP 422,data.errors 为字段到消息列表的字典。先判断 code 再使用 data:
result = requests.post(
f"{API_BASE}/agents",
headers={"Authorization": f"Bearer {token}"},
json={"name": "x"}, # 缺少必填的 team_id
).json()
if result["code"] != 0:
if result["code"] == 1001:
for field, messages in result["data"]["errors"].items():
print(f"{field}: {', '.join(messages)}")
else:
print(f"Error {result['code']}: {result['msg']}")相关文档
这篇文章对你有帮助吗?