AI Agent 自动化系统 - 开发设计文档

版本: v1.1
日期: 2026 年 3 月
目标: 构建一个可学习、可积累、可复用的桌面级 AI Agent 系统
阅读对象: 系统架构师、后端研发工程师、WPF 客服端研发工程师、AI 能力对接工程师。本记录作为编码落地的直接依据。


1. 系统概述

1.1 核心理念

智能体系统的核心价值在于将“人工操作路径”抽象并固化为“机器可执行流程”,并且允许机器在执行过程中根据环境变化进行感知降级自我修正

┌─────────────────────────────────────────────────────────────┐
│ 🧠 智能体核心思想                                           │
├─────────────────────────────────────────────────────────────┤
│ 1. 技能不写死 → 全部配置化 (Skill Config),实现逻辑层面解耦 │
│ 2. 过程可记录 → 执行日志结构化 (Execution Log),便于追溯异常│
│ 3. 经验可复用 → 成功路径可固化为标准模板 (Success Pattern)  │
│ 4. 能力可进化 → 失败重试及 AI 辅助修正生成新技能 (Learning) │
└─────────────────────────────────────────────────────────────┘

1.2 用户场景与边界

场景 频率 复杂度 核心诉求 依赖的技能类型
网易邮箱查账单 每月 定期提取多封邮件数据,结构化输出 感知 (DOM/OCR) + 执行 + 数据解析
央视体育直播 按需 自动打开特定网页并全屏播放,防休眠 执行 (Navigation/Window) + 媒体控制
RSS 头条阅读 每日 聚合多个数据源,提炼核心结论推送到端 感知 (API Fetch) + 总结生成 (AI)
自定义工作流 - 用户提供自然语言或录制,系统自动生成配置 Agent Planner + 动态生成配置

1.3 设计原则

原则 落地准则
配置驱动 代码本体不硬编码任何具体业务逻辑(如网址、DOM Selector),全由 JSON/YAML 载入。
感知降级 网页解析时,优先使用速度最快、无成本的 DOM 解析;失败时回退至本地 OCR 识别屏幕坐标;再次失败使用多模态大模型 (VL) 进行视觉理解。
单进程宿主 Main.exe 作为唯一宿主入口。浏览器利用 WebView2 (独立子进程不崩主进程);耗时任务通过 Task.Run 在后台线程池调度并派发状态。
防破坏性 系统必须提供运行状态可视化(正在做什么),且支持强制全局中断(Esc 或快捷键)。涉及资产或高危操作(如下单)必须加入人工二次确认 (Human-in-the-loop)。

2. 系统架构深入

2.1 模块依赖与架构分层

架构严格遵循依赖倒置原则(DIP)。上层依赖下层的接口,具体实现在 DI 容器中注入。

┌────────────────────────────────────────────────────────────────────────────────────────┐
│ UI 层 (MyAgent.UI) | MVVM 架构 | WPF + CommunityToolkit.Mvvm                           │
│ 负责展示面板、接管全局快捷键、与系统托盘交互。通过 EventAggregator 接收内核状态通知。  │
├────────────────────────────────────────────────────────────────────────────────────────┤
│ 业务编排层 (MyAgent.Host)                                                              │
│ 负责装配 DI 容器,初始化数据库,拉起 Scheduler (Quartz.NET),管理系统生命周期。        │
├─────────┬──────────────────────────────────────────────────────────────────────────────┤
│         │ 核心调度层 (MyAgent.Core)                                                    │
│ 基础    │ 暴露 IAgentEngine, ISkillManager, ILogService 等接口。                       │
│ 设施    │ 负责:1. 解析 YAML 加载 Skill 树。 2. 调度具体的 Step 运行。                 │
│         │       3. 上下文透传与流转。        4. 统一处理异常与重试逻辑。               │
│ Utils   ├──────────────────────────────────────────────────────────────────────────────┤
│ (SQLite │ 工具技能层 (MyAgent.Skills)                                                  │
│  Http   │ 1. Perception (感知): DOM 解析器, PaddleOCR 包装器, Qwen-VL 视觉请求客户端。 │
│  Log)   │ 2. Action (动作): WebView2 控制器 (点击/输入), 鼠标/键盘低级模拟 (Win32)。   │
│         │ 3. Media (媒体): FFmpeg 录屏调用, 音频播报等。                               │
│         │ 4. AI (认知): Qwen API 客户端,封装 Prompt 模板。                            │
└─────────┴──────────────────────────────────────────────────────────────────────────────┘

2.2 上下文流转机制 (Context Flow)

每个 Skill 的执行都会生成一个唯一的 SkillExecutionContext,用于在多个 Step 之间传递数据。

public class SkillExecutionContext
{
    public string ExecutionId { get; set; } = Guid.NewGuid().ToString("N");
    public string SkillId { get; set; }
    
    // 运行时环境变量 (例如:当前绑定的 WebView2 句柄, 全局超时等)
    public Dictionary<string, object> EnvironmentArgs { get; set; }
    
