前途科技
  • 科技
  • AI
    • AI 前沿技术
    • Agent生态
    • AI应用场景
    • AI 行业应用
  • 初创
  • 报告
  • 学习中心
    • 编程与工具
    • 数据科学与工程
我的兴趣
前途科技前途科技
Font ResizerAa
站内搜索
Have an existing account? Sign In
Follow US
Copyright © 2024 AccessPath.com, 前途国际科技咨询(北京)有限公司,版权所有。 | 京ICP备17045010号-1 | 京公网安备 11010502033860号
AI 前沿技术

让大模型读懂二方包:AI编程助手处理依赖代码的挑战与本地反编译解决方案

NEXTECH
Last updated: 2025年11月2日 上午7:24
By NEXTECH
Share
73 Min Read
SHARE

大模型难以理解二方包代码的示意图本文深入探讨了在开发过程中,大模型(如AI编程助手)在理解项目二方包代码时面临的挑战,并通过一个实际案例复盘了从失败到成功驯服AI的全过程。文章尝试使用Cursor等AI工具直接生成调用二方包接口的代码,但因AI无法读取未在当前工程中打开的依赖源码,导致生成的代码错误频出,甚至出现幻觉式编码。为解决此问题,文章探索了多种方案,最终发现本地反编译MCP方案最为有效,能够精准解析二方包中的类与方法,显著提升代码生成的准确性和可用性。文章强调,应将AI视为需辅助的“工具人”,通过提供良好上下文与工具来增强其能力,而非期待其无所不能。

查询用户订单状态背景图背景

近期有一个需求中需要查询用户订单状态,这个功能本身很简单,是一个经典的依赖下游场景,需要读取交易订单二方包的代码逻辑,并分析出入参出参的含义,并判定用户指定的订单是否已经进入终态。

在大多数日常工作开发过程中,会遇到很多需要调用各种下游提供的接口,对二方包有依赖的场景(例如优惠券、会员、订单……)。这种情况下,大模型是否能够理解开发者的诉求呢?

起初,面对如此简单的需求,AI编程助手被寄予厚望,结果却上演了一出大型“翻车现场”。本文复盘了从失败到驯服AI的全过程,揭示如何让大模型理解二方包。文中对部分方法名称做了脱敏处理,可能存在前后不一致,但这不影响核心论述点。

Cursor直接使用失败直接使用Cursor — 失败

You Might Also Like

Google Gemini 3 Pro横空出世:多项基准测试全面领先,重新定义大模型性能天花板
Google DeepMind揭示:开源AI模型如何泄露训练数据与核心秘方
69页AI Agent圣经报告:智能体发展前景、未来趋势与生态全解析
DeepSeek与百度OCR技术深度对比:谁是文档识别新水准的引领者?

文章尝试将交易接口的内部文档链接提供给Cursor,并使用/doc功能添加了交易相关的两个接口页:查询订单(在线库)和查询订单(历史库)(这两个网页是内部办公网页面,外部用户可能无法访问)。文章清晰地描述了需求:“请帮助实现一个批量查询订单的方法,先查询在线库,若查询不到则再去历史库获取……”以下是几轮对话记录:

user:

请帮我实现一个批量查询订单的方法,查询指定userId和List<long>subOrderIdList 下的订单结果。请在TpClientImpl中实现。请注意方法的逻辑。需要先在通过订单在线库中查询,使用xxxService.queryMainAndDetail,如果查询出来的结果中没有指定orderIdList的信息,请收集之后统一再次使用订单历史库查询,使用xxxBaseService.queryMainAndDetail。根据网页中给出的返回值的逻辑。最终将两者查询出来的结果统一按照传入的 subOrderIdList 的顺序返回一个订单列表。请先不要写代码,先规划任务并写入到.ai/指定订单查询task.md。

Cursor:

给出了需要 实现一个批量查询订单的方法queryBizOrderList,下面是任务规划文档,写的没啥问题:

