API
RAG-Core includes an API module intended to expose the endpoints your users will need to interact with your services. This API is automatically generated from a simple yaml config file.
It enables you to offer your users service documented on OpenAPI standard to facilitate interactions with your RAG.
API Configuration
API is generated according to a configuration file.
The configuration file expects the following structure:
info:
name: "Infopro Digital RAG API"
description_path: "examples/api_description.md"
contact:
name: "Antoine Meilliez"
email: "antoine.meilliez@datagears.io"
services:
- name: "USN RAG"
api_prefix: "usn_rag"
description: "Question Answering service providing answer based on USN news articles"
module_path: "examples/advanced/usn_rag_with_sources.py"
Let's break it down
info: Contains generic information about your API, displayed in the header of the OpenAPI documentation.name: The title shown a the header of your OpenAPI configurationdescription_path: The path to the markdown or text file containing a description of your API.contact:name: The technical referent of your applicationemail: The related email
services: Contains a list of services to be exposed in your API.- ❗️
name: The name attribute of theRAGorEmbeddingPipelineinstance (accessible viarag.name) api_prefix: The unique prefix used to route the generic endpoints such as/invoke,/batch,/stream.description: A small text displayed next to the tag (aka name) in OpenAPI docs- ❗️
module_path: The python file or folder path where theRAGorEmbeddingPipelineis instanciated. examples:app.my_rag.py
- ❗️
Registering a RAG or an EmbeddingsPipeline
In the services section, simply add an item with the following information:
` - name: "Fancy RAG" # Your RAG or EmbeddingPipeline name
api_prefix: "fancy" # Your unique api prefix
description: "A fancy description"
module_path: "path/to/your/fancy_file.py"
Environment variables
You can configure some properties of your API by setting a few environment variables.
-
PORT:int
The port behind which the API is exposed:
http://0.0.0.0:{PORT}/docs -
AUTO_RELOAD:bool
Automatically reload the server when you make changes to your code.
-
LOG_LEVEL:str
Can be one of
NOTSET/DEBUG/INFO/WARNING/ERROR/CRITICAL -
API_CONFIG_FILE:str
The path when the
api.yamlcan be found -
STATIC_FILE_URL:str
The URL path of the static demo
Demo is deactivated if not set.
default: /static
-
DOCS_URL:str
The URL of the OpenAPI docs
Docs are deactivated if not set.
default: /docs
Run it
Several ways allows you to run the API
- Poetry
- Make
- Fastapi
For development and debug only
Customize
API is generated by default but you can fully adatp it to your needs and application.
Add document schema validation
The API endpoint related to EmbeddingsPipeline (/batch) takes a list of documents as input.
One can request from its users to implement a specific schema for the documents to be embed.
Such feature can be critical to ensure consistency for the embeddings data your application will rely on.
In api/embeddings_router.py, update the Document BaseModel:
Source
class Document(BaseModel):
page_content: str = Field(
...,
examples=[
"L'annonce à été faite par le successeur de Tim Cook lors de la keynote...",
"Le NASDAQ réagit positivement à l'annonce...",
],
)
metadata: dict = Field(
default_factory=dict,
examples=[
{
"title": "Apple annonce l'iPhone 34",
"site_short_name": "USN",
"published_at": 1715923800000,
"published": True,
},
{
"title": "30/02/2042 - Le NASDAQ cloture en hausse",
"site_short_name": "USN",
"published_at": 1715934700000,
"published": False,
},
],
)
Example
metadata fields can be enforced by implementing a custom metadata BaseModel such as:
Custom output schema
One can customize the API output accepted schema in api/rag_router.py
either by updating the RAGOutputBaseModel:
Source
class DocumentOutput(BaseModel):
page_content: str
metadata: dict[str, Any]
type: str = "Document"
class RAGOutput(BaseModel):
context: List[DocumentOutput]
question: str = Field(
examples=["Quels sont les contrats signés avec AirBus au bourget?"]
)
answer: str = Field(
examples=[
"Airbus a signé un contrat de 100M€ avec Safran et un autre de 200M€ avec Thales"
]
)
Or by updating the parse_output function
Source
def parse_output(output: dict[str, Any]) -> RAGOutput:
"""Parse the output of the RAG model to a RAGOutput object.
This function ensure compatibility between Langchain (based on pydantic v1) models and RAG-Core (based on pydanitc v2) models.
"""
answer = output["answer"]
context = output["context"]
question = output["question"]
if isinstance(answer, BaseMessage):
answer = answer.content
if all([isinstance(doc, Document) for doc in context]):
context = [DocumentOutput(**doc.dict()) for doc in context]
return RAGOutput(answer=answer, context=context, question=question)
Add custom endpoints
On can add custom endpoint in api/__init__.py
Example
fastapi = FastAPI(
title=api_config.info.name,
description=api_config.info.description,
version=get_project_version(),
contact=api_config.info.contact.model_dump(),
openapi_tags=[
{"name": ref.name, "description": ref.description}
for ref in api_config.services
],
docs_url=os.environ.get("DOCS_URL", None),
redoc_url=None
)
add_rag_routes(fastapi, api_config)
add_embeddings_routes(fastapi, api_config)
add_exception_handlers(fastapi)
# -- Add your endpoints after these initialisation steps --
# Example of custom endpoint
@fastapi.get("/greetings")
def custom_endpoint() -> str:
return "Hello world"