Skip to content

Mann10/postgres-skill-agent

Repository files navigation

Agentic SQL Search with PostgreSQL Skill

A proof-of-concept demonstrating an agentic search pattern where an LLM agent uses on-demand skills to write correct PostgreSQL queries. The agent loads a PostgreSQL SQL skill before generating queries, ensuring proper syntax (e.g., ILIKE, ::cast, single quotes for strings).


Architecture

The agent follows a progressive skill-disclosure pattern: it knows skills exist, loads them when needed, executes queries, and formats results as natural language.

Request Flow

sequenceDiagram
    autonumber
    participant U as User
    participant A as Agent (LLM)
    participant S as Skill Registry
    participant T as execute_sql_query Tool
    participant DB as PostgreSQL

    Note over A: System prompt lists available skills:<br/>- postgresql-sql

    U->>A: "What is name of the session which Alice Johnson is about to give and what is her last signup_date?"

    A->>A: Decides SQL context is needed
    A->>S: load_skill("postgresql-sql")
    S-->>A: Returns skill content:<br/>- Use ILIKE for case-insensitive match<br/>- Use single quotes for strings<br/>- Use ::type for casting

    Note over A: Skill content is appended<br/>to the context window

    A->>A: Generates query with JOIN

    A->>T: execute_sql_query(query)
    T->>DB: Runs query
    DB-->>T: Result set
    T-->>A: Markdown table results

    A->>A: Synthesizes answer from results
    A-->>U: "Alice Johnson is about to give a session titled 'Agentic Search Patterns', and her last signup date is January 15, 2026."
Loading

Simplified Flowchart

flowchart TD
    A[User asks a question] --> B{Does this need<br/>a SQL query?}
    B -->|No| C[Answer directly]
    B -->|Yes| D[Call load_skill<br/>postgresql-sql]

    D --> E[Skill injected into<br/>agent context]
    E --> F[Agent writes<br/>PostgreSQL-specific query<br/>e.g. ILIKE, ::cast, LIMIT]
    F --> G[Call execute_sql_query]
    G --> H{Query valid?}
    H -->|Yes| I[Return results to user]
    H -->|No / Error| J[Use skill to rewrite query]
    J --> F

    C --> K[Done]
    I --> K
Loading

Prerequisites

  • Docker (for PostgreSQL container)
  • Python 3.10+
  • Ollama (for local LLM inference)
  • A model capable of tool use (tested with ministral-3:latest)

Setup

1. Start PostgreSQL with Docker

docker compose up -d

Verify the database is seeded:

docker exec -it pg-agent-poc psql -U agent -d conference -c "SELECT * FROM users;"

2. Install Python Dependencies

pip install -r requirements.txt

3. Configure Ollama

Pull the model (tested with ministral-3:latest):

ollama pull ministral-3:latest

Ensure Ollama is running:

ollama serve

4. Configure Environment

Create a .env file:

# Ollama / LiteLLM configuration
LITELLM_API_KEY=ollama
LITELLM_API_BASE=http://localhost:11434/v1

# PostgreSQL (matches docker-compose.yml)
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=conference
POSTGRES_USER=agent
POSTGRES_PASSWORD=agentpass

Note: When using Ollama, the API key can be any string (e.g., ollama). The base URL points to Ollama's OpenAI-compatible endpoint.


File Structure

.
├── .env                      # Environment variables
├── docker-compose.yml        # PostgreSQL container setup
├── init.sql                  # Database schema and dummy data
├── skills.py                 # Module 1: Skill definitions
├── db_tool.py                # Module 3: SQL execution tool
└── agent.py                  # Module 4: Agent wiring and middleware

Running the Agent

python agent.py

The agent will:

  1. Receive your question
  2. Load the postgresql-sql skill on demand
  3. Generate a correct PostgreSQL query
  4. Execute it against the database
  5. Summarize the results in natural language

Example Trace

Below is a real trace using Ollama with ministral-3:latest:

User:

What is name of the session which Alice Johnson is about to give and what is her last signup_date?

Agent (Turn 1 - Load Skill):

Tool Calls:

  • load_skill(skill_name="postgresql-sql")

Tool Result:

Loaded skill: postgresql-sql

PostgreSQL SQL Skill

Critical Syntax Rules

  • Use single quotes for string literals
  • PostgreSQL uses ILIKE for case-insensitive matching
  • Use :: operator for casting ...

Agent (Turn 2 - Execute Query):

Tool Calls:

  • execute_sql_query(sql_query="SELECT s.title AS session_title, u.signup_date AS last_signup_date FROM users u JOIN sessions s ON u.name = s.speaker_name WHERE u.name = 'Alice Johnson' ORDER BY u.signup_date DESC LIMIT 1;")

Tool Result:

session_title last_signup_date
Agentic Search Patterns 2026-01-15

Agent (Final Answer):

Alice Johnson is about to give a session titled "Agentic Search Patterns", and her last signup date is January 15, 2026.


How It Works

Progressive Skill Disclosure

The agent uses a three-layer context strategy:

Layer Content When It Appears
Layer 1 System prompt + skill descriptions Every request
Layer 2 Full skill content (e.g., PostgreSQL rules) Only after load_skill is called
Layer 3 Conversation history (questions, tool calls, results) Grows with each turn

This keeps the context window small for non-SQL questions while ensuring the agent has detailed syntax rules when it needs them.

Safety Guard

The execute_sql_query tool rejects any query that does not start with SELECT, preventing accidental data mutation.

Natural Language Output

The tool description instructs the LLM to summarize results in natural language rather than outputting raw markdown tables:

"When you receive results, summarize them in natural language. Do not simply output the raw table."


Customization

Adding More Skills

Edit skills.py and append to the SKILLS list:

{
    "name": "mysql-sql",
    "description": "Write MySQL-compatible SQL queries...",
    "content": "# MySQL SQL Skill\n..."
}

The SkillMiddleware will automatically make it discoverable without code changes.

Switching LLM Models

Update the model name in agent.py:

llm = ChatOpenAI(
    openai_api_base=os.getenv("LITELLM_API_BASE"),
    api_key=os.getenv("LITELLM_API_KEY"),
    model="ministral-3:latest",  # or any Ollama / OpenAI model
    temperature=0.2,
)

Teardown

Stop the PostgreSQL container:

docker compose down

To remove the database volume as well:

docker compose down -v

Notes

  • Ollama Compatibility: This POC was tested successfully with ministral-3:latest via Ollama's OpenAI-compatible API. Tool use support may vary across models.
  • Context Persistence: Conversation history is held in memory only. If you need persistence across script runs, add a LangChain checkpointer.
  • Read-Only: The SQL tool is restricted to SELECT statements for safety.

About

An AI agent framework that leverages PostgreSQL as a persistent skill store for tool execution, memory, and agent orchestration.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages