SophonRealtime APIHarness 控制台Console

Harness API

Harness 是 AI降临派面向硬件和应用的角色对话服务:你通过 HTTP 接口创建带人设、记忆、技能和工具的「角色」,设备再用一条 TCP 长连接和角色实时语音对话。如果你只需要一个裸的语音模型(自己管理提示词和上下文),请看 Realtime API。两套接口共用控制台的账号和 key。

Harness is Adventists AI's character conversation service for devices and apps. You create characters (persona, memory, skills, tools) over HTTP, and the device talks to a character in real time over one long-lived TCP connection. If you just need a bare voice model and manage prompts yourself, see the Realtime API. Both share the same console account and keys.

01
入门Getting started
入口地址、五分钟跑通、示例代码、key 和令牌Endpoints, a 5-minute first call, example code, keys and tokens

概览Overview

国内Mainland China海外Global
HTTPhttps://api.adventists.cnhttps://api.adventists.ai
TCPapi.adventists.cn:8009203.208.134.27:8009
WebSocketwss://api.adventists.cn/ws-betawss://api.adventists.ai/ws-beta

两个入口连的是同一套服务:账号、key、角色和记忆都是通用的。海外入口经新加坡专线加速。下文的路径都相对于 HTTP 入口,例如 POST /v2/init 指 https://api.adventists.cn/v2/init。8010 端口是测试端口,可能先于 8009 上线新功能,不保证稳定。

Both entry points reach the same service; accounts, keys, characters and memory are shared. The global entry is accelerated over our Singapore private line. Paths below are relative to the HTTP base, e.g. POST /v2/init means https://api.adventists.ai/v2/init. Port 8010 is a test port that may get features before 8009 and is not guaranteed to be stable.

