317 lines
11 KiB
Markdown
317 lines
11 KiB
Markdown
---
|
||
status: active
|
||
date: 2026-06-05
|
||
---
|
||
|
||
# feat: AgentKit CLI + 独立部署能力
|
||
|
||
**类型**: feat
|
||
**文件**: `docs/plans/2026-06-05-007-feat-agentkit-cli-deployment-plan.md`
|
||
**深度**: Standard — 新增 CLI 模块 + 部署配置改造,涉及 6 个新文件 + 4 个修改
|
||
|
||
---
|
||
|
||
## 问题框架
|
||
|
||
AgentKit v2 Phase 1 + Phase 2 已实现 12 个核心模块、544 个测试通过,但**无法独立部署和使用**:
|
||
|
||
1. **无 CLI** — 没有 `agentkit` 命令行工具,只能写 Python 脚本或手动敲 uvicorn 命令
|
||
2. **无 `__main__.py`** — 不能 `python -m agentkit` 启动
|
||
3. **无 `init` 脚手架** — 新用户不知道如何初始化配置
|
||
4. **Dockerfile 硬编码 GEO** — `CMD` 直接调用 `configs.geo_server`,不是通用入口
|
||
5. **无生产级 docker-compose** — 只有 `docker-compose.test.yml`(测试用),缺少生产部署配置
|
||
|
||
---
|
||
|
||
## 架构总览
|
||
|
||
```
|
||
agentkit CLI (Typer)
|
||
├── agentkit init → 生成 agentkit.yaml + .env.example + skills/ + docker-compose.yaml
|
||
├── agentkit serve → uvicorn agentkit.server.app:create_app --factory
|
||
├── agentkit task submit → AgentKitClient.submit_task()
|
||
├── agentkit task status → AgentKitClient.get_task_status()
|
||
├── agentkit task list → AgentKitClient.list_tasks()
|
||
├── agentkit task cancel → AgentKitClient.cancel_task()
|
||
├── agentkit skill list → SkillRegistry.list_skills() (本地) 或 API (远程)
|
||
├── agentkit skill load → SkillLoader.load_from_file() (本地)
|
||
├── agentkit skill info → Skill 详情
|
||
├── agentkit usage → LLMGateway.get_usage_summary()
|
||
├── agentkit health → /api/v1/health
|
||
└── agentkit version → importlib.metadata.version()
|
||
```
|
||
|
||
**核心设计决策**:CLI 是**薄封装层**,底层复用已有的 `AgentKitClient`(远程模式)和 `create_app()` + 各 Registry(本地模式)。
|
||
|
||
---
|
||
|
||
## 关键技术决策
|
||
|
||
### KTD-1: CLI 框架选择 Typer
|
||
|
||
**决策**: 使用 Typer(而非 Click 或 argparse)
|
||
|
||
**理由**:
|
||
- 与 FastAPI 同作者,类型注解驱动,团队学习成本最低
|
||
- 底层基于 Click,可无缝使用 Click 生态
|
||
- Rich 集成提供开箱即用的彩色输出、表格、进度条
|
||
- 自动生成帮助文档和 shell 补全
|
||
- 项目已使用 Pydantic v2 + 类型注解,Typer 风格完美契合
|
||
|
||
### KTD-2: 双模式运行(本地 vs 远程)
|
||
|
||
**决策**: CLI 支持两种运行模式
|
||
|
||
- **本地模式**(默认): 直接 import 模块执行,无需 Server 运行
|
||
- **远程模式**(`--server-url`): 通过 HTTP API 调用 AgentKit Server
|
||
|
||
**理由**: 开发调试时直接本地运行更方便;生产环境通过 Server 远程调用更安全。`agentkit task submit` 在本地模式下直接创建 Agent 执行,在远程模式下调用 API。
|
||
|
||
### KTD-3: 配置文件格式 agentkit.yaml
|
||
|
||
**决策**: 使用 YAML 格式,支持 `${ENV_VAR}` 环境变量替换
|
||
|
||
**理由**: 与现有 `configs/llm_config.yaml` 格式一致,复用 `_substitute_env_vars()` 逻辑。YAML 比 TOML 更适合嵌套配置,比 JSON 支持注释。
|
||
|
||
### KTD-4: Dockerfile 入口改为 CLI
|
||
|
||
**决策**: Dockerfile `ENTRYPOINT` 改为 `agentkit` CLI,`CMD` 默认 `serve`
|
||
|
||
**理由**: 统一入口,支持 `docker run agentkit task submit ...` 等一次性命令,比硬编码 uvicorn 更灵活。
|
||
|
||
---
|
||
|
||
## 实施单元
|
||
|
||
### U1. CLI 框架搭建 + `serve` + `version` + `health`
|
||
|
||
**Goal**: 建立 CLI 模块骨架,实现最基础的 3 个命令
|
||
|
||
**Dependencies**: 无
|
||
|
||
**Files**:
|
||
- `src/agentkit/cli/__init__.py` (新建)
|
||
- `src/agentkit/cli/main.py` (新建) — Typer app + serve/version/health 命令
|
||
- `src/agentkit/__main__.py` (新建) — `python -m agentkit` 入口
|
||
- `pyproject.toml` (修改) — 添加 `typer>=0.12` 依赖 + `[project.scripts]` 入口点
|
||
- `Dockerfile` (修改) — ENTRYPOINT 改为 `agentkit`
|
||
|
||
**Approach**:
|
||
- `main.py` 创建 `app = typer.Typer()` 并注册子命令
|
||
- `serve` 命令调用 `uvicorn.run()` 启动 `create_app()` 工厂函数
|
||
- `version` 命令使用 `importlib.metadata.version("fischer-agentkit")`
|
||
- `health` 命令调用 `http://localhost:{port}/api/v1/health`
|
||
- `__main__.py` 简单调用 `app()`
|
||
- pyproject.toml 添加 `[project.scripts] agentkit = "agentkit.cli.main:app"`
|
||
|
||
**Test scenarios**:
|
||
- `agentkit version` 输出正确版本号
|
||
- `agentkit serve --help` 显示帮助信息
|
||
- `agentkit health` 在 server 未运行时返回连接错误
|
||
- `agentkit health` 在 server 运行时返回健康状态
|
||
- `python -m agentkit version` 等同于 `agentkit version`
|
||
- Dockerfile ENTRYPOINT 正确执行 `agentkit serve`
|
||
|
||
**Verification**: `pip install -e . && agentkit version` 输出版本号
|
||
|
||
---
|
||
|
||
### U2. `task` 命令组(submit/status/list/cancel)
|
||
|
||
**Goal**: 实现任务管理的 CLI 命令
|
||
|
||
**Dependencies**: U1
|
||
|
||
**Files**:
|
||
- `src/agentkit/cli/task.py` (新建) — task 子命令组
|
||
- `src/agentkit/cli/main.py` (修改) — 注册 task 子命令
|
||
|
||
**Approach**:
|
||
- `task submit`:
|
||
- 本地模式: 创建 Agent → 执行任务 → 输出结果
|
||
- 远程模式: `AgentKitClient.submit_task()` / `submit_task_async()`
|
||
- `--mode sync|async` 控制同步/异步
|
||
- `--stream` 启用 SSE 流式输出
|
||
- `task status <task_id>`: 调用 `AgentKitClient.get_task_status()`
|
||
- `task list`: 调用 `AgentKitClient.list_tasks()`,Rich 表格输出
|
||
- `task cancel <task_id>`: 调用 `AgentKitClient.cancel_task()`
|
||
- 输入数据通过 `--input` 参数(JSON 字符串)或 `--input-file` 参数(JSON 文件路径)
|
||
|
||
**Test scenarios**:
|
||
- `agentkit task submit --skill content_generator --input '{"topic":"AI"}'` 提交同步任务
|
||
- `agentkit task submit --mode async --skill content_generator --input '{"topic":"AI"}'` 返回 task_id
|
||
- `agentkit task status <task_id>` 显示任务状态
|
||
- `agentkit task list` 列出所有任务
|
||
- `agentkit task list --status completed` 过滤已完成任务
|
||
- `agentkit task cancel <task_id>` 取消运行中任务
|
||
- `agentkit task submit --input-file input.json` 从文件读取输入
|
||
- 远程模式下所有命令正确调用 API
|
||
- 本地模式下直接执行无需 Server
|
||
|
||
**Verification**: `agentkit task submit --help` 显示完整帮助
|
||
|
||
---
|
||
|
||
### U3. `skill` 命令组(list/load/info)
|
||
|
||
**Goal**: 实现技能管理的 CLI 命令
|
||
|
||
**Dependencies**: U1
|
||
|
||
**Files**:
|
||
- `src/agentkit/cli/skill.py` (新建) — skill 子命令组
|
||
- `src/agentkit/cli/main.py` (修改) — 注册 skill 子命令
|
||
|
||
**Approach**:
|
||
- `skill list`: 列出已注册技能,Rich 表格输出(name, mode, description)
|
||
- `skill load <path>`: 从 YAML 文件加载技能到 Registry
|
||
- `skill info <name>`: 显示技能详情(config 完整信息)
|
||
- 本地模式直接操作 SkillRegistry,远程模式调用 `/api/v1/skills` API
|
||
|
||
**Test scenarios**:
|
||
- `agentkit skill list` 列出所有技能
|
||
- `agentkit skill load ./my_skill.yaml` 加载技能
|
||
- `agentkit skill info content_generator` 显示技能详情
|
||
- 无技能注册时 `skill list` 显示空列表
|
||
- 加载无效 YAML 文件报错
|
||
|
||
**Verification**: `agentkit skill list` 输出技能表格
|
||
|
||
---
|
||
|
||
### U4. `init` 命令 + `usage` 命令
|
||
|
||
**Goal**: 实现项目初始化和用量查询
|
||
|
||
**Dependencies**: U1
|
||
|
||
**Files**:
|
||
- `src/agentkit/cli/init.py` (新建) — init 命令
|
||
- `src/agentkit/cli/usage.py` (新建) — usage 命令
|
||
- `src/agentkit/cli/main.py` (修改) — 注册 init/usage 子命令
|
||
- `src/agentkit/cli/templates.py` (新建) — 模板文件内容(agentkit.yaml、.env.example、docker-compose.yaml、示例 skill)
|
||
|
||
**Approach**:
|
||
- `init` 命令:
|
||
- 交互式引导(使用 Typer `prompt`)或 `--non-interactive` 使用默认值
|
||
- 生成文件: `agentkit.yaml`, `.env.example`, `skills/example_skill.yaml`, `docker-compose.yaml`
|
||
- `agentkit.yaml` 包含 server/llm/memory/skills/logging 配置
|
||
- `.env.example` 包含 API key 占位符
|
||
- `docker-compose.yaml` 包含 agentkit + redis + postgres 服务
|
||
- 如果文件已存在,询问是否覆盖
|
||
- `usage` 命令:
|
||
- 本地模式: 从 LLMGateway.UsageTracker 获取统计
|
||
- 远程模式: 调用 `/api/v1/llm/usage` API
|
||
- `--agent` 过滤特定 Agent
|
||
- `--format table|json` 输出格式
|
||
|
||
**Test scenarios**:
|
||
- `agentkit init` 在空目录生成完整配置文件
|
||
- `agentkit init --non-interactive` 使用默认值生成
|
||
- `agentkit init` 文件已存在时提示覆盖
|
||
- 生成的 `agentkit.yaml` 包含所有必要配置段
|
||
- 生成的 `.env.example` 包含 API key 占位符
|
||
- 生成的 `docker-compose.yaml` 包含 3 个服务
|
||
- `agentkit usage` 显示用量统计表格
|
||
- `agentkit usage --agent content_generator` 过滤特定 Agent
|
||
- `agentkit usage --format json` 输出 JSON 格式
|
||
|
||
**Verification**: `mkdir /tmp/test-init && cd /tmp/test-init && agentkit init && ls -la` 看到生成的文件
|
||
|
||
---
|
||
|
||
### U5. Dockerfile 改造 + 生产级 docker-compose
|
||
|
||
**Goal**: 改造部署配置,支持 CLI 入口 + 生产部署
|
||
|
||
**Dependencies**: U1
|
||
|
||
**Files**:
|
||
- `Dockerfile` (修改) — ENTRYPOINT 改为 `agentkit`
|
||
- `docker-compose.yaml` (新建) — 生产部署配置
|
||
- `.dockerignore` (修改/新建) — 排除 tests/docs
|
||
|
||
**Approach**:
|
||
- Dockerfile:
|
||
- `ENTRYPOINT ["agentkit"]`
|
||
- `CMD ["serve", "--host", "0.0.0.0", "--port", "8001"]`
|
||
- 复制 `configs/` 目录到镜像
|
||
- 保持多阶段构建 + 非 root 用户
|
||
- docker-compose.yaml:
|
||
- `agentkit` 服务: build ., command: serve, ports: 8001, env_file: .env
|
||
- `redis` 服务: redis:7-alpine, healthcheck
|
||
- `postgres` 服务: pgvector/pgvector:pg15, healthcheck, volume
|
||
- `agentkit` depends_on redis + postgres (condition: service_healthy)
|
||
- `.dockerignore`: 排除 tests/, docs/, .git/, __pycache__/
|
||
|
||
**Test scenarios**:
|
||
- `docker build -t agentkit .` 构建成功
|
||
- `docker run agentkit version` 输出版本号
|
||
- `docker run agentkit serve` 启动 Server
|
||
- `docker-compose up` 启动完整环境
|
||
- `docker-compose exec agentkit agentkit health` 健康检查通过
|
||
|
||
**Verification**: `docker build -t agentkit . && docker run agentkit version`
|
||
|
||
---
|
||
|
||
### U6. README 更新 + 集成测试
|
||
|
||
**Goal**: 更新文档,添加 CLI 使用示例,编写集成测试
|
||
|
||
**Dependencies**: U1-U5
|
||
|
||
**Files**:
|
||
- `README.md` (修改) — 添加 CLI 使用章节
|
||
- `tests/unit/test_cli.py` (新建) — CLI 命令测试
|
||
|
||
**Approach**:
|
||
- README 添加:
|
||
- CLI 安装和快速开始
|
||
- 所有命令的使用示例
|
||
- Docker 部署说明
|
||
- `agentkit init` 生成的文件结构说明
|
||
- 测试:
|
||
- 使用 `typer.testing.CliRunner` 测试所有命令
|
||
- Mock 远程 API 调用
|
||
- 测试 init 生成的文件内容
|
||
|
||
**Test scenarios**:
|
||
- `agentkit --help` 显示所有子命令
|
||
- `agentkit task --help` 显示 task 子命令
|
||
- `agentkit init --non-interactive` 生成正确文件
|
||
- `agentkit skill list` 在无技能时显示空列表
|
||
- `agentkit version` 输出格式正确
|
||
- `agentkit usage` 在无用量时显示空表格
|
||
|
||
**Verification**: `pytest tests/unit/test_cli.py -v` 全部通过
|
||
|
||
---
|
||
|
||
## 范围边界
|
||
|
||
### 包含
|
||
- CLI 模块(Typer 框架)
|
||
- `__main__.py` 入口
|
||
- `init` 脚手架生成
|
||
- Dockerfile 改造
|
||
- 生产级 docker-compose
|
||
- README 更新
|
||
|
||
### 不包含
|
||
- 交互式 REPL 模式(后续可加)
|
||
- Web UI 管理界面
|
||
- CI/CD pipeline 配置
|
||
- Kubernetes 部署配置
|
||
- 插件市场/注册中心
|
||
|
||
---
|
||
|
||
## 执行顺序
|
||
|
||
```
|
||
U1 (CLI 骨架) → U2 (task) + U3 (skill) + U4 (init/usage) 并行 → U5 (Docker) → U6 (README + 测试)
|
||
```
|
||
|
||
U2/U3/U4 互相独立,可并行实现。U5 依赖 U1(Dockerfile 需要 CLI 入口)。U6 依赖所有前置单元。
|