234 lines
10 KiB
Plaintext
234 lines
10 KiB
Plaintext
================================================================================
|
||
工作流调用测试总结
|
||
================================================================================
|
||
|
||
测试时间:2026-01-19
|
||
测试场景:Agent工作流执行 - LLM节点"答非所问"问题诊断与修复
|
||
|
||
================================================================================
|
||
一、问题描述
|
||
================================================================================
|
||
|
||
1. 问题现象:
|
||
- LLM节点单独测试时能正常回答用户问题
|
||
- 整个Agent调用时,LLM返回通用欢迎语,而不是回答用户的具体问题
|
||
- 用户输入:"苹果英语怎么讲?"
|
||
- LLM返回:通用欢迎语 + 最后附加用户问题
|
||
|
||
2. 工作流结构:
|
||
- 开始节点 (start-1) → LLM处理节点 (llm-1) → 结束节点 (end-1)
|
||
- LLM节点配置:prompt = "请处理用户请求。"
|
||
|
||
================================================================================
|
||
二、测试方法与工具
|
||
================================================================================
|
||
|
||
1. 执行日志查看脚本:
|
||
- 文件:check_execution_logs.py
|
||
- 功能:查看最近的Agent执行记录,包括输入数据、输出数据、执行日志
|
||
- 使用方法:python3 check_execution_logs.py
|
||
|
||
2. 数据流转测试脚本:
|
||
- 文件:test_workflow_data_flow.py
|
||
- 功能:模拟完整工作流执行,详细记录每个节点的输入输出
|
||
- 使用方法:python3 test_workflow_data_flow.py
|
||
|
||
3. 日志查看命令:
|
||
- 后端日志:docker-compose -f docker-compose.dev.yml logs --tail=500 backend | grep "\[rjb\]"
|
||
- Celery日志:docker-compose -f docker-compose.dev.yml logs --tail=500 celery | grep "\[rjb\]"
|
||
|
||
================================================================================
|
||
三、问题定位过程
|
||
================================================================================
|
||
|
||
1. 数据流转检查:
|
||
- 输入数据(正确):{"query": "苹果英语怎么讲?", "USER_INPUT": "苹果英语怎么讲?"}
|
||
- Start节点输出(正确):{"query": "苹果英语怎么讲?", "USER_INPUT": "苹果英语怎么讲?"}
|
||
- LLM节点输入(问题):从执行日志看,数据被包装成了 {"input": {"query": "...", "USER_INPUT": "..."}}
|
||
- LLM节点输出(问题):返回通用欢迎语,而不是回答用户问题
|
||
|
||
2. 关键发现:
|
||
- 通过添加详细的调试日志([rjb]标记),发现:
|
||
* user_query提取逻辑能正确提取到用户问题
|
||
* 但prompt格式化时,通用指令检测可能有问题
|
||
* 或者LLM服务接收到的prompt不是格式化后的prompt
|
||
|
||
3. 日志分析结果:
|
||
- 从Celery worker日志中发现:
|
||
* user_query正确提取:"苹果英语怎么说?"
|
||
* 通用指令检测成功:is_generic_instruction=True
|
||
* formatted_prompt正确设置为:"苹果英语怎么说?"
|
||
* 实际发送给DeepSeek的prompt也是:"苹果英语怎么说?"
|
||
* LLM正确回答:"苹果的英语是 **apple**。"
|
||
|
||
================================================================================
|
||
四、问题根因分析
|
||
================================================================================
|
||
|
||
1. 主要问题:
|
||
- LLM节点的prompt配置是通用指令"请处理用户请求。"
|
||
- 当prompt是通用指令时,应该直接使用用户输入作为prompt
|
||
- 但之前的逻辑可能没有正确处理这种情况
|
||
|
||
2. 数据流转问题:
|
||
- get_node_input方法在处理非字典类型的source_output时,会包装成{"input": source_output}
|
||
- 这导致LLM节点接收到的输入数据格式为:{"input": "..."}
|
||
- user_query提取逻辑需要处理这种嵌套结构
|
||
|
||
3. End节点问题:
|
||
- End节点在提取输出时,会将所有文本字段组合
|
||
- 包括query字段,导致最终输出包含用户问题
|
||
|
||
================================================================================
|
||
五、修复方案
|
||
================================================================================
|
||
|
||
1. 修复user_query提取逻辑(backend/app/services/workflow_engine.py):
|
||
- 添加对嵌套input字段的处理
|
||
- 优先从嵌套的input中提取query等字段
|
||
- 如果嵌套input不存在,从顶层提取
|
||
- 支持多层嵌套结构
|
||
|
||
2. 修复prompt格式化逻辑(backend/app/services/workflow_engine.py):
|
||
- 增强通用指令检测:识别"请处理用户请求。"等通用指令
|
||
- 当检测到通用指令时,直接使用user_query作为prompt
|
||
- 添加详细的调试日志,记录整个格式化过程
|
||
|
||
3. 修复End节点输出处理(backend/app/services/workflow_engine.py):
|
||
- 在exclude_keys中添加'query', 'USER_INPUT', 'user_input', 'user_query'
|
||
- 优先使用input字段(LLM的实际输出)
|
||
- 避免将用户查询字段包含在最终输出中
|
||
|
||
4. 添加LLM服务调用日志(backend/app/services/llm_service.py):
|
||
- 在DeepSeek API调用前记录实际发送的prompt
|
||
- 便于调试和验证prompt是否正确
|
||
|
||
================================================================================
|
||
六、修复后的验证
|
||
================================================================================
|
||
|
||
1. 测试输入:
|
||
- 用户问题:"苹果英语怎么说?"
|
||
- 输入数据:{"query": "苹果英语怎么说?", "USER_INPUT": "苹果英语怎么说?"}
|
||
|
||
2. 执行日志验证:
|
||
[rjb] 开始提取user_query: input_data={'USER_INPUT': '苹果英语怎么说?', 'query': '苹果英语怎么说?'}
|
||
[rjb] 从顶层提取: key=query, value=苹果英语怎么说?, value_type=<class 'str'>
|
||
[rjb] 提取到字符串user_query: 苹果英语怎么说?
|
||
[rjb] 最终提取的user_query: 苹果英语怎么说?
|
||
[rjb] 检测到通用指令,直接使用用户输入作为prompt: 苹果英语怎么说?
|
||
[rjb] LLM节点prompt格式化: final_prompt前200字符='苹果英语怎么说?'
|
||
[rjb] 准备调用LLM: prompt前200字符='苹果英语怎么说?'
|
||
[rjb] DeepSeek实际发送的prompt前200字符: 苹果英语怎么说?
|
||
|
||
3. LLM输出验证:
|
||
- LLM正确回答:"苹果的英语是 **apple**。"
|
||
- 包含发音、例句、相关表达等详细信息
|
||
|
||
4. End节点输出验证:
|
||
- 最终输出只包含LLM的回答内容
|
||
- 不再包含用户问题
|
||
|
||
================================================================================
|
||
七、关键代码修改点
|
||
================================================================================
|
||
|
||
1. user_query提取逻辑(第467-525行):
|
||
- 添加嵌套input字段检查
|
||
- 支持多层数据提取
|
||
- 添加详细的调试日志
|
||
|
||
2. prompt格式化逻辑(第527-568行):
|
||
- 增强通用指令检测
|
||
- 当检测到通用指令时,直接使用user_query作为prompt
|
||
- 添加is_generic_instruction变量初始化
|
||
|
||
3. End节点输出处理(第1780-1799行):
|
||
- 在exclude_keys中添加用户查询相关字段
|
||
- 优先使用input字段
|
||
- 避免拼接用户问题
|
||
|
||
4. LLM服务调用日志(backend/app/services/llm_service.py):
|
||
- 在API调用前记录实际发送的prompt
|
||
|
||
================================================================================
|
||
八、测试经验总结
|
||
================================================================================
|
||
|
||
1. 调试方法:
|
||
- 使用详细的调试日志([rjb]标记)追踪数据流转
|
||
- 在关键位置添加日志:数据提取、格式化、API调用
|
||
- 查看Celery worker日志(工作流在Celery中执行)
|
||
|
||
2. 问题定位技巧:
|
||
- 对比节点测试和完整工作流执行的差异
|
||
- 检查数据在节点间的传递格式
|
||
- 验证实际发送给LLM的prompt内容
|
||
|
||
3. 常见问题:
|
||
- 数据被包装成嵌套结构(如{"input": {...}})
|
||
- 通用指令没有被正确识别
|
||
- End节点输出包含了不应该包含的字段
|
||
|
||
4. 最佳实践:
|
||
- 在LLM节点配置中,如果prompt是通用指令,应该直接使用用户输入
|
||
- End节点应该只输出LLM的实际回答,排除用户查询字段
|
||
- 添加详细的调试日志,便于问题定位
|
||
|
||
================================================================================
|
||
九、测试工具说明
|
||
================================================================================
|
||
|
||
1. check_execution_logs.py:
|
||
- 功能:查看最近的Agent执行记录和详细日志
|
||
- 输出:输入数据、输出数据、执行时间线、LLM节点详细分析
|
||
- 使用方法:python3 check_execution_logs.py
|
||
|
||
2. test_workflow_data_flow.py:
|
||
- 功能:模拟完整工作流执行,追踪数据流转
|
||
- 输出:每个节点的输入输出、数据格式转换过程
|
||
- 使用方法:python3 test_workflow_data_flow.py
|
||
|
||
3. 日志查看脚本(view_logs.sh):
|
||
- 功能:实时查看包含[rjb]标记的调试日志
|
||
- 使用方法:./view_logs.sh
|
||
|
||
================================================================================
|
||
十、修复验证结果
|
||
================================================================================
|
||
|
||
✅ 问题1:LLM答非所问
|
||
- 状态:已修复
|
||
- 验证:LLM能正确回答用户问题
|
||
|
||
✅ 问题2:End节点输出包含用户问题
|
||
- 状态:已修复
|
||
- 验证:最终输出只包含LLM的回答
|
||
|
||
✅ 问题3:数据流转问题
|
||
- 状态:已修复
|
||
- 验证:数据在节点间正确传递,格式正确
|
||
|
||
================================================================================
|
||
十一、后续建议
|
||
================================================================================
|
||
|
||
1. 节点配置建议:
|
||
- 如果LLM节点的prompt是通用指令(如"请处理用户请求。"),系统会自动使用用户输入作为prompt
|
||
- 如果需要更具体的指令,可以在prompt中明确说明任务类型
|
||
|
||
2. 测试建议:
|
||
- 使用check_execution_logs.py查看执行日志
|
||
- 使用Celery日志查看详细的调试信息
|
||
- 在节点配置面板中单独测试节点,对比完整工作流的执行
|
||
|
||
3. 监控建议:
|
||
- 定期检查执行日志,确认数据流转正常
|
||
- 关注LLM节点的输入输出,确保prompt格式化正确
|
||
- 检查End节点的输出,确保不包含用户查询字段
|
||
|
||
================================================================================
|
||
测试完成时间:2026-01-19 23:55
|
||
测试人员:AI Assistant
|
||
================================================================================
|