Category Archives: Uncategorized

Local RAG with .NET, PostgreSQL, and Ollama: Code Setup (Part 3)

In Part 1 and Part 2, we set up our infrastructure: a PostgreSQL database with pgvector for storing embeddings, and Ollama running the Phi4 model locally. Now we’ll create a .NET application to bring these components together into a working RAG system. We’ll start by setting up our solution structure with proper test projects.

If you’re just joining, you’ll need to follow the steps in Parts 1 and 2 first to get PostgreSQL and Ollama running in Docker.

Let’s start by creating the .NET solution and projects from the command line (we could do this through Visual Studio’s UI, but I prefer keeping my command-line-fu strong).

Creating a new .NET project

Open PowerShell as an administrator. Browse to a directory where you’d like to create your solution – I keep mine in my Git repositories folder. Then run these commands:

First, create the solution

dotnet new sln -n LocalRagConsoleDemo

You might see a prompt about the dev certificate – if so, run:

dotnet dev-certs https --trust

Now create our three projects: the main console app and two test projects

dotnet new console -n LocalRagConsoleDemo
dotnet new nunit -n LocalRagConsoleUnitTests
dotnet new nunit -n LocalRagConsoleIntegrationTests

Finally, add everything to the solution, organizing tests in their own folder

dotnet sln LocalRagConsoleDemo.sln add LocalRagConsoleDemo/LocalRagConsoleDemo.csproj

dotnet sln LocalRagConsoleDemo.sln add LocalRagConsoleUnitTests/LocalRagConsoleUnitTests.csproj --solution-folder "Unit Tests"

dotnet sln LocalRagConsoleDemo.sln add LocalRagConsoleIntegrationTests/LocalRagConsoleIntegrationTests.csproj --solution-folder "Unit Tests"

Now we have a solution set up with proper separation of concerns – a main console project for our RAG application and separate projects for unit and integration tests. In the next section, we’ll add the required NuGet packages and start building our connection to PostgreSQL.

You can verify everything is set up correctly by opening LocalRagConsoleDemo.sln in Visual Studio or your preferred IDE. You should see:

Two test projects organized in a “Unit Tests” solution folder and a main console project.

Adding Dependencies

Navigate to the LocalRagConsoleDemo project folder and add our initial NuGet packages:

dotnet add package Microsoft.Extensions.Http
dotnet add package Newtonsoft.Json

At this point, you should have a working solution structure:

  • A main console project
  • Two test projects in a “Unit Tests” solution folder
  • Basic HTTP and JSON handling capabilities

You can verify the setup by opening LocalRagConsoleDemo.sln in Visual Studio or your preferred IDE.

What’s Next?
I’ll be back soon with a detailed walkthrough of building the RAG application. In the meantime, you can check out the working code at:

https://github.com/jimsowers/LocalRAGConsoleDemo

Happy Coding!
-Jim

Local RAG with .NET, Postgres, and Ollama: Ollama Setup (Part 2)

In Part 1, we set up a PostgreSQL database with pgvector extension in a Docker container (that’s a mouthful of tech terms – sorry!).

Our goal is to build a local RAG (Retrieval-Augmented Generation) application combining Postgres for vector storage with a local AI model. Now, we’ll use Docker to run Ollama, an open-source tool that lets us run AI models locally on our machine.

Step 1: Pulling the Ollama Docker container

You can pull the ollama image in a powershell prompt from docker hub with this command:


 docker pull ollama/ollama

Or, you can use the search bar in docker desktop :

We already should have Docker running with Postgres with pgvector and now we will start the Ollama container also.

Step 2: Starting the Ollama container

Before you start Ollama, you should read the Docker Hub docs about starting it correctly for your video card / computer settings https://hub.docker.com/r/ollama/ollama. You click run on the container in Docker desktop, but if you use the proper startup settings for the GPU you have, it may run much much better.

For instance, I have used this startup from a command line:

docker run --name ollamaLocal --hostname=ollamaLocal --env=CUDA_VISIBLE_DEVICES=0 --env=GPU_MEMORY_UTILIZATION=90 --env=GPU_LAYERS=35 --env=NVIDIA_DRIVER_CAPABILITIES=compute,utility --env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin --env=OLLAMA_HOST=0.0.0.0 --env=LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64 --env=NVIDIA_VISIBLE_DEVICES=all --volume=ollama:/root/.ollama --network=bridge -p 11434:11434 --restart=no --label='org.opencontainers.image.ref.name=ubuntu' --label='org.opencontainers.image.version=22.04' --runtime=runc -d sha256:f1fd985cee59a6403508e3ba26367744eafad7b7383ba960d80872aae61661b6

