Agentic AI using DSPy and Ollama Cloud
A customer service airline booking Agent using DSPy + Ollama cloud models
The code below is based on https://dspy.ai/tutorials/customer_service_agent/ and modified to use Ollama cloud model so one can run it without downloading large models locally.
Setup
pip install -qU dspy pydantic- Install Ollama from https://ollama.com/
- Sign up for an Ollama Cloud account and get your API key.
- Install the
gpt-oss:120b-cloudmodel: Once we signin to ollama and have associated the laptop device with ollama user ID then we can connect to cloud model hosted at ollama.com by connecting to locally running ollama service. This enables running faster inference in cloud instead of running it locally on a model downloaded to laptop. With dspy we can easily switch between cloud hosted and locally hosted models by setting dspy.configure(lm=)
1
2
ollama signin
ollama run gpt-oss:120b-cloud
- Test if the setup is working:
1
2
3
4
5
6
7
8
9
10
11
12
import dspy
# Configure cloud Ollama (replace with your cloud endpoint)
cloud_ollama = dspy.LM(
api_base="http://localhost:11434",
api_key="",
model="ollama_chat/gpt-oss:120b-cloud",
model_type="chat"
)
dspy.configure(lm=cloud_ollama)
print(cloud_ollama("What is the capital of France?"))
Simple airline customer service agent
- Book new trips on behalf of the user.
- Modify existing trips, including flight change and cancellation.
- On tasks it cannot handle, raise a customer support ticket.
Create Test Data and define the tools
Setup test data and tool calls for the agent.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from pydantic import BaseModel
class Date(BaseModel):
# Somehow LLM is bad at specifying `datetime.datetime`, so
# we define a custom class to represent the date.
year: int
month: int
day: int
hour: int
class UserProfile(BaseModel):
user_id: str
name: str
email: str
class Flight(BaseModel):
flight_id: str
date_time: Date
origin: str
destination: str
duration: float
price: float
class Itinerary(BaseModel):
confirmation_number: str
user_profile: UserProfile
flight: Flight
class Ticket(BaseModel):
user_request: str
user_profile: UserProfile
user_database = {
"Adam": UserProfile(user_id="1", name="Adam", email="adam@gmail.com"),
"Bob": UserProfile(user_id="2", name="Bob", email="bob@gmail.com"),
"Chelsie": UserProfile(user_id="3", name="Chelsie", email="chelsie@gmail.com"),
"David": UserProfile(user_id="4", name="David", email="david@gmail.com"),
}
flight_database = {
"DA123": Flight(
flight_id="DA123", # DSPy Airline 123
origin="SFO",
destination="JFK",
date_time=Date(year=2025, month=9, day=1, hour=1),
duration=3,
price=200,
),
"DA125": Flight(
flight_id="DA125",
origin="SFO",
destination="JFK",
date_time=Date(year=2025, month=9, day=1, hour=7),
duration=9,
price=500,
),
"DA456": Flight(
flight_id="DA456",
origin="SFO",
destination="SNA",
date_time=Date(year=2025, month=10, day=1, hour=1),
duration=2,
price=100,
),
"DA460": Flight(
flight_id="DA460",
origin="SFO",
destination="SNA",
date_time=Date(year=2025, month=10, day=1, hour=9),
duration=2,
price=120,
),
}
itinery_database = {}
ticket_database = {}
Define Tools
- Have a docstring which defines what the tool does. If the function name is self-explanable, then you can leave the docstring empty.
- Have type hint for the arguments, which is necessary for LM to generate the arguments in the right format.
We need to prepare a list of tools so that the agent can behave like a human airline service agent:
- fetch_flight_info: get flight information for certain dates.
- pick_flight: pick the best flight based on some criteria.
- book_flight: book a flight on behalf of the user.
- fetch_itinerary: get the information of a booked itinerary.
- cancel_itinerary: cancel a booked itinerary.
- get_user_info: get users’ information.
- file_ticket: file a backlog ticket to have human assist.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import random
import string
def fetch_flight_info(date: Date, origin: str, destination: str):
"""Fetch flight information from origin to destination on the given date"""
flights = []
for flight_id, flight in flight_database.items():
if (
flight.date_time.year == date.year
and flight.date_time.month == date.month
and flight.date_time.day == date.day
and flight.origin == origin
and flight.destination == destination
):
flights.append(flight)
if len(flights) == 0:
raise ValueError("No matching flight found!")
return flights
def fetch_itinerary(confirmation_number: str):
"""Fetch a booked itinerary information from database"""
return itinery_database.get(confirmation_number)
def pick_flight(flights: list[Flight]):
"""Pick up the best flight that matches users' request. we pick the shortest, and cheaper one on ties."""
sorted_flights = sorted(
flights,
key=lambda x: (
x.get("duration") if isinstance(x, dict) else x.duration,
x.get("price") if isinstance(x, dict) else x.price,
),
)
return sorted_flights[0]
def _generate_id(length=8):
chars = string.ascii_lowercase + string.digits
return "".join(random.choices(chars, k=length))
def book_flight(flight: Flight, user_profile: UserProfile):
"""Book a flight on behalf of the user."""
confirmation_number = _generate_id()
while confirmation_number in itinery_database:
confirmation_number = _generate_id()
itinery_database[confirmation_number] = Itinerary(
confirmation_number=confirmation_number,
user_profile=user_profile,
flight=flight,
)
return confirmation_number, itinery_database[confirmation_number]
def cancel_itinerary(confirmation_number: str, user_profile: UserProfile):
"""Cancel an itinerary on behalf of the user."""
if confirmation_number in itinery_database:
del itinery_database[confirmation_number]
return
raise ValueError("Cannot find the itinerary, please check your confirmation number.")
def get_user_info(name: str):
"""Fetch the user profile from database with given name."""
return user_database.get(name)
def file_ticket(user_request: str, user_profile: UserProfile):
"""File a customer support ticket if this is something the agent cannot handle."""
ticket_id = _generate_id(length=6)
ticket_database[ticket_id] = Ticket(
user_request=user_request,
user_profile=user_profile,
)
return ticket_id
Create ReAct Agent
We need to provide a signature to dspy.ReAct to define task, and the inputs and outputs of the agent, and tell it about the tools it can access.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import dspy
class DSPyAirlineCustomerService(dspy.Signature):
"""You are an airline customer service agent that helps user book and manage flights.
You are given a list of tools to handle user request, and you should decide the right tool to use in order to
fulfill users' request."""
user_request: str = dspy.InputField()
process_result: str = dspy.OutputField(
desc=(
"Message that summarizes the process result, and the information users need, e.g., the "
"confirmation_number if a new flight is booked."
)
)
agent = dspy.ReAct(
DSPyAirlineCustomerService,
tools = [
fetch_flight_info,
fetch_itinerary,
pick_flight,
book_flight,
cancel_itinerary,
get_user_info,
file_ticket,
]
)
Use the Agent
- Invoke the dspy.ReAct with the inputs field defined in the signature, and it will start the reasoning and acting loop behind the scene.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Configure DSPy to use cloud Ollama model
cloud_ollama = dspy.LM(
api_base="http://localhost:11434",
api_key="",
model="ollama_chat/gpt-oss:120b-cloud",
model_type="chat"
)
dspy.configure(lm=cloud_ollama)
result = agent(user_request="please help me book a flight from SFO to JFK on 9/01/2025, my name is Adam")
print(result) #— Agent Trajectory shown below
print(itinery_database)
dspy.inspect_history(n=10)
confirmation_number = "{copy the confirmation number here}"
result = agent(user_request=f"i want to take DA125 instead on 09/01, please help me modify my itinerary {confirmation_number}")
print(result)
Agent Trajectory
1
trajectory={'thought_0': "I need to retrieve Adam's user profile before I can book a flight for him. I'll start by fetching his user information from the database.", 'tool_name_0': 'get_user_info', 'tool_args_0': {'name': 'Adam'}, 'observation_0': UserProfile(user_id='1', name='Adam', email='adam@gmail.com'), 'thought_1': "Now that I have Adam's user profile, I need to find available flights from SFO to JFK on September 1, 2025. I will fetch flight information for that route and date.", 'tool_name_1': 'fetch_flight_info', 'tool_args_1': {'origin': 'SFO', 'destination': 'JFK', 'date': {'year': 2025, 'month': 9, 'day': 1, 'hour': 0}}, 'observation_1': [Flight(flight_id='DA123', date_time=Date(year=2025, month=9, day=1, hour=1), origin='SFO', destination='JFK', duration=3.0, price=200.0), Flight(flight_id='DA125', date_time=Date(year=2025, month=9, day=1, hour=7), origin='SFO', destination='JFK', duration=9.0, price=500.0)], 'thought_2': 'I have the list of available flights. I will use the pick_flight tool to select the best option based on shortest duration and lowest price.', 'tool_name_2': 'pick_flight', 'tool_args_2': {'flights': [{'flight_id': 'DA123', 'date_time': {'year': 2025, 'month': 9, 'day': 1, 'hour': 1}, 'origin': 'SFO', 'destination': 'JFK', 'duration': 3.0, 'price': 200.0}, {'flight_id': 'DA125', 'date_time': {'year': 2025, 'month': 9, 'day': 1, 'hour': 7}, 'origin': 'SFO', 'destination': 'JFK', 'duration': 9.0, 'price': 500.0}]}, 'observation_2': Flight(flight_id='DA123', date_time=Date(year=2025, month=9, day=1, hour=1), origin='SFO', destination='JFK', duration=3.0, price=200.0), 'thought_3': 'I have selected the best flight (DA123) for Adam. The next step is to book this flight using his user profile.', 'tool_name_3': 'book_flight', 'tool_args_3': {'flight': {'flight_id': 'DA123', 'date_time': {'year': 2025, 'month': 9, 'day': 1, 'hour': 1}, 'origin': 'SFO', 'destination': 'JFK', 'duration': 3.0, 'price': 200.0}, 'user_profile': {'user_id': '1', 'name': 'Adam', 'email': 'adam@gmail.com'}}, 'observation_3': ('ta18vp18', Itinerary(confirmation_number='ta18vp18', user_profile=UserProfile(user_id='1', name='Adam', email='adam@gmail.com'), flight=Flight(flight_id='DA123', date_time=Date(year=2025, month=9, day=1, hour=1), origin='SFO', destination='JFK', duration=3.0, price=200.0))), 'thought_4': 'The flight has been successfully booked for Adam. I will now finish the task.', 'tool_name_4': 'finish', 'tool_args_4': {}, 'observation_4': 'Completed.'},
DSPy ReAct module makes it simple to write an agent by just pointing to the tools.
This post is licensed under CC BY 4.0 by the author.