AgentEvalTool/research/functional-completeness-assessment.md
sinohqb 01af6fca74 docs(research): 功能完整性评估方案调研
为 ticket #18 提供技术方案,分析现有 6 种规则对"意图识别→任务完成度→任务成功率"
分层测量的覆盖能力,推荐新增 task_completion 规则解决多轮对话结构化评估缺口。
2026-08-25 14:00:59 +08:00

509 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 功能完整性评估方案调研
> 调研日期2026-08-25
> 关联 Ticket#18功能完整性评估
> Wayfinder Map#13
> 代码库版本v1.3.0main 分支)
---
## 1. 现有规则能力分析
平台当前注册了 6 种评估规则(`@register_rule` 插件式注册),以下逐一分析其对分层测量的适用性。
### 1.1 规则清单与能力矩阵
| 规则 | 注册名 | 评估对象 | 输入范围 | 输出 | 模型依赖 |
|------|--------|---------|---------|------|---------|
| 关键词匹配 | `keyword_match` | 最后一轮回复 | `dialog[-1].reply` | passed + score匹配比例 | 无 |
| 响应时间 | `response_time` | 最后一轮延迟 | `dialog[-1].latency_ms` | passed + score时延/阈值比) | 无 |
| LLM 评分 | `llm_score` | 最后一轮回复 | `dialog[-1]` 的问答对 | passed + score0-10 归一化) | JUDGEchat |
| 语义相似度 | `semantic_similarity` | 最后一轮回复 | `dialog[-1].reply` vs reference | passed + score余弦相似度 | EMBEDDING |
| JSON Schema | `json_schema` | 最后一轮回复 | `dialog[-1].reply` 结构 | passed + 检查项计数 | 无 |
| 安全检测 | `safety` | 最后一轮回复 | `dialog[-1].reply` | passed + 违规类别 | MODERATION可选 |
### 1.2 关键限制:最后轮次瓶颈
**所有现有规则都只评估 `dialog[-1]`(最后一轮回复)**。这在引擎代码中是硬编码的:
```python
# keyword.py
last_turn = dialog[-1]
text = extract_reply_text(last_turn.reply).lower()
# llm_score.py
last_turn = dialog[-1]
reply_text = extract_reply_text(last_turn.reply)
# semantic.py
reply_text = extract_reply_text(dialog[-1].reply)
```
虽然引擎在 `_save_rule_results` 中将完整 `dialog: list[Turn]` 传入 `rule.evaluate(case, dialog)`,但所有规则实现都忽略了多轮上下文。
**对分层测量的影响**
- **意图识别**:通常只需评估单轮(用户发问 -> 智能体是否正确理解),最后轮次评估可以满足。
- **任务完成度**:需要跨多轮评估(如"是否收集了 3/5 个必要信息"),现有规则无法直接支持。
- **任务成功率**:需要综合多轮对话的全局判断,现有规则无法直接支持。
### 1.3 规则组合逻辑
`RuleLogic` 提供三种组合方式:
- `all`所有规则必须通过AND 语义)
- `any`至少一条通过OR 语义)
- `weighted`:加权平均分 >= 阈值(加权聚合)
隐式规则(从 `Expectation` 派生)是硬约束,任一失败则用例失败,独立于 `rule_logic`
**组合能力评估**:三种逻辑足以表达"分层测量中各层独立判定"的需求——每层可以是一组规则,层间用 `all` 组合(层间 AND层内用 `weighted` 聚合。但前提是需要规则能覆盖各层的评估维度。
---
## 2. 分层测量的实现方案
### 2.1 三层定义
| 层级 | 名称 | 含义 | 测量粒度 |
|------|------|------|---------|
| L1 | 意图识别准确率 | 智能体是否正确理解了用户意图 | 单轮级per-turn |
| L2 | 任务完成度 | 智能体是否完成了任务要求的各项子目标 | 用例级per-case跨轮次 |
| L3 | 任务成功率 | 整个任务是否最终成功 | 用例级per-case全局判定 |
三层关系L1 是 L2 的必要条件意图识别错误则任务不可能完成L2 是 L3 的主要决定因素(但不完全等价——任务完成但体验差仍可能判定为不成功)。
### 2.2 方案 A组合现有规则零新增规则
**思路**:仅使用 `llm_score` 的自定义 criteria 能力覆盖三个层级。
**L1 - 意图识别**
```json
{
"type": "llm_score",
"params": {
"criteria": "评估智能体是否正确识别了用户意图。用户意图是:{intent_description}。如果智能体的回复表明它理解了用户想要什么,给 8-10 分;如果部分理解(如识别了主题但误解了具体需求),给 4-7 分;如果完全误解或未回应意图,给 0-3 分。",
"min_score": 7
}
}
```
**L2 - 任务完成度**
```json
{
"type": "llm_score",
"params": {
"criteria": "评估智能体是否完成了以下子任务1) 收集用户姓名 2) 收集联系方式 3) 确认服务地址 4) 说明服务内容 5) 告知预计时间。每完成一项得 2 分,满分 10 分。",
"min_score": 6
}
}
```
**L3 - 任务成功率**
```json
{
"type": "llm_score",
"params": {
"criteria": "综合评估本次对话是否成功完成了用户任务。考虑:意图是否正确处理、必要信息是否收集完整、用户问题是否得到解决。成功给 10 分,部分成功给 5-7 分,失败给 0-3 分。",
"min_score": 7
}
}
```
**优点**
- 零代码变更,纯配置层面实现
- 利用现有 `weighted` 规则逻辑可以给三层分配权重
**缺点**
- `llm_score` 只看 `dialog[-1]`L2/L3 的跨轮次评估不准确
- LLM 评分的稳定性问题:同一对话多次评分可能结果不同
- 三个 `llm_score` 规则各自独立调用 LLM无法共享中间推理结果
- criteria 的编写质量直接决定评估质量,维护成本高
### 2.3 方案 B新增 `task_completion` 规则(推荐)
**思路**:新增一种支持全对话评估的规则类型,专门用于任务完成度和成功率测量。
#### 2.3.1 新规则:`task_completion`
```python
@register_rule
class TaskCompletionRule(EvalRule):
"""Evaluate task completion by checking required slots/steps across the full dialog."""
name = "task_completion"
```
**核心设计**
- 接收完整 `dialog: list[Turn]`(而非只看最后一轮)
- 支持两种评估模式:
- **slot 模式**定义需要收集的信息槽位如姓名、电话、地址LLM 判断每个槽位是否已收集
- **step 模式**定义需要完成的步骤如确认身份、记录问题、给出方案LLM 判断每个步骤是否完成
- 输出:每个槽位/步骤的完成状态 + 总体完成率
**参数设计**
```json
{
"type": "task_completion",
"params": {
"mode": "slot",
"required_slots": [
{"name": "user_name", "description": "用户姓名"},
{"name": "phone", "description": "联系电话"},
{"name": "address", "description": "服务地址"},
{"name": "service_type", "description": "服务类型"},
{"name": "appointment_time", "description": "预约时间"}
],
"min_completion_rate": 0.6,
"evaluation_scope": "full_dialog"
}
}
```
**评估逻辑**
1. 拼接完整对话(所有轮次的 sent_message + reply
2. 调用 LLMJUDGE 岗位),逐一判断每个 slot 是否在对话中被收集
3. 计算完成率 = 已收集槽位数 / 总槽位数
4. `passed = completion_rate >= min_completion_rate`
#### 2.3.2 新规则:`intent_classification`(可选)
```python
@register_rule
class IntentClassificationRule(EvalRule):
"""Check whether the agent correctly identified the user's intent."""
name = "intent_classification"
```
**与 `llm_score` 的区别**
- `llm_score` 输出连续分数0-10适合质量评分
- `intent_classification` 输出分类结果(正确/部分正确/错误),适合精确的意图匹配
- 支持定义意图分类表intent taxonomyLLM 从中选择
**参数设计**
```json
{
"type": "intent_classification",
"params": {
"expected_intent": "appointment_booking",
"intent_taxonomy": {
"appointment_booking": "预约服务",
"inquiry": "咨询信息",
"complaint": "投诉反馈",
"other": "其他"
},
"accept_partial": true
}
}
```
### 2.4 方案 C扩展 `llm_score` 支持全对话评估(折中方案)
**思路**:不新增规则类型,但扩展 `llm_score` 的参数,使其支持 `evaluation_scope: "full_dialog"` 模式。
**变更点**
- `llm_score.py` 中,当 `params.evaluation_scope == "full_dialog"` 时,拼接全部轮次的对话作为评估输入
- 新增 `params.dialog_format` 控制对话拼接格式
**优点**
- 不增加规则注册表的复杂度
- 复用 `llm_score` 的模型调用链路
**缺点**
- `llm_score` 职责膨胀,从"单轮质量评分"变成"万能评估器"
- 无法表达结构化的任务完成度(如"收集了 3/5 个信息"
- 与现有 `llm_score` 用例的语义不一致
### 2.5 方案对比
| 维度 | 方案 A纯组合 | 方案 B新增规则 | 方案 C扩展 llm_score |
|------|----------------|------------------|----------------------|
| 代码变更量 | 0 | 中(新增 1-2 个规则文件) | 小(修改 1 个文件) |
| L1 意图识别 | 可行llm_score 单轮够用) | 最优(专用规则,结构化输出) | 可行 |
| L2 任务完成度 | 不准确(只看最后一轮) | 最优(全对话 + 结构化槽位) | 可行但不结构化 |
| L3 任务成功率 | 不准确(只看最后一轮) | 最优(可基于 L1+L2 聚合) | 可行但不结构化 |
| 评估稳定性 | 低LLM 自由评分) | 高(结构化判断) | 低 |
| 前端展示友好度 | 低(只有分数) | 高(可展示每个槽位完成状态) | 低 |
| 维护成本 | 高criteria 易腐化) | 中(规则逻辑固定,参数可变) | 中 |
| 与现有架构一致性 | 高 | 高(插件式注册) | 中 |
---
## 3. 任务完成度的量化方式
### 3.1 槽位填充模型Slot-Filling
**定义**:一个任务需要收集 N 个信息槽位slots评估智能体在对话中实际收集了多少个。
```
completion_rate = filled_slots / total_required_slots
```
**示例**:预约维修服务需要收集 5 个信息:
- 姓名、电话、地址、故障描述、期望时间
- 智能体收集了 3 个 → completion_rate = 3/5 = 0.6
**实现方式**
- 场景配置中定义 `required_slots` 列表
- 规则执行时LLM 逐一判断每个槽位是否在对话中被收集
- 输出:`{slot_name: filled/unfilled}` 的映射 + 总体完成率
**优点**:直观、可解释、可部分得分
**适用场景**:信息收集类任务(预约、登记、咨询)
### 3.2 步骤完成模型Step Completion
**定义**:一个任务需要完成 N 个步骤steps评估智能体完成了多少个。
```
completion_rate = completed_steps / total_required_steps
```
**示例**:投诉处理需要完成 4 个步骤:
1. 倾听并记录投诉内容
2. 表达歉意和同理心
3. 给出解决方案或升级路径
4. 确认用户满意
**与槽位填充的区别**:步骤有顺序依赖(先记录再解决),槽位无顺序。
### 3.3 混合模型
实际场景中,一个任务可能同时包含槽位填充和步骤完成。建议 `task_completion` 规则支持混合配置:
```json
{
"mode": "hybrid",
"required_slots": [...],
"required_steps": [...],
"slot_weight": 0.4,
"step_weight": 0.6,
"min_completion_rate": 0.7
}
```
### 3.4 量化方式推荐
| 任务类型 | 推荐量化方式 | 理由 |
|---------|------------|------|
| 信息收集(预约/登记) | 槽位填充 | 目标是收集完整信息 |
| 流程执行(投诉/退款) | 步骤完成 | 目标是按流程处理 |
| 问答咨询 | 不适用(用 llm_score 即可) | 无结构化子任务 |
| 复杂混合任务 | 混合模型 | 同时有信息收集和流程要求 |
---
## 4. 任务成功率的定义
### 4.1 选项分析
**选项 A二值判断pass/fail**
- 定义:任务要么成功,要么失败,没有中间状态
- 判定标准:所有关键条件满足 = 成功,否则 = 失败
- 优点:简单明确,易于聚合(成功率 = 成功用例数 / 总用例数)
- 缺点:丢失了"接近成功"的信息
**选项 B概率/连续分数**
- 定义:任务成功率是一个 0-1 的连续值
- 计算:各层得分的加权组合
- 优点:保留了粒度信息
- 缺点语义模糊0.7 的成功率是什么意思?)
**选项 C分级判定推荐**
- 定义:三级结果
- `success`:任务完全成功(所有关键条件满足)
- `partial`:部分成功(核心目标达成但有缺陷)
- `failure`:任务失败(核心目标未达成)
- 聚合时success = 1.0, partial = 0.5, failure = 0.0
- 优点:兼顾粒度和可解释性
### 4.2 推荐定义
**任务成功率采用分级判定 + 数值聚合的混合方案**
```
case_outcome:
L1_intent: passed / failed (llm_score 或 intent_classification)
L2_completion: 0.0 ~ 1.0 (task_completion 规则的 completion_rate)
L3_success: success / partial / failure (综合判定)
聚合规则:
L3_success = success IF L1_intent.passed AND L2_completion >= 0.8
L3_success = partial IF L1_intent.passed AND L2_completion >= 0.5
L3_success = failure OTHERWISE
场景级成功率 = (success_count + 0.5 * partial_count) / total_cases
```
**与现有判定体系的关系**
- 现有 `CaseOutcome.passed` 保持二值语义passed = L3_success != failure
- 新增 `CaseOutcome.success_level` 字段存储分级结果success/partial/failure
- `RunSummary` 新增 `success_rate`(分级聚合)与现有 `pass_rate`(二值)并存
### 4.3 分层聚合公式
```
场景级指标:
intent_accuracy = L1_passed_count / total_cases
avg_completion = mean(L2_completion_rates)
success_rate = (success + 0.5*partial) / total_cases
pass_rate = (success + partial) / total_cases # 兼容现有口径
```
---
## 5. 工作量估算
### 5.1 方案 B推荐方案详细拆分
| 工作项 | 内容 | 人天 |
|--------|------|------|
| **后端:`task_completion` 规则** | 新建规则文件、slot/step 评估逻辑、全对话拼接、LLM 调用、结构化输出解析 | 2.0 |
| **后端:`intent_classification` 规则**(可选) | 新建规则文件、意图分类 prompt、分类结果匹配 | 1.0 |
| **后端:模型扩展** | `Case` 模型新增 `required_slots` / `required_steps` 字段(或复用 `eval_rules.params`)、`EvalResult` 新增 `detail` 字段存储结构化结果 | 0.5 |
| **后端:判定逻辑** | `judgement.py` 扩展支持三级判定success/partial/failure、`RunSummary` 新增 `success_rate` | 1.0 |
| **后端:聚合指标** | `run_summary.py` 新增分层指标计算 | 0.5 |
| **后端:测试** | 单元测试(规则逻辑、判定逻辑、聚合计算)+ 集成测试 | 1.5 |
| **前端:场景编辑** | 任务完成度规则的配置表单(槽位/步骤编辑器) | 1.5 |
| **前端:结果展示** | Run 报告页展示分层指标L1/L2/L3、槽位完成详情 | 1.5 |
| **文档** | 规则扩展文档、场景配置指南 | 0.5 |
| **合计** | | **10.0** |
### 5.2 方案 A纯组合零代码工作量
| 工作项 | 人天 |
|--------|------|
| 场景配置模板(各任务类型的 criteria 编写) | 1.0 |
| 前端:无变更(复用现有 llm_score 展示) | 0 |
| 测试验证 | 0.5 |
| **合计** | **1.5** |
### 5.3 方案 C扩展 llm_score工作量
| 工作项 | 人天 |
|--------|------|
| 后端:`llm_score` 扩展 `evaluation_scope` 参数 | 1.0 |
| 后端prompt 模板改造 | 0.5 |
| 后端:测试 | 0.5 |
| 前端:无变更 | 0 |
| **合计** | **2.0** |
---
## 6. 推荐方案
### 6.1 推荐:方案 B新增 `task_completion` 规则)
**理由**
1. **解决核心痛点**:现有规则的最后轮次瓶颈是功能完整性评估的根本障碍。方案 A 和 C 都无法真正解决多轮任务完成度的量化问题。
2. **结构化输出**`task_completion` 规则产出每个槽位/步骤的完成状态,前端可以展示"收集了 3/5 个必要信息"这种直观结果,比 LLM 自由评分的 7.2 分有意义得多。
3. **评估稳定性**:结构化判断(这个槽位是否被填充)比自由评分(给这个回复打 0-10 分)的 LLM 输出稳定性高得多。
4. **架构一致性**:遵循现有的插件式规则注册模式,新增规则不影响引擎核心逻辑。
5. **渐进实施**:可以先实现 `task_completion` 规则(覆盖 L2L1 继续用 `llm_score`单轮评估够用L3 通过判定逻辑聚合。`intent_classification` 规则可以后续按需添加。
### 6.2 实施路径建议
```
Phase 1MVP3 人天):
- 新增 task_completion 规则slot 模式)
- 扩展 judgement.py 支持分层判定
- RunSummary 新增分层指标
- 单元测试
Phase 2完善3 人天):
- task_completion 规则支持 step 模式和混合模式
- 前端场景编辑:槽位/步骤配置 UI
- 前端结果展示:分层指标 + 槽位详情
Phase 3增强2 人天):
- intent_classification 规则(可选)
- 场景级聚合指标intent_accuracy、success_rate
- 报告模板适配
```
### 6.3 场景配置示例
一个完整的"预约维修服务"功能完整性评估场景:
```json
{
"name": "预约维修服务 - 功能完整性",
"cases": [
{
"id": "case-001",
"type": "multi_turn",
"messages": [
"我家空调坏了,想预约维修",
"我叫张三",
"电话是 13800138000",
"地址是朝阳区建国路 88 号"
],
"eval_rules": [
{
"type": "intent_classification",
"params": {
"expected_intent": "appointment_booking",
"intent_taxonomy": {
"appointment_booking": "预约服务",
"inquiry": "咨询信息",
"complaint": "投诉反馈"
}
},
"weight": 1.0
},
{
"type": "task_completion",
"params": {
"mode": "slot",
"required_slots": [
{"name": "user_name", "description": "用户姓名"},
{"name": "phone", "description": "联系电话"},
{"name": "address", "description": "服务地址"},
{"name": "fault_description", "description": "故障描述"},
{"name": "appointment_time", "description": "预约时间"}
],
"min_completion_rate": 0.6
},
"weight": 2.0
},
{
"type": "llm_score",
"params": {
"criteria": "评估智能体的服务态度是否专业、礼貌、有同理心",
"min_score": 7
},
"weight": 1.0
}
],
"rule_logic": "weighted",
"rule_pass_threshold": 0.7
}
]
}
```
### 6.4 风险与缓解
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| LLM 判断槽位填充的准确性 | 错误判定导致评估结果不可信 | 提供 few-shot 示例;支持人工复核模式 |
| 多轮对话拼接超出 LLM 上下文 | 长对话被截断 | 限制最大轮次数;摘要压缩早期轮次 |
| 槽位定义的主观性 | 不同人对于"是否收集了地址"可能有不同判断 | 槽位描述要具体;提供判定示例 |
| 与现有 pass_rate 口径的关系 | 新旧指标并存可能混淆 | 明确文档说明;前端标注新旧指标 |
---
## 附录:现有规则对分层测量的覆盖分析
| 分层 | 现有规则能否覆盖 | 说明 |
|------|----------------|------|
| L1 意图识别 | **部分可以** | `llm_score` 自定义 criteria 可做意图判断,但输出非结构化(只有分数,没有"识别为哪个意图"的明确结论) |
| L2 任务完成度 | **不可以** | 所有规则只看最后一轮,无法评估跨轮次的信息收集/步骤完成情况;`llm_score` 即使看全对话也无法输出结构化的槽位完成状态 |
| L3 任务成功率 | **间接可以** | 可以通过 `weighted` 逻辑组合 L1+L2 的分数聚合,但前提是 L2 能准确测量 |
**结论**:现有规则体系的核心缺口是 **多轮对话的结构化评估能力**。新增 `task_completion` 规则填补这个缺口后,三层测量即可完整实现。