jd-opensource/joyagent-jdgenie · error · RuntimeError

解析llm json结果失败

Error message

解析llm json结果失败

What it means

_parse_json_result in table_column_filter.py raises RuntimeError('解析llm json结果失败') when re.findall for the ```json ...``` fenced block on the LLM response returns nothing. It signals the LLM reply was not the expected JSON code block.

Solutions

  1. Log the full result_str (already logged as 生成结果格式不合法) and strengthen the prompt to demand exactly one ```json fenced block
  2. Broaden the parser to also accept bare JSON: try json.loads(result_str) directly before regex
  3. Use response_format/JSON mode if the LLM API supports it, or a json_mode flag in your client
  4. Retry the LLM call (the surrounding retry loop in _filter_single_table already retries) with an explicit format reminder

Example fix

// before
result = re.findall(r'```json\s*([\s\S]*?)\s*```', result_str)
return result[0]
// after
match = re.findall(r'```(?:json)?\s*([\s\S]*?)\s*```', result_str)
if match:
    return match[0]
try:
    json.loads(result_str)
    return result_str
except Exception:
    raise RuntimeError('解析llm json结果失败')
Defensive patterns

Strategy: retry

Validate before calling

import re, json
def llm_json_block_ok(result_str: str):
    m = re.findall(r'```json\s*([\s\S]*?)\s*```', result_str)
    return bool(m) and _is_json(m[0])

Type guard

def is_fenced_json(s):
    m = re.match(r'```json\s*([\s\S]*?)\s*```$', s.strip())
    return m is not None

Try / catch

try:
    block = parse_json_result(result_str)
except RuntimeError:
    logger.warning('no ```json block, retrying with stricter prompt')
    result_str = llm_call(prompt + '\nRespond ONLY with a ```json block.')

Prevention

When it happens

Trigger: The LLM response string contains no ```json fenced block (pattern ```json\s*([\s\S]*?)\s*```), e.g. plain text answer, bare JSON without fences, or a different fence language; findall returns [] and result[0] raises IndexError caught and re-raised.

Common situations: Model returns raw JSON without markdown fences; temperature/high randomness makes model drift from the requested format; prompt for column filtering changes; model truncation drops closing fence.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of jd-opensource/joyagent-jdgenie@2417e0b8b6 (2026-09-08). Data as JSON: /api/errors/0bc8dc4d8e16d66c. Report an issue: GitHub.

Appendix: source

Thrown at genie-tool/genie_tool/tool/table_rag/table_column_filter.py:202

            "user_info": self.user_info,
            "time_info": self.time_info,
            "query": self.query,
            "memory_info": memory_info_str,
            "error_msg": error_msg
        }
        table_rag_prompts = get_prompt("table_rag")
        prompt = Template(table_rag_prompts["column_filter_prompt"]).render(info_dict)
        
        return prompt
    
    def _parse_json_result(self, result_str):
        pattern = r'```json\s*([\s\S]*?)\s*```'
        try:
            result = re.findall(pattern, result_str)
            return result[0]
        except Exception as e:
            logger.error(f"生成结果格式不合法:{result_str},{e}")
            raise RuntimeError("解析llm json结果失败")
    
    async def _filter_single_table(self, semaphore, table_schema_info: dict) -> dict | None:
        
        async with semaphore:
            llm_response = ""
            request_id = ""
            error_msg = None
            for retry in range(3):
                try:
                    columns_prompt = self._generate_filter_prompt(table_schema_info, error_msg)
                    
                    messages = [
                        {
                            "role": "system",
                            "content": "you are a helpful assistant.",
                        },
                        {
                            "role": "user",

View on GitHub (pinned to 2417e0b8b6)