WebSocket 和 TCP 是同一套协议:每条二进制消息里放的就是 TCP 的帧(##START…##END),适合浏览器和 App。ws-beta 对应 TCP 8009,ws-nightly 对应测试端口 8010。

WebSocket carries the same protocol as TCP: each binary message holds TCP frames (##START…##END), which suits browsers and apps. ws-beta maps to TCP 8009 and ws-nightly to test port 8010.

前缀Prefix内容Contents
/v2/角色、模板、令牌、音色、技能书、图片、会议、日志推送配置Characters, templates, tokens, voices, skill books, images, meetings, log webhook config
/hippo/api/记忆、个人知识图谱(PKG)、关系、日记、封禁Memory, personal knowledge graph (PKG), relationships, diary, blocking
/push/api/向在线设备推送消息Push messages to online devices

快速开始Quick start

  1. 在 控制台 注册并创建一把 key(sk-sophon-…,只显示一次)。
  2. POST /v2/init 创建一个角色,拿到 npcid。
  3. POST /v2/login 用 npcid 换一个 TCP 令牌(JWT,4 小时有效)。
  4. 连 TCP,发认证帧,收到 LISTEN start 后持续推麦克风音频,播放收到的音频。
  1. Sign up in the console and create a key (sk-sophon-…, shown once).
  2. POST /v2/init to create a character and get its npcid.
  3. POST /v2/login to exchange the npcid for a TCP token (JWT, valid for 4 hours).
  4. Connect over TCP, send the AUTH frame, and after LISTEN start stream microphone audio continuously and play what comes back.
KEY=sk-sophon-xxxxxxxx
curl -s https://api.adventists.cn/v2/init -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{}'
# {"code":201,"status":"success","data":"9ASU1C6e1d3ac79bab4cef8e225b0a46e2a6ac"}
curl -s https://api.adventists.cn/v2/login -H "Authorization: Bearer $KEY" -d npcid=9ASU1C6e1d3ac79bab4cef8e225b0a46e2a6ac
# {"token":"eyJhbGciOiJIUzI1NiIs..."}

完整的 Python 示例(只依赖 requests):建角色、拿令牌、全双工连上、推一段 16 kHz 单声道 wav,打印识别结果和回复文字,把回复音频存成 reply.wav。

A complete Python example (needs only requests): create a character, get a token, connect in duplex mode, stream a 16 kHz mono wav, print the transcript and reply text, and save the reply audio to reply.wav.

import socket, threading, time, wave, requests

BASE = "https://api.adventists.cn"        # global: https://api.adventists.ai
TCP = ("api.adventists.cn", 8009)         # global: ("203.208.134.27", 8009)
KEY = "sk-sophon-..."
H = {"Authorization": f"Bearer {KEY}"}

npc = requests.post(f"{BASE}/v2/init", headers=H, json={}).json()["data"]
token = requests.post(f"{BASE}/v2/login", headers=H, data={"npcid": npc}).json()["token"]

def frame(t, payload, tid=b"duplex00", seq=0):
    return b"##START" + bytes([t]) + tid + f"{seq % 10000:04d}".encode() + payload + b"##END"

s = socket.create_connection(TCP)
s.sendall(frame(1, f"{token}##mode:duplex##format:pcm##input_audio_format:pcm##engine:tag".encode(), b"00000000"))

listening, reply = threading.Event(), bytearray()
def reader():
    buf = b""
    while (d := s.recv(65536)):
        buf += d
        while (i := buf.find(b"##START")) >= 0 and (j := buf.find(b"##END", i + 20)) >= 0:
            t, body, buf = buf[i + 7], buf[i + 20:j], buf[j + 5:]
            if t == 2: reply.extend(body)                                  # AUDIO
            elif t == 8: listening.set()                                   # LISTEN start
            elif t in (4, 5): print(t, body.decode(errors="replace"))      # TEXT / STATUS
threading.Thread(target=reader, daemon=True).start()
assert listening.wait(10), "no LISTEN start"

w = wave.open("question_16k_mono.wav"); pcm = w.readframes(w.getnframes())
n = 1920                                                    # 60 ms x 16 kHz x 2 bytes
frames = [b"\0" * n] * 16 + [pcm[i:i + n].ljust(n, b"\0") for i in range(0, len(pcm), n)] + [b"\0" * n] * 150
for k, f in enumerate(frames):                              # keep sending, silence included
    s.sendall(frame(2, f, seq=k)); time.sleep(0.06)

s.sendall(frame(5, b"##DISCONNECT", b"00000000")); time.sleep(1)
with wave.open("reply.wav", "wb") as o:
    o.setnchannels(1); o.setsampwidth(2); o.setframerate(16000); o.writeframes(bytes(reply))
5 ##INFO:认证成功,NPCID: 9ASU1C6e1d3ac79bab4cef8e225b0a46e2a6ac, 模式: duplex
5 ##INFO:prompt: 你好,你叫什么名字?
4 我是贾维斯,原名"Just A Rather Very Intelligent
4  System",曾是托尼·斯塔克先生的人工智能助手。

示例里的解析按 ##END 切帧,便于阅读。正式客户端请按帧头定位,并把半包留到下一次 recv。

The example splits frames on ##END for readability. A production client should parse by header and keep partial frames across recv calls.

更多场景(麦克风实时对话、VAD、设备工具、会议、浏览器)见 示例代码。

More scenarios (live microphone, VAD, device tools, meetings, browser) are in Example code.

示例代码Example code

下面的示例都在国内和海外两个入口实测过,可以直接运行,也可以拷进你的项目。Key 从环境变量 ADVENTISTS_API_KEY 读,ADVENTISTS_REGION=global 切到海外入口。带 --wav 用文件代替麦克风,带 --save 把回复存成文件,没有声卡也能测试。

All examples were run against both the China and global endpoints; run them as is or copy them into your project. The key is read from ADVENTISTS_API_KEY; ADVENTISTS_REGION=global switches to the global endpoint. --wav replaces the microphone with a file and --save writes the reply to a file, so you can test without a sound card.

下载全部(zip)Download all (zip) · README

文件File内容What it shows
python/quickstart.py最简接入,只依赖 requests:建角色、拿令牌、全双工连接、推一段录音、存下回复Smallest integration, requests only: create, token, connect, send a recording, save the reply
python/talk_duplex.py全双工对话(推荐):麦克风 + 扬声器,一直在听,随时打断。--tools 注册设备工具(MCP),--emoji true 收表情帧,是端侧设备常用的组合Full-duplex chat (recommended): mic + speaker, always listening, interrupt any time. --tools registers device tools (MCP) and --emoji true adds emoji frames — the usual device setup
python/talk_vad.py自动(VAD)模式:每轮发 LISTEN start,收到 detecting 停止播放Auto (VAD) mode: LISTEN start per turn, stop playback on detecting
python/push_to_talk.py按键说话、文字输入、SPEAK、表情Push-to-talk, text input, SPEAK, emoji
python/device_tools.py设备工具(MCP):注册开灯、查电量,角色对话中调用Device tools (MCP): lights and battery, called by the character
python/meeting.py会议模式:实时转写和字幕,结束后生成纪要Meeting mode: live transcript and captions, minutes at the end
python/demo_tools.py示例工具的定义和处理:注册、执行、回结果。换成你的设备逻辑即可Tool definitions and handler: register, run, reply. Plug in your device logic
python/manage.pyHTTP 接口走一遍:模板、角色、记忆、推送、用量Tour of the HTTP APIs: templates, characters, memory, push, usage
python/adventists.py上面几个示例共用的小客户端:帧编解码、TCP 连接、音频输入输出Shared mini client: frames, TCP connection, audio in / out
web/server.py浏览器示例的后端:key 留在服务端,给浏览器发令牌Backend for the browser demo: keeps the key, hands out tokens
web/index.html浏览器端:WebSocket 连接、麦克风采集、实时播放Browser page: WebSocket, microphone capture, playback
python/realtime_api.pySophon Realtime API(裸模型)Sophon Realtime API (bare model)
pip install requests sounddevice
export ADVENTISTS_API_KEY=sk-sophon-...
python talk_duplex.py                                   # headphones on, just talk
python talk_duplex.py --tools --emoji true              # device tools (MCP) + emoji frames
python device_tools.py --say "帮我把客厅的灯关掉"
cd ../web && python server.py                        # http://localhost:8000

浏览器和 App 接入请照 web/ 的结构:你的后端保管 key、调用 /v2/login 换令牌,前端只拿令牌连 WebSocket。

For browsers and apps follow the web/ pattern: your backend holds the key and calls /v2/login; the front end only gets the token and connects over WebSocket.

认证Authentication

所有 HTTP 接口用控制台的 key,二选一:

All HTTP APIs take a console key, in either header:

Authorization: Bearer sk-sophon-xxxxxxxx
api-key: sk-sophon-xxxxxxxx

key 自带组织信息,不需要再传 org-id。已有企业账号(32 位 api-key + 6 位 org-id)照旧可用。key 只能在服务端使用,不要写进 App 或设备固件;设备只需要拿 /v2/login 签发的令牌。

Keys carry their organization, so no org-id is needed. Existing enterprise accounts (32-char api-key + 6-char org-id) keep working. Keep keys on your server; never ship them in an app or device firmware. Devices only need the token issued by /v2/login.

用途Used for有效期Lifetime
key所有 HTTP 接口All HTTP APIs直到在控制台撤销Until revoked in the console
令牌Token (JWT)TCP 认证帧;绑定一个角色TCP AUTH frame; bound to one character4 小时;过期后重新调 /v2/login4 hours; call /v2/login again

每个角色的 npcid 以所属组织的 6 位 org 开头。只能给自己组织的角色签令牌、读写记忆和推送。

Every npcid starts with its organization's 6-character org ID. You can only issue tokens for, read and write memory of, and push to your own organization's characters.

02
角色Characters
用 HTTP 创建和管理带人设的角色Create and manage characters over HTTP

模板与角色Templates and characters

模板(templateid)是一份人设配置:名字、性格、说话风格、开场白、音色、技能书、工具。角色(npcid)是从模板创建出来的一个实例,一台设备或一个用户用一个角色;记忆、知识图谱、日记都挂在角色上。修改模板不影响已创建的角色。不传 templateid 时使用默认模板(贾维斯)。也可以不用模板,直接用 templateid: "no_class" 加完整字段创建。

A template (templateid) is a persona config: name, personality, speaking style, opening line, voice, skill books and tools. A character (npcid) is an instance created from a template, typically one per device or end user; memory, the knowledge graph and the diary belong to the character. Editing a template does not change characters already created. Without a templateid the default template (Jarvis) is used. You can also skip templates and create with templateid: "no_class" plus the full set of fields.

可以把模板理解成「类」,角色是「实例」:1000 个用户用同一个模板,就创建 1000 个角色。模板记忆(用 save_template_memory 灌入)由所有角色共享;每个角色和自己用户的对话记忆互相独立。不要让多个用户共用一个 npcid,否则记忆会串。想重置一个角色,就从同一模板重新创建一个。公共模板(如 LuLu、Sakura、曹操)可以用 public_template_list 查到。

Think of a template as a class and a character as an instance: 1,000 users on one template means 1,000 characters. Template memory (loaded with save_template_memory) is shared by all of them; each character's memory of its own user is separate. Never share one npcid across users, or their memories mix. To reset a character, create a new one from the same template. Public templates (LuLu, Sakura, Cao Cao…) are listed by public_template_list.

POST /v2/init · POST /v2/login

接口Endpoint请求Request返回Response
POST/v2/initJSON {} / {"templateid": "…"} / {"templateid": "no_class", "name": …}{"code":201,"status":"success","data":"<npcid>"}
POST/v2/initJSON {"templateid": "copy_from_npc", "npcid": "<npcid>"}复制一个现有角色,返回新 npcidCopy an existing character; returns the new npcid
POST/v2/loginform npcid=<npcid>{"token":"eyJ…"};角色不属于本组织返回 404; 404 if the character is not yours

POST /v2/template

一个接口,用 action 区分操作,body 为 JSON。返回 {"code":200,"status":"success","data":…}。

One endpoint; action selects the operation. JSON body. Returns {"code":200,"status":"success","data":…}.

action参数Parameters说明Description
public_template_list—公共模板列表Public templates
private_template_list—本组织可用的模板(私有 + 公共)Templates your org can use (private + public)
create_template角色字段character fields返回 templateidReturns the templateid
load_template_contenttemplateid读取模板Read a template
modify_templatetemplateid + 要改的字段fields to change
delete_templatetemplateid
save_template_memorytemplateid, new_user_entry, new_assistant_entry给模板加一条预置记忆,之后从该模板创建的角色都会带上Add a preset memory; characters created from the template afterwards inherit it
curl -s https://api.adventists.cn/v2/template -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{
  "action": "create_template", "name": "小安", "mbti_type": "ENFJ", "love_type": "Virgo",
  "person": "你是一个陪伴型桌面机器人……", "style": "简短亲切", "emotion_system": "开心时语气轻快",
  "start_speech": "你好呀!", "temp": "0.5",
  "voice_id": "xiaonanhai", "functions": ["get_weather", "search_internet"]}'

POST /v2/npc

action参数Parameters说明Description
query_npcnpcid读取角色配置Read a character's config
modify_npcnpcid + 要改的字段fields to change下次连接生效Takes effect on the next connection
delete_npcnpcid
send_npc_memorynpcid, new_user_entry, new_assistant_entry写入一轮对话记忆Write one exchange into memory
load_npc_memorynpcid读取记忆Read memory

角色字段Character fields

创建模板和 no_class 角色时,name、person、style、emotion_system、mbti_type、love_type 必填,其余可选。

When creating a template or a no_class character, name, person, style, emotion_system, mbti_type and love_type are required; the rest are optional.

字段Field说明Description
name角色名Name
person人设:背景、身份、性格。最重要的字段Persona: background, identity, personality. The most important field
style说话风格,可以放例句Speaking style; example lines welcome
start_speech开场白(写入记忆,不会主动播放)Opening line (stored in memory, not spoken automatically)
emotion_system / emotion_responses情绪触发条件 / 具体情绪反应Emotion triggers / specific emotional responses
relationship与用户或其他角色的关系Relationship to the user or other characters
mbti_typeENFJ ISTJ INTJ ENTJ INFP ISFJ ESTJ INTP ENFP INFJ ESFJ ENTP
love_type星座:Star sign: Aries Taurus Gemini Cancer Leo Virgo Libra Scorpio Sagittarius Capricorn Aquarius Pisces
temp话多程度,0–2,默认 0.5Talkativeness, 0–2, default 0.5
voice_id默认音色,见Default voice, see /v2/get_voice_ids
skill_ids技能书 ID,见Skill book IDs, see 技能书Skill books
functions内置工具,不超过 10 个:Built-in tools, at most 10: get_weather get_news search_internet search_baidu read_url draw_pic draw_pic_google tarot bazi dance book_house_service car_sales
public模板是否公开Whether a template is public
hotword热词,空格分隔,例如 黑格尔 罗素 斯宾诺莎;提高这些专有名词的识别准确率Hot words, space-separated (e.g. product or person names), to improve their recognition
intent_extensions按意图类别补充本角色特有的说法,帮助意图识别。类别:assistant(查询、控制设备等功能性任务)entertainment greeting chat detailed_explanation harassment jailbreak,每类是字符串数组Extra phrasings per intent category to help intent detection. Categories: assistant (lookups, device control and other tasks), entertainment, greeting, chat, detailed_explanation, harassment, jailbreak; each is an array of strings
03
语音连接Voice connection
设备通过 TCP 和角色实时对话Devices talk to a character over TCP

实时语音:连接与帧格式Realtime voice: connection and frames

TCP 长连接(不是 WebSocket)。连接后 5 秒内要发认证帧;300 秒没有任何数据会被断开。所有消息都是同一种帧:

A plain TCP connection (not WebSocket). Send the AUTH frame within 5 seconds of connecting; the server closes connections idle for 300 seconds. Every message uses the same frame:

##START  [type 1 byte]  [task_id 8 bytes ASCII]  [seq 4 bytes ASCII, 0000–9999]  [payload]  ##END
type名称Name方向Direction内容Payload
0x01AUTHC→S令牌和参数,见下节Token and parameters, see below
0x02AUDIOC↔S音频数据Audio data
0x03ENDC↔S一段话结束(空)End of an utterance (empty)
0x04TEXTC↔SUTF-8 文本:上行是用户输入,下行是回复文字UTF-8 text: user input upstream, reply text downstream
0x05STATUSC↔S##INFO:… ##ERROR:… ##PING ##DISCONNECT
0x06MCPC↔S设备工具注册和调用(JSON)Device tool registration and calls (JSON)
0x07SPEAKC→S让角色直接念出这段文字Have the character say this text verbatim
0x08LISTENC↔S听的状态(JSON)Listening state (JSON)
0x09EMOJIS→C{"emoji":"happy"}
0x0aIMAGES→C{"type":"image","url":"…"}

task_id 由客户端定义,固定 8 字节;00000000 保留给系统消息(认证、心跳、断开)。duplex 模式下整场会话固定用 duplex00。

task_id is client-defined, exactly 8 bytes; 00000000 is reserved for system messages (auth, heartbeat, disconnect). In duplex mode use duplex00 for the whole session.

系统消息System message帧Frame回复Reply
心跳(可选)Heartbeat (optional)##START\x05000000000000##PING##END##INFO:PONG
主动断开Disconnect##START\x05000000000000##DISCONNECT##END##INFO:DISCONNECT 3 seconds,3 秒后关闭##INFO:DISCONNECT 3 seconds, closes after 3 s

认证帧参数AUTH parameters

##START\x01 00000000 0000 <token>##mode:duplex##format:pcm##input_audio_format:pcm##engine:tag##END

(空格只是为了好读,实际没有空格。)参数用 ##名称:值 跟在令牌后面,顺序随意,不认识的参数会被忽略。

(Spaces added for readability; there are none on the wire.) Parameters follow the token as ##name:value in any order; unknown parameters are ignored.

参数Parameter默认Default说明Description
modemanualduplex / auto / manual,见see 对话模式modes。vad、realtime 等同 autovad and realtime mean auto
engine newtagduplex 模式用哪个 Sophon 模型:tag(反应快、稳定)/ flash / e2e。不传或不认识的值用 tag。三个都已开放。e2e 目前限 4 路并发,满了会话会建立失败(报错 capacity_exceeded),请稍后重试或改用 tag;三个都支持克隆音色,Tag 和 e2e 最像原声,Flash 只能大致接近Which Sophon model to use in duplex mode: tag (fast, stable) / flash / e2e. Missing or unknown values use tag. All three are available. e2e is limited to 4 concurrent sessions for now; when full the session fails to start (error capacity_exceeded), retry later or use tag. All three support cloned voices; Tag and e2e sound closest to the original, Flash is an approximation
formatpcm下行音频:pcm / opusDownstream audio: pcm / opus
input_audio_formatpcm上行音频:pcm / opusUpstream audio: pcm / opus
voiceid角色默认character default本次连接使用的音色Voice for this connection
langdefault回复语言,可写自然语言:auto、中文、English、JA…Reply language, natural values accepted: auto, 中文, English, JA…
emoji_modefalse见see 表情Emoji
resolution—设备屏幕分辨率 宽x高,用于缩放下发的图片Device screen size WxH, used to scale images sent to it
device_id—设备 ID,用于封禁、日志和会议Device ID, used for blocking, logs and meetings
denoisefalse语音识别前先降噪,适合嘈杂环境,增加约 200 ms 延迟Denoise before speech recognition, for noisy places; adds about 200 ms
session_type—meeting 进入会议模式,见meeting enters meeting mode, see 会议模式Meeting mode
in_rate / in_channels / in_frame_ms16000 / 1 / 60上行音频的采样率、声道、帧长(服务端统一转成 16 kHz 单声道)Upstream sample rate, channels, frame length (the server converts to 16 kHz mono)

认证结果通过 STATUS 返回:成功 ##INFO:认证成功,NPCID: <npcid>, 模式: duplex,失败 ##ERROR:token error 并断开。

The result comes back as STATUS: success is ##INFO:认证成功,NPCID: <npcid>, 模式: duplex ("authenticated"); failure is ##ERROR:token error followed by a disconnect.

三种对话模式Conversation modes

duplex 推荐recommendedauto (VAD)manual
谁判断说完End of speech模型自己The model服务端 VADServer VAD客户端发 ENDClient sends END
打断Barge-in直接说话即可Just speak发新的 LISTEN start(可带 interrupt)Send a new LISTEN start (optionally with interrupt)发新的 LISTEN startSend a new LISTEN start
task_id固定 duplex00Fixed duplex00每轮换一个New one per turn每轮换一个New one per turn
上行音频Upstream audio一直发,包括静音Continuous, silence included一直发Continuous说话时发,发完补 ENDWhile speaking, then END
回复文字Reply text在对应音频之后约 1 秒About 1 s after the audio在音频之前Before the audio在音频之前Before the audio
SPEAK不支持Not supported支持Supported支持Supported

duplex

  1. 认证帧带 ##mode:duplex。
  2. 等服务端发 LISTEN start(type 8,约 1 秒内,整场只发这一次):{"taskid":"duplex00","type":"listen","state":"start","mode":"duplex"}。在这之前推的音频不保证被处理。
  3. 之后一直按 60 ms 一帧推音频,没人说话时也要推静音,断流会被当成没有输入。
  4. 收下行:AUDIO 边收边播;TEXT 是刚说完那句的文字记录;STATUS 里 ##INFO:prompt:… 是识别出的用户原话;END 表示一段回复结束。
  5. 用户随时说话就是打断,客户端什么都不用做。客户端发 LISTEN 会被忽略(回 ##INFO:LISTEN start ignored in duplex mode),发 SPEAK 会回 ##ERROR。
  1. Send ##mode:duplex in the AUTH frame.
  2. Wait for the server's LISTEN start (type 8, within about a second, sent only once per session): {"taskid":"duplex00","type":"listen","state":"start","mode":"duplex"}. Audio sent before it may be dropped.
  3. Then stream 60 ms audio frames continuously, including silence when nobody speaks; a gap in the stream is treated as no input.
  4. Downstream: play AUDIO as it arrives; TEXT is a transcript of what was just said; STATUS ##INFO:prompt:… is the recognized user speech; END marks the end of a reply segment.
  5. The user can barge in at any time just by talking; the client does nothing. Client LISTEN frames are ignored (##INFO:LISTEN start ignored in duplex mode) and SPEAK returns ##ERROR.

auto (VAD)

  1. 认证帧带 ##mode:auto。
  2. 客户端为这一轮选一个 task_id,发 LISTEN start:##START\x08task00010000{"type":"listen","state":"start"}##END,服务端回 ##INFO:开始监听,task_id: task0001。
  3. 用这个 task_id 持续推音频,不需要发 END。服务端检测到说话发 {"state":"detecting"},检测到说完发 {"state":"stop"}(都是 type 8),然后返回识别结果、回复文字和音频、END。
  4. 下一轮换一个新的 task_id 再发 LISTEN start。要在角色说话时打断,发 {"type":"listen","state":"start","interrupt":true}。旧 task_id 的音频帧会被丢弃。
  5. 只有噪音时服务端回 ##INFO: 提示并继续听。
  1. Send ##mode:auto in the AUTH frame.
  2. The client picks a task_id for the turn and sends LISTEN start: ##START\x08task00010000{"type":"listen","state":"start"}##END. The server replies ##INFO:开始监听,task_id: task0001 ("listening").
  3. Stream audio with that task_id; no END needed. The server sends {"state":"detecting"} when speech starts and {"state":"stop"} when it ends (both type 8), then the transcript, reply text and audio, and END.
  4. For the next turn use a new task_id and send LISTEN start again. To interrupt the character mid-reply send {"type":"listen","state":"start","interrupt":true}. Frames with an old task_id are dropped.
  5. If only noise is heard the server sends an ##INFO: hint and keeps listening.

manual

按键说话:用一个 task_id 推完这段音频(seq 从 0000 递增),再发 ##START\x03task0001<seq>##END。服务端返回 ##INFO:prompt:…、TEXT、AUDIO,最后 END。下一轮换新的 task_id。

Push-to-talk: send the utterance's audio with one task_id (seq counting up from 0000), then ##START\x03task0001<seq>##END. The server returns ##INFO:prompt:…, TEXT, AUDIO and finally END. Use a new task_id for the next turn.

音频格式Audio formats

pcmopus
编码Encoding16 kHz、单声道、16 bit 小端16 kHz, mono, 16-bit little-endian16 kHz 单声道,每帧 60 ms16 kHz mono, 60 ms per frame
打包Packing建议每帧 60 ms(1920 字节)60 ms per frame recommended (1920 bytes)每个 Opus 帧前加 2 字节大端长度;一个 AUDIO 帧可以拼多个「长度 + Opus 帧」,但不能把一个拆开;建议每个 AUDIO 帧不超过约 1 KBEach Opus frame is prefixed with a 2-byte big-endian length; one AUDIO frame may hold several length+frame units but must never split one; keep each AUDIO frame under about 1 KB
适合Use when首次接入、局域网First integration, LAN移动网络、省流量Mobile networks, low bandwidth

上行和下行的格式分别由 input_audio_format 和 format 控制,可以不同。

Upstream and downstream are set separately by input_audio_format and format and may differ.

文本、SPEAK 与状态消息Text, SPEAK and status messages

文字输入(manual / auto):##START\x04task0001 0000 你好##END 后跟 ##START\x03task0001 0001##END,角色会像听到这句话一样回复(有声音)。

Text input (manual / auto): ##START\x04task0001 0000 hello##END followed by ##START\x03task0001 0001##END; the character replies, with audio, as if it had heard the sentence.

SPEAK(manual / auto):##START\x07speak001 0000 欢迎回家##END,不经过模型,直接用角色音色念出来,返回 TEXT、AUDIO、END。

SPEAK (manual / auto): ##START\x07speak001 0000 Welcome home##END skips the model and reads the text in the character's voice, returning TEXT, AUDIO and END.

下行 STATUSDownstream STATUS含义Meaning
##INFO:prompt:<text>识别出的用户原话Recognized user speech
##INFO:…其他提示(连接、认证、监听状态等)Other notices (connection, auth, listening…)
##ERROR:…错误;认证错误后会断开Errors; auth errors close the connection

魔法命令Magic commands

用户在对话里说出(或用 TEXT 发送)下面的话,会切换会话行为,角色回一句确认:

When the user says (or sends as TEXT) one of these phrases, the session behaviour changes and the character confirms:

命令Command作用Effect
debug on / debug off调试模式:每轮回复后通过 TEXT 额外返回技能书命中、知识图谱、情绪状态等调试信息Debug mode: after each reply, extra TEXT with skill-book hits, knowledge graph, emotion state and more
incognito on / incognito off无痕模式:对话不写入记忆库Incognito: the conversation is not written to memory
04
设备能力Device features
工具调用、表情、图片、会议记录Tools, emoji, images, meetings

设备工具(MCP)Device tools (MCP)

设备可以把自己的能力(开灯、调音量、拍照…)注册给角色,角色在对话中需要时会调用。所有消息用 type 0x06,task_id 建议 mcp00001,认证成功后随时可以注册或重新注册。

Devices can register their own capabilities (lights, volume, camera…) and the character calls them when needed. All messages use type 0x06; task_id mcp00001 is recommended. Register (or re-register) any time after auth.

// C→S register
{"type":"register","data":{"services":{"light_control":{
  "description":"控制房间的灯 / Turn room lights on or off",
  "parameters":{"type":"object","properties":{
    "room":{"type":"string","description":"房间"},
    "state":{"type":"string","enum":["on","off"]}},"required":["room","state"]}}}}}
// S→C call
{"type":"call","data":{"call_id":"c-123","method":"light_control","params":{"room":"客厅","state":"off"}}}
// C→S result (same call_id)
{"type":"result","data":{"call_id":"c-123","result":{"success":true,"data":"客厅的灯已关"}}}

参数用 JSON Schema 描述;描述写清楚,模型才知道什么时候该调用。失败时返回 {"success":false,"error":"…"},角色会把失败告诉用户。

Parameters use JSON Schema; clear descriptions help the model decide when to call. On failure return {"success":false,"error":"…"} and the character tells the user.

表情Emoji

认证帧加 ##emoji_mode:true,服务端会随回复下发 EMOJI 帧(type 9):{"emoji":"happy"},设备据此播放表情动画。

Add ##emoji_mode:true to the AUTH frame and the server sends EMOJI frames (type 9) with replies, e.g. {"emoji":"happy"}, for the device to animate.

emoji_mode匹配Matching
true按回复的情绪,20 种:By the reply's sentiment, 20 keys: happy laughing sad angry crying loving surprised shocked thinking embarrassed winking cool relaxed delicious kissy confident sleepy silly confused funny
dimi / dimi2按问题和回复的关键词,2800+ 种场景表情;dimi 额外给问题配 playSoundBy keywords in question and reply, 2,800+ scene emojis; dimi also adds playSound for the question
jfb5 类情绪:angry / sad / hesitant / anxious / excited5 emotions: angry / sad / hesitant / anxious / excited

图片与视觉Images and vision

让角色看见(全双工 duplex):图片会直接交给正在说话的模型,角色当场看着画面回答,例如“我手里拿的是什么”。有两种发法,效果相同:

Let the character see (full-duplex): images go straight to the model that is speaking, so the character answers from the picture right away (“what am I holding?”). Two ways to send them, same result:

① 推荐:在语音连接里直接发图片帧。上行 IMAGE 帧(type 0x0a),载荷是 JPEG 二进制。一张图按每片不超过 1012 字节切开,同一张图的分片用同一个 task_id(如 img00001),seq 从 0000 递增;最后一片以 JPEG 结束标记 FF D9 结尾,服务端收到就算一张完整的图。

① Recommended: send image frames on the voice connection. Uplink IMAGE frames (type 0x0a) carry raw JPEG bytes. Split one image into chunks of at most 1012 bytes, give all chunks of the same image the same task_id (e.g. img00001) with seq counting up from 0000; the image is complete when a chunk ends with the JPEG end marker FF D9.

##START + [0x0a] + "img00001" + "0000" + <JPEG bytes 0–1011>    + ##END
##START + [0x0a] + "img00001" + "0001" + <JPEG bytes 1012–2023> + ##END
…  (last chunk ends with FF D9)

② 兼容:HTTP 上传。原来的接口不变,通话进行中上传的图 1 秒内也会送进模型:

② Compatible: HTTP upload. The existing endpoint still works; an image uploaded during a call reaches the model within a second:

POST /v2/upload_image
{"npcid": "<npcid>", "image": "<base64 JPEG, without the data:image/... prefix>"}
→ {"status": "ok", "path": "…"}

请以返回体里的 status 判断成功与否,不要只看 HTTP 状态码。也可以直接传文件:POST /v2/upload_image_file,multipart 字段 pic_file(图片文件)和 npcid。auto / manual 模式只支持 HTTP 上传。

Check the status field in the body rather than only the HTTP code. To upload a file instead: POST /v2/upload_image_file with multipart fields pic_file and npcid. The auto / manual modes support HTTP upload only.

什么时候发:每张图 10 秒内有效,过了 10 秒角色就不再认为自己看得到画面。

When to send: each image counts for 10 seconds; after that the character no longer assumes it can see.

角色画图或推图片:服务端下发 IMAGE 帧(type 0x0a){"type":"image","url":"…"},客户端 GET 这个地址显示即可。认证时声明了 resolution 的话,图片已按屏幕尺寸等比缩放。画图工具统一用 draw_pic / draw_pic_google(旧的 _t / _d 后缀已合并)。不认识 type 0x0a 的旧客户端会忽略它。

Images from the character (drawings or pushes) arrive as IMAGE frames (type 0x0a) {"type":"image","url":"…"}; GET the URL and display it. If you declared resolution at auth, the image is already scaled to fit. The drawing tools are draw_pic / draw_pic_google (the old _t / _d variants were merged). Older clients that don't know type 0x0a simply ignore it.

会议模式Meeting mode

设备当会议记录仪用:实时转写、字幕整理和翻译、会后区分说话人并生成纪要。认证帧:

Use the device as a meeting recorder: live transcription, cleaned-up and translated captions, and after the meeting speaker labels and minutes. AUTH frame:

<token>##session_type:meeting##mode:vad##device_id:<id>##caption_target_lang:zh##caption_mode:bilingual
参数Parameter说明Description
meeting_id传已有的 meeting_id 可在断线后续上同一场会议Pass an existing meeting_id to resume after a disconnect
caption_target_lang / caption_mode字幕翻译目标语言(zh、en…)/ original、translated、bilingualCaption target language (zh, en…) / original, translated, bilingual
asr_language / asr_allowed_languagesauto / zh / en;auto 时允许的语言,默认languages allowed in auto, default zh,en
meeting_topic会议主题和专有名词(≤500 字,不能含 #),帮助纠错Topic and proper nouns (≤500 chars, no #) to help correction
summary_template纪要模板(YAML),不传自动选择Minutes template (YAML); auto-selected if omitted

下行 STATUS 里会有 ##TRANSCRIPT:…(逐句转写)、##CAPTION_INTERIM:…(未定稿字幕,整行替换)、##CAPTION_FINAL:…(定稿字幕)。会议相关的 HTTP 接口:

Downstream STATUS carries ##TRANSCRIPT:… (per-sentence transcripts), ##CAPTION_INTERIM:… (draft caption, replace the whole line) and ##CAPTION_FINAL:… (final caption). Meeting HTTP APIs:

接口Endpoint说明Description
POST/v2/meeting创建会议Create a meeting
GET/v2/meeting/{meeting_id}会议状态Meeting status
POST/v2/meeting/{meeting_id}/stop-and-summarize结束会议并生成纪要End the meeting and generate minutes
GET/v2/meeting/{meeting_id}/summary查纪要(轮询方式)Get minutes (polling)
GET/v2/meeting/{meeting_id}/transcripts完整转写Full transcript
PUT/v2/meeting/{meeting_id}/summary-template换纪要模板Change the minutes template
POST/v2/meeting/{meeting_id}/retry-summarize重新生成纪要Regenerate minutes
GET/v2/meeting/{meeting_id}/audio下载会议录音Download the recording
GET/v2/meetings?npcid=…&limit=20&offset=0某个角色的历史会议(npcid 必填)A character's past meetings (npcid required)
POST/v2/webhook-config纪要生成后推送到你的地址:Push minutes to your URL: {"action":"update","webhook_url":"…","webhook_secret":"…"}
05
服务端接口Server APIs
音色、知识库、记忆、推送等管理接口Voices, knowledge, memory, push and more

音色与克隆Voices and cloning

接口Endpoint请求Request说明Description
GET/v2/get_voice_ids—可用音色列表(公共 + 本组织克隆的)Available voices (public + your clones)
POST/v2/voice_clonemultipart: voice_id, audio_file上传一段干净的人声提交克隆,返回任务;最终使用的 voice_id 以返回和状态查询为准Upload a clean voice sample to start cloning; use the voice_id from the response / status as the final ID
GET/v2/voice_clone/{voice_id}—克隆进度Cloning status

样本建议 10–30 秒、单人、无背景音乐和回声;同一段话复制拼接的音频会被拒绝。

Use 10–30 s of a single speaker without music or echo; audio made by repeating the same clip is rejected.

试听与批量合成Preview and batch synthesis

POST/v2/tts{"text":"你好","voice_name":"<voice_id>","voice_speed":1.0,"vol":1}返回 WAV 音频(16 kHz)。voice_speed 0.5–2.0,vol 0–10Returns WAV audio (16 kHz). voice_speed 0.5–2.0, vol 0–10
POST/v2/tts/batch{"items":[{"id":"1","text":"你好","voice_name":"…","voice_speed":1.2,"lang":"japanese"}],"timeout":60}一次合成多条,返回 {"results":[{"id","audio": base64 WAV}],"failed":0}Synthesize many at once; returns {"results":[{"id","audio": base64 WAV}],"failed":0}

技能书Skill books

技能书是给角色的专属知识库(产品手册、FAQ、故事集…)。流程:创建 → 上传文件 → 标记就绪 → 等学习完成 → 把 skill_id 写进模板或角色的 skill_ids。

A skill book is a private knowledge base for a character (manuals, FAQs, stories…). Flow: create → upload files → mark ready → wait for learning → add the skill_id to a template's or character's skill_ids.

接口Endpoint请求Request返回Response
POST/v2/skillbook/skillform: skill_name, public (true/false), description{"skill_id":"…"}
POST/v2/skillbook/uploadmultipart: skill_id, file (可多个;.md .txt .docx .doc .epub)(repeatable; .md .txt .docx .doc .epub){"message":"N files uploaded successfully"}
POST/v2/skillbook/ready/{skill_id}—开始学习Starts learning
GET/v2/skillbook/status/{skill_id}—status: created → ready for processing → learning N → finished(失败为 error / upload_failed) (or error / upload_failed)
GET/v2/skillbook/skills—技能书列表Skill book list

记忆(Hippo)Memory (Hippo)

角色会自动记住对话,并在后台整理出个人知识图谱(PKG)、关系和日记。这些接口用于读取、补充或修正。路径里的 {npcid} 必须属于你的组织。

Characters remember conversations automatically and, in the background, distill a personal knowledge graph (PKG), relationships and a diary. These APIs read, add to or correct them. {npcid} must belong to your organization.

接口Endpoint说明Description
POST/hippo/api/memory/{npcid}写一轮对话:Write one exchange: {"user_content":"…","assistant_content":"…","timestamp":""}
GET/hippo/api/memory/{npcid}?page_size=20&last_key=…分页读对话记忆(新的在前);有更多时返回 next_key,URL 编码后作为下一页的 last_keyPaged conversation memory, newest first; next_key is returned when there is more — URL-encode it as the next last_key
GET/hippo/api/pkg/{npcid}个人知识图谱Personal knowledge graph
PUT/hippo/api/pkg/{npcid}按字段合并更新:Merge-update fields: {"updates":[{"key":"Hobbies","value":["游泳","画画"]}]}。新角色还没生成 PKG 时返回 404. Returns 404 for a new character that has no PKG yet
GET/hippo/api/relationship/{npcid}关系数据Relationship data
GET/hippo/api/diary/{npcid}日记Diary
POST/hippo/api/dream/{npcid}?dry_run=true立即整理记忆(写日记、抽取 PKG、清理过期记忆);dry_run 只计算不写入。返回 {"status":"ok","report":{…}}Consolidate memory now (diary, PKG extraction, cleanup); dry_run computes without writing. Returns {"status":"ok","report":{…}}

PKG 单值字段(覆盖写入):Name(已有则不覆盖)Gender Age Occupation City Location Timezone Description Relationship "Favorite Food" Philosophy Father Mother other profile。多值字段(去重追加):Nickname(5) "Favorite Sports" "Favorite Books" "Favorite Movies" Hobbies(各 10)。字段名不区分大小写。

PKG single-value fields (overwrite): Name (not overwritten once set), Gender, Age, Occupation, City, Location, Timezone, Description, Relationship, "Favorite Food", Philosophy, Father, Mother, other, profile. Multi-value fields (deduplicated append): Nickname (5), "Favorite Sports", "Favorite Books", "Favorite Movies", Hobbies (10 each). Field names are case-insensitive.

用量统计Usage statistics

GET /v2/statistics?startTime=<ms>&endTime=<ms>&granularity=DAILY&npcId=…&deviceId=…

按天(DAILY)或按月(MONTHLY)返回本组织的对话次数和 token 用量,可按角色或设备过滤;时间是毫秒时间戳,跨度最多 30 天。返回 records[],每项含 period、callCount、inputToken、outputToken、totalToken。

Your org's conversation count and token usage per day (DAILY) or month (MONTHLY), optionally filtered by character or device. Times are millisecond timestamps, up to 30 days apart. Returns records[] with period, callCount, inputToken, outputToken, totalToken.

封禁Blocking

封禁某台设备或某个角色后,它将无法再建立对话。

A blocked device or character can no longer start conversations.

接口Endpoint请求Request
POST/hippo/api/device/block{"type":"device"|"npc","identifier":"…","reason":"…"}
POST/hippo/api/device/unblock同上Same as above
GET/hippo/api/device/blocklist?type=npc封禁列表Block list
GET/hippo/api/device/block/check?type=npc&identifier=…{"blocked":true|false,…}

设备推送Device push

从你的服务端给在线设备发消息(播报、通知、进度)。设备离线时,speak / text / info 会排队,设备重连后送达。

Send messages from your server to an online device (announcements, notices, progress). If the device is offline, speak / text / info are queued and delivered on reconnect.

POST /push/api/push
{"npcid":"<npcid>","type":"speak","payload":{"text":"你的快递到了"},
 "priority":"normal","callback_url":"https://your.server/hook","task_id":"optional-id"}
→ 200 {"ok":true,"task_id":"a1b2c3d4","status":"delivered"}
→ 202 {"ok":true,"task_id":"a1b2c3d4","status":"queued","queue_position":1}
type设备收到Device receivespayload离线排队Queued offline
speak 默认default角色音色播报(AUDIO)Spoken in the character's voice (AUDIO)text✓
textTEXT + ENDtext✓
infoSTATUS ##INFO:…text✓
imageIMAGE (0x0a)url否,离线返回 404No; 404 if offline

priority:urgent / high / normal / low。查询任务状态:GET /push/api/tasks/{task_id}。只能推给本组织的角色,否则 403。

priority: urgent / high / normal / low. Task status: GET /push/api/tasks/{task_id}. You can only push to your own characters (403 otherwise).

旧接口 POST /push/api/speak({"npcid","text"})仍可用,等同 type=speak。

The legacy POST /push/api/speak ({"npcid","text"}) still works and equals type=speak.

日志推送Log webhook

每轮对话或后台记忆任务结束后,把 token 用量和对话内容 POST 到你的地址,用于对账或自己的数据分析。用 POST /v2/log_config 管理,body 里的 action 取:

After each conversation turn or background memory task, we POST token usage and content to your URL for reconciliation or analytics. Manage it with POST /v2/log_config, where action is:

action参数Parameters
query_webhook—
update_webhookfields: 只传要改的项——only the items to change — log_webhook_url, log_webhook_headers (object, {} 清空clears), log_webhook_template (object, null 恢复完整推送restores full payload), log_webhook_wrap (bool, default true)
delete_webhook— 立即停止推送— stops pushing immediately

推送类型:llm_log(每轮对话,含 npcid、device_id、inputToken、outputToken、prompt、answer、各阶段耗时)、dream_log / flush_log(后台记忆任务)。wrap=true 时格式为 {"type":"llm_log","data":{…}}。不配 template 会推送完整内容(包括对话原文);配了 template 只推映射后的字段,适合只要 token 用量的计费平台。template 支持字段改名,以及 const、uuid、now、datetime、sum、field 规则。

Payload types: llm_log (each turn: npcid, device_id, inputToken, outputToken, prompt, answer, per-stage timings) and dream_log / flush_log (background memory tasks). With wrap=true the body is {"type":"llm_log","data":{…}}. Without a template the full payload, including conversation text, is sent; with a template only mapped fields are sent, which suits billing platforms that need token counts only. Templates support field renames and the rules const, uuid, now, datetime, sum, field.

{"action":"update_webhook","fields":{
  "log_webhook_url":"https://your.server/llm-log",
  "log_webhook_headers":{"Authorization":"Bearer your-token"},
  "log_webhook_template":{"upstream_tokens":"inputToken","downstream_tokens":"outputToken",
    "total":{"type":"sum","sources":["inputToken","outputToken"]},"platform":{"type":"const","value":"my-app"},
    "ts":{"type":"now"},"sent_at":{"type":"datetime","source":"timestamp"}}}}
→ {"status":"success","data":{"updated":["log_webhook_url","log_webhook_headers","log_webhook_template"]}}
06
参考Reference
错误码、常见问题和版本变化Errors, FAQ and changes

错误与常见问题Errors and FAQ

HTTP含义Meaning
401 / 403key 无效、已撤销,或账号未审核 / 已停用;访问别的组织的角色Invalid or revoked key, account pending or suspended; accessing another org's character
404角色不存在或不属于你(/v2/login);PKG 还没生成Character missing or not yours (/v2/login); PKG not generated yet
400参数缺失或格式错误Missing or malformed parameters
5xx服务端错误,可重试;持续出现请联系我们Server error; retry, and contact us if it persists

很多 /v2 接口失败时 HTTP 仍是 200,请同时检查返回体里的 status / code。

Many /v2 endpoints return HTTP 200 on failure too; also check status / code in the body.

认证成功但没有回复? duplex 要先等 LISTEN start,并持续推音频(包括静音);auto 要先由客户端发 LISTEN start;manual 要发 END。录音末尾没有静音时,服务端无法判断你说完了。

Authenticated but no reply? In duplex, wait for LISTEN start and keep streaming (silence included). In auto, the client must send LISTEN start first. In manual, send END. Without trailing silence the server cannot tell you have finished.

断线了怎么办? 重新连接并发认证帧;令牌过期就先调 /v2/login。

Disconnected? Reconnect and send AUTH again; call /v2/login first if the token expired.

用量和计费:Harness 的用量目前不在控制台的「用量」页里显示,按合同结算。按天 / 按月的 token 用量可查 /v2/statistics,逐轮明细可配置日志推送。

Usage and billing: Harness usage is not yet shown on the console's Usage page and is settled per contract. Daily / monthly token usage is at /v2/statistics; for per-turn detail configure the log webhook.

变更记录Changelog