# 指定订单查询任务规划``## 需求概述``实现批量查询指定 userId 和 List<long>&nbsp;subOrderIdList 下订单结果的方法&nbsp;queryBizOrderList。``## 业务逻辑``1.&nbsp;**先查询在线库**:使用&nbsp;xxxService.queryMainAndDetail&nbsp;方法查询传入的所有订单ID``2.&nbsp;**收集未找到的订单ID**:对比查询结果与传入的订单ID列表,收集未查询到的订单ID``3.&nbsp;**查询历史库补充**:使用&nbsp;xxxBaseService.queryMainAndDetail&nbsp;方法查询未找到的订单ID``4.&nbsp;**合并结果**:将在线库和历史库的查询结果合并``5.&nbsp;**按序返回**:按照传入的 List<long>&nbsp;subOrderIdList 的顺序重新排序并返回订单列表``## 技术实现任务分解``### 任务1:了解现有服务和方法签名``-&nbsp;[ ] 确认&nbsp;xxxService.queryMainAndDetail&nbsp;方法是否存在,如不存在需要定义``-&nbsp;[ ] 确认&nbsp;xxxBaseService(历史库服务)是否存在,如不存在需要引入``-&nbsp;[ ] 确认&nbsp;xxxBaseService.queryMainAndDetail&nbsp;方法签名``-&nbsp;[ ] 了解查询结果的数据结构和返回值类型``### 任务2:设计方法签名``java``/**``* 批量查询指定用户的订单列表``* @param userId 用户ID``* @param subOrderIdList 子订单ID列表``* @return 按照传入顺序返回的订单结果列表``* @throws TCException 查询异常``*/``List<SingleQueryResultDO> queryBizOrderList(long userId, List<Long> subOrderIdList) throws TCException;`### 任务3:实现核心逻辑``-&nbsp;[ ] 参数校验:检查 userId 和 subOrderIdList 的有效性``-&nbsp;[ ] 在线库批量查询:调用&nbsp;xxxService.queryMainAndDetail-&nbsp;[ ] 结果分析:识别哪些订单ID没有查询到结果``-&nbsp;[ ] 历史库补充查询:对未找到的订单ID调用&nbsp;`xxxBaseService.queryMainAndDetail– [ ] 结果合并:将两次查询的结果合并到一个Map中-&nbsp;[ ] 顺序重排:按照传入的 subOrderIdList 顺序构建返回列表### 任务4:异常处理和日志-&nbsp;[ ] 添加适当的异常处理逻辑– [ ] 对查询不到的订单ID记录ERROR日志(根据记忆中的用户偏好)-&nbsp;[ ] 使用 guard clauses(提前返回)优化代码结构– [ ] 添加 TraceLogUtil 链路追踪-&nbsp;[ ] 统计在线库和历史库的查询耗时### 任务5:性能优化考虑-&nbsp;[ ] 如果传入的订单ID列表为空,提前返回– [ ] 避免不必要的历史库查询(如果在线库已查询到所有订单)-&nbsp;[ ] 考虑是否需要并行查询在线库和历史库### 任务6:更新接口定义-&nbsp;[ ] 在 xxxClient 接口中添加&nbsp;`queryBizOrderList`&nbsp;方法定义– [ ] 确保方法签名的一致性### 任务7:单元测试– [ ] 编写测试用例-&nbsp;[ ] 测试场景:全部在在线库找到– [ ] 测试场景:部分在在线库,部分在历史库-&nbsp;[ ] 测试场景:全部需要从历史库查询– [ ] 测试场景:部分订单查询不到-&nbsp;[ ] 测试场景:异常处理## 依赖和风险点### 需要确认的依赖1. xxxBaseService 服务:需要确认历史库查询服务是否已配置2.&nbsp;**queryMainAndDetail 方法**:需要确认具体的方法签名和返回值结构3.&nbsp;数据一致性:确认在线库和历史库返回的数据结构是否一致### 潜在风险1. 性能风险:批量查询可能影响性能,需要考虑分页或限制查询数量2.&nbsp;超时风险:历史库查询可能较慢,需要设置合适的超时时间3.&nbsp;数据不一致:在线库和历史库的数据可能存在不一致## 实现优先级1. 高优先级:核心查询逻辑实现2.&nbsp;中优先级:异常处理和日志记录3. 低优先级:性能优化和监控`
并且要求确认依赖关系:

  • xxxBaseService服务需要引入;

  • queryMainAndDetail方法签名需要确认;

  • 批量查询的性能和超时控制。

