Retrieval-augmented generation over list data with pgvector or Azure AI Search

Retrieval-augmented generation over SharePoint lists, with SPSync writing the embeddings into pgvector or Azure AI Search on every sync.

Book a call

Book a call to talk through your use case, see further walkthroughs or demos, and set up a trial in your own environment.

Last updated

We want to build RAG over our SharePoint lists, but there is no clean, typed, up-to-date source to build embeddings from.

A retrieval pipeline is only as current as the text it embeds. An HR assistant that answers questions from policy summaries and guidance notes kept in SharePoint lists will quote last month’s wording if the embedding job that feeds it reads the whole list through Graph each night, resolves lookups and guesses at deletes in its own code, and then fails or runs late.

Let the sync write the embeddings

SPSync replicates the lists into pgvector or Azure AI Search and generates embeddings for the text columns you configure on every sync. The RAG pipeline queries that table or index for retrieval, and there is no separate embedding job to write, run or keep in step with the source. Delta sync already knows what changed, so only changed rows are re-embedded, and the cost follows the volume of edits.

Postgres with pgvectorAzure AI Search
ShapeA vector column on the same table as the relational columns, with lookups as key columns, multi-value columns as child tables and a stable primary key per itemOne index per list, each document carrying the row’s fields and a vector field, plus a child index per multi-value column
RetrievalOne SQL query can filter on a relational column and order by vector distanceOne request can combine keyword and vector search
When an item is deletedThe row and its vector stay, with sp_deleted_at setThe document is removed from the index on the next sync

Elasticsearch and OpenSearch replicate the same lists into a keyword search index, with no embedding field.

Wiring it into the pipeline

Pick the site and the lists to retrieve over, then the destination. Choose which text columns to embed and which embedding model to use, and set a schedule that matches how often the source changes. Point the RAG pipeline or agent framework at the same database or index. SharePoint to pgvector and SharePoint to Azure AI Search cover the setup and schema for each.

Further reading

The article on keeping a SharePoint vector index current shows how embeddings go out of date, and how re-embedding only changed rows keeps an HR policies assistant current.

The article on Graph throttling and AI pipelines explains why ingestion jobs and agent tools get 429 responses from SharePoint, and how reading once into a replica takes Graph out of query time.

The article on SharePoint lists in Foundry IQ after On Your Data retired moves an Azure OpenAI On Your Data app over a list onto Foundry IQ, with the index SPSync feeds kept in place.

Desktop, Azure or command line

All three editions run the same engine, write the same tables and use the same licence key, so the choice comes down to who looks after the sync.

Desktop app

For macOS and Windows. Sign in with Microsoft, tick the lists, choose a database and sync from your own machine on the schedule you set. Delegated sign-in needs no admin unless your tenant requires admin consent for apps.

In your Azure

SPSync in your Azure, a managed application for your own subscription, is deployed with you on a call while the Marketplace listing is prepared. Once deployed it is always on, so the sync keeps running with every laptop closed.

Command line

Every replication is a YAML file you can review and commit. Run it from a server, a container or a CI pipeline, and re-run it safely any time.

Set it up

Ready to run this against your own site? The setup guide takes you from install to a first replication, and the SharePoint connection guide covers signing in.

Script it

Everything you can click, you can script. The CLI, YAML config and automation below reproduce this scenario exactly. See the CLI reference.

spsync auth login --client-id 00000000-0000-0000-0000-000000000000
spsync export-config --output replication.yaml --pipeline-name rag_on_sharepoint_lists --prefix rag_on_sharepoint_lists --destination-kind postgres --connection-string-env SPSYNC_DB_CONNECTION --dataset-name rag_on_sharepoint_lists --client-id 00000000-0000-0000-0000-000000000000 --site-url https://contoso.sharepoint.com/sites/example --all-lists
spsync doctor replication.yaml
spsync run replication.yaml
pipeline_name: rag_on_sharepoint_lists
prefix: rag_on_sharepoint_lists
auth:
  mode: delegated
  client_id: 00000000-0000-0000-0000-000000000000
  tenant_id: common
destination:
  kind: postgres
  connection_string_env: SPSYNC_DB_CONNECTION
  dataset_name: rag_on_sharepoint_lists
scopes:
  - site_url: https://contoso.sharepoint.com/sites/example
    mode: entire_site
reconcile_interval_days: 7
create_reporting_views: false

Cron (PostgreSQL nightly):

# every night at 02:00
0 2 * * * cd /opt/spsync && SPSYNC_DB_CONNECTION="$(cat /etc/spsync/db.env)" uv run spsync run replication.yaml >> /var/log/spsync/run.log 2>&1

GitHub Actions:

# .github/workflows/spsync-run.yml
name: SPSync
on:
  schedule:
    - cron: "0 2 * * *"
  workflow_dispatch: {}
jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v3
      - run: uv sync
      - run: uv run spsync run replication.yaml
        env:
          SPSYNC_DB_CONNECTION: ${{ secrets.SPSYNC_DB_CONNECTION }}
          SPSYNC_LICENCE_KEY: ${{ secrets.SPSYNC_LICENCE_KEY }}

Azure DevOps:

# azure-pipelines.yml
schedules:
  - cron: "0 2 * * *"
    branches: { include: [main] }
    always: true
steps:
  - script: uv sync
  - script: uv run spsync run replication.yaml
    env:
      SPSYNC_DB_CONNECTION: $(SPSYNC_DB_CONNECTION)
      SPSYNC_LICENCE_KEY: $(SPSYNC_LICENCE_KEY)

Windows (PowerShell + Task Scheduler):

# Windows Task Scheduler action (see /docs/cli/automation/)
$env:SPSYNC_DB_CONNECTION = (Get-Content C:\spsync\db.env)
uv run spsync run C:\spsync\replication.yaml
schtasks /Create /SC DAILY /ST 02:00 /TN "SPSync" /TR "powershell -File C:\spsync\run.ps1"

macOS (launchd):

# ~/Library/LaunchAgents/io.spsync.run.plist, then: launchctl load ~/Library/LaunchAgents/io.spsync.run.plist

Secrets (licence key, connection strings) come from the environment, so never write them into the YAML. See scheduling and secrets.

Related reading: Search index design guide, with links to the articles and docs that cover it.

Book a call

Book a call to talk through your use case, see further walkthroughs or demos, and set up a trial in your own environment.