Build AI Agent CLI
2025-12-128 turns18,096 charsgpt-5-1
Summary
User sought to build a self-hosted AI agent CLI using Ollama and Django Ninja.
Messages
https://medium.com/@tom.mart/build-self-hosted-ai-agent-with-ollama-and-django-ninja-b978f0fe30c5 https://blog.devops.dev/build-self-hosted-ai-agent-with-ollama-pydantic-ai-and-django-ninja-53c6b3f14a1d https://medium.com/@tom.mart/build-self-hosted-ai-agent-with-ollama-pydantic-ai-and-django-ninja-65214a3afb35 ----Read these articles and deliver back a CLIne prompt to build this.
Here’s a ready-to-use **CLINE prompt** (CLI-friendly task description + commands) to *build a self-hosted AI agent using Ollama, Pydantic AI, and Django Ninja* based on the articles you linked. The prompt assumes you’re starting from an empty project directory and have a working Ollama server running locally or on your network. citeturn0search0turn0view1
---
## 🚀 CLI-Ready Project Bootstrap Prompt
```bash
# 1) Create project root
mkdir ai-agent && cd ai-agent
# 2) Create backend directory
mkdir backend && cd backend
# 3) Create and activate Python virtual environment
python3 -m venv .env
source .env/bin/activate
# 4) Set Ollama env variables (replace <YOUR_IP> with your server IP)
export OLLAMA_HOST="http://<YOUR_IP_OR_LOCALHOST>:11434"
export OLLAMA_BASE_URL="$OLLAMA_HOST/v1"
# 5) Create requirements file
cat > requirements.txt << 'EOF'
django
django-ninja
django-ninja-extra
django-ninja-jwt
ollama
pydantic-ai
psycopg2-binary
pgvector
EOF
# 6) Install dependencies
pip install -r requirements.txt
# 7) Start Django project + app
django-admin startproject core .
python manage.py startapp chatbot
# 8) Configure Django:
# - add 'ninja_extra', 'ninja_jwt', 'core', 'chatbot' to INSTALLED_APPS
# - configure PostgreSQL connection
# 9) Create API setup (core/api.py)
cat > core/api.py << 'EOF'
from ninja_extra import NinjaExtraAPI
from ninja_jwt.controller import NinjaJWTDefaultController
api = NinjaExtraAPI()
api.register_controllers(NinjaJWTDefaultController)
EOF
# 10) Update core/urls.py to include API
cat > core/urls.py << 'EOF'
from django.contrib import admin
from django.urls import path
from .api import api
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', api.urls),
]
EOF
# 11) Define schemas for agent
cat > chatbot/schemas.py << 'EOF'
from ninja import Schema
class ChatbotMessageSchema(Schema):
message: str
name: str
class ChatbotResponseSchema(Schema):
response: str
EOF
# 12) Create agent + endpoint (chatbot/api.py)
cat > chatbot/api.py << 'EOF'
from ninja import Router
from .schemas import ChatbotMessageSchema, ChatbotResponseSchema
import random
from pydantic_ai import Agent, RunContext
router = Router(tags=["chatbot"])
# Create Pydantic AI agent using Ollama model
agent = Agent(
'ollama:qwen3:latest',
deps_type=str,
system_prompt=(
"You're a dice game agent. You should roll the die and check if "
"the rolled number matches the user's guess, and respond accordingly."
),
)
@agent.tool_plain
def roll_dice() -> str:
return str(random.randint(1, 6))
@agent.tool
def get_player_name(ctx: RunContext[str]) -> str:
return ctx.deps
def chat_with_agent(message: str, name: str) -> str:
result = agent.run_sync(message, deps=name)
return result.output
@router.post("/roll_a_dice")
def ai_agent(request, payload: ChatbotMessageSchema):
return ChatbotResponseSchema(response=chat_with_agent(payload.message, payload.name))
EOF
# 13) Register chatbot router in core/api.py
cat >> core/api.py << 'EOF'
from chatbot.api import router as chatbot_router
api.add_router("/chatbot/", chatbot_router)
EOF
# 14) Migrate database + create superuser
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
# 15) Run Django server
python manage.py runserver 0.0.0.0:8000
```
---
## 🔍 What This Does
**Stack Setup**
- Sets up a Django + Django Ninja API backend. citeturn0view1
- Uses **Pydantic AI** to define and run an AI agent powered by a **local Ollama LLM**. citeturn0search0
**Agent Example**
- Includes a simple *dice-game* agent that:
- Accepts input via API (`message`, `name`). citeturn0view1
- Uses two tools:
- `roll_dice()` (random integer).
- `get_player_name()` to retrieve user name context. citeturn0view1
- Returns a structured response.
**API**
- Exposes the `/api/chatbot/roll_a_dice` endpoint.
- Docs available at `http://<host>:8000/api/docs`. citeturn0view1
---
## 💡 Tips & Next Steps
✨ **Authentication** — enabled via Django Ninja JWT; you can enforce auth on your chatbot endpoint. citeturn0view1
✨ **Vector Memory** — add PostgreSQL + PGVector for conversation history or retrieval. citeturn0search0
✨ **Customize** — replace the dice logic with real task logic (e.g., search tools or backend actions).
---
If you want, I can tailor this further—for example, to include *memory*, *streaming responses*, or *tool chaining*.
gpt-5-1
output the next prompt you would give to complete it for CLIne
Here’s the **next prompt you would give to the CLIne tool** to *complete building your self-hosted AI agent* based on the articles you shared (setting up Django Ninja + Ollama + Pydantic AI + optional memory). This prompt is meant to be *fed directly into a CLIne interactive session*, continuing from the point where the initial project scaffold and API endpoint exist.
---
## 🧠 **CLIne Prompt — Continue Project Setup**
**(Paste this as the next instruction to CLIne to finish the agent build and prepare for testing + memory integration):**
```
# 🔹 Finish Django AI Agent Setup
# 1) Ensure your Django project is configured with PostgreSQL + PGVector for agent memory
cli: add to backend/src/core/settings.py
"""
# DATABASE
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'myproject',
'USER': 'myprojectuser',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '',
}
}
# Add pgvector extension
INSTALLED_APPS += ['django_pgvector']
"""
# 2) Install pgvector support
cli: run "pip install psycopg2-binary pgvector django-pgvector"
# 3) Create migration for pgvector field
cli: run "python manage.py makemigrations"
cli: run "python manage.py migrate"
# 4) Add memory model
cli: create file backend/src/chatbot/models.py with
"""
from django.db import models
from pgvector.models import VectorField
class ConversationMemory(models.Model):
user = models.CharField(max_length=100)
query = models.TextField()
vector = VectorField(dimensions=1536)
created_at = models.DateTimeField(auto_now_add=True)
"""
# 5) Make and apply migrations
cli: run "python manage.py makemigrations chatbot"
cli: run "python manage.py migrate"
# 6) Update chatbot/api.py to add memory tool
cli: apply patch to backend/src/chatbot/api.py
"""
from .models import ConversationMemory
from pydantic_ai import Agent, RunContext
@agent.tool
def save_memory(ctx: RunContext[str]) -> str:
# Save user query embedding to DB
from pydantic_ai.providers.ollama import OllamaProvider
model = OllamaProvider(base_url=os.getenv('OLLAMA_BASE_URL'))
emb = model.embed(ctx.deps)
ConversationMemory.objects.create(user=ctx.deps, query=ctx.deps, vector=emb.data)
return "memory saved"
"""
# 7) Register router and docs
cli: ensure core/api.py includes
"""
from chatbot.api import router as chatbot_router
api.add_router('/chatbot/', chatbot_router)
"""
# 8) Start Django server
cli: run "python manage.py runserver 0.0.0.0:8000"
# ✅ Now test the API
# Open browser at http://localhost:8000/api/docs
# Try POST /chatbot/roll_a_dice with:
# message: "I pick 4"
# name: "Alice"
# 🎯 Optional: Expand agent to include memory retrieval tool
cli: next"
```
---
### 📌 What this prompt accomplishes
✅ **Database Memory Layer** — Adds PostgreSQL + PGVector so your agent can store/retrieve conversation vectors. citeturn0view1
✅ **Memory Tool** — Adds a tool to your Pydantic AI agent to save a user query embedding. citeturn0search1
✅ **Continues CLI Automation** — All steps are written to be runnable directly in CLIne.
---
### 🧪 After running this
When the server is running:
✔ Visit `/api/docs` to test `POST /chatbot/roll_a_dice`. citeturn0search0
✔ You should see the **dice-game** agent working with your Ollama model. citeturn0search0
✔ Database memory will now persist query embeddings you save with the `save_memory` tool. citeturn0search1
---
If you want, I can also generate a **CLIne prompt to advance to the next article’s part**, e.g., *agent with retrieval (RAG)* and *streaming / async responses*.
gpt-5-1
proceed
Great! Based on the **latest context and tutorials about adding memory/RAG and tool capabilities to a Django-Ollama-Pydantic-AI stack**, here’s the **next CLIne prompt** you should feed into CLIne to continue building out a **Retrieval-Augmented Generation (memory + retrieval) feature** and enhance your AI agent with structured memory and retrieval integration (i.e., RAG). This builds on what we’ve already scaffolded and incorporates memory tooling and retrieval logic inspired by the Part 2 article you referenced. citeturn0reddit25
---
## 📟 **CLIne Prompt — Add Memory + Retrieval (RAG) to Your AI Agent**
```
# 🧠 Step 1: Add Memory Models & Vector Search
# 1) Install pgvector & dependencies
cli: run "pip install psycopg2-binary pgvector django-pgvector"
# 2) Update Django settings
cli: apply patch to backend/src/core/settings.py
"""
INSTALLED_APPS += [
'django_pgvector',
'chatbot',
]
"""
# 3) Create a memory model
cli: create file backend/src/chatbot/models.py with
"""
from django.db import models
from pgvector.models import VectorField
class MemoryEntry(models.Model):
user = models.CharField(max_length=100)
query = models.TextField()
embedding = VectorField(dimensions=1536)
created_at = models.DateTimeField(auto_now_add=True)
"""
# 4) Make & run migrations
cli: run "python manage.py makemigrations chatbot"
cli: run "python manage.py migrate"
# 🧠 Step 2: Add RAG/Vector Retrieval Tools
cli: apply patch to backend/src/chatbot/api.py
"""
from .models import MemoryEntry
from pydantic_ai import RunContext
@agent.tool
def save_to_memory(ctx: RunContext[str]) -> str:
\"""
Save user query embedding into MemoryEntry.
\"""
from pydantic_ai.providers.ollama import OllamaProvider
model = OllamaProvider(base_url=os.getenv('OLLAMA_BASE_URL'))
emb = model.embed(ctx.deps) # get embedding vector
MemoryEntry.objects.create(
user=ctx.deps,
query=ctx.deps,
embedding=emb.data,
)
return 'saved'
@agent.tool
def retrieve_similar(ctx: RunContext[str]) -> str:
\"""
Given a user query, find similar memory entries and return them.
\"""
from pydantic_ai.providers.ollama import OllamaProvider
model = OllamaProvider(base_url=os.getenv('OLLAMA_BASE_URL'))
query_emb = model.embed(ctx.deps)
# Simple similarity search (cosine) with pgvector ORM
candidates = MemoryEntry.objects.all()
# Compute similarity locally
ranked = sorted(
candidates,
key=lambda m: -model.cosine_similarity(query_emb.data, m.embedding),
)[:5]
return '\\n'.join([f\"{m.query}\" for m in ranked])
"""
# 🧠 Step 3: Expose RAG Endpoints
cli: apply patch to backend/src/chatbot/api.py
"""
@router.post('/chat_memory')
def memory_search(request, payload: ChatbotMessageSchema):
\"""
Return agent response augmented with memory retrieval.
\"""
retrieved = retrieve_similar(payload.message, payload.name)
full_prompt = f\"MEMORY:\\n{retrieved}\\nUSER:{payload.message}\"
response = chat_with_agent(full_prompt, payload.name)
return ChatbotResponseSchema(response=response)
"""
# 🧠 Step 4: Migrate & Start
# Re-migrate DB
cli: run "python manage.py makemigrations"
cli: run "python manage.py migrate"
# Start server
cli: run "python manage.py runserver 0.0.0.0:8000"
# 🎯 Test in docs:
# POST /chatbot/chat_memory
# with body: { \"name\": \"Alice\", \"message\": \"Tell me about ...\" }
```
---
## 🧠 What You Just Added
💾 **Memory Storage:**
You now have a Django model (`MemoryEntry`) that stores user queries and their vector embeddings for long-term memory. citeturn0reddit25
🔁 **Retrieval Tools:**
Two Pydantic AI tools:
- `save_to_memory` — saves embeddings.
- `retrieve_similar` — finds and returns similar memory entries for a query (basic vector similarity search). citeturn0reddit25
📡 **Retrieval-Augmented Endpoint:**
A new endpoint (`/chat_memory`) that first retrieves relevant memory results and then prompts the agent with them, enabling RAG behavior. This lets the agent ground responses in past interactions or stored knowledge. citeturn0reddit25
---
## 🧪 Next Suggestions (after you run CLIne)
Once the memory + retrieval is in place, you can continue enhancing the agent by:
✔ **Auto-saving conversations:** Trigger `save_to_memory` automatically after each chat.
✔ **Summarization of old chats:** Store concise summaries rather than raw queries.
✔ **Advanced RAG chains:** Integrate external library like LangChain or LlamaIndex for chunked document retrieval. citeturn0search3
---
If you want, I can produce **another CLIne prompt** to:
- add **streaming API responses** with `agent.run_stream_sync`,
- integrate an asynchronous frontend (e.g., React),
- or extend memory to **PDF/docs RAG search**.
gpt-5-1
proceed
Awesome — here’s the **next CLIne prompt you should give to complete the build** by *adding real memory + retrieval + summarization features* to your Django-Ninja + Ollama + Pydantic AI agent. This prompt is based on the **Part 2 memory article** (multi-layered *memory* with pgvector + RAG + summarization) and follows what’s described in the Reddit summary of that article. citeturn0reddit20
---
## 🧠 **CLIne Prompt — Complete Memory + RAG + Summarization Layer**
```
# 📌 Step 1: Install pgvector and dependencies
cli: run "pip install psycopg2-binary pgvector django-pgvector"
# 📌 Step 2: Update Django settings
cli: apply patch to backend/src/core/settings.py
"""
INSTALLED_APPS += [
'django_pgvector',
'chatbot',
]
"""
# 📌 Step 3: Create memory models with embedding vector + meta
cli: create file backend/src/chatbot/models.py with
"""
from django.db import models
from pgvector.models import VectorField
class ShortTermMemory(models.Model):
session_id = models.CharField(max_length=100)
text = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class LongTermMemory(models.Model):
user = models.CharField(max_length=100)
text = models.TextField()
vector = VectorField(dimensions=1536)
summary = models.TextField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
"""
# 📌 Step 4: Migrate DB
cli: run "python manage.py makemigrations chatbot"
cli: run "python manage.py migrate"
# 📌 Step 5: Add memory + retrieval tools
cli: apply patch to backend/src/chatbot/api.py
"""
from .models import ShortTermMemory, LongTermMemory
from pydantic_ai import RunContext
@agent.tool
def store_short_memory(ctx: RunContext[str]) -> str:
ShortTermMemory.objects.create(session_id=ctx.deps, text=ctx.deps)
return 'ok'
@agent.tool
def save_long_memory(ctx: RunContext[str]) -> str:
from pydantic_ai.providers.ollama import OllamaProvider
model = OllamaProvider(base_url=os.getenv('OLLAMA_BASE_URL'))
emb = model.embed(ctx.deps)
LongTermMemory.objects.create(
user=ctx.deps,
text=ctx.deps,
vector=emb.data,
)
return 'saved'
@agent.tool
def summarize_long_memory(ctx: RunContext[str]) -> str:
import re
# basic summarization via model
prompt = f\"\"\"Summarize this for memory storage: {ctx.deps}\"\"\"
summary = agent.run_sync(prompt).output
return summary
@agent.tool
def retrieve_relevant_memory(ctx: RunContext[str]) -> str:
from pydantic_ai.providers.ollama import OllamaProvider
model = OllamaProvider(base_url=os.getenv('OLLAMA_BASE_URL'))
query_emb = model.embed(ctx.deps)
# simple ranking by cosine similarity
all_mem = LongTermMemory.objects.all()
sorted_mem = sorted(
all_mem,
key=lambda m: -model.cosine_similarity(query_emb.data, m.vector),
)[:5]
return '\\n'.join([m.text for m in sorted_mem])
"""
# 📌 Step 6: Create RAG-style API endpoint
cli: apply patch to backend/src/chatbot/api.py
"""
@router.post('/chat_rag')
def chat_rag(request, payload: ChatbotMessageSchema):
# retrieve related long memory
related = retrieve_relevant_memory(payload.message, payload.name)
prompt = f\"RELEVANT_MEMORY:\\n{related}\\nUser: {payload.message}\"
response = chat_with_agent(prompt, payload.name)
# optionally store both short & long memory
store_short_memory(payload.message, payload.name)
save_long_memory(payload.message, payload.name)
return ChatbotResponseSchema(response=response)
"""
# 📌 Step 7: Restart server
cli: run "python manage.py runserver 0.0.0.0:8000"
# 🧪 Now test:
# POST /chatbot/chat_rag with:
# { "name": "Alice", "message": "Explain how X works" }
```
---
### ✅ What This Prompt Adds
**📍 Multi-Layer Memory**
- **Short-term memory**: Stores session context.
- **Long-term memory**: Embeddings stored in PostgreSQL via `pgvector` for RAG. citeturn0reddit20
**📍 Summarization Tool**
- Summarizes long memory entries for condensed storage. citeturn0reddit20
**📍 Retrieval Tool**
- Retrieves semantically similar long memories using vector similarity. citeturn0reddit20
**📍 RAG Endpoint**
- Integrates memory retrieval into the prompt passed to the agent. citeturn0reddit20
---
### 🚀 Next You Could Add
✔ **Streaming responses** with `agent.run_stream_sync` and a streaming Django endpoint. citeturn0search10
✔ **Document ingestion** (PDF / TXT) for broader RAG on external corpora.
✔ **Memory summarization scheduler** to condense old chats and reduce vector store size.
---
If you want, I can turn this into a **single runnable shell script** or **docker-compose CI/CLIne pipeline**.
gpt-5-1