ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

TypeLLM输出类型全解析:7种字段类型实现零幻觉JSON Schema约束输出

TypeLLM输出类型全解析:7种字段类型实现零幻觉JSON Schema约束输出

【免费下载链接】TypeLLM

TypeLLM: LLMs with type-safe generation

项目地址:https://gitcode.com/gh_mirrors/ty/TypeLLM
点击查看免费下载

TypeLLM 是一个让大语言模型"按类型说话"的开源框架:它不改模型架构和权重,通过 JSON Schema 约束,让 LLM 输出零幻觉的结构化结果。本文完整解析 TypeLLM 支持的 7 种字段类型(string、integer、number、boolean、enum 选择、object、array),带你快速上手类型安全生成(type-safe generation),告别"模型说一套、程序收到另一套"的解析噩梦。

为什么需要类型安全的 LLM 输出?

普通 LLM 输出的是自由文本,下游程序要靠正则、prompt 技巧和后处理来"猜"出结构化数据,稍有不慎就得到格式错误、数值越界或根本不存在的枚举值。

TypeLLM 的思路是:把"类型"直接交给解码器。每个字段由 JSON Schema 片段描述,模型在生成时就被限制在合法候选内——枚举值只能从列表里选、布尔只能是 true/false、数值按有界十进制逐位解码。配合 SGLang 的共享前缀 KV 缓存,多个字段一次调用批量完成,token 成本极低。

核心卖点一览:

  • ✅无越界幻觉:选择类字段永远落在允许的候选值内
  • ⚡输出 token 开销可忽略:枚举/布尔字段各只花 1 个输出 token
  • 🧩依赖感知执行:depends_on声明依赖图,独立字段并行运行
  • 💭可选思考模式:需要推理的字段可先想后答,"thinking": "auto"自动选档
  • 🖼️图片输入:支持视觉语言模型,还能返回图像中目标的位置框

7 种字段类型速览

