{"record":{"id":"8a9a2ebd4da51f78","repo":"datawhalechina/hello-agents","slug":"stage-json","errorCode":null,"errorMessage":"{stage}失败：工具返回的不是有效 JSON","messagePattern":"(.+?)失败：工具返回的不是有效 JSON","errorType":"exception","errorClass":"WorkflowExecutionError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/zenith191-RequirementClarifierAgent/src/workflow.py","lineNumber":153,"sourceCode":"            raise WorkflowExecutionError(f\"{stage}阶段返回了空结果\")\n        return response.strip()\n\n    def _run_tool(\n        self, name: str, parameters: dict[str, object], stage: str\n    ) -> dict[str, object]:\n        \"\"\"通过官方 ToolRegistry 获取工具并解析其字符串协议。\"\"\"\n\n        tool = self.tool_registry.get_tool(name)\n        if tool is None:\n            raise WorkflowExecutionError(f\"{stage}失败：工具 {name} 未注册\")\n        try:\n            raw_result = tool.run(parameters)\n        except Exception as exc:\n            raise WorkflowExecutionError(f\"{stage}失败：工具执行异常：{exc}\") from exc\n        try:\n            payload = json.loads(raw_result)\n        except (TypeError, ValueError) as exc:\n            raise WorkflowExecutionError(f\"{stage}失败：工具返回的不是有效 JSON\") from exc\n        if not isinstance(payload, dict):\n            raise WorkflowExecutionError(f\"{stage}失败：工具结果必须是 JSON 对象\")\n        if not payload.get(\"ok\"):\n            raise WorkflowExecutionError(\n                f\"{stage}失败：{payload.get('message', '未知工具错误')}\"\n            )\n        return payload\n\n    def _clear_agent_histories(self) -> None:\n        \"\"\"避免多次运行时把上一条需求带入下一条需求。\"\"\"\n\n        for agent in (\n            self.team.analyst,\n            self.team.architect,\n            self.team.reviewer,\n            self.team.synthesizer,\n        ):\n            clear_history = getattr(agent, \"clear_history\", None)","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/zenith191-RequirementClarifierAgent/src/workflow.py#L135-L171","documentation":"Raised by _run_tool when json.loads(raw_result) fails with TypeError or ValueError — i.e. the tool's return value is not valid JSON text. The workflow parses a strict string protocol: every tool must return a JSON-encoded string (TypeError fires when raw_result is None/non-str, ValueError when the string is malformed JSON).","triggerScenarios":"A tool returns a Python dict directly (json.loads(dict) → TypeError); a tool returns plain text like 'done' (ValueError); a tool returns JSON with single quotes or trailing commas (ValueError).","commonSituations":"Writing a custom tool that returns json.dumps(...) inconsistently — or forgets dumps entirely; tools that return pretty-printed or Python-repr output; upgrading a tool that previously returned free text.","solutions":["Make the tool return json.dumps(payload) — always a JSON-encoded string of an object.","Validate the tool standalone: json.loads(MyTool().run({...})) should succeed before wiring it into the registry.","Keep the payload shape {\"ok\": bool, ...} so downstream checks (ok / message) also pass."],"exampleFix":"# before\ndef run(self, params):\n    return {\"ok\": True, \"result\": 42}  # dict, not JSON string\n\n# after\nimport json\ndef run(self, params):\n    return json.dumps({\"ok\": True, \"result\": 42})","handlingStrategy":"type-guard","validationCode":"# contract test every tool must pass before registration\nimport json\n\ndef tool_returns_json_object(tool, sample_params) -> bool:\n    raw = tool.run(sample_params)\n    try:\n        payload = json.loads(raw)\n    except (TypeError, ValueError):\n        return False\n    return isinstance(payload, dict) and \"ok\" in payload\n\nassert tool_returns_json_object(my_tool, sample_params)","typeGuard":"import json\n\ndef is_json_object_string(raw: object) -> bool:\n    \"\"\"True when raw is a string decoding to a JSON object.\"\"\"\n    if not isinstance(raw, str):\n        return False\n    try:\n        return isinstance(json.loads(raw), dict)\n    except ValueError:\n        return False","tryCatchPattern":"try:\n    result = workflow.run(requirement)\nexcept WorkflowExecutionError as e:\n    if \"不是有效 JSON\" in str(e):\n        fix_tool_return_type()  # make the tool json.dumps() its result\n        result = workflow.run(requirement)\n    else:\n        raise","preventionTips":["Standardize a small base class/helper: tools always return json.dumps({...}) with ok/message keys.","Add contract tests for tools: valid JSON string, dict shape, ok present.","Never return Python repr output or free text from tools consumed by this workflow."],"tags":["python","json","tools","protocol"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}