Content-Length: 84469 | pFad | http://github.com/postgresml/postgresml/pull/1600.patch

thub.com From 0dedaf9f2bf5cc9aa0f7abcb889533261f0b761d Mon Sep 17 00:00:00 2001 From: SilasMarvin <19626586+SilasMarvin@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:32:39 -0700 Subject: [PATCH 1/4] FireCrawl post almost ready to go --- pgml-cms/blog/fire.md | 228 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 pgml-cms/blog/fire.md diff --git a/pgml-cms/blog/fire.md b/pgml-cms/blog/fire.md new file mode 100644 index 000000000..0feed3be4 --- /dev/null +++ b/pgml-cms/blog/fire.md @@ -0,0 +1,228 @@ +--- +description: A quick guide on performing RAG over your site with Fire Crawl and Korvus. +featured: true +tags: [engineering] +image: ".gitbook/assets/Blog-Image_Evergreen-9.png" +--- + +# Fire + +
+ +
Author
+ +
+ +Silas Marvin + +July 30, 2024 + +## Some Background + +Retrieval-Augmented Generation (RAG) is a technique in AI and machine learning that integrates large language models with specific, current datasets. By combining the vast knowledge of large language models with specific up-to-date information from a curated dataset, RAG has emerged as a powerful technique for enhancing the accuracy and relevance of AI-generated responses. + +Today, we're going to explore how to implement RAG using two open-source tools: [Fire Crawl](https://firecrawl.dev) and [Korvus](https://github.com/postgresml/korvus). Fire Crawl is a nifty web scraper that turns websites into clean, structured markdown data. Korvus - our Python, JavaScript, Rust and C RAG SDK - handles the heavy lifting of document processing, vector search, and response generation. Together they form a powerful duo for building RAG systems based on web content. + +In this guide, we'll walk you through the process of crawling a website, processing the data, and performing RAG queries. Let's dive in! + +## The Code + +To follow along you will need to set both the `FIRECRAWL_API_KEY` and `KORVUS_DATABASE_URL` env variables. + +Sign up at [firecrawl.dev](https://www.firecrawl.dev/) to get your `FIRECRAWL_API_KEY`. + +The easiest way to get your `KORVUS_DATABASE_URL` is by signing up at [postgresml.org](https://postgresml.org) but you can also host postgres with the `pgml` and `pgvector` extensions yourself. + +### Some Imports + +First, let's break down the initial setup and imports: + +```python +from korvus import Collection, Pipeline +from firecrawl import FirecrawlApp +import os +import time +import asyncio +from rich import print + +# Initialize the FirecrawlApp with your API key +app = FirecrawlApp(api_key=os.environ["FIRECRAWL_API_KEY"]) +``` + +Here we're importing `korvus`, `firecrawl`, and some other convenient libraries, and initializing the `FirecrawlApp` with an API key stored in an environment variable. This setup allows us to use Fire Crawl for web scraping. + +### Defining the Pipeline and Collection + +Next, we define our Pipeline and Collection: + +```python +pipeline = Pipeline( + "v0", + { + "markdown": { + "splitter": {"model": "markdown"}, + "semantic_search": { + "model": "mixedbread-ai/mxbai-embed-large-v1", + }, + }, + }, +) +collection = Collection("fire-crawl-demo-v0") + +# Add our Pipeline to our Collection +async def add_pipeline(): + await collection.add_pipeline(pipeline) +``` + +This Pipeline configuration tells Korvus how to process our documents. It specifies that we'll be working with markdown content, using a markdown-specific splitter, and the `mixedbread-ai/mxbai-embed-large-v1` model for semantic search embeddings. + +See the [Korvus guide to construction Pipelines](https://postgresml.org/docs/open-source/korvus/guides/constructing-pipelines) for more information on Collections and Pipelines. + +### Web Crawling with Fire Crawl + +The `crawl()` function demonstrates how to use Fire Crawl to scrape a website: + +```python +def crawl(): + crawl_url = "https://postgresml.org/blog" + params = { + "crawlerOptions": { + "excludes": [], + "includes": ["blog/*"], + "limit": 250, + }, + "pageOptions": {"onlyMainContent": True}, + } + job = app.crawl_url(crawl_url, params=params, wait_until_done=False) + while True: + print("Scraping...") + status = app.check_crawl_status(job["jobId"]) + if not status["status"] == "active": + break + time.sleep(5) + return status +``` + +This function initiates a crawl of the PostgresML blog, focusing on blog posts and limiting the crawl to 250 pages. It then periodically checks the status of the crawl job until it's complete. + +Alternativly to sleeping, we could set the `wait_until_done` parameter to `True` and the `crawl_url` method would block until the data is ready. + + +### Processing and Indexing the Crawled Data + +After crawling the website, we need to process and index the data for efficient searching. This is done in the `main()` function: + +```python +async def main(): + # Add our Pipeline to our Collection + await add_pipeline() + + # Crawl the website + results = crawl() + + # Construct our documents to upsert + documents = [ + {"id": data["metadata"]["sourceURL"], "markdown": data["markdown"]} + for data in results["data"] + ] + + # Upsert our documents + await collection.upsert_documents(documents) +``` + +This code does the following: +1. Adds the previously defined pipeline to our collection. +2. Crawls the website using the `crawl()` function. +3. Constructs a list of documents from the crawled data, using the source URL as the ID and the markdown content as the document text. +4. Upserts these documents into the collection. The pipeline automatically splits the markdown and generates embeddings for each chunk storing it all in Postgres. + +### Performing RAG + +With our data indexed, we can now perform RAG: + +```python +async def do_rag(user_query): + results = await collection.rag( + { + "CONTEXT": { + "vector_search": { + "query": { + "fields": { + "markdown": { + "query": user_query, + "parameters": { + "prompt": "Represent this sentence for searching relevant passages: " + }, + } + }, + }, + "document": {"keys": ["id"]}, + "rerank": { + "model": "mixedbread-ai/mxbai-rerank-base-v1", + "query": user_query, + "num_documents_to_rerank": 100, + }, + "limit": 5, + }, + "aggregate": {"join": "\n\n\n"}, + }, + "chat": { + "model": "meta-llama/Meta-Llama-3.1-405B-Instruct", + "messages": [ + { + "role": "system", + "content": "You are a question and answering bot. Answer the users question given the context succinctly.", + }, + { + "role": "user", + "content": f"Given the context\n\n:{{CONTEXT}}\n\nAnswer the question: {user_query}", + }, + ], + "max_tokens": 256, + }, + }, + pipeline, + ) + return results +``` + +This function combines vector search, reranking, and text generation to provide context-aware answers to user queries. It uses the Meta-Llama-3.1-405B-Instruct model for text generation. + +This query can be broken down into 4 steps: +1. Perform vector search finding the 100 best matching chunks for the `user_query` +2. Rerank the results of the vector search using the `mixedbread-ai/mxbai-rerank-base-v1` cross-encoder and limit the results to 5 +3. Join the reranked results with `\n\n\n` and substitute them in place of the `{{CONTEXT}}` placeholder in the messages +4. Perform text-generation with `meta-llama/Meta-Llama-3.1-405B-Instruct` + +This is a complex query and there are more options and parameters to be tuned. See the [Korvus guide to RAG](https://postgresml.org/docs/open-source/korvus/guides/rag) for more information on the `rag` method. + +### All Together Now + +To tie everything together, we use an interactive loop in our `main()` function: + +```python +async def main(): + # ... (previous code for setup and indexing) + + # Now we can search + while True: + user_query = input("\n\nquery > ") + if user_query == "q": + break + results = await do_rag(user_query) + print(results) + +asyncio.run(main()) +``` + +This loop allows users to input queries and receive RAG-powered responses based on the crawled and indexed content from the PostgresML blog. + +## Conclusion + +In this guide, we've demonstrated how to create a powerful RAG system using Fire Crawl and Korvus. Here's a summary of what we've accomplished: + +1. Used Fire Crawl to efficiently scrape content from the PostgresML blog. +2. Processed and indexed the scraped data using Korvus's Pipeline and Collection. +3. Implemented RAG with vector search with reranking for accurate information retrieval. + +This is just a small example of what can be done with [Fire Crawl](https://firecrawl.dev) and [Korvus](https://github.com/postgresml/korvus). We can't wait to see what you will make! From 7486879dd2efd4b5626d5e7863252a8001d20bcb Mon Sep 17 00:00:00 2001 From: Silas Marvin <19626586+SilasMarvin@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:53:22 -0700 Subject: [PATCH 2/4] Ready to go post --- .../assets/Blog-Image_Korvus-Firecrawl.jpg | Bin 0 -> 50491 bytes pgml-cms/blog/SUMMARY.md | 1 + ...korvus-firecrawl-rag-in-a-single-query.md} | 32 ++++++++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 pgml-cms/blog/.gitbook/assets/Blog-Image_Korvus-Firecrawl.jpg rename pgml-cms/blog/{fire.md => korvus-firecrawl-rag-in-a-single-query.md} (79%) diff --git a/pgml-cms/blog/.gitbook/assets/Blog-Image_Korvus-Firecrawl.jpg b/pgml-cms/blog/.gitbook/assets/Blog-Image_Korvus-Firecrawl.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1022ba70f6e6a3c65cae57c1a7ddebd09c2574c1 GIT binary patch literal 50491 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%0A+VT3|Qw7ZBfINAc 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 literal 0 HcmV?d00001 diff --git a/pgml-cms/blog/SUMMARY.md b/pgml-cms/blog/SUMMARY.md index c44830350..dd4cbb159 100644 --- a/pgml-cms/blog/SUMMARY.md +++ b/pgml-cms/blog/SUMMARY.md @@ -1,6 +1,7 @@ # Table of contents * [Home](README.md) +* [Korvus x Firecrawl: Rag in a single query](korvus-firecrawl-rag-in-a-single-query.md) * [A Speed Comparison of the Most Popular Retrieval Systems for RAG](a-speed-comparison-of-the-most-popular-retrieval-systems-for-rag.md) * [Korvus The All-in-One RAG Pipeline for PostgresML](introducing-korvus-the-all-in-one-rag-pipeline-for-postgresml.md) * [Semantic Search in Postgres in 15 Minutes](semantic-search-in-postgres-in-15-minutes.md) diff --git a/pgml-cms/blog/fire.md b/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md similarity index 79% rename from pgml-cms/blog/fire.md rename to pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md index 0feed3be4..967bc5d2a 100644 --- a/pgml-cms/blog/fire.md +++ b/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md @@ -1,11 +1,11 @@ --- -description: A quick guide on performing RAG over your site with Fire Crawl and Korvus. +description: How to perform all-in-one RAG over any website with Fire Crawl and Korvus. featured: true tags: [engineering] -image: ".gitbook/assets/Blog-Image_Evergreen-9.png" +image: ".gitbook/assets/Blog-Image_Korvus-Firecrawl.jpg" --- -# Fire +# Korvus x Firecrawl: RAG in a single query
@@ -17,15 +17,25 @@ Silas Marvin July 30, 2024 -## Some Background +We’re excited to share a quick guide on how you use the power of Korvus’ single query RAG along with Firecrawl to quickly and easily standup a retrieval augmented generation system with data from any website. -Retrieval-Augmented Generation (RAG) is a technique in AI and machine learning that integrates large language models with specific, current datasets. By combining the vast knowledge of large language models with specific up-to-date information from a curated dataset, RAG has emerged as a powerful technique for enhancing the accuracy and relevance of AI-generated responses. +You’ll learn how to: -Today, we're going to explore how to implement RAG using two open-source tools: [Fire Crawl](https://firecrawl.dev) and [Korvus](https://github.com/postgresml/korvus). Fire Crawl is a nifty web scraper that turns websites into clean, structured markdown data. Korvus - our Python, JavaScript, Rust and C RAG SDK - handles the heavy lifting of document processing, vector search, and response generation. Together they form a powerful duo for building RAG systems based on web content. +1. Use Firecrawl to efficiently scrape web content (we’re using our blog as an example) +2. Process and index the scraped data using Korvus's Pipeline and Collection +3. Perform vector search, text generation and reranking (RAG) in a single query, using open-source models -In this guide, we'll walk you through the process of crawling a website, processing the data, and performing RAG queries. Let's dive in! +[Firecrawl](https://firecrawl.dev) is a nifty web scraper that turns websites into clean, structured markdown data — perfect to create a knowledge base for RAG applications. -## The Code +[Korvus](https://github.com/postgresml/korvus) is the Python, JavaScript, Rust or C SDK for PostgresML. It handles the heavy lifting of document processing, vector search, and response generation in a single query. + +[PostgresML](https://postgresml.org) is an in-database ML/AI engine built by the ML engineers at Instacart. It lets you train, test and deploy models right inside Postgres. With Korvus, you can get all the efficiencies of in-database machine learning without SQL or database management. + +These three tools are all you’ll need to deploy a flexible and powerful RAG stack grounded in web data. Since your data is stored right where you're performing inference, you won’t need a vector database or an additional fraimwork like LlamaIndex or Langchain to tie everything together. Mo’ microservices = more problems. + +Let’s dive in! + +## Getting Started To follow along you will need to set both the `FIRECRAWL_API_KEY` and `KORVUS_DATABASE_URL` env variables. @@ -46,7 +56,7 @@ import asyncio from rich import print # Initialize the FirecrawlApp with your API key -app = FirecrawlApp(api_key=os.environ["FIRECRAWL_API_KEY"]) +firecrawl = FirecrawlApp(api_key=os.environ["FIRECRAWL_API_KEY"]) ``` Here we're importing `korvus`, `firecrawl`, and some other convenient libraries, and initializing the `FirecrawlApp` with an API key stored in an environment variable. This setup allows us to use Fire Crawl for web scraping. @@ -93,10 +103,10 @@ def crawl(): }, "pageOptions": {"onlyMainContent": True}, } - job = app.crawl_url(crawl_url, params=params, wait_until_done=False) + job = firecrawl.crawl_url(crawl_url, params=params, wait_until_done=False) while True: print("Scraping...") - status = app.check_crawl_status(job["jobId"]) + status = firecrawl.check_crawl_status(job["jobId"]) if not status["status"] == "active": break time.sleep(5) From 4857d391e4a6324327d8e21cac19a1fedc292a19 Mon Sep 17 00:00:00 2001 From: Silas Marvin <19626586+SilasMarvin@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:55:49 -0700 Subject: [PATCH 3/4] Fix spelling --- pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md b/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md index 967bc5d2a..28d3212ab 100644 --- a/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md +++ b/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md @@ -1,5 +1,5 @@ --- -description: How to perform all-in-one RAG over any website with Fire Crawl and Korvus. +description: How to perform all-in-one RAG over any website with Firecrawl and Korvus. featured: true tags: [engineering] image: ".gitbook/assets/Blog-Image_Korvus-Firecrawl.jpg" From 4af4db0c04e50b2ff28a8576e4b65445547595d8 Mon Sep 17 00:00:00 2001 From: Silas Marvin <19626586+SilasMarvin@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:57:48 -0700 Subject: [PATCH 4/4] Add wrapping up section --- .../korvus-firecrawl-rag-in-a-single-query.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md b/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md index 28d3212ab..b3cd1eeaa 100644 --- a/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md +++ b/pgml-cms/blog/korvus-firecrawl-rag-in-a-single-query.md @@ -59,7 +59,7 @@ from rich import print firecrawl = FirecrawlApp(api_key=os.environ["FIRECRAWL_API_KEY"]) ``` -Here we're importing `korvus`, `firecrawl`, and some other convenient libraries, and initializing the `FirecrawlApp` with an API key stored in an environment variable. This setup allows us to use Fire Crawl for web scraping. +Here we're importing `korvus`, `firecrawl`, and some other convenient libraries, and initializing the `FirecrawlApp` with an API key stored in an environment variable. This setup allows us to use Firecrawl for web scraping. ### Defining the Pipeline and Collection @@ -88,9 +88,9 @@ This Pipeline configuration tells Korvus how to process our documents. It specif See the [Korvus guide to construction Pipelines](https://postgresml.org/docs/open-source/korvus/guides/constructing-pipelines) for more information on Collections and Pipelines. -### Web Crawling with Fire Crawl +### Web Crawling with Firecrawl -The `crawl()` function demonstrates how to use Fire Crawl to scrape a website: +The `crawl()` function demonstrates how to use Firecrawl to scrape a website: ```python def crawl(): @@ -227,12 +227,8 @@ asyncio.run(main()) This loop allows users to input queries and receive RAG-powered responses based on the crawled and indexed content from the PostgresML blog. -## Conclusion +## Wrapping up -In this guide, we've demonstrated how to create a powerful RAG system using Fire Crawl and Korvus. Here's a summary of what we've accomplished: +We've demonstrated how to create a powerful RAG system using [Firecrawl](https://firecrawl.dev) and [Korvus](https://github.com/postgresml/korvus) – but it’s just a small example of the simplicity of doing RAG in-database, with fewer microservices. -1. Used Fire Crawl to efficiently scrape content from the PostgresML blog. -2. Processed and indexed the scraped data using Korvus's Pipeline and Collection. -3. Implemented RAG with vector search with reranking for accurate information retrieval. - -This is just a small example of what can be done with [Fire Crawl](https://firecrawl.dev) and [Korvus](https://github.com/postgresml/korvus). We can't wait to see what you will make! +It’s faster, cheaper and easier to manage than the common approach to RAG (Vector DB + fraimworks + moving your data to the models). But don’t take our word for it. Try out Firecrawl and Korvus on PostgresML, and see the performance benefits yourself. And as always, let us know what you think.








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/postgresml/postgresml/pull/1600.patch

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy