API接入指南——用Python/JS调用EIOS接口

API接入指南——用Python/JS调用EIOS接口

宝软数字 · 实操教程·进阶玩法 · 2025-11-17

一、API概览——你能用API做什么以及API的组织结构

截至目前,我们的教程都在讲述「在EIOS平台内部」怎么使用各项功能。但还有一类使用场景:你已经有了一套自己的系统——可能是自研的ERP、可能是钉钉上的自定义应用、可能是一个数据看板——你想把EIOS的AI能力嵌入到你现有的系统里,而不是让用户跑到EIOS平台上来操作。这时你就需要API。

EIOS的RESTful API按功能域组织为六大模块,覆盖了平台的全部核心能力:

数据API:数据集的创建、查询、更新、删除。数据的导入(支持文件上传和流式推送)、数据的查询(支持条件过滤、聚合、分页)、数据集的导出。API地址前缀:https://api.isoftbao.com/v1/data。

Agent API:Agent的创建与配置、触发Agent执行任务、查询Agent的执行状态和结果、管理Agent的生命周期(启动/暂停/删除)。API地址前缀:https://api.isoftbao.com/v1/agents。

分析API:调用AI执行特定的分析任务——销售预测、异常检测、趋势分析、根因分析、文本摘要。你可以直接调用分析能力,而不需要先创建一个持久化的Agent。API地址前缀:https://api.isoftbao.com/v1/analytics。

报告API:生成和导出各类报告——月度经营报告、自定义报表、图表数据。支持PDF和Excel导出格式。API地址前缀:https://api.isoftbao.com/v1/reports。

用户与权限API:管理用户账号、角色、权限。支持SSO集成和企业微信/钉钉的组织架构同步。API地址前缀:https://api.isoftbao.com/v1/users。

通知API:发送各类通知——邮件、短信、企业微信、钉钉。支持模板化消息和批量发送。API地址前缀:https://api.isoftbao.com/v1/notifications。

