N.E.K.O × VRChat 架构解析:一个 AI 伙伴是怎么真正「进入」VRChat 的

文章发布时间:

最后更新时间:

文章总字数:
15.7k

预计阅读时间:
62 分钟

页面浏览: 加载中...

分析快照:2026-09-09 · 端口、频率与优先级均以该日期的公开源码为准,后续版本请以仓库当前代码为准。

本文不是图鉴,也不是接口清单,而是一篇从“它到底在解决什么问题”出发的技术拆解。你可以先按小白版一路读懂,再按每节的“专业版”展开到底层协议、频率、端口、调度与反馈闭环。

配套资源目录沿用现有 Wiki:diagrams/svg/、diagrams/png/、diagrams/mmd/、terminal/svg/、terminal/png/、terminal/txt/。文中所有图都用这些现有 slug,不要求重新命名。


0. 先回答最核心的问题:这个插件到底做了什么?

如果只看视频,很容易把它理解成:

“给 LLM 接了 VRChat,然后模型自己操控角色。”

实际工程结构复杂得多。真正发生的是:N.E.K.O 负责“人格、记忆、语言和意图”,VRChat 插件负责把这些低频意图转换成高频、稳定、可执行的身体控制。

换句话说,LLM 不会每 8.3ms 计算一次右手坐标,也不会每一帧都决定“下一步往前 1cm”。它只需要作出类似:

  • “向那个人打招呼”;
  • “走到他旁边”;
  • “伸手去拿”;
  • “转头看看右边”;

这样的语义级决策。

真正的身体运动、插值、动作冲突处理、输入释放、导航修正,都交给本地 deterministic controller 完成。

整个系统总览
整个系统总览

技术资源:SVG · PNG · Mermaid 源码

小白版:把它想成“脑子 + 小脑 + 神经 + 眼睛”

最容易理解的比喻是人类身体:

  • N.E.K.O / LLM 像“大脑”:知道你是谁、记得刚才聊了什么、决定“我要挥手”;
  • Behavior FSM + BodyScheduler 像“小脑”:把“挥手”变成平滑动作,并避免你一边鞠躬一边把手瞬移到头顶;
  • AnyaDance + SteamVR 像“运动神经”:把身体姿态真正送进 VRChat;
  • VRChat OSC 像“反馈神经”:告诉系统角色是否真的在动、Avatar 参数是什么;
  • DXcam / OpenVINO / VLM 像“眼睛”:看 VRChat 桌面画面,找玩家、目标和障碍迹象;
  • World State 像“短期空间认知”:把“屏幕右边那个框”变成稳定的 entity_7,让后续导航还能继续追踪它。

这套架构最大的优点是稳定。LLM 偶尔想慢一点,不会让身体停摆;视觉模型偶尔慢一帧,也不会卡死 120Hz 的身体线程。

代价也很明显:系统变成了多层架构,调试难度更高,而且“看见世界”和“知道自己真的做到了”需要额外的反馈机制,不能只看 LLM 自己怎么说。

专业版:总览图的真实模块、频率和控制边界

这一总览可以拆成四个不同时间尺度:

  1. 认知层:N.E.K.O 的对话、记忆、Agent Tool 调用,通常是 0.1–1Hz 量级或事件驱动;
  2. 导航层:Navigator 默认约 10Hz,负责闭环 steering,而不是让 LLM 连续输出摇杆值;
  3. 姿态输入层:N.E.K.O VMC 默认 60Hz,把 VRM 最终姿态发给插件;
  4. 身体输出层:BodyScheduler / AnyaDance 输出默认 120Hz,把六点姿态和 controller overlay 一起送进 OpenVR virtual devices。

这是一种典型的 hierarchical embodied-agent architecture:高层 policy 输出低频目标,本地 controller 把目标变成高频 actuator command;感知和执行再通过 OSC / screen capture 回到 world model。

关键点不是“LLM 控制了 VRChat”,而是 LLM 只拥有受控的语义工具;真正的 actuator authority 在 scheduler / backend。

相关参数:

  • N.E.K.O 主 HTTP:默认 127.0.0.1:48911;
  • VMC:127.0.0.1:39539,host 默认发送 60Hz;
  • AnyaDance:127.0.0.1:39570,插件默认 120Hz;
  • Driver telemetry:multicast 239.255.39.71:39571;
  • VRChat OSC:插件发送 9000,监听 9001;
  • Autonomy:manual_arm=true,session TTL 默认 30 分钟。

技术收益:控制回路与模型推理解耦、延迟可预测、LLM 不承担实时系统职责、故障可以分层降级。

技术代价:状态同步复杂;需要区分 accepted / sent / driver received / VRChat actually moved;多条 UDP 链路天然没有事务语义;视觉世界状态必须处理 freshness 与 uncertainty。

接下来先不要急着看 AnyDance、OSC 或 World-Native。第一件事应该先搞清楚:N.E.K.O 本体和这个 VRChat 插件到底谁负责什么。


1. N.E.K.O 是“脑”,VRChat 插件是“身体运行时”

N.E.K.O 本体职责
N.E.K.O 本体职责

技术资源:SVG · PNG · Mermaid 源码

小白版:为什么不能把所有东西都塞进一个 LLM?

N.E.K.O 本体本来就是一个 AI 伙伴平台:它管对话、角色设定、记忆、语音、VRM/Live2D/MMD 显示,以及 Agent 工具。

所以 VRChat 插件不是重新造一个 AI,而是给已有 AI 加上一具“能在 VRChat 里活动的身体”。

举个例子:

  1. 你说:“去跟右边那个人打招呼。”
  2. N.E.K.O 负责理解“右边那个人”以及“打招呼”这件事;
  3. 插件负责把它拆成:观察目标 → 转向 → 接近 → 停下 → 挥手;
  4. 每个动作是否安全、是否冲突、是否真的执行成功,再由本地 runtime 判断。

如果让 LLM 自己负责每个关节和每个网络包,系统会既慢又脆弱。

专业版:N.E.K.O 的职责边界与插件扩展面

N.E.K.O 是主应用层,提供 Core / Assist model、memory、avatar runtime 与 plugin/tool system。VRChat 插件通过插件系统把模型可调用工具暴露给 Agent,同时把高频 runtime 放在独立 backend 中。

这里的重要工程边界是:模型只调用工具,不直接访问 driver socket 或 SteamVR device state。

这意味着可以对工具做 schema validation、admission control、permission gate 和结果语义规范化。比如 body_express(intent="greet") 是一个稳定、高层接口;其内部未来可以换 VMD、程序化 gesture 或其他动作实现,而不需要改变 LLM 的推理方式。

N.E.K.O 当前默认主服务器端口是 48911,官方文档也强调这是 local integration surface,不应该暴露到不可信网络。

为什么还要“插件进程隔离”?

展开:插件进程隔离解释为什么抓屏、视觉、120Hz UDP 不直接塞进 N.E.K.O…
插件进程隔离
插件进程隔离

技术资源:SVG · PNG · Mermaid 源码

小白版:别让“身体出问题”把整个 AI 一起拖死

可以把 N.E.K.O 想成一个大商场,插件是里面不同店铺。VRChat 插件又很特殊:它要不停抓屏、跑视觉、发 120Hz UDP、听 OSC、做导航。

如果这些东西全塞进主程序,一旦某个 driver 卡住、视觉库崩掉,可能直接把整个 N.E.K.O 拖慢。

所以它把重活继续拆到本地 backend process。

专业版:两级隔离的意义

现有架构表现为:

N.E.K.O main → plugin process / hosted plugin → local backend process。

本地 backend 承载 BodyScheduler、VMC relay、VRChat OSC、Vision、World State、Navigator 等长期运行组件。Hosted plugin 更接近 SDK / LLM tool adapter。

这种拆分的技术收益:

  • 高频线程和模型/主 UI 隔离;
  • 可独立 restart backend;
  • 重依赖(OpenVINO、capture stack 等)不污染主 runtime;
  • 本地 IPC 可以加 token / loopback 限制。

代价是状态机跨进程,需要处理 backend 不可用、版本不匹配、生命周期 race 和 IPC error mapping。

