当获准的 AI Agent 任务需要执行出站策略、选择区域出口、在多步骤浏览器会话中保持同一网络身份、分配独立任务或记录网络遥测时,才需要代理。没有网络工具的纯文本 Agent 不需要代理。代理是一项基础设施控制,不代表可以绕过访问控制。
“AI Agent 代理”是什么意思?
正向代理位于 Agent 运行环境与目标服务之间。Agent 将 HTTP、HTTPS 或 SOCKS 流量交给代理,再由代理代表它连接目标。对于 HTTPS,HTTP CONNECT 方法可通过中间节点建立隧道。
- 执行目标域名白名单和出站策略。
- 为合法的本地化或可用性测试选择地域出口。
- 为有状态的浏览器会话保持稳定 IP。
- 将相互独立的任务分配到健康的出口池。
- 统计连接延迟、状态码和失败率。
代理不会自动让 Agent 匿名、合规或稳定。目标服务仍可能观察浏览器指纹、账户行为、Cookie、请求节奏以及应用层标识。
选择接入模式
下表描述的是常见生态接入模式。MIYAIP 提供代理连接能力;这张表并不表示所有托管 API、远程浏览器或 MCP 实现都是 MIYAIP 产品功能。请以实际服务的接口和会话行为为准。
接入方式 | 适用情况 | 会话控制 | 仍由你负责的事项 |
|---|---|---|---|
原始 HTTP(S) 或 SOCKS 代理 | HTTP 客户端或浏览器已有代理设置,并且需要直接控制 | 凭证、端口或供应商定义的会话键 | 客户端生命周期、重试、解析、速率限制与可观测性 |
托管抓取 API | 希望通过请求 API 完成抓取,并可能由服务处理渲染 | API 自己的请求或会话标识 | 确认供应商行为、数据权利、目标策略和结果质量 |
远程浏览器 | 希望由服务托管浏览器进程并暴露控制端点 | 浏览器实例或远程上下文标识 | Cookie 隔离、任务边界、允许访问的目标和资源清理 |
MCP 工具 | Agent 应通过标准工具接口调用受约束的网络能力 | 由 MCP Server 与下游服务共同定义 | 工具权限、输入校验、目标策略、密钥与审计日志 |
为什么 AI Agent 需要明确的代理策略
Agent 会反复调用工具,也可能受到意外输入或恶意内容影响。OpenAI Agents SDK 文档将工具描述为 Agent 获取数据、调用 API、运行代码或使用计算机的机制。OWASP 关于“过度代理权”的指南则提醒:过宽的工具权限可能把含糊或被操纵的模型输出转化为有害操作。
因此,网络路由本身就是一项策略决策。成熟的代理层应在请求离开环境前确认目标是否获准、应使用哪个身份与会话、适用怎样的重试和速率策略,以及哪些遥测信息可以安全记录。
参考架构
生产系统通常将决策与传输分离:Agent 选择经过批准的浏览器或 HTTP 工具;出站策略服务校验目标、任务和租户;代理网关根据路由键选择上游出口;指标返回编排层,但不向模型暴露代理凭证。
可以使用 tenant_id + workflow_id + session_id 作为稳定路由键。这样既能保持网络身份一致,也能让编排层重试或恢复任务。代理用户名和密码应保存在密钥管理系统中,只在运行时注入,绝不能出现在提示词、追踪记录、截图或工具输出中。
代理是传输与策略边界,不是验证码绕过器、授权绕过器,也不代表可以忽略网站条款。
如何选择代理类型
数据中心代理
数据中心出口通常是 API 调用、公开数据集、测试和高吞吐任务的首选。它速度快、成本可控、易于监测。当目标确实需要消费网络特征,或其风控系统会区别对待共享托管网段时,它可能不适合。
静态 ISP 代理
静态 ISP 出口兼具固定地址和 ISP 关联网络,适合需要稳定地域与身份的长期授权会话。应把它视为稀缺的会话资源,并监控账户与 IP 的绑定关系。
住宅或移动代理
只有当合法业务确实需要终端用户网络特征时才应使用,例如经过授权的本地化测试或区域 QA。供应商来源、用户同意、司法辖区、数据保留政策和可接受使用规则,比 IP 池规模更重要。
轮换与粘性会话
轮换适用于彼此独立、无状态的任务。登录、购物车、多步骤表单,以及任何依赖 Cookie 或服务端连续性判断的流程,更适合粘性会话。应在任务之间轮换,而不是在一次交易进行到一半时更换出口。
任务内与任务间的会话策略
使用模型无法随意编造的标识生成稳定会话键。在同一个有状态任务中,包括有限重试,都保持这个键不变;无关的新任务使用新键。只有获准工作流确实需要同一账户和网络身份时,才跨任务延续会话,并设置明确的过期时间。
tenant_acme + workflow_checkout + task_8472 -> session_6f2a…
步骤 1:打开商品页 -> session_6f2a…
步骤 2:加入购物车 -> session_6f2a…
步骤 2 有限重试一次 -> session_6f2a…
下一个独立任务 -> session_b91c…
恢复获准的任务 8472 -> session_6f2a…,直到过期- 同一个有状态任务内:复用相同的代理会话、浏览器上下文、Cookie 和路由键。
- 相互独立的任务之间:创建新会话,避免失败和状态在任务间泄漏。
- 恢复获准任务时:在提示词之外保存会话引用,加密浏览器状态,并让两者同时过期。
真正影响可靠性的模式
仅仅轮换代理并不能带来可靠性。应围绕每个出口建立反馈闭环:
- 分别设置连接、TLS、响应和任务总超时。
- 只重试可能属于暂时性的错误;对 429 和部分 5xx 响应使用有上限的指数退避与随机抖动。
- 遵循 Retry-After,配置熔断器,并按成功率、延迟和挑战信号给出口评分。
- 重试写操作时保留幂等键,并限制每个任务的尝试次数。
不要通过不断更换 IP 来重试认证失败、策略拒绝或确定性的校验错误。这会掩盖真正的问题,也可能放大滥用行为。
浏览器 Agent:最小 Playwright 示例
Playwright 可以在浏览器启动时应用 HTTP(S) 或 SOCKSv5 代理。这个经过实测的模式使用一个启动级代理和一个浏览器上下文,让三步任务中的出口线路、Cookie 和浏览器状态保持一致。
安装依赖并设置运行环境
npm install playwright@1.61.1
$env:PROXY_SERVER = "http://[redacted-proxy-host]:[redacted-port]"
$env:PROXY_USERNAME = "[redacted-user]"
$env:PROXY_PASSWORD = "[redacted-password]"
$env:TARGET_URL = "https://example.com/"
node .\agent-proxy-example.mjsimport { chromium } from "playwright";
const required = ["PROXY_SERVER", "PROXY_USERNAME", "PROXY_PASSWORD", "TARGET_URL"];
for (const name of required) {
if (!process.env[name]) throw new Error(`Missing ${name}`);
}
const target = new URL(process.env.TARGET_URL);
const allowedHosts = new Set(["example.com"]); // replace with approved destinations
if (target.protocol !== "https:" || !allowedHosts.has(target.hostname)) {
throw new Error("Target is not allowlisted");
}
const redactIp = (value) => value.includes(".")
? value.replace(/\.\d+$/, ".xxx")
: `${value.split(":").slice(0, 4).join(":")}::`;
const startedAt = performance.now();
let retries = 0;
let status = 0;
let steps = 0;
let outcome = "failed";
let browser;
try {
browser = await chromium.launch({
channel: "chrome",
headless: true,
proxy: {
server: process.env.PROXY_SERVER,
username: process.env.PROXY_USERNAME,
password: process.env.PROXY_PASSWORD,
},
});
const context = await browser.newContext();
try {
const page = await context.newPage();
page.setDefaultTimeout(15_000);
const readExitIp = async () => {
const response = await page.goto("https://api.ipify.org?format=json", {
waitUntil: "domcontentloaded",
timeout: 20_000,
});
if (!response?.ok()) throw new Error(`Exit check failed: ${response?.status()}`);
steps += 1;
return String((await response.json()).ip ?? "unavailable");
};
const firstExitIp = await readExitIp();
for (let attempt = 0; attempt < 2; attempt += 1) {
const response = await page.goto(target.href, {
waitUntil: "domcontentloaded",
timeout: 30_000,
});
status = response?.status() ?? 0;
if (status !== 429 && status < 500) break;
if (attempt === 1) throw new Error(`Target remained transiently unavailable: ${status}`);
retries += 1;
const retryAfter = Number(response?.headers()["retry-after"] ?? 1);
await page.waitForTimeout(Math.min(Math.max(retryAfter, 1), 10) * 1_000);
}
steps += 1;
const result = {
title: await page.title(),
heading: await page.locator("h1").first().textContent(),
};
result.titleMatchesHeading = result.title === result.heading;
const secondExitIp = await readExitIp();
const sameExitAcrossTask = firstExitIp === secondExitIp;
outcome = status >= 200 && status < 400 ? "success" : "failed";
console.log({
outcome,
status,
steps,
retries,
durationMs: Math.round(performance.now() - startedAt),
exitIp: redactIp(firstExitIp),
sameExitAcrossTask,
result,
});
} finally {
await context.close();
}
} catch (error) {
console.error({
outcome,
status,
steps,
retries,
durationMs: Math.round(performance.now() - startedAt),
error: String(error),
});
process.exitCode = 1;
} finally {
await browser?.close();
}每个逻辑会话保持一个浏览器上下文,每条代理线路使用一次独立的浏览器启动。不要在客户之间共享 Cookie,也不要让模型自行选择任意代理端点或凭证。
请通过 PowerShell 或密钥管理系统设置四个环境变量。白名单会拒绝任意目标。代理配置位于 chromium.launch,因此同一浏览器中的所有 context 都使用相同代理;需要更换代理线路时应启动新的浏览器,每个逻辑会话则保持一个 context。
{
"recordedAt": "2026-09-05T08:46:48Z",
"runtime": "Node.js 22.18.0",
"playwright": "1.61.1",
"browser": "Chrome",
"outcome": "success",
"status": 200,
"steps": 3,
"retries": 0,
"durationMs": 7322,
"exitIp": "[redacted-ip]",
"sameExitAcrossTask": true,
"result": {
"title": "Example Domain",
"heading": "Example Domain",
"titleMatchesHeading": true
}
}故障处理与安全日志字段
信号 | 处理动作 | 重试或会话规则 |
|---|---|---|
407 代理认证失败 | 停止任务,检查密钥、账户状态、端点和分配的认证模式 | 不要通过轮换 IP 或使用不变凭证反复重试 |
429 速率限制 | 遵循 Retry-After 并降低请求速率 | 只在尝试次数上限内重试;有状态任务保持同一会话 |
连接或导航超时 | 分别设置 DNS、连接、TLS 和页面超时,并检查出口健康状态 | 操作可安全重放时最多重试一次;仅在任务边界或确认出口故障后轮换 |
确定性的 4xx 或策略拒绝 | 修复请求或授权 | 不要重试 |
浏览器或解析错误 | 记录已脱敏的错误类别和失败步骤 | 只有状态可以安全重建时才重启上下文 |
建议记录时间戳、租户 ID、任务 ID、哈希后的会话或路由 ID、目标主机名、步骤、尝试次数、状态类别、duration_ms、结果和脱敏错误类别。绝不能记录代理密码、Authorization 请求头、Cookie、响应正文或带有查询密钥的完整 URL。
安全护栏
网络控制应降低提示词注入和工具误用造成的影响:
- 按工具设置目标主机、协议和端口白名单。
- 除非明确需要,否则阻断环回、链路本地、云元数据服务和私有网段,并防范 DNS 重绑定。
- 为每个 Agent 或租户发放短期代理凭证,并在模型之外执行并发和带宽限制。
- 对购买、账户变更、破坏性操作和敏感数据传输要求人工审批。
- 记录目标、策略决定、耗时、响应类别和路由 ID;避免记录正文、Cookie、授权头或原始凭证。
这些措施是模型护栏的补充,即使模型做出错误决定,网络边界仍然有效。
合规必须进入架构
在自动访问目标之前,应记录业务目的、授权依据、适用条款、速率限制、数据权利和地域限制。对于类似爬虫的行为,应评估网站公开政策和 Robots Exclusion Protocol。robots.txt 不能替代授权或法律,但它是自动化客户端应正确处理的标准化信号。
NIST AI 风险管理框架以 Govern、Map、Measure、Manage 四项职能组织风险工作。映射到 Agent 网络系统,就是明确责任人、梳理目标与数据流、度量失败和影响,并维护响应计划。
上线检查清单
- 定义允许访问的目标和任务目的;根据工作流选择代理类型,而不是根据营销话术。
- 为每个有状态会话绑定一个路由键,并隔离租户、Cookie 和浏览器存储。
- 在网关和目标两个层面执行速率限制;仅对合适的错误重试,并设置退避、抖动和次数上限。
- 监控出口健康状态,配置熔断器和默认拒绝的失败模式。
- 审核供应商来源、用户同意、保留政策、司法辖区、事件响应和凭证轮换。
结论
最适合 AI Agent 的代理,并不等于拥有最大的 IP 池。它应匹配工作流对身份和地域的需求,提供可度量的可靠性,支持最小权限凭证,并让运维人员能够执行明确的策略控制。先从小规模白名单架构开始,把会话行为定义清楚,在指标和治理成熟后再扩展。
