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" 是如何转换为代码执行的?
- 系统启动时,扫描
MyAgent.Skills程序集。 - 查找所有标记了
[SkillAction("browser.navigate")]的类,这些类必须实现IActionTool接口。 - 将
"browser.navigate"字符串作为 Key 注册到字典缓存中。 - 运行时,引擎读取 YAML 中的
action字段,从字典取出现实类,利用反射(或 ActivatorUtilities)通过 DI 创建实例。 - 将
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 在无人值守下的稳定性,必须对异常进行精确分类:
- TransientException (瞬态异常): 例如网络超时、元素加载暂时不可见。
- 策略: 按照
retry_policy(指数退避算法) 进行重试。
- 策略: 按照
- BusinessLogicException (业务异常): 网站提示“密码错误”、“验证码错误”。
- 策略: 降级或直接终止(abort),因为重试多半无用。通知用户
Notification.Send。
- 策略: 降级或直接终止(abort),因为重试多半无用。通知用户
- PerceptionException (感知异常): DOM 结构变化导致
SelectorNotFound。- 策略: 触发配置的
perception.fallback_chain(DOM -> OCR -> VL)。如果全部降级失败,记录为“技能失效需人工修正”。
- 策略: 触发配置的
- FatalException (致命异常): 浏览器内核崩溃、内存溢出。
- 策略: 捕获于最外层,重启 WebView2 进程环境,清理相关分配。
4.2 WebDriver 与 DOM 的交互隔离
使用 WebView2 的 ExecuteScriptAsync 执行 JS 与页面交互时,强烈建议注入一段受控的内嵌脚本库 (Agent.js),而不是零散地写原生 JS 代码。
Agent.js 负责平滑滚动、带重试的元素查找、消除遮罩层等稳定化操作,极大降低 C# 侧交互的复杂度。
5. 存储模型设计 (SQLite)
5.1 实体关系模型 (ER 概述)
数据库主要用于持久化产生的数据,不要用关系型数据库存死配置(配置统一用 YAML)。
-
Table: ExecutionLogs (主表)
Id(PK, Guid)SkillId(Varchar, 索引)StartTime(Datetime)EndTime(Datetime)Status(Int) -> EnumTriggerMode(Int) -> Enum
-
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)
-
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. 验收标准补充
增加针对开发者的技术性验收节点:
- 沙盒隔离:Skill A 的失败不应导致系统挂起,系统须能在出现未捕获异常时自动将其标记为 Fail 并继续监听下一个任务。
- 热加载:在修改了
/config/skills/目录下的某 YAML 文件后,系统应当包含文件系统变更监听 (FileSystemWatcher) 并自动重载规则,无需重启程序。 - 日志溯源:控制台和 Log 文件必须保证输出包含
ExecutionId关联上下文的 Trace,确保排错过程顺利。