Help us shape the future of Go! Take the 2026 Go Developer Survey

rag

package module
v0.8.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 23 Imported by: 0

README

rag

知识检索——向量化/混合召回/重排,向量后端可插拔 —— oagentkit 模块矩阵 tier 1(能力层,依赖 tier0)。

go get github.com/oagentkit/rag
包 职责
rag 知识检索:向量化接口(Embedder)、向量后端可插拔、混合召回与重排

定位

tier 1 — 能力层,依赖 tier0。

  • 本仓依赖的矩阵内仓:textx。

外部依赖地板

  • github.com/cloudwego/eino
  • github.com/milvus-io/milvus-sdk-go/v2

与 oekit 的关系

本矩阵(oagentkit,Agent/LLM 编排工具链)依赖 oekit(Open Easy Kit,Go 微服务工具链): oekit/pkg / oekit/concurrency / oekit/logx 等。oekit 是另一套独立矩阵,不是子品牌。

开发

go test ./... -race
go vet ./...
gofmt -l .

规范见 AGENTS.md。

License

MIT

  • 单路召回失败不得降级为 (nil, nil)。 混合召回中任一路 panic 或失败 要作为该路失败参与裁决;全部路失败时返回 panic 错误而非静默空结果。
  • 向量后端可插拔,新增后端不得改 Embedder/KnowledgeService 接口形状 —— 那会让所有后端同时 breaking。

Documentation

Overview

Package rag Embedding 接口定义与 OpenAI 兼容实现。

Hybrid 向量+关键词双路混合检索(R10,RRF 融合):语义路(MilvusStore,embedding 近邻)与词料路(Local,TF-IDF)各取候选,倒数排名融合(Reciprocal Rank Fusion)—— 跨路命中的文档得分累加(双路都认为相关=真相关的最强信号),单路独有的按名次计分。 降级哲学与装配侧一致:任一路失败降级为另一路纯检索(检索面永不因一路缺失禁用), 双路全败才回错。

Package rag Milvus 向量检索后端。 使用 Milvus Go SDK v2 实现 KnowledgeService 接口, 支持向量相似度检索(余弦相似度 / L2 距离)。

Package rag 知识检索服务。 提供两种后端:Local(本地 TF-IDF)和 MilvusStore(向量数据库)。 检索算法 = 词元重叠打分(ASCII 词 + CJK 二元组)或向量相似度, 零外部向量库依赖(Local)或 Milvus 向量数据库(MilvusStore)。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewSearchTool

func NewSearchTool(svc KnowledgeService) tool.BaseTool

NewSearchTool 构建 search_knowledge eino 工具(v0.14.1 导出缝):消费方包装 KnowledgeService 后须重建工具面——包装层 AsTool 直透内层会把工具调用绕过包装 检索语义(bianque 知识组去重包装实需)。schema/文案与 buildAsTool 单源。

Types

type Chunk

type Chunk struct {
	ID       string
	Content  string
	Score    float64
	Metadata map[string]string
}

Chunk 检索片段。

func ChunkPreview

func ChunkPreview(content string) []Chunk

ChunkPreview 切块只读预览(v0.14.2):与索引侧 chunkMarkdown 同一状态机——消费方 (bianque 知识文档管理面,对标 Dify/RAGFlow 分段预览)展示「这篇会切成几块、每块什么 内容」,预览与实际索引不分叉。返回块内容与所属标题(Metadata["heading"],无标题块为空)。

func FuseRRF

func FuseRRF(topK int, lists ...[]Chunk) []Chunk

FuseRRF 倒数排名融合:score=Σ 1/(k+rank_i)(rank 从 1 起),同 ID 跨路累加 (双路共识加权=混合检索的本意);输出按得分降序、同分按 ID 字典序(确定性可重放), 截 topK。lists 为空返回空。

type Embedder

type Embedder interface {
	// Embed 将文本切片转为向量切片,返回的向量维度应一致。
	Embed(ctx context.Context, texts []string) ([][]float32, error)
	// Dim 返回向量维度。
	Dim() int
}

Embedder 文本向量化接口。

type EmbedderOption added in v0.8.3

type EmbedderOption func(*embedderConfig)

EmbedderOption OpenAIEmbedder 构造选项。

命名遵循矩阵纪律:不使用裸 Option(多包 co-import 会冲突),统一 XxxOption。

func WithHTTPClient added in v0.8.3

func WithHTTPClient(c *http.Client) EmbedderOption

WithHTTPClient 注入自定义 HTTP client:出站守卫 / mTLS / 代理 / 连接池调参的入口。 传 nil 视为未设置(忽略)。

交互规则:

  • 注入的 client 会被复制一份后使用,调用方持有的对象不被修改——共享 client 被就地改 Timeout 会影响其它使用者;Transport / Jar / CheckRedirect 原样保留, 连接池与调用方共用。
  • 只给本选项、不给 WithTimeout 时,完全沿用注入 client 自身的 Timeout (0 表示无超时)。
  • 与 WithTimeout 同时给出时,timeout 覆盖注入 client 的 Timeout(见 NewOpenAIEmbedder 的交互规则)。

