Skip to content
Quick Start

Quick Start

Let’s build your first AI agent in under 5 minutes.

What You’ll Build

A simple agent that responds to messages with streaming AI responses. By the end, you’ll have a working /api/chat endpoint.


Install

pip install "django-ai-sdk[haystack]"

The haystack extra pulls in Haystack and the components agents run on. That’s all you need to start.

Want the full set of extras (MCP, DRF views, document parsing)?

pip install "django-ai-sdk[all]"
DRF views are experimental. The all extra includes DRF routers and serializers, but the DRF path is still in active development: use the Ninja views for production.

Configure Django

Add the app to your INSTALLED_APPS:

# settings.py
INSTALLED_APPS = [
    # ... your apps
    "django_ai_sdk",
]

Run migrations:

python manage.py migrate

This creates tables for conversation storage. You won’t need to think about them: the SDK handles it automatically.

Create an Agent

An agent is just a Python class with personality:

# agents.py
from django.conf import settings
from django_ai_sdk import Agent
from django_ai_sdk.adapters.base import Stream
from django_ai_sdk.agents import auto_register
from django_ai_sdk.common import prompt
from django_ai_sdk.pipelines.haystack import ToolAgent, ToolAgentConfig
from django_ai_sdk.protocols.vercel import VercelProtocolHandler
from django_ai_sdk.storage.db import DbStorageAdapter
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.utils import Secret

@auto_register
class ShakespeareAgent(Agent):
    """An agent that speaks like Shakespeare."""

    name = "Shakespeare Bot"
    model = settings.AI_SDK_DEFAULT_MODEL
    instructions = prompt(
        "You are a helpful assistant who speaks in Shakespearean English. "
        "Use thee, thou, and other Elizabethan expressions. "
        "Be poetic but always answer the user's question."
    )
    protocol = VercelProtocolHandler
    storage_adapter = DbStorageAdapter

    async def get_pipeline_adapter(self, thread_id=None, user=None):
        generator = OpenAIChatGenerator(
            model=self.get_model(),
            api_key=Secret.from_token(settings.OPENAI_API_KEY),
            api_base_url=getattr(settings, "OPENAI_API_URL", None),
        )
        tool_agent = ToolAgent(
            config=ToolAgentConfig(
                model=self.get_model(),
                system_prompt=self.get_system_prompt(),
                tools=await self.get_tools(thread_id=thread_id or "", user=user),
            ),
            generator=generator,
        )
        return Stream(
            pipeline=tool_agent.pipeline(),
            generator=generator,
            storage_adapter=await self.get_storage_adapter(thread_id),
        )

Three things to note:

  • name: What to call your agent
  • instructions: How it should behave (the system prompt)
  • get_pipeline_adapter: Returns the Stream that powers streaming chat

OpenAIChatGenerator works with any OpenAI-compatible endpoint. Point OPENAI_API_URL at a local server (vLLM, Ollama, llama.cpp) or leave it unset for OpenAI. Every other AI_SDK_* setting you might need is listed in the Settings Reference.

That’s it. No complex configuration. No framework setup.

Register Your Agent

Your agent must be registered before it can be used. Add it to AI_SDK_AGENTS in your settings.py:

# settings.py
AI_SDK_AGENTS = [
    "your_app.agents.ShakespeareAgent",
]

The SDK loads these classes at startup. Each agent gets a stable UUID derived from its module and class name, so you can retrieve it anywhere:

from django_ai_sdk.agents.services import AgentService

# Get an agent by its stable ID
agent = await AgentService.get(agent_id)

Agents are also registered automatically by the @auto_register decorator: AI_SDK_AGENTS just makes sure the module is imported.

Wire It to a View

Connect your agent to Django Ninja:

# views.py
from ninja import Router
from django_ai_sdk.agents.services import AgentService
from django_ai_sdk.views.schemas import ChatRequest

router = Router()

@router.post("/chat")
async def chat(request, payload: ChatRequest):
    """Chat with Shakespeare Bot."""
    agent = await AgentService.get(payload.agent_id)
    return await agent.as_view(payload.messages, user=request.user)

The as_view() method handles everything:

  • Protocol conversion (Vercel AI SDK Data Stream Protocol in, ChatMessages internally)
  • Building the pipeline adapter and streaming to the model
  • Returning an SSE StreamingHttpResponse

Add to URLs

# urls.py
from ninja import NinjaAPI
from your_app.views import router

api = NinjaAPI()
api.add_router("/", router)

urlpatterns = [
    path("api/", api.urls),
]

Test It

Start your server:

python manage.py runserver

Send a message:

curl -X POST http://localhost:8000/api/chat \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "messages": [{"role": "user", "parts": [{"type": "text", "text": "Hello!"}]}],
    "agent_id": "your-agent-uuid"
  }'

You’ll see a streaming response:

data: {"type":"start","messageId":"msg_abc123"}
data: {"type":"text-start","id":"text_001"}
data: {"type":"text-delta","id":"text_001","delta":"Hark!"}
data: {"type":"text-delta","id":"text_001","delta":" Good"}
data: {"type":"text-delta","id":"text_001","delta":" morrow"}
data: {"type":"text-delta","id":"text_001","delta":" to"}
data: {"type":"text-delta","id":"text_001","delta":" thee!"}
data: {"type":"text-end","id":"text_001"}
data: {"type":"finish"}
data: [DONE]

You did it! Your agent is live and streaming responses.

What just happened? as_view() converted the protocol messages to internal ChatMessages, get_pipeline_adapter() built a ToolAgent pipeline and returned a Stream, Haystack streamed chunks normalized into StreamEvents, and the events were serialized to the Vercel protocol over SSE. All in about 50 lines of code.

Next Steps