To solve the given optimization problem, we first need to convert the natural language description into a symbolic representation. This involves defining variables and formulating the objective function and constraints.

Let's denote:
- \(x_1\) as the number of Caesar salads made,
- \(x_2\) as the number of House salads made.

The objective is to maximize profit, given that each Caesar salad yields $5 in profit and each House salad yields $8 in profit. Therefore, the objective function can be represented as:
\[ \text{Maximize:} \quad 5x_1 + 8x_2 \]

Now, let's formulate the constraints based on the problem description:

1. **Lettuce Constraint**: The total amount of lettuce used for both types of salads cannot exceed 2000 grams. Given that each Caesar salad contains 20 grams of lettuce and each House salad contains 30 grams of lettuce, we have:
\[ 20x_1 + 30x_2 \leq 2000 \]

2. **House Salads vs. Caesar Salads Ratio**: At least three times the amount of House salads needs to be made compared to Caesar salads:
\[ x_2 \geq 3x_1 \]

3. **Minimum Caesar Salads**: A minimum of 8 Caesar salads needs to be made:
\[ x_1 \geq 8 \]

4. **Non-Negativity Constraints**: The number of salads cannot be negative, so we have:
\[ x_1 \geq 0 \]
\[ x_2 \geq 0 \]

Given these constraints and the objective function, the symbolic representation of the problem in JSON format is:

```json
{
    'sym_variables': [('x1', 'Number of Caesar salads'), ('x2', 'Number of House salads')],
    'objective_function': '5*x1 + 8*x2',
    'constraints': [
        '20*x1 + 30*x2 <= 2000',
        'x2 >= 3*x1',
        'x1 >= 8',
        'x1 >= 0',
        'x2 >= 0'
    ]
}
```

To solve this problem using Gurobi in Python, we use the following code:

```python
from gurobipy import *

# Create a new model
model = Model("Salad_Optimization")

# Define variables
x1 = model.addVar(vtype=GRB.INTEGER, name="Caesar_Salads", lb=0)
x2 = model.addVar(vtype=GRB.INTEGER, name="House_Salads", lb=0)

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

# Add constraints
model.addConstr(20*x1 + 30*x2 <= 2000, "Lettuce_Constraint")
model.addConstr(x2 >= 3*x1, "House_vs_Caesar_Ratio")
model.addConstr(x1 >= 8, "Minimum_Caesar_Salads")

# Optimize the model
model.optimize()

# Print the results
if model.status == GRB.OPTIMAL:
    print(f"Optimal solution found:")
    print(f"Number of Caesar salads: {x1.x}")
    print(f"Number of House salads: {x2.x}")
    print(f"Maximum Profit: {model.objVal}")
else:
    print("No optimal solution found")
```