你的第一个 AI 智能体:一个极简而诚实的构建
智能体就是一个置于循环中、能调用工具的模型。先构建最小而诚实的版本,理解它为何有效,并在添加雄心之前弄清它会在哪里出错。
“AI 智能体”已经变成一个承诺多于解释的词。剥去营销外衣,智能体其实相当具体、也相当可构建:一个语言模型,被置于一个循环之中,配上一组它可以调用的工具,朝着某个目标推进,直到它自己判断任务完成。这就是全部的核心思想。本文将构建这一思想最小而诚实的版本,解释每个部件为何存在,并且——更有用的是——告诉你它会在哪里崩溃,好让你的第一个智能体是你真正理解的,而不是照抄来、寄望它能跑通的。
智能体到底是什么
一个纯粹的语言模型只做一件事:你发去文本,它回复文本,交流就此结束。它无法查任何资料、无法运行计算、也无法对世界采取行动。智能体在这个基础上加了三样东西:模型被允许使用的工具、让它能多次行动的循环,以及它正在试图达成的目标。
关键的转变在于:模型不再只是一个文本生成器,而成为了一个决策者。在每一轮,它都要选择:我手上的信息足够回答了吗,还是应该先调用一个工具?如果它调用了工具,就会拿到结果、重新思考、再做一次选择。这个循环——思考、行动、观察、重复——就是全部机制。任何更花哨的东西,都不过是这个循环的变体。
三种要素
工具是你向模型暴露的函数:搜索网络、查询数据库、做算术、发送邮件。对模型而言,一个工具就是一个名字、一段它做什么的描述,以及一段它期待什么输入的描述。模型从不亲自运行你的代码——它发出一个调用请求,由你的程序运行函数,再把结果交还给它。这条边界很重要,我们稍后会回到它。
循环是把智能体与单次工具调用区分开来的东西。工具返回之后,模型看到结果,再决定下一步做什么,也许调用另一个工具,也许直接回答。没有循环,你拥有的只是一个能用一次工具的模型;有了循环,你拥有的是一个能把步骤串接起来的模型。
目标是你交给它的任务,外加关于它该如何行事的指令:它是为何而设、该优先使用哪些工具、什么时候停下。一个清晰的目标,决定了一个智能体究竟是收敛到答案,还是四处游荡。
设计工具
智能体的质量,很大程度上由它的工具决定,而工具设计正是新手投入不足的地方。模型只有在仅凭描述就能理解某个工具做什么、何时该动用它时,才能用好这个工具。把每段工具描述都当作一小段文档来写,面向一个能干却很死板的读者。
对输入和输出要写得具体。一个 search 工具,如果描述只说“搜索”,那它对模型来说什么也没说清——它搜的是网络、你的文件,还是产品目录?把它讲明白:它搜什么、一条查询应该长什么样、会返回什么。也要说明失败情形——当工具什么都没找到时返回什么——这样模型才能合理应对,而不是凭空编造一个结果。含糊的工具会造就一个在错误时机调用错误对象、随后又对自己造成的混乱临场发挥的智能体。
一条好纪律:工具要少而泾渭分明。三个明显在做不同事情的工具,比十个彼此重叠的工具更容易让模型在其间做选择。等你看着智能体在缺它们时挣扎过后,总可以再添加。
一步步拆解这个循环
下面是用伪代码写出的最小循环,值得慢慢读,因为其余一切都是这段之上的装饰:
messages = [system_instructions, user_goal]
loop:
response = model(messages, tools)
if response asks to call a tool:
result = run_the_tool(response.tool, response.inputs)
append the model's request and the result to messages
continue # back to the model with new information
else:
return response # the model is done; answer the user
读懂正在发生什么。你把对话连同可用工具一起发出去。模型要么请求一个工具,要么给出最终答案。如果它请求工具,由你执行它,把请求和结果都追加到正在进行的对话里,再调用模型一次——此刻它掌握的信息比片刻之前更多了。模型不断获取信息,直到足以作答。这个循环并不神奇;它不过是“把模型要的东西给它,然后再问一次”。
你绕不开的护栏
上面的循环有一个每个真实智能体都必须堵上的漏洞:没有任何东西能阻止它永远跑下去。模型可能卡在反复调用同一个工具上,或者追逐一个它永远达不到的目标。所以你要加一个上限——一个最大步数——超过之后智能体就停下,报告它已有的成果,哪怕不完整。一个会承认“我没能在允许的步数内完成”的智能体,远比一个无限循环、或更糟、把成本撑到失控的智能体安全得多。
第二条护栏关乎“决定”与“执行”之间的那条边界。模型决定调用一个工具,但由你的代码执行它——而模型可能出错、被操纵,或者干脆是糊涂了。如果某个工具能做出不可逆的事(删除数据、花钱、向一个真实的人发消息),在你的第一版构建里,就别让循环不受监督地触发它。把早期的工具保持为只读,或者在任何有后果的行动之前要求人工确认。模型是一个有主动性的初级同事:有用、偶尔出错,且还不能把任何你无法撤销之物的钥匙交给它。
第一批智能体会在哪里出错
有几种失败出现得如此可靠,值得提前点名。第一种是工具混淆:模型挑错了工具,或喂给它格式错误的输入,几乎总是因为工具描述含糊。先修描述,再去怪模型。第二种是死循环:智能体重复某个步骤,因为某个工具一直返回无用的东西,而模型一直尝试同一种修法。你的步数上限会兜住这种情况;读一读记录则会告诉你它为何发生。第三种是工具调用失败后的过度自信——一次搜索什么也没返回,模型却照样作答,仿佛它真的找到了什么。解药和处处都管用的那条相同:明确告诉模型,当一个工具返回为空时该怎么做。
把这三者串起来的线索是:你靠读取智能体的轨迹来调试它。那一连串的思考、工具调用与结果,就是智能体推理过程的记录。当出错时,答案几乎总是躺在那份日志里,而一个你无法审视的智能体,就是一个你无法改进的智能体。
总结
智能体就是一个置于循环中、能调用工具、瞄准某个目标的模型。先构建那个最小版本:几个描述得泾渭分明的工具,一个把结果反馈给模型的循环,一道硬性的步数上限,以及在任何不可逆之事前的人工确认。通过读取它的轨迹来观察它运作,你就会清清楚楚地看到它在哪里混淆工具、或在哪里原地打转。那些花哨的多智能体系统,不过是同一个循环的放大版。把这个小而诚实的版本彻底理解透,剩下的就只是延展,而非谜团。
