ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Tolaria 排查指南:为什么 AI Agent “找不到“ —— 本地 CLI 代理的发现机制与 PATH 故障诊断

Tolaria 排查指南:为什么 AI Agent “找不到“ —— 本地 CLI 代理的发现机制与 PATH 故障诊断 Tolaria 排查指南:为什么 AI Agent 找不到 —— 本地 CLI 代理的发现机制与 PATH 故障诊断【免费下载链接】tolariaDesktop app to manage markdown knowledge bases项目地址: https://gitcode.com/GitHub_Trending/to/tolaria当 Tolaria 的 AI 面板提示没有可用的受支持 Agent时,问题往往不在应用本身,而在于本地 CLI 代理的安装方式与应用进程实际看到的PATH不一致。本文以仓库中的故障排查文档 ai-agent-not-found.md 为主线,结合src-tauri中代理检测的真实实现,讲清楚:Tolaria 是如何发现本地 Agent CLI 的、一个终端里能跑、应用里找不到的根因是什么,以及按什么顺序排查和修复。一、症状识别:哪些现象属于 AI Agent Not Found原始排查文档给出了两个典型症状:AI 面板提示没有任何受支持的 Agent 可用;Claude Code 或其他 Agent 在某个终端里正常工作,但在 Tolaria 中却不可用。第二条是最有迷惑性的:命令在交互 shell 里能执行,不代表桌面应用也能找到它。原因在于 Tolaria 的 AI 能力只依赖本地安装的 CLI 代理——它通过启动本机 CLI 子进程来驱动对话与 Agent 任务(参见 ADR cli-agent-only-no-api-key),因此只要 CLI 装不上或不可被发现,整个 AI 面板就进入缺失状态。受支持的 Agent 与状态模型当前版本中,Tolaria 支持 8 个本地 CLI Agent。前端在 aiAgents.ts 中维护了完整的定义表(AI_AGENT_DEFINITIONS),每个 Agent 都有id、展示名与安装地址:Agent ID展示名claude_codeClaude CodecodexCodexcopilotGitHub CopilotopencodeOpenCodepiPiantigravityAntigravity CLIkiroKirohermesHermes Agent每个 Agent 的状态被建模为三种:checking(检测中)、installed(已安装,附版本号)、missing(缺失),见 aiAgents.ts 中的AiAgentStatus类型。当hasAnyInstalledAiAgent()判断所有 Agent 均为missing时,首次启动的引导界面 AiAgentsOnboardingPrompt.tsx 会展示缺失状态面板,并提供各 Agent 的官方安装入口——这就是AI 面板说没有可用 Agent这一症状在 UI 层的直接来源。对应地,后端在 ai_agents.rs 的get_ai_agents_status()中并行探测全部 8 个 Agent,返回一个字段齐全的状态结构;前端据此渲染检测中 / 已安装 / 缺失三种文案。二、第一手检查:在终端直接运行 Agent 命令排查文档给出的第一步检查是打开终端,直接运行 Agent 命令,以 Claude Code 为例:claude --version如果这条命令失败,说明问题出在 Agent 本身——需要先安装或修复该 CLI,而不是继续在 Tolaria 里找配置项。这一步之所以有效,是因为 Tolaria 内部对已安装的判定与它完全同构:后端探测到二进制后,会执行binary --version来取版本号。该逻辑位于 cli_agent_runtime.rs 的version_for_binary():pub(crate) fn version_for_binary(binary: Path) - OptionString { let target command_target_avoiding_windows_cmd_shim(binary).ok()?; let mut command crate::hidden_command(target.program); configure_agent_command_environment(mut command, binary); command.args(target.prefix_args); command .arg(--version) .output() .ok() .filter(|output| output.status.success()) .map(|output| String::from_utf8_lossy(output.stdout).trim().to_string()) }即能被发现且--version能成功执行才会标记为installed: true并带回版本号。你在终端里看到的claude --version输出,正是 Tolaria 界面上已安装 v1.x.x这行数据的来源。因此:终端里都跑不起来的 CLI,在应用里一定显示为缺失;终端里能跑起来的,才进入下文的 PATH 排查环节。三、检测流程详解:Tolaria 如何发现一个 CLI在终端能用、在 Tolaria 里找不到的排查核心,是理解应用侧的探测链路。以 Claude Code 为例,入口是 claude_cli.rs 的find_claude_binary(),它按优先级尝试三级回退:pub(crate) fn find_claude_binary() - ResultPathBuf, String { if let Some(binary) find_claude_binary_on_path() { return Ok(binary); } if let Some(binary) find_claude_binary_in_user_shell() { return Ok(binary); } if let Some(binary) crate::cli_agent_runtime::find_executable_binary_candidate( claude_binary_candidates(), Claude CLI, )? { return Ok(binary); } Err(Claude CLI not found. Install it: ....into()) }第 1 级:在应用进程的 PATH 中查找find_claude_binary_on_path()使用平台的标准定位命令:Unix 下是which claude,Windows 下是where claude(claude_cli.rs)。注意:这里的 PATH 是应用进程的 PATH,不是你交互 shell 的 PATH——这正是下一节要展开的根源。第 2 级:在登录 shell 中查找如果 PATH 里找不到,应用会退而求其次,模拟一次登录 shell 查询(claude_cli.rs):fn claude_path_from_shell(shell: Path) - OptionPathBuf { crate::hidden_command(shell) .arg(-lc) .arg(command -v claude) .output() .ok() .and_then(|output| path_from_successful_output(output)) }候选 shell 依次为环境变量SHELL指向的 shell、/bin/zsh、/bin/bash。-lc会执行完整的登录 shell 初始化(读取~/.zshrc、~/.bash_profile等),因此写在 shell 配置文件里的 PATH 扩展在这一级能被看到。这个回退也是有成本的——shell 启动文件的完整求值可能耗时约 1 秒,这也是为什么后端会把 8 个 Agent 的探测并行化(见第五节)。第 3 级:常见安装位置扫描最后一级是直接扫描一份硬编码的候选路径清单。Claude Code 的候选路径定义在 claude_cli.rs 的claude_binary_candidates_for_home():候选位置对应安装方式~/.local/bin/claude官方原生安装~/.claude/local/claudeClaude Code 本地目录安装~/.local/share/mise/shims/claudemise 版本管理器 shim~/.asdf/shims/claudeasdf 版本管理器 shim~/.npm-global/bin/claude、~/.npm/bin/claude全局 npm 安装~/AppData/Roaming/npm/claude.cmd、~/AppData/Local/pnpm/claude.cmdWindows npm/pnpm~/scoop/shims/claude.exeWindows scoop~/.linuxbrew/bin/claude、/home/linuxbrew/.linuxbrew/bin/claudeLinuxbrew/opt/homebrew/bin/claudeApple Silicon Homebrew/usr/local/bin/claudeIntel Mac Homebrew / 手动安装~/.nvm/versions/node/*/bin/claudenvm 管理的多版本 Node(目录会动态枚举)其中 nvm 路径不是写死的:实现会枚举~/.nvm/versions/node/下的每个版本目录,拼出bin/claude并排序后参与匹配(claude_cli.rs)。对应的单元测试claude_binary_candidates_include_nvm_managed_node_installs验证了 nvm 安装的 CLI 确实会被候选清单覆盖。候选文件存在但不可执行:一个明确的报错第三级扫描有一个容易被忽略的细节,在 cli_agent_runtime.rs 的find_executable_binary_candidate()中:如果某个候选路径文件存在但没有可执行权限,探测不会静默跳过,而是直接返回带路径的错误信息:Claude CLI binary found at/xxx/claudebut it is not executable. Fix the file permissions or reinstall the CLI.可执行性判定在 Unix 下检查权限位0o111,在 Windows 下检查扩展名是否为 CLI 合法形式(cli_agent_runtime.rs)。所以如果你在自定义安装目录里手动解压过 CLI、或用git clone拿到脚本但忘了加执行权限,会落在这一分支——修复方式是补权限或重装,而不是改 PATH。四、PATH 继承差异:终端能用、应用找不到的根本原因排查文档对 Path Issues 的定性是:桌面应用继承到的PATH可能与你的交互式 shell 不同。这在 macOS(Launchpad/双击启动的 App 不读取~/.zshrc)和从系统托盘启动的进程中尤为典型。Tolaria 的应对策略分两层:第一层是探测期的回退(第三节的登录 shell 查询与常见位置扫描),尽量兜住非标准安装。第二层是运行期的 PATH 扩展。即便二进制已经定位,应用启动 CLI 子进程时仍会主动扩充子进程可见的PATH。cli_agent_runtime.rs 中的configure_agent_command_environment()把已定位二进制的所在目录,以及一批通用工具目录(~/.local/bin、~/.local/share/mise/shims、~/.asdf/shims、~/.npm-global/bin、~/.npm/bin、~/.bun/bin、~/.linuxbrew/bin、npm/pnpm/scoop 的 Windows 目录、/opt/homebrew/bin、/usr/local/bin等)合并进PATH后注入子进程。这样即使主进程 PATH 缺失,Agent 运行期依赖的同目录脚本、node 可执行文件等也能被找到。从源码结构看,这套机制说明文档中Tolaria 会检查常见安装位置,但 shell 配置仍有差异这句话是准确的:应用覆盖的是高频标准位置,而不是复刻你 shell 初始化脚本里的全部自定义逻辑。Windows 上的两个特判Windows 的检测结果还有两个针对性修正,均有测试覆盖:优先选择claude.cmdshim 而非无扩展名的 npm 脚本:first_existing_path_for_platform()在 Windows 分支只接受带 CLI 扩展名的候选,测试windows_path_lookup_prefers_cmd_shim_over_extensionless_npm_script验证了这一行为(claude_cli.rs);跳过 Claude Desktop 的执行别名:is_windows_claude_desktop_execution_alias()会排除Microsoft\WindowsApps\Claude.exe这类商店应用别名,避免把桌面应用的入口误当成 CLI,测试windows_path_lookup_skips_claude_desktop_execution_alias覆盖了该场景(claude_cli.rs)。如果你同时安装了 Claude Desktop 和 Claude Code CLI,这条修正保证了 Tolaria 定位到的是 CLI 而不是桌面客户端。五、探测的超时与并行:为什么缺失判定有时需要等待8 个 Agent 的状态不是逐条阻塞返回的。ai_agents.rs 的get_ai_agents_status()注释明确说明了设计动机:每个 Agent 的check_cli()在二进制缺失、回退到登录 shell 查询时可能阻塞约 1 秒,串行探测在一个 Agent 都没装的冷启动时会累计约 5 秒,因此全部探测被派发到 Tokio 阻塞线程池并行执行,用户感知到的等待时间约等于最慢的单个探测。同时每个探测都有硬超时AI_AGENT_STATUS_PROBE_TIMEOUT 5 秒(ai_agents.rs):超时、或探测线程 panic,都会被availability_or_missing()归一化为installed: false, version: None,保证 IPC 永远返回一个字段齐全的状态结构,前端不会卡在检测中。测试availability_probe_timeout_returns_missing_status验证了超时即判缺失的行为。这带来一个排查提示:检测中状态短暂存在是正常现象;如果某个 Agent 长期停留在缺失,而它其实刚装好,重启应用让它重新执行一轮探测即可。六、推荐的修复方式综合排查文档与源码实现,按以下顺序处理最有效:终端直接验证:执行agent --version(如claude --version)。失败则先安装或修复 Agent 本身,各 Agent 的安装入口在 Tolaria 引导界面中均有对应链接,定义于 aiAgents.ts。确认安装位置是否标准:优先把 CLI 安装到~/.local/bin、Homebrew/Linuxbrew 路径、/usr/local/bin等 Tolaria 会扫描的标准位置;npm 全局安装请确保全局前缀目录落在~/.npm-global/bin、~/.npm/bin或系统 PATH 内;用 nvm/mise/asdf 管理的安装已被候选清单覆盖,但请确认 shim 或版本目录下的可执行文件权限正常。让登录 shell 可发现:将 CLI 所在目录写入登录 shell 会加载的配置(zsh 的~/.zprofile、bash 的~/.bash_profile),使command -v agent在登录模式下可用——这正是 Tolaria 第二级回退查询的内容。处理权限问题:若应用报错提示 binary found at ... but it is not executable,给该文件补可执行权限或重装。Windows 用户:确认where claude能输出带.cmd/.exe扩展名的 CLI 路径,且该路径不属于Microsoft\WindowsApps下的桌面应用别名。重开后仍缺失:重启 Tolaria 触发一轮新的并行探测(每 Agent 5 秒超时上限);必要时用终端能跑、应用不行的场景对照,检查是否 PATH 继承差异——文档给出的结论依然成立:优先把 CLI 装在标准位置,或保证它在登录 shell 中可用,这两点分别命中了 Tolaria 第 1/3 级与第 2 级探测。七、延伸阅读故障排查文档(仓库内):agent-docs 版本、站点文档版本Claude Code 探测实现:claude_cli.rs共享运行时(版本探测、PATH 扩展、可执行性校验):cli_agent_runtime.rs8 个 Agent 的并行状态探测:ai_agents.rs前端状态模型与缺失态引导界面:aiAgents.ts、AiAgentsOnboardingPrompt.tsx架构决策:只使用本地 CLI 代理、不内置 API Key【免费下载链接】tolariaDesktop app to manage markdown knowledge bases项目地址: https://gitcode.com/GitHub_Trending/to/tolaria创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进