Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

311 lines
10 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Command token-efficiency runs the 3-pipeline token-economy
// benchmark: ripgrep+full-read vs ripgrep+context vs gortex
// (search_symbols + get_symbol_source). See bench/token-efficiency/
// README.md for the contract and the methodology footnote it places
// in BENCHMARK.md.
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
)
// benchRow captures one query's outcome across all three pipelines.
type benchRow struct {
Query string `json:"query"`
Expected []string `json:"expected"`
RipgrepFull pipelineResult `json:"ripgrep_full"`
RipgrepCtx pipelineResult `json:"ripgrep_context"`
Gortex pipelineResult `json:"gortex"`
// Recall@k by token budget. 2k is the "agent reads two pages of
// context" frame; 10k is "agent reads a quarter of a window".
RecallAt2kFull float64 `json:"recall_at_2k_full"`
RecallAt2kCtx float64 `json:"recall_at_2k_context"`
RecallAt2kGortex float64 `json:"recall_at_2k_gortex"`
RecallAt10kFull float64 `json:"recall_at_10k_full"`
RecallAt10kCtx float64 `json:"recall_at_10k_context"`
RecallAt10kGortex float64 `json:"recall_at_10k_gortex"`
}
func main() {
repo := flag.String("repo", ".", "indexed repository path (queries run against this corpus)")
queriesPath := flag.String("queries", "bench/token-efficiency/queries.json", "JSON query set")
truthPath := flag.String("groundtruth", "bench/token-efficiency/groundtruth.json", "JSON per-query expected file paths")
out := flag.String("out", "", "markdown output path (default stdout)")
jsonOut := flag.String("json", "", "optional JSON metrics output")
format := flag.String("format", "markdown", "markdown | json")
topK := flag.Int("top-k", 5, "candidates per query for the gortex pipeline")
budgetRatio := flag.Float64("budget-ratio", 0.5, "fail when gortex median tokens > budget-ratio × ripgrep+full-read median (0 disables)")
strict := flag.Bool("strict", false, "exit 1 when the budget gate trips")
skipRipgrep := flag.Bool("skip-ripgrep", false, "skip ripgrep pipelines (e.g. when rg isn't installed)")
flag.Parse()
absRepo, err := filepath.Abs(*repo)
if err != nil {
die("repo path: %v", err)
}
if _, err := os.Stat(absRepo); err != nil {
die("repo path: %v", err)
}
queries, err := loadQueries(*queriesPath)
if err != nil {
die("queries: %v", err)
}
truth, err := loadGroundTruth(*truthPath)
if err != nil {
die("groundtruth: %v", err)
}
// Detect ripgrep up front so we can short-circuit cleanly.
rgAvailable := !*skipRipgrep
if rgAvailable {
if _, err := exec.LookPath("rg"); err != nil {
fmt.Fprintf(os.Stderr, "[token-eff] ripgrep not on PATH; --skip-ripgrep implied\n")
rgAvailable = false
}
}
// Index the repo once for the gortex pipeline.
fmt.Fprintf(os.Stderr, "[token-eff] indexing %s...\n", absRepo)
indexed, err := indexRepoForBench(absRepo)
if err != nil {
die("index: %v", err)
}
fmt.Fprintf(os.Stderr, "[token-eff] indexed %d nodes\n", len(indexed.graph.AllNodes()))
// Run each query across the available pipelines.
rows := make([]benchRow, 0, len(queries))
for _, q := range queries {
row := benchRow{Query: q, Expected: truth[q]}
if rgAvailable {
row.RipgrepFull = runRipgrepFullRead(absRepo, q)
row.RipgrepCtx = runRipgrepContext(absRepo, q)
}
row.Gortex = runGortex(absRepo, q, indexed, *topK)
row.RecallAt2kFull = recallAtBudget(row.RipgrepFull, row.Expected, 2_000)
row.RecallAt2kCtx = recallAtBudget(row.RipgrepCtx, row.Expected, 2_000)
row.RecallAt2kGortex = recallAtBudget(row.Gortex, row.Expected, 2_000)
row.RecallAt10kFull = recallAtBudget(row.RipgrepFull, row.Expected, 10_000)
row.RecallAt10kCtx = recallAtBudget(row.RipgrepCtx, row.Expected, 10_000)
row.RecallAt10kGortex = recallAtBudget(row.Gortex, row.Expected, 10_000)
rows = append(rows, row)
fmt.Fprintf(os.Stderr, "[token-eff] %-45s full=%-7d ctx=%-7d gortex=%d\n",
q, row.RipgrepFull.Tokens, row.RipgrepCtx.Tokens, row.Gortex.Tokens)
}
// Render primary output.
var primary []byte
switch strings.ToLower(*format) {
case "markdown", "md":
primary = []byte(renderMarkdown(rows, rgAvailable))
case "json":
primary = mustMarshalJSON(rows)
default:
die("unknown --format %q", *format)
}
if err := writeOutput(*out, primary); err != nil {
die("write primary: %v", err)
}
// Optional companion JSON.
if *jsonOut != "" {
if err := writeOutput(*jsonOut, mustMarshalJSON(rows)); err != nil {
die("write json: %v", err)
}
}
// Budget gate.
if *strict && *budgetRatio > 0 && rgAvailable {
medianFull := medianTokensFn(rows, func(r benchRow) int { return r.RipgrepFull.Tokens })
medianGortex := medianTokensFn(rows, func(r benchRow) int { return r.Gortex.Tokens })
if medianFull > 0 {
ratio := float64(medianGortex) / float64(medianFull)
if ratio > *budgetRatio {
die("budget gate: gortex median tokens (%d) / ripgrep+full-read median (%d) = %.2f > limit %.2f",
medianGortex, medianFull, ratio, *budgetRatio)
}
}
}
}
// --- rendering ------------------------------------------------------
// renderMarkdown produces the per-query table plus a summary line.
// When ripgrep is unavailable the ripgrep columns render as "—" so a
// CI without rg still gets a meaningful gortex-only table.
func renderMarkdown(rows []benchRow, rgAvailable bool) string {
var b strings.Builder
fmt.Fprintln(&b, "# Token-efficiency benchmark")
fmt.Fprintln(&b)
fmt.Fprintln(&b, "_Tokens per response (lower is better) and recall@k-by-token-budget for three retrieval pipelines: ripgrep+full-read (naive agent baseline), ripgrep+context (±50 lines around hit), and gortex (search_symbols + get_symbol_source)._")
fmt.Fprintln(&b)
fmt.Fprintln(&b, "| query | tokens (rg+full) | tokens (rg+ctx) | tokens (gortex) | recall@2k rg+full / rg+ctx / gortex | recall@10k rg+full / rg+ctx / gortex |")
fmt.Fprintln(&b, "|-------|----------------:|----------------:|---------------:|------------------------------------|--------------------------------------|")
for _, r := range rows {
fmt.Fprintf(&b, "| %s | %s | %s | %d | %s / %s / %.2f | %s / %s / %.2f |\n",
truncate(r.Query, 38),
tokensCell(r.RipgrepFull, rgAvailable),
tokensCell(r.RipgrepCtx, rgAvailable),
r.Gortex.Tokens,
recallCell(r.RecallAt2kFull, rgAvailable),
recallCell(r.RecallAt2kCtx, rgAvailable),
r.RecallAt2kGortex,
recallCell(r.RecallAt10kFull, rgAvailable),
recallCell(r.RecallAt10kCtx, rgAvailable),
r.RecallAt10kGortex,
)
}
fmt.Fprintln(&b)
fmt.Fprintln(&b, summaryLine(rows, rgAvailable))
return b.String()
}
func tokensCell(p pipelineResult, available bool) string {
if !available {
return "—"
}
if p.Error != "" {
return "ERR"
}
return fmt.Sprintf("%d", p.Tokens)
}
func recallCell(v float64, available bool) string {
if !available {
return "—"
}
return fmt.Sprintf("%.2f", v)
}
func truncate(s string, max int) string {
if len(s) <= max {
return s
}
return s[:max-1] + "…"
}
// summaryLine emits the headline median-tokens + recall figure that
// real readers care about. Format:
//
// "Median tokens: rg+full=X / rg+ctx=Y / gortex=Z (gortex P%).
// Median recall@2k: rg+full=A / rg+ctx=B / gortex=C."
func summaryLine(rows []benchRow, rgAvailable bool) string {
if len(rows) == 0 {
return "_no rows_"
}
mt := func(f func(benchRow) int) int { return medianTokensFn(rows, f) }
mr := func(f func(benchRow) float64) float64 { return medianFloatFn(rows, f) }
mFull := mt(func(r benchRow) int { return r.RipgrepFull.Tokens })
mCtx := mt(func(r benchRow) int { return r.RipgrepCtx.Tokens })
mGortex := mt(func(r benchRow) int { return r.Gortex.Tokens })
rec2Full := mr(func(r benchRow) float64 { return r.RecallAt2kFull })
rec2Ctx := mr(func(r benchRow) float64 { return r.RecallAt2kCtx })
rec2Gortex := mr(func(r benchRow) float64 { return r.RecallAt2kGortex })
if !rgAvailable {
return fmt.Sprintf("**Summary (gortex only — rg not installed):** Median tokens %d. Median recall@2k %.2f.",
mGortex, rec2Gortex)
}
ratio := ""
if mFull > 0 {
delta := (1.0 - float64(mGortex)/float64(mFull)) * 100
ratio = fmt.Sprintf(" gortex saves %.1f%% vs rg+full.", delta)
}
return fmt.Sprintf("**Summary:** Median tokens — rg+full=%d / rg+ctx=%d / gortex=%d.%s Median recall@2k — rg+full=%.2f / rg+ctx=%.2f / gortex=%.2f.",
mFull, mCtx, mGortex, ratio,
rec2Full, rec2Ctx, rec2Gortex,
)
}
// medianTokensFn / medianFloatFn condense per-pipeline values across
// rows into the median. Used by both the summary line and the budget
// gate so the two stay in lock-step.
func medianTokensFn(rows []benchRow, pick func(benchRow) int) int {
if len(rows) == 0 {
return 0
}
vs := make([]int, 0, len(rows))
for _, r := range rows {
vs = append(vs, pick(r))
}
sort.Ints(vs)
return vs[len(vs)/2]
}
func medianFloatFn(rows []benchRow, pick func(benchRow) float64) float64 {
if len(rows) == 0 {
return 0
}
vs := make([]float64, 0, len(rows))
for _, r := range rows {
vs = append(vs, pick(r))
}
sort.Float64s(vs)
return vs[len(vs)/2]
}
// --- helpers --------------------------------------------------------
func die(format string, args ...any) {
fmt.Fprintf(os.Stderr, "token-eff: "+format+"\n", args...)
os.Exit(1)
}
func writeOutput(path string, body []byte) error {
if path == "" {
_, err := os.Stdout.Write(body)
return err
}
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return err
}
return os.WriteFile(path, body, 0o644)
}
func mustMarshalJSON(rows []benchRow) []byte {
b, err := json.MarshalIndent(rows, "", " ")
if err != nil {
die("marshal json: %v", err)
}
return append(b, '\n')
}
func loadQueries(path string) ([]string, error) {
raw, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var doc struct {
Queries []string `json:"queries"`
}
if err := json.Unmarshal(raw, &doc); err != nil {
return nil, fmt.Errorf("parse %s: %w", path, err)
}
return doc.Queries, nil
}
func loadGroundTruth(path string) (map[string][]string, error) {
raw, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var doc struct {
Queries map[string][]string `json:"queries"`
}
if err := json.Unmarshal(raw, &doc); err != nil {
return nil, fmt.Errorf("parse %s: %w", path, err)
}
if doc.Queries == nil {
doc.Queries = map[string][]string{}
}
return doc.Queries, nil
}