Classifies text into zero or more categories from a fixed set — returns a subset of the configured labels.
| Field | Type | Description |
|---|---|---|
Input |
*string |
Text to classify |
| Field | Type | Description |
|---|---|---|
Result |
[]string |
Matched labels (CSV-encoded slice) |
Reasoning is captured by WithReasoningLog — no graph output needed.
| Key | Type | Default | Description |
|---|---|---|---|
categories |
string |
required | Comma-separated label set (minimum 2 labels) |
max_retries |
string |
"3" | Number of retries on parse error |
Zero matches are valid. When no category applies, the op returns an empty slice rather than an error. Use IfEmptySliceStringOp downstream to detect and handle this case.
Retry on parse error. If the model response cannot be parsed as a valid subset of the configured categories, the op retries up to max_retries times before returning an error. This makes it resilient to occasional malformed model output.
Classifies a support ticket into multiple categories simultaneously, returning all matching labels.
package main
import (
"context"
"encoding/json"
"log"
"os"
"time"
"github.com/akennis/sparsi-go/library"
_ "github.com/akennis/dagor/operator/builtin"
"github.com/panjf2000/ants/v2"
"github.com/akennis/dagor"
"github.com/akennis/dagor/graph"
)
func main() {
ticket := "My payment failed and now I can't access my account. The export feature is also broken."
library.RegisterConst("ticket_val", ticket)
g, err := graph.NewBuilder("ticket_classifier").
Vertex("ticket_src").Op("ticket_val").
Output("Result", "ticket_wire").
Vertex("classify").Op("AIClassifyMultiLabelOp").
Params(map[string]string{
"categories": "billing,technical,account,feature-request,abuse",
"max_retries": "3",
}).
Input("Input", "ticket_wire").
Output("Result", "matched_labels").
Build()
if err != nil {
log.Fatalf("build: %v", err)
}
pool, err := ants.NewPool(4)
if err != nil {
log.Fatalf("pool: %v", err)
}
defer pool.Release()
eng, err := dagor.NewEngine(g, pool)
if err != nil {
log.Fatalf("engine: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
if err := eng.Run(ctx); err != nil {
log.Fatalf("run: %v", err)
}
out := map[string]any{}
if raw, ok := eng.GetOutput("matched_labels"); ok {
out["labels"] = *raw.(*[]string)
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
enc.Encode(out)
}