6dfc13be1d
Implements five of the six enhancements from docs/kb-enhancements-proposal.htm, closing the retrieval-quality gap identified in the qmd review. - Cross-encoder reranking: new kb/reranker.py loads an optional reranking model at startup (KB_RERANK_ENABLED, KB_RERANKER_MODEL, KB_RERANK_CANDIDATES). Search degrades gracefully to plain hybrid retrieval when the model is absent. Exposed via a "rerank" block in /status, a rerank flag on search, and --no-rerank in the CLI. - RRF rank fusion: FTS and vector lists now merge by reciprocal rank fusion with a top-rank bonus, replacing the old score blend. Scores are comparable across queries. - Bench harness and explain traces: kb bench runs a query fixture against each backend and reports precision@k, recall and MRR. --explain returns a per-result score breakdown. - Tag context descriptions: tags carry an optional one-line description (kb tag-describe), returned as tag_contexts with search results. Adds a tags.description column migration. - Structured data ingestion: .json/.yaml/.toml files ingest as text via the new "data" doc type, pretty-printing minified JSON before chunking. Query expansion (proposal item 5) is deliberately left out pending bench results. Requires engine v3.3.0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
63 lines
1.4 KiB
Go
63 lines
1.4 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/kb-search/kb/internal/api"
|
|
"github.com/kb-search/kb/internal/output"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var tagDescribeCmd = &cobra.Command{
|
|
Use: "tag-describe <tag> [description]",
|
|
Short: "Set a one-line context description on a tag",
|
|
Long: `Attach a short description to a tag (e.g. "Lab operations runbooks").
|
|
Descriptions are returned as tag_contexts with every search result on a
|
|
document carrying the tag, helping consumers judge relevance.
|
|
|
|
Omit the description (or pass "") to clear it.`,
|
|
Args: cobra.RangeArgs(1, 2),
|
|
RunE: runTagDescribe,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(tagDescribeCmd)
|
|
}
|
|
|
|
func runTagDescribe(cmd *cobra.Command, args []string) error {
|
|
description := ""
|
|
if len(args) == 2 {
|
|
description = args[1]
|
|
}
|
|
|
|
body := map[string]interface{}{"description": description}
|
|
|
|
client := api.NewClient()
|
|
resp, err := client.Put("/api/v1/tags/"+args[0]+"/description", body)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
if err := api.CheckError(resp); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if output.IsJSON() {
|
|
var raw interface{}
|
|
if err := api.DecodeJSON(resp, &raw); err != nil {
|
|
return fmt.Errorf("failed to decode response: %w", err)
|
|
}
|
|
output.PrintJSON(raw)
|
|
return nil
|
|
}
|
|
|
|
if description == "" {
|
|
fmt.Printf("Description cleared for tag %q\n", args[0])
|
|
} else {
|
|
fmt.Printf("Tag %q: %s\n", args[0], description)
|
|
}
|
|
return nil
|
|
}
|