这里做得不错。

user:

请先阅读二方包代码xxxService.queryMainAndDetail以及xxxBaseService.queryMainAndDetail调用的出入参是什么,再写代码逻辑。

Cursor:

其阅读代码后给出了判定结果:

  1. xxxService.queryMainAndDetail方法不存在;

  2. xxxBaseService服务不存在;

代码库中没有找到历史库查询服务xxxBaseService;

  1. queryMainAndDetail方法在整个代码库中都不存在。

走到这里,判定结果说明Cursor只读取了工程代码库的代码,并不能读取明确指定的二方包中的方法。另外,由于之前曾有查询单个指定ID订单的方法,Cursor提出基于现有方法实现批量查询:使用循环调用getBizOrderById方法实现批量查询。

这表明Cursor无法读取二方包中的代码,于是下一轮对话中明确使用了全限定名。

user:

这两个类以及方法是二方包中的方法,二方包已在pom中以及Configuration引入,需要你阅读并使用com.tb.xxx.yyy.api.xxxService和com.tb.ccc.ddd.service.xxxBaseService,调用前面我提到的queryMainAndDetail方法。

Cursor:

开始随意实现,导入的包路径是LLM根据代码库中之前client防腐层中写过的getBizOrderById方法中引入的xxxService幻想出来的。

例如,使用了com.tb.xxx.yyy.api.xxxBaseService,而没有使用正确的com.tb.ccc.ddd.service.xxxBaseService。

Cursor发现报错后,再次进行猜测,转成了com.tb.xxx.yyy.api.history.xxxBaseService,纯粹根据“历史库查询”这一描述进行幻觉式编码。

在此阶段,文章介入手动修正了import路径,但并未直接告知大模型xxxService.queryMainAndDetail以及xxxBaseService.queryMainAndDetail的完整方法签名,仍抱有对AI能力的幻想。

user:

好了,我已经修正了引入了xxxService和txxxBaseService的导入路径,请你解析我指定的方法,根据出入参写出正确的调用代码。

Cursor:

Cursor并未直接读取xxxService.queryMainAndDetail以及xxxBaseService.queryMainAndDetail的方法签名,而是根据编译后返回的错误信息才得知其传入的参数不正确。以下是其思考过程:

好的,现在我看到了方法签名的错误。需要使用 QueryBizOrderDO 对象而不是直接传入 List<Long>。让我查看一下 QueryBizOrderDO 的结构:``我需要了解 QueryBizOrderDO 的结构。让我搜索更多相关信息:``让我继续搜索 QueryBizOrderDO 的相关信息:``看起来我无法在代码库中找到 QueryBizOrderDO 的具体实现。

Cursor发现其根本不知道应该如何构造这个入参。进行到这里已经非常确认Cursor无法读取到jar包中的代码(即便已明确使用了全限定名)。

进行到这里,文章发现与AI结对编程更像是辅导一个记性不佳且充满幻想的孩子完成作业。此外,观察到入参xxxQueryXxxOrderDO定义有两千多行,返回对象xxxOrderInfoResultDO内部也包含多层逻辑。

大模型在未理解二方包时的错误猜测其中要用到的订单信息bizOrderDO又有上万行。若将这些代码全部提供给AI,预计上下文Token将严重超限。为了优化Token使用效率,此方案被放弃。

理论上可以考虑直接将API网页导出为Markdown形式进行尝试。然而,该网页中嵌套了语雀文档,语雀文档进一步阐述了出参含义,且网页信息与实际二方包不符(例如订单ID,网页显示为long,实际二方包需传入long[]),因此该方案被放弃。

放弃盲目尝试的表情包【世上无难事,只要肯放弃(不是)】

对于这个需求,看似无往而不利的AI表现得像“智障”一样,这揭示了一个问题:对于未在当前工作区打开的、作为编译依赖(二方包)存在的代码,LLM几乎是“盲人”。它无法像IDE那样“Go to Definition”,也无法理解那些复杂对象的内部结构。指望通过提供文档链接来解决,在面对复杂的内部系统时,基本等于缘木求鱼。

