refactor(AI): single source of truth for embedding model name
Lift the hardcoded 'nomic-embed-text:v1.5' string out of both RagService and OllamaService into a shared EMBEDDING_MODEL_NAME constant in constants/ollama.ts. The duplicate in OllamaService existed only to dodge a circular import with RagService; the constants module has no service imports, so a shared constant eliminates both the duplication and the drift risk called out in the inline "keep in sync" comment.
This commit is contained in:
parent
ffa70a54bc
commit
a9c48fc098
|
|
@ -3,7 +3,7 @@ import OpenAI from 'openai'
|
|||
import type { ChatCompletionChunk, ChatCompletionMessageParam } from 'openai/resources/chat/completions.js'
|
||||
import type { Stream } from 'openai/streaming.js'
|
||||
import { NomadOllamaModel } from '../../types/ollama.js'
|
||||
import { FALLBACK_RECOMMENDED_OLLAMA_MODELS } from '../../constants/ollama.js'
|
||||
import { EMBEDDING_MODEL_NAME, FALLBACK_RECOMMENDED_OLLAMA_MODELS } from '../../constants/ollama.js'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import logger from '@adonisjs/core/services/logger'
|
||||
|
|
@ -594,13 +594,6 @@ export class OllamaService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedding model name exempt from the chat-model unload sweep. Hardcoded
|
||||
* to avoid a circular import with `RagService.EMBEDDING_MODEL`; keep in
|
||||
* sync with that constant if it ever changes.
|
||||
*/
|
||||
private static readonly EMBEDDING_MODEL_EXEMPT = 'nomic-embed-text:v1.5'
|
||||
|
||||
/**
|
||||
* Enforces the "at most one chat model resident in VRAM" invariant by firing
|
||||
* `keep_alive: 0` against every currently-loaded model except (a) the
|
||||
|
|
@ -641,7 +634,7 @@ export class OllamaService {
|
|||
}
|
||||
|
||||
const toUnload = loadedModels.filter(
|
||||
(name) => name !== OllamaService.EMBEDDING_MODEL_EXEMPT && name !== targetModel
|
||||
(name) => name !== EMBEDDING_MODEL_NAME && name !== targetModel
|
||||
)
|
||||
|
||||
await Promise.all(
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import type { FileWarning, FileWarningsResult, StoredFileInfo } from '../../type
|
|||
import type { KbIngestStateValue } from '../../types/kb_ingest_state.js'
|
||||
import { ZIMExtractionService } from './zim_extraction_service.js'
|
||||
import { ZIM_BATCH_SIZE } from '../../constants/zim_extraction.js'
|
||||
import { EMBEDDING_MODEL_NAME } from '../../constants/ollama.js'
|
||||
import { ProcessAndEmbedFileResponse, ProcessZIMFileResponse, RAGResult, RerankedRAGResult } from '../../types/rag.js'
|
||||
|
||||
export type EmbedSingleFileFailureCode =
|
||||
|
|
@ -44,7 +45,6 @@ export class RagService {
|
|||
private resolvedEmbeddingModel: string | null = null
|
||||
public static UPLOADS_STORAGE_PATH = 'storage/kb_uploads'
|
||||
public static CONTENT_COLLECTION_NAME = 'nomad_knowledge_base'
|
||||
public static EMBEDDING_MODEL = 'nomic-embed-text:v1.5'
|
||||
public static EMBEDDING_DIMENSION = 768 // Nomic Embed Text v1.5 dimension is 768
|
||||
public static MODEL_CONTEXT_LENGTH = 2048 // nomic-embed-text has 2K token context
|
||||
public static MAX_SAFE_TOKENS = 1600 // Leave buffer for prefix and tokenization variance
|
||||
|
|
@ -286,25 +286,25 @@ export class RagService {
|
|||
if (!this.embeddingModelVerified) {
|
||||
const allModels = await this.ollamaService.getModels(true)
|
||||
const embeddingModel =
|
||||
allModels.find((model) => model.name === RagService.EMBEDDING_MODEL) ??
|
||||
allModels.find((model) => model.name === EMBEDDING_MODEL_NAME) ??
|
||||
allModels.find((model) => model.name.toLowerCase().includes('nomic-embed-text'))
|
||||
|
||||
if (!embeddingModel) {
|
||||
try {
|
||||
const downloadResult = await this.ollamaService.downloadModel(RagService.EMBEDDING_MODEL)
|
||||
const downloadResult = await this.ollamaService.downloadModel(EMBEDDING_MODEL_NAME)
|
||||
if (!downloadResult.success) {
|
||||
throw new Error(downloadResult.message || 'Unknown error during model download')
|
||||
}
|
||||
} catch (modelError) {
|
||||
logger.error(
|
||||
`[RAG] Embedding model ${RagService.EMBEDDING_MODEL} not found locally and failed to download:`,
|
||||
`[RAG] Embedding model ${EMBEDDING_MODEL_NAME} not found locally and failed to download:`,
|
||||
modelError
|
||||
)
|
||||
this.embeddingModelVerified = false
|
||||
return null
|
||||
}
|
||||
}
|
||||
this.resolvedEmbeddingModel = embeddingModel?.name ?? RagService.EMBEDDING_MODEL
|
||||
this.resolvedEmbeddingModel = embeddingModel?.name ?? EMBEDDING_MODEL_NAME
|
||||
this.embeddingModelVerified = true
|
||||
}
|
||||
|
||||
|
|
@ -361,7 +361,7 @@ export class RagService {
|
|||
|
||||
logger.debug(`[RAG] Embedding batch ${batchIdx + 1}/${totalBatches} (${batch.length} chunks)`)
|
||||
|
||||
const response = await this.ollamaService.embed(this.resolvedEmbeddingModel ?? RagService.EMBEDDING_MODEL, batch)
|
||||
const response = await this.ollamaService.embed(this.resolvedEmbeddingModel ?? EMBEDDING_MODEL_NAME, batch)
|
||||
|
||||
embeddings.push(...response.embeddings)
|
||||
|
||||
|
|
@ -818,12 +818,12 @@ export class RagService {
|
|||
if (!this.embeddingModelVerified) {
|
||||
const allModels = await this.ollamaService.getModels(true)
|
||||
const embeddingModel =
|
||||
allModels.find((model) => model.name === RagService.EMBEDDING_MODEL) ??
|
||||
allModels.find((model) => model.name === EMBEDDING_MODEL_NAME) ??
|
||||
allModels.find((model) => model.name.toLowerCase().includes('nomic-embed-text'))
|
||||
|
||||
if (!embeddingModel) {
|
||||
logger.warn(
|
||||
`[RAG] ${RagService.EMBEDDING_MODEL} not found. Cannot perform similarity search.`
|
||||
`[RAG] ${EMBEDDING_MODEL_NAME} not found. Cannot perform similarity search.`
|
||||
)
|
||||
this.embeddingModelVerified = false
|
||||
return []
|
||||
|
|
@ -855,7 +855,7 @@ export class RagService {
|
|||
return []
|
||||
}
|
||||
|
||||
const response = await this.ollamaService.embed(this.resolvedEmbeddingModel ?? RagService.EMBEDDING_MODEL, [prefixedQuery])
|
||||
const response = await this.ollamaService.embed(this.resolvedEmbeddingModel ?? EMBEDDING_MODEL_NAME, [prefixedQuery])
|
||||
|
||||
// Perform semantic search with a higher limit to enable reranking
|
||||
const searchLimit = limit * 3 // Get more results for reranking
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ export const FALLBACK_RECOMMENDED_OLLAMA_MODELS: NomadOllamaModel[] = [
|
|||
|
||||
export const DEFAULT_QUERY_REWRITE_MODEL = 'qwen2.5:3b' // default to qwen2.5 for query rewriting with good balance of text task performance and resource usage
|
||||
|
||||
export const EMBEDDING_MODEL_NAME = 'nomic-embed-text:v1.5'
|
||||
|
||||
/**
|
||||
* Adaptive RAG context limits based on model size.
|
||||
* Smaller models get overwhelmed with too much context, so we cap it.
|
||||
|
|
|
|||
Loading…
Reference in New Issue