8.9 KiB
Agent
脚本入口: eve.Agent(),默认槽位 eve.agent。C++ 命名空间 eve::agent,库 EVAgent。
Agent 面向游戏自动操作、决策策略学习、仿真优化与自动测试。默认优化领域返回的累计奖励;覆盖率和失败奖励默认都是零,测试场景自行开启。
算法为进化 rollout 搜索加策略蒸馏:种群采样、精英选择、动作变异,以及两层 tanh MLP 的 masked-softmax 交叉熵训练。这不是严格的多温度 MCMC。保留均匀随机策略用于基线比较。
从脚本创建 agent
实现 reset(seed) 与 step(action, dt) 即可接入领域。回调返回观察表;执行错误可抛出脚本异常,绑定转换为 CallbackFailure Result。
local brain = eve.Agent();
local environment = {
x = 0,
observe = function(reward) {
return {features=[x / 3.0], legalActions=[0,1], reward=reward,
outcome=x == 3 ? "success" : "running"};
},
reset = function(seed) { x = 0; return observe(0.0); },
step = function(action, dt) {
local before = x;
x += action == 0 ? 1 : -1;
if (x < 0) x = 0;
if (x > 3) x = 3;
return observe((x - before).tofloat());
}
};
local trained = brain.run({featureCount=1, actionCount=2,
population=8, elites=2, generations=4, horizon=8}, environment);
if (!trained.ok) throw trained.code;
local chosen = brain.act(trained.value.policy, environment.reset("42"));
if (!chosen.ok) throw chosen.code;
local next = environment.step(chosen.value, 1.0 / 60.0);
完整脚本见 train.nut。act 只选择合法动作,不直接改变游戏;领域是状态和操作的唯一权威。
观察与配置
观察表字段:
features:有限数值数组,长度等于 featureCount,建议归一化到[-1,1]。legalActions:无重复整数动作 ID,范围[0,actionCount),Running 时必须非空。reward:本步增量奖励,默认零;初始观察奖励必须为零。outcome:running、success、failure,默认 running。coverage:可选语义覆盖标签数组。finding:稳定失败编号;failure 时必须非空。
配置均可省略以使用 Config 默认值,未知字段拒绝:
- 网络:
featureCount、actionCount、hiddenWidth。 - 搜索:
population、generations、horizon、elites、mutationProbability、randomProbability。 - 训练:
trainingEpochs、learningRate。 - 时间与随机源:
dt、environmentSeed、searchSeed、learningSeed。 - 策略:
strategy="evolution"或"random";backend="cpu"、"tensor"或"gpu"。 - 测试目标:
coverageWeight、failureWeight、maxFindings。
seed 可用非负整数或十进制字符串;reset 回调收到十进制字符串,避免完整 uint64 seed 失真。每个候选回合使用同一 environment seed;搜索和权重初始化使用独立 seed。多个场景需显式运行多个 environment seed。
使用 tensor
local tensorProvider = eve.AgentTensor(); // 构建需包含 agent_tensor
local trained = brain.run({featureCount=1, actionCount=2, backend="tensor",
population=8, elites=2, generations=4, horizon=8}, environment);
if (!trained.ok) throw trained.code;
local decision = brain.actTensor(trained.value.policy, environment.reset("42"));
if (!decision.ok) throw decision.code;
agent_tensor 位于 agent/tensor,依赖 agent 和 tensor;核心 agent 不反向依赖 tensor。provider 随模块构造注册,析构前撤销。缺少 provider 时,显式 tensor 请求返回 Unsupported,不隐式切换后端。
backend="tensor" 使用生产 Tensor 的 eager CPU 算子,报告 backend="tensor-cpu"、trainingBackend="cpu-sgd"。backend="cpu" 使用核心 double 网络。
GPU 推理与训练
在 Graphics 设备完成初始化后(例如 eve_init),创建 eve.AgentTensor(),将上例配置改为 backend="gpu",并使用 brain.actGpu(policy, observation) 或 brain.inferGpu(policy, observation)。
GPU 模式把两层 tanh、masked softmax、交叉熵反向传播、逐参数梯度裁剪及 SGD 更新编译成 tensor GPU 图,通过 Gpgpu 提交。报告为 backend="tensor-gpu"、trainingBackend="tensor-gpu-sgd"。搜索、环境回调、精英选择和随机采样仍在 CPU;没有引入通用自动微分 API。
网络形状不变时复用推理/训练图。Policy 的 owning 权重仍为唯一权威,每次调用上传输入并下载结果;失败不发布部分更新。未注册 provider、设备未就绪或计算图不支持时返回错误,不会静默退回 CPU。getBackends 报告设备就绪状态,具体网络的编译仍可能失败。
GPU 使用 FP32,CPU 使用 double,按数值容差比较;小差异可能改变后续随机动作,因此不承诺跨设备逐位相同的训练轨迹。已在 Vulkan 上验证生产生成 shader 的推理和 SGD;尚未验证 WebGPU。单个小网络可能受提交/读回开销影响,不承诺比 CPU 更快,当前未提供端到端加速比。
AgentTensor 拥有缓存图和设备资源,必须在 Graphics 设备销毁或重建前销毁;设备重建后重新创建 provider。不要在环境回调内销毁设备。所有 GPU 操作在设备 owner 线程同步完成,无异步资源借用。
测试与回放
测试时显式设置 coverageWeight=1.0、failureWeight=100.0 等领域目标。评分为累计奖励加本回合不同覆盖点数乘 coverageWeight,再加终止失败奖励。达到 maxFindings 后不保留更多失败轨迹,但失败计数继续增长。
报告包含 policy、best、去重 findings、coverage、episodes、steps、failures、trainingSamples、bestScore、backend 和 trainingBackend。best 是评分最高的轨迹,也可能为 horizon 截断的 Running,不保证成功。
foreach (trace in trained.value.findings) {
local reproduced = brain.replay(trace, environment, 0.00001);
if (!reproduced.ok) throw reproduced.code;
}
回放使用实际动作和初始 seed,比较每步观察、合法动作、覆盖与终止状态,不依赖训练策略。数值使用显式 tolerance,其余字段精确匹配。
API 快查
getName():模块名。getBackends():Result,value 为实际可用后端标签数组。run(config, environment):Result,value 为训练/搜索报告。infer(policy, observation):Result,value 为 CPU 合法动作概率数组。inferTensor(policy, observation):相同契约,使用 tensor provider。inferGpu(policy, observation):相同概率契约,使用 GPU 计算图,无 CPU fallback。act(policy, observation):Result,value 为最大概率合法动作 ID;平分时取合法目录中较早动作。actTensor(policy, observation):相同决策规则,使用 tensor provider。actGpu(policy, observation):相同决策规则,使用 GPU 计算图。replay(trace, environment, tolerance):无 value 的 Result;明确返回执行错误或 divergence。
C++ 使用 run/infer/replay 和 Backend。Codec.h 统一处理 Config/Observation/Policy/Trace 与 owning Value 的转换,脚本和 JSON 保存共用;例如 encodePolicy(policy).toJson()、decodePolicy(value)。Policy、Trace、Report 的 schema 为 evengine.agent.policy/trace/report,版本 1;未知字段/版本拒绝,无旧的已发布版本需迁移。不提供原始内存存档或自动文件写入。
生命周期与限制
环境由调用方拥有,在 owner 线程同步执行。绑定仅在调用期间 root 回调表,返回数据独立拥有。run/replay 嵌套调用返回 Conflict;每次回调恢复 VM 栈,抛错后模块可再次使用。runner 不持锁调用未知代码,不缓存领域对象或 provider 指针到下一次环境回调。
reset 必须重建领域句柄、事件队列和 RNG。完成或失败后环境停留在最后执行状态,不自动恢复调用前状态。长回合会阻塞当前线程;实时帧推进、进程隔离、native 崩溃和卡死超时需要外部宿主。输入和预算有上限;Squirrel 公共 Value 转换最多 100000 个元素,超限返回失败,不发布 ok + null。
C++ 示例覆盖生产 grid 与 UI layout 算法;布局数值测试不代表 UI 点击分派或渲染验收。学习不保证在所有领域优于随机策略,应按多个 seed 比较。
构建
依赖初始化后运行 make check/agent。Windows 用 MSVC 环境,或包裹 CMake:
.\cmake\with-msvc.cmd cmake -S test/agent -B build/agent -G Ninja -DCMAKE_BUILD_TYPE=Debug
.\cmake\with-msvc.cmd cmake --build build/agent -j 4
ctest --test-dir build/agent --output-on-failure
专用工程支持 EVE_ZEROERR_SOURCE、EVE_ECS_SOURCE、EVE_THIRD_PARTY_SOURCE。EVE_AGENT_TENSOR=OFF 验证缺少 tensor 的脚本路径;再关闭 EVE_AGENT_SCRIPT、EVE_AGENT_COMPOSITION 可验证纯核心。主引擎模块由 manifest 接线。