Nanobot 从onboard启动命令来看个人助理Agent的实现

背景

在之前的文章中Nanobot 轻量级的个人AI助手,我们提到了两个命令

一个是nanobot onboard,另一个是nanobot gateway,

从整理上来看,该 nanobot用到了Typer,Rich,Questionary,prompt_toolkit这种现代、美观且交互式命令行界面 (CLI) 的强大工具组合。

Typer 用于定义 CLI 结构和参数;Rich 负责文本样式、表格、面板和 Markdown 渲染;Questionary 用于创建交互式问答界面

其中 Rich中的Console,Markdown,Table,Text用来进行渲染,支持颜色、表格、面板、语法高亮和 Markdown ,以更好的进行个性化的展示。

nanobot onboard命令

onboardTyper 子命令,用于 首次或再次初始化 nanobot:处理配置文件路径、创建/更新 config.json、可选交互向导、合并channel插件默认配置、创建工作区并同步模板,最后打印下一步提示。

复制代码
@app.command()
def onboard(
    workspace: str | None = typer.Option(None, "--workspace", "-w", help="Workspace directory"),
    config: str | None = typer.Option(None, "--config", "-c", help="Path to config file"),
    wizard: bool = typer.Option(False, "--wizard", help="Use interactive wizard"),
):
    """Initialize nanobot configuration and workspace."""
    ...
参数 说明
-c / --config 指定配置文件路径;若给出,会调用 set_config_path,后续读写均针对该文件。
-w / --workspace 覆盖配置中的 agents.defaults.workspace(在内存中的 Config 上生效,保存时写入)。
--wizard 启用交互式向导(nanobot.cli.onboard.run_onboard),由向导决定是否保存。
  1. 第一步便是配置文件的路径,如果指定了--config,就从这里进行查找,否则默认为 ~/.nanbot/.config.json
python 复制代码
if config:
        config_path = Path(config).expanduser().resolve()
        set_config_path(config_path)
        console.print(f"[dim]Using config: {config_path}[/dim]")
else:
    config_path = get_config_path()
  1. 创建或者更新config.json文件
  • 配置文件已存在

    • 如果是wizard: 只 load_config + 工作区覆盖,不在这里做覆盖/刷新的交互;后面交给向导统一保存。
    • 非 wizard:
      提示:已存在,用typer.confirm("Overwrite?")问是否 Overwrite。
      确认覆盖:Config() 全新默认 + 工作区覆盖 → save_config,相当于重置为默认。
      不覆盖:load_config + 工作区覆盖 → save_config,保留已有字段值,同时用 save_config 把结构写回到config路径下。
  • 配置文件不存在

    Config() 默认 + 工作区覆盖。

    非 wizard:立刻 save_config

    wizard:先不保存,等向导结束再决定是否写盘。

    注意这里json配置转换为python Config配置用到了 pydantic 的 BaseSettings Field(default_factory=...) 以及 model_validate用于将数据(如字典)转换并验证为模型实例的方法。

python 复制代码
if config_path.exists():
        if wizard:
            config = _apply_workspace_override(load_config(config_path))
        else:
            console.print(f"[yellow]Config already exists at {config_path}[/yellow]")
            console.print("  [bold]y[/bold] = overwrite with defaults (existing values will be lost)")
            console.print("  [bold]N[/bold] = refresh config, keeping existing values and adding new fields")
            if typer.confirm("Overwrite?"):
                config = _apply_workspace_override(Config())
                save_config(config, config_path)
                console.print(f"[green]✓[/green] Config reset to defaults at {config_path}")
            else:
                config = _apply_workspace_override(load_config(config_path))
                save_config(config, config_path)
                console.print(f"[green]✓[/green] Config refreshed at {config_path} (existing values preserved)")
    else:
        config = _apply_workspace_override(Config())
        # In wizard mode, don't save yet - the wizard will handle saving if should_save=True
        if not wizard:
            save_config(config, config_path)
            console.print(f"[green]✓[/green] Created config at {config_path}")
  1. 进行向导式的配置
    如果配置了进行了向导式的操作,则利用 questionary包 进行引导式的操作,并且借助于prompt_toolkit 这个强大、交互式命令行界面(CLI)的纯 Python 库,
    具体见 onboard.py中的_select_with_back方法,使用KeyBindings捕获键盘的操作,用来锁定选择的配置,之后在利用python的 getattrsetattr以及_configure_pydantic_model方法 进行对应的配置
    并且会根据返回的值,判断是否进行持久化配置操作。
