CAPSOLVER
博客
如何在 LangChain 中通过 CapSolver 解决 AWS WAF 问题

如何在 LangChain 中使用 CapSolver 解决 AWS WAF 问题

Logo of CapSolver

Ethan Collins

Pattern Recognition Specialist

23-Jul-2026

简要说明

  • 当请求不携带有效令牌时,AWS WAF 可能返回 202 挑战响应或 405 CAPTCHA 响应;在路由代理前,需同时检查状态码和 x-amzn-waf-action 请求头。
  • 可靠的 LangChain 工作流应将模型推理与确定性授权、挑战处理、会话存储和最终页面验证分离。
  • CapSolver 记录了基于 capsolver-core 的代理适配器,提供现成的 LangChain 工具和面向浏览器的检测与填入方法。
  • 将 cookies、凭证、解决方案令牌和浏览器对象保留在提示和代理状态之外。仅向模型提供如 resolvednot_neededreviewdenied 等小而类型化的结果。
  • 将挑战完成视为中间结果。工作流应重复执行原始请求,并在继续前验证应用特定的成功条件。
  • 下面的示例适用于自有或明确授权的系统。它们经过语法检查,但实际端到端运行仍需要经过批准的测试页面和真实凭证。

AWS WAF 如何影响 LangChain 代理

AWS WAF 挑战和 CAPTCHA 操作会改变正常的请求路径。根据 AWS WAF 操作文档,携带有效令牌的请求会继续到下一个规则。不携带有效令牌的请求可能会收到挑战响应。

对于挑战,AWS 文档记录了 x-amzn-waf-action: challenge 响应头和 HTTP 状态 202。对于 CAPTCHA,它记录了 x-amzn-waf-action: captcha 和状态 405。当客户端期望 HTML 时,AWS WAF 可能返回 JavaScript 间谍页。成功的交互会更新令牌并重新提交原始请求。

这种行为对代理很重要,因为通用 HTTP 客户端可能将响应解释为正常页面、临时服务器错误或空结果。语言模型不应猜测发生了哪种情况。主机应用应分类响应、检查授权,并通过受控恢复步骤路由工作流。

目标不是让挑战处理变得不可见。目标是使其明确、有限、可观测,并仅限于操作员拥有或获得测试权限的系统上的合法自动化。

LangChain、AWS WAF 和 CapSolver 的架构

生产设计有五个独立职责:

  1. LangChain 代理:从有限的工具集中选择下一步业务操作。
  2. HTTP 或浏览器客户端:拥有当前会话、cookies、请求头和页面状态。
  3. 策略网关:检查域名、目的、操作和重试预算。
  4. CapSolver 适配器:公开记录的识别和浏览器填入功能。
  5. 验证器:重复执行预期操作并检查应用特定的成功条件。

CapSolver 的 官方代理工具指南 描述了 capsolver-agent 作为 capsolver-core 的轻量适配器。核心包执行 solvedetectsolve_on_page 等操作;代理包提供框架友好的工具模式。其记录的 LangChain 路径通过 get_langchain_tools() 提供现成工具。

这种边界很有用。模型不需要原始凭证、令牌、浏览器对象或无限制的网络功能。它接收狭窄的工具合同,而确定性应用代码控制工具何时运行。

授权集成的先决条件

在编写代理代码之前,定义操作边界:

  • 受信任的域名白名单(自有或明确授权的);
  • 批准的用途,如 QA 验证或允许的公共数据研究;
  • CAPSOLVER_API_KEY 和模型凭证的密钥存储;
  • 一个会话所有者负责完整的请求和挑战生命周期;
  • 最大重试次数和总时间预算;
  • 证明原始操作完成的成功断言;
  • 未知域名、重复失败或状态更改操作的人工审核路径;
  • 对 cookies、令牌、凭证和页面内容的脱敏规则。

使用隔离的 Python 环境。以下安装命令遵循当前 CapSolver 代理指南:

bash 复制代码
python -m venv .venv
source .venv/bin/activate

pip install git+https://github.com/capsolver-ai/capsolver-core.git
pip install "capsolver-agent[langchain] @ git+https://github.com/capsolver-ai/capsolver-agent.git"
pip install langchain-openai langgraph playwright

playwright install chromium

将凭证存储在源代码控制之外:

bash 复制代码
export CAPSOLVER_API_KEY="set-this-in-your-secret-manager"
export OPENAI_API_KEY="set-this-in-your-secret-manager"

