跳到主要内容

SSE 传输协议

POST /chat/control/stream 使用 服务器发送事件(SSE)(text/event-stream)响应:这是一种长连接响应,会在文本生成时持续发送内容,同时发送地点、地图操作和路线的结构化事件。

本页定义该数据流的协议。如果使用 kaleidr.js,聊天面板会自动解析数据流,无须阅读本页。自行开发客户端时请参考此文档。Node 和 Python 的可用客户端示例参见读取数据流;请求体参见接口列表。

/chat/summary/stream 和 /chat/button/stream 使用相同的帧格式,但事件种类较少。详见本页末尾。

数据流开始之前​

被拒绝的请求不会进入流式响应。身份验证、权限范围、配额、速率限制、参数校验及大小限制等错误,会返回带有 JSON 响应体和 4xx 状态码的普通 HTTP 响应(参见错误)。请先检查状态码,只有状态为 200 时才将响应体按 SSE 解析。

请求大小上限为:最多 400 条消息、单条消息最多 64,000 个字符、所有消息内容合计最多 200,000 个字符。超限请求会返回 422 及 conversation_too_long 等错误码;请求体超过 2 MiB 会返回 413。完整限制参见接口列表。

成功响应包含以下响应头:

HTTP/1.1 200 OK
Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform

帧格式​

一个帧由一行或两行内容组成,后面跟一个空行。每行以 \n 结束。

event: place
data: {"name": "Louvre Museum", "coordinates": {"lat": 48.8606, "lng": 2.3376}}

data: {"text": "The Louvre sits on the right bank"}

: keep-alive

  • 具名帧 包含一行 event:,随后是一行 data:。
  • 文本帧 只有一行 data:,没有 event: 行。
  • 注释 以冒号开头。Kaleidr 使用 : keep-alive 作为心跳信号;它不包含数据。
  • data: 始终在单独一行中包含一个完整的 JSON 对象。 文本采用 UTF-8 编码。

网络数据块不一定与帧边界对齐。一次读取可能只得到半帧,也可能得到多个帧。应缓冲收到的数据,按换行符切分,并且只在遇到帧末尾的空行时处理该帧。

兼容性规则​

忽略无法识别的事件名称及不需要的字段。 协议可能在不更改版本的情况下新增事件和字段。遇到未知事件就报错的客户端可能因此无法正常工作。

稳定事件​

event:载荷含义
(无名称){ text }下一段回答文字。追加到已有文本中。地点名周围可能有 [[Name]] 标记。
phase{ type: "phase", phase: "thinking", session_id }请求已接受,处理已开始。phase 始终为 "thinking"。
start{ type: "start", session_id, purpose: "control" }即将开始发送正文。
place{ name, coordinates?: { lat, lng }, address?, category?, icon?, source?, id?, unverified? }回答中提到的地点。按 name 合并;首次收到的坐标即为最终坐标。source: "vendor" 表示组织自有数据中的地点;source: "map" 表示当前已发布地图上已显示的地点。
place_linked地点字段加上 is_update?已发送地点的补充信息。按相同的 name 合并;如果此前没见过该地点则忽略。
early_actions{ type: "early_actions", actions: [ { type, payload } ], places_count, is_partial: true }可在回答完成前应用的地图操作;至少两个地点获得坐标后发送。
prompt_options{ type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] }请求含糊时发送的选择题。展示选项,并把所选选项的 send_text 作为下一条用户消息发送。
route_clear{}清除绘制过的路线;后续会发送新路线。
route{ type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, color?, label?, transit?, attribution? }计算得到的路线。导航问题中会在正文前到达,让地图能在文字生成期间绘制。
end{ type: "end", full_text, places[], actions[], question_type, response_time, total_tokens?, dropped_places? }回答完成。这是权威的最终结果。
error{ type: "error", message, code?, partial_text }回答失败。代替 end 发送。
quota服务器密钥使用 { type: "quota", product, meter, tier, used, limit, reset_at, period };会话令牌使用 { type: "quota", meter, reset_at }此调用计费后的组织 AI 积分使用情况。在 end 或 error 之后,作为数据流最后一个事件发送。参见 quota。
: keep-alive注释行静默 10 秒后发送的心跳信号。忽略其内容,但应视为活动。

已移除:grounding(2026-09-05)。不再发送该事件。

实时数据卡片和图层​

涉及实时或测量数据的问题可能触发以下事件。卡片会在正文之前到达;图层可能在正文发送期间或之后到达。这些事件是附加内容:支持的就绘制,不支持的就忽略。未来可能增加更多字段。

