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如果不记得这些,每次对话都是“新来的”。
我的
