To solve this optimization problem, we first need to define the decision variables and the objective function. Let's denote the number of small smoothies as \(x\) and the number of large smoothies as \(y\). The objective is to maximize profit, which can be calculated as \(3x + 5y\), given that each small smoothie yields a profit of $3 and each large smoothie yields a profit of $5.

Next, we need to define the constraints based on the availability of ice cream and peanut butter. Each small smoothie requires 2 units of ice cream, so \(x\) small smoothies will require \(2x\) units of ice cream. Similarly, each large smoothie requires 3 units of ice cream, meaning \(y\) large smoothies will need \(3y\) units of ice cream. Given that there are only 20 units of ice cream available, we have the constraint \(2x + 3y \leq 20\).

For peanut butter, each small smoothie requires 1 unit, and each large smoothie requires 2 units. With \(x\) small smoothies and \(y\) large smoothies, the total peanut butter needed is \(x + 2y\). Since there are only 18 units of peanut butter available, we have another constraint: \(x + 2y \leq 18\).

Lastly, it's important to note that the number of smoothies cannot be negative, so we also have non-negativity constraints: \(x \geq 0\) and \(y \geq 0\).

The problem can now be formulated as a linear programming problem:

Maximize: \(3x + 5y\)

Subject to:
1. \(2x + 3y \leq 20\)
2. \(x + 2y \leq 18\)
3. \(x \geq 0\)
4. \(y \geq 0\)

Here is the Gurobi code in Python that solves this problem:

```python
from gurobipy import *

# Create a model
m = Model("Smoothie_Optimization")

# Define decision variables
x = m.addVar(lb=0, vtype=GRB.CONTINUOUS, name="small_smoothies")
y = m.addVar(lb=0, vtype=GRB.CONTINUOUS, name="large_smoothies")

# Set the objective function
m.setObjective(3*x + 5*y, GRB.MAXIMIZE)

# Add constraints
m.addConstr(2*x + 3*y <= 20, "ice_cream_constraint")
m.addConstr(x + 2*y <= 18, "peanut_butter_constraint")

# Optimize the model
m.optimize()

# Print the results
for v in m.getVars():
    print(f"{v.varName}: {v.x}")
print(f"Objective: {m.objVal}")
```