不要将真实密钥粘贴到提示、跟踪、笔记本、问题或检查点中。环境变量对本地示例方便;部署系统中更推荐使用托管密钥存储。

在调用工具前检测 AWS WAF 响应

第一个确定性组件应分类响应。此示例使用 AWS 记录的状态和头组合:

python 复制代码
from dataclasses import dataclass
from typing import Mapping, Literal

WafAction = Literal["challenge", "captcha", "none", "unknown"]


@dataclass(frozen=True)
class WafSignal:
    action: WafAction
    status_code: int
    needs_review: bool = False


def classify_aws_waf_response(
    status_code: int,
    headers: Mapping[str, str],
) -> WafSignal:
    normalized = {key.lower(): value.lower() for key, value in headers.items()}
    action = normalized.get("x-amzn-waf-action", "")

    if action == "challenge" and status_code == 202:
        return WafSignal(action="challenge", status_code=status_code)
    if action == "captcha" and status_code == 405:
        return WafSignal(action="captcha", status_code=status_code)
    if action in {"challenge", "captcha"}:
        return WafSignal(
            action="unknown",
            status_code=status_code,
            needs_review=True,
        )
    return WafSignal(action="none", status_code=status_code)

需要同时满足两个信号。单独的 202 可能是有效的应用响应,单独的 405 可能意味着端点不支持该 HTTP 方法。意外组合应转至审核而不是触发自动化恢复循环。

AWS 还指出,跨域运行的浏览器 JavaScript 无法读取 x-amzn-waf-action,因为该头无法通过 CORS 访问。在这种情况下,在浏览器自动化层分类网络响应,或使用同源集成。不要仅通过页面文本推断挑战。

领取您的 CapSolver 奖励代码

立即提升您的自动化预算!
在充值 CapSolver 账户时使用奖励代码 CAP26,每次充值可获得额外 5% 奖励 —— 无限制。
现在在您的 CapSolver 仪表板 中领取
奖励代码

添加确定性策略网关

挑战处理不应对模型能提及的每个 URL 都可用。在任何代理工具执行前检查目标:

python 复制代码
from dataclasses import dataclass
from urllib.parse import urlparse


@dataclass(frozen=True)
class PolicyDecision:
    allowed: bool
    reason: str


ALLOWED_HOSTS = {"staging.example.com", "research.example.org"}
ALLOWED_PURPOSES = {"qa-validation", "authorized-research"}


def authorize_recovery(
    url: str,
    purpose: str,
    attempts: int,
) -> PolicyDecision:
    host = (urlparse(url).hostname or "").lower()

    if host not in ALLOWED_HOSTS:
        return PolicyDecision(False, "host-not-allowed")
    if purpose not in ALLOWED_PURPOSES:
        return PolicyDecision(False, "purpose-not-allowed")
    if attempts >= 2:
        return PolicyDecision(False, "retry-budget-exhausted")
    return PolicyDecision(True, "authorized")

将此函数保留在语言模型之外。在生产中,从版本化配置中加载批准的主机和用途,拒绝重定向到其他主机,并仅记录非敏感决策元数据。

为 LangChain 注册 CapSolver 工具

记录的代理包可以公开 LangChain 兼容工具。最小设置如下:

python 复制代码
import os
from capsolver_agent.langchain import get_langchain_tools


capsolver_tools = get_langchain_tools(
    api_key=os.environ["CAPSOLVER_API_KEY"],
)

具体的代理构建 API 可能会随着 LangChain 和 LangGraph 的版本而变化。将 CapSolver 工具获取保留在一个小的适配器模块中,固定测试过的依赖版本,并通过这些版本支持的代理构建器连接 capsolver_tools

不要给每个代理每个工具。更安全的模式是在恢复子图或专用执行器中仅暴露挑战工具,该执行器在 authorize_recovery() 返回 allowed=True 后运行。

CapSolver 在高层次上记录了代理工具映射:

  • solve_captcha 调用核心 solve 功能;
  • detect_captchas 调用核心 detect 功能;
  • solve_on_page 调用核心 solve_on_page 功能;
  • 余额和受支持类型工具提供账户或功能信息。

仅使用集成所需的最小工具。对于实时浏览器会话,面向浏览器的检测和填入工作流通常比让模型操作原始解决方案保留更多上下文。

将浏览器会话保留在代理状态之外