    // 步骤间数据传递 (Step 1 提取的数据,存入此处供 Step 2 的 AI 总结使用)
    public Dictionary<string, object> StateBag { get; set; }
    
    // 取消令牌,用于响应全局中止事件
    public CancellationTokenSource CancellationToken { get; set; }
    
    public ExecutionLogData Logger { get; set; }
}

3. 详细的 Skill 引擎设计

3.1 工作流解析与反射路由

配置文件中的 action: "browser.navigate" 是如何转换为代码执行的?

  1. 系统启动时,扫描 MyAgent.Skills 程序集。
  2. 查找所有标记了 [SkillAction("browser.navigate")] 的类,这些类必须实现 IActionTool 接口。
  3. "browser.navigate" 字符串作为 Key 注册到字典缓存中。
  4. 运行时,引擎读取 YAML 中的 action 字段,从字典取出现实类,利用反射(或 ActivatorUtilities)通过 DI 创建实例。
  5. params 节点反序列化为 JObject 或强类型类传入 ExecuteAsync

3.2 完整的 YAML 配置规范定义

为了让 AI 或人类更好编写配置,以下是标准化的 JSON Schema 概念:

# 规范化 skill 定义文件
schema_version: "1.1"
skill_id: "example_skill_id"
name: "技能名称"
description: "技能的自然语言描述,供规划器 Planner 理解该技能用于什么场景"

trigger:
  type: schedule | manual | event | api # 触发方式
  cron: "0 9 * * *" # 当 type=schedule 必填
  keywords: ["关键词1"] # 给意图识别模型用于匹配

workflow:
  - step_id: "step_1"
    name: "本步骤含义"
    action: "命名空间.动作名" # 必须是已注册的组件
    params: { ... } # 对应 action 的入参,可使用 {{StateBag.Key}} 解析上文变量
    timeout_ms: 5000 # 步骤级超时控制
    retry_policy: # 步骤级重试策略
      max_attempts: 3
      delay_ms: 1000
    on_error: "continue" | "abort" | "fallback" # 出错后的行为
    fallback_action: # 当 on_error=fallback 时必填
      action: "..."
      params: { ... }

success_criteria: # 决定该 Skill 是否计为最终成功的条件
  - type: element_exists | data_extracted | media_playing
    condition: { ... }

3.3 变量插值与动态参数 (新特性)

在复杂的流程中,后续步骤需要使用前面步骤的结果。我们需要支持类似 {{}} 的模板语法。
例如:步骤 A 获取了用户名,保存到了 StateBag["username"]。步骤 B 调用 API 时,url: "https://api.com/user/{{username}}"。引擎在执行前会正则替换并注入实际值。


4. 稳健的重试与网络保护

4.1 异常分类器

为了保证 Agent 在无人值守下的稳定性,必须对异常进行精确分类:

  1. TransientException (瞬态异常): 例如网络超时、元素加载暂时不可见。
    • 策略: 按照 retry_policy (指数退避算法) 进行重试。
  2. BusinessLogicException (业务异常): 网站提示“密码错误”、“验证码错误”。
    • 策略: 降级或直接终止(abort),因为重试多半无用。通知用户 Notification.Send
  3. PerceptionException (感知异常): DOM 结构变化导致 SelectorNotFound
    • 策略: 触发配置的 perception.fallback_chain(DOM -> OCR -> VL)。如果全部降级失败,记录为“技能失效需人工修正”。
  4. FatalException (致命异常): 浏览器内核崩溃、内存溢出。
    • 策略: 捕获于最外层,重启 WebView2 进程环境,清理相关分配。

4.2 WebDriver 与 DOM 的交互隔离

使用 WebView2 的 ExecuteScriptAsync 执行 JS 与页面交互时,强烈建议注入一段受控的内嵌脚本库 (Agent.js),而不是零散地写原生 JS 代码。
Agent.js 负责平滑滚动、带重试的元素查找、消除遮罩层等稳定化操作,极大降低 C# 侧交互的复杂度。


5. 存储模型设计 (SQLite)

5.1 实体关系模型 (ER 概述)

数据库主要用于持久化产生的数据,不要用关系型数据库存死配置(配置统一用 YAML)。

  1. Table: ExecutionLogs (主表)

    • Id (PK, Guid)
    • SkillId (Varchar, 索引)
    • StartTime (Datetime)
    • EndTime (Datetime)
    • Status (Int) -> Enum
    • TriggerMode (Int) -> Enum
  2. Table: StepLogs (明细表)

    • Id (PK, Guid)
    • ExecutionId (FK -> ExecutionLogs.Id)
    • StepId (Varchar, “step_1”)
    • ActionName (Varchar)
    • DurationMs (Int)
    • Status (Int)
    • RawInput (Text/JSON, 执行前的实际参数)
    • RawOutput (Text/JSON, 执行结果或 Error Stacktrace)
  3. Table: Analytics (统计报表,由定时任务聚合)

    • Date (Date)
    • SkillId (Varchar)
    • TotalExecutions (Int)
    • SuccessRate (Float)
    • TokensUsed (Int)

6. 技术栈与工程实践 (增强版)

6.1 精确版本锁定

