Files
Mofox-Core/docs/development/json_parser_unification.md

5.8 KiB
Raw Blame History

JSON 解析统一化改进文档

改进目标

统一项目中所有 LLM 响应的 JSON 解析逻辑,使用 json_repair 库和统一的解析工具,简化代码并提高解析成功率。

创建的新工具模块

src/utils/json_parser.py

提供统一的 JSON 解析功能:

主要函数:

  1. extract_and_parse_json(response, strict=False)

    • 从 LLM 响应中提取并解析 JSON
    • 自动处理 Markdown 代码块标记
    • 使用 json_repair 修复格式问题
    • 支持严格模式和容错模式
  2. safe_parse_json(json_str, default=None)

    • 安全解析 JSON失败时返回默认值
  3. extract_json_field(response, field_name, default=None)

    • 从 LLM 响应中提取特定字段的值

处理策略:

  1. 清理 Markdown 代码块标记(json 和
  2. 提取 JSON 对象或数组(使用栈匹配算法)
  3. 尝试直接解析
  4. 如果失败,使用 json_repair 修复后解析
  5. 容错模式下返回空字典或空列表

已修改的文件

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 解析聊天流印象数据
  • 添加了类型检查和错误处理

待修改的文件

需要类似修改的其他文件:

  1. src/plugins/built_in/affinity_flow_chatter/proactive_thinking_executor.py

    • 包含自定义的 JSON 清理逻辑
  2. src/plugins/built_in/affinity_flow_chatter/user_profile_tool.py

    • 包含自定义的 JSON 清理逻辑
  3. 其他包含自定义 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

测试建议

  1. 单元测试

    • 测试各种 JSON 格式(带/不带代码块标记)
    • 测试格式错误的 JSON验证 json_repair 的修复能力)
    • 测试嵌套 JSON 结构
    • 测试空响应和无效响应
  2. 集成测试

    • 在实际 LLM 调用场景中测试
    • 验证不同模型的响应格式兼容性
    • 测试错误处理和日志输出
  3. 性能测试

    • 测试大型 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

注意事项

  1. 导入语句:确保添加正确的导入

    from src.utils.json_parser import extract_and_parse_json
    
  2. 错误处理:统一工具已包含错误处理,无需额外 try-except

    # 不需要
    try:
        data = extract_and_parse_json(response)
    except Exception:
        ...
    
    # 应该
    data = extract_and_parse_json(response, strict=False)
    if not data:
        # 处理失败情况
        pass
    
  3. 类型检查:始终验证返回值类型

    data = extract_and_parse_json(response)
    if isinstance(data, dict):
        # 处理字典
    elif isinstance(data, list):
        # 处理列表
    

后续工作

  1. 完成剩余文件的迁移
  2. 添加完整的单元测试
  3. 更新相关文档
  4. 考虑添加性能监控和统计

日期

2025年11月2日