func WithRetry added in v0.8.3

func WithRetry(cfg httpjson.RetryConfig) EmbedderOption

WithRetry 开启重试路径(改走 httpjson.DoJSONWithRetry)。

默认不重试:单次尝试,行为与引入本选项前完全一致。理由:embedding 调用 默认单次,重试策略属于调用方的成本/时延决策——重试会放大上游配额消耗与 计费,且对不可重试错误(4xx 参数错)空转。

cfg.MaxAttempts < 1 由 httpjson 视为 1(等于不重试);cfg.Retryable 为 nil 时 用 httpjson 默认判定:网络超时或 HTTP 5xx/429 可重试,4xx 与响应解析失败不重试。 因此零值 RetryConfig{} 等价于单次尝试。

func WithTimeout added in v0.8.3

func WithTimeout(d time.Duration) EmbedderOption

WithTimeout 覆盖请求超时(默认 30s)。

d <= 0 视为未设置(忽略)——要取消超时,请注入自带 Timeout: 0 的 client 且不调用本选项。

交互规则:timeout 一律作用于生效后的 client(注入优先、timeout 覆盖其 Timeout),与 WithHTTPClient 的传入先后顺序无关。

type Filter

type Filter map[string]string

Filter 检索过滤条件(如 repo、规范文档名)。

type Hybrid

type Hybrid struct {
	// contains filtered or unexported fields
}

Hybrid 组合检索器:vector=语义路(必选),keyword=词料路(Local 的 TF-IDF 索引, 纯内存随目录重建)。

func NewHybrid

func NewHybrid(vector KnowledgeService, keyword *Local) *Hybrid

NewHybrid 构造混合检索器。

func (*Hybrid) AsTool

func (h *Hybrid) AsTool() tool.BaseTool

AsTool 工具化透传语义路(检索语义对 LLM 不可见——混合是检索器内部实现细节)。

func (*Hybrid) Retrieve

func (h *Hybrid) Retrieve(ctx context.Context, query string, topK int, filter Filter) ([]Chunk, error)

Retrieve 双路并行检索 → RRF 融合 → topK。两路各取 topK*2 候选(融合后截断, 候选池放大让跨路重叠有归并空间);单路失败降级单路,双路全败回 first error。 双路经 syncx.FanInErr 收口(concurrency v0.5.0 起 Slot 三态):路内 panic 不再 伪装成空路,而是作为该路失败参与降级裁决——单路 panic 降级另一路,双路全败 (含 panic)回错不再静默返回空结果;恐慌经全局 handler 上报,不出宿主进程。

type KnowledgeService

type KnowledgeService interface {
	Retrieve(ctx context.Context, query string, topK int, filter Filter) ([]Chunk, error)
	AsTool() tool.BaseTool
}

KnowledgeService 知识检索服务接口。 模式一:预检索(确定性)—— workflow 阶段在拼 prompt 前取 topK 片段。 模式二:工具化(自主)—— 包成 search_knowledge(query) 挂进 ReAct agent。

type Local

type Local struct {
	// contains filtered or unexported fields
}

Local 本地文件知识库(启动扫描 + 过期重扫)。

func NewLocal

func NewLocal(dir string) (*Local, error)

NewLocal 构造并立即扫描。dir 不存在时返回错误。

func (*Local) AsTool

func (l *Local) AsTool() tool.BaseTool

AsTool 把检索包成 search_knowledge 工具。

func (*Local) Rescan

func (l *Local) Rescan()

Rescan 强制重新扫描知识库目录(不等待自动过期)。 根目录不可达(卷卸载/被删)时保留旧索引并告警——静默换入空索引会让 知识库"消失"且无任何信号。

func (*Local) Retrieve

func (l *Local) Retrieve(ctx context.Context, query string, topK int, filter Filter) ([]Chunk, error)

Retrieve 检索 topK 片段。 重扫在锁外进行(构建新索引后原子换入)——并发检索不被文件 I/O 阻塞; 多 goroutine 同时判过期时重扫收敛为单份(scanning 标志让位,换入后对 所有人可见;此前并发各扫一遍,大目录下内存峰值按并发数放大)。

type MilvusConfig

type MilvusConfig struct {
	Address    string            // Milvus 地址,如 "localhost:19530"
	Collection string            // 集合名,默认 "agentkit_knowledge"
	Dimension  int               // 向量维度(需与 Embedder.Dim() 一致)
	MetricType entity.MetricType // 距离度量,默认 COSINE
	NProbe     int               // 搜索时的 nprobe,默认 16
}

MilvusConfig Milvus 连接配置。

type MilvusStore

type MilvusStore struct {
	// contains filtered or unexported fields
}

MilvusStore Milvus 向量检索后端。

func NewMilvusStore

