借助 Trae Work 学透 Multi-Agent 代码:从「抄出来了但没懂」到完整调通 v1.0.8
记录用 Trae 学习《多 Agent+Skills+SpringAI 构建自主决策智能体》教程代码的全过程。教程代码跟敲完了,但 Multi-Agent 协作链路、工具调用机制、异常定位------都没真正搞懂。这次拿 Trae 当私教,从代码分析到前端搭建到后端实测调通,前三章完成 v1.0.8 完整学习。如果你也有「能跑但不理解」的教程项目,这种学法值得试试。
前言
之前在掘金跟了一篇教程《多 Agent+Skills+SpringAI 构建自主决策智能体》,讲的是用 AgentScope + Spring AI 搭建 AiTripPlan(智能旅游规划系统)------ManagerAgent 调度 RouteMakingAgent、TripPlannerAgent、SuggestSightAgent 等多个子 Agent,协同完成出行规划。
跟着敲完了,代码也跑起来了,但说实话:心里虚得很。
- Multi-Agent 之间到底怎么协作的?ManagerAgent 怎么调度子 Agent?
- 工具调用链是怎么走的?
via ManagerAgent那个提示哪来的? - 加了日志,Agent 有没有被真正调用到?
- 报错了怎么定位?代码里哪些是核心逻辑、哪些是样板代码?
这些问题不搞清楚,这段代码就永远只能算「抄出来了」,不算「学会了」。
最初用 Qoder 起手做了代码分析和前端搭建------毕竟之前做过掘金图片上传工具,对它的代码生成能力有底。但 Qoder 免费额度很快就用完了,正好切到 Trae。结果这个切换反而点醒了我:你以 Trae 写代码,我用 Trae 学代码。 以前没搞懂的代码,结合 Trae 一步步分析、调试、验证,完整弄通了。三章下来,v1.0.8 不仅调通了,更重要的是每一行代码都真正理解了。下面是完整的学习过程。
一、代码分析与文档输出:先搞清楚 v1.0.8 到底有什么
第一步不是改代码,而是搞清楚现状。Qoder 起手,把 AiTripPlan-v108 的代码结构、Agent 架构、核心功能全部梳理一遍,并输出成文档。
分析 AiTripPlan-v108 大概是多agent,一个manage 多个agent,但是没有真正跑起来
先给出代码分析,并编写文档保存在 AiTripPlan-v108 的doc目录。
为什么没真正起作用,主要功能,都列出来,先作计划。


这一步下来,项目的整体面貌就清楚了:ManagerAgent 是总调度,RouteMakingAgent 负责路线规划,TripPlannerAgent 负责行程生成,SuggestSightAgent 负责景点推荐。各个 Agent 之间通过状态(State)和边(Edge)连接,数据传输用的是 OverAllState。文档落了地,后面每一步该往哪走就有了地图。
二、Trae 搭前端:学习项目也得有个能看的东西
纯后端的学习太抽象了,切到 Trae 之后第一件事:生成一个 Vue3 前端。不是为了好看,而是有了前端才能真正跑通完整的请求-响应链路。这是学习项目,接口不一定是正确的,正因为没学懂,才更需要前端来帮助验证。
AiTripPlan-v108 代码 ,分析后,先编写个前端, vue3 的版本,因为这个是学习项目,接口不一定是正确的。就是因为没有学懂,才要你帮忙分析的。放在当前目录


Web 页面长这样:


前端跑起来之后,学习的路径就打通了:聊天输入 → 后端 Agent 调用链 → 返回结果 → 前端展示,每一步都可以实际看到,不再只是看代码猜逻辑。
三、Trae 正式测试理解:跑起来、查问题、啃透代码
前端有了、代码结构也理清了,接下来就是最核心的环节------让后端真正跑起来,用真实请求去测,哪里报错就查哪里,哪里不懂就追哪里。这一章全部用 Trae 完成。
3.1 启动后端,验证 Agent 调用链
用 Trae 分析后端启动日志和 Agent 调用情况,确认有没有被正常调用。
我已运行后端,用真实代码进行测试,为什么没有正常调用agent,还有具体怎么调用,如果有问题,查一下在哪


