================================================================================
工作流调用测试总结
================================================================================

测试时间：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
================================================================================
