架构概览
在用技能和插件扩展言出法随之前,建议先了解它的基本架构,知道模型怎样感知世界、怎样调用能力。这样你才清楚新加的能力接在哪一层,又是怎样起作用的。
言出法随的架构自下而上分为三层。
最底层是 Minecraft,也就是智能体身体所在的世界。它的身体是服务端上一个真实的玩家实体,和你一样受游戏规则约束,要走路才能到达,要挖掘才能拿到方块,背包有容量,会饥饿也会受伤。
中间层是开放给模型的接口,主体是 Lua API。模型编写 Lua 程序调用这些 API,进而操控玩家实体。
插件也是通过这一层接入其他模组的。不过并不是每个功能都需要注册新的 API,一般来说,能用原版交互完成的事,只需要用技能教会智能体怎么做。
以车万女仆为例,驯服女仆只要手持蛋糕右键她,而智能体本来就有扫描、移动和手持物品右键的 Lua API,只需要在技能里教它把这些动作组合起来,就像这样:
-- 手持背包里的蛋糕右键女仆,驯服就完成了
numen.use.entity(maid, {item = "minecraft:cake"})但言出法随的身体是服务端上的玩家实体,没有自己的客户端。如果一个界面是服务端的标准容器菜单,比如箱子、熔炉这种只靠格子交互的界面,智能体照样能用 numen.use.block 打开、用 numen.gui 操作格子,不需要插件;可如果界面里有按钮、输入框,或者依赖客户端才有的状态,智能体就用不了了。指令也是同理,智能体能用 numen.mc.run 执行它有权限执行的任何指令,不需要插件。它右键这类方块时,右键在服务端产生的效果照常生效,只是界面不会出现。右键一个已驯服的女仆并不会打开女仆界面。这时插件就需要把界面里的功能封装成 Lua API,比如切换女仆的工作模式、修改她的日程。智能体虽然看不到界面,得到的结果却和普通玩家点界面完全一样,就像这样(完整实现见 plugins/tlm):
-- 812 是女仆的实体编号,可以从 numen.scan.entities 的结果里读到
-- 把她的工作模式切换成种地
tlm.maid.task("touhou_little_maid:farm", {maid = 812})
-- 修改她的日程:晚上干活,白天睡觉
tlm.maid.config(812, {schedule = "night"})"是,史蒂夫模型"的插件也是如此。你可能会问,"是,史蒂夫模型"本身就有更换模型的指令,为什么还要注册新的 API?
原因在于,截至 2026 年 10 月它仍未完全开源,我们只能通过指令与它交互。智能体本身能用 numen.mc.run 执行指令,numen.mc.run("help <指令>") 还会列出这条指令接下来能填什么。可是"是,史蒂夫模型"更换模型的指令需要管理员权限,智能体通常没有,连这条指令都看不到,自然也不知道有哪些模型、每个模型的 id 是什么。就像走进一家没有菜单的餐馆,知道可以点菜,却不知道厨房里有哪些菜。所以插件以服务器的权限、只对智能体自己执行这条指令,把"列出可用的模型"和"换成指定的模型"封装成了 Lua API,换完还会读回它身上穿的模型,确认真的换成了(完整实现见 plugins/ysm):
-- 查看外观信息,一次返回三样东西:
-- 现在穿的模型、所有能换的模型清单、当前模型可选的贴图
local looks = ysm.model.options()
-- 按清单里的 id 换成指定的模型
-- 注意要用 id(如 "misc/1_alex"),不是模型的显示名
ysm.model.switch("misc/1_alex")基于这套架构,可以总结出一条原则。服务端的玩家实体本身能完成的事,优先用技能教会它;它完成不了的事,比如只存在于客户端的界面和功能,就只能用插件封装成 Lua API 供它调用。
当然,有些事虽然能用原版交互完成,但步骤繁琐、容易出错,这时也可以封装成 Lua API,降低智能体出错的概率。
至于多复杂才算"复杂",靠感觉是说不准的。这是一个两难的取舍。把简单的事也封装成 Lua API,接口越来越多,会挤占模型的上下文、分散它的注意力;把复杂的事交给技能,模型又容易出错。
所以言出法随用专门的评测来衡量当前 Harness 的质量。Harness 指的是模型之外的一切,包括提供给它的接口、技能、提示词,以及运行程序的环境。
