本系统实现了基于 Qwen3-VL-4B 模型的 Vision-Language-Action (VLA) 架构,让 NPC 能够通过视觉感知来理解游戏环境并与玩家进行智能交互。系统支持两种模型部署方式:HTTP API 外挂服务器模式和LLamaSharp 内嵌模式。
- Unity Engine - 游戏引擎和渲染系统
- C# / .NET - 主要编程语言
- Async/Await - 异步编程模式
- Coroutines - Unity 协程系统
- Qwen3-VL-4B - 多模态视觉语言模型(支持图像+文本输入)
- LLamaSharp - .NET 平台的 LLM 推理库(内嵌模式)
- OpenAI-Compatible API - HTTP API 接口标准(外挂模式)
- Smart Resize 算法 - 图像预处理,满足 Qwen3-VL 的 Patch 对齐要求(28的倍数)
- MCP (Model Context Protocol) - 模型上下文协议,用于 Unity 运行时与 AI IDE(如 Cursor)的桥接
- HTTP/HTTPS - 与外部 LLM 服务器的通信协议
- SSE (Server-Sent Events) - MCP 服务器的实时数据推送
- JSON - 数据交换格式
- RenderTexture - 每个 NPC 独立的渲染目标
- Camera System - 为每个 NPC 创建独立的相机(锥形视野)
- GPU Async Readback - 异步 GPU 图像回读
- Graphics.Blit - 图像缩放和格式转换
- PNG Encoding - 图像编码
- Texture2D - Unity 纹理处理
- Base64 Encoding - 图像数据传输编码
VLASystemManager (系统管理器)
├── HttpApiLlamaManager (HTTP API 模型管理器)
├── LlamaManager (内嵌模型管理器)
├── UnityMCPServer (MCP 服务器)
├── VLAModelOutputLogger (模型输出日志管理器)
└── NPC 组件树
├── AgentEye (视觉传感器)
├── VLAAgentController (VLA 智能体控制器)
├── VLANPCBridge (VLA-NPC 桥接)
└── PlayerActionDetector (玩家动作检测器)
- 负责系统初始化
- 管理模型管理器的创建和加载
- 自动为 NPC 添加 VLA 支持
- 支持两种模型管理方式的切换
- 为每个 NPC 创建独立的 Camera 组件
- 配置锥形视野(FOV: 25°,距离: Archer 8m / Soldier 5m)
- 使用独立的 RenderTexture 捕获视野图像
- 支持异步 GPU 图像回读
- 实现感知-决策-行动循环
- 管理认知循环(默认 0.5 秒间隔)
- 调用模型管理器进行推理
- 解析模型输出的 JSON 动作指令
- 将 VLA 动作指令转换为 NPC 控制器的具体行为
- 支持动作映射:Attack、Move、Dodge、Realize、Escape、Idle
- 处理动作执行冷却和状态管理
- 实现 Smart Resize 算法
- 确保图像尺寸满足 Qwen3-VL 的 Patch 对齐要求(28的倍数)
- 在最小/最大像素限制内优化分辨率
- 检测玩家动作并触发 NPC 反应
- 支持事件驱动的响应机制
实现类: HttpApiLlamaManager
特点:
- ✅ 无需在 Unity 中加载大模型文件
- ✅ 支持任何兼容 OpenAI API 的服务器(LM Studio、Ollama、vLLM 等)
- ✅ 模型更新和维护更方便
- ✅ 可以共享模型服务器,多个 Unity 实例共用
- ✅ 支持流式响应(可选)
配置参数:
apiBaseUrl = "http://localhost:port" // LLM 服务器地址
apiModel = "qwen/qwen3-vl-4b" // 模型名称
allowInsecureHttp = true // 允许 HTTP 连接(开发用)工作流程:
- Unity 捕获 NPC 视野图像
- 将图像编码为 Base64
- 通过 HTTP POST 请求发送到 LLM 服务器
- 服务器返回 JSON 格式的动作指令
- Unity 解析并执行动作
支持的 API 端点:
/v1/chat/completions- 标准 OpenAI 兼容接口- 支持多模态输入(图像 + 文本)
实现类: LlamaManager
特点:
- ✅ 完全离线运行,无需网络连接
- ✅ 模型直接嵌入游戏,减少延迟
- ✅ 适合单机游戏和隐私敏感场景
⚠️ 需要较大的内存和显存⚠️ 模型文件需要打包到游戏中
技术实现:
- 使用 LLamaSharp 库加载 GGUF 格式模型
- 支持 GPU 加速(通过 CUDA 后端)
- 支持 CLI 包装器模式(如果 LLamaSharp 不可用)
- 动态反射加载,避免编译时依赖
配置参数:
modelPath = "Assets/.../Qwen3-VL-4B-Instruct-Q4_K_M.gguf"
mmprojPath = "Assets/.../mmproj-Qwen3-VL-4B-Instruct-F16.gguf"
nGpuLayers = 35 // GPU 层数
contextSize = 4096
temperature = 0.7f备用方案:
- 如果 LLamaSharp 加载失败,可以自动切换到 CLI 包装器模式
- 通过子进程调用
llama.cpp可执行文件 - 使用 StdIO 或命名管道通信
两种方式都实现了 IVLAModelManager 接口,确保代码的统一性:
public interface IVLAModelManager
{
bool IsModelLoaded { get; }
bool IsLoading { get; }
Task<bool> LoadModelAsync();
Task<VLAAction> InferAsync(byte[] imageData, int width, int height,
string systemPrompt, string userPrompt = "", ...);
}优先级策略:
- 系统优先使用 HTTP API 模式(如果启用)
- 如果 HTTP API 失败,自动回退到内嵌模式(如果启用)
- 可以在运行时动态切换
MCP 是一个用于 AI 应用与外部工具/服务交互的协议。本系统实现了 UnityMCPServer,提供 Unity 运行时与 AI IDE(如 Cursor)的桥接。
已注册资源:
unity://scene/hierarchy- Unity 场景层次结构unity://agent/view- NPC 视野图像unity://agent/memory- NPC 记忆系统
已注册工具:
get_agent_view- 获取指定 NPC 的当前视野query_agent_memory- 查询 NPC 的记忆信息teleport_agent- 传送 NPC 到指定位置execute_csharp- 在 Unity 运行时执行 C# 代码
serverPort = 8080 // 服务器端口
autoStart = true // 自动启动
enableLogging = true // 启用日志端点:
http://localhost:8080/sse- SSE 事件流http://localhost:8080/message- POST 消息接口
VLAModelOutputLogger 组件负责:
- 记录所有模型推理请求和响应
- 通过 MCP 服务器广播到客户端
- 支持实时监控和调试
┌─────────────────┐
│ AgentEye │ 捕获 NPC 视野图像
│ (视觉传感器) │
└────────┬────────┘
│ RenderTexture → PNG → Base64
▼
┌─────────────────┐
│ ImagePreprocessor│ Smart Resize (28倍数对齐)
└────────┬────────┘
│
▼
┌─────────────────┐
│ VLAAgentController│ 构建提示词 + 图像
│ (认知循环) │
└────────┬────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐
│ 模型管理器选择 │─────▶│ HttpApiLlamaManager│
│ │ │ 或 LlamaManager │
└─────────────────┘ └────────┬─────────┘
│
▼
┌──────────────────┐
│ 模型推理 │
│ (Qwen3-VL-4B) │
└────────┬─────────┘
│ JSON 响应
▼
┌─────────────────┐ ┌──────────────────┐
│ VLAAction │◀─────│ 解析 JSON │
│ (动作指令) │ │ │
└────────┬────────┘ └──────────────────┘
│
▼
┌─────────────────┐
│ VLANPCBridge │ 转换为 NPC 行为
│ (动作执行) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ NPC Controller │ 执行具体动作
│ (Archer/Soldier)│
└─────────────────┘
-
感知阶段(AgentEye)
- 每 0.5 秒触发一次认知循环
- 手动渲染相机到 RenderTexture
- 异步 GPU 回读图像数据
- 转换为 PNG 并编码为 Base64
-
预处理阶段(ImagePreprocessor)
- 计算符合 Qwen3-VL 要求的分辨率(28的倍数)
- 在最小/最大像素限制内优化
- 使用 Graphics.Blit 缩放图像
-
推理阶段(模型管理器)
- 构建多模态提示词(系统提示词 + 用户提示词 + 图像)
- 调用模型进行推理
- 解析 JSON 响应为 VLAAction 对象
-
决策阶段(VLAAgentController)
- 验证动作有效性
- 更新当前动作状态
- 触发 MCP 日志记录
-
行动阶段(VLANPCBridge)
- 映射动作到 NPC 控制器方法
- 处理动作冷却和状态冲突
- 执行具体游戏行为
[Header("模型管理器选择")]
useHttpApi = true // 启用 HTTP API 模式
useLocalModel = false // 启用内嵌模式(备用)
[Header("HTTP API 配置")]
apiBaseUrl = "http://localhost:port"
apiModel = "qwen/qwen3-vl-4b"
allowInsecureHttp = true
[Header("内嵌模型配置")]
modelPath = "Assets/.../Qwen3-VL-4B-Instruct-Q4_K_M.gguf"
mmprojPath = "Assets/.../mmproj-Qwen3-VL-4B-Instruct-F16.gguf"
[Header("NPC配置")]
enableVLAForArchers = true
enableVLAForSoldiers = truerenderWidth = 1024 // 渲染宽度
renderHeight = 1024 // 渲染高度
fieldOfView = 25f // 视野角度(度)
viewDistance = 5f // 视野距离(米)- Archer: 8m, Soldier: 5m
nearClipPlane = 0.3f // 近裁剪平面cognitiveInterval = 0.5f // 认知循环间隔(秒)
maxPixels = 1000000 // 最大像素数
minPixels = 100000 // 最小像素数在场景中创建一个 GameObject,命名为 VLASystemManager,并添加 VLASystemManager 组件。
方式一:使用 HTTP API(推荐)
- 启动 LLM 服务器(如 LM Studio、Ollama)
- 在
VLASystemManager中设置useHttpApi = true - 配置
apiBaseUrl和apiModel
方式二:使用内嵌模式
- 确保模型文件在指定路径
- 在
VLASystemManager中设置useLocalModel = true - 配置
modelPath和mmprojPath
启动游戏后,系统会自动:
- 初始化模型管理器
- 启动 MCP 服务器
- 加载模型
- 为所有 NPC 添加 VLA 支持
- 启动认知循环
- 每个 NPC 使用独立的低深度相机(depth = -1000 - ID)
- 禁用 HDR、MSAA、遮挡剔除
- 使用 RenderTexture 缓存,避免重复渲染
- 异步 GPU 回读,不阻塞主线程
- 图像分辨率限制在 100K - 1M 像素
- Smart Resize 算法减少传输数据量
- 认知循环间隔可调(默认 0.5 秒)
- 支持流式响应(HTTP API 模式)
- RenderTexture 按需创建和释放
- 图像数据及时清理
- 使用对象池管理临时纹理
- 在
VLAAction.cs中定义新的动作枚举 - 在
VLANPCBridge.cs的ExecuteVLAAction方法中添加处理逻辑 - 更新系统提示词,告诉模型新的动作类型
修改 AgentEye.cs 中的参数:
renderWidth/renderHeight- 渲染分辨率cullingMask- 可见层级fieldOfView- 视野角度viewDistance- 视野距离
实现 IVLAModelManager 接口:
public class CustomLlamaManager : MonoBehaviour, IVLAModelManager
{
public async Task<VLAAction> InferAsync(...)
{
// 实现自定义推理逻辑
}
}系统提供详细的日志输出:
[VLASystemManager]- 系统初始化日志[HttpApiLlamaManager]/[LlamaManager]- 模型加载和推理日志[VLAAgentController]- 认知循环日志[VLANPCBridge]- 动作执行日志[AgentEye]- 视觉传感器日志[UnityMCPServer]- MCP 服务器日志
AgentEye.showViewCone- 显示视野锥形(Gizmos)VLAModelOutputLogger- 实时查看模型输出- MCP 客户端 - 通过 HTTP 接口监控系统状态
- 确保 LLM 服务器支持多模态输入
- 检查防火墙和网络连接
- 开发环境可以使用 HTTP,生产环境建议使用 HTTPS
- 需要较大的内存和显存(推荐 8GB+ GPU)
- 模型文件会增加游戏包体大小
- LLamaSharp 可能不完全支持 Qwen3-VL,可能需要 CLI 包装器
- 每个 NPC 都会进行独立的模型推理,注意 API 调用频率
- 建议限制同时激活的 NPC 数量
- 可以根据游戏状态动态调整认知循环间隔