拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Operit 默认工具(Default Tools)架构全景:参数变更全链路 Checklist 与源码级同步指南

Operit 默认工具(Default Tools)架构全景:参数变更全链路 Checklist 与源码级同步指南
  • AI Agent
  • 人工智能
  • 大模型
  • AI 应用
  • 工具调用
  • 本地部署
  • MCP Clients
  • Agent 记忆

【免费下载链接】Operit

The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent

项目地址:https://gitcode.com/gh_mirrors/op/Operit
点击查看免费下载

导读

本文围绕 Operit 仓库中 docs/doc-src/architecture/DEFAULT_TOOLS_ARCH.md 展开,系统讲解 Android AI Agent 中“默认工具(default tools)”的完整链路:从 LLM 看到的 Prompt/Schema,到 Kotlin 执行实现、JS/TS 脚本封装、示例与打包产物。读完本文,你将掌握修改任意工具参数/签名时必须同步修改的全部文件清单、全局搜索防遗漏方法、编译级自检命令,以及新增一个工具时的一站式落地方案,并能在源码层面理解每一层的真实实现。


1. 默认工具的组成:一条从上到下的数据流

在 Operit 中,“默认工具”不是单个文件,而是一条贯穿“对外契约”与“内部实现”的数据流。文档将其归纳为 7 层:

  1. 工具 Prompt / Schema——工具对 LLM 的“说明书”,决定模型如何生成 tool call;
  2. 工具注册——把toolName -> executor绑定起来;
  3. 工具执行实现——Kotlin 侧真正做事的逻辑;
  4. 脚本侧封装(JS Tools)——给 JS/TS 脚本更好用的 API;
  5. 示例与类型定义——examples/types与examples/**;
  6. 文档——docs/doc-src/package-dev等;
  7. 打包资源 / 产物——app/src/main/assets/packages/*.js等。

其中第 (1)(4)(5)(6) 层是“对外契约”,第 (2)(3) 层是“实现”。任何一层不同步,都会出现“LLM 按旧参数调用”或“脚本侧类型不一致”这类运行时问题。

在源码中可以逐一印证这 7 层:

  • Schema 层:SystemToolPrompts.kt 中的ToolPrompt与ToolParameterSchema(约 1007 行),例如read_file定义了path、environment、intent、direct_image、direct_audio、direct_video等参数,且environment的取值说明为"android" | "linux" | "repo:<仓库名>";
  • 注册层:ToolRegistration.kt 中的registerAllTools(handler, context)(约 2745 行),通过handler.registerTool(name, descriptionGenerator, executor)完成绑定;
  • 实现层:core/tools/defaultTool/下的standard/、debugger/、admin/、root/、accessbility/五套实现;
  • JS 封装层:JsTools.kt 中的getJsToolsDefinition()(约 1593 行),生成注入到 JS 运行时的Tools对象;
  • 类型定义层:examples/types/*.d.ts(如files.d.ts、chat.d.ts、core.d.ts、system.d.ts等);
  • 示例层:examples/*.ts及其编译产物examples/*.js;
  • 打包层:app/src/main/assets/packages/*.js(如system_tools.js、extended_file_tools.js、browser.js等约 30 个运行时包)。

小结:修改任何一个工具的“参数/签名”,本质上是在这条 7 层数据流上做一致性变更。下面每一节对应一层,并给出必改项。


2. 改参数时必须改哪些文件(Checklist)

文档的核心价值在于一份可执行的“必改/常见遗漏/可选校验”清单。本节按层展开,并补充源码级依据。

2.1 必改:工具 Schema / Prompt

  • 文件:SystemToolPrompts.kt
  • 要做的事:
    • 修改对应工具的parametersStructured(新增/删除/改名/调整required);
    • 更新description/details(尤其是规则、示例、参数解释);
    • 注意中英文双份描述(如basicTools与basicToolsCn、fileSystemTools与fileSystemToolsCn),两处都要同步。

源码佐证:ToolParameterSchema支持name、type、description、required、default等字段。例如sleep工具的参数duration_ms声明为type = "integer"、default = "1000"、required = false;use_package的package_name为required = true。中英文两份定义(basicTools/basicToolsCn)结构完全对应。

为什么必须改:这是 LLM 生成 tool call 的唯一依据。只改执行层不改这里,LLM 仍会按旧参数调用,造成“参数不匹配”的连续失败。

2.2 必改:工具注册(toolName -> executor)

  • 文件:ToolRegistration.kt
  • 要做的事:
    • 工具名不变时,一般无需改注册,但要确认注册项绑定的 executor 没变;
    • 若工具名/分组变更(如拆分工具),必须同步调整注册项。

源码佐证:注册层大量使用handler.registerTool(name = "...", descriptionGenerator = { tool -> ... }, executor = { tool -> ... })。描述生成器会从tool.parameters.find { it.name == "..." }读取参数拼装人类可读描述——例如execute_shell读取command、create_terminal_session读取session_name。这意味着:即使参数名变了而描述生成器里的it.name未同步,描述也会变成空值。

另外,ToolRegistration.kt 中的parseProxyInvocation展示了“代理调用”的参数白名单机制:只允许tool_name、params及__operit_package_caller_name等系统上下文参数,多余参数会直接返回Unexpected parameters错误。若你改动的是代理类工具,需要关注这里的白名单。

为什么必须看:改工具名或拆分工具时,注册未同步会出现“工具不存在/无法执行”。

2.3 必改:Kotlin 执行实现(参数读取与校验)

  • 常见目录(均在app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/下):
    • standard/*(标准权限实现,如 StandardFileSystemTools.kt、StandardUITools.kt);
    • debugger/*(如 DebuggerFileSystemTools.kt);
    • admin/*(如 AdminFileSystemTools.kt);
    • root/*(如 RootFileSystemTools.kt);
    • accessbility/*(如 AccessibilityFileSystemTools.kt);
    • ToolGetter.kt(按权限级别选择具体实现)。
  • 要做的事:
    • 将旧参数的读取逻辑替换为新参数(典型写法tool.parameters.find { it.name == "..." });
    • 如果某工具在debugger/root/admin/accessibility目录下有 override/替代实现,这些实现里同样要同步更新参数读取与校验;
    • 新增参数合法性校验:必填、互斥、默认值、兼容性策略;
    • 更新错误消息,使其能引导正确用法。

源码佐证:ToolGetter.kt 是权限分发的核心:getFileSystemTools、getUITools、getSystemOperationTools、getDeviceInfoToolExecutor都依据androidPermissionPreferences.getPreferredPermissionLevel()在ROOT / ADMIN / DEBUGGER / ACCESSIBILITY / STANDARD之间切换,null时回退到Standard*实现。因此同一工具在不同权限级别下可能有 4~5 份实现,漏改其中一份就会导致“高权限环境行为不一致”。

为什么必须改:不改这里,即使 schema 改了,执行层也拿不到参数或行为不对。

2.4 必改:JS 侧工具封装(Tools.*)

  • 文件:JsTools.kt
  • 要做的事:
    • 更新对应的 JS wrapper 函数签名;
    • 更新 wrapper 内部构造的params对象字段名;
    • 注意undefined/null的处理(JS 传参常见问题)。

源码佐证:getJsToolsDefinition()生成的Tools对象中,Tools.Files封装了list/read/readBinary/readPart/write/writeBinary/deleteFile/exists/move/copy/mkdir/find/grep/grepContext/info/apply/create/edit/zip/unzip/open/share/download等。注意封装层与 LLM 工具的命名并不一一对应:

  • Tools.Files.read实际调用toolCall("read_file_full", ...);
  • Tools.Files.readBinary调用toolCall("read_file_binary", ...);
  • Tools.Files.write调用toolCall("write_file", ...);
  • Tools.Files.apply(path, type, oldContent, newContent, environment)调用toolCall("apply_file", { path, type, old?, new? });
  • Tools.Files.create调用toolCall("create_file", { path, new });Tools.Files.edit调用toolCall("edit_file", { path, old, new })。

这印证了文档中的关键警告:“许多脚本调用的是Tools.Files.xxx而不是直接 toolCall”。修改底层工具参数时,必须同步改写 wrapper 里params的字段名,否则脚本侧仍然会按旧字段组装。

2.5 必改:TypeScript 类型定义(对脚本作者的契约)

  • 文件:examples/types/*.d.ts,尤其是examples/types/files.d.ts、examples/types/chat.d.ts、examples/types/core.d.ts、examples/types/system.d.ts等
  • 要做的事:
    • 更新函数签名与参数类型;
    • 若新增枚举/联合类型(如"replace" | "delete" | "create"),补充 type 定义;
    • 确认返回类型与字段名仍然正确。

为什么必须改:这是脚本作者写 TS 时的类型提示来源。类型与运行时不一致,编辑器不报错但运行报错,是最隐蔽的一类问题。

2.6 必改:示例代码(TS/JS)

  • 目录:examples/**(如 examples/system_tools.ts、examples/extended_file_tools.ts 等)
  • 要做的事:
    • 更新示例里对Tools.*的调用参数(通常优先改*.ts源码);
    • 仓库中存在*.ts -> *.js的编译产物,一般只需要改 TS 并重新构建产物,不建议手动修改*.js;
    • 若存在“编译后的 JS 产物/打包后的单文件”,需确保重新构建后产物也被更新(见 2.7)。

补充说明(advice-only 工具):

  • 若某个工具仅用于说明/提示(如usage_advice),在 examples 的 metadata 里加入advice: true;
  • 标记为advice: true的工具不要求在运行时存在真实实现,可跳过“工具不存在”的校验。

为什么必须改:示例是实际用法,会直接误导使用者;同时示例产物可能被打包进 app。

2.7 必改:打包资源 / 产物文件

  • 常见位置:
    • app/src/main/assets/packages/*.js(App 运行时加载的包文件,如system_tools.js、browser.js、workflow.js等约 30 个);
    • examples/*.js(可能是构建产物或分发用 bundle)。
  • 要做的事:
    • 若这些文件由构建脚本生成:优先重新构建;
    • 若当前仓库直接提交产物:需手动同步修改产物中的调用签名。

packages 同步约定(重要):

  • examples/*.ts通常作为脚本包的源代码;
  • examples/*.js作为编译产物/分发产物(不建议手改);
  • app/src/main/assets/packages/*.js作为 App 运行时加载的包文件;
  • 仓库提供 sync_example_packages.py(约 1099 行):按 packages_whitelist.txt 中的清单(含12306.js、system_tools.js、browser.js、linux_ssh、worldbook等 40+ 项),将examples/*.js复制到app/src/main/assets/packages/*.js。

同步执行约定(重要):

  • 做包同步时,只需执行一条命令:

    python tools/example_packages/sync_example_packages.py
  • 不要额外手动复制examples/*.js到assets/packages/,避免源/产物不一致。

因此,修改脚本包功能的推荐流程是:

  1. 优先改examples/<package>.ts;
  2. 通过构建/编译生成对应的examples/<package>.js;
  3. 运行python tools/example_packages/sync_example_packages.py同步到assets/packages/;
  4. 不建议直接手动修改examples/*.js或assets/packages/*.js(避免被后续构建覆盖或造成源/产物不一致)。

为什么必须改:App 实际运行时可能直接加载 assets 里的 JS 包;只改了 TS 不改 assets,运行仍会调用旧参数。

2.8 必改:文档

  • 常见位置:docs/doc-src/package-dev/*.md、docs/doc-src/**/*.md
  • 要做的事:更新 API 描述、参数说明、示例,以及“关键规则/注意事项”。