避免版本碎片化,规定基础框架:

  • Target Framework: net8.0-windows
  • WPF 模式: 采用 MVVM 模式,避免后置代码(Code-Behind)臃肿。

6.2 核心 NuGet 包清单及用途补充

<!-- 微软依赖注入与配置扩展,用于 Host Builder 构建 -->
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.0" /> <!-- 用于 HTTP 调用的弹性策略 (重试、熔断) -->

<!-- 现代 MVVM 框架,取代 Prism,更加轻量现代 -->
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />

<!-- 浏览器内核 -->
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />

<!-- 大模型 SDK -->
<PackageReference Include="Aliyun.SDK.DashScope" Version="1.0.0" />

<!-- 定时任务调度器,比原生 Timer 更可靠,支持 Cron 表达式 -->
<PackageReference Include="Quartz" Version="3.8.0" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.8.0" />

<!-- ORM 选用轻量且快速的 Dapper -->
<PackageReference Include="Dapper" Version="2.1.28" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.0" />

7. 详细开发阶段拆解 (为 AI 执行做准备)

这一部分是将原本高层次的规划,拆解为可以分配给 AI 编程助手的颗粒度 Task

Phase 1: 底层基础设施 (Infrastructure) - 预计耗时 3 天

  • Task 1.1: 搭建 .sln 结构与空项目约束 (UI, Core, Skills, Host)。引入必要的 NuGet 包。
  • Task 1.2: 实现通用的依赖注入 Startup 注册类,并搭建基于 ILogger<T> 的日志系统(输出到控制台与文件)。
  • Task 1.3: 设计并实现 SQLite 仓储层,包含基于 Dapper 的基础增删改查和数据库自动建表脚本(启动时如果不存在库则自动创建)。

Phase 2: 核心引擎骨架 (Agent Engine) - 预计耗时 4 天

  • Task 2.1: 定义 ISkill, IActionTool, IPerception 等核心接口(复制 8.1 节内容生成文件)。
  • Task 2.2: 利用 YamlDotNet 编写 SkillConfigReader,支持反序列化目录下的所有 YAML 文件到 SkillDefinition 对象中。
  • Task 2.3: 实现 ActionFactory 和反射路由,保证给一个 action_name 字符串,能返回一个 IActionTool
  • Task 2.4: 组装主心骨 SkillEngine::ExecuteAsync 方法。实现顺序遍历 Step、参数插值、重试抓取和上下文(StateBag)管理。

Phase 3: 工具能力接入 (Skills Implementations) - 预计耗时 5 天

  • Task 3.1: 封装 WebView2Wrapper。实现原生的 Navigate, WaitForNetworkIdle, ExecuteScript 等底层 API 封装。(由于是后台进程要求,需处理好无界面的 WebView2 实例化问题,或隐藏窗体)。
  • Task 3.2: 实现基于 DOM 的感知工具 action: "perception.dom",包括查找元素、提取文本、判断是否存在。
  • Task 3.3: 对接 Aliyun.SDK.DashScope,实现 action: "ai.analyze",编写通用的大模型调用接口。

Phase 4: UI 与联调 (WPF Client) - 预计耗时 3 天

  • Task 4.1: 构建 WPF 主界面的导航栏 (Dashboard, Skills, Logs, Settings)。
  • Task 4.2: 将 UI 线程与 Agent 后台处理挂钩,通过类似于 Messenger.Default 通知 UI 刷新执行状态进度条。
  • Task 4.3: 联调“网易邮箱”或“RSS 阅读”的测试 YAML,跑通全链路并查看数据库写入结果。

8. 代码接口详细规约 (Guideline)

为确保 AI 生成的代码符合工程标准,制定以下代码约束:

namespace MyAgent.Core.Interfaces
{
    // 强制:所有的插件工具必须是无状态的单例 (Singleton) 生命周期
    public interface IActionTool
    {
        // 返回如 "browser.navigate" 格式的标识
        string ActionType { get; }
        
        // 核心执行逻辑,必须支持 CancellationToken
        // JToken 允许传入动态结构,工具内部在使用前映射为强类型的 DTO
        Task<ActionResult> ExecuteAsync(SkillExecutionContext context, JToken parameters, CancellationToken cancellationToken);
    }

    public class ActionResult
    {
        public bool IsSuccess { get; set; }
        public string ErrorMessage { get; set; }
        // 执行产出的数据,将被引擎自动合并到 context.StateBag
        public Dictionary<string, object> OutputData { get; set; } 
    }
}

9. 验收标准补充

增加针对开发者的技术性验收节点:

  1. 沙盒隔离:Skill A 的失败不应导致系统挂起,系统须能在出现未捕获异常时自动将其标记为 Fail 并继续监听下一个任务。
  2. 热加载:在修改了 /config/skills/ 目录下的某 YAML 文件后,系统应当包含文件系统变更监听 (FileSystemWatcher) 并自动重载规则,无需重启程序。
  3. 日志溯源:控制台和 Log 文件必须保证输出包含 ExecutionId 关联上下文的 Trace,确保排错过程顺利。