经过反思,既然AI无法“看见”二方包代码,便需要设法为其“开天眼”。文章调研并采用了以下几种解决方案。

让大模型读懂二方包的解决方案让大模型理解二方包:解决方案探索

此前的LLM幻觉问题,根源在于AI工具无法直接理解二方包的说明。这些AI工具常会尝试拼凑内容,假装完成了任务,若不仔细核查,甚至可能误认为其表现尚可。这类似于业务通过数据营造欣欣向荣的假象,或员工向管理者汇报任务完成,无论采用何种方式,最终目的都是呈现结果。🐶

前面提到,对于依赖下游二方包的需求,LLMs需要获取外部依赖知识才能生成代码,因此需要提供工具使其了解这部分知识。类比一位刚接手代码仓库的新同学,其熟悉项目的方式通常是查阅项目知识库,并通过IDE进行源码跳转。

对于大模型而言,同样存在两种解决方案,对比如下:

方案 优点 缺点
构建项目知识库:维护当前项目所需内容及外部依赖说明,可将接口类、出入参类都拷贝进去。 1. 能够让LLM对当前项目有一个全面的理解。
2. 人工可加入理解说明,因接口参数说明不全面时需人工解读。
1. 建立的知识库对当前项目理解深入,但对外部依赖理解仍局限于自身使用。
2. 需全集团维护公共完整知识库才能很好解决外部依赖问题。
3. 知识召回准确度可能存在问题,可能召回不需要的内容。
实现类似IDE的索引查询:开发时能像人一样点击到定义处了解具体类信息。 1. 召回的类数据一定是最准确的。
2. 可召回类依赖数据,确保LLM对某个类的理解全面完整。
1. 知识强依赖于类的说明和注解,错误的注解会影响最终效果。
2. 包需下载到本地.m2,分析可能Token耗用量较大。

为使AI工具能够获取二方包内容并实现需求,文章调研了以下几种方案。

▐方案一 & 二:大力出奇迹 — 手动“投喂”源码

最直接的思路是缺啥补啥。既然LLM看不到二方包的源码,那么直接将源码复制给它即可。这显然是最直接的方案,此处不再赘述手动将源码复制到聊天框的方案。

文章尝试了公司内部的AoneCopilot和通用的Claude,发现它们提供了一些无需手动粘贴即可读取二方包代码的方案。

  • 方案一:使用AoneCopilot

1. 找到选定文件后右键选择直接发送文件到chat

AoneCopilot能够分析指定文件的代码信息,并能解析二方包中的方法。尽管其识别出入参为QueryBizOrderDO,但由于未手动将二方包中的QueryBizOrderDO类添加到聊天上下文,Agent并未在二方包中查找此DTO,而是在项目代码中读取,最终未能找到入参的定义。

此方案与手动粘贴代码给Agent无异,只能读取手动添加进去的文件,对于未手动添加到chat的文件Agent是不能读取的。

AoneCopilot发送文件到chat的截图

可能会有疑问,如果这个二方包没有上传源码的情况,Agent能否拿到代码内容呢?经过测试,发现可以获取到代码内容。根据AoneCopilot文档说明:当使用“Add File To Chat”功能时,IDE已完成文件读取和反编译工作,并将结果直接提供给AoneCopilot,因此此时可直接获取反编译后的代码内容。

2、告知使用read_file工具

可以指定全限定名,并告知其使用read_file工具读取代码。此方案可以让AoneCopilot分析此类的代码信息,并且也能够分析未指定的入参的类的信息。此方案看起来已比较智能,但貌似只能读取有源码的二方包中的内容。

AoneCopilot使用read_file工具读取代码

  • 方案二:使用ClaudeCode

  • 要求ClaudeCode阅读源码,模型内部应做了特殊处理(估计也提供了类似 AoneCopilot 的read_file工具),其能够直接定位到.m2文件中的下载的jar包,并且CC能自动读取未指定的入参的类,表现相当出色。但同样,貌似只能读取有源码的二方包中的内容。

