克劳德有14%的概率返回JSON代码块。这是我希望早些时候就能拥有的Rust语言库。

发布日期:2026-05-21 10:01:42   浏览量 :0
发布日期:2026-05-21 10:01:42  
0

2026西湖龙井茶官网DTC发售:茶农直供,政府溯源防伪到农户家 

我曾使用一个系统提示词,其结尾为:仅回复一个 JSON 对象。不要包含代码围栏。不要包含解释。

这应该足够了。但事实并非如此。

在超过一周的结构化输出调用中(共 12,400 次,主要是 Claude Sonnet 4.5 和 4.7),我记录了响应在首次尝试使用 serde_json::from_str 时实际可被解析为 JSON 的频率。结果:86.0%。其余 14% 至少存在以下问题之一:

  • json ... 包装器(最常见,约占总数的 9.3%)
  • 前导或尾随的散文文本(例如:“这是您要求的 JSON:”)
  • 最后一个数组或对象元素后有多余逗号
  • 从训练数据中引入的智能引号

因此,我编写了 llm-json-repair。它包含三个按顺序应用的步骤,每一步都很廉价,且都不会重新调用大型语言模型。如果需要下游模型修复,那是您需要自行整合的问题。这个 crate 是在您花费另一次应用程序接口调用之前进行的本地清理工作。

三个步骤

use llm_json_repair::repair;

let raw = r#"```

json
{
  "intent": "book_flight",
  "slots": {
    "origin": "DAL",
    "destination": "JFK",
  },
}


```"#;

let cleaned = repair(raw)?;
let parsed: serde_json::Value = serde_json::from_str(&cleaned)?;

repair 实际上按顺序执行的操作如下:

步骤 1:去除围栏

查找第一个 ` 和最后一个 `。如果两者都存在,则提取它们之间的内容。可选的 json 语言标签会随起始围栏一起被丢弃。如果闭合围栏后有文本,则将其丢弃。

从概念上讲,这一步骤只是一行代码,但让我头疼的一个边缘情况是 JSON 字符串值中包含字面子串 `(是的,有一次输入了一份客户支持转录文本)。因此,匹配器仅在最外层去除围栏,且仅当围栏位于独立行或开头时才去除。

步骤 2:平衡提取

逐字符遍历。找到第一个 {[。计算嵌套层级。当嵌套层级归零时停止。返回该子字符串。

这一步骤无需模型即可去除前导散文(例如:“这是 JSON:”)和尾随散文(例如:“如果您还有其他需求,请告诉我。”)。它还处理模型连续输出两个 JSON 对象的情况(罕见但确实存在);您将获得第一个完整的对象。

`rust
let raw = "没问题!这是 JSON:\n{\"intent\": \"refund\", \"reason\": \"late\"}\n如果您有疑问,请告诉我。";
let cleaned = repair(raw)?;
assert_eq!(cleaned, r#"{"intent": "refund", "reason": "late"}"#);
`

这一步骤的成本是对响应进行 O(n) 复杂度的操作。对于 4 KB 的响应,在我的笔记本电脑上运行时间约为 30 微秒。

步骤 3:尾部 c

免责声明:本文内容来自互联网,该文观点不代表本站观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请到页面底部单击反馈,一经查实,本站将立刻删除。

关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
支持 反馈 订阅 数据
回到顶部