Agent Matching
给定一个
skillId + subDomain,从可用 Agent 中选出最合适的几个。评分是纯内存计算,不依赖外部服务。
职责
| 负责 | 不负责 |
|---|---|
| 四维加权评分 | 执行 Agent |
| 供给方去重 | 审核上架 |
| 批量匹配子任务 | 定义 Skill |
| 返回评分理由 | 处理支付 / 结算 |
评分模型
| 维度 | 权重 | 规则 |
|---|---|---|
| 能力 | 40% | skillId 精确匹配 +45;subDomain 匹配 +35;基础分 20 |
| 质量 | 20% | 准确率 60% + 执行量 40%(上限 50 次) |
| 价格 | 20% | ≤$50 → 100;≤$100 → 85;≤$200 → 70;≤$500 → 50 |
| 速度 | 20% | SLA ≤2min → 100;≤5min → 80;≤10min → 60;≤30min → 50 |
总分:
total = capability×0.4 + quality×0.2 + price×0.2 + speed×0.2去重
同一供给方(ownerId)只保留最高分的 Agent,避免一个企业用多个 Profile 垄断结果。
输出
json
{
"profile": { "agentId": "...", "name": "..." },
"scores": {
"capability": 95,
"quality": 88,
"price": 70,
"speed": 80
},
"totalScore": 85.9,
"reasons": ["skillId 精确匹配", "SLA 5 分钟"]
}平台默认返回 top-3,前端展示供用户选择。
接口
模块没有 HTTP controller,由调用方注入:
| 方法 | 用途 |
|---|---|
match(skillId, subDomain) | 单个子任务匹配 |
matchForSubTask(subDomain, entities) | 旧接口,逐步迁移 |
调用方:
demand-translation:翻译后逐个子任务匹配chat-execute:prepare 阶段agent-gateway:对话会话创建时选择 Agent
关键流程
match(skillId, subDomain)
├─ 查询 agent_profiles: status=active
├─ 过滤 skillIds 包含 skillId 或 subDomain 匹配
├─ 计算四维分数
├─ 加权求和
├─ 按 ownerId 去重
├─ 按 totalScore 降序
└─ 返回 top-N边界与限制
| 限制 | 说明 |
|---|---|
| 权重固定 | 当前硬编码,尚未做成策略设置 |
| 默认 domain | 历史上硬编码为 compliance,新接口已按参数传入 |
| 无匹配 | 返回空数组,由调用方创建占位节点 |
| 无实时负载 | 不感知 Agent 当前队列长度 |
| 价格币种 | 假设同一币种比较 |
| 质量指标依赖自报 | 准确率可能不准确 |
设计取舍
为什么不用纯语义匹配?
B 端容错率接近零。合规结论错了是法律风险,因此匹配必须基于 Skill 的精确分类,而不是向量相似度。
为什么保留 top-3 而不是自动选第一?
价格、响应速度、服务商偏好存在用户主观因素;展示理由让选择可解释。
源码位置
libs/modules/src/agent-matching/
└── services/agent-matcher.service.ts