Go bindings for Outlines — powered by pyffi.
Outlines provides structured generation for LLMs. Instead of hoping the model produces valid output and parsing it afterwards, Outlines guarantees the output matches your specified type during token generation via constrained decoding.
go get github.com/i2y/pyffi/outlinesPython 3.12+ is required at runtime. The outlines package is auto-installed via uv on first use.
Outlines' constrained decoding works at the token level using finite state machines built from regex patterns and JSON schemas. This is deeply integrated with model tokenizers and cannot be practically reimplemented in Go.
model, _ := outlines.NewOllama("llama3.2")
defer model.Close()
// Generate structured JSON via Pydantic model
result, _ := model.PydanticJSON(
"Generate a profile for a Go programmer.",
"Profile",
map[string]string{
"name": "str",
"age": "int",
},
)
fmt.Println(result) // {"age":40,"name":"John Doe"}
// Unmarshal directly into a Go struct
var profile struct {
Name string `json:"name"`
Age int `json:"age"`
}
model.PydanticJSONTo(
"Generate a profile for a Go programmer.",
"Profile",
map[string]string{"name": "str", "age": "int"},
&profile,
)
fmt.Println(profile.Name, profile.Age)Run with a local Ollama server — no API key needed:
model, _ := outlines.NewOllama("llama3.2")model, _ := outlines.NewOpenAI("gpt-4o") // uses OPENAI_API_KEY env
model, _ := outlines.NewOpenAIWithKey("gpt-4o", "sk-...") // explicit keymodel, _ := outlines.NewAnthropic("claude-3-haiku-20240307") // uses ANTHROPIC_API_KEY env
model, _ := outlines.NewAnthropicWithKey("claude-3-haiku-20240307", "sk-...") // explicit keyRun Hugging Face models directly — requires PyTorch:
model, _ := outlines.NewTransformers("microsoft/Phi-3-mini-4k-instruct")Works with all providers. Define fields as a map of name → Python type:
result, _ := model.PydanticJSON(
"Extract the event details.",
"Event",
map[string]string{
"title": "str",
"date": "str",
"location": "str",
"attendees": "int",
},
)Force output to one of the given strings. Works with OpenAI and local models:
sentiment, _ := model.Choice(
"Classify: 'This product changed my life!'",
[]string{"Positive", "Negative", "Neutral"},
)Generate JSON matching a JSON Schema. Works with OpenAI and local models:
schema := map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]any{"type": "string"},
"age": map[string]any{"type": "integer"},
},
"required": []string{"name", "age"},
}
jsonStr, _ := model.JSON("Generate a profile.", schema)Generate text matching a regex. Works with local models:
ip, _ := model.Regex(
"What is the IP address of localhost?",
`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`,
)text, _ := model.Text("Tell me a joke.")| Method | Description | Providers |
|---|---|---|
PydanticJSON(prompt, name, fields) |
Structured JSON via Pydantic model | All |
PydanticJSONTo(prompt, name, fields, &dest) |
PydanticJSON + unmarshal to Go struct | All |
Choice(prompt, choices) |
Force one of the given strings | OpenAI, Local |
JSON(prompt, schema) |
JSON matching a JSON Schema | OpenAI, Local |
JSONTo(prompt, schema, &dest) |
JSON + unmarshal to Go struct | OpenAI, Local |
Regex(prompt, pattern) |
Text matching a regex pattern | Local |
Text(prompt) |
Unconstrained text generation | All |
Note: Provider support varies.
PydanticJSONis the most portable method and works across all providers including Ollama and Anthropic.