起源
最初的想法是源自特别忙碌的一周——pre,小测,全部蜂拥而至,无论我决定去做什么事,总感觉没有安排妥当。仔细思索之后,如果有一个外部的事物,它可以帮你做出相当好的时间规划,那么我就可以将时间规划的责任外放到它身上,或许可以减少些许焦虑。其实这种事在中小学时大家都经历过,相信小学的时候,大家都觉得,学习的事情照着老师说的做就行,那时候可以说是完全信任老师了(正常的老师),一直到高中,渐渐发现老师也不是全能的,而且很多时候听老师的不如自己去做决策,便开始自己为自己的人生负责。虽说决定权仍在自身,但若有这样一个独立于自身之外的第二主体,无论如何想必也是轻松一些。
其实要实现这个想法并不是特别复杂:设置课表、toDo、日程、爱好、目标、……自己设计一套严格的规则,用硬编码的方式创建出来一个传统应用,也是显然可行的。然而,我总觉得这样的方案其实是在将自己的意志写入程序当中,总觉得它并没有独立于我,我将决策的责任放在它身上之后,还是感觉在自己做决策,没有跟着按部就班的感觉。所以最终还是用Agent的形式设计了这个项目。
而且有一个WeiXinBot的库,可以直接接到微信的clawbot,所以非常兴奋地开始实现。库在这里:
here
初稿
众所周知上下文太长,LLM会傻掉,所以控制上下文其实是Agent设计的核心,既不能让它没有上下文,也不能让它知道太多产生幻觉。因为Deepseek最便宜所以用Deepseek,仔细学习API文档之后,才发现原来LLM有许多之前没见过的API,最重要的就是每条message都有role和content,以及tool_calls。我再三思考写了初稿:
控制层
简单来说,就是监听信息,操作应用层给出回复,发送回复wellenough agent
将现有result和用户输入喂给AI,让它判断是否已经足够好,以及已经迭代的次数,让它动态判断。返回true或者false。一开始result为空就是falseplan agent
讲用户输入分解为多个任务,每个任务不能过于复杂,需要比较简单,json格式,即若干个提示词,对于每个提示词调用worker agent。拼接返回结果。需要将之前的提示词已经当前的result作为上文history提交给workercommand check agent
温度很低,提示词包含已有skill的api接口文档,让它检测给出的command是否合法。如果合法,返回True+空串,否则返回False+修改建议worker agent
调这个AI的时候,提示词应当包含已经存在的skills,而且temperature需要调得很低。让它生产若干个skill操作的集合。(json)格式。调用check agent,判断是不是正确的,如果是,执行这个集合,如果不是,将错误信息添加到提示词,回到开头循环继续。每5次循环之后询问用户是否继续,如果用户选择退出,返回False+错误原因(再次生成)。否则继续循环。总体是一个主循环,只要不wellenough,就继续调用planner。每一次都要回复一次,如果出现了无法处理的东西,可以询问用户是否使用迭代层自行研发skill。每5次询问用户是否继续。每一次提问到给出回复,我们都要记下来。最近10条对话是完整信息。前面就只需要摘要。应用层
若干个skills,包含了调用AI生成plan,设置course,添加日程记录作息表设计成一个class,1440数组,0代表00:00-00:01,依次类推。元素是对象,content是内容,fixed是是否必需进行
课表是7个作息表,代表周一到周日
日程记录是一个对象,key是日期比如20260401,value是当日作息,一张作息表1. 修改course信息,格式0-6(星期) xx:xx-xx:xx课程名称 ,也就是有三个参数。(不一定两位,写个正则匹配)
2. 添加日程记录,格式是日期id,然后就是一个数组,依次是时间段和content以及是否是fixed
3. 添加待办事项。一个deadline。还有一个内容。以及可能偏好的时间段。
4. 添加长期规划目标。只有内容,然后有上一次AI建议的频次等等
5. 上述内容都对应了查询操作。
6. 获取plan,需要给一个日期。因为上面的控制层已经做了worker agent,所以这个可以只生成一天的,这样不论是一周还是什么的,他都可以改出来。只生成目标日期的作息表。如果目标日期已经有记录了,那就返回说已经有了作息表,然后反馈之前那一张。不然的话就获取近90天(如果有)的作息表。还需要查询当天的课表。用户的待办事项和规划。以及可能存在的上文就是已经有了未来的作息表。(当然plan agent也需要有修改之前已经弄好的作息表的权限)。然后掉调AI,让他生成新的plan。
7. 运行控制台命令,这是为了迭代。迭代层
AI可以操纵自己创造新的skill
skills列表喝规范存在文档里,控制层调迭代层的迭代agent时,需要传入需要的功能,然后迭代agent会新的skill写成一个单独的脚本。这个默认的skill有区别。默认的skill比较快速,因为是通过模块调用的方式。这个skill必须使用文件输入输出来处理一些特殊的东西,比如说图片。
本来想要省事还设计了一个迭代层,写到后面才发现根本用不上,LLM的幻觉远比我想象中严重,执行我给的tool_calls都不一定准确……
这个模型我用vibecoding工具和手搓了一个下午,才搓出来一个初版,而且效率着实太低,一句简单的回复需要处理特别特别久,token消耗巨大。而且那个wellEnoughAgent有了上下文之后总是会输出莫名其妙的东西。所以我对它进行了简化。
第二版
因为写初稿的时候并没看到tool_calls这个东西,后面还是用tool_calls实现的,所以command_check_agent就省略了。这一版我简化成了三层Agent:
MainAgent,主Agent,负责判断用户是否操作plans数据(有AddPlan,DelPlan,AskPlan方法),以及对数据库进行操作(调用DataAgent的权限),还可以综合信息来生成日程计划DataAgent,数据库Agent,负责操作数据库的增删查改,因为项目很小,就直接用json文件存数据了。有Add, Del, Ask, Format方法。Format,格式化工具,单纯把我输入的自然语言格式化成我要求的格式,返回严格的JSON格式,status: 0/1, content: ...。MainAgent有全量上下文记忆,其它两个都是无记忆的。
这版的叽咕助手成功跑起来了!而且效果似乎还不错!于是赶紧补充了历史记忆history的储存规则:超过HISTORY_MAX条,就从头开始弹出,交给SummaryAgent提取概要后再放在队头。这样可以控制上下文长度。
问题出在对话数上来之后,有一次我让叽咕添加一条record,LLM产生了随机幻觉,这也很正常,所以他没有调用DataAgent之后,就告诉我操作成功了。本来我再让它重新操作就行了,但是由于这个上文的污染,他每次都说,操作成功了!
非常抽象,试图修改Prompt多次,Prompt工程还是失败了。后面做了一下实验,如果不加上文,终于聪明了……
我意识到这似乎不是Prompt的问题,是架构设计的问题:
- 我要求
MainAgent通过上下文理解用户的意图,这要求MainAgent扮演一个感性的角色,而且他要参考上下文; - 我又要求
MainAgent准确执行指令,这要求MainAgent扮演一个理性的角色,而且从上面问题可以看出,这部分人格最好是不要有上下文记忆。 - 这本身就是矛盾的,我让Agent不要参考上下文直接修改数据库,Agent由于Prompt中要求我让他根据上下文……,他就会发现矛盾,然后去上文找答案,于是又得去参考上下文……
和Kimi还有豆包聊天了很久,总结了一个设计原则,即Agent的角色只能是下列之一:
- 严格的决策机器,没有上下文,但无法生成拟人的回复;
- 感性的拟人态,有上下文,但不能执行命令。
第三版
简单来说,我加入了一个RouterAgent路由层,它没有上下文,严格返回决策type,1为数据库操作,2为生成plan,3为闲聊。它负责生成一个任务列表。
我还将plan的增删查改并入DataAgent。
新增的PlanAgent负责之前MainAgent的计划部分,他也没有上下文。(因为我设计了ChatAgent总结,不需要他生成拟人的回复)
新增ChatAgent负责之前MainAgent的拟人部分,他有全量上下文,负责总结所有Task的处理结果给出回答。
但是在应用中存在一些指代关系,比如用户添加一个record,AI说没有日期,你输入日期之后,如果RouterAgent一点记忆没有,就会说没有内容。这显得很蠢,所以RouterAgent需要有很短的上下文窗口,DataAgent同理。
然后问题又来了,只要有这个上下文窗口,RouterAgent的行为就变得非常不可控(事实上出现了类似第二版的问题),所以我采用的方案是先总结这个窗口生成摘要,添加一个getHis的tool,让它非常需要额外历史信息时再去获取,不要每次都硬编码加入到提供的信息中。
DataAgent同理,只提供数据库操作相关上文,而且也不是硬编码提供,让它自己get。
总而言之,到了第三版,叽咕助手已经相当稳定了,除了简陋的数据库设计导致的效率极低之外,基本上已经稳定了。
后续
不知道是不是开始开发Agent之后,开始关注这方面信息,我发现了LangChain这个东西。看到之后,感觉我上面的设计完全就是它的简陋版本,重复写了好久的轮子显得很蠢(
不过经过这次尝试,对AI取代人类的焦虑确实是减轻了不少,因为它确实还是很蠢(
本来还想学习一下OpenClaw,现在看来也没必要了,感觉指望它能帮你干所有活实在太不现实了……我用MiniMax实现第一版Agent项目的时候,问题都一大把,最后还是得自己来写……连这种专精的AI工具都无法完美完成工作,我是不指望一个从头到尾自动化的OpenClaw效果能有多好了……不过了解到它也有一个类似WellEnough的东西,会一直烧token试图做出来成果。说实话,我感觉这有点难评……
后面还是打算用数据库硬编码这些日程表,用传统应用去生成规划表了,AI最好仅仅做一些文书工作,这是最好的。