这篇教程不会逐一罗列所有接口(完整的API Reference文档在开发者中心 https://www.isoftbao.com/docs/api 可以查阅),而是聚焦在最实用的5个场景,给出可以直接复制使用的Python和JavaScript代码。从获取API密钥开始,到完整的错误处理结束。

EIOS API六大模块总览——数据、Agent、分析、报告、用户、通知
API的使用前提:你需要对HTTP协议和RESTful API有基本了解,并且熟悉至少一种编程语言(Python或JavaScript)。本教程假设你具备这些基础知识。如果你完全零基础,建议先学习一下Python的requests库或JavaScript的fetch API的基础用法。

二、获取API密钥——认证与安全配置是第一步

所有API调用都需要认证。EIOS使用API Key加签名的双重认证机制,确保即使API Key泄露,没有签名私钥也无法伪造请求。

第一步:生成API Key。登录EIOS → 右上角头像 → 「开发者中心」→「API管理」→ 点击「创建API Key」。填写Key的名称(便于你区分不同用途的Key,如「ERP对接」「数据看板」「自动化脚本」),选择Key的权限范围(强烈建议按最小权限原则创建——只勾选该Key实际需要的API模块)。点击创建后,系统生成一个Access Key ID(公开标识,类似用户名)和一个Access Key Secret(密钥,类似密码)。

重要警告:Access Key Secret只在创建时显示一次,请立即复制并保存到安全的地方(如密码管理器或环境变量中)。如果丢失,只能重新生成新的Key。绝对不要将Secret硬编码在源代码中提交到Git仓库!使用环境变量或密钥管理服务。

第二步:理解签名机制。每个API请求需要在HTTP Header中携带以下认证信息:X-Access-Key-Id(你的Access Key ID)、X-Timestamp(请求发出的Unix时间戳,秒级)、X-Signature(请求签名)。签名通过HMAC-SHA256算法生成。Python示例代码如下:

import hmac
import hashlib
import time
import requests

ACCESS_KEY_ID = "你的Access Key ID"
ACCESS_KEY_SECRET = "你的Access Key Secret"

def build_signature(method, path, body, timestamp):
    """构建请求签名"""
    message = f"{method}\n{path}\n{body}\n{timestamp}"
    signature = hmac.new(
        ACCESS_KEY_SECRET.encode('utf-8'),
        message.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    return signature

def api_request(method, path, body=""):
    """发送带签名的API请求"""
    timestamp = str(int(time.time()))
    signature = build_signature(method, path, body, timestamp)

    headers = {
        "X-Access-Key-Id": ACCESS_KEY_ID,
        "X-Timestamp": timestamp,
        "X-Signature": signature,
        "Content-Type": "application/json"
    }

    url = f"https://api.isoftbao.com{path}"
    response = requests.request(method, url, headers=headers, data=body)
    return response.json()

第三步:验证连接。运行一个最简单的API调用来验证你的Key配置正确。调用健康检查接口GET /v1/health,不需要参数,不需要签名。如果返回状态码200和服务器状态信息,说明网络连通性没问题。然后再调用一个需要签名的接口(如GET /v1/data/datasets)来验证签名机制正确。

API Key生成页面——Key权限配置和安全提醒
签名机制的价值:即使攻击者截获了你的API请求(比如在不安全的网络中),他拿到了Access Key ID和时间戳,但没有Access Key Secret,无法伪造签名。更重要的是,时间戳机制可以防止重放攻击——每个签名在5分钟内有效,过了5分钟旧签名自动失效。这就是为什么我们要求你在每个请求的Header中都携带当前时间戳。

三、Python调用实战——5个最常用的业务场景

以下是5个最常见的API使用场景,每个都配有完整的Python代码示例。你可以直接复制到你的项目中,替换参数即可使用。

场景一:导入销售数据。你的ERP系统每天生成销售数据CSV文件,你想让这些数据自动流入EIOS供Agent分析。使用数据导入API,支持文件上传。

def import_sales_data(csv_file_path):
    """将CSV销售数据导入EIOS"""
    path = "/v1/data/datasets/import"
    timestamp = str(int(time.time()))

    # 文件上传使用multipart/form-data格式
    with open(csv_file_path, 'rb') as f:
        files = {'file': ('sales_data.csv', f, 'text/csv')}
        data = {
            'dataset_name': 'ERP销售数据',
            'domain': 'sales',
            'date_column': 'order_date',
            'encoding': 'utf-8'
        }

        # 文件上传的签名逻辑略有不同,body取JSON序列化的data部分
        body_str = json.dumps(data)
        signature = build_signature('POST', path, body_str, timestamp)

        headers = {
            "X-Access-Key-Id": ACCESS_KEY_ID,
            "X-Timestamp": timestamp,
            "X-Signature": signature
        }

        response = requests.post(
            f"https://api.isoftbao.com{path}",
            headers=headers,
            files=files,
            data=data
        )
        return response.json()

场景二:触发Agent执行分析。你的系统在某个业务流程完成后(如月度结账完成),自动触发对应的Agent执行分析,并获取分析结果。

def trigger_agent(agent_id, params=None):
    """触发指定Agent执行任务"""
    path = "/v1/agents/execute"
    body = json.dumps({
        "agent_id": agent_id,
        "params": params or {},
        "async_mode": False  # False=同步等待结果, True=异步立即返回任务ID
    })

    result = api_request('POST', path, body)

    if result.get('success'):
        if result.get('async_mode'):
            task_id = result['data']['task_id']
            print(f"任务已提交,task_id: {task_id},稍后查询结果")
            return task_id
        else:
            analysis_result = result['data']['output']
            print("分析完成!")
            print(analysis_result)
            return analysis_result
    else:
        print(f"执行失败: {result.get('error', {}).get('message')}")

def query_task_result(task_id):
    """查询异步任务的结果"""
    path = f"/v1/agents/tasks/{task_id}"
    result = api_request('GET', path)

    status = result['data']['status']
    if status == 'completed':
        return result['data']['output']
    elif status == 'failed':
        print(f"任务失败: {result['data']['error']}")
        return None
    else:
        print(f"任务状态: {status},请稍后再查询")
        return None

场景三:查询数据集并进行聚合分析。你的数据看板需要展示本月各产品线的销售额汇总。直接通过API查询并聚合数据,不经过EIOS的前端页面。

def query_monthly_sales_by_product(date_from, date_to):
    """查询指定日期范围内的销售额,按产品线聚合"""
    path = "/v1/data/query"
    body = json.dumps({
        "dataset_id": "ds_sales_orders",
        "filters": [
            {"field": "order_date", "operator": "between", "value": [date_from, date_to]}
        ],
        "group_by": ["product_line"],
        "aggregates": [
            {"field": "amount", "function": "sum", "alias": "total_revenue"},
            {"field": "quantity", "function": "sum", "alias": "total_quantity"},
            {"field": "order_id", "function": "count", "alias": "order_count"}
        ],
        "order_by": [{"field": "total_revenue", "direction": "desc"}],
        "limit": 20
    })

    result = api_request('POST', path, body)

    if result.get('success'):
        rows = result['data']['rows']
        for row in rows:
            product = row['product_line']
            revenue = row['total_revenue']
            print(f"{product}: ¥{revenue:,.2f}")
        return rows
    return []

场景四:生成月度经营报告并导出PDF。每月自动生成经营分析报告,导出为PDF文件保存到指定路径。

def generate_monthly_report(year, month):
    """生成指定月份的月度经营分析报告PDF"""
    # 1. 提交报告生成请求
    path = "/v1/reports/generate"
    body = json.dumps({
        "template_id": "tpl_monthly_business",
        "params": {
            "year": year,
            "month": month
        },
        "format": "pdf"
    })

    result = api_request('POST', path, body)

    if not result.get('success'):
        print(f"报告生成请求失败: {result.get('error')}")
        return None

    report_id = result['data']['report_id']
    print(f"报告生成任务已提交,report_id: {report_id}")

    # 2. 轮询等待报告生成完成
    import time as time_mod
    for _ in range(30):  # 最多等待30轮
        time_mod.sleep(2)
        path = f"/v1/reports/{report_id}"
        status_result = api_request('GET', path)

        if status_result['data']['status'] == 'completed':
            download_url = status_result['data']['download_url']

            # 3. 下载PDF文件
            # 注意:下载URL不需要API签名
            pdf_response = requests.get(download_url)
            filename = f"monthly_report_{year}_{month:02d}.pdf"
            with open(filename, 'wb') as f:
                f.write(pdf_response.content)
            print(f"报告已下载: {filename}")
            return filename

        elif status_result['data']['status'] == 'failed':
            print("报告生成失败")
            return None

    print("报告生成超时")
    return None

场景五:批量查询多个Agent的执行状态。你有多个Agent在同时运行,需要在管理后台展示它们的状态。批量查询API可以一次获取所有Agent的最新状态。

def get_agents_status(agent_ids):
    """批量查询多个Agent的当前状态"""
    path = "/v1/agents/status/batch"
    body = json.dumps({
        "agent_ids": agent_ids
    })

    result = api_request('POST', path, body)

    if result.get('success'):
        status_map = {}
        for item in result['data']['agents']:
            agent_id = item['agent_id']
            status = item['status']
            last_run = item.get('last_run_at', '从未运行')
            task_count = item.get('pending_tasks', 0)
            status_map[agent_id] = {
                'status': status,
                'last_run': last_run,
                'pending_tasks': task_count
            }
            print(f"Agent {agent_id}: {status} | 上次运行: {last_run} | 待处理: {task_count}")
        return status_map
    return {}
Python代码示例——数据导入、Agent触发、数据查询、报告生成、状态批量查询
代码组织建议:把签名逻辑封装成一个独立的模块(如eios_client.py),在你的项目各处引用。不要把Access Key Secret散落在各个文件中——一个统一的客户端模块更容易管理和审计。最好把这个客户端模块打包成一个内部Python包,通过pip安装到各个项目中。

四、JavaScript调用实战——前端集成与Node.js后端

如果你的系统是Web应用,你可能需要在浏览器端或Node.js后端调用EIOS API。以下是两个最常用的JavaScript集成场景。

场景一:Node.js后端调用EIOS API(推荐方案)。生产环境中强烈建议API调用在后端进行,避免Access Key Secret暴露在前端代码中。使用Express框架作为中间层,前端请求你的后端,你的后端请求EIOS API。

// eios-client.js - Node.js EIOS API客户端
const crypto = require('crypto');
const https = require('https');

const ACCESS_KEY_ID = process.env.EIOS_ACCESS_KEY_ID;
const ACCESS_KEY_SECRET = process.env.EIOS_ACCESS_KEY_SECRET;
const API_BASE = 'api.isoftbao.com';

function buildSignature(method, path, body, timestamp) {
  const message = `${method}\n${path}\n${body}\n${timestamp}`;
  return crypto
    .createHmac('sha256', ACCESS_KEY_SECRET)
    .update(message)
    .digest('hex');
}

async function apiRequest(method, path, body = '') {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const signature = buildSignature(method, path, body, timestamp);

  return new Promise((resolve, reject) => {
    const options = {
      hostname: API_BASE,
      path: path,
      method: method,
      headers: {
        'X-Access-Key-Id': ACCESS_KEY_ID,
        'X-Timestamp': timestamp,
        'X-Signature': signature,
        'Content-Type': 'application/json'
      }
    };

    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => resolve(JSON.parse(data)));
    });

    req.on('error', reject);
    if (body) req.write(body);
    req.end();
  });
}