func NewMilvusStore(ctx context.Context, cfg MilvusConfig, embedder Embedder) (*MilvusStore, error)

NewMilvusStore 创建 Milvus 向量检索后端。

func (*MilvusStore) AsTool

func (s *MilvusStore) AsTool() tool.BaseTool

AsTool 实现 KnowledgeService 接口。

func (*MilvusStore) Close

func (s *MilvusStore) Close() error

Close 关闭 Milvus 连接。

func (*MilvusStore) DeleteFile

func (s *MilvusStore) DeleteFile(ctx context.Context, file string) error

DeleteFile 删除指定文件的所有索引数据。

func (*MilvusStore) Flush

func (s *MilvusStore) Flush(ctx context.Context) error

Flush 持久化本集合全部未落盘写入(批量写入收尾点)。

func (*MilvusStore) Index

func (s *MilvusStore) Index(ctx context.Context, file string, content string) error

Index 将文档分块并索引到 Milvus(单文件写=embed→delete→upsert→flush)。 批量写入请用 IndexQuiet+收尾 Flush——per-file Flush 实测 ~20s/文件(对象存储 落盘 RPC 主导,向量计算亚秒),千级文件会把全量重索引拖成小时级(2026-10-08 bianque 对拍实弹)。 幂等:成功路径上先清该文件旧数据再写入——文件变短(删章节/内容精简)时 chunk 数变少,只 Upsert 新块会残留 chunk_M..N-1 旧行携带过期内容参与检索 挤占 topK(与 Local.Rescan 的全量重建同语义)。 顺序:chunk → Embed 成功 → Delete → Upsert。Embed 是外部网络调用(抖动/ 限流/超时是常规事件),先删后嵌会把旧索引一并清掉;倒序后最常见的失败 (embedding)不再动旧数据。残余窗口:Delete 成功而 Upsert/Flush 失败时旧 数据已删新数据未写(该文件暂时从检索面消失,直到下次 Index 重建)—— 该窗口远小于原形态且失败以错误上抛,调用方可重试。

func (*MilvusStore) IndexQuiet

func (s *MilvusStore) IndexQuiet(ctx context.Context, file string, content string) error

IndexQuiet 单文件写入但不 Flush(批量收尾点由调用方 Flush 一次)。数据在 flush 前已可检索(growing segments),Flush 语义=持久化到 sealed segments—— 调用方须保证批次终态调 Flush,否则进程崩溃窗内未 flush 写入丢失(重跑幂等)。

func (*MilvusStore) Retrieve

func (s *MilvusStore) Retrieve(ctx context.Context, query string, topK int, filter Filter) ([]Chunk, error)

Retrieve 实现 KnowledgeService 接口:向量相似度检索。

type Noop

type Noop struct{}

Noop 空实现:Retrieve 返回空、AsTool 返回 nil。

func NewNoop

func NewNoop() *Noop

NewNoop 创建空实现。

func (*Noop) AsTool

func (n *Noop) AsTool() tool.BaseTool

func (*Noop) Retrieve

func (n *Noop) Retrieve(_ context.Context, _ string, _ int, _ Filter) ([]Chunk, error)

type OpenAIEmbedder

type OpenAIEmbedder struct {
	BaseURL string // 如 https://api.openai.com/v1 或 https://dashscope.aliyuncs.com/compatible-mode/v1
	APIKey  string
	Model   string // 如 text-embedding-3-small / text-embedding-v3
	// contains filtered or unexported fields
}

OpenAIEmbedder OpenAI 兼容 Embedding API 适配器。 支持 OpenAI / 百炼 / 任何兼容 /v1/embeddings 端点。

func NewOpenAIEmbedder

func NewOpenAIEmbedder(baseURL, apiKey, model string, dim int, opts ...EmbedderOption) *OpenAIEmbedder

NewOpenAIEmbedder 创建 OpenAI 兼容 Embedding 客户端。

opts 为可选行为(见 EmbedderOption):WithHTTPClient 注入自定义 client、 WithTimeout 覆盖超时、WithRetry 开启重试。不传任何 option 时行为与引入 本选项前完全一致:单次尝试、30s 超时。

交互规则(client 与 timeout 谁优先):

  1. 生效 client:给了 WithHTTPClient 就用它(取副本),否则用默认的 &http.Client{Timeout: 30s};
  2. 给了 WithTimeout,该 timeout 覆盖生效 client 自身的 Timeout——即 **timeout 优先于注入 client 的 Timeout**,且与两个选项的传入顺序无关;
  3. 只给 WithHTTPClient 时,完全沿用注入 client 的 Timeout(0 = 无超时)。

func (*OpenAIEmbedder) Dim

func (e *OpenAIEmbedder) Dim() int

Dim 返回向量维度。

func (*OpenAIEmbedder) Embed

func (e *OpenAIEmbedder) Embed(ctx context.Context, texts []string) ([][]float32, error)

Embed 将文本切片转为向量切片。

func (*OpenAIEmbedder) String

func (e *OpenAIEmbedder) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL