Files
Agent-System-Backend/internal/rag/hash_embed.go
T
weichenandCursor cd5b82186d Add the public extension surface and platform services
Why: Downstream products must extend the base through a public package and host API instead of editing internal code.
Evidence: go test ./... passed, including plugin v2 assets, sidecar startup, migration v13, pending confirms, HITL timeout, hash embedder, command pairs, and the extension surface snapshot.
Impact: apiVersion 2.0-experimental rejects empty network allowlists for declarative HTTP. Hash embeddings stay opt-in via models.embedding.provider=hash. Plugin secrets resolve per owner at execution time.
Refs: docs/proposals/2026-10-01-plugin-contract-v2.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-01 10:35:02 +00:00

72 lines
1.6 KiB
Go
Raw 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.
package rag
import (
"context"
"fmt"
"hash/fnv"
"unicode/utf8"
)
const hashDim = 32
// HashEmbedder 是零依赖的本地嵌入档。语义弱于真实模型,只保证同文本稳定、近文本可比较。
// 由 settings models.embedding.provider=hash 显式打开;未设置时仍按 D23 退化为全文。
type HashEmbedder struct{}
func (HashEmbedder) Embed(_ context.Context, texts []string) ([][]float32, error) {
out := make([][]float32, len(texts))
for i, text := range texts {
out[i] = hashVec(text)
}
return out, nil
}
func hashVec(text string) []float32 {
v := make([]float32, hashDim)
for _, r := range text {
h := fnv.New32a()
var buf [4]byte
n := utf8.EncodeRune(buf[:], r)
_, _ = h.Write(buf[:n])
idx := int(h.Sum32() % hashDim)
v[idx] += 1
}
var norm float32
for _, x := range v {
norm += x * x
}
if norm == 0 {
return v
}
inv := float32(1)
// 粗略归一,避免余弦被长度主导。
for norm > 1 {
norm = norm / 4
inv = inv / 2
}
for i := range v {
v[i] *= inv
}
return v
}
// SwitchingEmbedder 在 provider=hash 时走本地档,否则走 HTTP。
type SwitchingEmbedder struct {
HTTP *HTTPEmbedder
Provider func() string
}
func (e SwitchingEmbedder) Embed(ctx context.Context, texts []string) ([][]float32, error) {
if e.Provider != nil && e.Provider() == "hash" {
return HashEmbedder{}.Embed(ctx, texts)
}
if e.HTTP == nil {
return nil, fmt.Errorf("rag: embedding 模型未配置(settings.models.embedding)")
}
return e.HTTP.Embed(ctx, texts)
}
func (e SwitchingEmbedder) Offline() bool {
return e.Provider != nil && e.Provider() == "hash"
}