当一个 Agent 需要长期服务多个人、项目或工作区时,只记住“发生了什么”还不够,它还要记住“这是关于谁的”。User / Peer 用来把数据的所有权与交互对象分开,让记忆有清楚的归属,也让后续召回使用正确的上下文。
OpenViking 的每个 user 目录下,都可以使用 peer / 子目录来区分当前目录下的记忆和资源。
你关心的问题 | User | Peer |
|---|---|---|
它表示什么? | OpenViking 内的数据所有者和访问主体,可以是自然人,也可以是 Agent、机器人服务或固定集成实例。 | 某个 User 持续服务或交互的对象,可以是人、Agent、项目或工作区。 |
它属于哪一层? | 位于数据空间(Account)内,拥有自己的 User 根目录。 | 位于某个 User 的 peers/ 目录内;换一个 User,同名 Peer 也不是同一份数据。 |
需要独立凭证吗? | 访问请求先通过凭证确定当前 User,或由受信任服务明确指定身份。 | 不持有独立 User Key,也不独立鉴权;访问仍使用所属 User 的身份。 |
能保存什么? | 自身记忆、资料、会话、技能和隐私相关数据,以及这个 User 下的所有 Peer。 | 关于该对象的记忆和资料,即 memories/ 与 resources/。 |
用它解决什么? | 数据所有权、身份和访问边界。 | 一个数据所有者与多个对象交互时的记忆归属和检索视角。 |
例如,一位 IT 助手(Agent)可以是 User,员工 Alice 和 Bob 是它的两个 Peer。Alice 的设备偏好和 Bob 的历史工单分别保存,但两份数据仍由这个 IT 助手的 User 管理,Agent 可以使用他的专属鉴权 API Key 访问 Alice 和 Bob 与它相关的记忆和知识资产。员工不必因此各自注册一个 OpenViking User。反过来,如果 Alice 自己拥有数据,也可以让 Alice 是 User,把不同 Agent 或项目作为 Peer。
在 OpenViking 的配置语境下,本文把 User 自己的内容称为 Self。Self 不是另一个账号,而是与 Peer 相对的“目录所有者自身”这一侧。
下面以 User = it_assistant、Peer = person_8f31 为例。路径中的名称都是示例;目录和文件会按实际写入与抽取结果出现,不代表创建 User 后就已生成全部内容。
viking://user/it_assistant/ ├── memories/ # Self:目录所有者自身的记忆 │ ├── profile.md # 画像 │ ├── preferences/ # 偏好 │ ├── entities/ # 实体及其长期事实 │ ├── events/ # 事件 │ ├── identity.md # Agent 身份(适用时) │ ├── soul.md # Agent 风格与行为原则(适用时) │ └── experiences/ # 执行经验(需相应能力开启) ├── resources/ # 这个 User 使用的资料 ├── sessions/ # 原始对话、归档和抽取记录 ├── skills/ # 安装的技能 ├── privacy/ # 隐私相关数据 └── peers/ └── person_8f31/ ├── memories/ │ ├── profile.md │ ├── preferences/ │ ├── entities/ │ └── events/ └── resources/ # 这个对象提供或专属的资料
内容 | 放在哪里 | 如何产生 / 使用 |
|---|---|---|
关于一个对象的长期信息 | Self 的 memories/,或对应 peers/{peer_id}/memories/ | 会话提交后,按消息归属、记忆策略和已启用的记忆类型抽取。 |
原始文档、图片、网页、日志等资料 | User 的 resources/,或对应 Peer 的 resources/;数据空间共享资料可放在 viking://resources/ | 通过资源导入接口写入。把文件放进 resources/ 与从会话抽取 memories/ 是两条不同流程。 |
对话过程与抽取依据 | User 的 sessions/{session_id}/ | Session 始终属于 User;同一 Session 中可以有多个 Peer,依靠每条消息的 peer_id 区分。 |
技能、隐私相关目录 | User 的 skills/、privacy/ | 当前不提供 Peer 专属的 skills/、sessions/ 或 privacy/ 根目录。不要自行假设这些路径受支持。 |
User 和 Peer 架构十分灵活,你可以基于业务搭建不同的 Agent 交互场景架构。
场景 | 推荐建模 | 记忆放置与注意点 |
|---|---|---|
企业 IT / HR / 客服助手
|
| 服务规则和通用执行经验放在 User;每个人的偏好、历史问题和专属资料放在对应 Peer。 |
个人助手与多个 Coding Agent
|
| Peer 的含义由你决定,但同一个 ID 应长期保持同一种含义。按工作区分 Peer 可以区分项目事实;希望跨机器连续记忆时使用显式项目 ID。 |
每个人 / Agent 都独立沉淀上下文资产
|
| 每个用户与每个Agent的 Session 分别双写至用户的 user 目录 和 agent 的 user 目录。 |
以下示例假设 User 是常驻的 IT 助手,person_8f31 是它服务的一位员工。所有请求都使用这个 User 的凭证。
向 POST /api/v1/sessions 传入显示配置(详见:create_session-创建会话)。示例显式打开 Self 和 Peer,并把抽取范围限制在最常用的四类对象记忆:
{ "session_id": "helpdesk-peer-demo-001", "memory_policy": { "self": { "enabled": true }, "peer": { "enabled": true }, "memory_types": ["profile", "preferences", "entities", "events"] } }
Session 创建时默认 self.enabled 与 peer.enabled 均为 true,但实例默认、User 配置和 Session 配置都可能改变最终结果。
如果本次只希望产生 Peer 记忆,可以把 self.enabled 设为 false。没有 Peer 归属的内容不会因为关闭 Self 就自动转给某个 Peer;仍必须给对应消息传入 peer_id。
向 POST /api/v1/sessions/helpdesk-peer-demo-001/messages 发送消息 JSON(详见:add_message-添加消息)。员工的消息明确属于 person_8f31;这个例子中,服务 Agent 的回复不指定 Peer,保留在 User 自身的上下文中。
{ "messages": [ { "role": "user", "peer_id": "person_8f31", "content": "我负责数据平台,主要使用 macOS。以后给我的排障步骤请用中文,并优先提供命令行方式。" }, { "role": "assistant", "content": "收到。我会优先提供适用于 macOS 的中文命令行排障步骤。" } ] }
同一个 Session 有多个人时,为各自的 user 消息分别填写 peer_id。有些插件会把整个交互轮次的 user 和 assistant 消息标到同一 Peer。
提交会话会先归档消息,再在后台执行摘要与记忆抽取。成功写入消息不等于长期记忆已产生;Commit 返回 accepted 也只表示后台任务已接收。
POST /api/v1/sessions/helpdesk-peer-demo-001/commit Authorization: Bearer <USER_API_KEY> Content-Type: application/json {"keep_recent_count": 0}
从响应的 result.task_id 取出任务 ID,查询 GET /api/v1/tasks/{task_id},直到任务完成或明确失败。若返回 skipped 且 task_id 为 null,先检查是否有可归档的新消息。
在调用 find,search 和 其他文件系统的操作时,可指定header 或限定target_uri 为 peer/ <peer_id> 目录来定向获取某个交互对象的上下文:
POST /api/v1/search/find Authorization: Bearer <USER_API_KEY> Content-Type: application/json { "query": "这位用户习惯怎样的排障步骤?", "target_uri":"viking://users/it_helpdesk_bot/peers/user_1/", "max_tokens": 1600 }
或:
POST /api/v1/search/search Authorization: Bearer <USER_API_KEY> Content-Type: application/json X-OpenViking-Actor-Peer: person_8f31 { "query": "这位用户习惯怎样的排障步骤?", "mode": "context", "peer_scope": "actor", "max_tokens": 1600 }
以下插件可直接使用插件配置来控制 peer 的拆分逻辑,设置 peer 模式后,插件将自动化地为 peer 写入上下文。
集成 | 可直接配置的 Peer 能力 | 自动捕获 / Commit 与适用场景 |
|---|---|---|
OpenClaw 专属插件 | peer_role = person / assistant / none;peer_prefix 为 assistant 模式提供可选前缀。 | 有生命周期接入。person 最适合一个 Agent 服务多个真实用户;assistant 用于把不同 OpenClaw Agent 作为 Peer。 |
Claude Code、Codex、Cursor、TRAE / TRAE CN、OpenCode、DSH 专属插件 / 扩展 | OPENVIKING_PEER_ID;OPENVIKING_WORKSPACE_PEER;OPENVIKING_RECALL_PEER_SCOPE。 | 有自动捕获、召回和生命周期 Commit,触发时机因宿主而异。 |
参考:OpenClaw 安装与配置
已安装并连接 OpenViking 后,把插件配置改为 person,重启网关,再检查状态:
openclaw config set plugins.entries.openviking.config.peer_role person openclaw gateway restart openclaw openviking status --json
peer_role | 消息如何标注 | 适合什么情况 |
|---|---|---|
person | user 消息的 peer_id 来自发送者身份;数据面请求使用同一个人的 Actor Peer。 | 客服、IT / HR 助手、群机器人等一对多服务。必须能从渠道拿到稳定 sender identity。 |
assistant | assistant 消息标注当前 OpenClaw Agent 的 Peer ID;user 消息不因此变成个人 Peer。peer_prefix 只对这个模式生效。 | 一个数据所有者与多个 OpenClaw Agent 交互,按 Agent 区分上下文。不是“每个客户一个 Peer”。 |
none(默认) | 关闭插件的 Peer 消息归因与 Actor Peer 路由。 | 不需要 Peer 分组,或正在以 User 级方式使用记忆。 |
参考:完整插件集成能力参考
配置 | 默认 / 行为 | 什么时候改 |
|---|---|---|
OPENVIKING_PEER_ID | 显式指定稳定 Peer,覆盖工作区派生值。 | 希望同一项目在不同机器、路径或 Worktree 下复用同一个 Peer。 |
OPENVIKING_WORKSPACE_PEER | 默认开启;设为 0 关闭从工作区路径派生 Peer。 | 希望完全由业务或显式配置决定身份,避免路径变化产生新的 Peer。 |
OPENVIKING_RECALL_PEER_SCOPE | 默认 all,可召回其他工作区记忆并降权;设为 actor 排除其他 Peer。 | 多人服务、客户数据隔离,或项目之间不应交叉召回时。 |
Hook 会把有效 Peer 用于捕获消息的 peer_id,并在数据面请求上发送 Actor Peer。但一个进程级环境变量只能表达一个固定 Peer,不会替你区分同时接入的 Alice 和 Bob。自建多人机器人需要按每次交互传入正确身份