首页 > 基础资料 博客日记

Slickflow.AI 基于 Harness 工程规范的多智能体交互过程实现

2026-06-01 09:30:02基础资料围观1

本篇文章分享Slickflow.AI 基于 Harness 工程规范的多智能体交互过程实现,对你有帮助的话记得收藏一下,看极客资料网收获更多编程知识

Slickflow.AI 基于 Harness 工程规范的多智能体交互过程实现

以上功能实现已包含在Slickflow5.0 企业版版本


目录

  1. 背景与目标
  2. Harness 工程规范
  3. 核心架构设计
  4. 属性化工具注册(当前实现)
  5. 采购流程多智能体演示
  6. 落地路线图
  7. 自然语言驱动多智能体全流程生成
  8. 总结

1. 背景与目标

1.1 问题出发点

传统 BPM(业务流程管理)系统的核心是"人"驱动流程:人工节点负责决策,系统节点负责执行预定义规则。这一模型在面对复杂、动态、需要多步推理的企业场景时暴露出明显局限:

  • 规则节点无法处理非结构化输入(自然语言需求、图片、文档)
  • 复杂决策依赖大量 if-else 硬编码,维护成本高
  • 多系统协作需要人工中转,效率低

1.2 多智能体的价值

LLM Agent 节点引入 BPM 流程,每个 Agent 节点具备:

  • 推理能力:理解自然语言输入,分析上下文
  • 工具调用能力(Function Calling):调用企业系统 API、数据库、外部服务
  • 协作能力:通过共享上下文,多个 Agent 接力完成复杂任务
传统流程:用户 → 人工审核 → 系统执行 → 人工复核 → 结束

多智能体流程:用户 → Agent₁(需求分析) → Agent₂(方案搜索) →
              Agent₃(合规检查) → Agent₄(价格评估) → Agent₅(执行下单) → 结束

1.3 设计目标

目标 说明
流程驱动 Agent 行为由 BPMN 工作流定义驱动,不硬编码在程序里
工具解耦 工具实现与流程定义松耦合,通过 toolSetName 桥接
开发友好 业务开发者写普通 C# Service 类,不接触框架细节
可扩展 支持从代码工具逐步演进到声明式工具、MCP 协议工具

2. Harness 工程规范

Harness 是 Slickflow.AI 多智能体模块采用的工程架构规范,核心思想来源于 Claude 工程体系:以"注册→发现→执行"三段式管理智能体工具,使框架代码与业务代码完全分离。

2.1 核心思想

┌───────────────────────────────────────────────────────────────────┐
│                    Harness 三原则                                  │
│                                                                   │
│  1. 声明在设计时(BPMN + 属性面板)                                   │
│     toolSetName = "SupplierSearch"                                │
│                                                                   │
│  2. 注册在启动时(应用/测试初始化)                                    │
│     AgentToolSetRegistry.Global.Register<SupplierSearchService>() │
│                                                                   │
│  3. 执行在运行时(引擎自动驱动)                                       │
│     toolSetName → activityId → IReadOnlyList<IAgentTool>          │
└───────────────────────────────────────────────────────────────────┘

2.2 职责边界

