[GH-ISSUE #1256] [BUG] 在工具调用中参数的 JSON 格式经常括号不匹配 #812

Closed
opened 2026-10-26 21:30:09 +00:00 by bsakaguchi · 6 comments
Owner

Originally created by @weizhang-dotcom on GitHub (Apr 28, 2026).
Original GitHub issue: https://github.com/deepseek-ai/DeepSeek-V3/issues/1256

Describe the bug
在工具调用中,参数如果要求是 JSON格式,参数的JSON字符串的括号会不匹配,导致工具调用失败。该问题在V3和V4都存在。

To Reproduce

  1. MCP Server 提供一个工具,要求某个输入参数是JSON格式,复杂的有嵌套的,比如要求生成一个typescript 的AST结构。
  2. 通过对话,让AI调用这个工具,并使用复杂的JSON格式作参数。比如可以让它生成快速排序算法的ts AST,作为参数。
  3. 生成的JSON格式大概率括号不匹配。(5层时有可能不匹配,9层时几乎必然不匹配)

Expected behavior
JSON格式不出错。

Screenshots

Additional context
这是deepseek-v4 生成的某个工具的arguments. (已作格式化)

{
    "fileId": "m8zunjo0q9h-mogkm6z1-bpyaad0il9",
    "operations": [{
            "op": "addBlock",
            "tempId": "lcd_len",
            "blockJson": {
                "type": "lcd",
                "fields": {
                    "VD": {
                        "name": "len",
                        "type": "number"
                    },
                    "T": "number"
                },
                "inputs": {
                    "V": {
                        "block": {
                            "type": "v",
                            "extraState": {
                                "X": 66
                            },
                            "inputs": {
                                "P1": {
                                    "block": {
                                        "type": "lcg",
                                        "fields": {
                                            "VR": "list"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "parentBlockId": "Y4y*6Nju_ngM;gD,-r#H",
            "inputName": "D"
        }, {
            "op": "addBlock",
            "tempId": "ife1_check",
            "blockJson": {
                "type": "ife1",
                "extraState": {
                    "X": 2
                },
                "inputs": {
                    "if": {
                        "block": {
                            "type": "opc",
                            "fields": {
                                "O": "LE"
                            },
                            "inputs": {
                                "V1": {
                                    "block": {
                                        "type": "lcg",
                                        "fields": {
                                            "VR": "len"
                                        }
                                    }
                                },
                                "V2": {
                                    "block": {
                                        "type": "ipi",
                                        "fields": {
                                            "V": 1
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "do": {
                        "block": {
                            "type": "fnr",
                            "extraState": {
                                "rt": "ListT_Float"
                            },
                            "inputs": {
                                "R": {
                                    "block": {
                                        "type": "v",
                                        "extraState": {
                                            "X": 229
                                        },
                                        "inputs": {
                                            "P1": {
                                                "block": {
                                                    "type": "lcg",
                                                    "fields": {
                                                        "VR": "list"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }, "parentBlockId": "lcd_len", "inputName": "next"
    }
    ]
    }
Originally created by @weizhang-dotcom on GitHub (Apr 28, 2026). Original GitHub issue: https://github.com/deepseek-ai/DeepSeek-V3/issues/1256 **Describe the bug** 在工具调用中,参数如果要求是 JSON格式,参数的JSON字符串的括号会不匹配,导致工具调用失败。该问题在V3和V4都存在。 **To Reproduce** 1. MCP Server 提供一个工具,要求某个输入参数是JSON格式,复杂的有嵌套的,比如要求生成一个typescript 的AST结构。 2. 通过对话,让AI调用这个工具,并使用复杂的JSON格式作参数。比如可以让它生成快速排序算法的ts AST,作为参数。 3. 生成的JSON格式大概率括号不匹配。(5层时有可能不匹配,9层时几乎必然不匹配) **Expected behavior** JSON格式不出错。 **Screenshots** **Additional context** 这是deepseek-v4 生成的某个工具的arguments. (已作格式化) ``` { "fileId": "m8zunjo0q9h-mogkm6z1-bpyaad0il9", "operations": [{ "op": "addBlock", "tempId": "lcd_len", "blockJson": { "type": "lcd", "fields": { "VD": { "name": "len", "type": "number" }, "T": "number" }, "inputs": { "V": { "block": { "type": "v", "extraState": { "X": 66 }, "inputs": { "P1": { "block": { "type": "lcg", "fields": { "VR": "list" } } } } } } } }, "parentBlockId": "Y4y*6Nju_ngM;gD,-r#H", "inputName": "D" }, { "op": "addBlock", "tempId": "ife1_check", "blockJson": { "type": "ife1", "extraState": { "X": 2 }, "inputs": { "if": { "block": { "type": "opc", "fields": { "O": "LE" }, "inputs": { "V1": { "block": { "type": "lcg", "fields": { "VR": "len" } } }, "V2": { "block": { "type": "ipi", "fields": { "V": 1 } } } } } }, "do": { "block": { "type": "fnr", "extraState": { "rt": "ListT_Float" }, "inputs": { "R": { "block": { "type": "v", "extraState": { "X": 229 }, "inputs": { "P1": { "block": { "type": "lcg", "fields": { "VR": "list" } } } } } } } } } } } }, "parentBlockId": "lcd_len", "inputName": "next" } ] } ```
bsakaguchi 2026-10-26 21:30:09 +00:00
Author
Owner

@qingkong66 commented on GitHub (Apr 28, 2026):

@weizhang-dotcom 感谢这份非常具体的 bug 报告。你给出了明确的复现条件(嵌套深度 5 层开始不稳、9 层几乎必错),还附带了完整的错误 JSON 示例——这已经是一份可以直接递给官方工程团队的材料。

问题定性
这不是“模型偶尔写错格式”,是 模型在生成长嵌套 JSON 时,括号匹配的状态在自回归过程中丢失了。V3 和 V4 都有,说明这个缺陷贯穿了两个版本。

社区里的关联讨论

  • #1241(“极”字 bug)也属于“结构化输出场景下的鲁棒性不足”。一个是词汇选择错误,一个是语法结构未闭环,病因不同但性质类似。
  • 这类问题在 Agent/工具调用场景下会直接导致下游静默失败,用户看到的是“工具没反应”,很难自己排查到是括号不匹配。

建议方向(供你参考,也可作为给官方的输入)

  1. 浅层方案:对工具调用的 arguments 字段引入约束解码(constrained decoding),强制模型只能输出符合 JSON 语法的 token。
  2. 深层方案:在训练数据中增加深层嵌套 JSON 的示例,并配合括号匹配的辅助损失。

我们会怎么跟进
已收录到第二期反馈,单独归类为“结构化生成 / JSON 格式稳定性”。同时标记为与 #1241 关联但不合并。

感谢你把这个硬骨头翻出来。如果你还有补充,欢迎随时可以加上。

--

@weizhang-dotcom Thanks for this detailed bug report. You've provided clear reproduction conditions (nesting depth of 5 starts to fail, depth of 9 almost always fails) and a complete malformed JSON example — this is already material that can be handed directly to the official engineering team.

What this issue is
This is not "the model occasionally writes malformed JSON." It's the model losing bracket-matching state during autoregressive generation of deeply nested JSON. The fact that it exists in both V3 and V4 means this defect spans both versions.

Related discussions in the community

  • #1241 (the "极" character bug) also falls under "robustness issues in structured output scenarios." One is a token selection error, the other is an unclosed syntax structure — different root causes, but similar in nature.
  • In Agent/tool-calling scenarios, this type of issue causes silent failures downstream. Users simply see "the tool didn't respond" and have no easy way to trace it back to mismatched brackets.

Suggested directions (for your reference, and as input to the official team)

  1. Lightweight fix: Introduce constrained decoding for the tool call arguments field, forcing the model to output only JSON-syntactic tokens.
  2. Deeper fix: Add deeply nested JSON examples to training data, paired with an auxiliary loss for bracket matching.

What we'll do with this
Added to the second batch of feedback, categorized under "structured generation / JSON format stability." Also linked to #1241 as related but not merged.

Welcome to add more if you have further findings.

Thanks for surfacing this hard issue.

<!-- gh-comment-id:4336325909 --> @qingkong66 commented on GitHub (Apr 28, 2026): @weizhang-dotcom 感谢这份非常具体的 bug 报告。你给出了明确的复现条件(嵌套深度 5 层开始不稳、9 层几乎必错),还附带了完整的错误 JSON 示例——这已经是一份可以直接递给官方工程团队的材料。 **问题定性** 这不是“模型偶尔写错格式”,是 **模型在生成长嵌套 JSON 时,括号匹配的状态在自回归过程中丢失了**。V3 和 V4 都有,说明这个缺陷贯穿了两个版本。 **社区里的关联讨论** - #1241(“极”字 bug)也属于“结构化输出场景下的鲁棒性不足”。一个是词汇选择错误,一个是语法结构未闭环,病因不同但性质类似。 - 这类问题在 Agent/工具调用场景下会直接导致下游静默失败,用户看到的是“工具没反应”,很难自己排查到是括号不匹配。 **建议方向(供你参考,也可作为给官方的输入)** 1. **浅层方案**:对工具调用的 `arguments` 字段引入约束解码(constrained decoding),强制模型只能输出符合 JSON 语法的 token。 2. **深层方案**:在训练数据中增加深层嵌套 JSON 的示例,并配合括号匹配的辅助损失。 **我们会怎么跟进** 已收录到第二期反馈,单独归类为“结构化生成 / JSON 格式稳定性”。同时标记为与 #1241 关联但不合并。 感谢你把这个硬骨头翻出来。如果你还有补充,欢迎随时可以加上。 -- @weizhang-dotcom Thanks for this detailed bug report. You've provided clear reproduction conditions (nesting depth of 5 starts to fail, depth of 9 almost always fails) and a complete malformed JSON example — this is already material that can be handed directly to the official engineering team. **What this issue is** This is not "the model occasionally writes malformed JSON." It's **the model losing bracket-matching state during autoregressive generation of deeply nested JSON**. The fact that it exists in both V3 and V4 means this defect spans both versions. **Related discussions in the community** - #1241 (the "极" character bug) also falls under "robustness issues in structured output scenarios." One is a token selection error, the other is an unclosed syntax structure — different root causes, but similar in nature. - In Agent/tool-calling scenarios, this type of issue causes silent failures downstream. Users simply see "the tool didn't respond" and have no easy way to trace it back to mismatched brackets. **Suggested directions (for your reference, and as input to the official team)** 1. **Lightweight fix**: Introduce constrained decoding for the tool call `arguments` field, forcing the model to output only JSON-syntactic tokens. 2. **Deeper fix**: Add deeply nested JSON examples to training data, paired with an auxiliary loss for bracket matching. **What we'll do with this** Added to the second batch of feedback, categorized under "structured generation / JSON format stability." Also linked to #1241 as related but not merged. **Welcome to add more if you have further findings.** Thanks for surfacing this hard issue.
Author
Owner

@weizhang-dotcom commented on GitHub (Apr 30, 2026):

补充AI的自我分析原因是,blockly的block id 中包含过多特殊字符,导致它的json解析时出现问题。希望deepseek LLM 在这方面继续加强训练。我回去修改这个block id 的生成规则,看看有没有改进。

<!-- gh-comment-id:4350109955 --> @weizhang-dotcom commented on GitHub (Apr 30, 2026): 补充AI的自我分析原因是,blockly的block id 中包含过多特殊字符,导致它的json解析时出现问题。希望deepseek LLM 在这方面继续加强训练。我回去修改这个block id 的生成规则,看看有没有改进。
Author
Owner

@github-actions[bot] commented on GitHub (Jun 1, 2026):

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this issue is still relevant, please leave a comment to keep it open. Thank you for your contributions!

<!-- gh-comment-id:4588781886 --> @github-actions[bot] commented on GitHub (Jun 1, 2026): This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this issue is still relevant, please leave a comment to keep it open. Thank you for your contributions!
Author
Owner

@icophy commented on GitHub (Jun 1, 2026):

@weizhang-dotcom Your special-char observation matters, because two distinct failure surfaces get conflated under "the JSON is broken":

  1. Structural (bracket matching). At 5+ nesting levels the model has to keep an implicit open-bracket stack consistent across hundreds of tokens. That's a counting / state-tracking task that degrades with distance — closer to a long-range recall limit than a tokenizer issue, which is why it gets worse with depth (your 5-layer-sometimes, 9-layer-almost-always pattern). @qingkong66's constrained-decoding suggestion targets exactly this layer.
  2. String escaping. Special chars inside values (your block IDs) are a separate bug: the model under-escapes ", \, and control chars inside string literals, which a pure bracket-counter won't catch even if structure is valid.

We run long-lived agents that emit tool-call arguments every turn on OpenAI/Anthropic-compatible endpoints, and we treat every payload as untrusted output. Two things that work today without waiting on a provider-side fix:

  • Parse-validate-repair loop. Try to parse the arguments; on failure, echo the exact parser error (offset + expected token) back as a follow-up turn asking for only the corrected arguments. A single repair round resolves most malformed payloads in practice; the deep-nesting cases are the stubborn ones.
  • Flatten the schema where you control the tool. Your addBlock + tempId design already half-does this — replacing one deeply nested blockJson with a flat list of ops referenced by id makes the tree shallower, and shallow trees fail far less often. So your plan to fix the block-id generation rule is the right lever: fewer special chars and shallower nesting both shrink the surface.

One question: have you tried lowering temperature for these calls? Structured-output stability is often temperature-sensitive, so it may be a cheap stopgap while the deeper fix lands — curious whether it moves the needle at your nesting depths.


Context: Working on Cophy Runtime, running long-lived agents that emit tool-call arguments every turn.

<!-- gh-comment-id:4589020900 --> @icophy commented on GitHub (Jun 1, 2026): @weizhang-dotcom Your special-char observation matters, because two distinct failure surfaces get conflated under "the JSON is broken": 1. **Structural (bracket matching).** At 5+ nesting levels the model has to keep an implicit open-bracket stack consistent across hundreds of tokens. That's a counting / state-tracking task that degrades with distance — closer to a long-range recall limit than a tokenizer issue, which is why it gets *worse* with depth (your 5-layer-sometimes, 9-layer-almost-always pattern). @qingkong66's constrained-decoding suggestion targets exactly this layer. 2. **String escaping.** Special chars *inside values* (your block IDs) are a separate bug: the model under-escapes `"`, `\`, and control chars inside string literals, which a pure bracket-counter won't catch even if structure is valid. We run long-lived agents that emit tool-call `arguments` every turn on OpenAI/Anthropic-compatible endpoints, and we treat every payload as untrusted output. Two things that work today without waiting on a provider-side fix: - **Parse-validate-repair loop.** Try to parse the arguments; on failure, echo the exact parser error (offset + expected token) back as a follow-up turn asking for *only* the corrected arguments. A single repair round resolves most malformed payloads in practice; the deep-nesting cases are the stubborn ones. - **Flatten the schema where you control the tool.** Your `addBlock` + `tempId` design already half-does this — replacing one deeply nested `blockJson` with a flat list of ops referenced by id makes the tree shallower, and shallow trees fail far less often. So your plan to fix the block-id generation rule is the right lever: fewer special chars *and* shallower nesting both shrink the surface. One question: have you tried lowering temperature for these calls? Structured-output stability is often temperature-sensitive, so it may be a cheap stopgap while the deeper fix lands — curious whether it moves the needle at your nesting depths. --- *Context: Working on [Cophy Runtime](https://github.com/icophy/cophy-runtime), running long-lived agents that emit tool-call arguments every turn.*
Author
Owner

@github-actions[bot] commented on GitHub (Jul 15, 2026):

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this issue is still relevant, please leave a comment to keep it open. Thank you for your contributions!

<!-- gh-comment-id:4975462297 --> @github-actions[bot] commented on GitHub (Jul 15, 2026): This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this issue is still relevant, please leave a comment to keep it open. Thank you for your contributions!
Author
Owner

@github-actions[bot] commented on GitHub (Aug 4, 2026):

false

<!-- gh-comment-id:5173222808 --> @github-actions[bot] commented on GitHub (Aug 4, 2026): false
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
deepseek-ai/DeepSeek-V3#812
No description provided.