LLM Tool Call 的 JSON 自愈机制
做 LLM Tool Calling 时,一个很现实的问题是:
模型输出的 JSON,经常不是合法 JSON。
尤其是本地模型、量化模型、Ollama 系列,经常出现:
{"a":1,}或者:
{
"text": "hello
world"
}甚至直接:
None如果直接:
json.loads(raw_args)那么 Tool Runtime 很容易:
HTTP 400
invalid tool call arguments因此生产环境里,通常都会在 Tool Runtime 前增加一层:
LLM
↓
Repair Layer
↓
Tool Runtime核心目标不是“严格正确”,而是:
尽可能修复,保证系统别崩。
修复流程
整个 repair pipeline 基本可以概括为:
1. 空值修复
2. 宽松解析
3. 结构修复
4. 字符修复
5. 最终兜底1. 空值修复
处理:
""
" "
None统一转成:
{}避免最基础的解析错误。
2. 宽松 JSON 解析(最核心)
核心代码:
json.loads(raw, strict=False)这是整个 repair 的关键。
因为很多模型的问题,其实不是结构错误,而是字符串污染:
{
"text": "hello
world"
}strict=False 可以容忍:
未转义换行
tab
control chars
然后再:
json.dumps(parsed)重新序列化为标准 JSON:
{"text":"hello\nworld"}本质上:
用“宽松解析 + 标准重编码”完成 JSON 标准化。
3. 结构修复
如果还是解析失败,就进入字符串级修复。
删除尾随逗号
修复:
{"a":1,}变成:
{"a":1}补全缺失括号
修复:
{"a":[1,2自动补:
{"a":[1,2]}删除多余闭合符
修复:
{"a":1}}}循环删除尾部 }。
4. 非法字符修复
很多模型会输出非法控制字符:
\r
\t
\x00需要统一转义:
\n → \\n
\t → \\t否则 JSON 仍然无法解析。
5. 最终兜底
如果所有修复都失败:
return "{}"这里体现的是一种很典型的 AI Runtime 思路:
宁可丢参数,也不要让整个 Session 崩掉。
核心思想
传统系统默认:
输入是可信的但 LLM 系统必须默认:
模型输出永远不可信所以 Tool Calling 真正重要的,不只是 Function Calling,而是:
Repair Layer
Validation Layer
Retry Layer否则:
json.loads()就足以让整个 Runtime 不稳定。
一句话总结
这个 repair 函数本质上是在做:
“把 LLM 输出的半结构化脏数据,尽可能修复成可执行 JSON,并保证 Tool Runtime 永不因解析失败而崩溃。”
LLM Tool Call 的 JSON 自愈机制
https://blog.cikaros.cn/archives/llm-tool-call-de-json-zi-yu-ji-zhi