https://github.com/glidea/llm-structed
在 chat 场景中,通常模型不需要返回结构化的数据。但在 LLM 应用开发里,模型通常被视为提供某种原子能力的 API Service ,此时我们希望直接得到一个 JSON ,通常的解法有:
package main
import (
"context"
"fmt"
"github.com/glidea/llm-structed"
)
type Summary struct {
Title string `json:"title" desc:"The title of the summary"`
Content string `json:"content" desc:"A concise summary of the article content"`
Keywords []string `json:"keywords" desc:"Key topics mentioned in the article"`
Score int `json:"score" desc:"The quality score of the article (1-10)"`
Category string `json:"category" desc:"The category of the article" enum:"Technology,Science,Business,Health,Education,Other"`
}
func main() {
// New client (In minimal configuration, you only need to set the APIKey)
cli, _ := llmstructed.New(llmstructed.Config{
BaseURL: "https://openrouter.ai/api/v1",
APIKey: "sk-...",
Model: "google/gemini-flash-1.5",
Temperature: 0.3,
StructuredOutputSupported: true, // 使用方案 3
Retry: 1,
Debug: true,
// See source code comments of llmstructed.Config for these config detail
})
ctx := context.Background()
// Structured Outputed
var summary Summary
_ = cli.Do(ctx, []string{`Please generate a summary of this article: Artificial Intelligence (AI) is transforming the way we live and work. It refers to
computer systems that can perform tasks that normally require human intelligence. These
tasks include visual perception, speech recognition, decision-making, and language
translation. Machine learning, a subset of AI, enables systems to learn and improve
from experience without being explicitly programmed. Deep learning, particularly,
has revolutionized AI by using neural networks to process complex patterns in data.`,
}, &summary)
fmt.Printf("Go Struct: %v\n\n", summary)
// Simple method for single value
str, _ := cli.String(ctx, []string{"Hello, who are you?"})
fmt.Printf("String: %s\n\n", str)
languages, _ := cli.StringSlice(ctx, []string{"List some popular programming languages."})
fmt.Printf("String Slice: %v\n\n", languages)
count, _ := cli.Int(ctx, []string{`How many words are in this sentence: "Hello world, this is a test."`})
fmt.Printf("Integer: %d\n\n", count)
yes, _ := cli.Bool(ctx, []string{"Are you happy?"})
fmt.Printf("Boolean: %v\n\n", yes)
trues, _ := cli.BoolSlice(ctx, []string{"Are these statements true? [\"The sky is blue\", \"Fish can fly\", \"Water is wet\"]"})
fmt.Printf("Boolean Slice: %v\n\n", trues)
pi, _ := cli.Float(ctx, []string{"What is the value of pi (to two decimal places)?"})
fmt.Printf("Float: %.2f\n\n", pi)
}
![]() |
1
abc634 16 天前 ![]() 我的一个小经验:
让 api 返回 markdown 或者 html 或者 xml ,都比 json 好。 然后再解析 xml 就简单了。 |
2
IndexOutOfBounds OP @abc634 我理解场景有些区别,markdown 是半结构化的,主要用于直接展示,比如直接让 AI 用 markdown 写篇文章,这是很好的选择
json 是开发内部使用的,比如你需要提供接口给前端做二次展示 另外通过 json schema 可以做到很强的约束,比如文中给文章分类的例子,通过 enum:"Technology,Science,Business,Health,Education,Other" 强限制分类范围 |
3
IndexOutOfBounds OP |
![]() |
4
otakustay 16 天前 ![]() 用 function calling 呢?你需要的模型里有不支持 function 的吗
还有个办法是 Assistant Prefill ,不过我估计也不稳 |
![]() |
6
reeco 16 天前
还是 1 的方案吧,2 ,3 的方案你换个非 openai 的模型照样不能用
|
![]() |
7
ychost 16 天前
如果输出的 JSON 没有嵌套,就没必要让它输出 JSON 了,直接输出 kv 对,然后代码解析这样容错性更好
|
8
IndexOutOfBounds OP @otakustay 暂时不支持 function call ,不过确实有这个想法,自动注入结构体 Method
|
9
IndexOutOfBounds OP @reeco 非 openai ,比如 gemini ,deepseek 也支持 json 输出的,算是一个通用的规范了
https://openrouter.ai/models?fmt=cards&order=newest&supported_parameters=structured_outputs |
![]() |
10
otakustay 16 天前
要不这样,用写代码的思路,把你要的 schema 变成 TS interface ,然后下面写个 function 定义接收这个类型的参数,再一段注释说明你的需求,最后是 functionName({起头,让模型给你补……
|
12
lovestudykid 15 天前
还有个办法是给 json 开个头
|
![]() |
13
neptuno 14 天前
试了很多,function calling 是最优解
|