Check that Docker is running with this command:

docker ps

That should return something like this:

showing both Ollama and Postgres with pgvector are running.

To see if you already have models installed, you can execute the following command in PowerShell (please note that I did not include the full container ID—only enough characters to uniquely identify it: ‘5d5’—and typically, three characters are enough):

docker exec -it ollamaLocal ollama list

In this container, I already have phi4, deepseek-r1, and llama3.

For this project , I want to use Phi4 from Microsoft to start.

We will use the docker exec command to open an interactive terminal:

docker exec -it ollamaLocal /bin/sh

Then the pull command in the docker terminal:

ollama pull phi4

Step 3: Check that Phi4 is running in Ollama:

Staying in the interactive terminal (at the # prompt) – run this command:

ollama run phi4 "Tell me a joke about a duck and a pencil"

You should get a response from the phi4 model something like this:

To get out of the interactive terminal, type exit of Ctrl+D.

There you go – if all that went well, you have the phi4 language model running locally! Let’s review what we’ve accomplished:

  • Postgres with pgvector is running in a Docker container
  • Ollama is running with GPU optimization
  • Microsoft’s Phi4 model is ready to use

In the next articles, we’ll build a .NET application that ties these pieces together. We’ll cover generating embeddings from our documents, storing them in pgvector, and using Phi4 to answer questions based on our stored knowledge.

If you need to stop the containers, you can use docker stop with your container IDs, or use Docker Desktop to stop them.

NHibernate ‘IN’ clause with linq

NHibernate was giving me fits, not letting me use ‘.In’ in the linq statements.

Here is how I got it to go:

 IQueryable<int?> idsForOrgList = _repo.Get<OrganizationThingyXref>().Where(thingy => thingy.OrganizationID == orgId && thingy.IdICareAbout != null).Select(_=>_.IdICareAbout);
           
List<People> ThingysInOrg = _repo.Get<Thingy>().Where(_ => idsForOrgList.Contains(_.IdICareAbout)).ToList();

Selenium test .net webforms with data-attributes

I was struggling to E2E Selenium test a repeater, in a user control, in an old .net webforms page – tall ask right?

Here is the solution I came up with:

I added a custom attribute (“data-serviceid”) to the element the repeater is drawing – inside the code behind of the user control (a link button in this case):

var lbNewReport = (LinkButton)args.Item.FindControl("lbNewReport");
lbNewReport.Attributes.Add("data-serviceid", myServiceId);

Then I used this static helper method for selenium:

public static By SelectorByAttributeValue(string attributeName, string attributeValue)
{
return (By.XPath($"//*[@{attributeName} = '{attributeValue}']"));
}

With This call:

var linkIWant = _driver.FindElement(SelectorByAttributeValue("data-serviceid", myServiceId));

And voila – I have the control in hand that I want to interact with(clicking in this case for me).

Idempotent (run twice safe) sql statements

if (select count(*) from neatoSchema.YourTable where SomeColumnYouCanCheckDataOn = 2018)> 0
begin
print 'That row is already inserted'
end
else
begin
INSERT into neatoSchema.[ConferenceDate]
(... your data ...)
end

You can also interrogate information_schema.tables or information_schema.columns if you are doing a change to a table to ensure that doesn’t run twice!

Refactoring – or Code Remodeling

I think that most days, code remodeler would be the right job title for a lot of us. We take working code and just make it better working code.

The book that got me started thinking of myself as a ‘code remodeler’ is Refactoring: Improving the Design of Existing Code by Martin Fowler.

If you haven’t read it, go get it quick! (Of course, and then read it…) Fowler lays out refactoring techniques in a straightforward way. You can start applying it immediately. I use Replace magic number with symbolic constant and Extract Method almost every day when I am helping a team with an older codebase.

Thanks for stopping by, and happy coding,

-Jim

Javascript get sending element in all browsers

   function mySweetClickEvent(event) {

        event = window.event || event; //NOTE: another lovely hack to make Firefox work…

        var target = event.target ? event.target : event.srcElement; //NOTE: another lovely hack to make IE work

        var senderToUse;

        if (target) {

            senderToUse = target; //this works for ie and chrome

        } else {

            senderToUse = event; //this works for firefox

        }

…do stuff with the sender here…

}