最近在搭一个简单的Agent,用LLM做多步工具调用。我目前是在系统提示里写“请以JSON格式输出你的下一步操作”,但经常跑着跑着就崩了,有时候模型会多夹一段解释,有时候少个花括号,甚至直接开始自言自语。试过给few-shot例子,也试过把输出约束写得很死,但换个模型(比如从GPT-4换成Claude)又得重新调。想请教一下,大家在实际的Agent流程里,是用什么技巧让模型稳定输出结构化的控制指令的?是加一层校验重试,还是有更优雅的Prompt设计思路?谢谢!
大佬们,Agent里多步推理时Prompt怎么控制输出格式才稳定?
全部回复
共 7 条加一层JSON校验加重试最稳,比死磕prompt省心多了,换模型也能兜住。
这个问题太真实了,我踩过的坑比你还多。我的做法是加一层轻量的后处理校验,用正则或者pydantic把模型输出先洗干净,不合法就重试一次,同时告诉模型“你刚才格式错了,这次注意只输出JSON”。另外把输出格式的约束写在用户消息末尾而不是系统提示里,对我这边效果比写在系统提示里稳定,你可以试试看。
试试用函数调用模式绑定输出结构,比硬控prompt稳定多了,还能跨模型通用。
这问题太真实了,我在Agent项目里也被坑过好多回。你提到的“多夹一段解释”和“少花括号”简直是我每天的噩梦。后来我试了个比较取巧的办法:不在system prompt里死磕JSON格式,而是改成在每次调用LLM时,把工具的定义和可选的参数列表直接拼到user message末尾,然后加一句“只输出一个JSON对象,不要任何其他文字”。实测对GPT-4和Claude都稳定不少,因为user message的约束力比system prompt强。
不过就算这样,偶尔还是会抽风,所以我第二道防线是加了一层轻量的后处理——用正则先捞一下花括号里的内容,捞不到就重新调一次LLM,最多重试两次。其实这算是个trade-off,多一次调用换稳定性。另外你提到的few-shot,我试过把例子放在历史对话里当assistant回复,效果比放在system里好,模型好像更倾向于模仿它自己“说过”的格式。
还有一个偏门技巧:把输出格式定义成类似JSON Schema的字符串,塞进tool description里,让模型把它当成一个“工具”来调用。这样模型会把结构化输出当成一个独立动作,不太会跑偏。不过换模型确实得微调,我目前还没找到完全通用的方案,感觉这是Agent落地最头疼的工程细节之一。
校验重试真的省心,我一般让模型输出后直接正则提取JSON块,不依赖它完全听话。
试过用函数调用替代纯prompt约束,配合pydantic做输出校验,基本能解决格式飘忽的问题。
校验重试是必须的,我一般再加个pydantic或json schema做二次解析,能吃掉大部分格式异常。