- AI Agent
- 人工智能
- 大模型
- AI 应用
- 工具调用
- 本地部署
- MCP Clients
- Agent 记忆
【免费下载链接】Operit
The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent
导读
本文围绕 Operit 仓库中 docs/doc-src/architecture/DEFAULT_TOOLS_ARCH.md 展开,系统讲解 Android AI Agent 中“默认工具(default tools)”的完整链路:从 LLM 看到的 Prompt/Schema,到 Kotlin 执行实现、JS/TS 脚本封装、示例与打包产物。读完本文,你将掌握修改任意工具参数/签名时必须同步修改的全部文件清单、全局搜索防遗漏方法、编译级自检命令,以及新增一个工具时的一站式落地方案,并能在源码层面理解每一层的真实实现。
1. 默认工具的组成:一条从上到下的数据流
在 Operit 中,“默认工具”不是单个文件,而是一条贯穿“对外契约”与“内部实现”的数据流。文档将其归纳为 7 层:
- 工具 Prompt / Schema——工具对 LLM 的“说明书”,决定模型如何生成 tool call;
- 工具注册——把
toolName -> executor绑定起来; - 工具执行实现——Kotlin 侧真正做事的逻辑;
- 脚本侧封装(JS Tools)——给 JS/TS 脚本更好用的 API;
- 示例与类型定义——
examples/types与examples/**; - 文档——
docs/doc-src/package-dev等; - 打包资源 / 产物——
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/,避免源/产物不一致。
因此,修改脚本包功能的推荐流程是:
- 优先改
examples/<package>.ts; - 通过构建/编译生成对应的
examples/<package>.js; - 运行
python tools/example_packages/sync_example_packages.py同步到assets/packages/; - 不建议直接手动修改
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. 常见坑位总结
文档总结的四类高频事故,每一条都能对应到前面某一层:
| 坑位 | 现象 | 对应层级 |
|---|---|---|
| 只改了执行层没改 prompt | LLM 仍按旧参数调用 | 2.1 Schema |
| 只改了 prompt 没改 JS wrapper | 脚本仍按旧参数组装params | 2.4 JS 封装 |
| 只改了 TS,忘了 assets 里的 bundle | App 运行仍加载旧 bundle | 2.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
相关推荐
gRPC 默认 HTTP 代理映射器(Default HTTP Proxy Mapper)完全指南:环境变量、Channel 参数与源码级实现剖析
gRPC 默认 HTTP 代理映射器(Default HTTP Proxy Mapper)完全指南:环境变量、Channel 参数与源码级实现剖析 本指南聚焦
后端RPC框架微服务通信Hugo 默认版本(default version)完全指南:从 `defaultContentVersion` 到源码级解析
Hugo 默认版本(default version)完全指南:从 defaultContentVersion 到源码级解析 导读 :Hugo 0.153.0 起
开发工具前端CLISphinx 2.0 升级指南:HTML5 默认输出、master_doc 变更与弃用 API 全景解析
Sphinx 2.0 升级指南:HTML5 默认输出、master_doc 变更与弃用 API 全景解析 Sphinx 2.0 是 Sphinx 文档生成器(本
文档开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考