Files
agcore/docs/note-agent-runtime-design.md
T

336 lines
13 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.
# Phase 4 Agent Runtime — 设计决策记录
> 决策固化日期:2026-06-09
> 用途:记录 Phase 4 设计阶段的关键决策、接口签名草案、文件清单,作为 `docs/7-agent-runtime.md` 方案文档的输入约束。
> 关联:
> - `docs/7-agent-runtime.md` — 完整方案文档(待写 / 已写)
> - `docs/note-agent-harness-references.md` — 参考项目调研(OpenClaw / Hermes / OpenHuman / OpenHarness
> - `docs/roadmap.md` — 项目总 Roadmap
> - `docs/2-llm-call-lifecycle.md` / `3-phase0-remaining.md` / `4-prompt-engineering.md` / `5-tool-system.md` / `6-memory-system.md` — Phase 0-3 方案
本文件是 Phase 4 设计阶段的"事实基础"——所有决策都有明确的对话出处与依据。后续 Phase 4 实施时应与本记录保持一致;如需调整,应先更新本记录再改代码。
---
## 1. 设计目标
AG Core Phase 4 的定位是**「Phase 0-3 的薄胶水层 + 一组 trait 抽象」**,遵循 OpenHarness 的"显式依赖注入"模式 + Hermes 的"两层实体/会话"模型。**不**实现业务循环,**不**做产品级功能,**不**假设上层如何使用 memory。
## 2. 范围与边界
### 2.1 必须实现(12 项)
| # | 交付物 | 文件 | 关键决策 |
|---|--------|------|---------|
| 1 | `Agent` trait | `src/agent/agent.rs` | 角色定义:name / system_prompt / 工具集 / 引用 session 句柄 |
| 2 | `RuntimeBundle` | `src/agent/runtime.rs` | 依赖注入容器(OpenHarness 风格) |
| 3 | `AgentSession` | `src/agent/session.rs` | 会话实例 + **最小 reference impl**`submit_turn` ~30 行) |
| 4 | `TaskAgent` + `Plan` / `Step` | `src/agent/task.rs` | 双入口:`run(goal)` 自主式 + `execute_plan(plan)` 外部驱动式 |
| 5 | `PlanParser` trait + `JsonPlanParser` 参考实现 | `src/agent/task.rs` | 注入式(澄清 3 选项 C) |
| 6 | `AgentError` | `src/agent/error.rs` | 聚合 LlmError / ToolError / MemoryError,含 `is_recoverable()` |
| 7 | `AgentConfig` / `AgentBuilder` | `src/agent/builder.rs` | 链式构造 `RuntimeBundle` |
| 8 | Hook 事件扩展 | `src/llm/hooks.rs` | 追加 `OnTurnStart` / `OnTurnEnd` / `OnPlanStepComplete` 3 个事件 + 上下文扩展(澄清 4) |
| 9 | `lib.rs` 导出 | `src/lib.rs` | 一行 `pub mod agent;` |
| 10 | 烟雾测试 | `src/agent/tests.rs` 或内联 | 2-3 个:trait 可装配 / RuntimeBundle 可构造 / `submit_turn` 跑通 mock |
| 11 | 方案文档 | `docs/7-agent-runtime.md` | 编号 `7`(最大编号是 `6`,已确认无冲突) |
| 12 | Roadmap 同步 | `docs/roadmap.md` | 状态从 ❌ 缺失 改为 ✅ |
### 2.2 明确不做(v0.2+ 边界)
| 推迟项 | 理由 |
|--------|------|
| 完整 `BasicAgent` 多轮 turn 循环 | core 库不假设业务循环 |
| `ConversationAgent` 自动回写 | 记忆在独立 task 处理,由上层回写 |
| 强绑定 `ConversationMemory` 字段 | 改 `Option<Arc<dyn MemoryStore>>` 弱引用 |
| Plan 拆解的提示词模板 | 由上层注入 `PlanParser` |
| Multi-Agent / Swarm | 接口未稳定,独立 phase |
| Markdown 技能按需加载 | 属于知识层 |
| 三级权限模式 UI | 应用层 |
| 干运行 / TUI / Gateway | 应用层 |
| 完整的集成测试套件 | 2-3 个烟雾测试足够(呼应"最小范围" |
详细 v0.2+ 候选项见 `docs/roadmap.md` 扩展计划(v0.2+)小节与 `docs/note-agent-harness-references.md` 第 8 节。
## 3. 核心架构
### 3.1 分层(与 OpenHarness 5 层一致)
```
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (上层 crate / 二进制 / Gateway
├─────────────────────────────────────────────────────────────┤
│ Agent Runtime ← Phase 4trait + RuntimeBundle + Session │
├─────────────────────────────────────────────────────────────┤
│ LLM / Tool / Prompt / Memory ← Phase 0/1/2/3(已完成) │
└─────────────────────────────────────────────────────────────┘
```
### 3.2 实体关系
```
┌────────────┐ ┌──────────────────┐
│ Agent │ 1 * │ AgentSession │
│ (trait) ├────────►│ (struct) │
│ - name │ │ - session_id │
│ - prompt │ │ - bundle: Arc │
│ - tools │ │ - turn_index │
└────────────┘ │ - cost_so_far │
└──────────────────┘
▼ 共享
┌──────────────────┐
│ RuntimeBundle │
│ - provider │
│ - tool_registry │
│ - hook_executor │
│ - memory_store? │ ◄── 弱引用(澄清 2 选项 B)
│ - retriever? │
│ - config │
└──────────────────┘
▼ 注册为 tool
┌──────────────────┐
│ "retrieve" tool │ ◄── 如果 retriever 存在则自动注册
└──────────────────┘
```
### 3.3 决策对照表
| 决策点 | 选择 | 来源 |
|--------|------|------|
| 实体 vs 会话 | 两层模型(`Agent` + `AgentSession`) | 讨论第 4 轮第 1 条 / OpenHarness / Hermes |
| 范围控制 | trait + 最小 reference impl~30 行) | 讨论第 4 轮第 2 条 / 澄清 1 选项 B |
| 记忆处理 | 弱引用 + 自动注册 retriever 为 tool | 讨论第 4 轮第 3 条 / 澄清 2 选项 B |
| Hook 扩展 | 3 个新事件 + 上下文扩展 | 讨论第 4 轮第 4 条 / 澄清 4 |
| 方案文档位置 | `docs/7-agent-runtime.md` | 讨论第 4 轮第 5 条 |
| TaskAgent 入口 | 双入口(自主 + 外部驱动) | 讨论第 4 轮第 6 条 |
| 自主式 Plan 解析 | 注入式 `PlanParser` trait + `JsonPlanParser` 参考实现 | 澄清 3 选项 C |
| 依赖注入 | `RuntimeBundle` 显式容器 | 讨论第 4 轮第 7 条 / OpenHarness |
| 文档撰写 | 推迟到 Proposal 阶段 | 讨论第 4 轮第 8 条 |
## 4. 接口签名草案
> ⚠️ **这些是"设计约束",不是最终代码**。方案文档(`docs/7-agent-runtime.md`)与实施阶段可微调字段顺序、文档注释、错误变体等,但**核心 trait 形状**和**方法名**应保持稳定。
### 4.1 `Agent` trait
```rust
pub trait Agent: Send + Sync {
fn name(&self) -> &str;
fn system_prompt(&self) -> Option<&str>;
/// 列出该 Agent 想要暴露给 LLM 的工具定义。
/// 默认实现:从 RuntimeBundle.tool_registry 取全部(最常用)。
/// 子 trait 可覆盖做白名单/过滤。
fn tool_definitions(&self, bundle: &RuntimeBundle) -> Vec<ToolDefinition>;
}
```
### 4.2 `RuntimeBundle`
```rust
pub struct RuntimeBundle {
pub provider: Arc<dyn LlmProvider>,
pub tool_registry: Arc<ToolRegistry>,
pub hook_executor: Arc<HookExecutor>,
pub memory_store: Option<Arc<dyn MemoryStore>>, // 弱引用(澄清 2 选项 B
pub retriever: Option<Arc<MemoryRetriever>>, // 弱引用(澄清 2 选项 B
pub config: AgentConfig,
}
impl RuntimeBundle {
/// 构造时如果 retriever 存在,自动注册为 "retrieve" tool。
pub fn new(/* ... */) -> Self;
}
```
### 4.3 `AgentSession`
```rust
pub struct AgentSession {
pub session_id: String,
pub agent_name: String,
bundle: Arc<RuntimeBundle>,
turn_index: u32,
cost_so_far: CostTracker,
}
impl AgentSession {
pub fn new(agent: &dyn Agent, session_id: impl Into<String>, bundle: Arc<RuntimeBundle>) -> Self;
/// 最小 reference impl:组装 LlmCycle + submit + 累计 cost。
/// 不做 memory 回写(呼应"记忆在独立 task 处理"原则)。
pub async fn submit_turn(
&mut self,
user_input: impl Into<String>,
) -> Result<ChatResponse, AgentError>;
pub fn usage(&self) -> &CostTracker;
pub fn turn_index(&self) -> u32;
}
```
### 4.4 `TaskAgent` + `Plan` + `Step`
```rust
pub struct Plan {
pub id: String,
pub goal: String,
pub steps: Vec<Step>,
}
pub struct Step {
pub index: usize,
pub description: String,
pub status: StepStatus,
}
pub enum StepStatus {
Pending,
Running,
Completed(ChatResponse),
Failed(AgentError),
Skipped,
}
/// 注入式 Plan 解析器。
#[async_trait]
pub trait PlanParser: Send + Sync {
async fn parse(&self, raw: &str, goal: &str) -> Result<Plan, AgentError>;
}
/// 基于 serde_json 的参考实现(约 20 行)。
pub struct JsonPlanParser;
#[async_trait]
impl PlanParser for JsonPlanParser { /* ... */ }
/// TaskAgent 双入口。
#[async_trait]
pub trait TaskAgent: Agent {
/// 自主式:内部用 LLM 拆 Plan → execute_plan
async fn run(&mut self, session: &mut AgentSession, goal: &str) -> Result<Plan, AgentError>;
/// 外部驱动式:用户预定义 Plan → 逐步执行
async fn execute_plan(
&mut self,
session: &mut AgentSession,
plan: Plan,
) -> Result<Plan, AgentError>;
}
```
### 4.5 `AgentError`
```rust
pub enum AgentError {
Llm(LlmError),
Tool(ToolError),
Memory(MemoryError),
PlanParse(String),
HookBlocked(String),
LimitExceeded(String),
Config(String),
Other(String),
}
impl AgentError {
pub fn is_recoverable(&self) -> bool { /* ... */ }
}
```
### 4.6 `AgentConfig` + `AgentBuilder`
```rust
pub struct AgentConfig {
pub max_turns: u32,
pub max_tool_turns: u32,
pub session_ttl: Option<Duration>,
pub compact_config: Option<CompactConfig>,
}
pub struct AgentBuilder { /* ... */ }
impl AgentBuilder {
pub fn new() -> Self;
pub fn provider(self, p: Arc<dyn LlmProvider>) -> Self;
pub fn tool_registry(self, r: Arc<ToolRegistry>) -> Self;
pub fn hook_executor(self, h: Arc<HookExecutor>) -> Self;
pub fn memory_store(self, m: Arc<dyn MemoryStore>) -> Self; // 选填
pub fn retriever(self, r: Arc<MemoryRetriever>) -> Self; // 选填
pub fn config(self, c: AgentConfig) -> Self;
pub fn build(self) -> Result<RuntimeBundle, AgentError>;
}
```
### 4.7 Hook 扩展(`src/llm/hooks.rs` 改动)
```rust
pub enum HookEvent {
// ... 现有 4 个 ...
// 新增 3 个:
OnTurnStart,
OnTurnEnd,
OnPlanStepComplete,
}
// HookContext 扩展 2 个 Option 字段(澄清 4):
pub struct HookContext {
// ... 现有字段 ...
pub turn_index: Option<u32>, // OnTurnStart/End 用
pub plan_step_index: Option<usize>, // OnPlanStepComplete 用
}
```
## 5. 文件清单
### 5.1 新增文件(7 个)
```
src/agent.rs # 模块根 + pub use 重导出
src/agent/agent.rs # Agent trait
src/agent/runtime.rs # RuntimeBundle + AgentConfig
src/agent/session.rs # AgentSession
src/agent/task.rs # TaskAgent trait + Plan/Step + PlanParser + JsonPlanParser
src/agent/builder.rs # AgentBuilder
src/agent/error.rs # AgentError
```
### 5.2 修改文件(3 个)
```
src/lib.rs # + pub mod agent;
src/llm/hooks.rs # + 3 个事件变体 + 2 个上下文字段(极小改)
docs/roadmap.md # 状态翻转 + Phase 4 交付物清单更新(实施时再做)
```
### 5.3 关联文档(已存在 / 待写)
```
docs/note-agent-harness-references.md # 参考项目调研(已存在)
docs/7-agent-runtime.md # 完整方案文档(路径 A 输出)
docs/note-agent-runtime-design.md # 本文件
```
## 6. 预估规模
- **新增代码**:约 **600-700 行**(含 2-3 个烟雾测试)
- **修改代码**:约 **10-20 行**`hooks.rs` 改动 + `lib.rs` + `roadmap.md`
- **方案文档**:约 **450-550 行 Markdown**(沿用 6-memory-system.md 的 6 段式结构)
## 7. 待办事项(按依赖顺序)
1. ✅ Phase 4 范围已收窄(§2.1
2. ✅ 核心架构已对齐 OpenHarness / Hermes(§3
3. ✅ 接口签名草案已固化(§4
4. ✅ 文件清单已确定(§5
5. ✅ 编号冲突已验证(最大是 `6`,新文件用 `7`
6. ⏳ 写 `docs/7-agent-runtime.md` 方案文档
7. ⏳ 按文档实施 7 个新文件 + 3 个修改
8. ⏳ 跑通 2-3 个烟雾测试
9. ⏳ 更新 `docs/roadmap.md` 状态翻转
## 8. 一句话总结
> **Phase 4 = Phase 0-3 的薄胶水层 + 一组 trait 抽象**。**不**实现业务循环,**不**做产品级功能,**不**假设上层如何使用 memory。借鉴 OpenHarness 的"显式依赖注入容器"与 Hermes 的"实体/会话分离"模型,记忆以弱引用方式接入,`MemoryRetriever` 在 `RuntimeBundle::new()` 时自动注册为 LLM 可调用的 `retrieve` 工具。