Organizations of all sizes are increasingly turning to AI agents and multi-agent frameworks to build dependable, scalable, and well-managed solutions. However, without deliberate oversight, the expenses tied to AI agents and large language models (LLMs) can escalate rapidly. In this article, we explore common challenges in agent planning and cost control, reframing them as operations research problems approached through a data science perspective. For a deeper dive into Agent Planning and Agentic AI, see my piece titled “How to Build Your Own Agentic AI System Using CrewAI.”
What Does Optimization Mean in Operations Research?
Operations research applies mathematical modeling and optimization techniques to identify the optimal decision within real-world limitations. It forms the foundation of prescriptive analytics—the discipline that converts predictive insights into actionable strategies essential for effective decision-making. Translating a real-world challenge into a formal mathematical representation is the critical first step in tackling any operations research problem.
A well-known illustration of operations research is the linear programming problem, where the goal is to determine values for variables like x and y that maximize a linear expression (such as 2x + 4y), while satisfying constraints like x ≥ 0 and y ≥ 0. Most operations research problems consist of three core elements:
Decision Variables: The unknowns we aim to solve for.
Constraints: Practical limits on available resources or mandatory requirements.
Objectives: The metric we seek to maximize or minimize.
Optimizing Agent Costs and Resource Distribution
Planning for AI agents requires allocating resources within a defined budget while still achieving optimal results—making it a natural candidate for operations research methods. We can align the fundamental elements above with real-world agent cost and resource planning challenges.
Decision Variables: Which agents are assigned to specific tasks or projects
Constraints: Budget limits, response time targets, token usage caps
Objectives: Reduce costs, boost return on investment
We’ll apply four widely used optimization frameworks to tackle typical agent planning situations:
Set-Covering Problem: Identify the fewest agents needed to cover all necessary tasks, skills, or business functions—minimizing cost while ensuring no capability gaps remain.
Assignment Problem: Determine the best agent for each project to maximize total output value.
Knapsack Problem: Choose the most effective combination of agents within a fixed budget to maximize total token output.
Network Problem: Structure workflows across interconnected agents to fulfill departmental and user needs at minimal cost, respecting capacity limits.
To bring these concepts to life, we’ll walk through four Python examples using the Gurobi library. Gurobi is a high-performance mathematical optimization solver designed for enterprise use, supporting various problem types such as linear programming and mixed-integer programming. It’s commonly used as the computational engine behind operations research tools because it efficiently handles large-scale models and offers user-friendly APIs—including Python—for specifying decision variables, constraints, and objective functions. With Gurobi, data scientists can concentrate on building models rather than coding custom solvers from scratch. Note: this article is not sponsored by Gurobi, and all features discussed are accessible under its free license. All datasets used here are synthetic and intended solely for demonstration purposes.
1. Set-Covering Problem – Agent Skill Coverage
The set-covering problem is a classic optimization challenge focused on selecting the smallest possible group of options such that every required item is accounted for at least once. A practical AI agent cost-optimization use case that aligns with this pattern is skill coverage—where the objective is to determine the minimum number of agents needed to provide all essential skills required for the company’s daily operations.
Problem Statement: The company plans to integrate agents into its daily workflows and must cover the nine skill areas listed in the “Skill Area” table below. Each agent costs $20,000 to develop and possesses a unique set of skills detailed in the “Agent Skill” table. How can the company minimize total development costs while ensuring every skill area is fully covered?
Skill Area
Agent Skill
Implementation
We can model this as an optimization problem following the set-covering approach and solve it using the Gurobi library. The solution is structured around five key components: data, model, variables, constraints, and objectives.
Data: Load the datasets for skills, agents, agent-skill mappings, and agent costs (set at $20k per agent)
## data
skills = data["skills"]
agents = data["agents"]
agent_skills = data["agent_skills"]
agent_costs = {i: 20 for i in agents}
Model: Initialize a Gurobi model named “Set Covering.” If you haven’t installed gurobipy yet, run the command
## model
import gurobipy as gp
model = gp.Model("Set Covering")
Variables: Define binary decision variables for each agent, bounded between 0 and 1, indicating whether the agent is selected (1) or not (0). Gurobi provides several built-in variable types, including GRB.BINARY, GRB.INTEGER, and GRB.CONTINUOUS.
## variables
X = model.addVars(agents, lb=0, ub=1, vtype=GRB.BINARY,
## variables
from gurobipy import GRB
X = model.addVars(agents, projects, lb=0, ub=1, vtype=GRB.BINARY, name="x")
Constraints: Each skill area must have at least one qualified agent assigned to it, guaranteeing full coverage. We apply the gp.quicksum function to build these constraints through a loop over all nine skill areas.
## constraints: for each skill area, at least one agent with that skill must be selected
for j in skills:
model.addConstr(
gp.quicksum(X[i] for i in agents if j in agent_skills[i]) >= 1,
name=f'{j}_area_constr'
)
Objective: Reduce the overall expense of chosen agents, determined by the weighted sum of each agent's cost times the binary selection indicator.
## objective: minimize total cost of selected agents
model.setObjective(
gp.quicksum(agent_costs[i] * X[i] for i in agents),
GRB.MINIMIZE
)
Finally, execute the optimization by calling model.optimize().
Business Impact
Here, we analyze the model's best solution and assess how it compares to random decision-making. This allows business leaders to make informed choices about which agents to develop, implement, or phase out.
Optimal Result
model.ObjVal displays the best objective value. For every binary decision variable, we check X[i].X > 0.5 to identify which agents were chosen.
print(f"Total agents selected: {round(model.ObjVal, 4)}")
for i in agents:
if X[i].X > 0.5:
print(f"Agent {i} selected.")
Claude Code also recommended this alternative snippet for a clearer presentation of results.
print("================ Set-Covering: Skill Coverage ================")
if model.Status == GRB.OPTIMAL:
selected = [i for i in agents if X[i].X > 0.5]
print(f"Minimum agents needed : {len(selected)}")
print(f"Total cost : ${model.ObjVal:.0f}k")
print("nSelected agents:")
for agent in selected:
covered = ", ".join(
f"{s}({skill_labels[s]})" for s in agent_skills[agent]
)
print(f" - {agent} [{covered}]")
else:
print("No optimal solution found.")
The output below reveals that the ideal plan is to pick 4 agents (General Support Agent, Access & Permissions Agent, CRM Agent, and Cost & Performance Optimization Agent) to cover all skills within an $80k budget.
We ran simulations of random selections and compared them against the optimal outcome. As illustrated below, 500 feasible agent selections (blue histogram) were generated, with costs between $80k and $200k and an average of $134.6k (blue dotted line). This indicates that optimization enables the business to cut costs by ($134.6k − $80k)/$134.6 = 40.6% on average.
──────────────────────────────────────────────────
Set Covering — Skill Coverage
──────────────────────────────────────────────────
Minimum (Optimal) : 80.00 k$
Sim mean : 132.88 k$
Sim min : 80.00 k$
Sim max : 220.00 k$
Feasible solutions : 500/500
──────────────────────────────────────────────────
Explore the complete implementation in our GitHub repo.
2. Assignment Problem – Agent Resource Allocation
The Assignment Problem is a classic approach for matching tasks to people or objects, typically in one-to-one or one-to-many setups, aiming to maximize output or minimize cost. Agent resource allocation fits this framework, as it involves distributing agents across projects, usually with the rule that each project gets one primary agent, and the goal is to achieve the highest total output value.
Problem Statement: The company has developed a group of agents to handle 9 projects, and each project needs one primary agent. The table below shows the value each agent brings to each project. How can the company maximize total value by assigning the most suitable primary agent to each project?
Implementation
We follow the same six-step process to break down this assignment problem.
Data: Load the data for agents, projects, and values. Create a value_map dictionary to represent the relationship between agents and projects.
## data
agents = data["agents"]
projects = data["projects"]
values = data["values"]
# Build value lookup: (agent, project) -> score
value_map = {
(agents[i], projects[j]): values[i][j]
for i in range(len(agents))
for j in range(len(projects))
}
Model: Set up a Gurobi model named "Assignment".
## model
import gurobipy as gp
model = gp.Model("Assignment")
Variables: The decision variables here indicate whether an agent is assigned to a project, represented as a binary variable for each unique agent-project pair.
## variables
from gurobipy import GRB
X = model.addVars(agents, projects, lb=0, ub=1, vtype=GRB.BINARY, name="x")
Constraints: For each project, the total of all assigned agents should equal exactly one. For each agent, the total of projects it is assigned to should be at least one.
## constraints: each project is assigned exactly one agent
for j in projects:
model.addConstr(
gp.quicksum(X[(i, j)] for i in agents) == 1,
name=f"{j}_project_constr",
)
## constraints: each agent is assigned at least one project
for i in agents:
model.addConstr(
gp.quicksum(X[(i, j)] for j in projects) >= 1,
name=f"{i}_agent_constr",
)
Objective: Maximize the overall value score using the sum of each agent's score on each project multiplied by the decision variable indicating whether the agent is assigned to the project.
## objective: maximize the overall value score
model.setObjective(
gp.quicksum(value_map[(i, j)] * X[(i, j)] for i in agents for j in projects),
GRB.MAXIMIZE,
)
Business Impact
By framing agent allocation as an assignment problem, businesses can allocate agents to projects in a way that best matches their skills and maximizes overall value. This improves return on investment by increasing output quality while achieving business objectives with the same set of pre-built agents.
To understand the business impact of this optimization scenario, we will first interpret the recommended allocation after running model.optimize(), then estimate the impact on the overall value score by comparing the optimal result with random allocations.
Optimal Result
model.ObjVal prints out the optimal objective value. For each binary variable that indicates agent allocation, we use X[i, j].X > 0.5 to examine if agent i is allocated to project j.
print(f"Total value: {round(model.ObjVal, 4)}")
for i in agents:
for j in projects:
if X[(i, j)].X > 0.5:
print(f"Agent {i} should be allocated to Project {j}.")
OR use the following snippet to display the model output more verbosely.
print("================ Assignment Problem: Resource Allocation ================")
if model.Status == GRB.OPTIMAL:
print(f"Maximum total suitability score: {model.ObjVal:.0f}n")
print(f"{'Agent':<45} {'Project':<6} {'Description':<30} {'Score'}")
print("-" * 95)
for i in agents:
for j in projects:
if X[(i, j)].X > 0.5:
print(
f"{i:<45} {j:<6} {project_labels[j]:<30} {obj_coeffs[(i, j)]}"
The output below shows the optimal resource allocation, which assigns one primary agent to each project and achieves a total suitability score of 77.
We simulated 500 random, feasible agent allocations and compared them with the optimal outcome, where the value score is 77. As shown below, the 500 feasible allocations produced overall value scores ranging from 55 to 72, with a mean value score of 63.16. This indicates that optimization improves value scores by (77 − 63.16) / 63.16 = 21.9% on average.
──────────────────────────────────────────────────
Assignment — Agent-to-Project Allocation
──────────────────────────────────────────────────
Maximum (Optimal) : 77.00 score
Sim mean : 63.16 score
Sim min : 55.00 score
Sim max : 72.00 score
Feasible solutions : 500/500
──────────────────────────────────────────────────
3. Knapsack Problem – Agent Budgeting
The knapsack Problem is an optimization scenario where we pick the best combination of items while staying within a limit, like a budget or capacity constraint. Portfolio management and logistics arrangement are popular real-world implications. It is suitable for agent budget allocation scenarios where we need to maximize the agent output under a limited company budget.
Problem Statement: Given a $4,000 monthly budget, select agents from the list below, each with a fixed monthly cost, to maximize total tokens generated.
Implementation
Again, use the 6-step process to break down this knapsack problem.
Data: load the agent list, each agent's monthly cost, and each agent's token output, along with a fixed $4,000 monthly budget.
## data
agents = data["agents"]
N = range(len(agents)) # number of agents
C = data["costs"] # cost per agent
P = data["tokens"] # tokens per agent
K = 4000 # $4000 monthly budget
Model: Create a Gurobi model with the name "Knapsack".
## model
import gurobipy as gp
model = gp.Model("Knapsack")
Variables: A binary decision variable is associated with each
Variables: For each arc, define a continuous variable representing the volume of requests transferred between nodes, capped at the arc's maximum capacity.
Constraints: At every node, ensure that the total incoming flow plus any local supply equals the total outgoing flow plus any local demand.
## constraints: flow conservation at each node
for node in nodes:
inflow = gp.quicksum(flow[i, j] for i, j in arcs if j == node)
outflow = gp.quicksum(flow[i, j] for i, j in arcs if i == node)
model.addConstr(
inflow + supplies.get(node, 0) == outflow + demands.get(node, 0),
name=f"flow_constr_{node}",
)
Objective: Minimize the total routing cost across all arcs.
## objective: minimize total routing cost
model.setObjective(
gp.quicksum(costs[i, j] * flow[i, j] for i, j in arcs),
GRB.MINIMIZE,
)
Business Impact
Network optimization is essential for businesses managing complex distribution or workflow systems, as it identifies the most economical way to move tasks or goods from sources to destinations. We will evaluate the optimized routing plan against 500 randomly generated feasible routing configurations under identical constraints.
Optimal Result
After executing model.optimize(), we retrieve the minimal total cost via model.ObjVal. For each arc, we inspect flow[i, j].X to determine the actual number of requests routed along that connection.
print(f"Minimum total cost: ${round(model.ObjVal, 2)}")
for i, j in arcs:
if flow[i, j].X > 0:
print(f"Route {i} → {j}: {round(flow[i, j].X)} requests")
The optimal solution routes requests through agent hubs whenever possible, leveraging their lower per-request costs, while respecting capacity limits on each link.
================ Network Problem: Agent Routing ================
Minimum total cost: $48,200
Route Requests Cost/Req Total Cost
---------------------------------------------------------------
Coding Agent → Hub A 4,000 $3 $12,000
Writing Agent → Hub B 3,500 $4 $14,000
Hub A → IT Department 2,500 $5 $12,500
Hub A → Operations 1,500 $6 $9,000
Hub B → Marketing 3,500 $2 $7,000
---------------------------------------------------------------
TOTAL 15,000 $48,200
Simulations
We generated 500 random but feasible routing plans under the same capacity and demand constraints and compared them with the optimal cost of $48,200. Across simulations, total costs ranged from $48,200 to $89,500, averaging $67,840—meaning the optimized plan achieves roughly (67,840 − 48,200) / 67,840 = 28.9% savings compared to the average random configuration.
──────────────────────────────────────────────────
Network — Agent Routing Optimization
──────────────────────────────────────────────────
Minimum (Optimal) : $48,200
Sim mean : $67,840
Sim min : $48,200
Sim max : $89,500
Feasible solutions: 500/500
──────────────────────────────────────────────────
## variables
X = model.addVars(arcs, lb=0, ub=capacities, vtype=GRB.CONTINUOUS, name="x")
Constraints: At every node — whether it's an agent, an agent hub, or a department — the total incoming supply and flow must equal the total outgoing demand and flow.
## constraints: flow balance at each node
for i in nodes:
model.addConstr(
supplies[i] + gp.quicksum(X[(j, i)] for j in nodes if (j, i) in arcs)
== demands[i] + gp.quicksum(X[(i, j)] for j in nodes if (i, j) in arcs),
name=f"{i}_balance_constr",
)
Objective: Minimize the total cost of routing all requests from agents to agent hubs or directly to departments.
## objective: minimize total routing cost
model.setObjective(
gp.quicksum(costs[(i, j)] * X[(i, j)] for i, j in arcs),
GRB.MINIMIZE,
)
Business Impact
Agent routing optimization determines how many requests to route through each connection so that all department demand is satisfied at the lowest possible cost, while respecting workflow capacity and system constraints.
Optimal Result
We use model.ObjVal to retrieve the optimal total cost. Then we use X[(i,j)].X to display the volume of requests flowing from each source node to each destination node.
print(f"Total Cost: {round(model.ObjVal, 2)}")
for (i,j) in arcs:
if X[(i,j)].X > 0:
print(f"Send {X[(i,j)].X} units of flow on the arc from {i} to {j}")
As the output below shows, the optimal solution costs $5,630 per month to fulfill the 12,000 requests demanded by the Marketing, IT, and Operations departments.
================ Network Routing Problem: Agent Routing ================
Minimum total routing cost: $5,630.00
Arc Flow Cap Cost/req Total Cost
-------------------------------------------------------------------------------------
Coding Agent -> Marketing Dept 1500 2000 0.80 1,200.00
Coding Agent -> IT Dept 2000 2000 0.60 1,200.00
Coding Agent -> Operations Dept 1200 1200 0.30 360.00
Coding Agent -> Relay Hub A 1200 1500 0.30 360.00
Coding Agent -> Relay Hub B 600 1200 0.20 120.00
Writing Agent -> Marketing Dept 2000 2000 0.50 1,000.00
Writing Agent -> IT Dept 1000 1000 0.20 200.00
Writing Agent -> Operations Dept 1000 1000 0.20 200.00
Writing Agent -> Relay Hub A 300 2000 0.40 120.00
Writing Agent -> Relay Hub B 1200 1200 0.20 240.00
Relay Hub A -> Marketing Dept 1500 1500 0.30 450.00
Relay Hub B -> IT Dept 1000 1000 0.10 100.00
Relay Hub B -> Operations Dept 800 1000 0.10 80.00
Demand fulfillment:
Marketing Dept: received 5000 / needed 5000
IT Dept: received 4000 / needed 4000
Operations Dept: received 3000 / needed 3000
Simulations
After generating 500 feasible solutions using random request routing from agents to departments, we estimate that the optimal result cuts costs by 33% on average ($8,425.98 − $5,630.00 = $2,795.98).
──────────────────────────────────────────────────
Network — Agent Routing
──────────────────────────────────────────────────
Minimum (Optimal) : $5,630.00
Sim mean : $8,425.98
Sim min : $5,750.00
Sim max : $11,150.00
Feasible solutions : 500/500
──────────────────────────────────────────────────
Take Home Message
In this article, we explored four common optimization patterns in operations research and their real-world business impact, using AI agent planning scenarios:
Set Covering: Pick the smallest group of agents that still covers every required task, skill, or business function — minimizing cost while ensuring no capability gaps.
Assignment: Match each project to the right agent, aiming to maximize the total output value.
Knapsack: Choose the best combination of agents or features within a fixed budget to maximize total output tokens.
Network: Design workflows across a network of agents to meet department and user demand at the lowest cost, subject to capacity limits.
Complex agent planning becomes manageable when it's expressed as a standard optimization model with variables, constraints, and an objective. Modern solvers like Gurobi can rapidly find optimal solutions that meaningfully reduce spending or boost return on investment.