event:载荷用途
weather_card包含 lat、lng、name、温度(temp_c、temp_f)、conditions 和可选 forecast[] 的对象地点当前天气。
weather_layer包含 layer、tile_path_template、tile_size、max_zoom、scope、attribution 的对象区域温度叠加图层。
satellite_card包含 name、norad_id、lat、lng、altitude_km、velocity_kms、observed_at 的对象指定卫星的位置。
constellation_layer包含 group、features[](元素为 { name, norad_id, lat, lng })及可选 track 的对象卡片中的卫星周围的其他卫星。
building_card包含 lat、lng、可选 name、height_m、num_floors 的对象建筑物相关数据。
trees_card包含 lat、lng、count、radius_m 的对象某点附近的普查树木。
heritage_card包含 lat、lng、count、sites[] 的对象某点附近的文化遗产地点。
rail_card包含 lat、lng、lines[]、可选 nearest_station 的对象某点附近的铁路线路。
arrivals_card包含 lat、lng、stop、departures[]、alerts[]、attribution 的对象某站点的公共交通发车信息。
vehicles_layer包含 operator、vehicles[]、shapes[]、attribution 的对象卡片中站点或线路的公共交通车辆位置。
streetview_card包含 lat、lng、image_id、image_lat、image_lng 的对象地点附近的街景影像。

发送过这些事件时,end 会以相同名称再次包含其中五种数据,便于漏收事件的客户端读取:weather_card、satellite_card、constellation_layer、weather_layer 和 vehicles_layer(例如 end.weather_card)。其他卡片不会在 end 中重复。平台 API 不提供实时活动列表,参见数据许可。

诊断和实验性内容(不属于协议)​

以下内容可能出现在传输数据中,但不属于正式协议,请勿依赖。

event:载荷备注
debug{ scope, … }内部诊断信息。正常请求不会发送。
place_name_found{ name, is_early }提前提示文本中出现某个地点名。应使用其后到达的 place 事件。

事件顺序​

数据流会经历以下阶段。标记为可选的阶段不一定每次出现。

  1. 可选。 带有 source: "vendor" 的 place 事件:如果密钥包含 vendor 权限范围,最多先发送三个来自贵组织自有数据的地点,以便地图立即绘制。
  2. phase。始终是回答本身的第一个事件。
  3. 可选。 生成答案期间发送 : keep-alive 注释。
  4. 可选。 正文之前的事件:prompt_options;或 route_clear 后跟 route,以及一张卡片。
  5. start。
  6. 正文文本帧,期间穿插 place、place_linked、early_actions,有时还有 route_clear、route 和图层事件。空闲时通过保活信号维持连接。
  7. 可选。 正文结束后,延迟到达的 place、place_linked、图层及路线事件。
  8. end 或 error。
  9. 可选。 quota。
  10. 服务器关闭连接。

这对客户端有两点影响:

  • end 不是最后一个事件。 请持续读取,直到响应体关闭,否则会错过 quota。
  • 数据流可能在既没有 end 也没有 error 的情况下关闭,例如网络断开。没有终止事件就关闭的流应视为失败。

载荷说明​

文本与标记​

文本帧只携带文字,不会在正文中嵌入结构化数据。正文可能用双中括号标记地点名称,例如 near [[Louvre Museum]];聊天面板会将其转换为地图标记链接。若要显示纯文本,请去掉中括号并保留名称。

place​

字段类型备注
namestring用于合并记录的键。
coordinatesobject { lat, lng }十进制度数。可能缺失。 无法定位的地点会在没有坐标的情况下发送,并标记 unverified: true。不要为其绘制地图标记。
addressstring可选。
categorystring可选。
iconstring可选。地点的表情符号。
sourcestring可选。"vendor" 表示来自贵组织自有数据的地点。"map" 表示已发布地图中已有的地点;聊天面板不会重复绘制标记,因为地图已经绘制。
idstring可选。自有数据中的地点会包含此字段。
unverifiedboolean可选。如果地点位置尚未确认,则为 true。

地点还可能包含其他字段,不需要的字段可以忽略。

同一地点名称可能出现多次:先包含坐标,后续再补充信息。每个名称只保留一条记录;一旦获得坐标就不要移动其地图标记,后续事件可补充其他字段。

操作​

early_actions.actions 和 end.actions 都是 { type, payload } 对象列表。

操作类型载荷处理方式
map.fitBounds{ coordinates: [[lng, lat], …], padding, maxZoom, duration }让相机视野包含这些坐标。
places.highlight{ places: [ { name, lat, lng } ], options }突出显示这些地点。
map.showRoute{ id, label, profile, coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[], transit?, attribution? }绘制路线,并展示 attribution。
route.clear{ id? }删除具有该 id 的路线;如未指定 id 则删除所有路线。

还可能出现其他操作类型。无法处理的类型应跳过。注意两种坐标格式:地点使用 coordinates: { lat, lng },线条使用由 [lng, lat] 组成的列表。

route​

primary 包含要绘制的线条:{ coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[] }。turn_by_turn 的每一步包含 text,还可能包含 direction_type、distance_m、duration_s、lat 和 lng。origin 与 destination 各自包含 label。alternatives[] 是带有 route_id 的其他路线;comparison[] 给出每条备选路线相对于主路线的 delta_duration_s。如有 stops[],它是多站路线中按顺序排列的 { lat, lng, name } 点位。

道路路线包含 attribution: { text, url, license }。每次绘制路线时,都应显示链接到 url 的 text 署名。公共交通路线的运营方署名则位于 transit 中。

每个 route 事件都有 id。绘制具有相同 id 的路线会替换已有路线。

end​

