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,确保排错过程顺利。