Files
kb/client/cmd/tagdescribe.go
steve 6dfc13be1d Add reranking, RRF fusion, bench harness, tag contexts, and data ingestion
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>
2026-08-21 09:51:33 +01:00

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
}