TypeLLM 的 7 种输出字段类型及返回值对照如下(来源:README.md#L193-L207):

字段类型Schema 写法返回的 Python 值
文本{"type": "string"}str
整数{"type": "integer"}int
数值{"type": "number"}float
布尔{"type": "boolean"}bool
枚举选择{"type": "string", "enum": ["meal", "travel"]}候选类型之一:str/int/float
对象{"type": "object", "properties": {...}}dict
数组{"type": "array", "items": {...}}list

1️⃣ string:自由文本与枚举选择

string是最灵活的类型,分两种用法:

  • 不带enum:自由文本生成,默认最多 128 token,可用text_max_tokens放宽;
  • 带enum:枚举选择,候选 2~26 个(上限见 typellm/schema.py#L12 的MAX_ENUM_CHOICES),答案必然是其中之一。
questions = { "expense_type": { "type": "string", "enum": ["meal", "travel", "equipment"], "instructions": "What type of expense is this?", }, } # 结果必然是 "meal"、"travel" 或 "equipment",绝无第四种

枚举还支持choices写法,为每个候选附加描述,帮助模型理解含义。想要"答案有多确定",给该字段加return_probabilities: True,即可拿到每个候选的概率和confidence置信度。

2️⃣ integer 与 number:有界数值解码

不需要把 0~999999 全列成枚举。integer返回int、number返回float,模型用有界十进制逐位解码数字,默认最多 32 位(numeric_max_digits可调)。

"total": {"type": "number", "instructions": "Extract the total amount in GBP."} # {"total": 324.5}

进阶技巧:给number字段加levels(带顺序标签的等级),还能得到"评分(Score)"字段——返回各等级概率加权后的分数,如1.1表示介于"有替代方案"和"完全阻塞"之间。

3️⃣ boolean:是/否判断

boolean只输出True或False,适合"是否符合政策""是否已付款"这类二值判断。同样支持return_probabilities拿到两者的概率分布,配合temperature还可做有随机性的采样。

4️⃣ object 与 array:嵌套结构化数据

  • object把多个带类型的属性聚合成一个值,属性内部照样可用enum、thinking、depends_on;
  • array返回不定数量的同构条目,每条最多 50 个,支持minItems/maxItems约束,条目可以是枚举值,也可以是对象。
"employees": { "type": "array", "items": {"type": "object", "properties": { "name": {"type": "string"}, "role": {"type": "string"}, }}, "instructions": "Return all employees.", } # {"employees": [{"name": "Ada", "role": "CTO"}, ...]}

输入太长放不下一次调用时,用continue_from把上一段已得的条目传进去,数组会接着长、永不改写已有条目。

5️⃣ 组合拳:nullable 与字段依赖

  • 任意类型加"null"(如["number", "null"])即可表达"可能缺失",没有值时返回None;
  • depends_on让字段引用上游结果,形成依赖图——先跑system,再并行跑severity和deployment_related,最后跑依赖二者的rollback;
  • when条件字段:依赖字段的取值满足条件才执行,否则跳过并记入response.skipped,还支持按confidence判断"答案够不够确定"。

字段编译的完整逻辑见 typellm/schema.py(Decision/ArrayField数据类,typellm/schema.py#L24 起)。

实战:一张皱巴巴的收据,14 个类型化字段

官方示例 examples/receipt/receipt.py 把一张真实拍摄的餐厅收据照片喂给模型,一次generate()调用同时读出:

  • string:三行商品名(含原样保留的拼写错误)
  • integer:行数、数量
  • number:小计、折扣、总额、现金、找零
  • boolean:是否现金支付
  • 通过depends_on由前序字段计算出的派生字段:折扣百分比、找零是否正确、一句话报销备注

在 Qwen3.8-27B 上,不开思考 6.6 秒匹配 11/13,开思考 27.7 秒匹配 12/13,所有数值都精确命中。完整输出见 examples/receipt/result.json 与 examples/receipt/result_thinking.json,运行说明在 examples/receipt/README.md。

精度验证:JevBench 231 题基准测试

"零幻觉"只是底线,答得准才是本事。TypeLLM 在 231 道公开 JevBench 任务上的成绩:不开思考 195/231,开思考228/231(98.70%),且未做任何微调。

方法与配置细节见 evals/jevbench/METHOD.md,逐题答案见 evals/jevbench/README.md。

快速上手

pip install -U typellm
from typellm import TypeLLMClient client = TypeLLMClient("http://127.0.0.1:30000", model="Qwen/Qwen3.8-27B") response = client.generate( context="Receipt from Hilton London. Total: £324.50", questions={ "merchant": {"type": "string", "instructions": "Return only the merchant name."}, "total": {"type": "number", "instructions": "Extract the total amount in GBP."}, "expense_type": {"type": "string", "enum": ["meal", "travel", "equipment"]}, "reimbursable": {"type": "boolean"}, }, ) print(response.result) # {"merchant": "Hilton London", "total": 324.5, "expense_type": "travel", "reimbursable": True}

客户端实现位于 typellm/runtime.py,一次性请求可用便捷函数run_schema。行为测试覆盖在 tests/ 目录,其中 tests/test_structured.py 专门验证 object/array 等结构化类型。

选型建议:7 种字段类型怎么选?

你的场景推荐字段类型
分类打标签、路由工单string+enum(加choices描述更稳)
金额、数量、百分比number/integer
合规判断、是否通过boolean(加return_probabilities)
摘要、备注、自由描述string(纯文本)
一组相关属性打包object
不定数量条目:技能列表、员工清单array
可能缺失的字段任意类型 +"null"

一句话总结:能枚举就枚举,能布尔就布尔,数值交给 integer/number,结构用 object/array 打包——把每个字段都钉死在类型里,TypeLLM 的解码器就会把"幻觉"挡在门外。

参考资料

  • 项目总览与更新日志:README.md
  • 类型定义与依赖图执行:typellm/schema.py、typellm/runtime.py
  • 收据实战示例:examples/receipt/receipt.py
  • 结构化类型测试:tests/test_structured.py
  • JevBench 基准与逐题答案:evals/jevbench/

【免费下载链接】TypeLLM

TypeLLM: LLMs with type-safe generation

项目地址:https://gitcode.com/gh_mirrors/ty/TypeLLM
点击查看免费下载

相关推荐

上一篇:探秘HuJSON:高效、易用的JSON解析库
下一篇:探索MAME4iOS:复古游戏爱好者的移动乐园

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进