AWS WAF 令牌是客户端会话的一部分。 AWS WAF 令牌文档 解释了挑战和 CAPTCHA 操作使用令牌来跟踪成功交互。在检测和重试之间更换浏览器或丢失其 cookies 会丢弃该状态。

不要将 Playwright Page 序列化到 LangChain 消息或图检查点中。将其存储在应用拥有的注册表中:

python 复制代码
class BrowserRegistry:
    def __init__(self) -> None:
        self._pages: dict[str, object] = {}

    def register(self, page_id: str, page: object) -> None:
        self._pages[page_id] = page

    def get(self, page_id: str) -> object:
        if page_id not in self._pages:
            raise KeyError("browser page is not registered")
        return self._pages[page_id]

    async def close(self, page_id: str) -> None:
        page = self._pages.pop(page_id, None)
        if page is not None:
            await page.close()

代理状态应仅包含不透明的 page_id、当前 URL、用途、尝试次数和状态。排除 cookies、本地存储、解决方案令牌、API 密钥和原始 HTML。

使用类型化结果路由 LangChain 工作流

使用小的结果类型,使模型无法重新解释低级响应:

python 复制代码
from typing import Literal, TypedDict

RecoveryStatus = Literal[
    "not_needed",
    "authorized",
    "resolved",
    "retry",
    "review",
    "denied",
]


class RecoveryState(TypedDict, total=False):
    request_id: str
    purpose: str
    current_url: str
    page_id: str
    attempts: int
    waf_action: str
    recovery_status: RecoveryStatus
    error_code: str | None
    final_assertion_passed: bool


def route_after_detection(state: RecoveryState) -> str:
    if state.get("waf_action") not in {"challenge", "captcha"}:
        return "continue"
    if state.get("recovery_status") == "authorized":
        return "recover"
    if state.get("recovery_status") in {"denied", "review"}:
        return "human_review"
    return "authorize"


def route_after_recovery(state: RecoveryState) -> str:
    status = state.get("recovery_status")
    if status == "resolved":
        return "verify"
    if status == "retry":
        return "authorize"
    return "human_review"

恢复节点可以调用批准的 CapSolver 浏览器工具,但应仅返回状态和稳定错误代码。永远不要将原始工具响应放入下一个模型提示中。

在挑战步骤后验证成功

挑战完成并不证明原始业务操作成功。在相同会话中重复执行预期的导航或请求,并验证受控应用信号:

python 复制代码
async def verify_expected_page(page, expected_url_prefix: str) -> bool:
    await page.wait_for_load_state("domcontentloaded")

    if not page.url.startswith(expected_url_prefix):
        return False

    marker = page.get_by_test_id("authorized-content")
    try:
        await marker.wait_for(state="visible", timeout=15_000)
        return True
    except Exception:
        return False

选择由您的应用控制的稳定标记:测试 ID、特定 API 响应或已知状态转换。避免使用广泛断言,如“页面包含文本”,因为错误页面可能包含类似文字。

如果验证失败,请勿立即调用求解器。重新分类当前响应,检查会话是否更改,强制执行重试预算,并将模糊情况发送给人类。

无循环处理重试和失败

有限的工作流应区分至少以下情况:

条件 推荐路径
未检测到 AWS WAF 信号 继续正常工作流
在批准的主机上检测到已知信号 运行授权恢复节点
未知状态/头组合 人工审核
重定向到未批准的主机 拒绝
挑战工具超时 如果总预算允许,重试一次
恢复报告成功但页面断言失败 重新分类,然后审核
重试限制达到 停止并记录稳定错误代码
缺少凭证或浏览器会话 配置错误;不要让模型修复它

对瞬态传输错误使用指数退避,但不要使用无限制循环。重试计数器属于确定性状态,而不是模型内存。

记录事件如 waf_signal_detectedpolicy_allowedrecovery_startedrecovery_finishedpage_verified。包括请求 ID、主机、持续时间、尝试次数和错误代码。排除凭证、cookies、令牌、原始挑战负载和敏感页面内容。

监控 AWS WAF 和代理行为

Agent traces显示工作流的决策;AWS指标显示保护层的观察结果。AWS在其WAF指标参考中列出了Challenge和CAPTCHA活动的CloudWatch指标,包括请求、尝试、解决和有效令牌计数。

有用的运营问题包括:

  • 应用发布后挑战量有变化吗?
  • 重复的代理重试是否集中在某个路由上?
  • 应用验证器在恢复步骤后失败吗?
  • 策略拒绝是否由意外重定向引起?
  • 超时是在浏览器、工具适配器还是最终请求中发生?

