This commit is contained in:
2026-06-22 08:55:57 +08:00
parent dbb87823e8
commit 6ade6e8fa9
325 changed files with 41131 additions and 855 deletions
+43 -3
View File
@@ -12,8 +12,11 @@ import (
tiktoken "github.com/pkoukk/tiktoken-go"
)
// Compile-time assertion: OpenAIClient must satisfy LLMClient.
var _ LLMClient = (*OpenAIClient)(nil)
// Compile-time assertion: OpenAIClient must satisfy LLMClient + Embedder.
var (
_ LLMClient = (*OpenAIClient)(nil)
_ Embedder = (*OpenAIClient)(nil)
)
// OpenAIClient 通过官方 SDK 调用 Chat Completions API。
// baseURL 改写后兼容 DeepSeek / Qwen / Ollama / vLLM / Moonshot 等 OpenAI-compatible 端点。
@@ -54,7 +57,7 @@ func toOpenAIMessages(msgs []Message) []openai.ChatCompletionMessageParamUnion {
parts = append(parts, openai.ImageContentPart(openai.ChatCompletionContentPartImageImageURLParam{
URL: dataURI,
}))
// document/PDF 不翻译,由上层能力检查拦截
// document/PDF 不翻译,由上层能力检查拦截
}
}
out = append(out, openai.UserMessage(parts))
@@ -199,3 +202,40 @@ func (c *OpenAIClient) CountTokens(_ context.Context, modelID string, req Reques
}
return total, nil
}
// EmbedDims returns the platform-standard embedding dimension. text-embedding-3-*
// models honor the `dimensions` request param, so Embed always pins the output to
// PlatformEmbeddingDims to match the fixed pgvector column width.
func (c *OpenAIClient) EmbedDims(string) int { return PlatformEmbeddingDims }
// Embed calls POST /embeddings once for the whole batch (input order preserved)
// and converts the returned []float64 vectors to []float32 for pgvector storage.
func (c *OpenAIClient) Embed(ctx context.Context, modelID string, inputs []string) ([][]float32, error) {
if len(inputs) == 0 {
return nil, nil
}
resp, err := c.sdk.Embeddings.New(ctx, openai.EmbeddingNewParams{
Model: openai.EmbeddingModel(modelID),
Input: openai.EmbeddingNewParamsInputUnion{OfArrayOfStrings: inputs},
Dimensions: param.NewOpt(int64(PlatformEmbeddingDims)),
EncodingFormat: openai.EmbeddingNewParamsEncodingFormatFloat,
})
if err != nil {
return nil, fmt.Errorf("openai embeddings: %w", err)
}
if len(resp.Data) != len(inputs) {
return nil, fmt.Errorf("openai embeddings: got %d vectors for %d inputs", len(resp.Data), len(inputs))
}
out := make([][]float32, len(resp.Data))
for _, e := range resp.Data {
if e.Index < 0 || int(e.Index) >= len(out) {
return nil, fmt.Errorf("openai embeddings: out-of-range index %d", e.Index)
}
v := make([]float32, len(e.Embedding))
for i, f := range e.Embedding {
v[i] = float32(f)
}
out[e.Index] = v
}
return out, nil
}