结果发现 Agent 调用并没有按预期走。深入排查需要结合代码,但这里出了一个小插曲:代码目录指错了,Trae 访问的是另一个路径下的 AiTripPlan-v108。重新指定目录后才正确显示出来:
makefile
先将这些生成文档,代码不在这里,而是在E:\ivy\ai\ai-code-projects\qoder目录上AiTripPlan-v108



为了确认 Agent 确实被调用到了,加日志是最直接的办法:在 RouteMakingAgent、TripPlannerAgent 和 SuggestSightAgent 里都加上日志,跑一次就知道走到哪了。
现在修改后端代码,在RouteMakingAgent、TripPlannerAgent和SuggestSightAgent添加日志,让我知道,确实调用过。


加上日志再跑,问题浮出水面了:Agent 调用会报错,而且非常慢。
现在问题是调用agent会报错,查看日志。 调用非常慢。为什么


核心错误找到了------DashScopeHttpException: DashScope API error: url error,AgentScope 调用 DashScope 的 API 地址不对。同时 Agent 调用走的是 block 模式,导致响应非常慢。
这些报错信息也是学习材料,一并存档:
将这些报错的图,文档之类都形成md文档

3.2 修 Bug 实战:从「调不通」到「搞懂了」
真正考验 Trae 的时候到了------改代码,不是改完就行,而是要边改边理解。第一个要修的问题:变 block 为流式,解决响应卡死。
scss
按要求修改,不要block,改成流式。


改完后跑了一次,抓到了具体报错------关键的 DashScope URL 错误:
php
[15:20:55.096] INFO v.w.i.m.h.PlanHook - 帮我制定从合肥到岳西红二十八军,旅游 3天日程
[15:20:55.767] WARN v.w.i.m.a.ManagerAgent - Agent 流式执行异常
io.agentscope.core.model.DashScopeHttpClient$DashScopeHttpException: DashScope API error: url error, please check url! For details, see:
https://help.aliyun.com/zh/model-studio/error-code#error-url
at io.agentscope.core.model.DashScopeHttpClient.lambda$stream$2(DashScopeHttpClient.java:292)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:116)
at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onNext(FluxFilter.java:248)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:224)
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.onNext(FluxSubscribeOn.java:155)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:80)
at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.runAsync(FluxPublishOn.java:448)
at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.run(FluxPublishOn.java:536)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:93)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)

错误明确了之后,还有几个行为上的谜团需要解开:
一、为什么程序会经常重启
二、工具调用
via ManagerAgent 是哪来的
三、 看似聊天完成,但没有发到前端




Trae 帮我定位了「via ManagerAgent」的来源------这是 Agent 工具调用的前端展示问题。先关掉:
还有一个小问题,将工具调用via ManagerAgent关掉吧。 这是前端的问题吧。

但光关掉不够,我更想要的是把真实调用效果做成 mock 数据那样的展示------方法名、Agent 归属、返回结果,一目了然:
🗺️
callRouteMakingAgent
via RouteMakingAgent
TOOL_RESULT
【callRouteMakingAgent 返回】
起点:深圳市(经度 114.06,纬度 22.55)
终点:惠州市(经度 114.41,纬度 23.11)
驾车路线:深圳 → 惠深沿海高速 → 惠州,全程约 96 公里,耗时约 1 小时 30 分钟。
途经:盐田港、大亚湾、惠阳区。
mock显示就比较好
而真实的显示
🧭
工具调用via ManagerAgent
能不能也修改后端,变成mock一样的


中间反复调试了几轮,Trae 在理解代码上下文上确实不错------每次反馈它都能顺着之前的分析往下挖,不会动不动从头来。这比上一篇文章里「越改越错」的经历好太多了。


