我为我的代理配备了搜索工具,但它拒绝使用,以及其他一些我犯的错误
摘要
作者详细介绍了构建一个用于书籍推荐的个人AI代理,分享了关于工具合规性、成本管理和反馈循环的经验,使用基于Go的实现。
我一直在构建一个小型代理来帮助我查找要阅读的书籍和漫画。它从RSS feeds、Bluesky和一些博客中收集候选内容,根据我写在markdown中的口味档案对每个内容进行判断,并通过Telegram向我发送提案以供接受或拒绝。它每周按计划运行一次,我也可以随时向其发出临时请求。从实现角度来看,它是一个在DigitalOcean droplet上运行的单一Go二进制文件。这是个人选择,因为我喜欢Go并在日常工作中使用它。我使用BAML进行提示和LLM交互,使用go-workflows来建模管道,使其在重启后能自然恢复,并使用systemd timer进行调度,这样我可以更改调度而无需重新部署任何东西。我已经让它运行了一个完整的调度周期,还通过Telegram界面进行了许多临时请求。现在还处于早期阶段,但我想写下一些我在此过程中搞错的事情,主要是因为其中没有一个是关于模型本身的。仅仅给它一个搜索工具是不够的,我必须停止要求。我给了评审一个search_web工具,以便它在提案之前验证标题的详细信息。它拒绝使用,并以0.90的置信度愉快地提出了基于卷数、上色师和“无已知改编”的提案,这些完全是从记忆中提取的。让我惊讶的是,即使我在对话记录中告诉它去验证,它仍然拒绝。解决办法是停止要求,而是无条件地先运行搜索,并在其开口之前将结果交给它。我还在每个判决中添加了一个名为completeness_basis的字段,其值可以是verified、my_own_knowledge或not_established。一旦事实被写入文本中,就无法区分查找的和记住的,所以模型必须说明是哪一种。真正有效的限制是代码中的限制。一周内到达我这里的提案数量有一个上限。有趣的是,这有多少必须在代码中保持确定性,而不是让模型随意发挥。上限不是提示中礼貌要求克制的句子,而是这个:if len(accepted) > in.MaxProposalsPerMedium { out.Dropped[m] = len(accepted) - in.MaxProposalsPerMedium accepted = accepted[:in.MaxProposalsPerMedium] }。同样的思想也体现在评审循环的建模中。每一步返回工具调用或最终判决,作为联合类型:function JudgeCandidateStep(...) -> GetTasteProfileTool | SearchItemsTool | CheckPassedOnTool | SearchWebTool | FinalVerdictTool。不在该联合中的工具是模型无法调用的,无论提示如何。最后一点是我推荐给任何构建类似系统的人。公平性只存在于你截断的点。提取每个帖子需要一次模型调用,所以收集有预算。我汇总了所有来源,按日期排序并取前N个。这悄悄地将预算变成了关于发帖频率的竞赛。添加两个每小时发帖的subreddits,从每周发帖的新闻通讯中占用了所有五个名额。更糟糕的是,这在我注意到之前就一直在发生:一个漫画网站因为其帖子较旧而在每次运行中都被排除在外。解决办法是引入轮询方法,每个来源轮流,首先处理最新的内容。然后我需要第二个修复,当我意识到预算完全是在限制错误的东西时。获取是网络请求,而提取才是花钱的步骤。在知道有什么可供选择后,限制昂贵的步骤。反馈循环只有在“拒绝”与“接受”同样便宜时才能闭合。我有十三次接受和零次拒绝,并不是因为所有提案都是想要的。接受只需两次点击。拒绝需要两次点击加上在一个我不在的浏览器中写一句话。所以口味模型只听到了“是”。我将拒绝移入Telegram以减少摩擦。关于成本,我在测量之前不知道一次运行花了多少钱。BAML提供了一个捕获输入和输出令牌的良好界面,所以我将其纳入了代码。一次完整的调度运行成本约为1.80美元,而评审在一半的调用上消耗了三倍于提取的输入令牌,这个数字告诉你需要调整哪个旋钮。最后一个可能是我最喜欢的,因为这完全是我自己的错。代理提案了Batman: Year One并声称它是创作者拥有的。我说这显然是错误的,它是DC的受雇创作作品。然后我认真阅读了自己的口味轴,发现其中有一行写着,即使我选择的超级英雄也是“交给一个大胆创作者”的版本。按这种解读,它确实符合,而我正是那个要写错误内容到文件中的人,而这个文件本应是真相来源。代理在这里没有产生幻觉,它使用给定的数据解决了歧义。规范是脆弱的部分,而不是模型。我很乐意详细讨论这些中的任何一个,特别是BAML或go-workflows方面。我写了整个东西,包含更多代码和截图,我会在评论中放链接,因为链接在这里应该放在那里。
相似文章
我用JavaScript从零开始构建了一个网页搜索AI智能体
作者使用JavaScript和LLM工具调用从零开始构建了一个网页搜索AI智能体,展示了无框架下的智能体构建,并将代码分享在GitHub上以获取反馈。
我构建了一个赛博朋克风格的智能体匹配工具,受够了克隆那些有问题的仓库
作者开发了一个免费的基于问答的工具,帮助开发者在50多个选项中寻找合适且维护良好的AI智能体仓库,避免那些出现故障或过时的仓库,并正在寻求社区反馈。
好奇大家实际上在使用哪些无代码/低代码AI代理工具
作者对比了多种无代码和低代码AI代理工具,并寻求社区反馈,了解这些工具在实际应用中的表现,而非仅限于原型阶段。
你的智能体到底用来干什么?不是编程相关的。
作者向社区征集非编程领域使用AI智能体的实例,分享了家庭晚餐协商和背景调研等个人用例,并邀请其他人描述他们的窄领域专用智能体。
AI 代理依然拉胯,于是我自己造了一个
作者构建了一款自定义 AI 代理应用,封装了 Claude Code 并即将支持 Codex,侧重于可组合的工作流,并期待社区反馈。