fix: add LLM provider detection and defaults to memory config (#4400)
This commit is contained in:
+33
-1
@@ -66,7 +66,39 @@ You can do this in one of the following ways:
|
||||
|
||||
```env
|
||||
OPENAI_API_KEY=sk-xxx
|
||||
USER=<user-id> # The User Id you want to associate the memories with
|
||||
USER=<user-id> # The User Id you want to associate the memories with
|
||||
```
|
||||
|
||||
- #### LLM Configuration (optional)
|
||||
|
||||
By default, OpenMemory uses OpenAI (`gpt-4o-mini`) for the LLM and embedder. You can configure a different provider using these environment variables in `/api/.env`:
|
||||
|
||||
| Variable | Description | Default |
|
||||
|---|---|---|
|
||||
| `LLM_PROVIDER` | LLM provider (`openai`, `ollama`, `anthropic`, `groq`, `together`, `deepseek`, etc.) | `openai` |
|
||||
| `LLM_MODEL` | Model name for the LLM provider | `gpt-4o-mini` (OpenAI) / `llama3.1:latest` (Ollama) |
|
||||
| `LLM_API_KEY` | API key for the LLM provider | `OPENAI_API_KEY` env var |
|
||||
| `LLM_BASE_URL` | Custom base URL for the LLM API | Provider default |
|
||||
| `OLLAMA_BASE_URL` | Ollama-specific base URL (takes precedence over `LLM_BASE_URL` for Ollama) | `http://localhost:11434` |
|
||||
| `EMBEDDER_PROVIDER` | Embedder provider (defaults to `ollama` when LLM is Ollama, otherwise `openai`) | `openai` |
|
||||
| `EMBEDDER_MODEL` | Model name for the embedder | `text-embedding-3-small` (OpenAI) / `nomic-embed-text` (Ollama) |
|
||||
| `EMBEDDER_API_KEY` | API key for the embedder provider | `OPENAI_API_KEY` env var |
|
||||
| `EMBEDDER_BASE_URL` | Custom base URL for the embedder API | Provider default |
|
||||
|
||||
**Example: Using Ollama (fully local)**
|
||||
```env
|
||||
LLM_PROVIDER=ollama
|
||||
LLM_MODEL=llama3.1:latest
|
||||
EMBEDDER_PROVIDER=ollama
|
||||
EMBEDDER_MODEL=nomic-embed-text
|
||||
OLLAMA_BASE_URL=http://localhost:11434
|
||||
```
|
||||
|
||||
**Example: Using Anthropic**
|
||||
```env
|
||||
LLM_PROVIDER=anthropic
|
||||
LLM_MODEL=claude-sonnet-4-20250514
|
||||
LLM_API_KEY=sk-ant-xxx
|
||||
```
|
||||
- #### Example `/ui/.env`
|
||||
|
||||
|
||||
@@ -1,2 +1,15 @@
|
||||
OPENAI_API_KEY=sk-xxx
|
||||
USER=user
|
||||
USER=user
|
||||
|
||||
# LLM Configuration (optional - defaults to openai/gpt-4o-mini)
|
||||
# LLM_PROVIDER=ollama
|
||||
# LLM_MODEL=llama3.1:latest
|
||||
# LLM_API_KEY=
|
||||
# LLM_BASE_URL=
|
||||
# OLLAMA_BASE_URL=http://localhost:11434
|
||||
|
||||
# Embedder Configuration (optional - defaults to openai/text-embedding-3-small)
|
||||
# EMBEDDER_PROVIDER=ollama
|
||||
# EMBEDDER_MODEL=nomic-embed-text
|
||||
# EMBEDDER_API_KEY=
|
||||
# EMBEDDER_BASE_URL=
|
||||
|
||||
@@ -133,6 +133,97 @@ def reset_memory_client():
|
||||
_config_hash = None
|
||||
|
||||
|
||||
# --- LLM provider config factories ---
|
||||
|
||||
def _build_ollama_llm_config(model, api_key, base_url, ollama_base_url):
|
||||
config = {"model": model or "llama3.1:latest"}
|
||||
# OLLAMA_BASE_URL takes precedence, then LLM_BASE_URL, then default
|
||||
config["ollama_base_url"] = ollama_base_url or base_url or "http://localhost:11434"
|
||||
return config
|
||||
|
||||
|
||||
def _build_openai_llm_config(model, api_key, base_url, ollama_base_url):
|
||||
config = {
|
||||
"model": model or "gpt-4o-mini",
|
||||
"api_key": api_key or "env:OPENAI_API_KEY",
|
||||
}
|
||||
if base_url:
|
||||
config["openai_base_url"] = base_url
|
||||
return config
|
||||
|
||||
|
||||
_LLM_CONFIG_FACTORIES = {
|
||||
"ollama": _build_ollama_llm_config,
|
||||
"openai": _build_openai_llm_config,
|
||||
}
|
||||
|
||||
|
||||
def _create_llm_config(provider, model, api_key, base_url, ollama_base_url):
|
||||
"""Build LLM config using registered provider factory or generic fallback."""
|
||||
base_config = {
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
}
|
||||
|
||||
factory = _LLM_CONFIG_FACTORIES.get(provider)
|
||||
if factory:
|
||||
base_config.update(factory(model, api_key, base_url, ollama_base_url))
|
||||
else:
|
||||
# Generic provider (anthropic, groq, together, deepseek, etc.)
|
||||
if not model:
|
||||
raise ValueError(
|
||||
f"LLM_MODEL environment variable is required when using LLM_PROVIDER='{provider}'. "
|
||||
f"Set LLM_MODEL to a valid model name for the '{provider}' provider."
|
||||
)
|
||||
base_config["model"] = model
|
||||
if api_key:
|
||||
base_config["api_key"] = api_key
|
||||
|
||||
return base_config
|
||||
|
||||
|
||||
# --- Embedder provider config factories ---
|
||||
|
||||
def _build_ollama_embedder_config(model, api_key, base_url, ollama_base_url, llm_base_url):
|
||||
config = {"model": model or "nomic-embed-text"}
|
||||
config["ollama_base_url"] = base_url or ollama_base_url or llm_base_url or "http://localhost:11434"
|
||||
return config
|
||||
|
||||
|
||||
def _build_openai_embedder_config(model, api_key, base_url, ollama_base_url, llm_base_url):
|
||||
config = {
|
||||
"model": model or "text-embedding-3-small",
|
||||
"api_key": api_key or "env:OPENAI_API_KEY",
|
||||
}
|
||||
if base_url:
|
||||
config["openai_base_url"] = base_url
|
||||
return config
|
||||
|
||||
|
||||
_EMBEDDER_CONFIG_FACTORIES = {
|
||||
"ollama": _build_ollama_embedder_config,
|
||||
"openai": _build_openai_embedder_config,
|
||||
}
|
||||
|
||||
|
||||
def _create_embedder_config(provider, model, api_key, base_url, ollama_base_url, llm_base_url):
|
||||
"""Build embedder config using registered provider factory or generic fallback."""
|
||||
factory = _EMBEDDER_CONFIG_FACTORIES.get(provider)
|
||||
if factory:
|
||||
config = factory(model, api_key, base_url, ollama_base_url, llm_base_url)
|
||||
else:
|
||||
if not model:
|
||||
raise ValueError(
|
||||
f"EMBEDDER_MODEL environment variable is required when using EMBEDDER_PROVIDER='{provider}'. "
|
||||
f"Set EMBEDDER_MODEL to a valid model name for the '{provider}' provider."
|
||||
)
|
||||
config = {"model": model}
|
||||
if api_key:
|
||||
config["api_key"] = api_key
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def get_default_memory_config():
|
||||
"""Get default memory client configuration with sensible defaults."""
|
||||
# Detect vector store based on environment variables
|
||||
@@ -235,27 +326,51 @@ def get_default_memory_config():
|
||||
})
|
||||
|
||||
print(f"Auto-detected vector store: {vector_store_provider} with config: {vector_store_config}")
|
||||
|
||||
|
||||
# Detect LLM provider from environment variables
|
||||
llm_provider = os.environ.get('LLM_PROVIDER', 'openai').lower()
|
||||
llm_model = os.environ.get('LLM_MODEL')
|
||||
llm_api_key = os.environ.get('LLM_API_KEY')
|
||||
llm_base_url = os.environ.get('LLM_BASE_URL')
|
||||
ollama_base_url = os.environ.get('OLLAMA_BASE_URL')
|
||||
|
||||
llm_config = _create_llm_config(
|
||||
provider=llm_provider,
|
||||
model=llm_model,
|
||||
api_key=llm_api_key,
|
||||
base_url=llm_base_url,
|
||||
ollama_base_url=ollama_base_url,
|
||||
)
|
||||
print(f"Auto-detected LLM provider: {llm_provider}")
|
||||
|
||||
# Detect embedder provider from environment variables
|
||||
embedder_provider = os.environ.get('EMBEDDER_PROVIDER', llm_provider if llm_provider == 'ollama' else 'openai').lower()
|
||||
embedder_model = os.environ.get('EMBEDDER_MODEL')
|
||||
embedder_api_key = os.environ.get('EMBEDDER_API_KEY')
|
||||
embedder_base_url = os.environ.get('EMBEDDER_BASE_URL')
|
||||
|
||||
embedder_config = _create_embedder_config(
|
||||
provider=embedder_provider,
|
||||
model=embedder_model,
|
||||
api_key=embedder_api_key,
|
||||
base_url=embedder_base_url,
|
||||
ollama_base_url=ollama_base_url,
|
||||
llm_base_url=llm_base_url,
|
||||
)
|
||||
print(f"Auto-detected embedder provider: {embedder_provider}")
|
||||
|
||||
return {
|
||||
"vector_store": {
|
||||
"provider": vector_store_provider,
|
||||
"config": vector_store_config
|
||||
},
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
"api_key": "env:OPENAI_API_KEY"
|
||||
}
|
||||
"provider": llm_provider,
|
||||
"config": llm_config
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small",
|
||||
"api_key": "env:OPENAI_API_KEY"
|
||||
}
|
||||
"provider": embedder_provider,
|
||||
"config": embedder_config
|
||||
},
|
||||
"version": "v1.1"
|
||||
}
|
||||
@@ -327,18 +442,10 @@ def get_memory_client(custom_instructions: str = None):
|
||||
# Update LLM configuration if available
|
||||
if "llm" in mem0_config and mem0_config["llm"] is not None:
|
||||
config["llm"] = mem0_config["llm"]
|
||||
|
||||
# Fix Ollama URLs for Docker if needed
|
||||
if config["llm"].get("provider") == "ollama":
|
||||
config["llm"] = _fix_ollama_urls(config["llm"])
|
||||
|
||||
|
||||
# Update Embedder configuration if available
|
||||
if "embedder" in mem0_config and mem0_config["embedder"] is not None:
|
||||
config["embedder"] = mem0_config["embedder"]
|
||||
|
||||
# Fix Ollama URLs for Docker if needed
|
||||
if config["embedder"].get("provider") == "ollama":
|
||||
config["embedder"] = _fix_ollama_urls(config["embedder"])
|
||||
|
||||
if "vector_store" in mem0_config and mem0_config["vector_store"] is not None:
|
||||
config["vector_store"] = mem0_config["vector_store"]
|
||||
@@ -357,6 +464,12 @@ def get_memory_client(custom_instructions: str = None):
|
||||
if instructions_to_use:
|
||||
config["custom_fact_extraction_prompt"] = instructions_to_use
|
||||
|
||||
# Fix Ollama URLs for Docker environment (applies to both env-var defaults and DB overrides)
|
||||
if config.get("llm", {}).get("provider") == "ollama":
|
||||
config["llm"] = _fix_ollama_urls(config["llm"])
|
||||
if config.get("embedder", {}).get("provider") == "ollama":
|
||||
config["embedder"] = _fix_ollama_urls(config["embedder"])
|
||||
|
||||
# ALWAYS parse environment variables in the final config
|
||||
# This ensures that even default config values like "env:OPENAI_API_KEY" get parsed
|
||||
print("Parsing environment variables in final config...")
|
||||
|
||||
Reference in New Issue
Block a user