""" Ollama Embedding客户端 调用Ollama的OpenAI兼容API获取文本向量表示 """ import time from typing import List import numpy as np import requests class OllamaEmbedder: """ 基于Ollama部署的Embedding模型客户端 默认使用 quentinz/bge-large-zh-v1.5 (中文向量模型) """ def __init__( self, base_url: str = "http://192.168.1.250:11434", model: str = "quentinz/bge-large-zh-v1.5", timeout: int = 180, ): """ 参数: base_url: Ollama服务地址 model: Embedding模型名称 timeout: 请求超时时间(秒) """ self.base_url = base_url.rstrip("/") self.model = model self.timeout = timeout self.endpoint = f"{self.base_url}/v1/embeddings" print(f"[OllamaEmbedder] Initialized url={self.endpoint} model={model}") def encode(self, texts: List[str]) -> np.ndarray: """ 将文本列表编码为向量 参数: texts: 待编码的文本列表 返回: shape为(len(texts), embedding_dim)的numpy数组 """ if not texts: return np.array([]) t0 = time.time() print(f"[OllamaEmbedder] Encoding {len(texts)} texts...") payload = { "model": self.model, "input": texts, } try: resp = requests.post( self.endpoint, json=payload, timeout=self.timeout ) dt = time.time() - t0 if resp.status_code != 200: print(f"[OllamaEmbedder] Error status={resp.status_code} body={resp.text[:200]}") resp.raise_for_status() data = resp.json() # 解析OpenAI格式的响应: {"data": [{"embedding": [...]}, ...]} if "data" not in data: raise RuntimeError(f"Unexpected response format: {data}") embeddings = [] for item in data["data"]: if "embedding" not in item: raise RuntimeError(f"Missing 'embedding' in response item: {item}") embeddings.append(item["embedding"]) result = np.array(embeddings, dtype=np.float32) print(f"[OllamaEmbedder] Success shape={result.shape} elapsed={dt:.2f}s") return result except Exception as e: dt = time.time() - t0 print(f"[OllamaEmbedder] Failed after {dt:.2f}s: {e}") raise def encode_single(self, text: str) -> np.ndarray: """ 编码单个文本(便捷方法) 返回: shape为(embedding_dim,)的1D数组 """ result = self.encode([text]) return result[0] if len(result) > 0 else np.array([])