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

13 KiB
Raw Blame History

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 implsubmit_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

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

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

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

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

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

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 改动)

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 的"实体/会话分离"模型,记忆以弱引用方式接入,MemoryRetrieverRuntimeBundle::new() 时自动注册为 LLM 可调用的 retrieve 工具。