Files
llama-agent-skills/openspec/changes/add-skill-support/design.md
T
Summer Shen 9578366e36 init repo
2026-03-31 09:14:32 +08:00

148 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
本项目是一个全新的 Python 项目(greenfield),目标是构建一个基于 LlamaIndex Workflow 的 Agent,能够动态加载和执行 SKILL。
**当前状态:**
- 项目仅有 `src/llama_agent_skills/__init__.py` 中一个空的 `main()` 入口
- 无任何现有依赖(`pyproject.toml``dependencies = []`
- `.opencode/skills/``.github/skills/` 下有 4 个 SKILL.md 示例文件,定义了 SKILL 的标准格式
**SKILL 格式(已有约定):**
- YAML frontmatter`name``description``license``metadata`author、version
- Markdown 正文:自由格式的指令文本,包含 Steps、Guardrails、Input/Output 等段落
**LlamaIndex Workflow 关键能力(调研结论):**
- `Workflow` 基类:事件驱动、`@step` 装饰器、`Context` 状态管理
- `AgentWorkflow.from_tools_or_functions()`:接受 `tools` 列表和 `system_prompt`
- `FunctionAgent`:支持 `system_prompt``tools``can_handoff_to`
- 工具列表存储为实例变量 `self.tools`,可运行时动态增删
- `Context.set/get` 提供步骤间状态共享
**约束:**
- 不引入 Shell/subprocess,纯 Python 运行
- 脚本类 SKILL 功能暂不支持
- 需要支持线上部署场景
## Goals / Non-Goals
**Goals:**
- 实现 SKILL.md 文件的解析器,能提取 frontmatter 元数据和正文指令
- 实现 SKILL 注册表,支持从目录扫描、运行时动态注册/注销
- 构建基于 LlamaIndex Workflow 的核心 Agent,将 SKILL 作为 system prompt 的扩展注入
- 提供清晰的 Python API,方便程序化创建和运行 Agent
- 保持架构简洁,为后续扩展(MCP 工具、多 Agent 协作)留出空间
**Non-Goals:**
- 不实现 Shell/subprocess 执行能力(安全约束)
- 不实现 SKILL 内定义的脚本/命令执行功能
- 不实现多 Agent 协作/handoff(后续迭代)
- 不实现 SKILL 的远程加载(仅支持本地文件系统)
- 不实现 Web UI 或 REST API 层
- 不实现 MCP server/client 集成(后续迭代)
## Decisions
### D1: SKILL 注入方式 — System Prompt 拼接
**决定:** 将 SKILL 的 Markdown 正文作为 system prompt 的一部分注入 Agent。
**备选方案:**
- A) 将 SKILL 转换为 LlamaIndex `BaseTool`(每个 SKILL 变成一个可调用工具)
- B) 将 SKILL 注入 system prompt(当前选择)
- C) 将 SKILL 作为 RAG 文档,通过检索注入
**选择 B 的理由:**
- SKILL 本质是「行为指令」而非「可调用函数」,它定义了 Agent 应该如何行动,而不是提供一个新的能力入口
- System prompt 注入最自然,与 LlamaIndex 的 `system_prompt` 参数直接对应
- 方案 A 需要为每个 SKILL 包装一个工具入口,增加不必要的间接层
- 方案 C 引入 RAG 复杂度,对于有限数量的 SKILL 是过度设计
- 后续如果 SKILL 需要携带工具定义,可以在 SKILL 格式中扩展 `tools` 字段,注册为真正的工具
### D2: SKILL.md 解析策略 — python-frontmatter 库
**决定:** 使用 `python-frontmatter` 库解析 SKILL.md 的 YAML frontmatter + Markdown body。
**备选方案:**
- A) 手写 YAML + Markdown 分割解析器
- B) 使用 `python-frontmatter` 库(当前选择)
- C) 使用 `pyyaml` + 手动分割 `---` 分隔符
**选择 B 的理由:**
- `python-frontmatter` 是成熟的库,专门处理 frontmatter 格式,边界情况覆盖好
- 减少自研代码量和 bug 风险
- 自动处理 YAML 类型转换
### D3: Agent 架构 — 基于 AgentWorkflow 的单 Agent
**决定:** 使用 `AgentWorkflow.from_tools_or_functions()` 构建单 Agent,通过 `system_prompt` 参数注入 SKILL 上下文。
**备选方案:**
- A) 自定义 `Workflow` 子类,手动实现所有步骤
- B) 使用 `AgentWorkflow.from_tools_or_functions()`(当前选择)
- C) 使用 `FunctionAgent` + 多 Agent 编排
**选择 B 的理由:**
- `AgentWorkflow` 提供开箱即用的对话循环、工具调用、流式输出
- 对于第一版,单 Agent 足够验证 SKILL 注入概念
- 如需自定义步骤(如 SKILL 热加载),可以后续继承扩展
- 方案 A 需要重写大量 LlamaIndex 已有逻辑
- 方案 C 在当前阶段是过度设计
### D4: 模块结构 — 职责分离
**决定:** 按职责划分为以下模块:
```
src/llama_agent_skills/
├── __init__.py # 包入口 + main()
├── skill.py # Skill 数据模型 + SKILL.md 解析器
├── registry.py # SkillRegistry(扫描、注册、查询)
├── agent.py # Agent 构建与运行(封装 AgentWorkflow
└── config.py # 配置管理(环境变量、默认值)
```
**理由:**
- `skill.py` 专注数据解析,与 LlamaIndex 无关,可独立测试
- `registry.py` 管理 SKILL 生命周期,依赖 `skill.py` 但不依赖 `agent.py`
- `agent.py` 是唯一依赖 LlamaIndex 的模块,负责将 registry 中的 SKILL 组装为 Agent
- `config.py` 集中管理配置,避免硬编码散落
### D5: SKILL 上下文组装策略
**决定:** 在 Agent 启动时,将所有已注册 SKILL 的正文按固定格式拼接到 system prompt
```
{base_system_prompt}
---
## Active Skills
### Skill: {skill.name}
{skill.description}
{skill.body}
---
### Skill: {skill2.name}
...
```
**理由:**
- 结构化的分隔让 LLM 清楚区分不同 SKILL 的指令
- 每个 SKILL 带有名称和描述作为标题,便于 LLM 理解上下文切换
-`---` 分隔避免 SKILL 间指令混淆
## Risks / Trade-offs
- **[System prompt 长度爆炸]** → 当加载多个大型 SKILL 时,system prompt 可能超出 LLM context window。**缓解:** 限制同时加载的 SKILL 数量,后续可引入选择性加载或摘要机制。
- **[SKILL 间指令冲突]** → 多个 SKILL 可能包含矛盾指令。**缓解:** 第一版不解决,通过文档约定 SKILL 应自包含;后续可增加冲突检测。
- **[LlamaIndex 版本锁定]** → 依赖 `llama-index-core` 的特定 API(如 `AgentWorkflow`),升级可能 break。**缓解:** 通过 `agent.py` 隔离 LlamaIndex 依赖,仅在该模块中引用 LlamaIndex API。
- **[无 Shell 限制降低灵活性]** → 部分 SKILL 可能期望执行 CLI 命令(如 `openspec` CLI)。**缓解:** 明确标记为 Non-Goal,后续可通过安全沙箱或 API wrapper 支持。
- **[SKILL.md 格式无 schema 校验]** → frontmatter 字段错误不会被提前发现。**缓解:** 在 `skill.py` 中做基本校验(必填字段检查),后续可引入 JSON Schema 或 Pydantic 校验。