1. 古法逆向的黄昏:人肉逆向正在撞上什么样的天花板
我去年接手一个电商数据采集的内部项目时,第一次认真感受到“Agent爬虫逆向”这个说法不是噱头。当时团队还在用老办法对付某电商平台(内部代号“蓝鲸商城”)的接口签名:打开开发者工具,断点、搜索关键字、抠混淆代码、手动还原加密逻辑。整个过程活像拆一座俄罗斯套娃——拆开一个混淆函数,里面还有一层。
传统“古法逆向”的核心思路其实很简单:人把网站前端的JS逻辑读明白,把加密参数生成规则还原出来,然后模拟浏览器或直接发HTTP请求。听起来很清晰,做起来却是另一回事。现在的电商网站早就不是“加密字符串+固定规则”的简单组合,而是把接口签名、参数混淆、行为风控、动态环境校验捆成一个体系。我见过最典型的一个场景:列表页的请求里带一个 x-sign 签名参数,看着像 MD5,结果它是三段拼接后走了一个自研摘要函数,函数名已经被混淆成三个字节的乱码,断点单步跟着跟着就进了WebAssembly模块。
问题还不在破解本身,而在维护成本。老逆向工程师花两三天解出来的签名逻辑,对方改一次前端版本就能让你全部推倒重来。算一笔账:一次逆向平均要投入一到两周人力,改版频率高的时候,团队三分之二的时间都耗在重复劳动上。真正让人绝望的不是“解不出”,而是“解出了也没法长期用”。这也为什么我后来彻底转向Agent思路——不是小修小补,而是把“人肉读懂逻辑”这件事,整个交给大模型驱动的Agent来完成。
这篇内容适合被JS逆向折腾过的人、想用LLM做自动化采集的工程师、以及所有对“Agent如何落地到具体业务”感兴趣的朋友。我会用蓝鲸商城这个实战案例,把Agent爬虫逆向的架构、搭建流程、源码关键模块和实际踩坑一次讲透。先打个预防针:Agent不是银弹,它改变的是效率模型,不是物理规律。
1.1 接口签名、参数混淆与行为风控:三座绕不开的大山
老逆向圈的共识是,一个“好啃”的站点和一个“难啃”的站点,差别往往不在框架,而在它到底堆了多少层防御。
第一层是接口签名。几乎所有主流电商平台都会给关键接口加签名参数,比如 x-sign、x-nonce、x-timestamp 这类请求头。签名算法本身有可能不难,但它是“活”的:参数拼接顺序、参与签名的字段集合、加的盐(salt)是动态下发的还是写死在Bundle里的,一直在变。第二层是加密参数混淆。变量名替换成单字母、字符串拆成数组翻转、控制流压平,这些手段虽然不是新的,但只要跟签名逻辑结合,人工阅读成本立刻翻倍。第三层是行为风控。哪怕你参数全部齐全,请求频率异常、浏览器指纹缺失、TLS握手特征不对,照样会给你返回一个验证码页或者纯广告页。
这三层彼此独立又相互联动。破解签名只是第一步,还要让整套请求看起来“像真人”。传统逆向往往只盯着第一层,花大力气搞定签名之后,发现触发了行为风控,又要回头补环境。而Agent的做法完全不同——它不执着于“人类完全读懂代码”,而是抓住两个关键:一是找到签名生成的实际位置,二是能在对应运行时环境里把签名调出来。至于这中间的逻辑细节,大模型能理解多少就理解多少,理解不了的部分直接交给工具执行。
1.2 改版一次、返工一次:人肉逆向的时间账
接触Agent之前,我做一次完整的电商平台逆向,流程大概是这样的:沟通需求、抓包分析、定位加密函数、打断点调试、还原算法、本地模拟签名、联调验证,最后写出一套看起来“固化”的采集脚本。这套流程最致命的问题不是单次耗时,而是它假设前端代码不会变。
现实是,对方一个版本迭代,可能只是把某个常量改掉,你的脚本就失效了。更麻烦的是,失效后你甚至不知道它为什么失效——签名逻辑没变,但参数来源变了;参数来源没变,但摘要算法换了。每次都是一轮新的断点跟栈,每次都让团队里最资深的同事亲自上阵。我后来跟朋友开玩笑说:一个人如果能持续三年做这种工作,他的核心竞争力就不是逆向,而是“耐心”。
Agent出现之后,我第一反应是把它当“进阶版搜索引擎”用——让大模型帮我读代码片段、解释某个函数的逻辑。后来才意识到这个用法格局小了。Agent真正改变的是闭环方式:它能感知页面环境、定位目标逻辑、调用运行时工具、发起请求验证、根据验证结果修正策略。整个人类参与的环节可以被压缩成“定义目标 + 审核最终代码”。我实测在蓝鲸商城项目上,过去两周的工作量压缩到了两天,其中还有半天是在调Agent自己的参数。这就是为什么我说“古法爬虫逆向已死”——不是贬低这项技术,而是它作为“主要生产力”的时代确实过去了。
2. Agent爬虫的核心设计:把逆向思维交给大模型,而不是写死规则
说清楚一个容易误解的点:Agent爬虫逆向并不是“让大模型直接生成一个能跑的爬虫”,那在安全合规和工程实现上都不可靠。真正的Agent是一套系统,由大模型充当“大脑”,外围挂一圈可调用的工具,再配合任务分解与自我验证机制,形成闭环。
这套设计和我以前写的爬虫脚本有一个本质区别:传统脚本是规则驱动的——if 这个参数就 那样处理,else 就按另一个逻辑来;而Agent是目标驱动的——给定“抓取蓝鲸商城商品列表页数据”这个目标,它会自己规划路径:先看页面长什么样,再找签名在哪,再决定怎么调签名,然后执行并验证。换言之,以前是我替机器思考每一步怎么做,现在是我告诉机器“做到什么程度算成功”,剩下的路径让它的推理能力去探索。
2.1 四层结构:感知、分析、策略、执行各管一段
我习惯把Agent爬虫逆向拆成四个层次,每一层都有明确的职责边界,这样无论是调试还是扩展都清晰得多。
感知层负责把“网页世界”翻译成大模型能读的文本/结构化数据。它包含无头浏览器、网络请求捕获模块、DOM快照工具。Agent要分析接口签名,第一步就得知道页面发出了哪些请求、每个请求的请求头是什么、响应体长什么样。感知层把这些信息转成JSON日志喂给大模型,而不是让大模型直接去看二进制流量。
分析层是大模型的主场。它拿到页面快照和请求日志后,要回答几个关键问题:签名参数是哪个?它由什么生成?对应逻辑在哪个JS文件里?这段逻辑涉及哪些外部依赖?分析层不需要能“从头实现签名算法”——它的任务是定位与理解,把复杂的逆向问题缩小到一个精确的坐标上。
策略层是把分析结果转化为可执行动作的地方。比如大模型发现签名是由一个叫util.encrypt的全局函数生成的,策略层就会决定:第一步加载页面运行时环境;第二步在运行时环境里调用这个函数;第三步把参数传进去拿到签名。这个决策过程是动态的,每一步执行完都会把结果摘要回填给大模型,它再判断下一步怎么走。
执行层就是一组真实的工具集合:加载页面、调用JS函数、发起HTTP请求、保存响应、执行验证。执行层不依赖大模型,它只负责“干活”。这四层拆开的价值在于,出问题时可以快速定位:是感知层没抓到接口?还是分析层定位错了函数?还是执行层的运行时环境不对?而不是面对一个黑箱脚本无从下手。
2.2 需要大模型的地方用大模型,不需要的地方用规则
这是我踩过不少坑之后总结出的重要原则:Agent的每一步如果都调大模型,又贵又慢,还容易出错。大模型擅长的是“理解”“推断”“决策”这类模糊任务,不擅长的是“稳定复现”“精确拼接”“大量循环”。
举一个实际例子。分析层让大模型读一段混淆代码,它表现得很好——比人类能更快地认出“这段函数是对字符串做了排列拼接,然后进MD5”。但如果你让它自己写一段JS来模拟这个加密过程,它经常给出“看起来合理但跑不出来”的代码。原因是签名算法是确定性逻辑,容不得半点偏差,而大模型生成代码天然带随机性。
所以我的设计原则是:不确定的事情让大模型判断,确定的事情让代码执行。定位加密函数是不确定的——让Agent来做;函数找到之后,实际生成签名是不确定的吗?不是,只要在运行时环境里调用原函数就是确定的——这时候应该走执行层工具,而不是让大模型从头写代码。同理,验证逻辑也是确定的:返回体里有没有商品字段、状态码是否200,这些用规则写死,又快又准。
2.3 把上下文“切碎”:子任务化与上下文窗口管理
大模型的上下文窗口再大,也架不住把整个页面的几千行JS一股脑塞进去。如果直接塞,轻则注意力涣散、分析跑偏,重则直接把关键信息截断掉。
我在蓝鲸商城项目里采用的办法是子任务化。大模型的主循环只做“指挥官”该做的事:看目标、看每个子任务的摘要、决定下一个子任务。真正读JS代码、分析某段函数逻辑的任务,交给独立的子任务去执行。子任务完成之后,只把结论摘要回传主循环,不把原始代码整个带回来。
举个例子,主循环收到“定位x-sign生成逻辑”这个子任务后,不直接读全部JS,而是先让执行层在JS文件里搜索关键词“x-sign”“encrypt”“sign”出现的位置,把命中的行号附近几十行代码截出来,再把这个小片段交给大模型分析。这样每次喂给模型的都是“精确切片”,而不是“整个文件”。这套思路听着简单,却是Agent逆向能否规模化跑起来的关键。
3. 蓝鲸商城实战:一遍完整跑通的逆向链路
下面进入正题,用蓝鲸商城这个案例把整个链路串一遍。为了描述方便,我简化了部分协议细节,但整体思路和我在真实项目中使用的完全一致。
先交代一下目标:需要从蓝鲸商城H5端的商品列表页,拿到每个商品的标题、价格、销量和评价数。难点是它的列表接口请求头里有四个自定义参数:x-sign、x-nonce、x-timestamp、x-app-id。其中x-sign是最难搞的,它参与签名的不只是URL参数,还包括一段固定请求体的摘要。
3.1 第一步不是写代码,而是让Agent“读”页面
以前我拿到这种需求,第一件事是打开控制台抓包,手动翻一下请求参数。现在我的第一动作是启动Agent的感知层:无头浏览器加载列表页,同时把所有网络请求按顺序转成结构化日志,包括请求URL、请求方法、请求头、请求体、响应状态码和响应体前几个字节。
Agent拿到这些日志后,主循环先做一轮“快读”:哪些请求是接口数据请求,哪些是静态资源。它很快定位到/api/v1/product/list这个接口——响应的JSON里含有关键字段。然后策略层启动:先检查这个请求的请求头参数,发现有五个自定义头,其中三个是时间戳、随机数、应用ID,剩下两个是签名相关。到这里,Agent已经完成了传统逆向中最费神的“找入口”工作。
这一步传统方法可能要花上半小时,Agent大概用了两轮模型调用,耗时两分钟。原因是感知层把信息整理得足够干净,大模型不需要自己对着开发者工具一个个点开请求看。
3.2 签名位置还原:让Agent给自己“定位坐标”
确定目标接口后,Agent进入分析阶段。它要回答一个问题:x-sign这个参数,在页面代码里是什么地方生成的?
Agent的方法是关键词定位。它让执行层下载列表页关联的bundle JS文件,然后搜索“x-sign”“sign”“encrypt”“md5”这些关键词。注意,这一步不需要把整个文件喂给大模型,而是先让代码逻辑把关键词出现的行号、上下文片段提取出来,做成一个“候选坐标列表”。
列表出来后,大模型分析每个候选片段的上下文,判断哪个才是真正生成x-sign的地方。它发现有一个工具函数g.calcSign(e, t),在请求拦截器里被调用,返回值直接赋给请求头的x-sign。大模型顺藤摸瓜,在另一个文件里找到了calcSign的具体实现:入场参数是路径、时间戳、nonce和一个写死的appKey,内部先做字符串拼接,然后走一个自研的摘要函数digest()。
到这里,Agent并没有真正“还原”digest函数的具体算法,但它已经知道:签名必须在蓝鲸商城的页面运行时环境里生成,因为digest依赖了多个全局常量。这也决定了下一步的执行策略:不能拿大模型生成的代码模拟签名,而要把页面环境加载起来,直接调原函数。
3.3 策略回放与结果校验:让Agent自己验证自己
Agent制定的执行策略可以概括成三步:加载页面运行时环境、注入脚本调用calcSign、获取返回值。
执行层先在无头浏览器中打开一个同域名下的空白页面,确保所有全局变量都初始化完毕。然后注入一段JavaScript,直接调用g.calcSign来生成当前请求所需的签名,并把签名返回给Agent主程序。这一招其实是“把原函数当计算器用”——我不需要知道它内部怎么算的,只要它在真实环境里能给出正确结果。
生成签名之后,Agent组装完整的HTTP请求:URL、请求头五个自定义参数、请求体。发出去之后看响应:状态码200,返回体是JSON且包含商品数组。这一步验证通过。
这里有一个传统逆向里很容易忽略的点:签名正确不代表请求一定成功。如果Agent生成的是一个“半对”的签名,可能能过参数校验,却死在行为风控。所以我让Agent在正式验证之前,先把请求频率降到很低,并且带着完整的浏览器指纹。记住:签名正确 + 请求行为正常 = 能过;签名正确但请求像机器人 = 照样被拒。Agent的验证器会把这两种失败模式分开记录,方便后续针对性修正。
3.4 降级与收口:能规则化的就规则化
Agent把链路跑通之后,我会做一件传统逆向里也常做的事:把动态逻辑收口成规则化代码。毕竟Agent调用大模型的成本是按token算的,生产环境如果每发一个请求都让大模型分析一次,成本会很快失控。
在蓝鲸商城案例里,Agent跑通链路后,整个签名过程实际上已经被固化成一段代码:加载页面运行时、调calcSign、获取签名、构造请求。这套流程不再需要大模型参与决策。Agent在生产中只承担“异常处理”角色——比如哪天签名逻辑改了,规则化代码失效了,再让Agent重新分析一遍,产出新的规则化代码。这个模式我一直认为是Agent爬虫的正确打开方式:日常用规则省钱省时间,异常用Agent兜底。
在蓝鲸商城这个案例里,我在平台进行一次前端改版后发现,原有的签名坐标变了,calcSign函数仍然存在,但参数拼接方式换了顺序。规则化请求头会一直失败。此时完全不需要重新走一遍完整逆向,直接启动Agent的分析层去读新的代码片段,就能更新参数拼接规则。整个过程没有人工参与代码还原,这就是Agent方案相对古法最大的优势。
4. 源码关键模块拆解:任务分解、工具调用与验证回退
标题里提到“附源码”,这里把源码里最核心的几个模块设计逻辑讲清楚。完整的工程代码涉及的业务细节比较多,我这里给出的是骨架化的核心实现思路,你在自己的项目里可以直接沿用这套结构,往工具列表里填自己的工具即可。
4.1 工具注册表:给Agent一套“能动手”的权限
Agent不能只靠“想”,它必须能“做”。工具注册表就是把Agent能做的动作全部枚举出来,并以标准化的JSON Schema形式描述给大模型。
我的工具注册表大概长这样:
tools = [ { "name": "capture_network_logs", "description": "加载指定URL并返回页面发出的所有网络请求日志(结构化JSON)", "parameters": { "type": "object", "properties": { "url": {"type": "string", "description": "目标页面URL"} } } }, { "name": "search_keyword_in_js", "description": "在指定JS文件中搜索关键词,返回命中行号和上下文片段", "parameters": { "type": "object", "properties": { "file_url": {"type": "string"}, "keywords": {"type": "array", "items": {"type": "string"}} } } }, { "name": "execute_js_in_page", "description": "在已加载的页面运行时环境中执行JavaScript表达式并返回结果", "parameters": { "type": "object", "properties": { "expression": {"type": "string", "description": "要执行的JS表达式"} } } }, { "name": "send_http_request", "description": "向目标接口发送HTTP请求,返回状态码、响应头和响应体", "parameters": { "type": "object", "properties": { "method": {"type": "string"}, "url": {"type": "string"}, "headers": {"type": "object"}, "body": {"type": "object"} } } } ]工具描述写得是否清楚,直接决定Agent会不会正确使用工具。我见过一个常见的坑:某工具描述写得太宽泛,比如“加载页面”,结果Agent每次需要发HTTP请求时都先加载一次页面,白白浪费时间。工具描述应该精确到“什么场景用、输入是什么、输出是什么、副作用是什么”。这么多工具同时暴露给主循环时,大模型选择工具靠的就是description的语义匹配度,含糊不得。
4.2 任务分解器:把逆向题拆成可验证的小目标
任务分解器是Agent的“拆题”模块。它将总目标“抓取蓝鲸商城商品列表页数据”分解成多个可验证阶段:加载页面、抓取请求日志、定位签名生成位置、生成签名、发起请求、验证响应。每个阶段都是一个独立任务,都有明确的输入输出和终止条件。
实现上,任务分解器与主循环协同工作。简单示意:
class AgentCrawler: def __init__(self, llm, tools): self.llm = llm self.tool_map = {tool["name"]: tool for tool in tools} self.memory = [] def run(self, task): # 第一次调用LLM,让它生成整体计划 plan = self.llm.plan(task, available_tools=self.tool_map) for step in plan: result = self.execute_step(step) self.memory.append(self.summarize(step, result)) if self.should_stop(result): break return self.final_answer() def execute_step(self, step): # 每个step包含 tool_name 和 arguments tool = self.tool_map[step["tool_name"]] return tool["invoke"](**step["arguments"])分解的好处在于,每一步的执行结果都可以被验证。验证不是等到最后看“对不对”,而是每走一步都对一处:加载页面是否成功、请求日志里有没有目标接口、搜索关键词有没有命中、执行JS有没有返回值。这让我可以精确定位Agent是在哪一步“想歪了”,而不是拿到一个黑箱结果后从头猜。
4.3 验证器:语义一致性检查与执行成功率
验证器是整个Agent系统里我投入最多心思的模块,因为它决定了“什么时候算成功”。
验证器分两层。第一层是规则验证器,完全用代码实现:检查请求状态码是否是200、响应体是否能被解析成JSON、包含目标字段的数组是否不为空、字段值类型是否符合预期。这些判断快且准,不需要大模型参与。第二层是语义验证器,让大模型看响应内容,判断返回的是真实商品列表还是风控占位页。比如返回的JSON里有一个code: 200,但data.list里的商品全是同一件测试商品——这种情况规则验证器很可能放行,语义验证器却能发现异常。
我在代码里给验证器设计了成功率的返回:单个任务成功率要超过90%才认为该阶段通过,否则进入失败回退流程。回退不是简单重试,而是先让Agent总结当前失败原因,再调整策略或换一个切入点。例如,若它在执行JS表达式时发现某个全局变量不存在,说明页面运行时初始化不完整,那就需要先换成真实的用户操作路径(比如滚动一下页面、点一次分类Tab),让相关JS模块被加载,再重新执行。
4.4 失败回退与缓存设计:让Agent不至于“空转”
Agent跑在生产环境里,失败是常态,真正决定体验的是失败后怎么处理。我在蓝鲸商城项目里遇到过几次典型的失败场景,最后沉淀下来的回退设计有两类。
一类是工具级回退。某个工具调用失败(比如无头浏览器崩溃),Agent会尝试换一个等价工具或换一种调用参数。比如直接在页面执行JS失败时,可以改用注入完整script标签的方式,或者从当前页面的次级入口重新进入。另一类是策略级回退。整个链路在某一步走不通时,Agent回到计划级别重新拆分任务,生成一套新的approach,必要时可以把“直接模拟浏览器”改成“先调一次真实的用户点击动作再发请求”。
缓存设计也很关键。Agent在一次逆向过程中会反复读取同一个JS文件、反复执行同一个加密函数。我会给这些高耗时操作加一个会话级缓存,哈希URL与关键词,同一份文件只下载一次、同一个函数结果短时间缓存复用。实测这个优化能够把单次逆向的模型调用耗时降低约30%,同时显著降低被目标站点限流的概率。缓存永远先把旧结果命中,再在后台验证新结果是否仍然有效,避免“缓存签名单一导致请求全挂”。
5. 一台机器从零搭建Agent逆向流程:环境和参数细节
理论说得再多,不如实际把流程跑起来。这里给出我从零搭建的完整步骤,你在自己机器上按顺序操作就能得到一个可用的Agent逆向基础框架。
5.1 环境准备与模型选型:本地推理还是云端API
先说我推荐的基础环境组合:Python 3.x、一个无头浏览器自动化框架(至少支持页面加载、JS注入、网络日志捕获)、一个轻量HTTP客户端。这些基础的第三方库大家应该都熟悉,选型时优先看社区的活跃度和接口稳定性,避免选那种好几年不更新的冷门库,否则环境问题就能消耗掉你半天时间。
模型选型是最影响Agent质量的关键点。我的建议是:分析任务用推理能力强的模型,这类模型在“读懂混淆代码”“推断签名逻辑”这些复杂任务上表现明显更好,上下文理解也更稳健;而像“提取JSON字段”“判断响应体是否正常”这类简单任务,用轻量模型就够了。实际使用中我一般是主循环用强推理模型,子任务里的“摘要”“格式化”用轻量模型,这个搭配在成本和效果之间比较平衡。
如果你本地有显卡,也可以考虑部署本地推理服务,用量化过的开源模型跑子任务。好处是请求数据不出本机,隐私风险低,合规上更可控。但是纯粹的主循环推理任务,我建议还是用云端API,本地模型在关键时刻的稳定性和推理深度还是稍有差距。
5.2 最小闭环Demo:加载页面 → 生成策略 → 发起请求 → 校验结果
我强烈建议第一次接触Agent逆向时,先搭一个最小闭环,而不是一上来就弄完整的生产系统。最小闭环的目标只有一句话:给定一个目标URL,让Agent能自己找到接口、补全参数、拿到数据并声称成功。
最小闭环的代码结构比起完整版会简单很多,核心流程就是四个步骤:
- 调用加载页面工具,拿到页面请求日志。
- 将日志摘要、页面JS关键词搜索结果、用户目标一起交给大模型,让它生成策略(可能包含1到3个工具调用)。
- 按策略调用工具(如执行JS生成签名、发送HTTP请求)。
- 用规则验证器检查结果,返回成功或失败。
搭完最小闭环后,再逐步加“任务分解”“多轮回退”“语义验证器”这些高级特性。别一开始就追求全功能,这样出了问题很难定位是哪个环节的Bug。
5.3 提示词模板与结构化输出解析
Agent的“智商”很大程度上取决于提示词的质量。我的提示词模板通常固定分四段:角色定义、任务目标、已知条件、输出要求。
一个简化版模板如下:
你是网站逆向工程师。你的任务:{task} 已知信息: - 页面请求日志:{network_logs} - 页面代码关键词命中:{keyword_hits} - 已加载页面运行时状态:{runtime_status} 请先给出执行计划,然后按计划逐步调用工具。每次工具调用完成后,回复格式为JSON: {"thought": "对当前情况的简要分析", "tool": "工具名", "arguments": {...}} 只有确认任务完成时,返回: {"done": true, "summary": "结果摘要", "data": {...}}关键点在于输出格式必须结构化。我不允许大模型输出自由文本,因为自由文本无法被代码可靠解析。要求它返回JSON,就是一个很好的工程约束。解析失败时不应该直接报错,而是把解析错误信息回传给大模型,让它修正输出格式。实测这个方法能把Agent的整体任务完成率提高一大截。
5.4 参数调优:温度、工具数量与重试节奏
Agent系统里值得调的参数不多,但每个都影响明显。
温度是最直接的一个。逆向任务本质上是“确定性任务”,大模型的输出一旦随机,后面全乱。我在所有逆向相关步骤都把温度设为0,只在最后的“结果摘要”这步可以稍微调高,让摘要更自然一些。工具数量不是越多越好,工具列表超过15个之后,大模型选错工具的概率会明显上升。所以生产环境中我配置的Agent往往只暴露与当前任务最相关的工具,其余工具放在另一个Agent里。这就是“一个Agent干一类事”的分工思路。
重试节奏也要精心设计。我在蓝鲸商城项目里踩过“重试太频繁导致IP行为分下降”的坑。现在我的策略是:单个请求失败后,先等待3秒重试一次;仍然失败,等待15秒再重试一次;第三次失败就停止自动重试,触发Agent分析原因。真正有效的不是“多试几次”,而是“试失败之后认真反思策略”。
6. 边界与踩坑:Agent不是银弹,怎么收场很重要
最后一部分,聊一聊我在Agent爬虫逆向这条路上真正踩过的坑。这部分的内容价值不亚于前面的技术框架,因为框架是定式,坑才是变量。
6.1 幻觉问题:大模型生成“看似合理但完全不可用”的签名
我遇到的第一个大坑是幻觉。第一次让Agent尝试自动生成签名时,它返回了一段看起来完整的Python签名函数,代码里有正则匹配、有hash调用、有拼接逻辑。但我复制运行,得到的结果和目标站点预期的签名完全对不上。大模型在“不确定函数细节”时,倾向于生成一个“看起来合理”的版本,而不是承认“我不知道”。
解决方案前面已经提过:不要让大模型“算”签名,让它“调”签名。只要目标站点提供运行时环境,直接在环境里调用原函数是最可靠的方式。人的逆向思路需要“理解算法逻辑”才会自己实现签名,但Agent不需要——它需要的是“定位函数、调用函数”的能力。这个认知转变之后,我的Agent成功率才真正上了台阶。
6.2 上下文膨胀:一个上万token的JS文件把Agent“淹没”
蓝鲸商城的bundle JS单文件就有近两万行,压缩后一行上万token。第一次我直接把文件内容塞给大模型,结果它分析到一半时逻辑混乱,把两个不同模块的变量当成同一个,还理直气壮输出了一段错误结论。上下文窗口虽然大,但“大”不等于“能全部用对”,更不等于“重点不会被稀释”。
解决方案就是前面说的“切片化”。关键词搜索定位到具体行号,然后只抽取目标函数的前后文片段。一次分析控制在500到800行之间,再配合一个“滑动窗口”机制——读完一段,记录摘要,再读下一段。这样即使面对超大型JS文件,Agent也能保持稳定的分析质量。一个拦路的坑是:某些bundle文件做了sourcemap或压缩变体,会导致关键词搜索命中位置偏移(例如命中了一行特别长的压缩代码,上下文窗口包含的根本不是相邻逻辑)。所以我在搜索之后还会做一个“代码片段可读性检查”,把过长的行按字符边界切成可读的多行,再喂给模型。
6.3 合法合规与边界认知:Agent只是工具,授权才是前提
最后想说的其实是老生常谈,但不说不行。Agent爬虫逆向只是技术工具,它解决的是“效率”问题,不解决“合法性”问题。
我在做蓝鲸商城项目时,是拿到了对方口头授权的内部数据接口测试权限,且仅用于内部可行性验证。你如果要在真实业务里做Data Mining,务必先确认以下三点:目标网站是否有明确的技术接口授权说明,是否允许自动化访问;你抓取的数据类型是否涉及用户隐私或平台核心资产;你的请求频率和并发是否会对对方服务造成额外压力。从技术上看,“Agent能不能绕过某些请求频率限制”和“该不该这么做”是两回事。后者是底线。
还有一个很容易被忽视的边界:Agent分析过程中会把页面代码片段和请求数据传给大模型服务,相当于把目标站点的部分前端逻辑交给了第三方LLM处理。如果你的项目对数据保密性有要求,这一点必须提前评估。敏感目标可以在本地部署模型,或者只让Agent做“定位与指令”层面的判断,不传递具体业务数据的原始内容。我在自己项目中会对这类敏感度做分级,比如仅让Agent接触请求日志的结构信息,而不接触完整的商品或用户数据。原则是:能少传就少传,能不传就不传。
我现在的习惯是,让Agent负责“看不懂的部分”,让规则负责“看得懂的部分”。两者互为兜底,兼顾效率与稳定。搭建Agent的过程里,前期调试可能会稍显痛苦——模型输出变来变去、工具参数传错、验证器误判,这些都是正常的。但一旦闭环跑顺,你就能体会到“让机器替自己读懂代码”的痛快感。它不能包治百病,但能把最磨人的部分替你扛掉大半。