为什么必须改:文档是对外说明;很多线上问题其实来自文档与实现不一致——文档写旧参数,用户照抄,自然报错。


3. 强烈建议:全局搜索旧参数名(找遗漏)

当你把某个参数(例如content)改为old/new/type时,建议按需调整关键词执行以下搜索,确认没有遗留在 toolCall、schema、示例、assets 中:

  • 搜工具名:如"apply_file";
  • 搜旧参数名:如"content";
  • 搜新参数名:如"old"/"new"/"type"。

注意:如果你在 Kotlin/TS/JS 三端都封装了同一套工具接口,任何一端遗留都会导致不一致。搜索时应覆盖app/src/main/java/**、examples/**、app/src/main/assets/packages/**三个区域。

从源码结构看,apply_file确实是“一对多”委派的枢纽:create_file、edit_file的 schema 说明里明确写着“delegating to apply_file with type=create / type=replace”(见 SystemToolPrompts.kt 第 152-169 行)。因此改apply_file的参数时,create_file/edit_file的 schema、Tools.Files.apply/create/edit的 wrapper、files.d.ts的类型定义都要联动检查。


4. 编译/运行级别的自检(避免提交后才爆)

4.1 Kotlin 编译自检(推荐)

  • 运行:app:compileDebugKotlin(或等价 Gradle 任务);
  • 目的:捕捉 JsTools.kt、ToolRegistration.kt、Standard*Tools.kt的签名/引用错误。

4.2 示例/脚本侧检查(按需)

  • 如果 examples 有 TypeScript 构建流程:跑一次构建(例如npm run build或仓库内的 build 脚本);
  • 如果 assets 由构建生成:重新打包生成 assets。

5. 常见坑位总结

文档总结的四类高频事故,每一条都能对应到前面某一层:

坑位现象对应层级
只改了执行层没改 promptLLM 仍按旧参数调用2.1 Schema
只改了 prompt 没改 JS wrapper脚本仍按旧参数组装params2.4 JS 封装
只改了 TS,忘了 assets 里的 bundleApp 运行仍加载旧 bundle2.7 打包产物
参数名改动但错误提示没更新用户不知道正确用法,反复试错2.3 执行实现

结合仓库代码可以补充第五个隐蔽坑:只改 LLM 工具名、忘了Tools.*的调用目标名。例如Tools.Files.read调用的是read_file_full而不是read_file,Tools.Files.exists调用的是file_exists——封装名与底层工具名并不总是相同的,搜索时不能只搜工具名。


6. 扩展:当你新增一个工具时(简版)

新增工具时通常需要:

  • SystemToolPrompts.kt:新增ToolPrompt(中英文两份);
  • ToolRegistration.kt:注册执行器;
  • Standard*Tools.kt(必要时配套Debugger/Root/Admin/Accessibility*Tools.kt):实现逻辑;
  • JsTools.kt:暴露给脚本侧(如需要);
  • examples/types/*.d.ts:类型定义(如需要,Tools.System.*记得同步examples/types/system.d.ts);
  • docs/doc-src/:补文档。

这条清单与“改参数”的 7 层一一对应:新增工具 = 在每层各加一个条目,而已有工具改参数 = 在每层同步修改。两者共享同一套一致性心智模型。


结语

Operit 的默认工具体系是典型的多层契约架构:Kotlin 实现负责能力,Schema 负责让 LLM 正确调用,Tools.*封装与.d.ts类型负责让脚本作者安全调用,示例与打包产物负责把改动真正送达运行时。修改任何一个工具的参数/签名,本质上是沿着这 7 层做一次“全链路同步”。以本文的 Checklist 为索引,配合 SystemToolPrompts.kt、ToolRegistration.kt、ToolGetter.kt、JsTools.kt 与 sync_example_packages.py 逐层核对,即可把“改一个参数”这件事从易错的手工活变成可复现的标准流程。

  • AI Agent
  • 人工智能
  • 大模型
  • AI 应用
  • 工具调用
  • 本地部署
  • MCP Clients
  • Agent 记忆

【免费下载链接】Operit

The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent

项目地址:https://gitcode.com/gh_mirrors/op/Operit
点击查看免费下载

相关推荐

上一篇:AssetRipper:3步把Unity游戏资源搬进你的项目
下一篇:魔兽争霸3终极优化指南:WarcraftHelper 2024完全配置教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表