Skip to content

Commit

Permalink
Merge pull request #9075 from mindsdb/staging
Browse files Browse the repository at this point in the history
Release 24.4.3.0
  • Loading branch information
StpMax committed Apr 15, 2024
2 parents 8c4f890 + a30f358 commit d097d20
Show file tree
Hide file tree
Showing 34 changed files with 742 additions and 119 deletions.
74 changes: 74 additions & 0 deletions docs/integrations/ai-engines/mindsdb_inference.mdx
@@ -0,0 +1,74 @@
---
title: MindsDB Inference Endpoints
sidebarTitle: MindsDB Inference Endpoints
---

This documentation describes the integration of MindsDB with [MindsDB Inference Endpoints](https://mindsdb-docs.hashnode.space/), a cloud service that simplifies the way developers interact with cutting-edge LLMs through a universal API.

## Prerequisites

Before proceeding, ensure the following prerequisites are met:

1. Install MindsDB [locally via Docker](https://docs.mindsdb.com/setup/self-hosted/docker) or use [MindsDB Cloud](https://cloud.mindsdb.com/).
2. To use MindsDB Inference Endpoints within MindsDB, install the required dependencies following [this instruction](/setup/self-hosted/docker#install-dependencies).
3. Obtain the MindsDB Inference API key required to deploy and use MindsDB Inference Endpoints models within MindsDB. Follow the [instructions for obtaining the API key](https://mindsdb-docs.hashnode.space/docs/authentication).

## Setup

Create an AI engine from the [MindsDB Inference Endpoints handler](https://github.com/mindsdb/mindsdb/tree/staging/mindsdb/integrations/handlers/mindsdb_inference_handler).

```sql
CREATE ML_ENGINE mindsdb_serve
FROM mindsdb_inference
USING
mindsdb_inference_api_key = 'api-key-value'
```

Create a model using `mindsdb_serve` as an engine.

```sql
CREATE MODEL mindsdb_inference_model
PREDICT answer
USING
engine = 'mindsdb_serve', -- engine name as created via CREATE ML_ENGINE
model_name = 'model-name', -- choose one of available models
prompt_teplate = 'prompt-to-the-model'; -- prompt message to be completed by the model
mode = 'mode_name' -- choose one of the available modes: 'conversational', 'conversational-full'
```

## Usage

The following usage examples utilize `mindsdb_serve` to create a model with the `CREATE MODEL` statement.

Classify text sentiment using the Mistral 7B model.

```sql
CREATE MODEL mindsdb_inference_model
PREDICT sentiment
USING
engine = 'mindsdb_serve',
model_name = 'mistral-7b',
prompt_template = 'Classify the sentiment of the following text as one of `positive`, `neutral` or `negative`: {{text}}';
```

Query the model to get predictions.

```sql
SELECT text, sentiment
FROM mindsdb_inference_model
WHERE text = 'I love machine learning!';
```

Here is the output:

```sql
+--------------------------+-----------+
| text | sentiment |
+--------------------------+-----------+
| I love machine learning! | positive |
+--------------------------+-----------+
```

## Supported Models

For an overview of the models supported, visit the [following docs](https://docs.mdb.ai/). This list will help you quickly identify the right models for your needs.
12 changes: 12 additions & 0 deletions docs/mindsdb_sql/agents/knowledge-bases.mdx
Expand Up @@ -27,6 +27,18 @@ CREATE KNOWLEDGE_BASE my_kb
[storage = vector_database.storage_table;]]
```

### Managing input columns

Knowledge base can accept optional columns parameters to define where id, content and metadata columns are located:
```sql
CREATE KNOWLEDGE_BASE my_kb
USING
metadata_columns = ['date', 'creator'], -- optional, if not set: no metadata columns
content_columns = ['review'], -- optional, if not set: all columns is content
id_column='index' -- optional, default: id
```


## Step by step guide


Expand Down
1 change: 1 addition & 0 deletions docs/mint.json
Expand Up @@ -977,6 +977,7 @@
"integrations/ai-engines/langchain",
"integrations/ai-engines/llamaindex",
"integrations/ai-engines/monkeylearn",
"integrations/ai-engines/mindsdb_inference",
"integrations/ai-engines/ollama",
"integrations/ai-engines/openai",
"integrations/ai-engines/replicate-llm",
Expand Down
4 changes: 2 additions & 2 deletions docs/sql/tutorials/text-sentiment-hf.mdx
Expand Up @@ -3,7 +3,7 @@ title: Predict Text Sentiment with Hugging Face and MindsDB
sidebarTitle: Predict Text Sentiment
---

In this tutorial, we'll use a model from the Hugging Fae hub to predict text sentiment.
In this tutorial, we'll use a model from the Hugging Faсe hub to predict text sentiment.

## Connect a database

Expand Down Expand Up @@ -44,7 +44,7 @@ USING
labels=['negative','neutral','positive'];
```

To create a model in MindsDB, we use the `CREATE MODEL` statement. Next, we define the target column using the PREDICT clause. Finally, we specify all required parameters in the `USING` clause.
To create a model in MindsDB, we use the `CREATE MODEL` statement. Next, we define the target column using the `PREDICT` clause. Finally, we specify all required parameters in the `USING` clause.

Once the above query is executed, we can check the status of the creation process:

Expand Down
2 changes: 1 addition & 1 deletion mindsdb/__about__.py
@@ -1,6 +1,6 @@
__title__ = 'MindsDB'
__package_name__ = 'mindsdb'
__version__ = '24.4.2.1'
__version__ = '24.4.3.0'
__description__ = "MindsDB's AI SQL Server enables developers to build AI tools that need access to real-time data to perform their tasks"
__email__ = "jorge@mindsdb.com"
__author__ = 'MindsDB Inc'
Expand Down
Expand Up @@ -315,7 +315,7 @@ class InformationSchemaDataNode(DataNode):
"IS_RUNNING",
"LAST_ERROR",
],
"KNOWLEDGE_BASES": ["NAME", "PROJECT", "MODEL", "STORAGE"],
"KNOWLEDGE_BASES": ["NAME", "PROJECT", "MODEL", "STORAGE", "PARAMS"],
"SKILLS": ["NAME", "PROJECT", "TYPE", "PARAMS"],
"AGENTS": [
"NAME",
Expand Down Expand Up @@ -672,7 +672,7 @@ def _get_knowledge_bases(self, query: ASTNode = None):

columns = self.information_schema['KNOWLEDGE_BASES']

# columns: NAME, PROJECT, MODEL, STORAGE
# columns: NAME, PROJECT, MODEL, STORAGE, PARAMS
data = []

for kb in kb_list:
Expand All @@ -684,7 +684,8 @@ def _get_knowledge_bases(self, query: ASTNode = None):
kb.name,
project_name,
embedding_model.name if embedding_model is not None else None,
vector_database_name + '.' + kb.vector_database_table
vector_database_name + '.' + kb.vector_database_table,
to_json(kb.params),
))

return pd.DataFrame(data, columns=columns)
Expand Down
Expand Up @@ -6,7 +6,6 @@

import pandas as pd
import pytest
from mindsdb_sql import parse_sql

from tests.unit.executor_test_base import BaseExecutorTest

Expand All @@ -19,15 +18,6 @@

@pytest.mark.skipif(not CHROMA_DB_INSTALLED, reason="chroma_db is not installed")
class TestChromaDBHandler(BaseExecutorTest):
def run_sql(self, sql):
ret = self.command_executor.execute_command(parse_sql(sql, dialect="mindsdb"))

assert ret.error_code is None
if ret.data is not None:
columns = [
col.alias if col.alias is not None else col.name for col in ret.columns
]
return pd.DataFrame(ret.data, columns=columns)

@pytest.fixture(autouse=True, scope="function")
def setup_method(self):
Expand Down
Expand Up @@ -87,7 +87,7 @@
DEFAULT_AGENT_TIMEOUT_SECONDS = 300
# These should require no additional arguments.
DEFAULT_AGENT_TOOLS = []
DEFAULT_AGENT_TYPE = AgentType.CONVERSATIONAL_REACT_DESCRIPTION
DEFAULT_AGENT_TYPE = AgentType.OPENAI_FUNCTIONS
DEFAULT_MAX_ITERATIONS = 10
DEFAULT_MAX_TOKENS = 2048
DEFAULT_MODEL_NAME = 'gpt-4-0125-preview'
Expand Down
Expand Up @@ -27,13 +27,14 @@
DEFAULT_ASSISTANT_COLUMN
)
from mindsdb.integrations.handlers.langchain_handler.log_callback_handler import LogCallbackHandler
from mindsdb.integrations.handlers.langchain_handler.mindsdb_database_agent import MindsDBSQL
from mindsdb.integrations.utilities.rag.settings import DEFAULT_RAG_PROMPT_TEMPLATE
from mindsdb.integrations.handlers.langchain_handler.tools import setup_tools
from mindsdb.integrations.handlers.openai_handler.constants import CHAT_MODELS as OPEN_AI_CHAT_MODELS
from mindsdb.integrations.libs.base import BaseMLEngine
from mindsdb.integrations.libs.llm.utils import get_llm_config
from mindsdb.integrations.utilities.handler_utils import get_api_key
from mindsdb.interfaces.storage.model_fs import HandlerStorage, ModelStorage
from mindsdb.integrations.handlers.langchain_embedding_handler.langchain_embedding_handler import construct_model_from_args
from mindsdb.utilities import log
from mindsdb.utilities.context_executor import ContextThreadPoolExecutor

Expand Down Expand Up @@ -76,7 +77,7 @@ def __init__(
if self.log_callback_handler is None:
self.log_callback_handler = LogCallbackHandler(logger)

def _get_provider(self, args: Dict) -> str:
def _get_llm_provider(self, args: Dict) -> str:
if 'provider' in args:
return args['provider']
if args['model_name'] in ANTHROPIC_CHAT_MODELS:
Expand All @@ -87,6 +88,14 @@ def _get_provider(self, args: Dict) -> str:
return 'ollama'
raise ValueError(f"Invalid model name. Please define provider")

def _get_embedding_model_provider(self, args: Dict) -> str:
if 'embedding_model_provider' in args:
return args['embedding_model_provider']
if 'embedding_model_provider' not in args:
logger.warning('No embedding model provider specified. trying to use llm provider.')
return args.get('embedding_model_provider', self._get_llm_provider(args))
raise ValueError(f"Invalid model name. Please define provider")

def _get_chat_model_params(self, args: Dict, pred_args: Dict) -> Dict:
model_config = args.copy()
# Override with prediction args.
Expand All @@ -95,8 +104,8 @@ def _get_chat_model_params(self, args: Dict, pred_args: Dict) -> Dict:
model_config['api_keys'] = {
p: get_api_key(p, args, self.engine_storage, strict=False) for p in SUPPORTED_PROVIDERS
}
llm_config = get_llm_config(args.get('provider', self._get_provider(args)), model_config)
config_dict = llm_config.model_dump()
llm_config = get_llm_config(args.get('provider', self._get_llm_provider(args)), model_config)
config_dict = llm_config.dict()
config_dict = {k: v for k, v in config_dict.items() if v is not None}
return config_dict

Expand Down Expand Up @@ -131,6 +140,9 @@ def _create_chat_model(self, args: Dict, pred_args: Dict):
return ChatOllama(**model_kwargs)
raise ValueError(f'Unknown provider: {args["provider"]}')

def _create_embeddings_model(self, args: Dict):
return construct_model_from_args(args)

def _handle_parsing_errors(self, error: Exception) -> str:
response = str(error)
if not response.startswith(_PARSING_ERROR_PREFIX):
Expand All @@ -152,7 +164,13 @@ def create(self, target: str, args: Dict = None, **kwargs):
args = args['using']
args['target'] = target
args['model_name'] = args.get('model_name', DEFAULT_MODEL_NAME)
args['provider'] = args.get('provider', self._get_provider(args))
args['provider'] = args.get('provider', self._get_llm_provider(args))
args['embedding_model_provider'] = args.get('embedding_model', self._get_embedding_model_provider(args))
if args.get('mode') == 'retrieval':
# use default prompt template for retrieval i.e. RAG if not provided
if "prompt_template" not in args:
args["prompt_template"] = DEFAULT_RAG_PROMPT_TEMPLATE

self.model_storage.json_set('args', args)

@staticmethod
Expand All @@ -162,7 +180,8 @@ def create_validation(_, args: Dict=None, **kwargs):
else:
args = args['using']
if 'prompt_template' not in args:
raise ValueError('Please provide a `prompt_template` for this engine.')
if not args.get('mode') == 'retrieval':
raise ValueError('Please provide a `prompt_template` for this engine.')

def predict(self, df: pd.DataFrame, args: Dict=None) -> pd.DataFrame:
"""
Expand All @@ -174,7 +193,8 @@ def predict(self, df: pd.DataFrame, args: Dict=None) -> pd.DataFrame:
if 'prompt_template' not in args and 'prompt_template' not in pred_args:
raise ValueError(f"This model expects a `prompt_template`, please provide one.")
# Back compatibility for old models
args['provider'] = args.get('provider', self._get_provider(args))
args['provider'] = args.get('provider', self._get_llm_provider(args))
args['embedding_model_provider'] = args.get('embedding_model', self._get_embedding_model_provider(args))

df = df.reset_index(drop=True)
agent = self.create_agent(df, args, pred_args)
Expand All @@ -189,6 +209,16 @@ def create_agent(self, df: pd.DataFrame, args: Dict=None, pred_args: Dict=None)
# Set up tools.
model_kwargs = self._get_chat_model_params(args, pred_args)
llm = self._create_chat_model(args, pred_args)

# Set up embeddings model if needed.
if args.get('mode') == 'retrieval':
# get args for embeddings model
embeddings_args = args.pop('embedding_model_args', {})
# create embeddings model
pred_args['embeddings_model'] = self._create_embeddings_model(embeddings_args)
pred_args['llm'] = llm
pred_args['mindsdb_path'] = self.engine_storage.folder_get

tools = setup_tools(llm,
model_kwargs,
pred_args,
Expand Down Expand Up @@ -228,7 +258,7 @@ def create_agent(self, df: pd.DataFrame, args: Dict=None, pred_args: Dict=None)
max_execution_time=pred_args.get('timeout_seconds', args.get('timeout_seconds', DEFAULT_AGENT_TIMEOUT_SECONDS)),
max_iterations=pred_args.get('max_iterations', args.get('max_iterations', DEFAULT_MAX_ITERATIONS)),
memory=memory,
verbose=pred_args.get('verbose', args.get('verbose', False))
verbose=pred_args.get('verbose', args.get('verbose', True))
)
return agent_executor

Expand Down
Expand Up @@ -13,6 +13,7 @@ class LogCallbackHandler(BaseCallbackHandler):
def __init__(self, logger: logging.Logger):
logger.setLevel('DEBUG')
self.logger = logger
self._num_running_chains = 0

def on_llm_start(
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
Expand Down
Expand Up @@ -4,5 +4,6 @@ tiktoken >= 0.3.0
anthropic==0.3.5
langchain-experimental # Tools
langfuse # Tracing
litellm==1.23.2
litellm==1.35.0
-r mindsdb/integrations/handlers/openai_handler/requirements.txt
-r mindsdb/integrations/handlers/langchain_embedding_handler/requirements.txt

0 comments on commit d097d20

Please sign in to comment.