CHARACTOID 是什么
CHARACTOID 是一个本地优先、角色驱动、可恢复执行的 Agent 工作台。 它不是把聊天、知识库、音频和 Live2D 拼在一起的页面集合,而是把这些能力放进同一个可追踪的运行模型:一次请求有明确的入口、路由、Worker、工具、状态事件、结果资产和最终回复。
事实依据:
app/main.py、app/startup/routes.py、agents/graph/、agents/registry.py、agents/runtime/、app/routers/、voice/、rag/。
一句话模型
用户永远对着某个角色说话。角色带着自己的人设、知识、记忆、声音、形象和授权能力。监督者(persona_supervisor)是唯一对用户开口的出口;领域 Worker 只返回结构化结果,不直接扮演角色。
flowchart TB
subgraph entry [入口]
UI[Web UI /static]
API[FastAPI /api]
end
subgraph agent [角色运行时]
S[persona_supervisor]
W[knowledge / memory / document / profile / voice / rvc / live2d / config]
T[ToolSpec 注册表]
end
subgraph data [数据面]
DB[SQLite]
RS[RunStore]
FS[附件与资产]
end
UI --> API --> S
S --> W --> T
W --> RS
T --> DB
T --> FS
S --> UI五个核心原则
- Supervisor 是唯一的对外表达出口。Worker 必须交出符合
_WORKER_OUTPUT_SCHEMA的结果:worker, status, answer, evidence, artifacts, uncertainties, citations, trace, requires_approval, error。监督者再组织成角色口吻。 - 模型负责选择,代码负责执行。需要访问知识库、SQL、文件或外部服务时,执行路径由
agents/tools/*的确定性代码约束,而不是让模型自由调任意系统命令。 - 输入和结果使用引用。附件、任务和音频结果通过
attachment_id、run_id、asset_id、session_id、task_id关联。浏览器拿不到本地绝对路径。 - 可暂停、可确认、可恢复。写操作、联网回退和资源变更可以进入人工确认(HITL)或 checkpoint。运行可用
POST /api/runs/{id}/cancel取消,POST /api/runs/{id}/approval审批。 - 能力按角色授权。内置 Tool、Skill 和 MCP 都要经过注册、作用域和授权;不是把全部工具塞给每个角色。角色能力见
GET/PUT /api/personas/{id}/capabilities,MCP 授权见GET/PUT /api/personas/{id}/mcp-grants。
运行入口
应用工厂在 app/main.py:create_app(),路由注册在 app/startup/routes.py:register_routes。
默认端口 18000。根路径 / 重定向到 /static/index.html。
内建系统接口(直接写在 register_routes,不属于某个业务 router):
| 方法 | 路径 | 作用 |
|---|---|---|
| GET | /api/health | {"status":"ok","workspace_id":...} |
| GET | /api/status | ingestion.status.get_system_status() |
| GET | /api/launcher/progress | 启动器进度;未注入时返回空步骤 |
静态资源:
/static→ Web 工作台/live2d-assets→data/live2d/sqlite→ 可选 Datasette 挂载(依赖安装失败时静默跳过)
Worker 不是插件口号
agents/registry.py 里的规范顺序是固定的:
knowledge_worker → memory_worker → document_worker → profile_worker → voice_worker → rvc_worker → live2d_worker → config_worker
超时与重试(秒):
| Worker | 超时 | 重试 |
|---|---|---|
| knowledge_worker | 45 | 最多 2 次,backoff 0.5s |
| memory_worker | 30 | 1 |
| document_worker | 120 | 最多 2 次,backoff 1s |
| profile_worker | 30 | 1 |
| voice_worker | 300 | 1 |
| rvc_worker | 1800 | 1 |
| live2d_worker | 45 | 1 |
| config_worker | 45 | 1 |
兼容别名(_WORKER_COMPAT_ALIASES)仍然认识旧短名:knowledge、memory、document、profile、voice、voice_clone、live2d、rvc、config。新代码应使用 *_worker 全名。
清单 HTTP 接口:
GET /api/workers/manifestsGET /api/workers/manifests/{worker}
它不是什么
- 不是云端多租户 SaaS。默认假设本机用户,
require_local会拒绝非本机写资源和敏感操作。 - 不是通用操作系统 Agent。没有任意 shell、没有任意文件系统遍历;工具按 specialist 切片。
- 不是“有页面就等于能力已就绪”。语音、RVC、Embedding、GPT-SoVITS、Live2D 都是可选资源,
/api/status和资源页会显示未就绪。 - 不是 Worker 直接对用户说话的系统。如果某个 Worker 返回了适合展示的
answer,仍然由监督者决定如何说。
和页面的对应关系
落地页把同一条链拆成几章,只是展示,不是另一套架构:
| 落地页章节 | 对应源码事实 |
|---|---|
| 工作台 | 角色是工作台:人设、知识、对话在同一对象上 |
| 案例 | 一句话落到一次真实操作(附件、确认、长任务、结果) |
| 系统 | 监督者编排,Worker 分头执行 |
| 接入 | QQ / 直播等外部通道接到同一角色 |
| 资源 | Worker 依赖可管理资源,而不是凭空推理 |
更细的源码地图见 源码地图,模块关系见 系统架构,任务状态机见 任务生命周期。
源码合同(中档补全)
CHARACTOID 不是多页面 SaaS:默认拒绝非本机写资源。也不是通用操作系统 Agent:没有任意 shell、没有任意文件系统。RVC、Embedding、GPT-SoVITS、Live2D 都是可选资源,GET /api/status 未就绪时必须允许「缺了也能对话」。
Worker 超时(秒)是产品边界,不是建议值:profile 30、document 120、knowledge/live2d/config 45、memory 30、voice 300、rvc 1800。超时后 Run 失败或进入可恢复错误,前端应按事件展示,不要当卡住。
HTTP 面工厂:app/main.py:create_app() → middleware → register_routes → 静态挂载。数据面默认 SQLite + Milvus Lite;Lite 的 .db 只能被同一进程里的 MilvusClient 使用,退出时 close_milvus_connections。
默认入口不是聊天 SaaS 首页,而是本机工作台。GET / 只重定向到 /static/index.html。对话页可以触发资源安装、文档索引、RVC、TTS,但这些仍然是 Worker 任务,有 Run、事件、确认和失败态。
不要把 CHARACTOID 理解成:
- 云端多租户(
workspace_id写死local-default) - 通用电脑接管(无任意 shell)
- 「装完就能说话」的语音产品(GPT-SoVITS / RVC / ASR 均可缺)
- Worker 直接对用户播报的多机器人聊天室(用户只面对 Supervisor)
可选资源未装时,/api/status 与资源页必须能表示未就绪,而不是让对话入口消失。
创建角色、绑定知识/声音/形象、在对话里提出目标、Supervisor 选 Worker、Worker 执行可观察任务——这条主线在源码里是同一套 Run,而不是五个微应用。文档分层(guide / capabilities / concepts / development / reference / troubleshooting)只是阅读切面。
要查「某个按钮打哪条路由」,先看 API 地图,再看对应 reference 页,不要在本页复制 schema。