// Express路由示例:前端通过你的后端查询数据
app.get('/api/eiose/sales-summary', async (req, res) => {
  try {
    const result = await apiRequest('POST', '/api/v1/data/query', JSON.stringify({
      dataset_id: 'ds_sales',
      group_by: ['product_category'],
      aggregates: [{ field: 'amount', function: 'sum', alias: 'total' }]
    }));
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

场景二:前端直接调用(仅适用于低安全场景)。如果你需要在浏览器中直接调用EIOS API(比如一个内部管理工具),请务必使用临时令牌而非永久API Key。临时令牌由后端生成,有效期短(默认15分钟),只能用于特定操作。

// 前端JavaScript - 使用临时Token调用EIOS API
async function fetchWithToken(path, options = {}) {
  // 1. 先从你的后端获取临时Token
  const tokenResponse = await fetch('/api/eiose/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      scope: options.scope || 'read',
      resource: options.resource || ''
    })
  });

  const { token } = await tokenResponse.json();

  // 2. 使用临时Token调用EIOS API
  const response = await fetch(`https://api.isoftbao.com${path}`, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  });

  return response.json();
}

// 使用示例:获取某Agent的分析报告
async function getAnalysisReport(agentId) {
  const report = await fetchWithToken(`/api/v1/agents/${agentId}/reports/latest`, {
    scope: 'read',
    resource: `agent:${agentId}`
  });

  document.getElementById('report-container').innerHTML =
    report.data.summary;
}
Node.js后端调用和前端安全调用的代码架构对比
前端安全的底线:永远不要把Access Key Secret放在前端代码中。即使你用了代码混淆、环境变量、构建时替换——浏览器的运行环境本质上是不安全的,任何在前端出现的密钥都可能被提取。唯一的正确做法是通过后端生成临时令牌。如果你的业务场景无法满足这个要求(比如纯静态网站没有后端),那么至少使用一个Cloudflare Worker或Vercel Edge Function作为轻量级的中间代理层。

