5.8 KiB
5.8 KiB
JSON 解析统一化改进文档
改进目标
统一项目中所有 LLM 响应的 JSON 解析逻辑,使用 json_repair 库和统一的解析工具,简化代码并提高解析成功率。
创建的新工具模块
src/utils/json_parser.py
提供统一的 JSON 解析功能:
主要函数:
-
extract_and_parse_json(response, strict=False)- 从 LLM 响应中提取并解析 JSON
- 自动处理 Markdown 代码块标记
- 使用 json_repair 修复格式问题
- 支持严格模式和容错模式
-
safe_parse_json(json_str, default=None)- 安全解析 JSON,失败时返回默认值
-
extract_json_field(response, field_name, default=None)- 从 LLM 响应中提取特定字段的值
处理策略:
- 清理 Markdown 代码块标记(
json 和) - 提取 JSON 对象或数组(使用栈匹配算法)
- 尝试直接解析
- 如果失败,使用 json_repair 修复后解析
- 容错模式下返回空字典或空列表
已修改的文件
1. src/chat/memory_system/memory_query_planner.py ✅
- 移除了自定义的
_extract_json_payload方法 - 使用
extract_and_parse_json替代原有的解析逻辑 - 简化了代码,提高了可维护性
修改前:
payload = self._extract_json_payload(response)
if not payload:
return self._default_plan(query_text)
try:
data = orjson.loads(payload)
except orjson.JSONDecodeError as exc:
...
修改后:
data = extract_and_parse_json(response, strict=False)
if not data or not isinstance(data, dict):
return self._default_plan(query_text)
2. src/chat/memory_system/memory_system.py ✅
- 移除了自定义的
_extract_json_payload方法 - 在
_evaluate_information_value方法中使用统一解析工具 - 简化了错误处理逻辑
3. src/chat/interest_system/bot_interest_manager.py ✅
- 移除了自定义的
_clean_llm_response方法 - 使用
extract_and_parse_json解析兴趣标签数据 - 改进了错误处理和日志输出
4. src/plugins/built_in/affinity_flow_chatter/chat_stream_impression_tool.py ✅
- 将
_clean_llm_json_response标记为已废弃 - 使用
extract_and_parse_json解析聊天流印象数据 - 添加了类型检查和错误处理
待修改的文件
需要类似修改的其他文件:
-
src/plugins/built_in/affinity_flow_chatter/proactive_thinking_executor.py- 包含自定义的 JSON 清理逻辑
-
src/plugins/built_in/affinity_flow_chatter/user_profile_tool.py- 包含自定义的 JSON 清理逻辑
-
其他包含自定义 JSON 解析逻辑的文件
改进效果
1. 代码简化
- 消除了重复的 JSON 提取和清理代码
- 减少了代码行数和维护成本
- 统一了错误处理模式
2. 解析成功率提升
- 使用 json_repair 自动修复常见的 JSON 格式问题
- 支持多种 JSON 包装格式(代码块、纯文本等)
- 更好的容错处理
3. 可维护性提升
- 集中管理 JSON 解析逻辑
- 易于添加新的解析策略
- 便于调试和日志记录
4. 一致性提升
- 所有 LLM 响应使用相同的解析流程
- 统一的日志输出格式
- 一致的错误处理
使用示例
基本用法:
from src.utils.json_parser import extract_and_parse_json
# LLM 响应可能包含 Markdown 代码块或其他文本
llm_response = '```json\\n{"key": "value"}\\n```'
# 自动提取和解析
data = extract_and_parse_json(llm_response, strict=False)
# 返回: {'key': 'value'}
# 如果解析失败,返回空字典(非严格模式)
# 严格模式下返回 None
提取特定字段:
from src.utils.json_parser import extract_json_field
llm_response = '{"score": 0.85, "reason": "Good quality"}'
score = extract_json_field(llm_response, "score", default=0.0)
# 返回: 0.85
测试建议
-
单元测试:
- 测试各种 JSON 格式(带/不带代码块标记)
- 测试格式错误的 JSON(验证 json_repair 的修复能力)
- 测试嵌套 JSON 结构
- 测试空响应和无效响应
-
集成测试:
- 在实际 LLM 调用场景中测试
- 验证不同模型的响应格式兼容性
- 测试错误处理和日志输出
-
性能测试:
- 测试大型 JSON 的解析性能
- 验证缓存和优化策略
迁移指南
旧代码模式:
# 旧的自定义解析逻辑
def _extract_json(response: str) -> str | None:
stripped = response.strip()
code_block_match = re.search(r"```(?:json)?\\s*(.*?)```", stripped, re.DOTALL)
if code_block_match:
return code_block_match.group(1)
# ... 更多自定义逻辑
# 使用
payload = self._extract_json(response)
if payload:
data = orjson.loads(payload)
新代码模式:
# 使用统一工具
from src.utils.json_parser import extract_and_parse_json
# 直接解析
data = extract_and_parse_json(response, strict=False)
if data and isinstance(data, dict):
# 使用数据
pass
注意事项
-
导入语句:确保添加正确的导入
from src.utils.json_parser import extract_and_parse_json -
错误处理:统一工具已包含错误处理,无需额外 try-except
# 不需要 try: data = extract_and_parse_json(response) except Exception: ... # 应该 data = extract_and_parse_json(response, strict=False) if not data: # 处理失败情况 pass -
类型检查:始终验证返回值类型
data = extract_and_parse_json(response) if isinstance(data, dict): # 处理字典 elif isinstance(data, list): # 处理列表
后续工作
- 完成剩余文件的迁移
- 添加完整的单元测试
- 更新相关文档
- 考虑添加性能监控和统计
日期
2025年11月2日