Gemini CLI 非交互模式工具调用问题解析
问题描述
在使用 gemini -p 非交互模式时,遇到以下错误:
Error executing tool write_file: Tool "write_file" not found in registry.
Tools must use the exact names that are registered.
Did you mean one of: "read_file", "write_todos", "glob"?
但是使用 --allowed-tools write_file 后,工具却能正常工作:
bash
# ❌ 不工作
gemini -p "生成一个md文件123写入123"
# ✅ 工作
gemini -p "生成一个md文件123写入123" --allowed-tools write_file
根本原因
工具注册正常
通过检查发现,工具确实已经正确注册:
javascript
// 已注册的工具数量: 12
工具列表:
01. list_directory
02. read_file
03. search_file_content
04. glob
05. replace
06. write_file // ✅ 已注册
07. web_fetch
08. run_shell_command // ✅ 已注册
09. save_memory
10. google_web_search
11. write_todos
12. delegate_to_agent
真正的问题:策略系统限制
文件 : packages/core/src/policy/policies/write.toml
toml
# Priority 10: Write tools default to ASK_USER
[[rule]]
toolName = "run_shell_command"
decision = "ask_user" # ← 默认需要用户确认!
priority = 10
[[rule]]
toolName = "write_file"
decision = "ask_user" # ← 默认需要用户确认!
priority = 10
[[rule]]
toolName = "web_fetch"
decision = "ask_user"
priority = 10
这些危险工具默认被设置为 ask_user(需要用户确认)。
为什么非交互模式会失败
- 策略系统 要求这些工具需要用户确认
- 非交互模式(
-p) 无法请求用户确认 - 工具调用被拒绝,返回 "Tool not found" 错误
- 当使用
--allowed-tools时,命令行参数(优先级 2.3)会覆盖默认策略(优先级 1.010)
优先级系统
根据 write.toml 的注释:
# Priority bands (tiers):
# - Default policies (TOML): 1 + priority/1000 (e.g., priority 100 → 1.100)
# - User policies (TOML): 2 + priority/1000 (e.g., priority 100 → 2.100)
# - Admin policies (TOML): 3 + priority/1000 (e.g., priority 100 → 3.100)
#
# Settings-based and dynamic rules (all in user tier 2.x):
# 2.95: Tools that the user has selected as "Always Allow" in the interactive UI
# 2.9: MCP servers excluded list (security: persistent server blocks)
# 2.4: Command line flag --exclude-tools (explicit temporary blocks)
# 2.3: Command line flag --allowed-tools (explicit temporary allows) ← 这里
# 2.2: MCP servers with trust=true (persistent trusted servers)
# 2.1: MCP servers allowed list (persistent general server allows)
优先级顺序:
ask_user策略(优先级 1.010)--allowed-tools命令行参数(优先级 2.3)
所以 --allowed-tools 会覆盖默认策略!
解决方案
方案 1: 使用 --allowed-tools 参数(推荐用于临时使用)
bash
# 允许特定工具
gemini -p "生成文件" --allowed-tools write_file,run_shell_command
# 允许所有危险工具
gemini -p "执行任务" --allowed-tools write_file,run_shell_command,web_fetch,replace
优点:
- ✅ 临时性,不影响全局配置
- ✅ 灵活,可以按需指定工具
- ✅ 安全,明确知道哪些工具被允许
缺点:
- ⚠️ 每次都需要输入
- ⚠️ 需要记住工具名称
方案 2: 使用 YOLO 模式(推荐用于开发环境)
bash
# -y 参数自动批准所有工具
gemini -y -p "生成文件"
优点:
- ✅ 简单,只需加一个
-y参数 - ✅ 所有工具自动批准
- ✅ 适合开发环境
缺点:
- ⚠️ 会批准所有工具,包括危险操作
- ⚠️ 不适合生产环境
方案 3: 修改策略文件(推荐用于生产环境)
文件 : packages/core/src/policy/policies/write.toml
toml
# 将 ask_user 改为 allow
[[rule]]
toolName = "write_file"
decision = "allow" # ← 从 "ask_user" 改为 "allow"
priority = 10
[[rule]]
toolName = "run_shell_command"
decision = "allow" # ← 从 "ask_user" 改为 "allow"
priority = 10
然后重新构建:
bash
cd gemini-cli
npm run build
npm run build:packages
优点:
- ✅ 永久性修改
- ✅ 适合生产环境
- ✅ 无需每次指定参数
缺点:
- ⚠️ 安全风险:这些工具可以不经确认执行
- ⚠️ 需要重新构建 CLI
- ⚠️ 更新代码后需要重新应用修改
方案 4: 创建用户策略文件(最佳方案)
位置 : ~/.gemini/policies/user-tools.toml(用户主目录)
toml
# 用户自定义工具策略
# Priority 100: High priority user overrides
[[rule]]
toolName = "write_file"
decision = "allow"
priority = 100
[[rule]]
toolName = "run_shell_command"
decision = "allow"
priority = 100
[[rule]]
toolName = "web_fetch"
decision = "allow"
priority = 100
优先级: 2 + 100/1000 = 2.100(高于默认策略的 1.010)
优点:
- ✅ 永久性修改
- ✅ 不影响源代码,更新时不会丢失
- ✅ 可以版本控制
- ✅ 清晰明确
缺点:
- ⚠️ 安全风险:需要谨慎配置
完整示例
交互模式(默认)
bash
# 交互模式下,工具会请求确认
gemini "创建一个 test.txt 文件"
# 输出:
# ⚠️ Tool "write_file" requires confirmation
# Allow this tool call? [y/n]
非交互模式(失败)
bash
# 非交互模式无法请求确认,工具被拒绝
gemini -p "创建一个 test.txt 文件"
# 输出:
# Error executing tool write_file: Tool "write_file" not found in registry.
非交互模式 + allowed-tools(成功)
bash
# 使用 --allowed-tools 覆盖策略
gemini -p "创建一个 test.txt 文件" --allowed-tools write_file
# 输出:
# ✅ 文件创建成功
非交互模式 + YOLO(成功)
bash
# 使用 -y 自动批准所有工具
gemini -y -p "创建一个 test.txt 文件"
# 输出:
# ✅ 文件创建成功
SDK 集成注意事项
SDK 启动 Gemini CLI 时的建议
python
import subprocess
import json
# ❌ 错误:工具会被拒绝
proc = subprocess.Popen(
["gemini", "-p", "创建文件"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# ✅ 方案 1: 使用 --allowed-tools
proc = subprocess.Popen(
["gemini", "-p", "创建文件",
"--allowed-tools", "write_file,run_shell_command,read_file"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# ✅ 方案 2: 使用 YOLO 模式(开发环境)
proc = subprocess.Popen(
["gemini", "-y", "-p", "创建文件"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
推荐配置
python
# SDK 启动参数
SDK_GEMINI_ARGS = [
"gemini",
"-y", # YOLO 模式(开发)或 "--allowed-tools" (生产)
"-p", # 非交互模式
"--input-format", "stream-json", # SDK 模式
"--channel", "SDK"
]
# 或者更安全的配置
SDK_GEMINI_ARGS = [
"gemini",
"--allowed-tools", "write_file,run_shell_command,read_file,search_files",
"-p",
"--input-format", "stream-json",
"--channel", "SDK"
]
技术细节
策略检查流程
工具调用请求
↓
CoreToolScheduler.isAutoApproved()
↓
检查 ApprovalMode
├─ YOLO → 自动批准
└─ DEFAULT → 继续
↓
检查 allowedTools
├─ 匹配 → 自动批准
└─ 不匹配 → 继续
↓
策略系统检查(write.toml)
├─ decision = "allow" → 自动批准
├─ decision = "ask_user" → 请求确认
│ ├─ 交互模式 → 显示确认对话框
│ └─ 非交互模式 → ❌ 拒绝(抛出错误)
└─ decision = "deny" → ❌ 拒绝
优先级计算
typescript
// Default policies (TOML): 1 + priority/1000
priority = 10 → 1.010
// User policies (TOML): 2 + priority/1000
priority = 100 → 2.100
// Command line flags (dynamic): 2.x
--allowed-tools → 2.3
--exclude-tools → 2.4
// 结果:2.3 > 2.100 > 1.010
// 所以 --allowed-tools > 用户策略 > 默认策略
总结
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 非交互模式下工具找不到 | 策略系统要求用户确认,但非交互模式无法确认 | 使用 --allowed-tools 或 -y |
| 交互模式下能正常工作 | 可以请求用户确认 | 无需修改 |
--allowed-tools 能工作 |
命令行参数优先级高于默认策略 | 推荐用于临时使用 |
推荐做法
- 开发环境 :使用
-y参数方便开发 - 生产环境 :使用
--allowed-tools明确指定需要的工具 - 长期使用 :创建用户策略文件
~/.gemini/policies/user-tools.toml
安全建议
- ⚠️ 谨慎使用 YOLO 模式:会批准所有工具,包括危险操作
- ✅ 明确指定工具 :使用
--allowed-tools只允许需要的工具 - ✅ 审查策略文件 :定期检查
write.toml和用户策略配置 - ✅ 版本控制策略:将用户策略文件纳入版本控制
文档版本 : 1.0
最后更新 : 2025-01-02
作者: 基于 Gemini CLI 源码分析和问题排查