调着调着还有一个效率问题------每次查询 Java 和 Maven 的环境信息太浪费时间了。干脆让 Trae 把这些写进 skills,避免重复查询:
能不能记住java,maven的地址,写在skills里面,每次查询浪费时间,maven也可以使用里面有的。不要每次从网上下载,浪费时间。能不能记住java,maven的地址,写在skills里面,每次查询浪费时间

还有一个小插曲------Trae 只启动了 8110 端口:
是不是只启动了8110,不行就停了,我来启动


最终确认了根因:DashScope API 的 URL 配置问题。AgentScope 2.0 的 API 地址和 1.0 不同,代码里用的地址是旧版的:
php
确定是这个问题
io.agentscope.core.model.DashScopeHttpClient$DashScopeHttpException: DashScope API error: url error, please check url! For details, see: https://help.aliyun.com/zh/model-studio/error-code#error-url
at io.agentscope.core.model.DashScopeHttpClient.lambda$stream$2(DashScopeHttpClient.java:292)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:116)
at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onNext(FluxFilter.java:248)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:224)
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.onNext(FluxSubscribeOn.java:155)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:80)
at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.runAsync(FluxPublishOn.java:448)
at reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.run(FluxPublishOn.java:536)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:93)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)

找到根因之后,很自然的下一步:Trae 提出升级到 2.0 版本。

到这里,v1.0.8 的完整学习过程就走完了------从前端到后端,从 Agent 调用链到 API 配置,每一步都是真实运行、真实报错、真实定位、真实修复。和三小时前「代码能跑但不知道为什么」的状态相比,这次是真的学进去了。
注:升级到 AgentScope 2.0 以及迁移到 opencode 的内容,是下一篇的事情。为什么迁移到Opencode,因为免费额度又用完了。
小结
把前三章的学习过程做个总结:
关于这次学习
- 第一章(代码分析 + 文档):起手把 Multi-Agent 的架构、调用链、核心类全部梳理出来,输出文档。有了"地图",后面的学习和调试才有了方向
- 第二章(前端搭建):Trae 生成的 Vue3 前端不只是个壳,它打通了「用户输入 → Agent 链 → 返回结果」的完整链路,学习从猜变成了看
- 第三章(实测调通) :这一章是核心------加日志验证 Agent 调用 → 发现 block 模式卡顿 → 改流式 → 定位 DashScope API URL 错误 → 优化前端工具调用展示 → 环境信息写入 skills。每一步都是先碰到问题、再让 Trae 查原因、最后改代码验证,这就是「学」和「抄」的本质区别
关于用 Trae 学代码
- 这是我第一次系统性地用 AI 工具「学」一段教程代码,而不是「抄」一段教程代码。差别就在于:抄完了你只知道它能跑,学完了你知道它为什么能跑、哪里会挂、挂了怎么修
- Trae 在跟进上下文方面的体验不错:每次反馈它都能顺着之前的分析往下挖,不会动不动从头来。这一点对学习特别重要------学习是一个连续的、渐进的过程,最怕 AI 每次都"重新理解"
- 关键不在工具本身有多强,而在于你得知道自己要学什么。需求驱动、问题驱动,把 AI 当成能随时提问的私教,而不是一键生成的魔法棒
一句话总结:教程代码「写出来」和「学进去」是两码事。拿 Trae 当私教,逐行分析 + 实测调通,把以前没搞懂的代码完整弄通------这才是 AI 辅助学习的正确打开方式。
是用 Trae 学习《多 Agent+Skills+SpringAI 构建自主决策智能体》AiTripPlan v1.0.8 的完整记录:从代码分析、前端搭建到后端实测调通。这是我第一次系统性地用 AI 「学会」一段教程代码,而非「抄完」一段代码。如果你也有「能跑但没懂」的教程项目,拿 Trae 当私教,这个学法值得一试。感谢阅读!