Skip to content

Commit c18c7f4

Browse files
authored
docs: bring your own llms and embeddings (#631)
explains how to customize Ragas with your own llms and embeddings
1 parent f6a932a commit c18c7f4

File tree

6 files changed

+128
-623
lines changed

6 files changed

+128
-623
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ docs-site: ## Build and serve documentation
3939
watch-docs: ## Build and watch documentation
4040
rm -rf $(GIT_ROOT)/docs/_build/{html, jupyter_execute}
4141
sphinx-autobuild docs docs/_build/html --watch $(GIT_ROOT)/src/ --ignore "_build" --open-browser
42+
rewrite-docs: ## Use GPT4 to rewrite the documentation
43+
@echo "Rewriting the documentation in directory $(DIR)..."
44+
@python $(GIT_ROOT)/docs/python alphred.py --directory $(DIR)
4245

4346
# Benchmarks
4447
run-benchmarks-eval: ## Run benchmarks for Evaluation

docs/alfred.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
from collections import namedtuple
5+
import argparse
56
import asyncio
67
from tqdm.asyncio import tqdm
78
import typing as t
@@ -21,6 +22,7 @@ def load_docs(path: str) -> t.List[File]:
2122
docs = []
2223
for file in files:
2324
with open(file, "r") as f:
25+
print("fixing: ", file)
2426
docs.append(File(file, f.read()))
2527
return docs
2628

@@ -54,8 +56,15 @@ async def main(docs: t.List[File], llm: BaseChatModel):
5456
"""
5557
Helpful assistant for documentation review and more (hopefully in the future).
5658
"""
59+
# Create an argument parser
60+
parser = argparse.ArgumentParser(
61+
description="Helpful assistant for documentation review."
62+
)
63+
parser.add_argument("-d", "--directory", help="Directory to run the script against")
64+
args = parser.parse_args()
65+
directory = args.directory
66+
docs = load_docs(directory)
5767
gpt4 = ChatOpenAI(model="gpt-4")
58-
docs = load_docs("./getstarted/")
5968
fix_docs = asyncio.run(main(docs, gpt4))
6069
for doc in fix_docs:
6170
with open(doc.name, "w") as f:
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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

Comments
 (0)