五、错误处理与重试机制——让API调用生产级可靠

在开发和测试环境中,API调用几乎总是成功的。但在生产环境中,网络抖动、服务器限流、数据量过大、并发冲突等问题会频繁出现。一套健壮的错误处理和重试机制是生产级集成的必备要素。

EIOS API的错误码体系:所有API响应都包含统一的错误结构。HTTP状态码400表示客户端错误(参数错误、格式错误),401表示认证失败(Key过期或签名错误),403表示权限不足(Key没有该操作的权限),429表示请求过于频繁(触发了限流),500表示服务器内部错误。响应体中的error.code字段提供了更细粒度的错误码,如DATA_NOT_FOUND(数据不存在)、AGENT_BUSY(Agent正在执行其他任务)、RATE_LIMIT_EXCEEDED(超出调用频率限制)。

指数退避重试策略:对于可重试的错误(网络超时、服务器500、429限流),使用指数退避策略。不可重试的错误(401认证失败、403权限不足、400参数错误)应该立即失败并记录日志。Python实现:

import random
import time as time_mod

RETRYABLE_ERRORS = {'NETWORK_TIMEOUT', 'SERVER_ERROR', 'RATE_LIMIT_EXCEEDED'}
MAX_RETRIES = 3
BASE_DELAY = 1.0  # 基础延迟秒数

def api_request_with_retry(method, path, body=""):
    """带指数退避重试的API请求"""
    for attempt in range(MAX_RETRIES + 1):
        try:
            result = api_request(method, path, body)

            if result.get('success'):
                return result

            error_code = result.get('error', {}).get('code', '')

            # 不可重试错误,直接返回
            if error_code not in RETRYABLE_ERRORS:
                print(f"不可重试错误 [{error_code}],放弃")
                return result

            # 可重试错误,判断是否还有重试次数
            if attempt < MAX_RETRIES:
                # 指数退避: 1s, 2s, 4s + 随机抖动
                delay = BASE_DELAY * (2 ** attempt) + random.uniform(0, 0.5)
                print(f"遇到可重试错误 [{error_code}],{delay:.1f}秒后重试 (第{attempt+1}次)")
                time_mod.sleep(delay)
            else:
                print(f"重试{MAX_RETRIES}次后仍失败")
                return result

        except requests.exceptions.Timeout:
            if attempt < MAX_RETRIES:
                delay = BASE_DELAY * (2 ** attempt)
                print(f"请求超时,{delay:.1f}秒后重试")
                time_mod.sleep(delay)
            else:
                raise  # 重试耗尽,向上抛出异常

