micro/go-micro · error
flow: LLMOptimizer requires a model
Error message
flow: LLMOptimizer requires a model
What it means
The PromptOptimizer was constructed without a backing AI model, so OptimizePrompt cannot generate a revised prompt. The check also covers calling the method on a nil receiver. The library refuses to proceed rather than panicking on a nil model.
Source
Thrown at flow/analyze.go:159
runs, graded, gradeFailures, errors, retries int
feedback, runIDs []string
latencies []time.Duration
}
// PromptOptimizer proposes prompt improvements for a candidate without mutating
// the source flow. Applying the returned prompt stays explicitly gated by the caller.
type PromptOptimizer struct{ model ai.Model }
// LLMOptimizer returns an optimizer that asks model to revise prompts for
// Analyze candidates. The model is injected so tests and callers can use mocks.
func LLMOptimizer(model ai.Model) *PromptOptimizer { return &PromptOptimizer{model: model} }
// OptimizePrompt asks the model for a revised prompt for candidate using the
// current prompt and trace feedback. It returns only the proposal; it never
// modifies a Flow, Step, or Checkpoint.
func (o *PromptOptimizer) OptimizePrompt(ctx context.Context, candidate Candidate, currentPrompt string) (string, error) {
if o == nil || o.model == nil {
return "", fmt.Errorf("flow: LLMOptimizer requires a model")
}
prompt := fmt.Sprintf("Revise this workflow step prompt to improve the failing step.\nStep: %s\nMetric: %s\nScore: %.2f\nFeedback:\n- %s\n\nCurrent prompt:\n%s\n\nReturn only the revised prompt.", candidate.Step, candidate.Metric, candidate.Score, strings.Join(candidate.SampleFeedback, "\n- "), currentPrompt)
resp, err := o.model.Generate(ctx, &ai.Request{Prompt: prompt})
if err != nil {
return "", err
}
proposal := strings.TrimSpace(resp.Answer)
if proposal == "" {
proposal = strings.TrimSpace(resp.Reply)
}
if proposal == "" {
return "", fmt.Errorf("flow: LLMOptimizer returned an empty prompt")
}
return proposal, nil
}
func verificationFields(result string) (bool, string, bool) {
if result == "" {View on GitHub (pinned to 24529f1404)
Solutions
- Create the optimizer with a valid model: NewLLMOptimizer(ai.New("openai", ai.WithAPIKey(key))).
- Set Provider and APIKey (and optionally BaseURL) in flow options so the model is initialized.
- Check the ai.New return value for nil before wiring it into the optimizer.
- Skip optimization paths when no model is configured instead of calling OptimizePrompt.
Example fix
// before
opt := &flow.PromptOptimizer{}
newPrompt, err := opt.OptimizePrompt(ctx, cand, prompt)
// after
opt := flow.NewLLMOptimizer(ai.New("openai", ai.WithAPIKey(os.Getenv("OPENAI_API_KEY"))))
newPrompt, err := opt.OptimizePrompt(ctx, cand, prompt) Defensive patterns
Strategy: validation
Validate before calling
if optimizer == nil || reflect.ValueOf(optimizer).IsZero() {
return errors.New("prompt optimizer not configured with a model")
} Type guard
func (o *PromptOptimizer) Ready() bool { return o != nil && o.model != nil } Try / catch
prompt, err := opt.OptimizePrompt(ctx, cand, current)
if err != nil && strings.Contains(err.Error(), "requires a model") {
return current, nil // fall back to the unchanged prompt
} Prevention
- Always construct the optimizer via NewLLMOptimizer with a non-nil model.
- Validate Provider/APIKey config at service startup, before any optimization runs.
- Gate optimization behind a config flag so it's skipped when no model is configured.
When it happens
Trigger: Calling OptimizePrompt on a PromptOptimizer built without NewLLMOptimizer(model) — e.g. constructed with a nil model, or when model initialization was skipped because ai.New returned nil for an unknown provider.
Common situations: Configuring a flow without Provider/APIKey so no model is created; passing a nil model deliberately for testing; using a pointer to PromptOptimizer that was never initialized.
Related errors
- unknown provider: %s
- ai model is nil
- flow: LLMOptimizer returned an empty prompt
- discover tools: %w
- flow: UntilLLM requires a flow model (set Provider/APIKey)
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/2d5edf7a6f2e2def.
Report an issue: GitHub.