角色 职责 代码位置
流程设计师 定义节点类型(Agent)、绑定 toolSetName、设置 System Prompt BPMN 设计器(数据库)
业务开发者 实现 [AgentToolSet] 服务类,写业务方法 ToolSets/*.cs
框架层 ReAct 循环、工具注册/发现、参数绑定、上下文管理 Slickflow.AI/Agent/
引擎层 读取 BPMN 定义,驱动 Agent 节点执行 Slickflow.Engine/

2.3 命名与注册规范

工具集命名(toolSetName)规则:

✅ 推荐:PascalCase,业务语义清晰
   NeedsAnalysis / SupplierSearch / ComplianceCheck

❌ 避免:技术实现名称
   AgentTool001 / Step2Handler / MyFunc

工具方法命名规则:

// ✅ 动词+名词,描述行为
public Task<SupplierQuote> RequestQuote(string supplierId, int quantity)

// ❌ 不描述行为的名称  
public Task<object> Execute(JsonObject args)

注册时机:在应用程序/测试的入口点一次性注册,不在请求处理中动态注册:

// Program.cs 或 测试入口
AgentToolSetRegistry.Global
    .Register<NeedsAnalysisService>()
    .Register<SupplierSearchService>()
    .Register<ComplianceCheckService>();

2.4 上下文传递规范

多 Agent 之间通过共享变量键(Variable Key)传递数据,键名在代码中集中定义为常量:

// ✅ 在测试/应用入口集中定义
private const string VarPurchaseRequest        = "PurchaseRequest";
private const string VarStructuredRequirements = "StructuredRequirements";
private const string VarSupplierQuotes         = "SupplierQuotes";

// ✅ 数据流配置与工具注册分离
["SupplierSearch"] = new(InputKey: VarStructuredRequirements,
                         OutputKey: VarSupplierQuotes)

3. 核心架构设计

3.1 整体架构图

┌──────────────────────────────────────────────────────────────────┐
│                    Slickflow.AI 多智能体架构                       │
│                                                                  │
│  ┌─────────────┐    ┌─────────────────────────────────────────┐ │
│  │  BPMN 设计器 │    │              Slickflow.Engine            │ │
│  │             │    │                                         │ │
│  │ toolSetName ├───►│  WorkflowService → ProcessModelFactory  │ │
│  │ SystemPrompt│    │  AIServiceExecutor → AgentMultiTurnService│ │
│  └─────────────┘    └──────────────┬──────────────────────────┘ │
│                                    │                             │
│                    ┌───────────────▼──────────────────────────┐ │
│                    │           Slickflow.AI / Agent            │ │
│                    │                                          │ │
│                    │  AgentToolSetRegistry                    │ │
│                    │    toolSetName → IReadOnlyList<IAgentTool>│ │
│                    │                  │                       │ │
│                    │  AgentToolRegistry                       │ │
│                    │    activityId → IReadOnlyList<IAgentTool> │ │
│                    │                  │                       │ │
│                    │  AgentNodeBase (ReAct Loop)              │ │
│                    │    Reason → Act → Observe → ...          │ │
│                    │                  │                       │ │
│                    │  OpenAIToolCallLlmClient                 │ │
│                    │    HTTP POST (tools + messages)          │ │
│                    └──────────────────┼───────────────────────┘ │
│                                       │                          │
│                    ┌──────────────────▼───────────────────────┐ │
│                    │         业务工具层 (ToolSets)              │ │
│                    │                                          │ │
│                    │  [AgentToolSet("SupplierSearch")]        │ │
│                    │  class SupplierSearchService             │ │
│                    │  {                                       │ │
│                    │    [AgentTool("搜索供应商")]              │ │
│                    │    Task<List<Supplier>> SearchSuppliers()│ │
│                    │  }                                       │ │
│                    └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘

3.2 ReAct 循环

每个 Agent 节点执行 ReAct(Reason → Act → Observe) 循环,直到 LLM 给出最终答案:

用户输入 / 上一个 Agent 输出
        │
        ▼
┌───────────────────────────────────────────────┐
│  Iteration 1                                  │
│  Reason: LLM 收到输入 + 工具定义 → 决策       │
│  Act:    LLM 返回 finish_reason="tool_calls"  │
│          → 调用 search_suppliers(category=IT) │
│  Observe: 工具返回 [SUP001, SUP002, SUP003]   │
├───────────────────────────────────────────────┤
│  Iteration 2                                  │
│  Reason: LLM 收到工具结果 → 继续决策           │
│  Act:    调用 request_quote(supplierId=SUP002) │
│  Observe: 返回报价 ¥2950×10=¥29500            │
├───────────────────────────────────────────────┤
│  Iteration 3                                  │
│  Reason: LLM 综合所有结果                      │
│  → finish_reason="stop"(最终答案)            │
└───────────────────────────────────────────────┘
        │
        ▼
最终文本输出 → 写入 OutputVariableKey → 下一个 Agent 的输入

循环保护MaxIterations(默认 10)防止死循环,超出后返回降级答案。

3.3 工具注册体系

两层注册表实现"逻辑名 → 活动 ID"的解耦:

AgentToolSetRegistry(名称注册)
  "SupplierSearch" → IReadOnlyList<IAgentTool>
        │
        │ TryResolveToActivityRegistry(toolSetName, activityId)
        ▼
AgentToolRegistry(活动注册)
  "Activity_ABC123" → IReadOnlyList<IAgentTool>
        │
        │ 引擎执行节点时调用
        ▼
  AgentNodeBase.ExecuteReActAsync()

这样做的好处:BPMN 定义里的 activityId 是运行时才知道的(每个流程实例可能不同),toolSetName 才是设计时确定的。两层注册表在运行时完成映射。

3.4 共享记忆(AgentConversationMemory)

多个 Agent 节点通过 AgentConversationMemory 共享输出,实现跨节点的上下文传递:

// Agent₁ 写入
AgentConversationMemory.RecordOutput(
    processInstanceId, activityId, "StructuredRequirements", result);

// Agent₂ 可以读取 Agent₁ 的输出(通过 sharedVars 传递)
var input = sharedVars["StructuredRequirements"];

记忆以 processInstanceId 为隔离键,流程实例结束后调用 Evict() 释放。


4. 属性化工具注册(当前实现)

4.1 问题与方案

问题:早期实现使用 lambda + 手写 JSON Schema,框架代码和业务代码混在一起:

// ❌ 旧方式:开发者需要理解 JsonObject、AgentToolResult 等框架类型
.Register("quote_request", "向供应商请求报价",
    Schema("""{"type":"object","properties":{"supplierId":{"type":"string"},...}}"""),
    async (args, ct) => {
        var suppId = args["supplierId"]?.GetValue<string>() ?? "";
        return new AgentToolResult(true, JsonSerializer.Serialize(result));
    })

方案:通过 [AgentToolSet] / [AgentTool] 属性 + 反射引擎,业务开发者只写普通 Service 类:

// ✅ 新方式:普通 C# 类,无框架代码
[AgentToolSet("SupplierSearch")]
public class SupplierSearchService
{
    [AgentTool("向指定供应商发起报价请求,返回单价、货期和总金额")]
    public async Task<SupplierQuote> RequestQuote(string supplierId, int quantity)
    {
        // 纯业务逻辑
        return new SupplierQuote { SupplierId = supplierId, UnitPrice = 2950m };
    }
}

4.2 反射引擎(AgentToolReflector)工作原理

AgentToolReflector.BuildToolsFromType<T>() 扫描类的方法,自动完成:

框架任务 自动化方式
JSON Schema 生成 方法参数类型 → {"type":"string"/"integer"/"number"...}
工具名称 方法名 PascalCase → snake_case(RequestQuoterequest_quote
参数绑定 JsonObject args["supplierId"]string supplierId
可选参数 default 值的参数不进入 required 数组
异步支持 Task<T> → 自动 await,提取 Result
返回值序列化 强类型返回值 → JsonSerializer.Serialize() → LLM 可读字符串
CancellationToken 自动注入,不出现在 Schema 中

4.3 注册扩展:Register<T>() 泛型重载

AgentToolSetRegistry 增加泛型重载,从属性读取 toolSetName,无需重复书写字符串:

// AgentToolSetRegistry.Register<T>() 内部实现
public AgentToolSetRegistry Register<T>() where T : class, new()
{
    var attr      = typeof(T).GetCustomAttribute<AgentToolSetAttribute>();
    var toolSetName = attr.Name;                          // 从属性读
    var tools       = AgentToolReflector.BuildToolsFromType(typeof(T)); // 反射构建
    _store[toolSetName] = () => tools;
    return this;
}

5. 采购流程多智能体演示

5.1 业务场景

企业员工提交采购需求后,由 5 个 AI Agent 节点依次处理,全程无需人工干预,最终自动生成采购订单。

5.2 流程节点设计

用户提交采购需求
        │
        ▼
┌──────────────────┐
│  NeedsAnalysis   │  分析需求,提取品类和规格
│  [Agent 节点]    │  工具:ClassifyCategory / ExtractSpecs
└────────┬─────────┘
         │ StructuredRequirements(结构化需求)
         ▼
┌──────────────────┐
│  SupplierSearch  │  搜索供应商,获取报价
│  [Agent 节点]    │  工具:SearchSuppliers / RequestQuote
└────────┬─────────┘
         │ SupplierQuotes(供应商报价列表)
         ▼
┌──────────────────┐
│ ComplianceCheck  │  合规审查(并行支持)
│  [Agent 节点]    │  工具:CheckRegulations / CheckBlacklist
└────────┬─────────┘
         │ ComplianceReport(合规报告)
         ▼
┌──────────────────┐
│ PriceEvaluation  │  综合评估,推荐最优方案
│  [Agent 节点]    │  工具:CalculateTco(总拥有成本)
└────────┬─────────┘
         │ PurchaseRecommendation(采购建议)
         ▼
┌──────────────────┐
│  OrderExecution  │  在 ERP 中创建采购订单
│  [Agent 节点]    │  工具:CreatePurchaseOrder
└────────┬─────────┘
         │ PurchaseOrderId(订单号)
         ▼
     采购完成

流程图示例:
QQ_1780275964234

5.3 Agent 节点定义(Service 类)

需求分析服务

[AgentToolSet("NeedsAnalysis")]
public class NeedsAnalysisService
{
    [AgentTool("根据采购物品描述,识别采购类别代码")]
    public string ClassifyCategory(string description)
    {
        return description.Contains("router", StringComparison.OrdinalIgnoreCase)
            ? "IT_HARDWARE" : "GENERAL";
    }

    [AgentTool("从采购描述中提取规格参数,返回数量、单位和技术规格")]
    public async Task<ItemSpec> ExtractSpecs(string text, string category)
    {
        await Task.Delay(5); // 实际场景:调用 NLP 服务或规格库
        return new ItemSpec { Quantity = 10, Unit = "units",
                              Specification = "5G/LTE, DIN rail, -40~70°C, IPX5" };
    }
}

供应商搜索服务

[AgentToolSet("SupplierSearch")]
public class SupplierSearchService
{
    [AgentTool("搜索供应商目录,返回符合条件的供应商列表")]
    public async Task<List<Supplier>> SearchSuppliers(string category, string specification = "")
    {
        // 实际场景:查询供应商数据库
        return new List<Supplier>
        {
            new() { SupplierId = "SUP001", Name = "TechNet Industrial Ltd", Rating = 4.2 },
            new() { SupplierId = "SUP002", Name = "GlobalRouter Solutions",  Rating = 4.5 },
        };
    }

    [AgentTool("向指定供应商发起报价请求,返回单价、货期和总金额")]
    public async Task<SupplierQuote> RequestQuote(string supplierId, int quantity)
    {
        // 实际场景:调用供应商门户 API 或 EDI 接口
        return new SupplierQuote { SupplierId = supplierId, UnitPrice = 2950m,
                                   LeadTimeDays = 10, QualityScore = 4.5,
                                   TotalAmount = 2950m * quantity };
    }
}

5.4 数据流配置

private static readonly IReadOnlyDictionary<string, AgentRunConfig> RunConfigs =
    new Dictionary<string, AgentRunConfig>(StringComparer.OrdinalIgnoreCase)
    {
        ["NeedsAnalysis"]  = new(InputKey: "PurchaseRequest",        OutputKey: "StructuredRequirements"),
        ["SupplierSearch"] = new(InputKey: "StructuredRequirements", OutputKey: "SupplierQuotes"),
        ["ComplianceCheck"]= new(InputKey: "StructuredRequirements", OutputKey: "ComplianceReport"),
        ["PriceEvaluation"]= new(InputKey: "SupplierQuotes",         OutputKey: "PurchaseRecommendation"),
        ["OrderExecution"] = new(InputKey: "PurchaseRecommendation", OutputKey: "PurchaseOrderId")
    };

5.5 启动注册(一次性)

// 应用启动时(Program.cs 或测试入口)
AgentToolSetRegistry.Global
    .Register<NeedsAnalysisService>()
    .Register<SupplierSearchService>()
    .Register<ComplianceCheckService>()
    .Register<PriceEvaluationService>()
    .Register<OrderExecutionService>();

5.6 BPMN 侧配置(设计器)

流程设计师在 BPMN 属性面板为每个 Agent 节点设置:

属性 说明
type Agent 节点类型
toolSetName SupplierSearch 与注册名称对应
system_prompt 存入 ai_activity_config 角色定义,可数据库配置

5.7 运行日志示例

=== WorkflowDrivenProcurementTest ===
    ProcessCode : SmartProcurement  Version: 1
    Model       : qwen-plus

[OK] Loaded process: 智能采购流程  (id=1001)
[OK] Found 5 Agent node(s):
       [NeedsAnalysis]   toolSetName=NeedsAnalysis   id=Activity_001
       [SupplierSearch]  toolSetName=SupplierSearch   id=Activity_002
       [ComplianceCheck] toolSetName=ComplianceCheck  id=Activity_003
       [PriceEvaluation] toolSetName=PriceEvaluation  id=Activity_004
       [OrderExecution]  toolSetName=OrderExecution   id=Activity_005

─── Agent 1/5: NeedsAnalysis [NeedsAnalysis] ───
[Agent] ReAct iteration 1/8
[Agent][LLM] POST ... model=qwen-plus tools=2 msgs=2
[Agent][LLM] tool_calls: classify_category id=call_001
[Agent] Calling tool 'classify_category' | args={"description":"...routers..."}
    [NeedsAnalysisService.ClassifyCategory] → IT_HARDWARE
[Agent] ReAct iteration 2/8
[Agent][LLM] tool_calls: extract_specs id=call_002
    [NeedsAnalysisService.ExtractSpecs] 提取规格中...
[Agent] ReAct iteration 3/8
[Agent][LLM] text response (256 chars)
[Agent] Final answer produced

─── Agent 2/5: SupplierSearch [SupplierSearch] ───
...
    [SupplierSearchService.SearchSuppliers] 搜索中...
    [SupplierSearchService.RequestQuote] SUP002 → ¥2950×10
...

─── Agent 5/5: OrderExecution [OrderExecution] ───
    [OrderExecutionService.CreatePurchaseOrder] 已创建 PO-20260531-7823

═══════════════════════════════════════
  采购完成  订单号:PO-20260531-7823
  供应商:GlobalRouter Solutions
  金额:¥29,500
═══════════════════════════════════════

6. 落地路线图

当前实现(属性化 Service 类)解决了"开发者写代码"的体验问题,但面向企业客户还有更深一层的问题:谁来为每家客户写那些 Service 类?

三个阶段的答案是:从"写代码"演进到"填配置",最终达到"零配置自发现"。


6.1 近期:预置企业工具库

核心思想:平台方提前实现 80% 的高频企业操作,客户只需选择并配置,不需要写代码。

工具库分类设计

Slickflow.AI.Enterprise.Tools/
├── ErpTools/
│   ├── InventoryQueryTool      查库存
│   ├── PurchaseOrderTool       创建/查询采购订单
│   ├── GoodsReceiptTool        收货确认
│   └── VendorMasterTool        供应商主数据查询
│
├── ApprovalTools/
│   ├── StartApprovalTool       发起审批(钉钉/企微/飞书/OA)
│   ├── ApprovalStatusTool      查询审批状态
│   ├── ApprovalUrgerTool       审批催办
│   └── ConditionalBranchTool   条件判断(金额/部门/级别)
│
├── HrTools/
│   ├── EmployeeQueryTool       查询人员信息
│   ├── LeaveBalanceTool        假期余额查询
│   ├── OrgChartTool            组织架构查询
│   └── AttendanceTool          考勤记录查询
│
├── NotifyTools/
│   ├── EmailSendTool           发送邮件
│   ├── DingTalkMsgTool         钉钉消息
│   ├── WeChatWorkMsgTool       企业微信消息
│   └── TodoCreateTool          创建待办事项
│
└── DataTools/
    ├── SqlQueryTool            参数化 SQL 查询(只读)
    ├── FormDataWriteTool       写入表单数据
    └── ReportQueryTool         报表数据查询

配置化设计(以 ERP 为例)

工具类通过配置文件或数据库读取连接参数,不硬编码:

[AgentToolSet("ErpInventory")]
public class InventoryQueryTools
{
    private readonly ErpConfig _config;

    public InventoryQueryTools()
    {
        // 从 appsettings.json 或数据库读取
        _config = ErpConfigLoader.Load("ERP_MAIN");
    }

    [AgentTool("查询指定物料的当前库存数量和仓库分布")]
    public async Task<InventoryResult> QueryInventory(string materialCode, string warehouse = "")
    {
        // 调用配置的 ERP 接口
        return await _config.ErpClient.GetInventoryAsync(materialCode, warehouse);
    }
}
// appsettings.json
{
  "ErpConfigs": {
    "ERP_MAIN": {
      "BaseUrl": "http://erp.company.com/api",
      "ApiKey": "sk-xxx",
      "Timeout": 30
    }
  }
}

注册方式(集成时)

// 客户集成时,只需选择需要的工具集并配置连接参数
AgentToolSetRegistry.Global
    .Register<InventoryQueryTools>()    // 平台预置
    .Register<PurchaseOrderTools>()     // 平台预置
    .Register<DingTalkApprovalTools>()  // 平台预置
    // 以下才是客户自己写的业务特定工具
    .Register<CustomerSpecificPricingTools>();

覆盖范围预估

场景 预置工具覆盖率
采购申请审批 ~90%
费用报销 ~85%
员工入职 ~80%
合同审批 ~75%
客户拜访管理 ~70%

6.2 中期:声明式 HTTP 工具适配器

核心思想:为 REST API 类工具提供 JSON/数据库配置方式,业务人员在设计器里填写 API 地址和参数映射,不需要写任何 C# 代码

工具描述格式(存储在数据库)

{
  "toolSetName": "SupplierPortalTools",
  "tools": [
    {
      "name": "search_suppliers",
      "description": "搜索供应商目录,返回符合条件的供应商列表",
      "type": "http",
      "method": "GET",
      "url": "http://supplier-portal.company.com/api/suppliers",
      "headers": {
        "Authorization": "Bearer {{config.ApiToken}}",
        "Content-Type": "application/json"
      },
      "parameters": [
        { "name": "category",      "type": "string",  "required": true,  "in": "query" },
        { "name": "specification", "type": "string",  "required": false, "in": "query" }
      ],
      "responseMapping": "$.suppliers"
    },
    {
      "name": "request_quote",
      "description": "向指定供应商请求报价",
      "type": "http",
      "method": "POST",
      "url": "http://supplier-portal.company.com/api/quotes",
      "body": {
        "supplierId": "{{args.supplierId}}",
        "quantity":   "{{args.quantity}}"
      },
      "parameters": [
        { "name": "supplierId", "type": "string",  "required": true },
        { "name": "quantity",   "type": "integer", "required": true }
      ]
    }
  ]
}

框架层:HttpToolAdapter

// 框架层新增,业务开发者不接触
public sealed class HttpToolAdapter : IAgentTool
{
    private readonly HttpToolDescriptor _descriptor;
    private readonly IHttpClientFactory _httpFactory;

    public string     Name        => _descriptor.Name;
    public string     Description => _descriptor.Description;
    public JsonObject InputSchema  => BuildSchemaFromDescriptor(_descriptor);

    public async Task<AgentToolResult> ExecuteAsync(JsonObject args, CancellationToken ct)
    {
        var url     = ResolveTemplate(_descriptor.Url, args);
        var headers = ResolveHeaders(_descriptor.Headers);
        var body    = _descriptor.Method == "POST" ? ResolveBody(_descriptor.Body, args) : null;

        var response = await _httpFactory
            .CreateClient()
            .SendAsync(BuildRequest(url, headers, body, _descriptor.Method), ct);

        var json = await response.Content.ReadAsStringAsync(ct);
        return new AgentToolResult(response.IsSuccessStatusCode, json);
    }
}

注册方式(数据库驱动)

// 框架启动时,从数据库加载所有声明式工具集
var toolSetDescriptors = await db.LoadHttpToolSetDescriptors();
foreach (var descriptor in toolSetDescriptors)
{
    var tools = descriptor.Tools
        .Select(t => new HttpToolAdapter(t, httpFactory))
        .ToList();
    AgentToolSetRegistry.Global.RegisterTools(descriptor.ToolSetName, tools);
}

设计器集成

BPMN 设计器新增"HTTP 工具配置"面板,业务人员直接在界面上:

  1. 填写 API Endpoint
  2. 拖拽参数映射
  3. 测试连接并保存

这一步实现后,新增一个企业系统集成的成本从"写代码+部署"降为"填表单+保存"。


6.3 长期:MCP 协议集成

核心思想:企业各系统各自部署 MCP Server(Model Context Protocol),Agent 节点通过标准协议动态发现和调用工具,平台侧零代码、零配置完成集成。

MCP 是由 Anthropic 推动的 AI 工具标准协议,OpenAI、Microsoft 等主流厂商均已跟进支持。

架构图

┌─────────────────────────────────────────────────────────┐
│                  Slickflow Agent 节点                     │
│                                                         │
│  AgentNodeBase (ReAct Loop)                             │
│       │                                                 │
│       │ Tools = McpClientTool × N                       │
│       ▼                                                 │
│  McpServerClient (已实现)                               │
│       │                                                 │
│       │ JSON-RPC 2.0                                    │
└───────┼─────────────────────────────────────────────────┘
        │
        ├──► MCP Server (ERP 系统)
        │        tools/list → [query_inventory, create_order, ...]
        │        tools/call → 执行并返回结果
        │
        ├──► MCP Server (CRM 系统)
        │        tools/list → [get_customer, update_opportunity, ...]
        │
        ├──► MCP Server (OA 审批系统)
        │        tools/list → [start_approval, get_status, urge_approval]
        │
        └──► MCP Server (第三方供应商门户)
                 tools/list → [search_suppliers, request_quote, ...]

项目现有基础:McpClientTool

// 已实现:source/core/Slickflow.AI/Agent/Tools/McpClientTool.cs
public sealed class McpClientTool : IAgentTool
{
    // JSON-RPC 2.0 代理,自动发现并调用 MCP Server 暴露的工具
    public Task<AgentToolResult> ExecuteAsync(JsonObject args, CancellationToken ct)
        => _mcpClient.CallAsync(_toolName, args, ct);
}

使用方式(设计时)

// BPMN 节点配置 MCP Server 地址
// sf:AiService mcpServerUrl="http://erp.company.com/mcp"
//              toolSetName="ErpTools"(自动发现,不需要预注册)

// 引擎运行时自动执行:
var mcpClient = new McpServerClient(mcpServerUrl);
var tools     = await mcpClient.DiscoverToolsAsync();  // 自动获取工具列表
AgentToolRegistry.Global.Register(activityId, tools);

MCP Server 部署参考(企业侧)

以 ERP 系统为例,企业只需在 ERP 旁边部署一个轻量 MCP Server(提供商已有 SDK):

ERP 主系统                MCP Server(新增)
   │                           │
   │  内部调用                  │ JSON-RPC 2.0(供 Agent 使用)
   ◄──────────────────────────►│
                               │
                    ┌──────────┘
                    │  暴露的工具:
                    │  - query_inventory
                    │  - create_purchase_order
                    │  - check_vendor_status

三阶段能力对比

维度 近期(预置工具库) 中期(声明式 HTTP) 长期(MCP 协议)
接入新系统的工作量 写 C# Service 类 填 JSON 配置表单 部署 MCP Server
需要开发人员参与 否(配置即可) 否(标准协议)
工具更新方式 代码发布 修改数据库配置 MCP Server 动态更新
适用范围 高频标准场景 任意 REST API 任意支持 MCP 的系统
技术门槛 低(写普通类) 极低(填表单) 中(部署 MCP Server)

7. 自然语言驱动多智能体全流程生成

7.1 现有基础与补充目标

Slickflow 产品已具备自然语言 → BPMN 流程图的生成能力:用户用中文描述业务场景,LLM 自动生成对应的 BPMN XML,并在设计器中渲染出可编辑的流程图。

将这一能力延伸到多智能体场景,面临一个新问题:

现有能力(已有):
  "我需要一个采购审批流程" → LLM → BPMN 结构(节点 + 连线)

需要补充的能力(新增):
  BPMN 结构中的 Agent 节点 → 需要进一步配置:
    ① toolSetName(绑定哪个工具集)
    ② System Prompt(角色定义)
    ③ 输入/输出变量键(数据流)
    ④ MaxIterations、模型选择等参数

这些 Agent 专属配置无法完全从自然语言描述中一次性推断,需要一套分层生成 + 人工确认的补充方案。


7.2 三层生成架构

整体方案分三层,依次递进:

┌────────────────────────────────────────────────────────────────┐
│  第一层:自然语言 → BPMN 结构(已有功能延伸)                    │
│                                                                │
│  用户输入:"我需要一个采购审批流程,包括供应商查询、合规审查        │
│           和价格评估,金额超过 50 万需要人工审批"               │
│                                                                │
│  LLM 输出:                                                    │
│    ① BPMN XML(含 Agent 节点类型标记)                          │
│    ② 每个 Agent 节点的语义描述("供应商查询节点")               │
│    ③ 初步推断的数据流(输入/输出变量名建议)                     │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│  第二层:Agent 节点配置(AI 预填 + 表单确认)                    │
│                                                                │
│  对于 BPMN 中识别到的每个 Agent 节点,AI 自动:                  │
│    ① 从现有 toolSetName 注册表中模糊匹配,推荐最接近的工具集      │
│    ② 根据节点语义生成 System Prompt 草稿                        │
│    ③ 推断 InputKey / OutputKey(基于上下游节点关系)             │
│                                                                │
│  用户在属性面板:确认 or 修改(低成本,不需从零填写)             │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│  第三层:缺失工具集的代码生成(Claude Code CLI)                  │
│                                                                │
│  当第二层推荐的 toolSetName 不存在(注册表中没有匹配项时):       │
│    ① 用户在设计器中点击"生成工具类"按钮                          │
│    ② 填写 API 描述或上传 OpenAPI Spec                           │
│    ③ 调用 Claude Code 生成 [AgentToolSet] C# 代码               │
│    ④ 开发者 Review → 注册到工具库 → 回填 toolSetName            │
└────────────────────────────────────────────────────────────────┘

7.3 表单辅助配置层

第二层的核心是一个智能预填的属性面板,在 BPMN 设计器中每个 Agent 节点的侧边栏展示。

AI 预填逻辑(服务端)

// 当 BPMN 中检测到 Agent 节点时,后端自动执行预填推断
public sealed class AgentNodeConfigSuggester
{
    private readonly AgentToolSetRegistry _registry;
    private readonly ILlmClient           _llm;

    /// <summary>
    /// 为一个 Agent 节点生成配置建议
    /// 输入:节点的语义描述 + 上下游节点信息 + 已有注册表
    /// 输出:预填的 AgentNodeConfig(用户可在面板中修改)
    /// </summary>
    public async Task<AgentNodeConfigSuggestion> SuggestAsync(
        string nodeDescription,    // "查询供应商并获取报价"
        string upstreamOutputKey,  // 上游节点的 OutputKey(如 "StructuredRequirements")
        string downstreamHint)     // 下游节点的语义(如 "合规审查")
    {
        // 1. 从注册表中获取所有可用 toolSetName
        var availableToolSets = _registry.GetAllToolSetNames();

        // 2. 让 LLM 从中选择最匹配的,并生成其他配置
        var prompt = $"""
            已注册的工具集列表:{string.Join(", ", availableToolSets)}
            
            当前 Agent 节点描述:{nodeDescription}
            上游节点的输出变量:{upstreamOutputKey}
            下游节点的用途:{downstreamHint}
            
            请输出 JSON,包含:
            - toolSetName: 从已注册列表中选择最匹配的(没有匹配时输出 null)
            - systemPrompt: 根据节点描述生成的角色定义(100字以内)
            - inputKey: 建议的输入变量名
            - outputKey: 建议的输出变量名
            - confidence: 推荐置信度(high/medium/low)
            只输出 JSON。
            """;

        var json = await _llm.CompleteAsync(prompt);
        return JsonSerializer.Deserialize<AgentNodeConfigSuggestion>(json)!;
    }
}

public sealed record AgentNodeConfigSuggestion(
    string?  ToolSetName,     // null 表示未找到匹配,需要生成
    string   SystemPrompt,
    string   InputKey,
    string   OutputKey,
    string   Confidence);     // "high" / "medium" / "low"

属性面板 UI 行为

Agent 节点属性面板(设计器侧边栏)
┌─────────────────────────────────────────┐
│  节点名称:供应商查询                     │
│                                         │
│  工具集 (toolSetName)                   │
│  ┌─────────────────────────┐ [生成代码] │
│  │ SupplierSearch ✓ AI推荐  │           │
│  └─────────────────────────┘           │
│  置信度:● 高  ( 可从下拉列表选其他 )    │
│                                         │
│  System Prompt                          │
│  ┌─────────────────────────────────┐   │
│  │ 你是供应商查询专家,负责根据采购  │   │
│  │ 规格搜索合适供应商并获取报价...   │   │
│  └─────────────────────────────────┘   │
│  [AI 重新生成]                          │
│                                         │
│  输入变量:StructuredRequirements       │
│  输出变量:SupplierQuotes               │
│                                         │
│  最大迭代:10   模型:claude-sonnet     │
│                                         │
│         [确认配置]  [重置]              │
└─────────────────────────────────────────┘

⚠ 当 toolSetName = null 时,面板显示:
┌─────────────────────────────────────────┐
│  ⚠ 未找到匹配的工具集                   │
│  请选择:                               │
│  ○ 从预置库选择(近似功能)              │
│  ● 声明式 HTTP 配置(填写 API 地址)     │
│  ○ 生成 C# 工具类(Claude Code)        │
└─────────────────────────────────────────┘

7.4 Claude Code 工具类生成

当没有现成工具集时,第三层方案是通过 Claude Code CLI 直接生成符合 Slickflow Harness 规范的 [AgentToolSet] C# 代码。

两种触发方式

方式一:设计器内嵌调用

在属性面板点击"生成工具类"后,设计器将用户填写的接口描述组装成 Prompt,通过后端调用 Anthropic API,在界面中实时展示生成的代码供 Review:

// 后端:AgentToolCodeGenerator.cs
public sealed class AgentToolCodeGenerator
{
    private readonly ILlmClient _claude;

    public async Task<string> GenerateToolSetAsync(ToolGenerationRequest request)
    {
        var prompt = $"""
            请生成一个符合 Slickflow Harness 规范的 C# AgentToolSet 类。
            
            工具集名称:{request.ToolSetName}
            业务描述:{request.Description}
            API 信息:{request.ApiDescription}
            
            规范要求:
            1. 类上标注 [AgentToolSet("{request.ToolSetName}")]
            2. 每个方法标注 [AgentTool("工具功能描述")]
            3. 使用强类型参数和返回值,不使用 JsonObject
            4. 异步方法返回 Task<T>
            5. 通过构造函数注入 HttpClient 或配置类
            
            参考现有规范:
            [AgentToolSet("SupplierSearch")]
            public class SupplierSearchService
            {{
                [AgentTool("搜索供应商目录,返回符合条件的供应商列表")]
                public async Task<List<Supplier>> SearchSuppliers(string category) {{ ... }}
            }}
            
            只输出 C# 代码,不要额外解释。
            """;

        return await _claude.CompleteAsync(prompt);
    }
}

public sealed record ToolGenerationRequest(
    string ToolSetName,
    string Description,
    string ApiDescription);    // 用户填写的 API 说明,或上传的 OpenAPI Spec JSON

方式二:Claude Code CLI 命令行

开发者也可以在终端直接调用 Claude Code,适合在本地开发环境中快速生成:

# 基于描述生成工具类
claude "根据以下 Slickflow Harness 规范,生成一个 C# AgentToolSet 类。
工具集名称:InventoryQuery
业务场景:查询 SAP 库存系统,支持按物料编码查询库存数量和仓库分布。
API endpoint:GET http://sap.company.com/api/inventory/{materialCode}
参考规范:[AgentToolSet] + [AgentTool] 属性化注册,强类型返回值,构造函数注入 HttpClient。"

# 基于 OpenAPI Spec 文件生成工具类
claude "读取 ./supplier-portal-openapi.json,为 Slickflow Harness 框架生成
对应的 [AgentToolSet] C# 类,仅包含 GET /suppliers 和 POST /quotes 两个接口,
类名为 SupplierPortalTools。"

生成结果示例

// Claude Code 生成的代码(开发者 Review 后直接使用)
[AgentToolSet("InventoryQuery")]
public class InventoryQueryService
{
    private readonly HttpClient _http;

    public InventoryQueryService(IHttpClientFactory httpFactory)
    {
        _http = httpFactory.CreateClient("SapInventory");
    }

    [AgentTool("查询指定物料编码的当前库存数量,支持按仓库筛选")]
    public async Task<InventoryResult> QueryStock(
        string materialCode,
        string warehouse = "")
    {
        var url = string.IsNullOrEmpty(warehouse)
            ? $"/api/inventory/{materialCode}"
            : $"/api/inventory/{materialCode}?warehouse={warehouse}";

        var response = await _http.GetFromJsonAsync<SapInventoryResponse>(url);
        return new InventoryResult
        {
            MaterialCode = materialCode,
            Quantity     = response?.Quantity ?? 0,
            Warehouse    = response?.Warehouse ?? warehouse,
            Unit         = response?.Unit ?? "EA"
        };
    }

    [AgentTool("批量查询多个物料的库存汇总,返回可用/缺货状态")]
    public async Task<List<InventoryResult>> QueryBatchStock(List<string> materialCodes)
    {
        var tasks = materialCodes.Select(code => QueryStock(code));
        return (await Task.WhenAll(tasks)).ToList();
    }
}

生成后的接入流程

① 设计器界面点击"生成工具类",填写接口描述
        │
        ▼
② 后端调用 LLM(或 Claude Code CLI),生成 C# 代码
        │
        ▼
③ 设计器弹出代码预览窗口,开发者 Review + 小改
        │
        ▼
④ 开发者将代码保存到 ToolSets/ 目录,提交并部署
        │
        ▼
⑤ 在 Program.cs 注册:AgentToolSetRegistry.Global.Register<InventoryQueryService>()
        │
        ▼
⑥ 设计器属性面板的 toolSetName 下拉列表中出现新工具集,回填到 Agent 节点
        │
        ▼
⑦ 全流程配置完成,可以执行

7.5 三种交互模式对比

根据用户角色和场景复杂度,自然语言生成多智能体流程有三种落地模式:

模式 适用场景 操作路径 工具集来源
A. 全自动模式 需求完全匹配预置工具库 NL → BPMN → AI 预填配置 → 一键确认 预置工具库
B. 表单辅助模式 工具集存在但需自定义 HTTP API NL → BPMN → 表单填写 API 地址 → 保存 声明式 HTTP 适配器
C. 代码生成模式 需要全新工具集 NL → BPMN → Claude Code 生成类 → Review 注册 AI 生成 C# 代码

预期用户体验

普通业务人员(无代码):
  用自然语言描述 → 流程图自动生成 → 从预置工具库选择 → 确认 → 运行
  全程 5-10 分钟,零代码

集成工程师(低代码):
  自然语言生成框架 → 填写 HTTP API 表单 → 测试连通 → 保存
  全程 30 分钟,零 C# 代码

开发者(有代码能力):
  自然语言生成框架 → Claude Code 生成工具类 → Review + 小改 → 注册
  全程 1-2 小时,大量代码由 AI 生成

当前可实现程度

子能力 现状 所需工作
NL → BPMN 结构 ✅ 已有 增加 Agent 节点类型识别
AI 预填 toolSetName 🔧 可实现 接入注册表的模糊匹配 API
AI 生成 System Prompt 🔧 可实现 复用现有 LLM 调用能力
表单式 HTTP 工具配置 🔧 规划中(6.2 章节) 中期工作
Claude Code 工具类生成 🔧 可实现 接入 Anthropic API,增加代码预览组件
生成代码自动注册 ⚠ 需谨慎 安全评估后再考虑自动化

8. 总结

8.1 核心设计决策

决策 原因
ReAct 循环代替单次 LLM 调用 复杂任务需要多步推理和工具协作,单次调用无法完成
两层注册表(SetRegistry + Registry) toolSetName 是设计时名称,activityId 是运行时名称,两者必须解耦
属性化工具注册代替 lambda 业务开发者不应接触框架细节,Service 类可读性更高、可测试性更强
BPMN 驱动代替硬编码节点顺序 流程结构由设计师在 BPMN 里调整,不需要改代码
共享变量传递上下文 Agent 之间通过键值对共享状态,避免强耦合

8.2 开发者工作量变化

                   框架代码  |  业务代码
                             |
旧方式(lambda)  ████████   |  ██
新方式(属性化)  ░░░░░░░░   |  ████████
近期(预置库)    ░░░░░░░░   |  ██(选配置)
中期(声明式)    ░░░░░░░░   |  █(填表单)
长期(MCP)       ░░░░░░░░   |  ░(零代码)
NL 生成(新增)   ░░░░░░░░   |  ░(自然语言描述)

本文档描述的所有代码均已在 source/core/Slickflow.AI/Agent/
source/test/Slickflow.ConsoleTest/MultiAgent/ 目录下实现并通过编译验证


文章来源:https://www.cnblogs.com/slickflow/p/20245331
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云