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

Let's define:
- $x_1$ as the number of researchers,
- $x_2$ as the number of developers.

The objective is to minimize the total weekly wages, which can be represented by the objective function: $2500x_1 + 1500x_2$.

The constraints are as follows:
1. The project requires at least 50 workers: $x_1 + x_2 \geq 50$.
2. At least 30 must be developers: $x_2 \geq 30$.
3. The number of researchers must be at least a third of the number of developers: $x_1 \geq \frac{1}{3}x_2$.
4. The weekly payroll should not exceed $250,000: $2500x_1 + 1500x_2 \leq 250,000$.

Given this symbolic representation, we can now formulate the optimization problem as follows:

```json
{
    'sym_variables': [('x1', 'number of researchers'), ('x2', 'number of developers')],
    'objective_function': '2500*x1 + 1500*x2',
    'constraints': ['x1 + x2 >= 50', 'x2 >= 30', 'x1 >= (1/3)*x2', '2500*x1 + 1500*x2 <= 250000']
}
```

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

```python
from gurobipy import *

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

# Define variables
x1 = m.addVar(vtype=GRB.INTEGER, name="researchers")
x2 = m.addVar(vtype=GRB.INTEGER, name="developers")

# Set the objective function
m.setObjective(2500*x1 + 1500*x2, GRB.MINIMIZE)

# Add constraints
m.addConstr(x1 + x2 >= 50, "total_workers")
m.addConstr(x2 >= 30, "min_developers")
m.addConstr(x1 >= (1/3)*x2, "researcher_to_developer_ratio")
m.addConstr(2500*x1 + 1500*x2 <= 250000, "max_payroll")

# Optimize the model
m.optimize()

# Print the solution
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Number of researchers: {x1.x}")
    print(f"Number of developers: {x2.x}")
    print(f"Total wages: ${2500*x1.x + 1500*x2.x:.2f}")
else:
    print("No optimal solution found")
```