Skip to main content
A powerful AI agent built with DSPy that combines LLM reasoning with tool execution. Uses Nebius AI and DSPy’s ReAct module for multi-step reasoning tasks with Wikipedia search and Python evaluation.

Features

  • ReAct framework for reasoning and action
  • Tool integration (Wikipedia search, Python interpreter)
  • LLM orchestration with DSPy
  • Multi-step task execution
  • Structured answer generation

Prerequisites

Installation

1

Clone the repository

git clone https://github.com/Arindam200/awesome-ai-apps.git
cd starter_ai_agents/dspy_starter
2

Install dependencies

uv sync
3

Configure environment

Create a .env file and add your Nebius API key:
NEBIUS_API_KEY=your_api_key_here

Implementation

DSPy Configuration

Configure DSPy with Nebius AI:
main.py
import dspy
import os

# Configure dspy with Nebius AI
lm = dspy.LM(
    "nebius/moonshotai/Kimi-K2-Instruct",
    api_key=os.environ.get("NEBIUS_API_KEY"),
    api_base="https://api.tokenfactory.nebius.com/v1",
)

dspy.configure(lm=lm)

Tool Definitions

Define tools for the agent:
main.py
def evaluate_math(expression: str):
    """Evaluate mathematical expressions using Python"""
    return dspy.PythonInterpreter({}).execute(expression)

def search_wikipedia(query: str):
    """Search Wikipedia for information"""
    results = dspy.ColBERTv2(
        url="http://20.102.90.50:2017/wiki17_abstracts"
    )(query, k=3)
    return [x["text"] for x in results]

ReAct Agent

Create the ReAct agent with tools:
main.py
react = dspy.ReAct(
    "question -> answer: str", 
    tools=[evaluate_math, search_wikipedia]
)

question = "What is 9362158 divided by the year of Messi's first Ballon d'Or?"

pred = react(question=question)

print("Question:", question)
print("Answer:", pred.answer)

Usage

Run the DSPy agent:
uv run main.py
The agent will:
  1. Analyze the question
  2. Use Wikipedia to find Messi’s first Ballon d’Or year
  3. Use Python evaluation to perform the calculation
  4. Return the final answer

Example Tasks

Try these complex queries:
  • “What is the population of France multiplied by the number of Nobel Prizes won by Marie Curie?”
  • “Calculate the square root of the year the Eiffel Tower was built.”
  • “Find the capital of Japan and its population.”
  • “Who won the Nobel Prize in Physics in 1921 and what was their age at the time?”

Technical Details

DSPy Architecture

LM Configuration

Language model setup with Nebius AI

ReAct Module

Reasoning and action framework

Tools

Python interpreter and Wikipedia search

Signatures

Input/output specifications

ReAct Pattern

DSPy’s ReAct module follows this pattern:
  1. Thought: Reason about the question
  2. Action: Select and execute a tool
  3. Observation: Process tool results
  4. Repeat: Continue until answer is found
  5. Answer: Return final result

Extending the Agent

Add Custom Tools

def fetch_weather(city: str):
    """Fetch current weather for a city"""
    # Implementation
    return weather_data

def calculate_distance(city1: str, city2: str):
    """Calculate distance between two cities"""
    # Implementation
    return distance

react = dspy.ReAct(
    "question -> answer: str",
    tools=[evaluate_math, search_wikipedia, fetch_weather, calculate_distance]
)

Use Different Models

# Use a different Nebius model
lm = dspy.LM(
    "nebius/Qwen/Qwen3-235B-A22B",
    api_key=os.environ.get("NEBIUS_API_KEY"),
    api_base="https://api.tokenfactory.nebius.com/v1",
)

dspy.configure(lm=lm)

Add Structured Output

from pydantic import BaseModel

class DetailedAnswer(BaseModel):
    answer: str
    reasoning_steps: list[str]
    sources: list[str]
    confidence: float

react = dspy.ReAct(
    "question -> DetailedAnswer",
    tools=[evaluate_math, search_wikipedia]
)

result = react(question="What is 2+2?")
print(result.answer)  # Structured output

Chain Multiple Modules

class ResearchAssistant(dspy.Module):
    def __init__(self):
        super().__init__()
        self.researcher = dspy.ReAct(
            "question -> findings: str",
            tools=[search_wikipedia]
        )
        self.analyzer = dspy.ChainOfThought("findings -> analysis: str")
        self.summarizer = dspy.ChainOfThought("analysis -> summary: str")
    
    def forward(self, question):
        findings = self.researcher(question=question)
        analysis = self.analyzer(findings=findings.findings)
        summary = self.summarizer(analysis=analysis.analysis)
        return summary

assistant = ResearchAssistant()
result = assistant(question="What is quantum computing?")

Tool Implementation Details

Python Interpreter

def evaluate_math(expression: str):
    """Safely evaluate mathematical expressions"""
    try:
        result = dspy.PythonInterpreter({}).execute(expression)
        return str(result)
    except Exception as e:
        return f"Error: {str(e)}"
def search_wikipedia(query: str, k: int = 3):
    """Search Wikipedia and return top k results"""
    try:
        results = dspy.ColBERTv2(
            url="http://20.102.90.50:2017/wiki17_abstracts"
        )(query, k=k)
        return [x["text"] for x in results]
    except Exception as e:
        return [f"Error searching Wikipedia: {str(e)}"]

Best Practices

  • Keep tools focused on single tasks
  • Provide clear docstrings
  • Handle errors gracefully
  • Return structured, parseable data
  • Choose appropriate model size
  • Test with different temperature settings
  • Consider cost vs. performance
  • Use caching for repeated queries
  • Use clear input/output specifications
  • Include type hints
  • Document expected formats
  • Test with edge cases

DSPy Modules

DSPy provides several built-in modules:
  • ReAct: Reasoning and action with tools
  • ChainOfThought: Step-by-step reasoning
  • ProgramOfThought: Program generation
  • MultiChainComparison: Compare multiple reasoning paths
  • Retrieve: Document retrieval
# Chain of Thought
cot = dspy.ChainOfThought("question -> answer")

# Program of Thought
pot = dspy.ProgramOfThought("question -> code, answer")

# Multi-Chain Comparison
mcc = dspy.MultiChainComparison("question -> answer", M=3)

Optimization

DSPy supports automatic optimization:
from dspy.teleprompt import BootstrapFewShot

# Define training examples
trainset = [
    dspy.Example(question="What is 2+2?", answer="4"),
    dspy.Example(question="What is the capital of France?", answer="Paris"),
]

# Optimize the agent
optimizer = BootstrapFewShot(metric=exact_match)
optimized_react = optimizer.compile(react, trainset=trainset)

Environment Variables

VariableDescriptionRequired
NEBIUS_API_KEYYour Nebius API keyYes

Next Steps

Advanced DSPy

Build complex DSPy applications

RAG with DSPy

Add retrieval to your agents

Build docs developers (and LLMs) love