使用内部请求ID而非凭证或令牌来关联系统。挑战流量的突然增加应触发诊断,而不是默认增加重试预算。

常见实现错误

让模型从页面文本中推断挑战

文本具有歧义且容易更改。应优先使用文档化的响应状态和头部、浏览器网络事件或应用自有信号。

在检测后启动新浏览器

新浏览器可能会丢失cookies和令牌状态。在检测、恢复、重试和验证过程中保持相同的已批准会话。

将原始令牌返回给代理

模型不需要它们。将敏感值保留在确定性适配器内部,并返回一个类型化状态。

将工具成功视为工作流成功

始终重复预期操作并检查领域特定的断言。

给工具不受限制的目标

强制执行主机名允许列表、用途检查、重定向检查、重试预算,并在模型外审查路由。

复制示例而不固定版本

LangChain和LangGraph构建API会不断演进。固定通过测试的版本,将框架连接隔离在一个模块中,并在升级前重新运行集成测试。

在生产前测试工作流

使用自有的测试页面并覆盖以下情况:

  1. 无挑战的正常响应;
  2. 文档化的Challenge信号;
  3. 文档化的CAPTCHA信号;
  4. 状态和头部不匹配;
  5. 未经批准的主机名;
  6. 跳转至允许列表外的地址;
  7. 缺失浏览器会话;
  8. 工具超时;
  9. 最终断言失败;
  10. 重试预算耗尽。

在单元测试中模拟分类器、策略门和验证器。将带凭证的端到端测试保留给已批准的环境。测试日志同样重要:断言凭证、cookies和令牌应不存在。

CapSolver的入门指南记录了其任务生命周期和支持的CAPTCHA类别。选择任务路径时,请使用当前的第一方文档;不要根据旧代码片段或第三方帖子猜测字段。

结论

可靠的AWS WAF LangChain集成是一个受控状态机,而不是单个“解决”提示。检测文档化的WAF信号,验证目标和用途,调用作用域狭窄的工具,保留相同的客户端会话,并在代理继续之前确认原始操作。

对于授权自动化,CapSolver 提供了将挑战处理连接到LangChain所需的代理和核心层,同时将策略、秘密和最终验证保留在应用代码中。

使用CapSolver构建可靠的自动化工作流

使用CapSolver的文档验证当前集成路径,然后在自有的或明确授权的测试环境中尝试CapSolver。充值时使用优惠码CAP26可获得配置的5%优惠

常见问题

Q: LangChain代理如何检测AWS WAF Challenge?

在确定性的HTTP或浏览器层中检查HTTP 202x-amzn-waf-action: challenge的文档化组合。不要让语言模型从页面文本中推断条件。

Q: 哪种响应表示AWS WAF的CAPTCHA操作?

AWS文档中规定,当请求没有有效令牌时,使用HTTP 405x-amzn-waf-action: captcha作为CAPTCHA响应。将状态/头部组合不匹配的情况视为未知,并路由至审核。

Q: CapSolver API密钥是否应传递给LangChain模型?

不。应从已批准的密钥存储中在主机应用或工具适配器中加载。模型不应看到密钥、cookies、WAF令牌或原始解决方案值。

Q: 代理在完成挑战后能否使用新浏览器?

应尽可能保持相同的浏览器上下文,因为AWS WAF令牌状态与客户端会话相关联。更换会话可能会丢弃重复请求所需的令牌状态。

Q: 成功的挑战工具结果是否足够继续?

不。重复预期操作并验证应用特定的成功断言。工具结果仅是中间状态。

Q: 代理应重试多少次?

根据工作流的风险和时间限制设置一个小的显式重试预算。示例中使用两次尝试作为应用策略,而非CapSolver或AWS的保证。

Q: 此工作流能否用于任何网站?

不能。仅用于您拥有或明确授权自动化的系统。在模型外部强制执行目标和用途检查,并将不确定情况路由至人工审核。

合规声明: 本博客提供的信息仅供参考。CapSolver 致力于遵守所有适用的法律和法规。严禁以非法、欺诈或滥用活动使用 CapSolver 网络,任何此类行为将受到调查。我们的验证码解决方案在确保 100% 合规的同时,帮助解决公共数据爬取过程中的验证码难题。我们鼓励负责任地使用我们的服务。如需更多信息,请访问我们的服务条款和隐私政策。

更多