ClaudeCode阅读源码的交互截图ClaudeCode自动读取入参类ClaudeCode分析二方包源码效果总结:

评价: 简单粗暴,大力出奇迹。对于一次性的、依赖不多的临时需求,此方法立竿见影。只要将读取源码(或者使用read_file)这个prompt添加到rules,模型基本就能够实现。

缺点: 不是很优雅,每次提问都需要重复“投喂”,如果依赖关系复杂,涉及十几个类,那么复制粘贴将是体力活,且容易超出模型的上下文窗口限制。另外也要求有二方包的源码。

▐方案三:自己动手,丰衣足食 — 本地反编译MCP

手动投喂过于笨拙,是否存在更优雅的方式?答案是肯定的。通过MCP工具,LLM能够像IDE一样“查看定义”。就像程序员在IDE中点击一下就能看到各种定义。

核心思路分两步:

  • 建索引 (Index): 在项目初始化时,通过mvn dependency:tree扫描项目所有依赖的二方包,再通过jar tf命令解析每个jar包,建立一个“类全名 -> JAR包路径”的本地映射索引。

  • 反编译 (Decompile): 提供一个Java Class Analyzer工具。当LLM需要分析某个类(比如QueryBizOrderDO)时,它会调用这个工具。工具根据索引找到对应的JAR包,然后调用cfr之类的反编译库,将.class文件实时反编译成Java源码,再返回给LLM。

具体MCP由长济提供,由于此工具目前只在内部提供,此处仅介绍基本原理和使用效果,不详细说明安装方法。

  • 实现:

本地反编译MCP方案实现原理

  • 初始化项目建立二方包的索引数据,通过 mvn dependency:tree -DoutputType=text -DappendOutput=false -o 获取当前项目依赖的所有二方包,通过 jar tf “${jarPath}” | grep ‘.class$’获取所有类名,建立class->二方包的索引。

  • 提供一个类分析的工具,通过cfr进行类的反编译即可拿到对应的类。

Prompt说明需要加上使用工具(提醒有这么个工具可以分析类和函数的说明):当要分析某一个类的时候可以使用 Java Class Analyzer进行分析,整个项目最开始需要告知调用 java class indexer 初始化。【这个语句直接添加到项目维度下的rules即可】。

使用MCP工具后大模型成功解析类信息

可以看到,通过索引工具和类分析工具,大模型非常顺利地获取了完整的类、出入参的说明。要求给出查询代码,也给出了非常好的调用示例,重要的是import都没有问题,代码是直接可用的。

使用结果:

MCP方案下大模型生成的可用代码

总结:

  • 评价: 这才是真正的“授人以渔”!通过这种方式能够很好地解决LLM不理解二方包内信息的问题,避免LLM幻觉胡乱发挥的问题;一方面减少了技术方案中的各种资料库和外部说明(文档想要做到实时保鲜太难了),更重要的是提高了代码生成的准确率和可用性。生成的代码质量和准确率飙升,连import都书写得明明白白。

  • 优点: 一次配置,长久受益。最重要的是,它不依赖任何外部系统,只要是本地的依赖包,无论是集团内部的还是开源的,通通都能搞定。

配置MCP后AI完成订单查询需求干活:配好反编译MCP后再给AI一次机会

使用方案三,将MCP和rules配置好之后,大模型非常顺利地完成了订单查询需求。它能够正确import,并正确构造请求入参,解析出参,不再像一开始是完全不可用的状态。

  • 1. 更新了xxxClient接口

  • 添加了queryBizOrderList方法的定义;

  • 方法签名:List<BizOrderDO> queryBizOrderList(long userId, List<Long> subOrderIdList) throws TCException;

  • 添加了必要的import和注释。

  • 2. 完善了xxxClientImpl实现

查询流程:

  1. 先查在线订单库:使用xxxService.queryMainAndDetail方法查询;

  2. 收集查询结果:将查询到的订单存储到Map中,key为subOrderId,value为BizOrderDO;

  3. 找出缺失订单:收集在线库中没有查到的订单ID;

  4. 查历史订单库:对于缺失的订单ID,使用xxxBaseService.queryMainAndDetail再次查询;

  5. 合并结果:将历史库查询到的订单也加入到Map中;

  6. 按序返回:按照传入的List<Long>的顺序,从Map中取出对应的BizOrderDO并返回。

