Skip to content

Commit 7d675c9

Browse files
add tutorial on customizing modules (#8370)
1 parent b3d7d2c commit 7d675c9

File tree

5 files changed

+210
-3
lines changed

5 files changed

+210
-3
lines changed

docs/docs/learn/programming/modules.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,13 @@ class Hop(dspy.Module):
245245
return dspy.Prediction(notes=notes, titles=list(set(titles)))
246246
```
247247

248+
Then you can create a instance of the custom module class `Hop`, then invoke it by the `__call__` method:
249+
250+
```
251+
hop = Hop()
252+
print(hop(claim="Stephen Curry is the best 3 pointer shooter ever in the human history"))
253+
```
254+
248255
## How do I track LM usage?
249256

250257
!!! note "Version Requirement"

docs/docs/tutorials/build_ai_program/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
- [Build AI Agents with DSPy](/tutorials/customer_service_agent/)
1+
- [Building AI Agents with DSPy](/tutorials/customer_service_agent/)
2+
- [Building AI Applications by Customizing DSPy Modules](/tutorials/custom_module/)
23
- [Retrieval-Augmented Generation (RAG)](/tutorials/rag/)
34
- [Building RAG as Agent](/tutorials/agents/)
45
- [Entity Extraction](/tutorials/entity_extraction/)
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"id": "1cR_pjqz1AsF"
7+
},
8+
"source": [
9+
"# Building AI Applications by Customizing DSPy Modules\n",
10+
"\n",
11+
"In this guide, we will walk you through how to build a GenAI application by customizing `dspy.Module`.\n",
12+
"\n",
13+
"A [DSPy module](https://dspy.ai/learn/programming/modules/) is the building block for DSPy programs.\n",
14+
"\n",
15+
"- Each built-in module abstracts a prompting technique (like chain of thought or ReAct). Crucially, they are generalized to handle any signature.\n",
16+
"\n",
17+
"- A DSPy module has learnable parameters (i.e., the little pieces comprising the prompt and the LM weights) and can be invoked (called) to process inputs and return outputs.\n",
18+
"\n",
19+
"- Multiple modules can be composed into bigger modules (programs). DSPy modules are inspired directly by NN modules in PyTorch, but applied to LM programs.\n",
20+
"\n",
21+
"Although you can build a DSPy program without implementing a custom module, we highly recommend putting your logic with a custom module so that you can use other DSPy features, like DSPy optimizer or MLflow DSPy tracing."
22+
]
23+
},
24+
{
25+
"cell_type": "markdown",
26+
"metadata": {
27+
"id": "KBYjBQtv3Cn5"
28+
},
29+
"source": [
30+
"Before getting started, make sure you have DSPy installed:\n",
31+
"\n",
32+
"```\n",
33+
"!pip install dspy\n",
34+
"```"
35+
]
36+
},
37+
{
38+
"cell_type": "markdown",
39+
"metadata": {
40+
"id": "reQSTM8a8qMf"
41+
},
42+
"source": [
43+
"## Customize DSPy Module\n",
44+
"\n",
45+
"You can implement custom prompting logic and integrate external tools or services by customizing a DSPy module. To achieve this, subclass from `dspy.Module` and implement the following two key methods:\n",
46+
"\n",
47+
"- `__init__`: This is the constructor, where you define the attributes and sub-modules of your program.\n",
48+
"- `forward`: This method contains the core logic of your DSPy program.\n",
49+
"\n",
50+
"Within the `forward()` method, you are not limited to calling only other DSPy modules; you can also integrate any standard Python functions, such as those for interacting with Langchain/Agno agents, MCP tools, database handlers, and more.\n",
51+
"\n",
52+
"The basic structure for a custom DSPy module looks like this:\n",
53+
"\n",
54+
"```python\n",
55+
"class MyProgram(dspy.Module):\n",
56+
" \n",
57+
" def __init__(self, ...):\n",
58+
" # Define attributes and sub-modules here\n",
59+
" {constructor_code}\n",
60+
"\n",
61+
" def forward(self, input_name1, input_name2, ...):\n",
62+
" # Implement your program's logic here\n",
63+
" {custom_logic_code}\n",
64+
"```"
65+
]
66+
},
67+
{
68+
"cell_type": "markdown",
69+
"metadata": {
70+
"id": "DziTWwT8_TrY"
71+
},
72+
"source": [
73+
"Let's illustrate this with a practical code example. We will build a simple Retrieval-Augmented Generation (RAG) application with mulitple stages:\n",
74+
"\n",
75+
"1. **Query Generation:** Generate a suitable query based on the user's question to retrieve relevant context.\n",
76+
"2. **Context Retrieval:** Fetch context using the generated query.\n",
77+
"3. **Answer Generation:** Produce a final answer based on the retrieved context and the original question.\n",
78+
"\n",
79+
"The code implementation for this multi-stage program is shown below."
80+
]
81+
},
82+
{
83+
"cell_type": "code",
84+
"execution_count": 3,
85+
"metadata": {
86+
"id": "lAoV5_v7YlvN"
87+
},
88+
"outputs": [],
89+
"source": [
90+
"import dspy\n",
91+
"\n",
92+
"class QueryGenerator(dspy.Signature):\n",
93+
" \"\"\"Generate a query based on question to fetch relevant context\"\"\"\n",
94+
" question: str = dspy.InputField()\n",
95+
" query: str = dspy.OutputField()\n",
96+
"\n",
97+
"def search_wikipedia(query: str) -> list[str]:\n",
98+
" \"\"\"Query ColBERT endpoint, which is a knowledge source based on wikipedia data\"\"\"\n",
99+
" results = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')(query, k=1)\n",
100+
" return [x[\"text\"] for x in results]\n",
101+
"\n",
102+
"class RAG(dspy.Module):\n",
103+
" def __init__(self):\n",
104+
" self.query_generator = dspy.Predict(QueryGenerator)\n",
105+
" self.answer_generator = dspy.ChainOfThought(\"question,context->answer\")\n",
106+
"\n",
107+
" def forward(self, question, **kwargs):\n",
108+
" query = self.query_generator(question=question).query\n",
109+
" context = search_wikipedia(query)[0]\n",
110+
" return self.answer_generator(question=question, context=context).answer"
111+
]
112+
},
113+
{
114+
"cell_type": "markdown",
115+
"metadata": {},
116+
"source": [
117+
"Let's take a look at the `forward` method. We first send the question to `self.query_generator`, which is a `dspy.Predict`, to get the query for context retrieving. Then we use the query to call ColBERT and keep the first context retrieved. Finally, we send the question and context into `self.answer_generator`, which is a `dspy.ChainOfThought` to generate the final answer."
118+
]
119+
},
120+
{
121+
"cell_type": "markdown",
122+
"metadata": {
123+
"id": "FBq_4e8NamwY"
124+
},
125+
"source": [
126+
"Next, we'll create an instance of our `RAG` module to run the program.\n",
127+
"\n",
128+
"**Important:** When invoking a custom DSPy module, you should use the module instance directly (which calls the `__call__` method internally), rather than calling the `forward()` method explicitly. The `__call__` method handles necessary internal processing before executing the `forward` logic."
129+
]
130+
},
131+
{
132+
"cell_type": "code",
133+
"execution_count": 7,
134+
"metadata": {
135+
"colab": {
136+
"base_uri": "https://localhost:8080/"
137+
},
138+
"id": "ZR7xcFSTa596",
139+
"outputId": "f3427754-8a16-48fe-c540-8c9f31d9a30d"
140+
},
141+
"outputs": [
142+
{
143+
"name": "stdout",
144+
"output_type": "stream",
145+
"text": [
146+
"The question of whether LeBron James is the basketball GOAT is subjective and depends on personal opinions. Many consider him one of the greatest due to his achievements and impact on the game, but others may argue for different players like Michael Jordan.\n"
147+
]
148+
}
149+
],
150+
"source": [
151+
"import os\n",
152+
"\n",
153+
"os.environ[\"OPENAI_API_KEY\"] = \"{your_openai_api_key}\"\n",
154+
"\n",
155+
"dspy.configure(lm=dspy.LM(\"openai/gpt-4o-mini\"))\n",
156+
"rag = RAG()\n",
157+
"print(rag(question=\"Is Lebron James the basketball GOAT?\"))"
158+
]
159+
},
160+
{
161+
"cell_type": "markdown",
162+
"metadata": {},
163+
"source": [
164+
"That's it! In summary, to build your GenAI applications, we just put the custom logic into the `forward()` method, then create a module instance and call the instance itself."
165+
]
166+
},
167+
{
168+
"cell_type": "markdown",
169+
"metadata": {
170+
"id": "aYAYc-Hg39ri"
171+
},
172+
"source": [
173+
"## Why Customizing Module?\n",
174+
"\n",
175+
"DSPy is a lightweight authoring and optimization framework, and our focus is to resolve the mess of prompt engineering by transforming prompting (string in, string out) LLM into programming LLM (structured inputs in, structured outputs out) for robust AI system.\n",
176+
"\n",
177+
"While we provide pre-built modules which have custom prompting logic like `dspy.ChainOfThought` for reasoning, `dspy.ReAct` for tool calling agent to facilitate building your AI applications, we don't aim at standardizing how you build agents.\n",
178+
"\n",
179+
"In DSPy, your application logic simply goes to the `forward` method of your custom Module, which doesn't have any constraint as long as you are writing python code. With this layout, DSPy is easy to migrate to from other frameworks or vanilla SDK usage, and easy to migrate off because essentially it's just python code.\n"
180+
]
181+
}
182+
],
183+
"metadata": {
184+
"colab": {
185+
"provenance": []
186+
},
187+
"kernelspec": {
188+
"display_name": "Python 3",
189+
"name": "python3"
190+
},
191+
"language_info": {
192+
"name": "python"
193+
}
194+
},
195+
"nbformat": 4,
196+
"nbformat_minor": 0
197+
}

