后端 Agent HTTP/SSE API 参考(完全自定义方案)
面向不用 Flutter SDK、自建 UI 的集成方(Web / React Native / 原生 / 后端代理)。直连 ai-boss 后端的 HTTP + SSE 接口,自己渲染对话与业务卡片。
用 Flutter?直接用《Agent SDK 对接说明》更快(它封装了这里的全部)。
0. 概览
你的 UI ──HTTP/SSE──▶ ai-boss 后端 ──连接器──▶ NearBoss / 业务网关
(本文档) (上游 BFF,见下)
- 本文档 = 你和 ai-boss 后端 的契约(
/api/v1/agent/*)。 - 上游 BFF(
docs/外部 api/2026-06-10-aigent-AI对接说明.md,minipos-aigent)是 ai-boss 后端再往下调的 NearBoss 接口——你不直接对接它。两者别混。
支持两个专家:营销专家 promo-designer、数据专家 data-analyst。一个 SSE 入口承载对话 + 流式文本 + 结构化卡片;营销活动的确认 / 生命周期走独立的同步端点。
1. 通用约定
1.1 Base URL
所有路径以 ai-boss 后端根地址为前缀,统一 /api/v1。例:https://api.example.com/api/v1/agent/chat。
1.2 认证头(每个请求都带)
| 头 | 必填 | 说明 |
|---|---|---|
X-Merchant-Id | 是 | 商家 ID(租户隔离)。缺 → 401。 |
X-Store-Id | 否 | 门店 ID(scope;部分工具需要) |
X-User-Id | 否 | 用户 ID(审计) |
X-Role | 否 | boss / store_manager / staff / ops / admin(默认 boss) |
X-Plan | 否 | 套餐(默认 basic) |
Accept-Language | 否 | zh / en / ar(影响返回文案语言) |
X-Trace-Id | 否 | 链路追踪 ID;不传则后端自动生成并回显 |
Content-Type | 是 | application/json |
自定义鉴权(JWT 等)按你的网关约定附加
Authorization,但租户隔离仍需X-Merchant-Id。
1.3 SSE 帧格式
对话端点返回 Content-Type: text/event-stream,每个事件一帧:
event: <事件名>
data: <一行 JSON>
(事件名 + JSON 数据 + 空行分隔。)以 final(或 plan_final)事件标记流结束,随后连接关闭。
1.4 trace_id
每个请求生成唯一 trace_id,回显在响应头 X-Trace-Id、SSE final 事件、后端日志——排障时提供它即可全链路定位。
1.5 统一错误格式(非 SSE 端点)
HTTP <status>
{
"error_code": "AUTH_INVALID",
"message": "人类可读说明",
"kind": "auth|authz|quota|validation|biz|system",
"trace_id": "…"
}
2. 对话主端点(SSE)
POST /api/v1/agent/chat
Content-Type: application/json
Accept: text/event-stream
2.1 请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
message | string | 是 | 用户问题 / 指令 |
agent_id | string | 否 | 指定专家(promo-designer / data-analyst…)。省略 → 路由器按意图自动分流 |
conversation_id | string | 否 | 续聊会话 ID;省略则自动新建并在首帧回传 |
entry | string | 否 | 场景入口 ID(优先级高于 agent_id) |
context | object | 否 | 上下文;营销编辑续聊时带 {"draft": {…前轮活动草稿}} 防覆盖 |
choose_expert | bool | 否 | 「换个专家」:返回候选专家列表让用户选,不自动重路由 |
exclude_agents | string[] | 否 | 重路由时避开的专家 |
plan_run_id | string | 否 | 多步规划续跑 ID |
resume | object | 否 | 审批 / 补答续跑参数 |
2.2 响应
HTTP 200 + SSE 流。首帧总是 conversation(携 conversation_id),随后按对话进展推送 token / 卡片 / 控制事件,以 final 收尾。
3. SSE 事件类型与 payload
| 事件 | 何时 | data 关键字段 | UI 该做什么 |
|---|---|---|---|
conversation | 首帧 | {conversation_id} | 存下,用于续聊 |
step | 阶段 / 工具调用 | {phase, agent, agent_name, tool?, ok?} | 可选:展示「正在查询…」 |
token | LLM 逐字 | {text} | 追加到当前助手气泡 |
action_card | 结构化输出 | 见 §3.1 | 渲染业务卡片 |
final | 流尾(必发) | {answer, cost_usd?, trace_id} | 收尾;流结束 |
clarify | 路由低置信 / 缺信息 | {message, candidates[], kind} | 渲染候选 chip 让用户选 |
routed / reroute | 自动 / 决策转接 | {agent, reason} / {from_agent, reason} | 可选:提示「已转接到 X」 |
approval_required | 需人工审批 | {step_id, message, options[]} | 弹确认;用户选择后带 resume 重发 |
ask_user | 需补充信息 | {step_id, message, input_type?} | 收集输入后带 resume 重发 |
plan_created / plan_progress / plan_final | 多步规划 | 计划 DAG / 进度 / 汇总 | 可选:渲染步骤树 |
memory / memory_used / memory_write | 记忆读写 | 已读 / 已用 / 已存的偏好项 | 可选:透明展示「已结合历史偏好」 |
error | 出错 | {error_code, message, trace_id} | 渲染错误气泡,不击穿 |
还有一组
react_*事件属实验中的 ReAct 路径,当前默认不开启,集成时可忽略。
3.1 action_card 结构
{
"id": "card_1",
"title": "活动建议",
"body": "建议做一场招牌秒杀…",
"category": "marketing",
"indicators": [ {"key": "net_income", "value": 12345.6} ],
"chart": {
"type": "line",
"title": "近7天净收入趋势",
"unit": "AED",
"data": [ {"x": "06-09", "y": 1820.5}, … ]
},
"form": { "kind": "nb_campaign", "...": "可编辑草稿字段" },
"buttons": [ {"id":"confirm","label":"确认发布","action":"...","params":{}} ]
}
- 数据卡(数据专家):
indicators+ 可选chart。数字全部来自接口,零推算(后端不自算)。指标域:净收入 / 成功交易 / 退款。 - 营销卡(营销专家):
form.kind决定卡型——nb_type_picker(选活动类型)/nb_campaign(可编辑草稿)/nb_campaign_list(活动列表)/nb_campaign_detail(详情 + 生命周期按钮)。buttons/availableActions驱动操作。
3.2 完整示例流
event: conversation
data: {"conversation_id":"conv_abc"}
event: step
data: {"phase":"start","agent":"promo-designer","agent_name":"营销专家"}
event: token
data: {"text":"根据你的数据,"}
event: action_card
data: {"id":"k1","title":"活动建议","form":{"kind":"nb_campaign"},"buttons":[…]}
event: final
data: {"answer":"根据你的数据,建议做一场招牌秒杀…","cost_usd":0.012,"trace_id":"t_xyz"}
4. 营销确认 / 管理端点(同步,非 SSE)
营销活动遵循 preview→commit 两段式:对话里产出草稿卡(preview),用户确认后调以下端点落地。
4.1 确认发布 / 存草稿
POST /api/v1/agent/nearboss/commit
两种 body:
// A. token 直提(未编辑,卡片按钮已带 preview_token)
{ "surface": "campaign", "preview_token": "…", "action": "PUBLISH", "confirmed": true }
// B. 编辑后提交(改了草稿字段)→ 后端 re-preview→commit
{ "surface": "campaign", "action": "PUBLISH", // PUBLISH | DRAFT
"params": { "activityType": "FLASH_SALE", "activityName": "周末秒杀", "...": "…" } }
surface 取值:campaign(活动)/ member_tag(会员标签)/ member_delete(删会员)/ report_export(报表导出)。
成功 200:
{ "id": "act_1", "status": "PUBLISHED", "activityName": "周末秒杀" }
业务错误(4xx,error_code + message):参见 §6。
4.2 活动生命周期动作
POST /api/v1/agent/nearboss/campaign/action
{ "op": "PAUSE", "id": "act_1", "confirmed": false }
op:PAUSE/RESUME/TERMINATE。TERMINATE不可逆,首次返回AIGENT_CONFIRM_REQUIRED,带confirmed: true重发。- 成功 200:整形后的详情卡(
status/statusLabel/availableActions/metrics)——可直接刷新你的详情卡 UI。
哪些动作可用由返回的
availableActions决定(按状态 DRAFT / PENDING / ACTIVE / PAUSED / ENDED),别在 UI 写死。
5. 历史会话端点
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/v1/conversations?limit=&offset= | 会话列表(按最近活跃) |
GET | /api/v1/conversations/{id}/messages?limit=&before_seq= | 会话消息(游标翻页,含历史 action_card) |
POST | /api/v1/conversations/{id}/archive | 归档会话 |
6. 错误码表
| error_code | HTTP | kind | 含义 / 处理 |
|---|---|---|---|
AUTH_INVALID | 401 | auth | 缺 X-Merchant-Id |
AUTHZ_DENIED | 403 | authz | 角色无权限 |
QUOTA_EXCEEDED | 429 | quota | 配额用尽(可能降级运行) |
VALIDATION | 400 | validation | 入参 / 字段校验失败 |
TOOL_FAILED | 502 | biz | 下游工具 / API 调用失败 |
LLM_UNAVAILABLE | 503 | system | LLM 不可用(SSE 内以 error 事件透出) |
BIZ_UNAVAILABLE | 503 | biz | 业务系统不可用 |
SYS_INTERNAL | 500 | system | 内部错误 |
AIGENT_CONFIRM_REQUIRED | 4xx | validation | 危险操作需二次确认(带 confirmed:true 重发) |
AIGENT_PREVIEW_EXPIRED / TOKEN_EXPIRED | 409 | validation | 预览失效,重走一次 preview |
AIGENT_INVALID_ACTIVITY_TYPE | 400 | validation | 活动类型非法 |
MKT_* | 400 | biz | 上游活动校验(如「全单折扣须 10–99」),message 可直接转述商家 |
7. 专家与活动类型常量
agentId:promo-designer(营销专家)· data-analyst(数据专家)。省略 agent_id 走统一入口自动分流。
4 类营销活动(枚举名与直觉相反,以此为准):
| 枚举 | 含义 | 关键参数 |
|---|---|---|
FLASH_SALE | 秒杀 | 选品 + 秒杀价 |
DIRECT_AMOUNT_OFF | 订单直减 | directAmount 1–999 + 门槛 minOrderAmount |
ORDER_DISCOUNT | 全单折扣 | discountValue 10–99(实付 X%,9 折=90) |
FIRST_ORDER_DISCOUNT | 首单优惠 | discountType + discountValue + 门槛 |
8. cURL 速查
对话(SSE):
curl -N -X POST https://api.example.com/api/v1/agent/chat \
-H 'X-Merchant-Id: M123' -H 'X-Store-Id: B1' -H 'X-Role: boss' \
-H 'Accept-Language: zh' -H 'Content-Type: application/json' \
-d '{"message":"做个全单9折活动","agent_id":"promo-designer"}'
确认发布:
curl -X POST https://api.example.com/api/v1/agent/nearboss/commit \
-H 'X-Merchant-Id: M123' -H 'Content-Type: application/json' \
-d '{"surface":"campaign","action":"PUBLISH","params":{"activityType":"ORDER_DISCOUNT","discountValue":90}}'
终止活动(二次确认):
curl -X POST https://api.example.com/api/v1/agent/nearboss/campaign/action \
-H 'X-Merchant-Id: M123' -H 'Content-Type: application/json' \
-d '{"op":"TERMINATE","id":"act_1","confirmed":true}'
9. 自建 UI 最小实现提示
浏览器端用 fetch + ReadableStream 读 SSE(EventSource 不支持 POST + 自定义头,故用 fetch 手动解帧):
const resp = await fetch(`${BASE}/api/v1/agent/chat`, {
method: 'POST',
headers: { 'X-Merchant-Id': 'M123', 'X-Role': 'boss', 'Content-Type': 'application/json' },
body: JSON.stringify({ message: '本月净收入多少', agent_id: 'data-analyst' }),
});
const reader = resp.body.getReader();
const dec = new TextDecoder();
let buf = '';
for (;;) {
const { value, done } = await reader.read();
if (done) break;
buf += dec.decode(value, { stream: true });
const frames = buf.split('\n\n'); buf = frames.pop(); // 留半帧
for (const f of frames) {
const ev = f.match(/^event: (.+)$/m)?.[1];
const data = JSON.parse(f.match(/^data: (.+)$/m)?.[1] || '{}');
if (ev === 'token') appendText(data.text);
else if (ev === 'action_card') renderCard(data);
else if (ev === 'final') finish(data.answer);
}
}
确认 / 动作端点是普通 POST,按 §4 发 JSON 即可。
文档基于后端真实代码整理(2026-06-15)。SDK 集成见《Agent SDK 对接说明》。问题反馈联系 ai-boss 团队。