关键特性:

  • 智能查询:只对在线库没有查到的订单再查历史库,避免重复查询;

  • 保持顺序:严格按照传入的subOrderIdList的顺序返回结果;

  • 健壮性:包含完整的异常处理和日志记录;

  • 性能优化:使用Map进行快速查找,避免重复遍历。

数据结构处理:

  • 正确处理了BatchQueryOrderInfoResultDO返回值

  • 从List<OrderInfoTO>中提取BizOrderDO

  • 使用BizOrderDO.getBizOrderId()作为订单ID进行匹配

MCP方案优化后大模型完成的批量查询逻辑总结:从“方法清单”到“思想升华”

方案 核心思想 优点 缺点 适用场景 点评
手动投喂 缺啥补啥,人肉Copy 简单直接,立竿见影 繁琐,不优雅,上下文易超限 临时、依赖少的简单需求 大力出奇迹,饲养员的快乐!
本地反编译 赋能AI,让它和人一样能够查看定义 一劳永逸,精准 需要一次性配置开发,但Token调用可能会比较多 日常主力开发,复杂依赖场景 自己动手,丰衣足食!有Token财大气粗就没缺点

文章最大的感悟是:不应将LLM视为无所不能的神,而应视其为一个能力边界清晰的强大“工具人”。

手动投喂,是为其“开小灶”;打造反编译工具链,是为其构建“专属的搜索引擎”;无论哪种方式,核心都在于弥合AI基础能力与复杂多变的业务现实之间的鸿沟。

因此,当AI助手再次“犯傻”时,不应急于抱怨其“不行”。而应首先反思:是否为其提供了足够好的“上下文”和“工具”?

TAGGED:AI编程助手二方包代码理解大模型本地反编译
Share This Article
Email Copy Link Print
Previous Article 20251102070736735.jpg 儿童对科学家信任度:媒体反派形象影响有限?
Next Article 20251102073218521.jpg Salesforce CEO抛售股票引关注:AI忧虑笼罩未来?
Leave a Comment

发表回复 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注

最新内容
20251205174331374.jpg
家的定义与核心价值:探索现代居住空间的意义
科技
20251202135921634.jpg
英伟达20亿美元投资新思科技,AI芯片设计革命加速
科技
20251202130505639.jpg
乌克兰国家AI模型选定谷歌Gemma,打造主权人工智能
科技
20251202121525971.jpg
中国开源AI新突破:DeepSeek V3.2模型性能比肩GPT-5
科技

相关内容

AI 前沿技术

HiRAG问答流程与知识图谱构建深度解析

2025年10月16日
GitHub Copilot与Anthropic Claude Sonnet 4模型集成,提升智能编程效率
AI

GitHub Copilot重磅升级:默认集成Claude Sonnet 4,AI编码性能卓越超越GPT-5

2025年9月17日
RAG双阶段处理流程图
AI 前沿技术

Dify知识库从Demo到生产:RAG构建企业级私有知识库的7个关键步骤

2025年11月1日
GPT-5模型的情感缺失与修复示意图
AI 前沿技术

GPT-5 Instant:修复AI情商漏洞,平衡智能与情感发展

2025年10月6日
Show More
前途科技

前途科技是一个致力于提供全球最新科技资讯的专业网站。我们以实时更新的方式,为用户呈现来自世界各地的科技新闻和深度分析,涵盖从技术创新到企业发展等多方面内容。专注于为用户提供高质量的科技创业新闻和行业动态。

分类

  • AI
  • 初创
  • 学习中心

快速链接

  • 阅读历史
  • 我的关注
  • 我的收藏

Copyright © 2025 AccessPath.com, 前途国际科技咨询(北京)有限公司,版权所有。 | 京ICP备17045010号-1 | 京公网安备 11010502033860号

前途科技
Username or Email Address
Password

Lost your password?

Not a member? Sign Up