Skip to content

工具集 ​

Nova 能做的事全部包装成工具,走 OpenAI 的 function calling 协议交给模型选。当前一共 68 个,但这页不列清单——只讲工具面是怎么设计的。

注册表长什么样 ​

每个工具就是一条记录:

csharp
public sealed record NovaTool(
    string Name,            // 函数名,snake_case
    string DisplayName,     // 给人看的名字,会出现在确认清单里
    string Description,     // 给模型看的:什么时候该调它
    string ParametersJson,  // JSON Schema
    bool ReadOnly,          // 信任边界的分水岭
    Func<JsonElement, CancellationToken, Task<string>> ExecuteAsync);

序列化出去就是标准 tools 参数:

json
{
  "type": "function",
  "function": {
    "name": "read_version_detail",
    "description": "查看某个已安装版本的详情:Java 要求、实例设置、已装 mod 列表。",
    "parameters": {"type":"object","properties":{"version_id":{"type":"string"}},"required":["version_id"]}
  }
}

工具本身不做新业务逻辑,全部复用既有服务——删文件、装东西、启动游戏都走启动器原本那条路径,不给 AI 另开一条后门。Description 是写给模型的说明书,所以写成祈使句并带约束,比如 list_versions 的描述是「不要臆造版本号,装版本前先看这里」——这是提示注入的防线之一:模型被告知 ID 必须来自工具结果。

只读与写 ​

ReadOnly 是整个信任模型的分水岭:

  • 只读工具(ReadOnly: true):查询类,Agent 循环里立即执行,结果以 role: "tool" 回喂,模型据此继续下一轮。
  • 写工具(ReadOnly: false):只生成参数,不执行。NovaAgentLoop 把它们攒成一份确认清单交给用户。
工具读还是写备注
get_settings读游戏目录、内存、Java、下载源、版本隔离
check_environment读这版本能不能起来:Java 匹配、内存越界、路径、账号
analyze_crash读离线诊断崩溃,不依赖云端
check_mod_conflicts读重复 modId、加载器混装、损坏文件
install_content写装 mod/资源包/光影,project_id 必须来自搜索结果
install_modpack写导入 .mrpack 或 CurseForge 导出 zip
export_modpack写把实例导出成可分享的 .mrpack
backup_version / restore_backup写备份 id 来自 list_backups

有一条贯穿全部写工具的纪律:能回滚就不硬删。模组冲突「处理」是改名加 .disabled 后缀,存档搬家是移动前先压一份 zip 到 backups/。确认清单里写得很直白——「改名 sodium.jar.disabled(不删除,随时可改回来)」。

顺序即语义 ​

Tools 的注册顺序就是发给 LLM 的顺序,注册表把它分成两段:

csharp
Tools = readOnlyOnly
    ? [.. BuildReadTools()]
    : [.. BuildReadTools(), .. BuildWriteTools()];

只读工具排在前面。这不是美观问题——不少模型对工具列表的顺序敏感,把「查询类」放前面能显著降低它一上来就提议写操作的概率。

readOnlyOnly 这个开关是给跨端最小实现准备的:没有 UI 确认清单执行入口的宿主(比如移动端)只注册只读工具,宁可不给模型这个能力,也不给一个提了也落不了地的写操作。

两个收口 ​

结果统一截断 900 字符。 工具返回的是给人看还是给模型看的都有,但模型那边必须封顶,否则一个 list_versions 就能把上下文撑爆:

csharp
private const int MaxResultChars = 900;

var result = await tool.ExecuteAsync(args, ct);
return result.Length <= MaxResultChars ? result : result[..MaxResultChars] + "…(已截断)";

宿主相关的能力条件注册。 NovaToolContext 里 Host(录屏 / 插件 / 外观 / 页面跳转)为空时,recording_status、start_recording、list_plugins、set_appearance 这些工具根本不注册;Multiplayer 为空时联机工具同理。Core 的单元测试不依赖 WinUI,这些工具会自动缺席——比在运行时返回一个「当前宿主不支持」更干净,因为模型根本看不到它们就不会去调。

一个例外

open_page 被标成 ReadOnly: true。它只是把界面切到某个页面,不改任何配置——但它存在的意义是引导用户去做只有界面能完成的事(登录账户、看皮肤),所以必须能立刻执行,不能卡在确认清单上。

相关链接:Nova 是什么 —— 信任递进与降级链 相关链接:Agent 循环 —— 工具怎么被调用与回喂

基于 MIT 许可证(有修改)开源