1. 从“会回答”到“会干活”:GLM 5.1 真正改掉的不是参数表
1.1 我为什么盯上这次升级
先交代背景。我手头有个一直在迭代的“智能工单助理”项目,核心目标是把客服同学从每天几百条重复咨询里解放出来。模型要做的不是回答问题,而是完成一整条工作流:读工单、判断类别、查历史订单、写初步回复、必要时推送审批。这套流程在旧版模型上能跑,但非常不稳,最典型的毛病是工具调用时好时坏:有时给了明确的函数定义,它还是把参数塞错位置;有时绕了两轮就忘了最初目标,开始一本正经地编答案。
GLM 5.1 发布之后,我第一批做了升级试用。最直观的感受是:它终于不再把“答对”当作唯一目标了。过去我要花大量精力去补模型的“执行力”,如今模型自带的 Agent 能力把一部分工作接管了过去,工程上的难点从“逼模型干活”变成了“给模型设计一份靠谱的干活说明书”。这篇文章就是围绕这次升级,把我看到的模型变化、工程化设计取舍、迁移踩坑和落地建议一次讲清楚,适合正在做 Agent 应用、尤其是准备把大模型接进真实业务流程的开发者参考。
1.2 几项关键能力的实际体感变化
我拿一套模拟工单数据做了对比评测,100 条样本覆盖 30 个意图、5 个外部工具,对比升级前后模型在工具选择、参数填充、多轮任务保持上的表现。结果如下:
| 能力维度 | 旧的体验 | GLM 5.1 的体验 | 工程上的意义 |
|---|---|---|---|
| 工具选择 | 偶尔在两个相似工具之间犹豫 | 基本能按描述选准,误选率明显下降 | 可以少写一层“工具分流器” |
| 参数填充 | JSON 里常有多余字段或类型错误 | 基本符合 schema,偶发需要修正 | 校验层仍然要留,但不用过度设计 |
| 长任务保持 | 三轮以上容易丢失目标 | 五轮内主线保持较好 | 记忆层做摘要即可,不必精确回放 |
| 结构化输出 | 不稳定,需要反复纠正 | 一次成功率大大提升 | 流程中的重试成本降低 |
| 思维链推理 | 经常输出冗长思考 | 推理更简洁,结论更直接 | 可以减少对“想太多”的无效 token 消耗 |
这套数据不代表官方基准,但和团队里其他几个项目的反馈基本一致:模型本身的执行稳定性在提升,尤其是“意图—工具—参数—动作”这条链路,终于达到了可以上生产的边缘。
1.3 工程视角:“Agent 型大模型”的本质变化
“Agent 型大模型”这个概念这两年被说得很多,但真正接触代码之后,我对它的理解是:它不再是一个静态的知识库,而是一个拿着工具箱的执行者——能够根据目标任务,自己决定调用哪个工具、填充什么参数、看到结果后再决定下一步动作。这个能力的内核是模型同时具备了三样东西:稳定的意图理解、可靠的结构化输出、以及对“当前任务状态”的感知。
这里面的关键是“当前状态”。聊天模型只需要对上文负责,Agent 模型却必须对“目标”负责。GLM 5.1 在多轮工具调用里表现得明显更“认账”:它知道自己刚才已经查过订单,下一步应该在查到的结果上继续,而不是把同一个问题再问一遍。这一点听起来简单,实际做到非常难,因为它意味着模型必须在长上下文中维护一个隐含的工作记忆。工程上的意义也在这里:我们可以用更薄的记忆层实现同样的效果,而不是把每轮历史完整塞给模型,省下来的都是真金白银的 token。
2. Agent 型大模型工程化的三个支柱:工具协议、上下文与循环控制
2.1 工具协议设计:把“说明书”写到模型能读懂
做 Agent 落地,第一件要设计清楚的事不是模型,是工具。模型再聪明,工具描述写得模棱两可,它也会做错选择。我把工具定义总结成四条原则:
- 工具 description 要写清“目的、触发条件、注意事项”,不要只写函数名。
- 参数定义要有类型、说明、取值范围和示例值,尤其注明哪些参数可空。
- 不要暴露内部字段给模型,比如数据库主键、加密 token、日志标记,模型会把它们当成可用信息。
- 为工具设计“不需要调用”的说明。很多误调用是因为模型不知道什么情况下应该停止。
举个例子,一个查订单工具如果写“根据订单号查询订单”,模型确实会去调用,但遇到用户说“我想看看这个月买过的东西”,它可能不会意识到自己需要先调用一个“解析用户身份”的工具。更好的写法是:“输入用户手机号或用户 ID 查询订单列表;当用户未提供身份信息时,先调用 identify_user 获取 ID;若无法确定,则向用户询问。”
这层设计做完,工具误选率能降一截。不要小看这段描述文本的权重,在 Agent 化的大模型场景里,工具描述就是模型脑中的程序说明书,写得越清楚,执行越靠谱。
2.2 上下文管理:长任务下如何让模型不迷路
Agent 多轮任务最大的挑战不是单步推理,而是“整个流程走到第三步时,模型还记得第一步的目标”。我在项目里采用了一张“状态卡片”的方法,每一轮构造上下文时先把当前任务状态整理成一段固定结构的文本,再拼上本次要处理的消息:
当前任务:处理工单 #T-2024-00123 目标:确认用户订单状态并给出退款方案 已完成步骤: 1. 已调用 identify_user,确认用户ID=u_88772 2. 已调用 query_orders,拉取到近30天订单3笔 3. 已调用 query_order_status,订单#OD-9981处于“已签收” 当前需要:判断是否满足退款条件 待处理输入:用户描述“刚收到的商品有瑕疵”这段内容其实就是“状态压缩”后的工作记忆。GLM 5.1 的上下文窗口足够大,直接塞原文也能跑,但构造一张状态卡片有两个额外好处:一是 token 开销更可控,二是模型不容易被冗余历史干扰。这个思路有点像开发时写接口文档:人要看清楚状态,模型也要看清楚。
在此基础上,我还会把一些高频业务规则抽到系统提示里,比如“签收超过 15 天的订单不走原路退款,转人工处理”。这类规则不需要模型推理,直接给约束即可,比让模型从历史对话里总结要可靠得多。
2.3 决策循环控制:既要用模型的判断,又不能全交给模型
很多初做 Agent 的人会犯一个错误:把决策权全部交给模型——让模型自由决定调用什么、什么时候结束。看起来智能,实际管理起来非常痛苦:模型可能在一件事上绕圈子,可能连续调用高成本工具,甚至在无需外部动作时仍然强行调用。我最终的方案是“确定性外层 + 模型内层”的双层循环:
- 外层由代码写死:明确任务步骤、超时时间、最大调用次数、异常分支。
- 内层每一步调用模型,让它只做两个判断:调用哪个工具,或直接输出回答。
- 每次工具返回后,代码先做结果校验,再决定是否进入下一轮。
这个设计的本质是把“无限自由度”降级成“有限决策点”。模型在每一个决策点上的成功率可能是 95%,如果一次任务要做 5 次决策,整体成功率就已经掉到 77%。所以工程上要做的不是追求每一步都让模型自由发挥,而是把误差控制在单一决策点上,剩下的可靠性交给流程代码来兜底。
我在落地中还加了一条硬规则:模型连续两次调用同一个工具且返回结果完全相同,自动截断并转人工。这个看似粗暴的规则,在实际运行里帮我拦截了很多死循环。
3. 升级到 GLM 5.1 的适配过程与关键取舍
3.1 接口改动与提示模板重写
从旧版本模型切换到 GLM 5.1,第一关就是接口适配。函数调用从原来的“在 message 里塞一段文本格式”变成更严格的结构化格式,返回体中有了独立的 tool_calls 字段,每个调用都带 id、function.name、function.arguments。这意味着上层解析逻辑要重写,不能再用正则去文本里抠参数了。
同时,系统提示也需要重做。旧模型时代,为了让它“听话”,我写了几百字的长提示:强调角色、强调步骤、强调不要乱来。这套提示在 GLM 5.1 上反而有点累赘——模型理解能力增强了,过多的命令式表述会占用注意力,分散对业务关键信息的处理。我把系统提示压缩到两段:一段说明角色与边界,一段列出硬性业务规则。工具说明移动到 tools 定义里,让模型在需要时再“查阅”。
压缩之后有两方面提升:一是平均响应 token 少了不少,二是模型反而更聚焦。这个结果挺有意思,说明新一代模型需要的是“信息架构”,不是“情绪感染式提示”。
3.2 结构化输出:一定要留一道校验闸门
即使 GLM 5.1 的 JSON 输出稳定性提升明显,我仍然不建议无脑信任模型输出。我们平时接收工具调用参数时,流程上会过三层校验:
- JSON 语法解析,失败则带着错误信息让模型重新生成,最多重试两次;
- 参数类型与必填项校验,这类校验用 Python 的 JSON Schema 工具或 Pydantic 模型来完成;
- 业务规则校验,比如订单号是否存在、金额是否为正数,这部分必须查库确认。
我的项目里出过一次事故:模型在调用“发送退款通知”时,把金额参数填成了“免运费金额”,逻辑上没有类型错误,但业务语义完全不对。这说明语义层校验不能省,尤其是涉及资金、通知、状态变更这类有副作用的工具,必须在执行前做一层“人工兜底确认”或“二次规则拦截”。
3.3 离线仿真到灰度发布:别直接在正式环境试
我把适配流程分成了三层:离线仿真、受控联调、灰度上线。
离线仿真就是用历史工单数据回放一遍,让模型跑完整链路,对比新旧版本的工具调用轨迹。这个阶段不用连真实系统,工具一律打桩,返回固定 mock 数据,目的是彻底摸清模型的行为模式。受控联调阶段接入真实工具,但只在测试账号上跑,记录每一步的工具调用、参数、返回值和最终输出。灰度上线前,我会设置 5% 的流量切过去,持续观察一天,重点看“任务完成率”“工具错误率”“用户转人工率”。
整套流程走下来,最大的收获是:升级大模型一定要有配套的测试套件,否则你根本不知道这次升级是帮你还是害你。很多问题不是模型自身能力不行,而是你根本没给它一个可以稳定发挥的工程环境。
4. 一个小而完整的实战:工单分类与跨系统流转 Demo
4.1 业务目标与模块拆解
为说清楚前面的设计怎么落地,我拿一个简化版“工单分类与跨系统流转”举例。场景:客服系统收到用户咨询后,Agent 需要自动完成以下处理。
- 识别意图:退款、发票、物流、技术问题。
- 调用订单工具:查订单、查物流、查退款记录。
- 调用知识库工具:检索退换货政策。
- 输出回复草稿,并在退款场景下推送审批队列。
这里面最大的难点不是识别意图,而是工具之间的连贯使用。比如“我收到的手机颜色不对”这句话,意图是退货,但正确的处理路径是先查订单、再查是否在退换周期内、然后调知识库拿政策条文、最后生成回复。模型需要经过多次工具调用,保持主线不偏。
4.2 核心实现结构:一个可控的 Agent 循环
我把核心循环做了一个简化版本。代码不追求完整,重点看结构:
import json MAX_STEPS = 8 def run_agent(user_input, tools, max_steps=MAX_STEPS): history = [{"role": "user", "content": user_input}] final_tool_results = [] for step in range(max_steps): resp = model.chat(messages=history, tools=tools, tool_choice="auto") msg = resp["choices"][0]["message"] # 不再调用工具,直接出最终回复 if not msg.get("tool_calls"): return {"reply": msg["content"], "steps": step + 1} history.append({"role": "assistant", "content": msg["content"], "tool_calls": msg["tool_calls"]}) for call in msg["tool_calls"]: tool_name = call["function"]["name"] tool_args = parse_and_validate(call["function"]["arguments"]) # 校验失败则把错误返回给模型,让它自行修正 if tool_args is None: history.append({ "role": "tool", "tool_call_id": call["id"], "content": json.dumps({"error": "参数校验失败,请检查必填项与类型"}, ensure_ascii=False) }) continue result = execute_tool(tool_name, tool_args) final_tool_results.append({"tool": tool_name, "args": tool_args, "result": result}) history.append({ "role": "tool", "tool_call_id": call["id"], "content": json.dumps(result, ensure_ascii=False) }) return {"reply": "处理超时,转人工", "steps": max_steps, "tool_results": final_tool_results}这个循环做了三件关键的事:第一,把模型的每一步输出都追加到历史里,保证上下文连续;第二,工具执行结果以 tool 角色回传,模型可以看到真实的执行结果,而不是自己猜;第三,设置了硬性最大步数,防止模型无限循环。
真正的生产版本还会加结果缓存、幂等号、超时控制、审计日志。这里不再展开,但核心思路一致:模型负责“判断”,代码负责“控制和兜底”。
4.3 跑了两周之后的踩坑清单
- 空工具调用陷阱。模型在不需要调用工具时仍然给出了一个调用,返回结果为空。解决方法是把“不需要调用时直接输出回答”写进工具描述,并增加“无实际动作”的判断分支。这类问题不在评测集里出现,却会在真实流量中高频发生。
- 并行工具调用的重复副作用。GLM 5.1 支持在一条消息里返回多个 tool_call,某些场景下会重复调用同一个有副作用的工具,比如同一个“发送通知”被连续执行两次。对策是在工具执行层增加幂等键,同一个任务 ID 只允许执行一次。
- 用户中途插入新消息。用户发了“顺便帮我看一下另一个订单”,这条新消息会混入工具调用历史中,容易让模型迷失。我做了事件隔离:把原始任务和实时消息分成两个上下文段,模型先处理新消息的插入,再回到主线任务。
这些坑都不是模型“笨”,而是工程侧没有做好边界管理。Agent 落地本质上是在给模型立规矩,规矩立好了,模型才能安心发挥自己的判断力。
5. 成本、评测与监控:Agent 上生产的三道平衡
5.1 Token 成本模型与预算设计
Agent 场景的 token 消耗比普通聊天高得多。以一个 5 轮工具调用任务为例,消耗包括:系统提示 + 状态卡片、每轮模型响应、每轮工具结果回传。粗略估算,一次普通任务可能消耗 6000 到 12000 token,如果中间出现重试或死循环,成本还会直线上升。
我给一个简单公式:
单任务成本 ≈ 系统提示 token + 输入历史 token × 轮数 + 输出 token × 轮数 + 工具结果 token × 轮数在不改变模型的前提下,能压成本的手段有三类:一是状态卡片代替完整历史回放,二是把高频工具结果转成摘要再回传,三是限制最大轮数和超时时间。GLM 5.1 的长上下文能力很诱人,但不要因为“窗口够大”就无节制塞数据,那会把单任务成本推到不可接受的水平。
5.2 评测指标:从“答对”到“办成”
做 Agent 项目,评测体系必须和纯问答项目区分开。我目前在用的是四类指标:
- 工具调用正确率:每一步调用的工具和参数是否符合预期。
- 任务完成率:整个流程是否走到正确终态,而不是停在半路。
- 副作用率:是否出现重复调用、错误调用、多余调用。
- 单任务成本:平均 token 消耗,用于成本预警。
日常迭代时我维护了一个 60 条左右的回归集,覆盖常见意图、边界场景、容易绕弯的任务。每次升级模型或改提示词,先跑一遍回归集,看四类指标的变化。这样做最大的好处是:当出现“某些任务变好、某些任务变差”时,能快速定位是哪一个环节出了问题。
5.3 可观测性:把 Agent 的每一步都记下来
在 Agent 项目里,最痛苦的事就是线上任务失败了,但你不知道失败在哪一步。我在项目里要求所有 Agent 执行必须输出结构化日志:时间戳、当前步骤、输入目标、模型响应、调用工具名、参数快照、工具返回值、耗时、错误信息。这份日志既是排查工具,也是后续优化提示词的素材库。
有一次排查“退款任务一直转人工”的问题,就是靠日志发现模型在第三轮调用知识库工具时传入了错误的文章 ID,导致返回了一条不相关的政策条文,最终判断逻辑走入异常分支。这种问题光看用户反馈永远发现不了,但日志里一眼就能定位。
6. 下一步演进:Agent 型大模型在企业场景里的扩展方向
讲完当前项目里已经落地的东西,再聊聊我对下一步演进的判断。GLM 5.1 这一代模型把单个 Agent 的执行可靠性拉到可以商用的水平,但真正复杂的企业场景往往需要多个 Agent 协同,而不是一个巨型 Agent 包打天下。
多 Agent 分解时,要考虑的三个点是:记忆怎么共享、任务怎么分配、结果怎么合并。比如客服场景可以分成“基础问答 Agent”“订单处理 Agent”“退款审批 Agent”,三者共享一个订单状态数据库,但各自维护独立的工具集和提示词。这样每个 Agent 的职责单一,模型决策空间小,准确率和可维护性都更有保证。
工具生态上,我也在尝试把更多系统能力暴露成标准工具:企业微信消息推送、工单系统状态更新、审批流触发。只要接口定义清晰,模型就能接入更多真实业务流程。最后想说一句个人体会:Agent 型大模型带来的不是“全自动”的幻觉,而是一个终于愿意“按指令办事”的聪明实习生——你依然要写清楚流程说明、设好边界、做好兜底,但省下的心力,足以让团队把精力放到更难的业务问题上。