1. 从问答机到决策引擎:重新理解LLM在AI系统中的角色
第一次接触AI系统测试时,我也以为测试LLM就是检查回答是否合理。直到在WorkLog Agent项目中踩了无数坑才发现,现代AI系统中的LLM早已不是简单的聊天机器人,而是一个需要承担复杂决策任务的"大脑"。
想象一下,你正在训练一个新入职的实习生。最初你只让他回答简单问题("公司几点上班?"),这就像早期的聊天机器人。但随着他熟悉业务,你会让他处理更复杂的任务:判断客户需求类型(是咨询还是投诉?)、决定是否需要转接其他部门、提取关键信息生成工单...这正是LLM在Agent系统中的真实工作场景。
在技术架构上,LLM决策层通常位于输入处理和工具执行之间。以我最近参与的智能客服系统为例,完整流程是这样的:
code复制用户输入 → 输入清洗 → LLM决策 → 工具调用 → 结果整合 → 输出响应
其中LLM需要完成四个关键决策:
- 意图分类:这是咨询、投诉还是操作请求?
- 工具判断:是否需要调用知识库、工单系统等外部工具?
- 参数提取:如果要创建工单,需要哪些字段?
- 响应生成:如何将工具返回结果组织成自然语言回复?
2. LLM决策层的三大测试维度
2.1 意图识别测试:当用户说"系统挂了",TA到底想要什么?
在电商客服系统中,我们遇到过这样的案例:
- 用户输入:"支付系统挂了"
- 预期意图:系统故障报修
- 实际识别:普通咨询(未触发工单系统)
这类问题的测试要点在于构建意图边界用例。我的经验是准备三类测试数据:
-
明确指令(直接触发工具)
- "创建工单:支付失败"(应直接触发工单创建)
- "查询订单12345"(应调用订单查询API)
-
模糊表达(考验意图推断)
- "钱付了但没反应"(应识别为支付问题)
- "东西没收到"(应识别为物流查询)
-
干扰项(应不触发工具)
- "系统挂了哈哈"(可能是用户调侃)
- "支付系统很棒"(正向反馈)
测试时建议使用混淆矩阵统计识别准确率,重点关注:
- 假阳性(不该触发时触发)
- 假阴性(该触发时未触发)
2.2 工具调用测试:不该出手时乱出手
在某知识管理系统项目中,我们遇到过LLM过度调用搜索工具的情况——即使用户只是简单打招呼,系统也会去搜索知识库。这类问题需要通过调用合理性测试来预防。
具体测试方法:
-
工具触发测试
- 正向用例:"查找2023年销售数据"(应触发数据查询工具)
- 负向用例:"你好"(不应触发任何工具)
-
工具选择测试
- "订明天上午的会议室"(应触发日历工具而非邮件工具)
- "报销3月差旅费"(应触发财务系统而非HR系统)
-
调用频率测试
- 连续输入10条查询指令,检查是否出现工具调用丢失
- 混合工具调用和非工具调用请求,检查交叉影响
重要经验:在测试工具调用时,一定要模拟真实场景中的连续对话。很多调用错误只会在多轮交互中暴露。
2.3 参数提取测试:日期到底是"今天"还是"2024-03-15"?
在WorkLog Agent项目中,最常出现的问题就是参数格式不一致。例如:
- 用户说"今天完成了测试"
- LLM可能生成:"date": "today" 或 "date": "2024-03-15"
这类问题需要通过参数完整性检查来捕获。建议测试以下方面:
-
必填字段检查
- 缺失关键字段时应拒绝执行并提示用户
- 例如工单系统缺少"问题描述"字段
-
格式一致性检查
- 日期应统一为ISO格式
- 数字不应混用汉字和阿拉伯数字
-
值域有效性检查
- "优先级"字段只能为高/中/低
- "数量"字段必须大于0
-
上下文关联检查
- 在多轮对话中,参数应能继承前文信息
- 例如"修改刚才的订单"应能关联到前文订单ID
3. 实战:构建LLM决策测试体系
3.1 测试数据设计策略
根据多个项目经验,我总结出测试数据的"3×3"原则:
三个维度:
- 语法(完整句/片段/错别字)
- 语义(字面意思/隐含意图/反讽)
- 场景(单轮/多轮/中断恢复)
三种类型:
- 种子用例(核心场景)
- 变异用例(同义改写)
- 对抗用例(刻意设计的边缘情况)
示例测试集结构:
markdown复制# 查询意图测试
- [正常] "查看昨天的会议记录" → 应触发查询工具
- [变异] "昨天的会议说了啥" → 应触发查询工具
- [对抗] "会议记录啥的给我看看呗" → 应触发查询工具
# 创建意图测试
- [正常] "创建任务:测试登录功能" → 应触发创建工具
- [变异] "记一下要测试登录" → 应触发创建工具
- [对抗] "登录测试是不是该做一下?" → 不应触发创建
3.2 自动化测试框架搭建
手工测试无法满足持续迭代需求,建议采用分层自动化策略:
-
单元测试层
- 使用pytest测试单个决策点
- 示例:
python复制def test_intent_classification(): input = "支付失败了怎么办" intent = llm.detect_intent(input) assert intent == "PAYMENT_ISSUE"
-
集成测试层
- 使用Behave等BDD工具测试完整流程
- 示例:
gherkin复制场景: 工单创建流程 当用户输入"网络连接不上" 那么系统应识别为"NETWORK_ISSUE"意图 并且调用"create_ticket"工具 且参数包含"problem_description"字段
-
监控层
- 在生产环境部署影子测试
- 对比新旧版本的决策差异
3.3 决策质量评估指标
除了正确率外,建议监控这些指标:
| 指标名称 | 计算公式 | 健康阈值 |
|---|---|---|
| 工具调用准确率 | 正确调用次数/总调用次数 | ≥95% |
| 参数完整率 | 完整参数数/总调用数 | ≥98% |
| 意图识别一致率 | 相同语义输入的识别结果一致率 | ≥90% |
| 决策延迟 | 从输入到完成决策的平均耗时 | <500ms |
4. 避坑指南:来自三个失败案例的经验
4.1 案例一:过度依赖LLM导致系统崩溃
在某智能家居项目中,最初设计让LLM处理所有指令。结果发现:
- 简单指令("开灯")也要经过完整决策流程
- 系统响应延迟高达2秒
- 并发量超过10时错误率飙升
解决方案:
引入规则引擎处理高频简单指令,LLM仅处理复杂请求。改造后:
- 将30%的高频指令转为规则匹配
- 平均延迟降低到300ms
- 错误率下降80%
4.2 案例二:参数提取中的时区陷阱
国际电商项目曾出现订单日期错误:
- 用户说"今天下单"
- 系统记录为UTC时间的"今天"
- 但用户实际在GMT+8时区
解决方案:
- 在参数提取环节强制要求时区转换
- 前端明确显示系统理解的日期时间
- 添加确认环节("您指的是北京时间3月15日吗?")
4.3 案例三:多轮对话中的决策漂移
在客服系统中发现:
- 第一轮用户说"订单问题" → 正确识别
- 第二轮说"还没解决" → 仍然识别为订单问题
- 第三轮说"我要投诉" → 还是订单问题...
解决方案:
- 实现对话状态机管理
- 设置决策超时机制(超过3轮未解决自动升级)
- 引入人工确认阈值
5. 架构设计建议:规则与LLM的黄金比例
经过多个项目验证,我总结出决策层架构设计的"70/30原则":
-
70%规则+30%LLM
- 高频简单场景用规则处理(开灯、查询状态)
- 低频复杂场景用LLM处理(投诉协商、多条件查询)
-
决策分层设计
mermaid复制graph TD A[用户输入] --> B{是否规则匹配?} B -->|是| C[规则引擎处理] B -->|否| D[LLM决策] C --> E[执行动作] D --> E -
兜底机制
- LLM决策超时自动降级到规则
- 置信度低于阈值时要求人工确认
- 连续失败自动触发诊断模式
在实际项目中,这套架构使得系统稳定性从最初的82%提升到了99.5%,同时LLM的调用成本降低了60%。