资讯动态

Go Struct秒变JSON Schema:Fantasy schema反射生成机制源码揭秘

发布时间:2026/10/15 16:14:01 来源:尧图企业网站定制
人工智能AI AgentAgent 框架工具调用大模型【免费下载链接】fantasyBuild AI agents with Go. Multiple providers, multiple models, one API. 项目地址https://gitcode.com/gh_mirrors/fantasy6/fantasy点击查看免费下载Fantasy 是一个用 Go 构建 AI Agent 的开源框架主打“多 Provider、多模型、统一 API”。它最让人眼前一亮的机制之一就是内置的schema 反射生成你只要定义一个普通的 Go Struct它就能在运行时自动“秒变” JSON Schema直接用于 LLM 的结构化输出Structured Outputs和工具调用Tool Calling的参数校验——全程零手工编写。一、为什么需要自动反射生成 JSON Schema 当你让大模型返回“可用的数据”而不是“自由文本”时必须给它一份 JSON Schema工具调用模型要知道每个参数的名字、类型、是否必填才能正确填写工具入参结构化输出模型返回的 JSON 要能被解析、校验最终 unmarshal 成你的 Go 类型传统做法是手写一份 Schema 描述再手动同步字段——字段一改Schema 就过期了。Fantasy 的思路很直接既然你的 Go Struct 本身就是一份“类型即文档”的声明那就用 reflect 包在运行时把它反射成 Schema。核心实现集中在 schema/schema.go入口函数只有两行// Generate 从 reflect.Type 递归生成 JSON Schema func Generate(t reflect.Type) Schema { return generateSchemaRecursive(t, make(map[reflect.Type]bool)) }见 schema/schema.go。下面进入源码拆解。二、入口在哪里泛型调用背后发生了什么在 Fantasy 里你几乎不需要直接调用schema.Generate两个最常用的泛型入口会自动触发反射1️⃣ 结构化对象生成—— object/object.govar zero T s : schema.Generate(reflect.TypeOf(zero)) opts.Schema s调用object.GenerateRecipe时框架取出 T 的零值、反射出类型自动生成 Schema 并塞进请求模型返回后再校验、unmarshal 回*Recipe。2️⃣ 工具定义—— tool.goNewAgentToolTInput内部同样执行schema.Generate(reflect.TypeOf(input))见 tool.go生成的 Schema 再通过ToParameters转成模型 API 需要的parameters字段见 tool.go。 一句话总结你写 Struct → 反射生成 Schema → 自动注入请求 → 返回结果自动校验形成闭环。三、核心源码拆解generateSchemaRecursive 的递归逻辑所有魔法都发生在 generateSchemaRecursive 中它是一个对reflect.Kind做 switch 的递归函数。3.1 基础类型映射一眼看懂Go 类型生成的 JSON Schema typestringstringint/int8~int64/ 各种uintintegerfloat32/float64numberboolboolean[]T/[N]Tarray递归生成itemsmap[string]Tobject带通配属性*structobject递归展开字段指针*T先解引用按T本身生成interface{}/ 其他object兜底指针会被直接解引用见 schema/schema.go所以*string字段照样生成string类型字符串切片、嵌套 struct、map 都会一路递归到底。3.2 struct 字段解析三个 Struct Tag 决定一切这是整个机制中最实用的一段位于 schema/schema.goStruct Tag作用示例json:name指定字段名覆盖 Go 字段名json:name,...含omitempty该字段不算必填从required列表中移除json:-完全跳过该字段不出现在 Schema 中无 json tag字段名自动转 snake_caseFirstName→first_name见 toSnakeCasedescription:...写入字段的description给模型看的字段说明enum:a,b,c生成enum枚举约束限制模型只能取这几个值几个值得注意的细节未导出字段直接跳过!field.IsExported()与 Go 序列化习惯保持一致description标签直接喂给模型——这是控制输出质量的关键模型看到描述才知道字段语义enum标签按逗号切分逐个 trim 后写入Enum数组见 schema/schema.go官方开发文档 AGENTS.md 中也明确了这一约定Struct tags json, description, enum drive schema generation。3.3 循环引用的优雅处理visited 防环机制Go 里链表这种自引用结构很常见type Node struct { Value string json:value Next *Node json:next,omitempty }如果递归不加限制Node → *Node → Node → ...会无限递归。Fantasy 用一个visited map[reflect.Type]bool解决进入某个类型前打标记发现已访问过就短路返回object见 schema/schema.go测试用例可参考 schema/schema_test.go。3.4 生成的 Schema 长什么样内部Schema结构体schema/schema.go保留了 JSON Schema 最常用的字段Type、Properties、Required、Items、Description、Enum、Format以及Minimum/Maximum/MinLength/MaxLength等约束。以 examples/structured-outputs/main.go 中的 Recipe 为例type Recipe struct { Name string json:name description:The name of the recipe Ingredients []string json:ingredients description:List of ingredients needed Steps []string json:steps description:Step-by-step cooking instructions PrepTime int json:prep_time description:Preparation time in minutes }反射后大致等价于一个object四个 propertiesname为 string、ingredients/steps为 string 数组、prep_time为 integer且全部必填、各带 description。完整可运行示例见 examples/structured-outputs/main.go。四、从 Schema 到 API 参数ToParameters 与 Normalize生成只是第一步还要适配各家模型 API 的差异ToParametersschema/schema.go把Schema转成ToolInfo.Parameters需要的map[string]any工具定义直接可用ToMapschema/schema.go递归转成标准 JSON Schema 的 map其中还藏着一个兼容性细节——为 llama.cpp 等对items.type敏感的后端补上缺失的type字段Normalizeschema/schema.goOpenAI 会拒绝type: [string,null]这种类型数组该函数会递归把 type 数组改写为anyOf并给裸array补上items: {}——多 Provider 兼容正是 Fantasy 的招牌能力五、Schema 的另一半使命返回结果的解析与校验 生成 Schema 用来“约束输入”同一套机制反过来也负责“约束输出”ParsePartialJSONschema/schema.go先标准解析失败则调用内置的 jsonrepair 修复补全括号、去尾逗号等并返回successful / repaired / failed四种状态ParseAndValidateschema/schema.go解析 基于 kaptinlin/jsonschema 编译校验失败时返回携带原始文本的ParseError方便重试ParseAndValidateWithRepairschema/schema.go支持注入自定义ObjectRepairFunc校验不通过时把错误交给 LLM 再“修一次”各 Provider 实现中都有调用如 providers/openai/language_model.go也就是说模型哪怕吐出一段带毛边的 JSONFantasy 也会尽力修复并按 Schema 校验最终给你一个干净、类型安全的 Go 结构体。六、快速上手三步体验 Struct → JSON Schema克隆仓库如需源码git clone https://gitcode.com/gh_mirrors/fantasy6/fantasy定义带 tag 的 Struct给每个字段加上json、description需要枚举时加enum写法参考 schema/schema_test.go 的WeatherInput调用泛型入口object.Generate你的类型获取结构化输出或fantasy.NewAgentTool入参类型让工具参数自动生成 Schema枚举支持的完整断言可看 TestEnumSupport嵌套 struct、指针、递归结构体的边界行为在 schema/schema_test.go 中都有覆盖。七、总结这套反射机制好在哪✨零同步成本Schema 与类型永远一致改 Struct 即改 Schema不存在“文档漂移”声明式约束description和enum标签把业务约束直接翻译成模型能读懂的约束显著提升输出准确率防御式闭环递归防环、JSON 修复、Schema 校验、Provider 差异归一化Normalize细节拉满多 Provider 通用同一份 Schema 经ToParameters/ToMap即可喂给 OpenAI、Anthropic、Google 等各家 API对 Go 开发者来说Fantasy 的 schema 包把“让 LLM 说人话”这件事收敛成了最熟悉的一个动作——定义一个 Struct。想深入源码建议从 schema/schema.go 的generateSchemaRecursive读起再顺着 object/object.go 和 tool.go 看消费链路半天时间就能吃透整套反射生成机制。赞分享人工智能AI AgentAgent 框架工具调用大模型【免费下载链接】fantasyBuild AI agents with Go. Multiple providers, multiple models, one API. 项目地址https://gitcode.com/gh_mirrors/fantasy6/fantasy点击查看免费下载相关推荐深入解析 invopop/jsonschema从 Go 类型反射生成 JSON Schema 的完整实战指南深入解析 invopop/jsonschema从 Go 类型反射生成 JSON Schema 的完整实战指南 导读 本篇文章围绕 devspace 仓库中引入云原生开发工具DevOps容器编排如何用Assistant-UI实现JSON Schema秒变React组件AI开发效率提升的黑科技如何用Assistant UI实现JSON Schema秒变React组件AI开发效率提升的黑科技 在现代前端开发中将JSON Schema转换为React前端UI组件人工智能AI Agentmcp-go 结构化输入输出实战用 Go struct 自动生成 Tool 的 JSON Schema 与 structuredContent 结果mcp go 结构化输入输出实战用 Go struct 自动生成 Tool 的 JSON Schema 与 structuredContent 结果 mcp人工智能MCP 服务MCP Clients创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