To solve the given optimization problem, we first need to convert the natural language description into a symbolic representation. This involves defining variables for the quantities of peanut butter and almond butter smoothies to be made, formulating the objective function that represents the total profit, and listing the constraints based on the availability of ingredients.

Let's define:
- $x_1$ as the number of peanut butter smoothies to be made,
- $x_2$ as the number of almond butter smoothies to be made.

The objective function, which is the total profit, can be represented as $3x_1 + 5x_2$, since each peanut butter smoothie gives a profit of $3 and each almond butter smoothie gives a profit of $5.

The constraints are based on the availability of ingredients:
- Peanut butter: $2x_1 \leq 80$ (since one peanut butter smoothie requires 2 units of peanut butter and there are 80 units available),
- Almond butter: $3x_2 \leq 90$ (since one almond butter smoothie requires 3 units of almond butter and there are 90 units available),
- Milk: $3x_1 + 3x_2 \leq 100$ (since each smoothie, regardless of type, requires 3 units of milk and there are 100 units available).

Non-negativity constraints also apply since the number of smoothies cannot be negative:
- $x_1 \geq 0$,
- $x_2 \geq 0$.

Thus, the symbolic representation of the problem is:

```json
{
  'sym_variables': [('x1', 'number of peanut butter smoothies'), ('x2', 'number of almond butter smoothies')],
  'objective_function': '3*x1 + 5*x2',
  'constraints': ['2*x1 <= 80', '3*x2 <= 90', '3*x1 + 3*x2 <= 100', 'x1 >= 0', 'x2 >= 0']
}
```

Now, let's implement this problem using Gurobi in Python:

```python
from gurobipy import *

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

# Define variables
x1 = m.addVar(name="peanut_butter_smoothies", vtype=GRB.CONTINUOUS, lb=0)
x2 = m.addVar(name="almond_butter_smoothies", vtype=GRB.CONTINUOUS, lb=0)

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

# Add constraints
m.addConstr(2*x1 <= 80, name="peanut_butter_availability")
m.addConstr(3*x2 <= 90, name="almond_butter_availability")
m.addConstr(3*x1 + 3*x2 <= 100, name="milk_availability")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Number of peanut butter smoothies: {x1.x}")
    print(f"Number of almond butter smoothies: {x2.x}")
    print(f"Total profit: {m.objVal}")
else:
    print("No optimal solution found")
```