python 复制代码
 try:
          answer = _get_questionary().select(
              "What would you like to configure?",
              choices=[
                  "[P] LLM Provider",
                  "[C] Chat Channel",
                  "[A] Agent Settings",
                  "[G] Gateway",
                  "[T] Tools",
                  "[V] View Configuration Summary",
                  "[S] Save and Exit",
                  "[X] Exit Without Saving",
              ],
              qmark=">",
          ).ask()
      except KeyboardInterrupt:
          answer = None

      if answer is None:
          action = _prompt_main_menu_exit(_has_unsaved_changes(original_config, config))
          if action == "save":
              return OnboardResult(config=config, should_save=True)
          if action == "discard":
              return OnboardResult(config=original_config, should_save=False)
          continue

      _MENU_DISPATCH = {
          "[P] LLM Provider": lambda: _configure_providers(config),
          "[C] Chat Channel": lambda: _configure_channels(config),
          "[A] Agent Settings": lambda: _configure_general_settings(config, "Agent Settings"),
          "[G] Gateway": lambda: _configure_general_settings(config, "Gateway"),
          "[T] Tools": lambda: _configure_general_settings(config, "Tools"),
          "[V] View Configuration Summary": lambda: _show_summary(config),
      }
  1. 同步配置channel
    对于已经配置好,或者没有配置的channel,都会写入到config.json文件中,
    没有配置的会写入默认值,配置的则覆盖默认值。

  2. 同步工作区配置
    把templates目录下的 AGENTS.md,HEARTBEAT.md,SOUL.md,TOOLS.md,USER.md等文件拷贝到工作目录下.
    形成如下的目录结构:

    shell 复制代码
     ├── AGENTS.md
     ├── HEARTBEAT.md
     ├── memory
     │   ├── HISTORY.md
     │   └── MEMORY.md
     ├── skills
     ├── SOUL.md
     ├── TOOLS.md
     └── USER.md
相关推荐
拓朗工控2 小时前
视觉检测行业工控机选型指南:核心要素与避坑策略
人工智能·数码相机·视觉检测·工控机·工业电脑
Urbano2 小时前
工装制作全流程科普:从面料到自动化生产
网络·人工智能
武子康2 小时前
调查研究-166 VoxCPM 详解:一个值得重点关注的开源 TTS 项目
人工智能·openai
hhzz2 小时前
详细解读Anthropic报告《当AI构建自己时...》
人工智能
xrgs_shz3 小时前
基于K-Means聚类分析的鸢尾花分类
人工智能·机器学习
Chef_Chen3 小时前
论文解读:GAIA给通用AI助手泼冷水,人类92分GPT-4插件版只到30分
人工智能
Black蜡笔小新3 小时前
自动化AI算法训练服务器DLTM训推一体工作站赋能多行业智能化升级
人工智能·算法·自动化
KaMeidebaby3 小时前
卡梅德生物技术快报|噬菌体文库构建实验优化及偶联体系实验数据分析
大数据·人工智能·架构·spark·新浪微博
NineData3 小时前
SQL 都在等锁时,ChatDBA 先帮 MySQL 找到谁在挡路
数据库·人工智能·sql·mysql·安全·数据复制·数据迁移工具
意图共鸣3 小时前
意图共鸣科技《AI记忆链商业化白皮书3.0》技术解读:“AI焦虑的解药”——从通用AI到个人记忆链架构
人工智能·科技·架构