这几个月我一直在折腾AI代理(AI Agent),最大的感受是:模型本身的能力当然重要,但真正让AI从“会聊天”变成“会干活”的,往往是框架。ChatGPT刚火那阵,大家让它“写个周报”,它给你一段文本,你自己复制粘贴到文档里;现在用OpenClaw这类代理框架,你可以直接说“把下载目录里的文件按类型归档,整理出一份清单发给我”,它会自己去扫描目录、建文件夹、移动文件、生成报告,全程你只需要在关键节点点确认。差别就在这:聊天是给建议,干活是动手办。
1. AI从会聊天到会干活,卡在哪儿?
1.1 聊天是“嘴上功夫”,干活是“手脚并用”
很多人有个误解:模型足够聪明,自然就会干活。其实不是。模型再聪明,它本质上也只是一个“文本接龙选手”——输入一段文字,输出下一段文字。在聊天场景下,它输出的是回答,你负责理解和执行;但在干活场景下,它必须自己把回答变成一连串真实操作。比如让它“把图片压缩后传到指定目录”,它得先知道图片在哪、用什么压缩、传到哪个目录、重复文件怎么处理。这些动作单靠模型内部的知识是完成不了的,必须有外部工具帮它执行。
OpenClaw解决的问题,就是在这两者之间架一座桥:把模型生成的意图翻译成可执行的工具调用,再把工具返回的结果喂回给模型,让模型决定下一步。这套机制有一个专门的说法叫ReAct循环,来自“Reason + Act”的组合。模型先想一下当前要做什么,然后调用一个工具,看结果,再想下一步,循环往复,直到任务完成。本质上就是“小步快跑,边做边看”,而不是让模型一次性生成一个完整答案然后结束。
我见过不少刚接触Agent的朋友,以为只要把API接上,AI就会自动干活。实际跑起来才发现,模型经常不知道该调哪个函数,或者调了函数但参数填错,甚至干到一半忘了自己已经处理过哪些文件。这些问题不是模型笨,而是缺少一层“施工框架”。换句话说,聊天只需要嘴巴,干活需要手、脚、眼睛,还需要一套指挥手脚的流程。
1.2 干活需要一套“翻译机制”和“安全锁”
聊天时错了重说就行,干活时不行。所以一个能干活的AI框架必须回答三个问题:第一,模型怎么知道有哪些工具可用?第二,模型怎么把自然语言请求转成规范的工具参数?第三,工具执行出错或者产生不可逆影响时怎么办?
第一个问题的答案,是工具注册表。OpenClaw会让开发者把每个工具的描述、参数结构、返回值结构登记成一个JSON Schema,模型通过读取这些Schema,就知道“我有哪些手可以用”。第二个问题的答案,是结构化输出。框架要求模型输出固定格式的调用请求,比如“调用move_file,参数src=/tmp/a.txt,dest=/tmp/docs/”,而不是自由发挥说一句“帮我把文件移过去”。第三个问题更关键:很多代理框架默认带“审批模式”,工具要执行危险操作前,先暂停下来问用户。
你可能觉得审批模式多此一举,但真让AI删文件、发邮件、改配置时,你就会庆幸有这道锁。我自己的习惯是,跑陌生任务时全程开启确认模式,等摸清了模型的脾气再放开权限。说到底,大模型不是确定性程序,它每一步都有概率性。安全机制不是“产品体验”,是“底线”。
2. OpenClaw的代理循环:让大模型真正动起来
2.1 代理循环长什么样
如果你翻过Agent框架的源码,会发现核心其实就那么几十行:一个循环,里面四步——观察当前状态、规划下一步、调用工具、根据结果反思。OpenClaw把这个循环做成了可配置的流程,你可以调整最大步数、是否让用户确认、是否允许并行调用多个工具。
最简版的循环,用伪代码表示大概是这样的:
while not task_finished and step < max_steps: observation = get_current_state() # 当前任务状态 plan = model.reason(observation) # 模型思考下一步 action = parse_tool_call(plan) # 解析工具调用 result = execute_tool(action) # 执行工具 memory.push(observation, action, result) # 记录到上下文这里没有魔法,就是很朴素的“循环加上下文”。模型每一步都在看上下文,而上下文里的信息是工具的真实返回结果,不是模型自己编的。这也是代理框架和大模型直接对话最大的区别:模型不再靠想象猜测结果,而是靠工具反馈获得事实。
举个生活化的例子。你让实习生去整理仓库,他不会站在仓库门口脑补里面有什么,而是先推开门看一眼,再决定先搬什么。代理循环就是逼着模型“推开门看一眼”,而不是闭着眼睛写一份《仓库整理计划书》。
2.2 工具注册:告诉模型“你有这些手”
工具注册是代理框架里最影响成败的一环。OpenClaw里一个工具定义通常包含:名称、一句话用途、参数Schema、返回值说明、内部实现。名称和用途描述决定了模型会不会在正确时机选它,参数Schema决定了模型能不能填对参数,返回值说明决定了模型能不能看懂结果。
我见过不少翻车现场:工具描述写得太笼统,比如就写“处理文件”,模型根本不知道什么时候该调它;参数约束没写清楚,结果模型传进来一个不存在的路径。所以一个成熟的做法是:工具描述里带上使用场景和边界,比如“list_files:列出指定目录下的文件,适合在归档前查看目录结构。参数dir必须是绝对路径,不支持~”。
这里放一个工具定义的示例,方便你直观感受 Schema 长什么样:
{ "name": "move_file", "description": "将文件从源路径移动到目标目录,适用于文件归档、整理场景", "parameters": { "type": "object", "properties": { "src": {"type": "string", "description": "源文件的绝对路径"}, "dest_dir": {"type": "string", "description": "目标目录的绝对路径,目录必须已存在"} }, "required": ["src", "dest_dir"] } }模型读到这个Schema,就会按格式生成调用。如果你的工具没有Schema,模型就只能“自由发挥”,结果就是参数错乱、任务中断。工具注册这件事,做得越细,模型越不容易跑偏。我自己调试Agent时,花在工具描述上的时间比写工具实现还多,这个投入非常值。
2.3 记忆与上下文管理:干活不能没有“小本本”
聊天时上下文丢了,用户可能没察觉;干活时上下文丢了,AI会忘了自己已经移动了哪些文件,然后重复操作。所以代理框架通常有两类记忆:短期记忆和长期记忆。短期记忆就是当前任务的完整上下文,每次循环都追加进去;长期记忆则是任务结束后沉淀下来的总结、偏好、规则,下次任务可以直接复用。
OpenClaw的通用思路是:短期记忆需要裁剪,因为大模型上下文窗口有限,不能把所有日志都塞进去。要定期把旧内容压缩成摘要,保留最近几轮的关键信息。长期记忆可以存成结构化记录,比如“用户喜欢把图片放在/pics/image目录,而不是/pics/img”,下次直接按这个偏好执行。
这个点很值得重视,也是很多Agent项目“跑得起来但跑不久”的原因:任务一长,上下文爆了,模型开始胡言乱语。我后面会专门讲怎么排查这个问题。这里先记住一句话:干活型AI的上下文,不是越多越好,而是越“精炼”越好。
3. 实操:用OpenClaw自动整理下载目录并生成归档报告
3.1 先说需求,再定工具
选一个最典型的场景:自动整理下载目录。目标是:扫描Downloads目录下所有文件,按扩展名放到images、docs、archives、others等子目录,最后生成一份归档报告,记录每个文件移动前后的位置。这个任务不大不小,刚好能把“规划、调用工具、失败处理、生成结果”全流程走一遍。
一开始不要贪多。我给自己的要求是:先能用,再优化。所以第一批工具只定义三个:list_files,扫描目录,返回文件列表和大小;move_file,移动文件到目标目录;write_report,把结果写到指定位置。三个工具足够跑通整个流程,也不至于让模型做太多选择。工具少,模型决策就简单。
很多新手容易犯的错是,一上来就把场景设计得很宏大,要给模型准备十几个工具。工具一多,模型选择的难度几何级上升,它经常选了错误的工具,然后你还得在日志里疯狂排查。我的经验是:第一批工具控制在三到五个,先把主链路跑通,再逐步加工具。
3.2 定义工具和系统提示词
我用OpenClaw风格写一个简化配置。先注册工具,再给系统提示词。系统提示词不能只写“你是文件整理助手”,那样模型容易自作主张。要写清楚任务边界:先列目录、再分类、再建目录、再移动、再报告。更重要的是,要写明白“不允许删除任何文件”“遇到重名文件要跳过并在报告中说明”。
提示词原文不需要太长,但关键约束必须显式声明。以下是我实际用过的精简版:
你是文件归档助手。你的任务是把下载目录中的文件按类型归档。 执行步骤: 1. 调用list_files查看下载目录的完整文件列表。 2. 根据文件扩展名确定目标子目录:图片类(jpg/png/gif)放images,文档类(pdf/docx/txt/md)放docs,压缩包(zip/rar/7z)放archives,其他放others。 3. 如果目标子目录不存在,先调用create_dir创建,再调用move_file移动。 4. 遇到同名文件时,跳过移动,并在最终报告中标记为“冲突文件”。 5. 禁止删除任何文件。 6. 全部完成后,调用write_report生成报告。这个提示词的核心作用,是给模型一个“施工图纸”。模型按步骤执行,而不是凭“直觉”乱来。我在没有这些约束时试过一次,模型直接想把同名文件覆盖掉,幸好是在测试目录。所以提示词里的约束不是给模型添堵,是给自己兜底。
3.3 跑起来之后看到的效果与要注意的关键点
实际运行时,模型的行为大致是:先list_files,拿到文件列表后开始规划;然后按顺序建目录、移动文件;中途如果遇到文件不存在,它会尝试再次list_files确认;最后调用write_report。整个过程大概两三分钟,取决于文件数量和API响应速度。
我这边第一次跑出来的报告长这样:
归档完成,共处理12个文件。 移动: report.pdf -> Downloads/docs/report.pdf 移动: photo.jpg -> Downloads/images/photo.jpg 冲突: archive.zip 已存在同目录同名文件,已跳过。看见没,模型不仅完成了任务,还会自己处理冲突。这就是代理框架的意义。但也别高兴太早,有几个点一定注意:第一,一定要先在临时目录测试,别一上来就拿真实下载目录练手;第二,建议开启“确认模式”,让每次移动文件前都弹一个确认,确认模式跑顺了再关掉;第三,关注日志输出,OpenClaw这类框架会把每一步的工具调用都打出来,出问题能快速定位。
我自己的习惯是:先跑一遍dry-run,把“会做什么”列出来,人工看一眼逻辑没问题,再正式执行。这多花两分钟,但能避免很多不可逆的后悔。干活型AI最怕的不是慢,而是不可控。
4. 常见问题与排查技巧实录
4.1 上下文越跑越长,AI反而变笨
最常遇到的坑,就是任务还没干完,模型就开始“忘事”。原因通常是上下文管理没做好:每次把完整文件内容塞给模型,几轮之后token爆炸,模型只能勉强回应,决策质量直线下降。
排查思路:一是看单次工具返回的数据量,如果返回了整个文件内容,改成只返回文件路径、大小、修改时间这类元数据;二是开启自动摘要,把早期步骤压缩成“已移动文件清单”放进上下文,而不是保留全部原始日志;三是给工具返回加截断,超过一定长度就只保留前N行。我实际测试里,把list_files的返回值从“完整文件树”改成“扁平列表加数量统计”之后,任务成功率明显提升。
这里有个反直觉的点:你以为给模型的信息越多,它越聪明。但在Agent场景里,信息越杂,模型越容易迷失重点。干活型AI需要的不是“全量信息”,而是“当前这一步最相关的信息”。
4.2 工具调用参数总出错
另一个高频问题:模型生成的工具参数不合法。比如路径拼错、目录不存在、把整数参数传成字符串。这其实不能全怪模型,很多时候是工具定义没写清楚。解决方法是:要么在工具内部做参数校验和修正,要么在Schema里写严格的格式说明。
我建议在工具内部做“防御性处理”。比如move_file,开头先判断src是否存在,不存在就直接返回错误信息;dest_dir不存在,就自动创建而不是报错。这样就算模型传错参数,工具也能自行消化一部分,任务不会硬生生中断。记住一个原则:不要依赖模型自觉,把边界写在工具代码里。
顺带一提,有时候模型传给工具的路径是带空格的,比如“/Users/me/My Downloads/file.pdf”,而工具内部没有处理空格,直接拼接路径就炸了。这种问题,在工具内部对参数做一次strip和合法化检查,可以避免掉大部分低级错误。
4.3 死循环和不必要的重复操作
模型有时候会在两个工具之间反复横跳:list_files看到文件在A目录,move_file之后再次list_files,发现文件还在原处?这可能是因为工具实现有bug,或者模型误解了返回值。死循环在Agent场景里特别消耗预算,而且看着很蠢,明明报错了也不改策略。
解决思路:第一,给循环加最大步数上限,OpenClaw里可以配置,比如最多50步,超过就强制停止并把当前状态报告给用户;第二,增加“去重提示”,在工具返回里写上“该文件已在本轮任务中处理过”,模型看到就不会重复处理;第三,发现同一操作重复超过阈值,让框架主动暂停,把上下文交给用户接管。这些都是工程上非常管用的兜底措施。
我还遇到过一个很有意思的情况:模型把“移动文件”和“复制文件”搞混了,它以为move_file执行后原文件还在,于是下一次迭代又尝试移动同一个文件。后来我在工具返回值里明确加上“原文件已不存在”,模型的困惑立刻少了很多。这说明,工具返回值不仅要准确,还要“有信息量”。
4.4 “大而化之”的规划害死人
还有一个隐蔽问题:模型特别喜欢“一次性规划所有步骤”,然后按规划顺序执行。如果中间某个文件的情况和预期不一致,整个计划就崩了。比如模型规划“先建3个目录,再把8个文件移过去”,结果发现下载目录里其实有15个文件,它可能就愣住,然后开始重复执行旧的计划。
正确做法是让模型“走一步看一步”,而不是把所有希望寄托在一份完整计划上。你在提示词里可以加一句“每次调用工具前,先根据最新返回结果判断下一步,不要依赖之前规划里的假设”。这样模型会更灵活,不容易被自己的计划锁死。
我踩过几次坑之后,习惯把每类任务都先做一次小样本测试,比如先只整理3个文件,看模型行为和预期是否一致,再扩大范围。这比一次性跑大批量数据再回头debug高效得多。
最后分享一点我个人实操中的体会:让AI干活,一开始别追求“全自动”,把每一步的确认、回滚、日志都做好,等你摸清了模型在真实任务里的脾气,再慢慢放开。工具定义越细,边界越清晰,模型越不容易自由发挥;反过来,你越指望模型“聪明地临场发挥”,翻车概率就越高。OpenClaw这类的代理框架,本质上是给大模型装上双手、上了保险,真正让人放心的,还是那个在背后做设计和兜底的人。