|
| 1 | +# Bring Your Own LLMs and Embeddings |
| 2 | + |
| 3 | +Ragas uses LLMs and Embeddings for both evaluation and test set generation. By default, the LLM and Embedding models of choice are OpenAI but you can easily customize the `evaluation` and `TestsetGenerator` with the LLMs and Embeddings of your choice. In this tutorial, we will go through the basics of how to do it. |
| 4 | + |
| 5 | +:::{note} |
| 6 | +`BaseRagasLLM` and `BaseRagasEmbeddings` are the base classes Ragas uses internally for LLMs and Embeddings. Any custom LLM or Embeddings should be a subclass of these base classes. |
| 7 | + |
| 8 | +If you are using Langchain, you can pass the Langchain LLM and Embeddings directly and Ragas will wrap it with `LangchainLLMWrapper` or `LangchainEmbeddingsWrapper` as needed. |
| 9 | +::: |
| 10 | + |
| 11 | +:::{seealso} |
| 12 | +After understanding the basics, feel free to check out the specific guides here |
| 13 | + |
| 14 | +- [Azure OpenAI](./azure-openai.ipynb) |
| 15 | +- [AWS Bedrock](./aws-bedrock.ipynb) |
| 16 | +- [Google Cloud (VertexAI)](./gcp-vertexai.ipynb) |
| 17 | +::: |
| 18 | + |
| 19 | +## Customizing Evaluations |
| 20 | + |
| 21 | +Depending on which metric you use for evaluations, it will use LLMs and/or Embeddings under-the-hood. You can customize which models to use in 2 ways: |
| 22 | + |
| 23 | +1. By Passing it through `evaluate()`: The evaluate function has 2 arguments `llm=` and `embeddings=`. You can pass any instance of `BaseRagasLLM` or `BaseRagasEmbeddings` respectively. If you are using Langchain, you can pass the Langchain llm and embeddings instances directly and Ragas will wrap it with `LangchainLLMWrapper` or `LangchainEmbeddingsWrapper` as needed. |
| 24 | + |
| 25 | +```{code-block} python |
| 26 | +from langchain_core.language_models import BaseLanguageModel |
| 27 | +from langchain_core.embeddings import Embeddings |
| 28 | +
|
| 29 | +langchain_llm = BaseLanguageModel(model="my_model") # any langchain LLM instance |
| 30 | +langchain_embeddings = Embeddings(model="my_model") # any langchain Embeddings instance |
| 31 | +
|
| 32 | +results = evaluate(metrics=[], llm=langchain_llm, embeddings=embeddings) |
| 33 | +``` |
| 34 | + |
| 35 | +2. Attaching it to `metrics`: You can attach the LLM and Embeddings to the `metrics` object directly. |
| 36 | +```{code-block} python |
| 37 | +# override the llm and embeddings for a specific metric |
| 38 | +from ragas.metrics import answer_relevancy |
| 39 | +answer_relevancy.llm = langchain_llm |
| 40 | +answer_relevancy.embeddings = langchain_embeddings |
| 41 | +
|
| 42 | +# You can also init a new metric with the llm and embeddings of your choice |
| 43 | +
|
| 44 | +from ragas.metrics import AnswerRelevancy |
| 45 | +ar = AnswerRelevancy(llm=langchain_llm, embeddings=langchain_embeddings) |
| 46 | +
|
| 47 | +# pass to evaluate |
| 48 | +result = evaluate(metrics=[ar, answer_relevancy]) |
| 49 | +# even if I pass an llm or embeddings to evaluate, it will use the ones attached to the metrics |
| 50 | +result = evaluate( |
| 51 | + metrics=[ar, answer_relevancy, faithfullness], |
| 52 | + llm=llm, |
| 53 | + embeddings=embeddings |
| 54 | +) |
| 55 | +``` |
| 56 | + |
| 57 | +:::{note} |
| 58 | +A note on precedence: llms and embeddings attached to metrics have higher precedence than the llm and embeddings passed to `evaluate()` function. You can use this to override specific metrics with a different llm or embedding models that perform better for the metric in question. |
| 59 | +::: |
| 60 | + |
| 61 | +## Customizing Testset Generation |
| 62 | +There are a lot of components in the test set generation pipeline that use LLMs and Embeddings here we will be explaining the top-level components. |
| 63 | + |
| 64 | +1. `DocumentStore`: The `DocumentStore` requires an `Extractor` to extract keywords from the documents and nodes and `embeddings` to calculate the embeddings of nodes and calculate similarity. |
| 65 | +```{code-block} python |
| 66 | +# default extractor |
| 67 | +from ragas.testset.extractor import KeyphraseExtractor |
| 68 | +from langchain.text_splitter import TokenTextSplitter |
| 69 | +# default DocumentStore |
| 70 | +from ragas.testset.docstore import InMemoryDocumentStore |
| 71 | +
|
| 72 | +# define llm and embeddings |
| 73 | +langchain_llm = BaseLanguageModel(model="my_model") # any langchain LLM instance |
| 74 | +langchain_embeddings = Embeddings(model="my_model") # any langchain Embeddings instance |
| 75 | +# make sure to wrap them with wrappers |
| 76 | +from ragas.llms import LangchainLLMWrapper |
| 77 | +from ragas.embeddings import LangchainEmbeddingsWrapper |
| 78 | +langchain_llm = LangchainLLMWrapper(langchain_llm) |
| 79 | +langchain_embeddings = LangchainEmbeddingsWrapper(langchain_embeddings) |
| 80 | +
|
| 81 | +# you can also use custom LLMs and Embeddings here but make sure |
| 82 | +# they are subclasses of BaseRagasLLM and BaseRagasEmbeddings |
| 83 | +llm = MyCustomLLM() |
| 84 | +embeddings = MyCustomEmbeddings() |
| 85 | +
|
| 86 | +# init the DocumentStore with your own llm and embeddings |
| 87 | +splitter = TokenTextSplitter(chunk_size=1000, chunk_overlap=100) |
| 88 | +keyphrase_extractor = KeyphraseExtractor(llm=langchain_llm) |
| 89 | +docstore = InMemoryDocumentStore( |
| 90 | + splitter=splitter, |
| 91 | + embeddings=langchain_embeddings, |
| 92 | + extractor=keyphrase_extractor, |
| 93 | +) |
| 94 | +``` |
| 95 | +2. `TestsetGenerator`: The `TestsetGenerator` requires `generator_llm` for evolutions, `critic_llm` for the question and node filters and `docstore` for accessing the documents. You can pass the llms when instantiating the `TestsetGenerator`. |
| 96 | +```{code-block} python |
| 97 | +# any langchain LLM instance |
| 98 | +generator_llm = BaseLanguageModel( |
| 99 | + model="model_for_generation" |
| 100 | +) |
| 101 | +# any langchain LLM instance |
| 102 | +critic_llm = BaseLanguageModel( |
| 103 | + model="model_for_critic(ideally more advanced and capable)" |
| 104 | +) |
| 105 | +# refer above if in doubt |
| 106 | +docstore = InMemoryDocumentStore( |
| 107 | + splitter=splitter, |
| 108 | + embeddings=langchain_embeddings, |
| 109 | + extractor=keyphrase_extractor, |
| 110 | +) |
| 111 | +``` |
| 112 | +The `TestsetGenerator` will now init the `evolutions` and `filters` with the llms you passed. If you need further fine-grained control, you will have to initialize the `evolutions` and `filters` manually and use them. Feel free to raise an issue if the docs need clarity on this. |
0 commit comments