限流处理:EIOS API有速率限制。默认情况下,每个API Key每秒钟最多调用10次,每分钟最多调用200次。当你收到429状态码时,响应Header中的Retry-After字段(单位秒)指示了你需要等待多久才能重试。在重试逻辑中优先使用这个值:

if response.status_code == 429:
    retry_after = int(response.headers.get('Retry-After', 5))
    print(f"触发限流,等待{retry_after}秒")
    time_mod.sleep(retry_after)
    # 使用更长的退避间隔重试

批量操作的并发控制:当你需要调用大量API(如批量导入100个文件),不要无脑并发——那样会立即触发限流。使用信号量控制并发数,建议并发数不超过5。

import asyncio

async def batch_import_with_concurrency(file_paths):
    """批量导入文件,并发控制"""
    semaphore = asyncio.Semaphore(5)  # 最多5个并发

    async def import_one(file_path):
        async with semaphore:
            # 在异步环境中调用同步的导入函数
            loop = asyncio.get_event_loop()
            result = await loop.run_in_executor(
                None, import_sales_data, file_path
            )
            return result

    tasks = [import_one(fp) for fp in file_paths]
    results = await asyncio.gather(*tasks, return_exceptions=True)

    success_count = sum(1 for r in results if isinstance(r, dict) and r.get('success'))
    print(f"批量导入完成: {success_count}/{len(file_paths)} 成功")
    return results
错误处理与重试机制——指数退避和并发控制示意图
生产环境的日志是不可或缺的:每一次API调用都记录下:调用时间、API路径、响应状态码、耗时(毫秒)、错误信息(如有)。这些日志在排查问题时是无价之宝——你能精确地回答「上个月销售数据导入失败了多少次?原因都是什么?」而不是「好像有时候失败但我也不知道为什么」。使用结构化日志(JSON格式),方便后续接入日志分析平台。

六、高级用法——Webhook与批量操作的最佳实践

在前面的五个场景之外,还有两个高级用法值得单独说明。

Webhook集成(将在下一篇教程详解):前面的所有场景都是「你的系统主动调用EIOS」。但有时候你需要反过来——当EIOS中的某些事件发生时,EIOS主动通知你的系统。这就是Webhook。例如:当Agent完成一项分析任务,EIOS通过Webhook将结果推送到你的系统;当库存Agent检测到某SKU库存低于安全值,自动推送预警到你的ERP或钉钉群。Webhook让你的系统和EIOS之间从「单向调用」升级为「双向通信」。

批量数据推送(Data Push):如果你的系统每天产生大量数据(如上万条销售记录),使用单条API逐条推送效率太低。使用批量推送接口,一次推送最多1000条记录,系统会在后台异步处理。API路径:POST /v1/data/datasets/{dataset_id}/records/batch。

使用SDK简化开发:如果你不想从头实现签名和重试逻辑,EIOS提供了官方Python SDK(pip install eios-sdk)和Node.js SDK(npm install @baodoo/eios-sdk)。SDK封装了认证、签名、重试、并发控制等所有底层逻辑,你只需要关注业务逻辑。完整文档在 https://github.com/baodoo/eios-sdk。

高级用法总览——Webhook、批量推送、SDK简化开发
选择调用方式的决策树:如果你的系统需要「定时拉取EIOS数据」(如每天凌晨同步一次销售数据),用API主动调用。如果你的系统需要「实时响应EIOS事件」(如Agent一完成分析就通知),用Webhook。如果你的系统需要「高频、大批量写入数据」,用批量推送接口加并发控制。如果你的团队没有精力处理底层API细节,用官方SDK。不同的需求有对应的最优方式,不要用一种方式解决所有问题。

API是EIOS平台开放能力的核心通道。通过API,你可以把EIOS的AI能力无缝嵌入到已有的业务系统中,而不是让用户在不同的平台间来回切换。下一篇(也是进阶玩法的收官教程)我们将专门讲解Webhook配置——如何让EIOS主动推送到你的系统,实现真正的双向智能联动。

准备好把你的系统和EIOS打通了吗?

免费试用EIOS,获取你的API Key开始集成

免费试用