# michael-aiagent **Repository Path**: meng-cl/michael-aiagent ## Basic Information - **Project Name**: michael-aiagent - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-16 - **Last Updated**: 2026-10-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WWT.AiAgent AI Agent 框架 - 支持前后端工具统一、ReAct 编排、多 LLM Provider。 ## 特性 - ✅ **前后端工具统一**:前端工具(弹表单/确认)和后端工具(直接执行)使用统一的 `ToolResult` 结构 - ✅ **ReAct 编排**:内置 ReAct 循环编排,支持推理链(reasoning)和工具调用 - ✅ **多 LLM Provider**:支持 OpenAI、DeepSeek、通义千问、Ollama - ✅ **分布式锁**:基于数据库 CAS 实现的任务锁,支持多实例部署 - ✅ **流式响应**:SSE 流式输出,支持思考过程和内容分别推送 - ✅ **持久化会话**:多轮对话历史持久化,跨任务保留上下文 - ✅ **灵活配置**:路由前缀、鉴权、表名、SystemPrompt 等均可配置 ## 快速开始 ### 1. 安装包 ```bash dotnet add package WWT.AiAgent dotnet add package WWT.AiAgent.Persistence.SqlSugar dotnet add package WWT.AiAgent.Logging.NLog # 可选 ``` ### 2. 配置 appsettings.json ```json { "AiAgent": { "Provider": "deepseek", "BaseUrl": "https://api.deepseek.com", "ApiKey": "sk-your-api-key", "Model": "deepseek-chat", "EnableReasoning": false, "MaxHistoryMessages": 20, "MaxIterations": 10, "RoutePrefix": "/api/ai-agent", "RequireAuthorization": true, "SystemPromptFile": "prompt.txt" }, "ConnectionStrings": { "Default": "Data Source=ai_agent.db" } } ``` ### 3. 注册服务 ```csharp using WWT.AiAgent.Extensions; using WWT.AiAgent.SqlSugar; using WWT.AiAgent.NLog; var builder = WebApplication.CreateBuilder(args); // 注册 AI Agent 服务 builder.Services.AddAiAgent(builder.Configuration) .UseSqlSugarSqlite( builder.Configuration.GetConnectionString("Default")!, opts => { opts.TablePrefix = "ai_"; // 表名前缀 opts.AutoMigrate = true; // 自动建表 opts.WorkerId = 1; // 雪花ID WorkerId }) .UseNLog() // 可选:NLog 日志 .AddTools(t => t .Add() // 注册工具 .Add()); // 添加认证(可选) builder.Services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { /* ... */ }); builder.Services.AddAuthorization(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); // 映射 AI Agent 端点 app.MapAiAgent(); app.Run(); ``` ### 4. 前端集成 ```typescript // 创建会话 const session = await fetch('/api/ai-agent/sessions', { method: 'POST', headers: { 'Authorization': 'Bearer ' } }).then(r => r.json()); // 创建任务 const task = await fetch('/api/ai-agent/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' }, body: JSON.stringify({ sessionId: session.id, goal: '查询旅游线路' }) }).then(r => r.json()); // SSE 流式对话 const eventSource = new EventSource( `/api/ai-agent/chat?taskId=${task.id}&message=北京三日游`, { headers: { 'Authorization': 'Bearer ' } } ); eventSource.onmessage = (event) => { const data = JSON.parse(event.data); switch (data.type) { case 'session.started': console.log('会话开始:', data.data); break; case 'reasoning.delta': console.log('思考:', data.data.delta); break; case 'content.delta': console.log('内容:', data.data.delta); break; case 'tool_call.emitted': console.log('工具调用:', data.data); // 前端工具需要用户交互后回填结果 break; case 'tool_call.result': console.log('工具结果:', data.data); break; case 'task.status_changed': if (data.data.status === 'Done') { eventSource.close(); } break; } }; ``` ## 工具系统 ### 后端工具(服务端执行) ```csharp using WWT.AiAgent.Abstractions; using WWT.AiAgent.Attributes; public class GetWeatherArgs { [ToolParam(Description = "城市名称", Required = true)] public string City { get; set; } = ""; } [BackendTool( Name = "get_weather", Description = "查询指定城市的天气信息")] public class GetWeatherTool : BackendTool { private readonly HttpClient _httpClient; public GetWeatherTool(HttpClient httpClient) { _httpClient = httpClient; } protected override async Task ExecuteAsync( GetWeatherArgs args, ToolContext ctx, CancellationToken ct) { var weather = await FetchWeatherAsync(args.City); return new ToolResult( success: true, message: $"{args.City}天气:{weather.Description},温度 {weather.Temp}°C", data: weather ); } } ``` ### 前端工具(需要用户交互) ```csharp using WWT.AiAgent.Attributes; [FrontendTool( Name = "query_tour", Description = "查询旅游线路信息")] public class QueryTourArgs { [ToolParam(Description = "目的地", Required = true)] public string Destination { get; set; } = ""; [ToolParam(Description = "出发日期")] public string DepartureDate { get; set; } = ""; } ``` 前端接收到 `tool_call.emitted` 事件后,弹出表单让用户填写,然后通过 POST `/api/ai-agent/chat` 回填结果: ```typescript fetch('/api/ai-agent/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ taskId: task.id, messageType: 'ToolResult', toolResult: { toolCallId: '', messageId: '', result: JSON.stringify({ success: true, message: "用户确认了查询条件", data: { destination: "北京", days: 3 } }) } }) }); ``` ### OpenAPI 工具(自动从 Swagger 生成) 无需手写任何 Tool 代码,直接把现有 WebAPI 的 Swagger/OpenAPI 规范转换成 Agent 工具: ```csharp builder.Services.AddAiAgent(builder.Configuration) .AddOpenApiTools(builder.Configuration) // 读取 "OpenApiTools" 配置段 .AddTools(t => t.Add()); ``` ```json { "OpenApiTools": { "HttpTimeoutSeconds": 30, "FailOnLoadError": false, "Sources": [ { "Name": "CMS", "SwaggerUrl": "http://localhost:5000/swagger/v1/swagger.json", "ToolPrefix": "cms_", "Enabled": true, "Authentication": { "Type": "BearerToken", "SourceHeader": "Authorization" } } ] } } ``` 说明: - 应用启动时同步下载并解析所有 `Sources`,为每个 operation 生成一个后端工具(`RequiresFrontend=false`),重启应用才会重新发现。 - `ToolPrefix` 必填,用于避免跨源工具名冲突(工具名 = `{ToolPrefix}{operationId}`,无 `operationId` 时按资源名+HTTP 动词自动生成,Controller/Action 路由风格下为 `{ToolPrefix}{Controller}_{Action}`)。 - `Authentication.Type=BearerToken` 时,会把当前用户请求 `SourceHeader`(默认 `Authorization`)里的 Token 原样转发给目标 API。 - 仅支持 `application/json` 请求体;仅支持 Bearer Token 透传认证(暂不支持 ApiKey/自定义 Header)。 ## 配置选项 ### AiAgentOptions | 配置项 | 默认值 | 说明 | |---|---|---| | `Provider` | `"deepseek"` | LLM 提供商:deepseek / openai / tongyi / ollama | | `BaseUrl` | `"https://api.deepseek.com"` | LLM API 地址 | | `ApiKey` | `""` | API 密钥 | | `Model` | `"deepseek-chat"` | 模型名称 | | `EnableReasoning` | `false` | 启用推理模式 | | `MaxHistoryMessages` | `20` | 历史消息截断数量 | | `MaxIterations` | `10` | ReAct 最大循环次数 | | `RoutePrefix` | `"/api/ai-agent"` | API 路由前缀 | | `RequireAuthorization` | `true` | 是否强制鉴权 | | `SystemPromptFile` | `null` | SystemPrompt 文件路径 | | `LockTtlSeconds` | `120` | 任务锁 TTL(秒)| | `RunningTimeoutSeconds` | `300` | Running 状态超时(秒)| | `WaitingToolTimeoutSeconds` | `1800` | WaitingTool 状态超时(秒)| ### SqlSugarPersistenceOptions | 配置项 | 默认值 | 说明 | |---|---|---| | `ConnectionString` | `""` | 数据库连接字符串 | | `DbType` | `"SQLite"` | 数据库类型:SQLite / MySQL / PostgreSQL | | `TablePrefix` | `"ai_"` | 表名前缀 | | `TableSuffix` | `""` | 表名后缀 | | `SchemaName` | `null` | Schema 名称(PostgreSQL/SQL Server)| | `AutoMigrate` | `true` | 启动时自动建表 | | `WorkerId` | `1` | 雪花 ID WorkerId | ## 自定义鉴权 框架默认使用 ASP.NET Core 的鉴权系统。如果需要自定义鉴权逻辑(如 Header 透传 UserId),实现 `IUserContext` 接口: ```csharp public class HeaderUserContext : IUserContext { private readonly IHttpContextAccessor _accessor; public HeaderUserContext(IHttpContextAccessor accessor) { _accessor = accessor; } public long UserId { get { var header = _accessor.HttpContext?.Request.Headers["X-User-Id"].FirstOrDefault(); return long.TryParse(header, out var id) ? id : 0; } } public string UserName => _accessor.HttpContext?.Request.Headers["X-User-Name"].FirstOrDefault() ?? "Guest"; } // 注册自定义实现 builder.Services.AddScoped(); ``` ## Skill 系统 为 LLM 按需注入知识/规则/流程说明(Prompt 片段),不执行业务逻辑;业务操作仍通过 `ITool` 完成。参考 OpenCode Superpowers 与 arkcli Skills 的三层加载策略: - **Tier 1(Process,强制)**:如调试流程、头脑风暴流程,命中触发条件即强制注入。 - **Tier 2(Implementation,自动匹配)**:如"创建页面"指南,按关键词/正则打分,取 Top-N 自动注入。 - **Tier 3(Reference,按需引用)**:详细文档默认不加载,LLM 通过 `load_skill` 工具显式请求。 ### 安装 ```bash dotnet add package WWT.AiAgent.Skills ``` ### 配置 ```csharp builder.Services.AddAiAgent(builder.Configuration) .UseSqlSugarSqlite(connStr, opts => { ... }) .AddSkillSystem(builder.Configuration) // 读取 "Skills" 配置节 .AddTools(t => t.Add().Add()); ``` ```json { "Skills": { "PackageDirectories": ["Skills/core-skills", "Skills/cms-skills"], "MaxAutoMatchResults": 3, "MinAutoMatchScore": 0.5, "EnableContentCache": true, "ContentCacheExpirationMinutes": 10 } } ``` ### Skill Package 目录结构 ``` Skills/ └── cms-skills/ └── skills/ ├── introduction/ │ └── SKILL.md └── create-page/ ├── SKILL.md └── references/ ├── create-workflow.md └── error-handling.md ``` ### SKILL.md 格式 ```markdown --- id: cms.create-page name: Create Page description: Step-by-step guide for creating CMS pages category: cms tags: [page, create] priority: 100 skillType: implementation # process | implementation | reference match: keywords: ["创建页面", "create page"] patterns: ["^创建.*页面$"] mode: any # any | all dependencies: skills: [cms.domain-model] tools: [QueryTour, CreatePage] references: - path: references/create-workflow.md description: Detailed create workflow --- # Goal Create pages following best practices. ... ``` 新增一个 `SKILL.md` 即完成一个 Skill 的接入,无需改动框架代码;重启应用(或调用 `ISkillRegistry.RefreshAsync()`)后自动被发现。 ### 运行机制 - 每次 ReAct 迭代前,`ISkillOrchestrator.ResolveForTaskAsync` 计算 Tier1+Tier2 应激活的 Skill,与 `Task.Meta` 中已通过 `load_skill` 主动加载的 Skill Id 合并。 - `SystemPromptProvider.ResolveAsync(task)` 把 Agent Prompt、Available Skills 列表、已激活 Skill 全文、Business Prompt 拼接为最终 System Prompt。 - LLM 可随时调用内置工具 `load_skill`(参数 `skillIds` / 可选 `referencePath`)主动加载额外 Skill 或某个 Reference 文档;加载结果写回 `Task.Meta`,下一轮迭代生效。 ## 支持的 LLM Provider | Provider | 配置值 | 说明 | |---|---|---| | OpenAI | `openai` | OpenAI GPT 系列 | | DeepSeek | `deepseek` | DeepSeek API | | 通义千问 | `tongyi` / `qwen` / `dashscope` | 阿里云通义千问 | | Ollama | `ollama` | 本地 Ollama | ## 许可证 MIT ## 贡献 欢迎提交 Issue 和 Pull Request。