docs/docs/tutorials/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ Welcome to DSPy tutorials! We've organized our tutorials into three main categor
1313

1414

1515
- Build AI Programs with DSPy
16+
- [Building AI Agents with DSPy](/tutorials/customer_service_agent/)
17+
- [Building AI Applications by Customizing DSPy Modules](/tutorials/custom_module/)
1618
- [Retrieval-Augmented Generation (RAG)](/tutorials/rag/)
1719
- [Building RAG as Agent](/tutorials/agents/)
18-
- [Build AI Agents with DSPy](/tutorials/customer_service_agent/)
1920
- [Entity Extraction](/tutorials/entity_extraction/)
2021
- [Classification](/tutorials/classification/)
2122
- [Multi-Hop RAG](/tutorials/multihop_search/)

docs/mkdocs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ nav:
2727
- Tutorials Overview: tutorials/index.md
2828
- Build AI Programs with DSPy:
2929
- Overview: tutorials/build_ai_program/index.md
30-
- Build AI Agents with DSPy: tutorials/customer_service_agent/index.ipynb
30+
- Building AI Agents with DSPy: tutorials/customer_service_agent/index.ipynb
31+
- Building AI Applications by Customizing DSPy Modules: tutorials/custom_module/index.ipynb
3132
- Retrieval-Augmented Generation (RAG): tutorials/rag/index.ipynb
3233
- Building RAG as Agent: tutorials/agents/index.ipynb
3334
- Entity Extraction: tutorials/entity_extraction/index.ipynb

0 commit comments

Comments
 (0)