字段类型备注
full_textstring完整答案。优先使用此值,而不是手动拼接的正文帧。
placesarray按顺序排列的最终地点列表。按名称与已收到的地点合并。
actionsarray最终地图操作。应以此替换 early_actions 并应用。
dropped_placesarray of strings可选。此前发送但不属于最终答案的地点名称。请移除它们的地图标记。
question_typestring问题类型标签,仅供参考。
response_timenumber回答耗时,以秒为单位。
total_tokensnumber可选。回答使用的令牌数,也是计费依据。

error​

event: error
data: {"type": "error", "code": "upstream_stall", "message": "The AI service stopped responding. Please try again.", "partial_text": "The Louvre sits"}

message 可以直接展示给用户。partial_text 是出错前已经生成的文字。code 只在一种情况下出现:

情况code处理方式
回答停止推进或数据流已达到最大长度"upstream_stall"提示用户重试。
回答期间发生的其他错误无显示 message;重试可能成功。

error 之后不会再有 end,但仍可能收到 quota 事件。

quota​

字段取决于打开数据流时使用的凭证。

字段类型服务器密钥或旧版密钥会话令牌
type字符串, "quota"是是
meter字符串是是
reset_at字符串,含时区偏移的 ISO 8601是是
product字符串是否
period字符串是否
tier字符串是否
used数字是否
limit数字是否

会话令牌由网页访客使用,可以从可公开使用的密钥交换取得,也可以是已发布地图的访客会话。其 quota 事件仅说明本计费周期何时重置,不会泄露组织的订阅方案、使用量或限额。浏览器客户端不应依赖 used 或 limit 字段。429 quota_exceeded 响应体也遵循相同规则,参见配额与速率限制。

保活信号与超时​

行为取值客户端处理方式
聊天流心跳连续 10 秒没有其他输出后发送 : keep-alive 注释收到任何字节时重置空闲计时器,包括注释。
空闲连接连接静默约一分钟时,传输过程中可能被关闭设置 30 到 60 秒的空闲(读取)超时,不要设置过短的总超时。
首段正文等待时间复杂问题可能需要几十秒从 phase 开始显示进度,不要将等待视为错误。
数据流最长持续时间约 10 分钟,此后服务器发送带有 upstream_stall 的 error为保险起见,将总超时设置为略长于 10 分钟。

中止数据流与计费​

关闭连接即可中止数据流。服务器通常会在约十秒内发现断开并停止生成答案。

  • 正常完成 的数据流按回答消耗的令牌数计费,数值由 end.total_tokens 报告。
  • 中止或失败 的数据流在完成前结束时按估算值计费。估算至少涵盖请求中提交的全部对话文本,也可能根据已发送的内容计算。因此,最终费用可能高于预留额度:收到首帧后立即断开,也不会让一段较长的对话免费。
  • 自有数据中的地点(source: "vendor")不计入费用。

重试属于新的请求,会再次计费。参见配额与速率限制。

摘要流和按钮流​

这两个接口用于 Kaleidr Chat 的地点卡片。它们使用相同的帧格式、无名称文本帧和末尾的 quota 事件。与主要聊天流相比有三点不同:不发送 phase,不发送地点或操作事件,并且不发送保活信号。应设置 60 秒空闲超时。

两个接口都会在数据流开始前以 422 field_too_long 拒绝过长字段,并忽略未列出的字段,参见接口列表。若流中止或失败,费用基于已发送文本估算,且不会高于预留额度。

POST /chat/summary/stream,描述地点:

  1. 可选。 address,载荷为 { type: "address", address, source }
  2. start,载荷为 { type: "start", poi_type }
  3. 可选,可能重复。 url,载荷为 { type: "url", website, source }
  4. 文本帧,载荷为 { text }
  5. end,载荷为 { type: "end", full_text, summary, poi_type, category, city, country, sources[], website?, total_tokens? };或 error,载荷为 { type: "error", message, partial_text }
  6. 可选。 quota

POST /chat/summary/stream,描述建筑物(type: "building"):

  1. start,载荷为 { type: "start", address }
  2. 文本帧
  3. end,载荷为 { type: "end", full_text, parsed, total_tokens? },或 error
  4. 可选。 quota

POST /chat/button/stream:

  1. start,载荷为 { type: "start", query_type }
  2. 文本帧
  3. end,载荷为 { type: "end", full_text, reply, query_type, first_token_ms, total_ms, total_tokens? }
  4. 可选。 quota

按钮流没有 error 事件。如果开始后失败,连接会在没有 end 的情况下关闭。开始前失败则返回 HTTP 500,响应体为 {"detail": "Button chat stream error"}。

POST /spot/overview/stream 会发送上述地点摘要的帧,并在此之前发送一个载荷为 { type: "place", name } 的 place 帧:name 是所描述地点或区域的完整名称,例如 "Springfield, Ohio, United States of America",可用于标注或复制。该帧先于其他所有帧发送,也可能不存在。它不同于聊天数据流中的 place 事件,不含坐标。如果无法描述某个 ref,它会用一帧 error(载荷为 { type: "error", message, ref })代替摘要。参见接口列表。

相关文档​