引言
Agent 不是孤立的——多个用户同时请求、多个工具并行执行、多个 Agent 协作完成任务。并发控制确保这些并行活动不互相干扰、不超出资源限制、不产生数据竞争。2026年,随着 Agent 集群规模扩大到数百实例,并发控制从单机问题升级为分布式问题。
一、Agent 并发的四个层次
┌──────────────────────────────────────────────────┐
│ Agent 并发控制层次 │
├──────────────────┬───────────────────────────────┤
│ 请求级 │ 多用户并发请求 │
│ (Request) │ → 限流 + 队列 + 优先级 │
├──────────────────┼───────────────────────────────┤
│ Agent级 │ 单用户多Agent实例 │
│ (Agent) │ → 信号量 + 状态隔离 │
├──────────────────┼───────────────────────────────┤
│ 工具级 │ 多工具并行调用 │
│ (Tool) │ → 并发限制 + 超时控制 │
├──────────────────┼───────────────────────────────┤
│ 资源级 │ 共享资源访问 │
│ (Resource) │ → 分布式锁 + 乐观锁 │
└──────────────────┴───────────────────────────────┘
二、请求级并发控制
2.1 多维限流器
import asyncio
import time
from collections import defaultdict
class MultiDimensionRateLimiter:
"""多维度限流器"""
def __init__(self, redis_client):
self.redis = redis_client
async def check(
self,
user_id: str,
agent_name: str,
limits: dict
) -> bool:
"""多维度限流检查
limits = {
"qps": 10, # 每秒请求数
"concurrent": 5, # 最大并发
"daily_tokens": 500000, # 日Token上限
"monthly_cost": 100, # 月成本上限
}
"""
checks = []
# QPS 限流(滑动窗口)
if "qps" in limits:
checks.append(self._check_sliding_window(
f"qps:{user_id}:{agent_name}",
limits["qps"],
window=1
))
# 并发限流
if "concurrent" in limits:
checks.append(self._check_concurrent(
f"conc:{user_id}:{agent_name}",
limits["concurrent"]
))
# Token 配额
if "daily_tokens" in limits:
checks.append(self._check_quota(
f"tokens:{user_id}:{date.today()}",
limits["daily_tokens"]
))
results = await asyncio.gather(*checks)
return all(results)
async def _check_sliding_window(
self,
key: str,
limit: int,
window: int
) -> bool:
"""滑动窗口限流"""
now = time.time()
pipe = self.redis.pipeline()
# 移除窗口外的记录
pipe.zremrangebyscore(key, 0, now - window)
# 添加当前请求
pipe.zadd(key, {str(uuid.uuid4()): now})
# 统计窗口内请求数
pipe.zcard(key)
# 设置过期时间
pipe.expire(key, window * 2)
results = await pipe.execute()
count = results[2]
if count > limit:
# 移除刚添加的记录
pipe.zrem(key, str(uuid.uuid4()))
return False
return True
async def _check_concurrent(self, key: str, limit: int) -> bool:
"""并发数限流"""
current = await self.redis.incr(key)
if current == 1:
await self.redis.expire(key, 300) # 5分钟自动过期
if current > limit:
await self.redis.decr(key)
return False
return True
async def release_concurrent(self, key: str):
"""释放并发槽"""
await self.redis.decr(key)
class PriorityRequestQueue:
"""优先级请求队列"""
def __init__(self, max_concurrent: int = 100):
self.semaphore = asyncio.Semaphore(max_concurrent)
self.queues = {
"high": asyncio.Queue(maxsize=50),
"normal": asyncio.Queue(maxsize=500),
"low": asyncio.Queue(maxsize=1000),
}
self._running = True
async def submit(
self,
request: Request,
priority: str = "normal"
) -> Response:
"""提交请求"""
queue = self.queues.get(priority, self.queues["normal"])
if queue.full():
raise QueueFullError(f"{priority} queue is full")
future = asyncio.Future()
await queue.put((request, future))
# 启动消费者(如果未启动)
asyncio.create_task(self._consume())
return await future
async def _consume(self):
"""消费请求:按优先级调度"""
async with self.semaphore:
# 按优先级获取请求
for priority in ["high", "normal", "low"]:
queue = self.queues[priority]
if not queue.empty():
request, future = await queue.get()
try:
result = await self._process(request)
future.set_result(result)
except Exception as e:
future.set_exception(e)
return
# 所有队列为空
await asyncio.sleep(0.01)
三、工具级并发控制
3.1 并行工具调用管理
class ParallelToolExecutor:
"""并行工具调用管理器"""
def __init__(self):
self.tool_limits = {} # {tool_name: Semaphore}
self.global_limit = asyncio.Semaphore(10)
def register_tool(
self,
name: str,
max_concurrent: int = 5,
timeout: float = 30.0
):
"""注册工具并发限制"""
self.tool_limits[name] = {
"semaphore": asyncio.Semaphore(max_concurrent),
"timeout": timeout
}
async def execute_parallel(
self,
tool_calls: list[ToolCall]
) -> list[ToolResult]:
"""并行执行多个工具调用"""
tasks = []
for call in tool_calls:
task = asyncio.create_task(
self._execute_single(call)
)
tasks.append(task)
# 等待所有完成,设置全局超时
results = await asyncio.gather(*tasks, return_exceptions=True)
return [
result if not isinstance(result, Exception)
else ToolResult(success=False, error=str(result))
for result in results
]
async def _execute_single(self, call: ToolCall) -> ToolResult:
"""执行单个工具调用(带并发限制和超时)"""
tool_limit = self.tool_limits.get(call.tool)
if not tool_limit:
raise UnknownToolError(call.tool)
# 双重信号量:全局 + 工具级
async with self.global_limit:
async with tool_limit["semaphore"]:
try:
result = await asyncio.wait_for(
self._call_tool(call),
timeout=tool_limit["timeout"]
)
return ToolResult(success=True, data=result)
except asyncio.TimeoutError:
return ToolResult(
success=False,
error=f"Tool {call.tool} timed out"
)
# 注册工具并发限制
executor = ParallelToolExecutor()
executor.register_tool("web_search", max_concurrent=5, timeout=10)
executor.register_tool("database_query", max_concurrent=3, timeout=15)
executor.register_tool("file_read", max_concurrent=20, timeout=5)
executor.register_tool("file_write", max_concurrent=2, timeout=10)
executor.register_tool("send_email", max_concurrent=1, timeout=30)
四、资源级并发控制
4.1 分布式锁
class DistributedLock:
"""基于 Redis 的分布式锁"""
def __init__(self, redis_client):
self.redis = redis_client
self._local_locks = {} # 本地锁缓存
async def acquire(
self,
resource: str,
holder: str,
ttl: int = 30,
timeout: float = 10.0
) -> bool:
"""获取分布式锁
Args:
resource: 锁定的资源名
holder: 持有者标识(如 agent_id + session_id)
ttl: 锁的生存时间(秒)
timeout: 等待获取锁的超时时间
"""
lock_key = f"lock:{resource}"
start = time.time()
while time.time() - start < timeout:
# 尝试获取锁(原子操作)
acquired = await self.redis.set(
lock_key, holder, nx=True, ex=ttl
)
if acquired:
# 启动看门狗续期
asyncio.create_task(self._watchdog(resource, holder, ttl))
return True
# 检查持有者是否是自己(重入)
current = await self.redis.get(lock_key)
if current == holder:
await self.redis.expire(lock_key, ttl)
return True
# 等待重试
await asyncio.sleep(0.1)
return False
async def release(self, resource: str, holder: str) -> bool:
"""释放锁(使用 Lua 脚本保证原子性)"""
lua_script = """
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
"""
result = await self.redis.eval(
lua_script, 1,
f"lock:{resource}", holder
)
return bool(result)
async def _watchdog(self, resource: str, holder: str, ttl: int):
"""看门狗:自动续期锁"""
lock_key = f"lock:{resource}"
renew_interval = ttl * 0.3 # 在30% TTL时续期
while True:
await asyncio.sleep(renew_interval)
# 检查是否仍持有锁
current = await self.redis.get(lock_key)
if current != holder:
break # 锁已被释放或被抢
# 续期
await self.redis.expire(lock_key, ttl)
class AgentResourceLock:
"""Agent 资源锁管理"""
def __init__(self, lock_manager: DistributedLock):
self.locks = lock_manager
async def with_resource_lock(
self,
resource: str,
agent_id: str,
action: callable,
ttl: int = 30
):
"""在锁保护下执行操作"""
acquired = await self.locks.acquire(
resource, agent_id, ttl=ttl
)
if not acquired:
raise LockAcquisitionError(
f"Could not acquire lock for {resource}"
)
try:
return await action()
finally:
await self.locks.release(resource, agent_id)
4.2 乐观锁
class OptimisticLock:
"""乐观锁:适用于低冲突场景"""
async def update_with_version(
self,
resource_id: str,
update_fn: callable,
max_retries: int = 3
) -> any:
"""带版本控制的更新"""
for attempt in range(max_retries):
# 1. 读取当前版本
current = await self.db.get(resource_id)
if not current:
raise NotFoundError(resource_id)
version = current.version
# 2. 计算更新
updated = await update_fn(current.data)
# 3. 乐观写入(带版本检查)
result = await self.db.update_with_version(
resource_id,
data=updated,
expected_version=version
)
if result.success:
return updated
# 版本冲突,重试
logger.warning(
f"Optimistic lock conflict on {resource_id}, "
f"attempt {attempt+1}"
)
await asyncio.sleep(0.05 * attempt) # 短暂退避
raise ConcurrencyError(
f"Failed after {max_retries} retries due to conflicts"
)
五、Agent 级并发控制
class AgentInstanceManager:
"""Agent 实例管理——控制单用户的 Agent 并发"""
def __init__(self, redis_client):
self.redis = redis_client
self.limits = {
"free": 1, # 免费用户:1个并发Agent
"pro": 5, # Pro用户:5个
"enterprise": 20, # 企业用户:20个
}
async def acquire_slot(
self,
user_id: str,
tier: str,
agent_type: str
) -> AgentSlot:
"""获取 Agent 执行槽"""
limit = self.limits.get(tier, 1)
key = f"agent_slots:{user_id}"
# 检查当前活跃数
active = await self.redis.scard(key)
if active >= limit:
raise ConcurrencyLimitError(
f"User {user_id} has {active}/{limit} active agents"
)
# 分配槽位
slot_id = str(uuid.uuid4())
await self.redis.sadd(key, slot_id)
await self.redis.expire(key, 3600) # 1小时过期
return AgentSlot(
slot_id=slot_id,
user_id=user_id,
agent_type=agent_type,
acquired_at=time.time()
)
async def release_slot(self, slot: AgentSlot):
"""释放 Agent 执行槽"""
key = f"agent_slots:{slot.user_id}"
await self.redis.srem(key, slot.slot_id)
class AgentCoordinator:
"""Agent 协调器——管理多Agent并发执行"""
async def run_agents_concurrent(
self,
agents: list[Agent],
max_parallel: int = 5
) -> list[AgentResult]:
"""并发运行多个 Agent"""
semaphore = asyncio.Semaphore(max_parallel)
async def run_one(agent: Agent) -> AgentResult:
async with semaphore:
try:
result = await agent.run()
return AgentResult(
agent_id=agent.id,
success=True,
result=result
)
except Exception as e:
return AgentResult(
agent_id=agent.id,
success=False,
error=str(e)
)
return await asyncio.gather(*[run_one(a) for a in agents])
async def run_agents_pipeline(
self,
agents: list[Agent],
dependencies: dict # {agent_id: [depends_on_ids]}
) -> dict[str, AgentResult]:
"""按依赖关系运行 Agent(拓扑排序)"""
results = {}
completed = set()
while len(completed) < len(agents):
# 找到可执行的 Agent(依赖已完成)
ready = [
agent for agent in agents
if agent.id not in completed
and all(
dep in completed
for dep in dependencies.get(agent.id, [])
)
]
if not ready:
# 检测死锁
raise DeadlockError("Dependency cycle detected")
# 并发执行就绪的 Agent
batch_results = await self.run_agents_concurrent(ready)
for result in batch_results:
results[result.agent_id] = result
completed.add(result.agent_id)
return results
六、并发控制监控
class ConcurrencyMonitor:
"""并发控制监控"""
METRICS = {
"active_requests": "当前活跃请求数",
"queue_depth": "各优先级队列深度",
"concurrent_agents": "各用户活跃Agent数",
"tool_concurrent_usage": "各工具并发使用数",
"lock_wait_time": "锁等待时间分布",
"lock_contention_rate": "锁竞争率",
"rate_limit_hits": "限流触发次数",
}
async def health_check(self) -> dict:
return {
"healthy": await self._check_health(),
"active_connections": await self._count_active(),
"queue_health": await self._check_queues(),
"lock_health": await self._check_locks(),
"alerts": await self._get_alerts(),
}
async def detect_issues(self) -> list[Issue]:
issues = []
# 检测队列堆积
for priority, queue in self.queues.items():
if queue.qsize() > queue.maxsize * 0.8:
issues.append(Issue(
severity="warning",
type="queue_backlog",
detail=f"{priority} queue at {queue.qsize()}/{queue.maxsize}"
))
# 检测锁饥饿
lock_waits = await self._get_lock_wait_times()
for resource, wait_time in lock_waits.items():
if wait_time > 5.0:
issues.append(Issue(
severity="high",
type="lock_starvation",
detail=f"{resource} lock wait: {wait_time:.1f}s"
))
# 检测限流频繁触发
rate_limit_hits = await self._get_rate_limit_hits()
for user_id, hits in rate_limit_hits.items():
if hits > 100: # 每分钟超过100次
issues.append(Issue(
severity="medium",
type="excessive_rate_limiting",
detail=f"User {user_id} hit rate limit {hits} times"
))
return issues
七、并发控制 Checklist
□ 多维限流(QPS + 并发数 + Token + 成本)
□ 优先级队列(高/中/低优先级请求隔离)
□ 工具级并发限制(不同工具有不同并发上限)
□ 全局并发限制(总并发不超过系统容量)
□ 分布式锁保护共享资源(带看门狗续期)
□ 乐观锁用于低冲突场景
□ Agent 实例数按用户等级限制
□ 依赖感知的 Agent 调度(拓扑排序)
□ 死锁检测和预防
□ 并发监控和告警
□ 队列堆积自动扩容
□ 压测验证并发上限
结语
并发控制是 Agent 系统从"能跑"到"能扛"的关键。单机时代,一个信号量就够了;分布式时代,你需要考虑锁的公平性、可重入性、死锁预防和故障恢复。最好的并发控制是"恰到好处"——限制太松会导致雪崩,限制太紧会浪费资源。通过压测找到你的系统边界,然后在那里设置护栏。记住:并发控制不是阻碍性能,而是保护性能。
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
