1. 从改界面改到心态崩,到想给WinForms配一个懂行的Agent
1.1 老项目的痛,全在Designer文件和属性记忆上
我手头维护的几个WinForms项目,年纪最小的也有三四年,大的那个从.NET Framework 2.0时代一路升到4.7.2,窗体代码里到处是早年留下的“风格遗迹”。这类项目的共同特点是:业务逻辑不复杂,但界面层极其琐碎。一个稍微像样点的订单录入窗体,放上七八个GroupBox、十几个TextBox、三四个DataGridView,再配上右键菜单、状态栏、校验控件,整个Designer文件能到两千行。
改这种界面的痛苦在于,大多数需求根本不是“写新功能”,而是在现有控件堆里调整行为:给某个ComboBox加一个下拉事件、把某个DataGridView的某列改成只读、调整一下控件之间的锚定关系。每一次改完,都要在窗体设计器和代码文件之间反复切换,查控件名、查属性枚举值、查事件签名。这些事不是不会,而是太琐碎,琐碎到让人怀疑人生。我记得有一次改一个DataGridView的单元格样式,为了确认DataGridViewCellStyle的各个属性到底怎么配,翻了半个小时的文档和社区帖子,最后只改了三行代码。
1.2 Agent在这里不是替代写代码,而是接住三类脏活
所以当我开始接触AI Agent相关的东西时,第一个冒出来的念头就是:能不能让一个Agent来帮我干这些脏活?这里的“脏活”我归类成三类:
第一类,知识点查询类。WinForms的控件体系太大了,属性、事件、方法加起来数百个,即便是用了十年WinForms的人也记不全。比如DataGridView的AutoSizeColumnsMode有哪几个枚举值、每个值的表现差异是什么,这种问题就是典型的“搜索一下就知道,但搜索本身很烦”的场景。第二类,代码定位与结构理解类。一个两千行的Designer文件,要找出某个按钮的事件挂载点、某个控件的初始化位置,靠肉眼扫很费劲。第三类,代码生成与批量修改类。比如把窗体上所有TextBox的Enter事件都挂上一个统一的方法,或者给一组Button批量设置统一的FlatStyle和BackColor,这类重复性操作最适合交给Agent。
这就是我做WinForms Expert Agent的初衷:不是让Agent替代开发者写业务逻辑,而是让它作为开发环境里的一个“资深WinForms顾问+码农助理”,把文档查询、代码理解、批量修改这三类活接住。这篇文章把我从选型、架构到落地过程中积累的经验完整梳理一遍,适合正在做Agent开发、或者想在老项目中引入智能辅助的.NET开发者参考。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Agent骨架怎么搭:主从协作、记忆分层、Skill与MCP的取舍
2.1 主从模式:把子Agent当作一种特殊工具来调用
在设计WinForms Expert Agent的架构时,我第一个纠结的问题是:到底用单Agent一把梭,还是用多Agent协作?单Agent的好处是简单,上下文统一,不需要考虑Agent之间的消息传递。但实际跑下来,单Agent在WinForms这个垂直场景里有明显的天花板。
原因在于,WinForms的辅助工作其实包含好几个能力维度,而且每个维度需要的上下文差异很大。比如“查DataGridView的AutoSizeColumnsMode枚举说明”这件事,只需要一个精简的属性知识库就够了;但“解析整个Form的Designer.cs文件并给出控件树结构”这件事,需要的是代码分析能力,跟属性知识库基本不重叠。如果把这些都塞进同一个Agent,系统提示词会变得非常臃肿,而且每一轮对话都要把所有能力文档加载进上下文,既浪费token又拖慢响应。
后来我采用了主从模式,也就是主Agent(Supervisor)负责理解用户意图、拆解任务、调度子Agent,子Agent(Sub-Agent)负责具体领域的执行。这个模式现在业界讨论很多,我的理解是:主从模式本质上就是把子Agent当作一种特殊的Tool来调用。主Agent不直接回答“DataGridView的某个属性怎么配”,而是决定“这个问题应该交给控件知识Agent去处理”,然后把子Agent的返回结果汇总成最终答案。
这种设计有几个实际好处。一是上下文隔离,每个子Agent只加载自己领域的知识,主Agent的上下文只保留用户原始诉求和各子Agent的返回摘要,整个系统的上下文消耗大幅下降。二是可以独立测试,控件知识Agent、Designer解析Agent、代码生成Agent可以单独调试,哪个环节出问题就修哪个。三是扩展性好,以后想加一个新的能力维度,只需要新增一个子Agent并注册到主Agent的工具清单里就行。
实际落地时,我给每个子Agent定义了一个标准的调用协议:输入参数是一个JSON结构,包含任务描述、上下文数据、输出格式约定;返回结果也是JSON结构,包含执行状态、结果内容、置信度说明。主Agent通过函数调用机制触发子Agent,子Agent执行完毕后把结果回传给主Agent,由主Agent决定是直接回复用户还是继续调用其他子Agent。这个模式跑了一段时间,稳定性比单Agent高很多。
2.2 记忆层设计:长期记忆存项目约定,短期记忆存轮次上下文
Agent光有工具还不够,还得有记忆。在WinForms这个场景里,记忆的重要性甚至比通用Agent更高。原因很简单:一个项目的控件命名方式、代码风格、业务约定,是高度个性化的,Agent如果不记得这些,每次对话都是“新来的”。
我的记忆层分两层。短期记忆就是多轮会话的上下文,记录当前这次会话里用户说过的需求、Agent已经做过的修改、以及用户对中间结果的反馈。这一层我直接复用Agent框架自带的对话历史管理,限制最大轮次,超过就做摘要压缩。实际过程中我发现,WinForms的修改任务往往需要多轮确认:“先把A按钮的Text改了,再把B按钮的Enabled设为false,等一下,B按钮的Text也一起改了吧”,这种逐步追加的需求,短期记忆必须足够可靠。
长期记忆存的是跨会话的项目级信息。我设计了一个项目配置模型,包含三个部分:
- 项目基本信息:解决方案路径、目标框架版本(比如.NET Framework 4.7.2)、主命名空间、UI项目的程序集名称。
- 控件命名约定:比如按钮统一用btn前缀、TextBox统一用txt前缀、DataGridView统一用dgv前缀。这个信息的作用是,Agent在生成新代码或修改现有代码时,能主动遵循项目的命名风格,而不是生成一个叫button1的新变量。
- 风格偏好:比如窗体背景色、按钮的通用FlatStyle、字体统一用微软雅黑9pt等。这些信息来自我跑Agent时手动录入,或者Agent从现有Designer文件里自动提取。
长期记忆存储我用的就是项目根目录下的一个JSON文件,Agent启动时加载,会话结束后如果有变化就回写。有人可能会问,为什么不放到数据库里?我的考虑是,WinForms项目的Agent通常是以“开发助手”的形态存在,单人单项目使用,JSON文件足够简单直接,而且能看到具体内容,方便手动修正。如果以后要支持多人协作,再换后端存储也不迟。
2.3 Skill与MCP怎么选:本地能力用Skill封装,外部数据走MCP
这里得聊一个最近特别热的话题:Agent的Skill和MCP(Model Context Protocol)到底有什么区别,什么时候用哪个。我的理解不一定权威,但根据实际落地经验,可以给一个比较实用的判断标准。
Skill在我的理解里,是给Agent预置的一套能力封装,本质上是“把某个领域的专业知识和操作步骤固化下来,让Agent在特定场景下调用”。它更像是一本内部培训手册加一组内部工具:培训手册告诉Agent“遇到这类问题该怎么思考”,内部工具告诉Agent“具体可以调哪些方法”。我的WinForms Expert Agent里,控件知识库、Designer解析器、代码生成模板这些,都是以Skill的形式存在。它们有一个共同特点:不需要依赖外部系统,所有逻辑和数据都在本地。
MCP的作用则是打通Agent与外部系统的数据通路。假如有一天我想让Agent去查询项目管理系统里的需求单,或者从内部的控件样式服务器拉取最新的主题配置,这时候就需要MCP来标准化Agent与这些外部系统之间的通信。可以把MCP理解成一个通用的USB接口:只要外部系统实现了MCP协议,Agent就能像插上USB设备一样直接访问它,而不需要为每个系统单独写一套集成代码。
我的取舍原则是这样的:如果能力完全可以在本地闭环实现的,用Skill,因为它的开发成本低、调试直观、不依赖网络。如果能力需要跨系统交互、而且希望未来能被其他Agent复用,那么考虑MCP。目前我的WinForms Expert Agent里面,90%的能力走Skill,MCP暂时只做了几个实验性的对接,比如接入一个内部的代码片段服务,目的是验证MCP的可行性,为后续扩展探路。
3. 让Agent真正懂WinForms:控件知识库与Designer解析
3.1 控件、属性、事件、方法的知识库,不是塞文档而是建索引
Agent要成为WinForms专家,第一步就是得有高质量的WinForms知识储备。但这里有个很容易踩的坑:很多人以为把微软官方文档或者某本WinForms书籍的文本灌给Agent就行了,反正大模型能理解自然语言。我一开始也这么干过,效果很差。
差的根源在于,大模型在训练时就见过大量WinForms相关内容了,你额外塞进去的文档反而可能造成信息冲突和上下文污染。而且,把几百页的文档全文喂给Agent,光是上下文长度就够喝一壶的。我的做法是:不塞文档,而是建索引。
具体来说,我整理了一份WinForms核心控件的结构化索引,每个控件记录四类信息:
- 基本用途:这个控件是干什么的,一句话说清。
- 常用属性:列出实际开发中最高频的10到20个属性,注明每个属性的类型、默认值、常见取值。
- 常用事件:列出最重要的5到10个事件,注明触发时机和典型使用场景。
- 常用方法:列出实际会手工调用的方法,注明方法和属性的配合方式。
这个索引并不是把文档里的所有内容都搬过来,而是只保留高频和易错的部分。比如DataGridView,我的索引里重点记录了AutoSizeColumnsMode、DataSource、DataPropertyName、DefaultCellStyle、AllowUserToAddRows这几个高频属性,以及CellClick、CellValueChanged、DataError这几个高频事件。对于不常用的深水区属性,索引里只留一个“详见官方文档”的标记,让Agent去搜索引擎检索,而不是硬背。
3.2 Designer文件解析:从InitializeComponent逆向出项目模型
如果说知识库解决了“懂理论”的问题,那么Designer文件解析解决的就是“懂现状”的问题。Agent要帮用户改代码,首先得知道当前项目里有什么。
WinForms的Designer文件(Form1.Designer.cs)本质上是一段C#代码,里面是InitializeComponent方法,包含一系列这样的语句:
csharp复制this.btnSave = new System.Windows.Forms.Button();
this.dgvOrders = new System.Windows.Forms.DataGridView();
// ...
this.btnSave.Text = "保存";
this.btnSave.Location = new System.Drawing.Point(12, 12);
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
要让Agent理解这段代码,我写了一个轻量级的Designer解析器(Parser),基于Microsoft.CodeAnalysis(Roslyn)来做语法分析。解析器的核心任务有三个:
第一,构建控件树。遍历InitializeComponent方法里的new语句,找到每个控件的类型和变量名,再根据Controls.Add和Controls.SetChildIndex的调用顺序,还原出窗体的控件层级关系。第二,提取属性赋值。把像this.btnSave.Text = "保存"这样的赋值语句提取出来,记录到控件节点的属性表里。这个属性表之后会作为Agent修改代码时的依据。第三,建立事件绑定关系。把this.btnSave.Click += new System.EventHandler(this.btnSave_Click)解析成“控件btnSave的Click事件绑定到了方法btnSave_Click”。
3.3 实战:让Agent自己动手改一个DataGridView的样式
知识库和解析器就位之后,Agent才真正有了“动手”的基础。我拿一个实际需求来演示整个链路:用户说“帮我把订单列表改成隔行变色,表头深蓝色,自动列宽”。
这个需求主Agent收到后,会做几步处理。第一步,判断这是控件样式修改任务,分发给控件知识子Agent去查DataGridView的相关属性和枚举值。知识子Agent返回的内容包括:AlternatingRowsDefaultCellStyle.BackColor可以设置偶数行颜色;ColumnHeadersDefaultCellStyle.BackColor可以设置表头背景色;AutoSizeColumnsMode设置为Fill可以实现自动列宽。
第二步,主Agent把修改任务连同Designer解析器给出的当前控件属性表,一起交给代码生成子Agent。代码生成子Agent的任务是输出具体的修改代码。它需要知道当前DataGridView的变量名是什么(假设是dgvOrders),当前是否已经有DefaultCellStyle设置(如果有,是覆盖还是合并),事件绑定情况如何。最终生成的代码可能是这样:
csharp复制dgvOrders.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(240, 244, 248);
dgvOrders.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(31, 78, 121);
dgvOrders.ColumnHeadersDefaultCellStyle.ForeColor = Color.White;
dgvOrders.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
第三步,主Agent会调用一个静态检查子Agent,对生成的代码做合理性校验。校验点包括:控件名是否存在、属性名是否拼写正确、枚举值是否是该属性的合法取值、有没有明显的逻辑冲突(比如同时设置了AutoSizeColumnsMode为Fill又手动设了列宽)。校验通过后,Agent把修改方案返回给用户,等用户确认后执行。
我在这步做了一个特别重要的设计:Agent默认不直接写回Designer文件,而是先给出修改方案让用户确认。原因是Designer文件是Visual Studio窗体设计器的核心依赖,一旦格式出错,轻则代码编译不过,重则窗体设计器打不开。让用户确认这步,虽然多了一个交互环节,但能挡掉大多数低级错误。
4. 在.NET Framework 4.7.2上搭Agent运行环境的实战记录
4.1 为什么宿主程序选WinForms + 4.7.2,而不是.NET Core
聊技术选型之前,先说一个背景:我的WinForms Expert Agent不是一个独立的命令行工具,而是直接嵌入到一个WinForms宿主程序里。换句话说,Agent的运行环境本身就是一个WinForms进程,用户通过一个侧边栏窗口和Agent交互。
为什么这样设计?因为WinForms开发者的工作流是围绕Visual Studio和窗体设计器展开的,我不想让Agent变成一个需要切换到外部窗口才能用的东西。把Agent嵌入到WinForms进程里,最大的好处是不需要离开窗体调试环境,Agent可以实时读取当前打开窗体的Designer文件、甚至直接操作窗体实例。
宿主程序的目标框架我选的是.NET Framework 4.7.2,不是.NET Core或.NET 6+。原因很现实:我要辅助的项目本身就是4.7.2的。虽然.NET Framework下做Agent开发会遇到很多麻烦,比如Roslyn的版本兼容、异步支持不如现代.NET好、一些新库不可用,但为了能直接在目标环境里跑,这个代价值得。如果你要辅助的项目是.NET 6+,那宿主程序也建议用对应版本,别跨。
4.2 一个绕不开的选型:4.7.2下做BLE通信用什么库
在开发过程中,我还遇到一个和Agent本身无关、但被频繁问到的问题:在.NET Framework 4.7.2的WinForms项目里,想实现BLE蓝牙通信,能用什么第三方库?
这个问题我研究过,因为有一个需求方希望在他们的老WinForms程序里加上BLE设备通信功能。直接说结论:4.7.2环境下做BLE,目前比较靠谱的方案是32feet.NET这个老牌蓝牙库,它在NuGet上的包名是InTheHand.Net.Personal,社区版可以覆盖基本的BLE中心设备模式,支持扫描、连接、读写特征值。如果你需要更完整的GATT服务端能力或者更激进的功能,也可以考虑升级到InTheHand的付费版本。
另一个思路是使用Windows.Devices.Bluetooth的WinRT API,但4.7.2直接引用WinRT API会比较别扭,需要做不少适配工作,而且不同Windows版本的行为差异也很大,调试成本高。我当时做技术评估的时候,给需求方的建议是:如果BLE功能是刚需,而且未来还有持续迭代的计划,不如考虑把通信层拆成一个独立模块,用.NET Core的Worker Service来实现BLE,再通过本地IPC和WinForms主程序通信。这样既能绕开.NET Framework对WinRT支持不好的问题,又能让通信层独立部署、独立升级。
这个选型经验其实也能用在Agent设计上:如果一个能力在宿主环境里实现不好,就把它拆出去,通过进程间通信来调用。Agent本身不需要什么都在主进程里做。
4.3 Agent执行提供方超时:did not respond in time的排查思路
在实际跑Agent的过程中,我还遇到过一个非常典型的报错,相关信息搜索热度也很高,就是“the agent execution provider did not respond in time. this may indicate the”。这个报错的意思是:Agent执行提供方没有在预期时间内返回结果。
我排查这个问题的过程,可以给同样在做Agent开发的人一个参考。第一步,确定是什么环节超时。我的Agent链路里有多个环节:主Agent接收请求、调用子Agent、子Agent中的工具执行、最终响应生成。任何一个环节卡住,都会体现为客户端这边的超时错误。我通过加日志埋点的方式,把每个环节的起止时间打出来,定位到是哪个环节耗时异常。
第二步,分析超时原因。我遇到的超时主要集中在两类情况。一类是模型推理超时:当问题比较复杂、上下文较长时,大模型的推理时间会明显变长,超过了我设置的客户端超时阈值。另一类是子Agent调用外部工具卡住:比如Designer解析器在解析一个特别大的Designer文件时,或者代码生成子Agent在调用搜索引擎检索文档时,如果这些工具没有设置自己的超时,就可能无限等待。
第三步,对症下药。对于模型推理超时,我做了三件事:一是调大客户端超时阈值,从30秒调到60秒;二是限制单轮上下文长度,过长的历史记录先做摘要再做增量拼接;三是把复杂的单次请求拆成多个小的子任务,让主Agent先出阶段性结论,再逐步细化。对于工具调用卡住,我在所有外部工具调用外面套了超时保护,默认15秒必须返回,超时则向上层抛出“工具调用失败,请重试或换一种方式”。
如果你也遇到这个报错,我的建议是先从日志定位耗时环节,不要一上来就盲目调大超时参数。盲目调大只会让问题从“超时”变成“长时间无响应”,体验更差。
5. 三个典型翻车现场,以及我加的防呆规则
5.1 跨线程改UI导致假死,Agent却毫不知情
第一次让Agent实际执行代码修改时,我犯了一个WinForms开发者都应该知道的经典错误:跨线程访问UI控件。
当时我给Agent加了一个“直接应用修改”的能力,让它在后台线程里执行生成的代码片段。结果在修改某个Label的Text属性时,程序直接抛了InvalidOperationException,提示“线程间操作无效,从不是创建控件的线程访问它”。有些场景下甚至不抛异常,而是界面卡死,Agent还傻傻地以为修改成功了,继续执行后续步骤,整个窗体就变成了假死状态。
这个问题让我明白:Agent即使再智能,它也没有WinForms开发者的“肌肉记忆”——不在工作线程碰UI。解决方案也不复杂,我在Agent执行代码片段的外层包了一层UI线程调度器。具体实现是:调用了控件的Invoke或BeginInvoke方法,把实际执行代码的委托调度到UI线程上。同时我在Agent的System Prompt里明确加了一条规则:所有涉及UI控件的操作,必须通过UI线程调度器执行,禁止直接从子Agent线程访问控件。
5.2 事件被重复挂载,点一次触发三次
第二个翻车场景是事件重复挂载。在一次批量修改中,Agent要给窗体上的多个按钮统一挂上检查逻辑。它生成了一段代码,大致逻辑是遍历所有按钮,给Click事件添加事件处理程序。但问题是,这段代码每次触发时都会重新执行一遍挂载逻辑,而挂载前没有先判断事件是否已经挂载过。
结果就是,按钮的Click事件被挂载了三次。用户点一次按钮,事件处理程序执行三次。第一次出现这个Bug的时候,我甚至没往Agent身上想,以为是自己代码写的重复了。后来一查才发现,Agent生成的代码里有一个循环,外部循环遍历按钮,内部循环又调了一次公共的挂载方法,天然就重复了。
教训是:Agent在生成事件绑定相关的代码时,必须要做幂等性检查。我在代码生成子Agent的输出规范中加了几条强制约束:事件挂载前先检查方法是否已经在事件的调用列表中;优先使用-=再+=的模式来确保唯一绑定;对于循环内的事件挂载,必须在循环外先写好处理函数,循环内只做一次绑定。另外,代码生成子Agent的输出会被静态检查子Agent自动检查,凡是发现重复挂载的,直接打回重写。
5.3 上下文一长就失忆,靠什么把约定钉在Prompt里
第三个问题比前两个更隐蔽:上下文越长,Agent越容易把项目约定忘掉。我遇到过的情况是,会话进行到第30轮左右时,用户让Agent“把这个新按钮也放到现有按钮的那一行去”,结果Agent生成的新按钮还是从默认位置开始排,完全忘了之前约定的布局规则。
我分析下来,问题的根源是:短期记忆里的对话历史虽然包含了项目约定,但大模型的注意力在长上下文里会分散,早期的关键信息被后续的琐碎对话稀释了。解决办法是在主Agent的System Prompt里设置一个“项目约定固定区”,把用户确认过的关键约定写进去,并且在每一轮对话开始时都重新加载。
这个固定区的内容是结构化的,比如:
- 命名前缀约定:按钮btn、标签lbl、文本框txt、数据表格dgv
- 布局规范:新控件默认跟随上一个控件的底部,间距8像素
- 风格规范:背景色统一使用Color.White,强调色使用Color.FromArgb(31, 78, 121)
- 编码规范:事件处理统一挂载在InitializeComponent下方的Load事件中,不直接写在构造器里
用上这个固定区之后,Agent的“失忆”问题明显缓解了。我的体会是,与其指望大模型在长上下文中记住所有细节,不如主动把关键约定放到它每轮都能看到的位置。这和给新员工写交接文档是一个道理,把重要的事贴在墙上,比让对方翻聊天记录靠谱得多。
6. 用了大半年,我对WinForms Agent的真实评价与建议
6.1 收益最大和收益最小的环节
WinForms Expert Agent跑了半年多,我对它的能力边界有了比较清晰的判断。收益最大的场景,集中在风险低、重复度高的任务上。比如批量修改控件属性、查询控件的事件签名和属性枚举值、生成重复的事件处理逻辑、快速梳理Designer文件的控件结构。这些任务的特点是:答案相对标准、错误代价低、人工做又很耗时。Agent在这些场景下效率提升明显,一个之前需要二十分钟的批量修改,现在一两分钟内就能给出可执行的方案。
收益最小的场景,是那些需要深度业务理解的重构任务。比如“把订单列表改成支持多选批量审核”这种需求,涉及业务逻辑梳理、数据模型调整、UI交互重设计,Agent目前最多只能做到碎片化辅助,离独立完成还有很大距离。我一开始对Agent的预期偏高,总希望它能一口气解决复杂需求,后来发现把需求拆细、每个小步骤让Agent逐个处理,比让它一步到位靠谱得多。
6.2 给.NET开发者的一条Agent学习路径
因为我本身就是.NET背景,很多同行问我“Agent开发要从哪里开始学”。我结合自己的经验,给一条比较务实的路线。
第一步,不要一上来就学框架,先学Prompt编写。你先拿一个现成的大模型,把WinForms里的高频问题丢给它,看看它答得怎么样,慢慢摸索出怎么描述问题能拿到最准确的答案。第二步,学工具调用(Function Calling)。这是Agent能不能干活的分水岭。你给模型定义几个函数,比如“查询控件属性”“解析Designer文件”,让模型学会在合适的时机调用这些函数。第三步,学Agent框架。有了工具调用的基础,再接触Agent核心的循环机制:模型接收任务、调用工具、观察结果、继续推理。多Agent协作、记忆管理、上下文压缩,都是在循环机制之上的扩展。第四步,学评估。给Agent跑测试用例、统计成功率、记录回归问题,这一块最容易被忽略,但决定Agent能不能从“demo”变成“工程”。
6.3 接下来想做的三个扩展方向
这个项目目前还没有停下,我下一步计划做三件事。第一,给Agent接入MCP,让它能跨进程访问更多资源。比如通过MCP去读取另一个后端服务提供的业务数据,让Agent在生成代码时能参考真实数据形态。第二,做一个控件样式库的沉淀功能。把我在各个项目中手动调整过的控件样式提取出来,做成一个可复用的样式包,让Agent在修改新项目时可以直接套用,而不是每次从零计算。第三,把Agent接入自动化测试流程。让Agent生成的代码自动跑一遍控件级冒烟测试,比如检查按钮是否触发对应事件、数据表格是否正确绑定数据源,用自动化测试来给Agent的修改兜底。
这个项目做下来,我最大的体会是:Agent不是神,它更像是一个记性好、反应快、但需要你盯着的小朋友。你给它划好边界、立好规矩、备好工具,它能帮你干不少活;你指望它全自动接管一切,它就会在各种意想不到的小细节上翻车。WinForms Expert Agent这个方向,我判断还会继续演进,尤其是MCP生态成熟之后,Agent能连接的系统越多,它在老项目里的价值就越大。做这个项目的过程中,最大的收益不是代码本身,而是让我把Agent开发从“听过概念”变成了“亲手踩过坑”,这些经验,比任何教程都值钱。