到这里我们只知道“脑”和“身体”分开了,但还没有解释一个关键问题:N.E.K.O 屏幕里本来已经有一个 VRM 角色,它的动作究竟怎么跨出浏览器,进入 VRChat? 这就是 VMC 出场的原因。


展开:本节技术档案(1 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:两级进程隔离用缩进快速展示两级隔离。
两级进程隔离
两级进程隔离

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

用缩进快速展示两级隔离。

小白版

小白看成“大程序里有插件,插件再叫一个身体后台”;专业上是宿主插件边界和高频 backend 边界分离,利于依赖/故障隔离,但增加 IPC 生命周期。

展开专业版

小白看成“大程序里有插件,插件再叫一个身体后台”;专业上是宿主插件边界和高频 backend 边界分离,利于依赖/故障隔离,但增加 IPC 生命周期。

原始终端内容:

1
2
3
4
5
6
7
8
9
10
N.E.K.O
└── plugin process
└── VRC Body hosted plugin
└── local backend process
├── BodyScheduler
├── VMC relay
├── VRChat OSC
├── Vision
├── World State
└── Navigator

2. 第一座桥:VMC 把 N.E.K.O 里的 VRM 动作送出来

VMC 输出链路
VMC 输出链路

技术资源:SVG · PNG · Mermaid 源码

小白版:VMC 就像“把桌宠的动作录成标准动作广播”

N.E.K.O 里的 VRM 已经会动:眨眼、转头、做表情、播放动画。

但这些动作原本只存在 N.E.K.O 自己的 3D 页面里。VRChat 插件想复用它,首先要把“现在头在哪里、手在哪里、表情是什么”发到外面。

VMC 可以理解成一种标准的“动作广播语言”。N.E.K.O 把 VRM 当前最终姿态采样出来,然后通过 WebSocket 交给后端,再由后端用 OSC/UDP 发给插件。

这一步的好处是:VRChat 插件不需要重新写一套“猫娘待机动作”;它可以直接继承 N.E.K.O 里本来就有的自然动作。

缺点是:这仍然只是“骨骼动作数据”,并不是 VRChat 里的真实玩家身体。后面还需要转换。

专业版:N.E.K.O VMC PR #2463 的数据面与控制面

2026-07-25 合入的 N.E.K.O PR #2463 增加了 VMC Protocol 输出:

  • REST 控制面:/api/vmc;
  • 独立 WebSocket 高频数据面;
  • main_logic/vmc_sender.py 负责 VMC OSC/UDP;
  • 发送频率支持 1–120Hz;
  • 发送 Humanoid bones、expressions、T-Pose;
  • 单 publisher lease;
  • CSRF / Origin 校验;
  • 帧队列与 release ACK;
  • disable / source release 时进行 expression reset,并发送 /VMC/Ext/OK 0。

非常关键的一点:采样发生在 VRM 完成 animation、gaze、spring bone、expression 更新之后。也就是说发送的是最终渲染姿态,不是某个上游动画 clip 的原始值。

这保证 VMC 更接近“用户当前看到的角色动作”。

VMC 的实际时序是什么?

展开时序图:启用、发布、释放一帧 VMC 的完整过程
VMC 实际时序
VMC 实际时序

技术资源:SVG · PNG · Mermaid 源码

小白理解:先告诉 N.E.K.O “往哪里发”,再建立一条专门的动作数据通道;角色每次更新后发一帧;退出时要明确清空状态,而不是突然断线。

专业理解:REST 负责配置 sender,WebSocket 负责 claim publisher lease 和高频 frame delivery,后端 sender 做 UDP 限频与终止状态。把聊天 WebSocket 和高频姿态数据分开,可以减少主对话链的抖动和耦合。

插件甚至会主动帮你把 VMC 打开

展开:插件启动时如何配置 N.E.K.O VMC
插件主动配置 N.E.K.O VMC
插件主动配置 N.E.K.O VMC

技术资源:SVG · PNG · Mermaid 源码

小白理解:插件启动后会检查“动作广播有没有开、是不是发到正确端口”,必要时自己配置,并请求一次 T-Pose 做初始校准。

专业参数:

  • Host API:http://127.0.0.1:48911;
  • VMC receiver:127.0.0.1:39539;
  • host_send_rate_hz = 60;
  • stale_after_ms = 500;
  • manage_host_output = true;
  • 控制接口包括 GET /api/vmc/status、POST /api/vmc/enable、disable、t_pose。

现在我们已经把“完整 Humanoid 骨骼”送到了插件。但 VRChat 并不会直接接收“另一个 VRM 模型的骨骼”。下一步要解决的是:怎样把一整套人形骨骼变成 SteamVR 能理解的追踪设备。


展开:本节技术档案(2 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:HostVmcController REST 接口列出插件管理 N.E.K.O VMC 的四个控制接口。
HostVmcController REST 接口
HostVmcController REST 接口

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出插件管理 N.E.K.O VMC 的四个控制接口。

小白版

查看、打开、关闭、摆 T-Pose

展开专业版

REST 是低频 control plane,高频骨骼不走这些接口,而走独立数据面。

原始终端内容:

1
2
3
4
GET  /api/vmc/status
POST /api/vmc/enable
POST /api/vmc/disable
POST /api/vmc/t_pose

展开:VMC 默认输出固定 VMC 主链的默认地址和频率。
VMC 默认输出
VMC 默认输出

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

固定 VMC 主链的默认地址和频率。

小白版

N.E.K.O 每秒约60次把动作发到39539

展开专业版

vmc_idle listener 与 host output 必须端口一致,stale/端口占用都要处理。

原始终端内容:

1
2
3
4
5
6
N.E.K.O VMC output
127.0.0.1:39539
60 Hz

VMC receiver
listen 127.0.0.1:39539



3. 为什么要把 Humanoid 骨骼压成“六点追踪”?

Humanoid 骨骼到六点追踪
Humanoid 骨骼到六点追踪

技术资源:SVG · PNG · Mermaid 源码

小白版:不是把猫娘模型塞进 VRChat,而是“假装有六个 VR 追踪器”

这是最容易误解的一步。

系统不是把 N.E.K.O 的 VRM 模型直接复制到 VRChat。它做的是:

  1. 从完整骨骼里算出头、左手、右手、腰、左脚、右脚的位置和旋转;
  2. 把这六个点伪装成 SteamVR 的 HMD、控制器和 tracker;
  3. 让 VRChat 自己的 IK 根据这六个追踪点把 Avatar 骨架解出来。

举个例子:你把右手抬起来。N.E.K.O 的 VRM 可能有肩、上臂、前臂、手腕很多骨骼。插件最后只需要告诉 VRChat:“右控制器现在在这里、朝这个方向。”VRChat 自己负责把胳膊弯成合理姿势。

优点:能复用 VRChat 自己成熟的 IK / FBT 系统,不需要远程控制 Avatar 的每根骨头。

缺点:中间有信息损失。原 VRM 的细微肘部、脊柱姿态不一定能完整保留。

专业版:Humanoid FK → six-point pose

VMC relay 接收到 humanoid bone transforms 后,需要先完成 humanoid FK,得到关键端点的 world/local transform,再抽取:

  • head;
  • left_controller / left hand;
  • right_controller / right hand;
  • hip;
  • left_foot;
  • right_foot。

这六点随后成为 AnyaDance protocol 中的 recognized device IDs。它不是 skeletal streaming,而是 tracker-space pose streaming。

因此整个系统把 N.E.K.O avatar rig 与 VRChat avatar rig 解耦:两个模型可以骨骼比例不同,只要 six-point pose 和 calibration 合理,VRChat 会通过自己的 IK 重建目标姿势。

代价是 IK underconstraint:六个 tracker 无法唯一确定所有中间关节,自然姿态依赖 VRChat IK、avatar rig 和 calibration。

4. AnyaDance 是什么?为什么它是“进入 VRChat”的关键执行层?

六点姿态进入 VRChat
六点姿态进入 VRChat

技术资源:SVG · PNG · Mermaid 源码

小白版:AnyaDance 像一个“虚拟 VR 套装”

普通 VRChat 玩家会有真实头显和控制器。AnyaDance 做的事情很像:在软件层创建一套虚拟的设备。

插件不断告诉这套虚拟设备:

  • 头在哪里;
  • 两只手在哪里;
  • 腰在哪里;
  • 两只脚在哪里。

SteamVR 看到的是一套合法的 OpenVR 设备,VRChat 再从 SteamVR 读取它们。

所以链路不是:

AI → VRChat avatar bone API

而是:

AI → 虚拟 VR 设备 → SteamVR → VRChat IK

这也解释了为什么插件可以比较自然地驱动 Avatar,而不用依赖一个不存在的“VRChat 全身骨骼写入 API”。

专业版:AnyaDance protocol 与 virtual device model

AnyaDance driver 暴露六个 OpenVR virtual devices:HMD、左右 controller、hip tracker、左右 foot tracker。

默认协议:

  • UDP:127.0.0.1:39570;
  • UTF-8 JSON;
  • version = 1;
  • fire-and-forget datagram;
  • packet < 8192 bytes;
  • quaternion order XYZW;
  • driver 对 pose 和 controller input 做 validation / safety clamp。

插件 plugin.toml 默认 rate_hz = 120,并且 pose 与 controller input overlay 共享同一个完整帧。

注意安全边界:AnyaDance 本身明确提示,虚拟设备 / spoofed tracking 在在线游戏中可能涉及平台条款与 anti-cheat 风险;它还会修改 SteamVR driver 配置。这个风险应在博客中作为“使用边界”保留,不要删除。

展开终端参数:AnyaDance 线协议
AnyaDance 协议
AnyaDance 协议

技术资源:SVG · PNG · 原始 TXT

看到这里还有一个性能问题:VMC 默认只有 60Hz,但驱动输出是 120Hz;而且 LLM 甚至可能一秒才决定一次动作。那中间大量帧是谁生成的?答案就是 BodyScheduler。


5. 为什么 LLM 不直接控制每一帧?BodyScheduler 才是“真正的小脑”

LLM 语义动作到 120Hz Scheduler
LLM 语义动作到 120Hz Scheduler

技术资源:SVG · PNG · Mermaid 源码

小白版:你不会每 8ms 想一次“手再往右 0.2cm”

人类想“挥手”时,也不会意识层面计算每根肌肉。大脑发出意图,小脑和脊髓完成高速控制。

这个插件完全采用相同思路:

  • LLM:说“greet”;
  • Behavior:决定 greet 对应什么动作、当前能不能插进去;
  • Scheduler:用连续轨迹把动作跑完;
  • Driver:每秒接收 120 帧。

这样就算模型生成一次响应花了 1 秒,已经开始的动作仍然会正常持续。

优点:实时、平滑、成本低、行为可预测。

缺点:LLM 不再拥有任意自由度;它只能使用程序预先开放的动作技能。想增加能力,需要增加 skill/controller,而不是只改 prompt。

专业版:多频率控制栈

核心频率关系:

  • LLM planning:约 0.1–1 Hz,事件驱动;
  • semantic VLM:按需;
  • Navigator:默认 10 Hz;
  • N.E.K.O VMC:默认 60 Hz;
  • Body / AnyDance output:默认 120 Hz。

Scheduler 支持的 command 类别包括:arm_pose、hand、move_hand、reach_and_grab、gesture、sequence、play_clip、express、semantic_clip、input_axes、input_button、input_release。

这意味着 high-level policy 与 trajectory generation 被明确分离。LLM 的输出不是 frame command,而是 action primitive。

展开:60Hz VMC 到 120Hz 输出链
60Hz → 120Hz 控制链
60Hz → 120Hz 控制链

技术资源:SVG · PNG · 原始 TXT

如果两个动作同时来,谁赢?

展开:动作优先级解释多个动作同时出现时如何避免冲突。
动作优先级
动作优先级

技术资源:SVG · PNG · Mermaid 源码

小白版:急停一定比“卖萌”重要

假设猫娘正在跳舞,这时候你突然按“停止”。如果系统只是让 LLM 自己判断,很可能出现冲突。

所以动作优先级直接写进代码:

  • 急停 / reset / disable:最高;
  • 抓取:很高;
  • sequence;
  • 精确姿态;
  • clip;
  • gesture;
  • semantic expression:最低。

这让安全和精确控制不会被“自然表达”覆盖。

专业版:Behavior MotionPolicy 的具体 priority

当前 behavior.py 中的 MOTION_POLICIES:

  • enable / disable / reset / stop / cancel:priority=100,safety layer;
  • reach_and_grab:90;
  • sequence:85;
  • arm_pose / move_hand / hand:80;
  • play_clip:75;
  • gesture:70;
  • semantic_clip / express:40。

expression_admission() 还会保护已经在进行的 interaction / sequence / clip / gesture,低优先级全身表达不能随意覆盖;head-only gesture 可以在部分情况下作为 overlay 保留。

这不是“prompt 建议”,而是 runtime enforcement。

动作切换为什么不会瞬移?

展开:Crossfade 与状态机
VMC Idle 与显式动作状态机
VMC Idle 与显式动作状态机

技术资源:SVG · PNG · Mermaid 源码

动作切换 / Crossfade
动作切换 / Crossfade

技术资源:SVG · PNG · 原始 TXT

小白版:新动作不是从“动作模板第一帧”瞬间跳过去,而是先记录当前真实姿态,再花大约 0.4 秒平滑混过去。

专业版:默认 default_crossfade_ms = 400,transition strategy 是 current_pose_snapshot_crossfade,旋转使用 quaternion shortest-path interpolation。它借用了 N.E.K.O 3D 动画系统的调度语义,但插件端不是完整浏览器 THREE.AnimationMixer / VRM skeleton mixer,而是基于 six-point pose snapshot 的等价实现。

一个“挥手”真正经过哪些步骤?

展开完整时序:body_express("greet")
“挥手”执行时序
“挥手”执行时序

技术资源:SVG · PNG · Mermaid 源码

小白版:模型只说“打招呼”,动作系统把它翻译成右手挥手,先检查有没有更重要的动作,再平滑进入、持续、平滑退出。

专业版:当前 expression profile 中 greet = wave / right / intensity 0.55 / 1350ms。body_express 属于低优先级语义表达;如果 active base motion 正被 protection 保护,则可能 reject,而不是盲目叠加。

到这里“身体怎么动”已经解释清楚了。但 VRChat 不只有骨骼:移动、按钮、聊天、Avatar 参数,以及角色是否真的动起来,都需要另一套接口。这就是 OSC。


展开:本节技术档案(2 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:BodyScheduler 命令集列出 Scheduler 可接受的动作 primitive。
BodyScheduler 命令集
BodyScheduler 命令集

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出 Scheduler 可接受的动作 primitive。

小白版

LLM 不是传坐标流,而是调用“摆手、移手、抓、播放动作、按钮”等技能

展开专业版

这些 command 构成低层受控 action space。

原始终端内容:

1
2
3
4
5
6
7
8
9
10
11
12
arm_pose
hand
move_hand
reach_and_grab
gesture
sequence
play_clip
express
semantic_clip
input_axes
input_button
input_release

展开:Transition Strategy给出状态机记录的 transition strategy 名称。
Transition Strategy
Transition Strategy

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

给出状态机记录的 transition strategy 名称。

小白版

表示“从当前真实姿势平滑切”

展开专业版

这是 awareness/diagnostics 可观测字段,便于知道动作并非从预制起始帧硬跳。

原始终端内容:

1
current_pose_snapshot_crossfade

6. 为什么已经有 AnyaDance,还需要 VRChat OSC?

VRChat OSC 双向链路
VRChat OSC 双向链路

技术资源:SVG · PNG · Mermaid 源码

小白版:一条线负责“身体在哪”,另一条线负责“游戏按钮和反馈”

AnyaDance 最擅长的是“模拟 VR 设备”。但 VRChat 里还有很多事情不是六点追踪能表达的:

  • 在聊天框发文字;
  • 改 Avatar Expression Parameter;
  • 触发 Grab / Use / Drop;
  • 读取 VelocityX/Z、Grounded 等状态;
  • 接收 Avatar 切换与参数反馈。

所以系统同时保留 VRChat OSC。

可以把它理解成两条并行总线:

  1. Tracking Plane:AnyaDance / SteamVR,负责“身体的空间姿态”;
  2. OSC Plane:VRChat OSC,负责“游戏输入、参数与反馈”。
专业版:OSC 的端口与消息类型

默认:

  • Plugin → VRChat:127.0.0.1:9000;
  • VRChat → Plugin:127.0.0.1:9001;
  • input pulse 默认 100ms;
  • parameter cache size 默认 256。

典型路径:

  • /avatar/parameters/<parameter>;
  • /chatbox/input;
  • /input/GrabLeft、GrabRight、UseLeft、UseRight、DropLeft、DropRight;
  • locomotion / look / run / jump 输入。

9001 是回传端,因此它同时承担“感知”角色。

展开:身体追踪与 OSC 两个控制平面把 AnyaDance 与 OSC 的职责明确分开,避免读者认为两者…
身体追踪与 OSC 两个控制平面
身体追踪与 OSC 两个控制平面

技术资源:SVG · PNG · Mermaid 源码

为什么移动输入现在优先走 AnyaDance?

展开:移动/控制器输入路由解释 locomotion/controller input 为什么…
移动/控制器输入路由
移动/控制器输入路由

技术资源:SVG · PNG · Mermaid 源码

小白版:既然已经伪造了一对 Index Controller,就顺便让摇杆也从那里走

如果虚拟控制器已经存在,移动摇杆和按钮可以直接附着到虚拟 Index controller frame 中。这样姿态和输入更统一。

只有主路径不可用或需要兼容时,才走 OSC fallback。

专业版:输入路由参数

当前配置:

1
2
3
4
5
6
[input]
primary = "anyadance"
rate_hz = 120
osc_fallback = true
max_hold_ms = 10000
emergency_release_ms = 50

ControllerInputOverlay 与 six-point pose 可以共用同一个 120Hz AnyaDance frame。OSC 仍作为兼容 fallback。

技术收益是降低两条 actuator path 之间的时序差异;代价是对 AnyaDance driver 可用性依赖更高。

现在出现一个非常重要的 Agent 问题:插件调用 sendto() 成功,能不能算“猫娘已经走了”?答案是不行。 这一步把它从“自动化脚本”变成了真正有反馈的闭环系统。


展开:本节技术档案(5 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:VRChat OSC 端口固定 OSC 双向端口方向。
VRChat OSC 端口
VRChat OSC 端口

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

固定 OSC 双向端口方向。

小白版

9000 发给VRChat,9001收VRChat

展开专业版

两者都是UDP,listen端口通常只能被一个进程独占,路由器场景要转发。

原始终端内容:

1
2
3
4
5
Plugin → VRChat
127.0.0.1:9000

VRChat → Plugin
127.0.0.1:9001

展开:OSC Hand / Use 输入列出 Grab/Use/Drop 输入。
OSC Hand / Use 输入
OSC Hand / Use 输入

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出 Grab/Use/Drop 输入。

小白版

相当于按左右手的抓取/使用/丢弃按钮

展开专业版

应使用 pulse+auto release,避免 stuck input。

原始终端内容:

1
2
3
4
5
6
/input/GrabLeft
/input/GrabRight
/input/UseLeft
/input/UseRight
/input/DropLeft
/input/DropRight

展开:OSC 移动输入列出移动、视角、跑、跳等 OSC 输入。
OSC 移动输入
OSC 移动输入

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出移动、视角、跑、跳等 OSC 输入。

小白版

像键盘/摇杆

展开专业版

当前主路径优先AnyDance controller overlay,OSC主要是兼容fallback。

原始终端内容:

1
2
3
4
5
6
7
8
9
10
11
12
/input/Vertical
/input/Horizontal
/input/LookHorizontal

/input/MoveForward
/input/MoveBackward
/input/MoveLeft
/input/MoveRight
/input/LookLeft
/input/LookRight
/input/Run
/input/Jump

展开:OSC Chat / Avatar 参数展示聊天和 Avatar 参数两类 OSC 能力。
OSC Chat / Avatar 参数
OSC Chat / Avatar 参数

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

展示聊天和 Avatar 参数两类 OSC 能力。

小白版

一类“说话”,一类“改角色开关/数值”

展开专业版

/chatbox/input 与 /avatar/parameters/ 是不同语义面。

原始终端内容:

1
2
3
/chatbox/input

/avatar/parameters/<parameter>

展开:输入优先级配置展示输入路由的当前默认配置。
输入优先级配置
输入优先级配置

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

展示输入路由的当前默认配置。

小白版

先走虚拟手柄,不行再走OSC

展开专业版

120Hz overlay与pose共帧,osc_fallback=true需要防双发。

原始终端内容:

1
2
3
4
[input]
primary = "anyadance"
rate_hz = 120
osc_fallback = true

7. “命令发出去了”不等于“角色真的做到了”

移动反馈闭环
移动反馈闭环

技术资源:SVG · PNG · Mermaid 源码

小白版:你按了油门,不代表车真的向前走

想象机器人发出“前进”命令:

  • 可能 UDP 包发出去了;
  • 可能 driver 收到了;
  • SteamVR 可能也看到了;
  • 但 VRChat 角色可能正顶着墙,实际没往前走。

如果 Agent 只相信自己的命令,它会产生一种很危险的错觉:

“我已经走到目标了。”

于是插件读取 VRChat 回传的速度和旋转参数,判断角色实际发生了什么。

这就像汽车不是只看油门踏板,而是还看速度表。

专业版:accepted、driver delivery 与 motion feedback 是三层不同事实

必须区分:

  1. accepted=true:本地工具 / scheduler 接受了动作;
  2. UDP sendto() success:OS 接受 datagram;
  3. driver_delivery:39571 telemetry 证明 AnyaDance driver 实际处理;
  4. VRChat OSC motion feedback:VelocityX/Y/Z、AngularY、Upright、Grounded 证明 avatar movement state。

仓库 README 明确强调,accepted=true 只代表本地发送链受理,不等于 avatar 实际移动。

实测 VelocityX/Z 是 avatar local coordinate frame;当前 avatar 跑满速度曾实测约 2.6667 m/s。速度参数只在移动时回传,因此“静止时没包”不能简单缓存成永久零速度。

展开:如何从速度信号判断撞墙/侧滑
碰撞/侧滑信号
碰撞/侧滑信号

技术资源:SVG · PNG · 原始 TXT

小白版:如果你一直按“前进”,却发现前进速度没了、横向速度变大,很可能是在贴着墙滑;如果水平速度几乎归零,可能正面撞墙。

专业版:Navigator 可以根据 forward_ratio、slip_ratio 与 horizontal speed 构造弱碰撞证据。它不是直接读取 physics collision event,而是从 CharacterController 实际 velocity 反推运动受阻。

Driver telemetry 又解决了什么?

展开:AnyaDance Driver Telemetry
AnyaDance Driver Telemetry
AnyaDance Driver Telemetry

技术资源:SVG · PNG · Mermaid 源码

39570 是 fire-and-forget UDP,因此单靠 send success 不足以证明 driver 收到。插件订阅 multicast 239.255.39.71:39571,在 driver 支持 command log 时得到 delivery evidence。

默认 stale_after_ms = 3000、history_size = 64。如果检测到另一个活跃 sender,还会标记控制冲突并撤销 autonomy / 释放输入。

有了“身体”和“反馈”之后,Agent 还是瞎的。接下来才进入视觉:它如何从 VRChat 的普通桌面画面里,找出“右边那个人”。


展开:本节技术档案(3 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:UDP sendto 的含义提醒 sendto 成功不是动作成功。
UDP sendto 的含义
UDP sendto 的含义

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

提醒 sendto 成功不是动作成功。

小白版

信投进邮筒不等于对方收到,更不等于角色动了

展开专业版

需要driver telemetry和VRChat motion feedback分层确认。

原始终端内容:

1
2
3
4
5
sendto() = success

≠

VRChat 角色真的移动了

展开:移动反馈参数列出用于实际移动反馈的六个内置 Avatar 参数。
移动反馈参数
移动反馈参数

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出用于实际移动反馈的六个内置 Avatar 参数。

小白版

速度、转向、站立/着地

展开专业版

VelocityX/Z 是avatar local frame,回传稀疏,不能把静默当永久0。

原始终端内容:

1
2
3
4
5
6
VelocityX
VelocityY
VelocityZ
AngularY
Upright
Grounded

展开:Driver Delivery 真实性再次区分本地发送和driver处理。
Driver Delivery 真实性
Driver Delivery 真实性

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

再次区分本地发送和driver处理。

小白版

需要39571“回执”

展开专业版

driver delivery仍不是最终avatar movement,需继续看OSC velocity。

原始终端内容:

1
2
3
4
5
6
7
sendto() success
↓
NOT sufficient
↓
39571 driver telemetry
↓
body_awareness.driver_delivery


8. 猫娘怎么“看见”VRChat?不是读游戏内存,而是看桌面画面

VRChat 视觉感知链
VRChat 视觉感知链

技术资源:SVG · PNG · Mermaid 源码

小白版:它像一个坐在电脑前的人,而不是拿到了上帝视角

当前桌面方案的视觉入口非常朴素:抓 VRChat 的 desktop mirror/window frame。

然后分两类处理:

  • 本地 detector 快速回答“哪里像有人”;
  • VLM / 主 LLM 在必要时回答“这个人是谁、菜单上写了什么、这是镜子还是目标”。

这种设计很像人:眼睛一直在看,但不是每一帧都进行复杂语言推理。

优点:比较符合“正常玩家可见信息”,不依赖 VRChat 内部 world API。

缺点:它只有像素,没有真正的 3D 世界坐标。这会成为后面最大的瓶颈。

专业版:Capture / Detector / VLM 三层

Backend 提供 desktop frame source,优先/可选 DXGI/DXcam、Windows Graphics Capture(WinRT),并有 MSS fallback。视觉 worker 与 120Hz body thread 隔离。

本地 perception 可以使用 OpenVINO / ONNX detector 产出 bbox、bearing、confidence、track id 等结构化 observation;VLM 是按需语义通道,不作为每帧 detector。

plugin.toml 当前 capture interval_ms = 100,queue_size = 1。该配置强调实时 freshness,而不是保存所有帧。

为什么 Queue 只有 1?丢帧反而是正确选择

展开:Latest-frame Queue解释为什么实时系统宁可丢帧也不要排队。
Latest-frame Queue
Latest-frame Queue

技术资源:SVG · PNG · Mermaid 源码

小白版:宁可看“现在”,不要认真分析三秒前的画面

如果屏幕每秒 60 帧,而 detector 每秒只能处理 5 帧,最糟糕的设计是把 60 帧全排队。

因为过几秒以后,模型虽然每一帧都没漏,但它看到的全是“过去”。

所以系统选择:新帧来了就覆盖旧帧,detector 永远拿最新的一张。

这就是:freshness > completeness。

专业版:实时感知中的 bounded latest-frame queue

queue_size = 1 是典型 real-time perception backpressure 策略。它牺牲 frame completeness,换取 bounded latency。

对导航来说,过期的 bbox 比少一帧更危险:目标早已移动,但 agent 仍可能按旧 bearing 转向。

因此感知链必须携带 timestamp / age / TTL,并让 Navigator 在 stale 时停止,而不是继续使用最后一个已知目标。

为什么还要同时用本地 Detector 和 VLM?

展开:本地 Detector 与 VLM 分工解释为什么不把每一帧都交给多模态大模型。
本地 Detector 与 VLM 分工
本地 Detector 与 VLM 分工

技术资源:SVG · PNG · Mermaid 源码

小白版:一个负责“快”,一个负责“懂”

本地 detector 很适合回答:

“右边有一个像人的东西,框在这里。”

但它不擅长回答:

“这是 Jasper 吗?”
“这个框其实是菜单里的头像缩略图吗?”
“镜子里的那个算不算目标?”

VLM 能理解这些语义,但速度慢、成本高。所以系统只在需要的时候让 VLM 介入。

专业版:结构化 perception 与 semantic perception 分离

Local detector 产出低成本、可连续追踪的几何/检测信息;VLM 用于 semantic disambiguation。主动视觉预算可限制到类似 10 frames/minute,避免 agent loop 每次都传图。

技术上这是 classical perception + foundation model semantic layer 的混合架构:

  • detector 提供 temporal continuity;
  • VLM 提供 open-vocabulary semantic grounding;
  • world state 负责把二者合并。

VLM 识别一次之后,为什么不用每帧重新问?

展开:一次 VLM 语义绑定,多帧复用解释一次语义判断如何在后续多帧复用。
一次 VLM 语义绑定,多帧复用
一次 VLM 语义绑定,多帧复用

技术资源:SVG · PNG · Mermaid 源码

小白版:认出“这是小明”以后,只要持续跟踪同一个人就行

第一次看到 track_7 时,系统不知道是谁。它让 VLM 看图,得到“这是目标 NPC”。

之后 detector 只要还能稳定追踪 track_7,就可以继承这个语义标签,不需要每 100ms 再问一次 LLM。

优点:省成本、低延迟、身份稳定。

风险:tracker 如果把 ID 跟错人,旧标签也可能跟着漂移。所以需要 TTL、confidence 和重新确认机制。

专业版:semantic_commit 与 temporal identity

典型流程:detector track → screenshot/VLM → vrc_semantic_commit(track_id, label=...) → world state binding → subsequent track updates reuse semantic identity。

它把“语义识别”从 frame-level inference 变成 entity-level state mutation。技术收益是把 expensive multimodal inference amortize 到多个 frame。

主要 failure mode 是 ID switch / occlusion / stale semantic binding,因此 world entity 需要 age、TTL、source、confidence 和 unknown semantics。

现在我们终于有了很多 detector track,但 LLM 不能一直记“屏幕 x=861 的框”。它需要一个稳定、可查询的世界接口。于是 World State 出场。


展开:本节技术档案(5 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:实时视觉原则强调实时视觉的核心原则。
实时视觉原则
实时视觉原则

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

强调实时视觉的核心原则。

小白版

宁可漏掉旧画面,也别认真看过期画面

展开专业版

queue_size=1提供bounded latency,配合timestamp/TTL。

原始终端内容:

1
2
3
freshness > completeness

queue_size = 1

展开:本地 Detector 结构化输出展示 detector 应该输出结构化几何,而不是长篇自然语言。
本地 Detector 结构化输出
本地 Detector 结构化输出

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

展示 detector 应该输出结构化几何,而不是长篇自然语言。

小白版

告诉Agent“有个人、ID、方向、框、可信度”

展开专业版

便于WorldState做track-level fusion。

原始终端内容:

1
2
3
4
5
there is a person
stable_id = ...
bearing = ...
bbox = ...
confidence = ...

展开:本地 detector 不知道的语义明确本地 detector 不擅长的语义。
本地 detector 不知道的语义
本地 detector 不知道的语义

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

明确本地 detector 不擅长的语义。

小白版

能看出像人,不代表知道是谁、是不是镜子

展开专业版

这些需要VLM/open-vocabulary reasoning或额外传感器。

原始终端内容:

1
2
3
4
这是 Jasper
这是某个 NPC
菜单写了什么
镜子里的还是本人

展开:主动视觉预算展示主动视觉调用预算。
主动视觉预算
主动视觉预算

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

展示主动视觉调用预算。

小白版

大模型看图很贵,所以不是每帧都看

展开专业版

budget让semantic inference按需触发,防止agent loop context/token爆炸。

原始终端内容:

1
10 frames / minute

展开:Semantic Binding用最短流程解释 semantic_commit。
Semantic Binding
Semantic Binding

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

用最短流程解释 semantic_commit。

小白版

认一次“track_7是目标”,以后继续跟track_7

展开专业版

semantic state从frame推理提升为entity binding,需防ID switch。

原始终端内容:

1
2
3
4
5
6
7
track_7
↓ screenshot
Main LLM
↓
“这个是目标 NPC”
↓
vrc_semantic_commit(track_7, label=targetNPC)



9. World State:把像素变成“可被 Agent 理解的实体”

World State 稳定接口
World State 稳定接口

技术资源:SVG · PNG · Mermaid 源码

小白版:从“右边一个框”变成“entity_14”

如果目标每一帧都换坐标,LLM 很难连续操作。

World State 的作用就是给感知结果一个更稳定的表示,例如:

  • entity_id;
  • 类型;
  • 方位;
  • 置信度;
  • 多久没更新;
  • 来源;
  • 哪些语义还是 unknown。

于是 Agent 可以说:

“继续跟着 entity_14。”

而不是不断说:

“追屏幕坐标 (823, 417) 那个框。”

专业版:WorldStateStore 是 perception / planner 的契约层

World state 接收 local vision、semantic commit、OSC / external observations,并对 Agent 暴露 snapshot、revision delta、salient events 等结构化结果。

它的重要价值是隔离 perception implementation 与 planner。未来 detector 从 YOLO 换别的模型,或 world-native route 直接提供 Unity entity,都可以映射到统一 entity contract。

世界记忆也区分可持久化事实和 session observation:当前配置 persist_world=true、persist_players=false,检测轨迹与 session entity 不应被错误当作长期事实。

10. “走到那个人旁边”是怎么闭环完成的?

“走到那个人旁边”闭环
“走到那个人旁边”闭环

技术资源:SVG · PNG · Mermaid 源码

小白版:不是“一次规划完路线”,而是边看边修

当前桌面方案没有完整地图,所以它更像人在陌生房间里盯着目标走:

  1. 找到目标;
  2. 看目标在左还是右;
  3. 转一点;
  4. 往前走;
  5. 再看一眼;
  6. 如果目标变大,说明在接近;
  7. 如果速度异常,可能撞墙;
  8. 如果目标丢了,停下来,不继续盲走。

这叫 reactive closed-loop navigation。

它的优点是不用建完整 3D 地图就能完成简单接近。

缺点也很明显:复杂绕路、墙后目标、楼梯、多房间拓扑会非常困难。

专业版:10Hz Navigator 与 observation freshness

Navigator 默认以约 10Hz tick。典型参数包括:

  • max_forward_axis ≈ 0.60;
  • max_turn_axis ≈ 0.35;
  • turn gain 约 0.8;
  • 最大单次/控制参考转角约 45°;
  • 最低 confidence 约 0.40。

它不是 LLM 10Hz 调用,而是本地 controller 读取 world state 的最新 bearing / confidence / age,再输出 movement axis。

反馈又来自 OSC velocity,因此形成:

perception → world state → navigator → actuator → VRChat → OSC feedback → navigator。

这是本文最关键的 closed-loop 之一。

为什么 Agent 不能随便自己跑路?

展开:Autonomy 授权门解释为什么模型不能一获得工具就无限自主行动。
Autonomy 授权门
Autonomy 授权门

技术资源:SVG · PNG · Mermaid 源码

小白版:自主移动前要“解锁”,而且解锁会过期

因为这已经不是一个只会说话的 bot,而是能真的操作 VRChat。系统不希望 LLM 一句话理解错就开始乱跑。

所以 autonomy 默认需要手动 arm;过一段时间会过期;世界状态太旧或 safety 不通过时,导航停止。

专业版:Autonomy gate 的安全语义

默认配置 manual_arm = true,session_ttl_minutes = 30。Autonomy controller 不绕过 scheduler / safety layer。目标执行还应检查 world state freshness、confidence、driver conflict、emergency stop 等条件。

这是一种 capability gating:让 high-level Agent “可以提出 autonomy goal”,但真正 actuator permission 由 runtime state 控制。

11. Body Awareness:为什么 AI 还需要“知道自己现在身体在干嘛”?

展开:Body Awareness / Proprioception解释 AI 如何获得“自己身体现在是什么状态”的可靠来源。
Body Awareness / Proprioception
Body Awareness / Proprioception

技术资源:SVG · PNG · Mermaid 源码

小白版:聊天记录不能当成身体状态

LLM 可能刚才说过:“我在挥手。”

但两秒后挥手已经结束了。如果它继续只读聊天历史,就可能产生错觉。

所以系统有一个 body_awareness:直接问 scheduler “你现在真实在做什么”。

就像人闭上眼也能感觉自己的手大概在哪里,这叫 proprioception(本体感觉)。

专业版:body_awareness 的 runtime-grounded fields

body_awareness 可暴露:

  • current motion / source / phase / progress;
  • elapsed / remaining time;
  • previous action;
  • transition;
  • arm elevation / direction / extension;
  • hand state / grip;
  • head rotation;
  • behavior layers;
  • VRChat OSC motion / parameter feedback;
  • natural-language summary。

每个动作返回的 target pose 只是 intention,completion_confirmed=false 时不能当作实际完成。回答“我现在是不是还在挥手”应查询 runtime awareness,而不是复述之前的 tool call。

到这里,桌面方案已经形成了完整闭环:看 → 形成实体 → 导航 → 动作 → 反馈 → 再看。但现在必须正面面对它的天花板:它看到的是 2D 屏幕,不是真正的 3D 世界。 只有理解这个瓶颈,后面的 World-Native 才不会显得突然。


展开:本节技术档案(3 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:WorldState 实体字段列出 WorldState entity 的关键字段。
WorldState 实体字段
WorldState 实体字段

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出 WorldState entity 的关键字段。

小白版

给每个目标一张“身份证+新鲜度+可信度”

展开专业版

age/ttl/source/unknown让planner知道哪些字段可依赖。

原始终端内容:

1
2
3
4
5
6
7
8
entity_id
type
bearing
confidence
age_ms
ttl_ms
source
unknown

展开:分层控制频率一屏展示四层不同时间尺度。
分层控制频率
分层控制频率

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

一屏展示四层不同时间尺度。

小白版

LLM想目标、Navigator修方向、Scheduler跑身体、VRChat执行物理

展开专业版

multi-rate control是整套架构稳定性的关键。

原始终端内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LLM
↓
目标级 planning ~秒级

Navigator
↓
闭环 steering 10 Hz

BodyScheduler
↓
姿态/输入 interpolation 120 Hz

SteamVR / VRChat
↓
实际 physics / character controller

展开:body_awareness 字段列出 proprioception 返回给 LLM 的主要字段。
body_awareness 字段
body_awareness 字段

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

列出 proprioception 返回给 LLM 的主要字段。

小白版

告诉AI自己现在做什么、做到哪、手头朝哪

展开专业版

runtime state优先于chat history,支持relative command grounding。

原始终端内容:

1
2
3
4
5
6
7
8
9
10
11
current motion
phase
progress
remaining time
previous action
transition
arm elevation
arm direction
hand state
head rotation
summary


12. 当前桌面 AnyDance 路线最大的瓶颈:它没有真正的 3D 世界模型

小白版:它像拿着摄像头走路,不像拿着室内地图

现在的猫娘可以看到:“右边有个人”,也可以根据目标变大判断“我在靠近”。

但它并不知道:

  • 那堵墙在 3D 空间里的准确位置;
  • 墙后面有没有路;
  • 房间和房间怎么连;
  • 某个物体的真实世界坐标;
  • NavMesh 上哪条路可走。

所以它擅长的是:

看见人 → 转过去 → 往前走 → 持续修正。

不擅长的是:

“绕过这堵墙,从楼梯上二楼,在另一个房间找到目标。”

这不是“LLM 不够聪明”,而是感知输入根本没有提供足够的 3D 几何信息。

展开:当前缺失的 3D world-model 能力
当前 AnyDance 路线缺失
当前 AnyDance 路线缺失

技术资源:SVG · PNG · 原始 TXT

当前没有通用 depth、SLAM、collision map、NavMesh、VRChat world object API。因而“绕到墙后”这类需要 global spatial planning 的请求会返回 unsupported_spatial_navigation,而不是虚构完成。

不支持的空间导航
不支持的空间导航

技术资源:SVG · PNG · 原始 TXT

这是一个很重要的设计优点:明确 unknown / unsupported,比让 Agent 伪装成功更可靠。

抓取也有同样的“可观测边界”

展开:为什么 object_held 必须是 unknown
抓取的可观测边界
抓取的可观测边界

技术资源:SVG · PNG · 原始 TXT

插件可以知道:手已经移动到目标位置、grip input 已经发送。

但通用 VRChat OSC 并没有一个 universally available API 告诉插件:某个 Pickup 现在是否真的 attach 到这只手。所以 runtime 不应该编造 object_held=true,而应保持 unknown。

这体现了整个项目非常重要的一条 agent engineering 原则:只把真正观测到的事实当成事实。

当前也没有完整的 VRChat 语音输出链

展开:文字聊天已接通,但虚拟麦克风链尚未实现
当前没有 VRChat Voice Path
当前没有 VRChat Voice Path

技术资源:SVG · PNG · 原始 TXT

N.E.K.O 本体可以有 TTS,但当前 VRC Body 主线里没有通用 N.E.K.O TTS → virtual microphone → VRChat voice runtime。现有可确认的交流路径主要是 /chatbox/input。

到这里我们终于可以自然地提出一个问题:如果 2D 屏幕几何是瓶颈,那能不能不要从屏幕猜,直接让 AI NPC 生活在 Unity 世界里,拿到真正的 NavMesh、Raycast 和世界坐标? 这就是 YUI World-Native 路线出现的原因。


展开:本节技术档案(1 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:Reactive Navigation用一句流程概括当前擅长的导航类型。
Reactive Navigation
Reactive Navigation

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

用一句流程概括当前擅长的导航类型。

小白版

看见目标→转→走→目标变大→停

展开专业版

bearing/apparent-scale + feedback的reactive servo,不是global path planning。

原始终端内容:

1
2
3
4
5
6
看到一个人在右边
→ 转向
→ 前进
→ 人变大
→ 减速
→ 停

13. 为什么仓库里又出现了一套 YUI World-Native NPC?

YUI 世界原生 NPC 架构
YUI 世界原生 NPC 架构

技术资源:SVG · PNG · Mermaid 源码

小白版:从“扮演一个 VR 玩家”变成“世界里真正有一个 NPC”

AnyDance 路线想做的是:

让猫娘看起来像一个正常 VRChat 玩家,可以进普通世界。

World-Native 路线做的是另一件事:

在你自己制作的 VRChat World 里,直接放一个 Unity/Udon NPC。

一旦 NPC 真正在 Unity 场景里,它就不必从像素猜“墙在哪里”。世界本身就能告诉它:

  • 自己的 world coordinate;
  • 玩家坐标;
  • NavMesh;
  • Raycast 是否被墙挡住;
  • Trigger / Touch collider;
  • Animator / prefab state。

这就是为什么 “AnyDance vs World-Native 几何” 必须放在这里,而不是文章前面突然出现:它是为了解决上一节刚刚暴露出的 3D 感知瓶颈。

专业版:两条路线解决的是不同环境约束

World-native 设计使用 Unity/Udon 世界内 runtime,协议文档定义 Python/N.E.K.O ↔ VRChat client / Udon 的命令、上半身、文本与 telemetry 通道。世界内可以使用 NavMeshAgent、Physics.Raycast、VRCPlayerApi、collider trigger、Animator、network sync 等 native information。

这将 perception 从“screen-space inference”变成“world-space state”。

关键代价:它不是任意 VRChat world 的通用 player agent。World 必须预先放置 prefab、Udon logic、NavMesh 等支持设施。

World-Native 的 Prefab 里实际有哪些组件?

展开:YUI NPC Prefab 结构
YUI World-Native Prefab
YUI World-Native Prefab

技术资源:SVG · PNG · Mermaid 源码

小白版:把它当成一个“自带大脑接口、腿、手、眼睛、碰撞感知和对话气泡的 NPC 机器人”。

专业版:root 侧包含 VRCObjectSync / NavMeshAgent,runtime 下拆 MidiRouter、SafetyController、Locomotion、ActionController、UpperBodyController、TextController、Perception、Telemetry、VoiceController 等职责;触摸区域通过 colliders 划分头、脸、手、躯干等交互区。

为什么 World-Native 的几何能力更强?

World-native 3D 控制闭环
World-native 3D 控制闭环

技术资源:SVG · PNG · Mermaid 源码

小白版:一个是在“看照片猜距离”,一个是“直接拿场景地图”

AnyDance 桌面路线:

screen pixels → 猜目标方向/大小 → 反应式移动

World-native:

Unity world coordinates + NavMesh + Raycast → 真正空间路径

所以复杂导航上,World-native 天生更有优势。

但它并不是“全面更好”,因为它失去了最重要的泛化能力:不能随便进入别人做的普通 world,就自动获得这些 world-native API。

专业版:Geometry / observability trade-off

AnyDance route 的 agent identity 接近普通 player,环境兼容性强,但观测主要依赖 screen + OSC;World-native route 的 agent 是受控 world entity,几何可观测性强,但 environment contract 强。

因此二者是两个不同 Pareto point:

  • AnyDance:environment generality ↑,world-state observability ↓;
  • World-native:world-state observability ↑,environment generality ↓。

仓库 plugin.toml 还明确标记 AnyDance/YOLO 身体方案与 yui_npc_controller 冲突,不能简单同时启用。

展开对比:为什么 World-Native 不是直接替代 AnyDance
World-native 的限制
World-native 的限制

技术资源:SVG · PNG · 原始 TXT

两条路线现在终于都讲清楚了。最后一步不是再列模块,而是把它抽象成一个更通用的观点:这其实是一个完整的 embodied-agent stack。


展开:本节技术档案(1 项)不打断主线:端口 / 字段 / 优先级 / 状态机证据
展开:AnyDance vs World-Native 几何作为引出World-Native的几何对比。
AnyDance vs World-Native 几何
AnyDance vs World-Native 几何

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

作为引出World-Native的几何对比。

小白版

一个看像素猜位置,一个直接拿Unity坐标

展开专业版

screen-space inference vs world-space authoritative state。

原始终端内容:

1
2
3
4
5
AnyDance route:
screen pixels → guess geometry

World-native route:
Unity world coordinates → actual geometry



14. 把它抽象以后:这其实是一个标准的 Embodied Agent

抽象为通用 Embodied Agent
抽象为通用 Embodied Agent

技术资源:SVG · PNG · Mermaid 源码

小白版:一个真正“有身体”的 Agent,需要的不只是 LLM

如果一个 AI 只会聊天,LLM 本身就能完成很多事情。

但只要它要在世界里行动,就必须回答六类问题:

  1. 我看到了什么? → Perception
  2. 世界里有哪些稳定对象? → World Model
  3. 我想做什么? → Cognition / Planner
  4. 这个目标应该拆成什么动作? → Skill / Behavior
  5. 动作怎么平滑、安全执行? → Low-level Controller
  6. 我真的做到了吗? → Feedback / Proprioception

N.E.K.O VRChat 插件恰好把这六层几乎都实现了一个版本。

它最有研究价值的地方,不是“VRChat 很酷”,而是它展示了:怎样让一个语言模型在不承担实时控制的情况下,可靠地控制一个持续变化的虚拟身体。

专业版:模块映射
Embodied Agent 概念 当前项目对应
Perception DXcam/MSS + local detector + VLM + OSC
World Model WorldStateStore / stable entity IDs
Memory N.E.K.O memory
Cognition N.E.K.O Core/Assist model + Agent
Skill interface body_* / vrc_* semantic tools
Behavior arbitration BehaviorStateMachine
Local planner Navigator
Low-level controller BodyScheduler
Actuator AnyaDance OpenVR virtual devices + OSC
Proprioception body_awareness + driver telemetry + velocity feedback
Environment VRChat / SteamVR / optional world-native Unity

该架构的核心是 separation of concerns + multi-rate control + observation-grounded state。

15. 最后再回到一张图:完整数据流到底是怎么跑的?

最终主线数据流
最终主线数据流

技术资源:SVG · PNG · Mermaid 源码

小白版:从一句“去跟他打招呼”完整走一遍

假设你说:

“去右边那个人旁边,跟他打个招呼。”

完整过程可以这样理解:

  1. N.E.K.O 理解语言:知道“右边那个人”是目标,“打招呼”是意图;
  2. 视觉找目标:桌面画面里 detector 找到候选,必要时 VLM 确认身份;
  3. World State 固定目标:把它变成稳定 entity;
  4. Navigator 开始闭环走路:10Hz 看目标在哪,持续修正方向;
  5. BodyScheduler 120Hz 发输入:通过 AnyaDance 虚拟控制器推动 VRChat;
  6. OSC 检查实际速度:发现撞墙就修正,目标丢失就停;
  7. **到达后 LLM 发 greet**;
  8. Behavior 检查动作冲突;
  9. Scheduler 平滑挥手;
  10. body_awareness 告诉 Agent 动作是否仍在进行。

这才是“一句话控制 VRChat”背后真正的系统复杂度。

专业版:全栈频率总结
全栈运行频率
全栈运行频率

技术资源:SVG · PNG · 原始 TXT

多频率设计不是实现细节,而是整套架构的核心:

  • 模型做低频、不确定、语义强的工作;
  • 本地算法做高频、确定、实时的工作;
  • perception 以 freshness 为第一目标;
  • actuator feedback 不与“命令已发送”混为一谈。

16. 这套实现真正的优点和短板是什么?

优点 1:LLM 没有被错误地当作实时控制器

这是最正确的架构选择。模型负责 intent,scheduler 负责 120Hz;两者各做擅长的事情。

优点 2:它很重视“事实和意图的区别”

accepted=true ≠ driver received ≠ avatar moved;grip sent ≠ object held。不能观测的就保持 unknown。

对 Agent 来说,这是比“动作种类多”更重要的可靠性基础。

优点 3:传统视觉和 VLM 分工合理

高频 track 用 detector,开放语义用 VLM,语义识别后绑定稳定 ID。这比每一帧都把截图塞给大模型高效得多。

优点 4:AnyDance 方案有很强的普通 VRChat 泛化潜力

它通过虚拟 SteamVR 设备扮演普通玩家,不要求目标 world 专门配合。

短板 1:当前桌面方案缺少真正 3D geometry

复杂空间规划能力受限,这是从 2D screen route 天然带来的信息瓶颈。

短板 2:视觉假阳性和镜像/菜单问题仍然棘手

桌面像素会同时包含 UI、镜子、缩略图、装饰物。单纯 person detector 无法稳定等价于“世界里真实玩家”。

短板 3:通用交互结果难以确认

VRChat OSC 并不是完整 world API,因此 Pickup attachment、世界物体状态等无法普适观测。

短板 4:系统工程复杂度高

VMC、WebSocket、OSC、UDP、OpenVR driver、capture、VLM、world state、navigator、scheduler 多层叠加,部署和诊断门槛高。

短板 5:虚拟 SteamVR driver 有使用边界

AnyaDance 自身明确提示 online game / anti-cheat / Terms of Service 风险,使用时应限制在授权测试环境并自行评估平台规则。


17. 一句话总结

一句话类比
一句话类比

技术资源:SVG · PNG · 原始 TXT

如果只记住一句话:

N.E.K.O 是脑和人格;VMC 把桌宠身体动作送出来;Behavior FSM / BodyScheduler 是小脑;AnyaDance / SteamVR 是运动神经;VRChat OSC 是反馈神经;DXcam / detector / VLM 是眼睛;World State 把“看到的东西”变成可持续操作的世界对象。

而 YUI World-Native 并不是突然出现的第二套“更高级方案”,它是对桌面路线核心限制——缺少真实 3D world geometry——的一种结构性回答。

因此真正值得关注的不是“AI 会不会在 VRChat 里挥手”,而是这个项目正在探索一个更普遍的问题:

如何让 LLM 拥有身体,但不把实时控制、物理反馈和世界事实交给 LLM 幻想。


附录:端口、模块与安全层速查

这一节不放叙事,只放工程上真正会被反复查的东西:后端模块拆分、端口拓扑、遥测与四层安全。默认折叠,需要时再展开。

展开:Backend 模块拆分解释独立 backend 内部不是一个大循环,而是多个职责明确的模块。
Backend 模块拆分
Backend 模块拆分

技术资源:SVG · PNG · Mermaid 源码

为什么这张图会出现在这里?

解释独立 backend 内部不是一个大循环,而是多个职责明确的模块。

小白版

把身体系统拆成“动作、眼睛、地图、导航、安全、网络”等小部门,各自做一件事。

举个例子: Vision 坏了不应该让 OSC 发包代码也变得不可维护;Navigator 只读 WorldState,不直接写 detector。

优点: 可测试、可替换、故障定位清楚。

缺点 / 代价: 接口数量多,跨模块状态更复杂。

展开专业版:模块、参数与技术取舍

BackendService 组合 adapters/Scheduler/OSC/VMC/driver telemetry/WorldState/Vision/Navigator/Autonomy/Cognition;process/client 构成 hosted plugin 与 backend 的 IPC 边界。

具体参数 / 协议: 各 worker 运行频率独立;body 120Hz、nav 10Hz、capture约10Hz/配置、VLM按需。

技术层面的优劣: 模块化适合长期演进,但需要严格 contract 与 thread/process ownership。


展开:网络 / 端口拓扑给部署和排障提供一张“每个端口是谁和谁说话”的地图。
网络 / 端口拓扑
网络 / 端口拓扑

技术资源:SVG · PNG · Mermaid 源码

为什么这张图会出现在这里?

给部署和排障提供一张“每个端口是谁和谁说话”的地图。

小白版

如果角色不动,先看是哪一段断了:N.E.K.O→VMC、插件→AnyaDance、SteamVR→VRChat,还是 VRChat→OSC 回传。

举个例子: 39539 被别的 VMC 接收器占用时,待机骨骼链就会出问题;9001 被路由器独占时,反馈会消失。

优点: 排障直接。

缺点 / 代价: 端口多,用户环境冲突概率高。

展开专业版:模块、参数与技术取舍

列出 control plane/data plane:48911 HTTP、39539 VMC UDP、39570 AnyaDance command UDP、39571 driver telemetry multicast、9000/9001 VRChat OSC。

具体参数 / 协议: 所有默认绑定 loopback,driver telemetry 使用239.255.39.71 multicast group。

技术层面的优劣: 本机化降低安全暴露,但仍需处理端口独占、路由器转发和多 sender 冲突。


展开:四层安全系统汇总模型工具、行为仲裁、低层限幅和 autonomy gate 四层…
四层安全系统
四层安全系统

技术资源:SVG · PNG · Mermaid 源码

为什么这张图会出现在这里?

汇总模型工具、行为仲裁、低层限幅和 autonomy gate 四层安全。

小白版

像开车有四道保险:方向盘指令先校验,动作冲突再检查,底层速度/范围有限制,自主驾驶还要单独授权。

举个例子: body_stop 会冻结当前合法姿态、释放控制器输入并锁定后续运动,reset 才恢复。

优点: 单点失误不容易直接变成失控。

缺点 / 代价: 多重 gate 会让失败原因变多,需要 UI 清楚说明。

展开专业版:模块、参数与技术取舍

Tool validation → Behavior admission → Scheduler limits/state latch → Autonomy arm/TTL/freshness;emergency input release 是独立低层保护。

具体参数 / 协议: auto_start=false;启动后 state=disabled;emergency_release_ms=50。

技术层面的优劣: defense in depth 适合具身体 Agent,但会增加状态组合与测试矩阵。


展开:默认端口速查部署/排障速查表。
默认端口速查
默认端口速查

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

部署/排障速查表。

小白版

哪段不通就查对应端口

展开专业版

48911 HTTP、39539 VMC、39570 command、39571 telemetry、9000/9001 OSC。

原始终端内容:

1
2
3
4
5
6
48911  N.E.K.O HTTP / VMC control
39539 VMC UDP: N.E.K.O → plugin
39570 AnyaDance UDP: plugin → driver
39571 Driver telemetry multicast
9000 VRChat OSC input
9001 VRChat OSC output

展开:默认安全启动说明插件默认不会自动接管身体。
默认安全启动
默认安全启动

技术资源:SVG · PNG · 原始 TXT

这张终端图想证明什么?

说明插件默认不会自动接管身体。

小白版

启动程序也不会立刻乱动,必须显式开启

展开专业版

auto_start=false + state=disabled 是fail-safe default。

原始终端内容:

1
2
3
4
5
auto_start = false

state = disabled

必须显式 body_enable


主要公开来源

参数与实现状态基于 2026-09-09 公开仓库快照。后续版本若修改配置,Worker 应优先以仓库当前代码为准,并在页面顶部标注“本文分析快照日期”。

分析快照:2026-09-09 · 本文不保证未来实现一致;参数变化请以 当前仓库源码 为准。