ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

钉钉群内Agent全链路实践:从消息解析到多Agent协作与记忆体系

钉钉群内Agent全链路实践:从消息解析到多Agent协作与记忆体系 1. 为什么要把Agent的入口放在钉群里先说个场景。你是一个五六个人的技术小组负责人或者是一个内部平台的owner。每天打开钉钉未读消息里永远有几条是这样的这个报表能帮我跑一下吗线上那个订单为什么失败了查一下下午的周报模板发我一份。这些需求单个看都不难但架不住每天来好几轮。你手头正写着核心代码突然被打断去查一条日志、跑一个脚本、组装一份文档。一次打断十五分钟一天五六次等于每天少了两小时的有效工作时间。我一开始的想法是做一个内部Web页面让团队把需求提交上去。结果呢没人用。大家习惯在群里说一句而不是打开一个系统再填表单。这个习惯改不动也不该改——工具的形态应该顺着人的习惯走而不是反过来。所以我把Agent的入口直接接进了钉群。团队里的任何人在群里一下机器人用自然语言说一句帮我查一下订单20250801的支付状态然后就在群里等结果。这句话会走完一整条链路消息解析、意图识别、任务路由、工具执行、结果汇总最后以一条结构化的消息回到群里。对提问的人来说体验和一个同事没有区别对系统来说这是一个完整的任务生命周期。选择钉群作为入口不只是因为大家习惯用它。更重要的是群聊天然带了一个协作属性一个问题抛出来答案不只有提问者能看到群里其他相关人也能看到。一个订单问题往往是开发、产品、运营在同一个群里Agent的回答省去了我截图给你你再转发给运营的二次传播。这个信息触达效率是独立Web页面做不到的。再加上钉群的机器人API已经相当成熟接收消息、发送消息、指定人、卡片消息这些基础能力都有现成的SDK团队自己维护一个长连接服务并不复杂。这篇文章就把我在这套系统上踩过的坑、想明白的事、沉淀下来的设计思路完整写出来。整个过程不是某一个模型或者某一个框架的单点应用而是从入口到执行、从记忆到安全、从测试到上线的全链路工程实践。2. 一条钉群消息变成结构化任务的全过程很多做Agent demo的人会轻视消息接入层觉得不就是接一个webhook嘛,收到消息丢给大模型返回结果发回去完事。真到了生产环境这一层会先给你上一课。2.1 长连接运维与消息可靠性钉钉机器人有两种接收消息的方式一种是webhook回调需要你的服务有一个公网可访问的HTTPS接口另一种是Stream模式客户端主动建立长连接不需要暴露公网端口。我在内网环境里用的是Stream模式省去了公网网关的安全审计流程。但Stream模式有自己的问题长连接会断。服务器重启、网络抖动、钉钉服务端升级都会导致连接断开。如果连接断了而没有重连机制群里发的消息就全部丢失用户感知就是机器人死了。我处理的办法是加了两个机制心跳检测和指数退避重连。每30秒发一次ping连续三次没有pong就主动断开重连重连的等待时间从1秒开始翻倍递增最多等60秒避免断连后所有客户端同时重连把服务打崩。消息可靠性还有一个容易被忽略的点重复消息。钉钉的Stream模式在极端情况下会重复推送同一条消息比如客户端重连后进行消息补偿如果不对消息ID做去重同一条指令可能被Agent执行两遍。我这边接到消息后的第一件事就是查Redis看这个消息ID是否已经处理过处理过就直接丢弃。排重逻辑放在所有业务逻辑之前这行代码能拦住一大批诡异问题。2.2 意图识别与参数抽取的工程化消息进来了下一步是让大模型理解用户想干什么。在早期版本里我把整条消息直接扔给大模型让它自由发挥结果就是输出不稳定——同一个问题今天答对明天答错。后来我改成两段式处理。第一段是意图分类。在这一步我不让模型立刻执行任务而是先从有限的一组意图集合里选一个。意图集合是我自己定义的十几个固定类型比如查订单、查日志、跑报表、发周报、查监控、操作权限申请等等。模型的输出被约束为只能从这十几个标签里选一个这样就把开放式任务转化成了封闭式分类问题稳定性立刻上了一个台阶。第二段是参数抽取。确定了意图之后再让模型从消息里抽出执行该任务所需的参数。比如意图是查订单就需要抽订单号、查询范围、时间范围这些字段。每个意图类型的参数字段是提前定义好的JSON Schema模型输出JSON我用校验器做格式校验没抽到的必填参数就用追问的方式向用户补齐。这里有一个经验不要在一步里让模型既做意图分类又做参数抽取。分类和抽取混合输出模型容易在分类错误的情况下强行抽参数错误还会互相传染。拆成两步第一次错误可以在第二次之前被拦截纠正。实测这两种方案的准确率差异在复杂指令上能差到2030个百分点。2.3 确认与拒绝机制不是所有任务都能直接执行。比如帮我把生产库的user表清空这种破坏性操作或者给我查一下财务系统的工资数据这种权限不明的请求都必须有确认和拒绝机制。我的做法是引入一个可执行性评估节点。参数抽取完之后系统会做三件事查用户的权限等级、判断操作的风险等级、检查任务是否在允许执行的时间窗口内。风险等级高的操作删除、修改、批量操作生成一个确认卡片在钉群里让用户明确回复确认执行才往下走权限不够的直接拒绝并说明缺什么权限、找谁申请。这个机制在后来的安全审计中起到了决定性作用否则我根本不敢把系统开放给整个团队使用。3. 路由识别节点与技能管理任务往下走的核心枢纽热词里有路由识别节点和多Agent协作这确实是整个链路里最关键的一个设计。意图分类解决了用户想干什么但这个任务该由谁来干是路由节点的事。3.1 路由识别的判定逻辑先说简单的场景系统里只有一个Agent什么活都它干。这种情况下路由节点可以砍了。但只要你的系统里有两个以上的Agent就必须有一个明确的调度者来决定任务去哪里。少了这个环节你就会遇到经典的两个AI互相推活或者两个AI抢同一个任务的尴尬局面。我的系统里有一个编排Agent作为路由核心。它不执行具体任务只做三件事接收已解析的任务指令根据当前Agent注册表决定把任务派给谁然后在Agent返回结果后决定是否需要多Agent协作或二次路由。路由判定不完全是模型自由发挥。我给每个Agent预置了一份能力描述文件Agent Profile里面写清楚这个Agent负责什么、擅长什么、不负责什么、需要什么输入参数。编排Agent在做路由决策时是从这份注册表里匹配最合适的执行者而不是凭它自己训练的记忆。这就像公司里的工单系统派单员拿着一张部门职责表分配任务而不是靠猜。3.2 技能Skill和Agent有什么区别刚接触Agent的时候我一度混淆了Skill和Agent的概念。后来在实际设计中被逼着理清了。我当时问自己的问题是如果一个Agent能写周报又能查订单还能发通知它到底是一个Agent还是三个Agent答案是它作为一个Agent存在但内部加载了三个Skill。Skill是能力单元Agent是能力的容器和调度者。一个Agent可以加载多个Skill对外表现为这个Agent能干好多事而多个Agent也可以共享同一个Skill比如编译检查这个Skill可以被代码审查Agent用也可以被CI助手Agent用。用代码类比的话Skill更像是一个个函数Agent是调用函数的主流程路由节点是决定当前该调用哪段主流程的分发器。SkillAgent的关系是多对多的而不是一一对应。搞清这个关系后我把系统里通用的能力日志查询、数据库访问、文件读写、HTTP调用都做成了独立Skill然后按Agent职责不同配置不同的Skill集合。这样做的好处是能力复用率高新增一个Agent时不用从零开发组合几个Skill就能跑起来。3.3 技能注册表与动态扩展技能管理不只是在代码里定义几个类生产环境还需要一套可视化的注册表。我建了一个简单的管理后台每一行展示一个技能技能名称、版本号、描述、依赖的Agent、最近调用次数、成功率、平均耗时。这套后台最大的价值是让我能快速发现某个技能正在被用得越来越多或者某个技能成功率明显下滑前者是扩展资源的信号后者是排查故障的起点。新增一个Skill的流程也固定下来了写一个符合接口规范的执行函数写一份能力描述文档在注册表里登记然后跑一遍预置的测试用例。整个过程大约一小时内完成不需要重新发布整个系统。这个轻量化的扩展机制保证了Agent基础设施不是一个僵化的平台而是一个能随业务需要持续生长的系统。4. 多Agent协作的编排机制到了多Agent这一步系统的复杂度会明显上一个量级。不是说把两个Agent拼一起就叫多Agent协作重要的是协调、信任和容错。4.1 主管与执行者的协作模型我采用的拓扑很简单也是目前在团队场景下最稳的一个主管Agent加多个执行Agent。主管Agent负责拆解任务、分配调度、汇总结果执行Agent只管把自己负责的那一块干完把结果交回来。举一个实际例子。群里有人机器人说帮我看一下最近一周订单失败率升高的原因。这条消息经过解析和路由后到达主管Agent主管把这个任务拆成三个子任务拉取最近一周订单失败统计数据、查询相关服务的异常日志、检查最近一次发布变更记录。然后分别派发给数据Agent、日志Agent和发布Agent。三个Agent并行执行各自返回结果主管Agent再汇总成一份排查报告发回群里。这种模式的优点在于责任心清晰——每个Agent只对它的子任务负责出错了很容易定位是哪一个环节。信任关系也好建立主管Agent不用了解每个执行Agent的内部逻辑只要它们提供的输出符合约定的格式就行。4.2 协作中的数据交换格式多Agent协作搞不好80%的问题出在数据交换上。Agent A输出的结果Agent B读不懂或者Agent B拿到的数据里缺字段又要回头找Agent A要。这些扯皮在人工团队里也存在只是Agent之间不会抱怨只会默默地出错。我的解决办法是给所有Agent之间的数据交互定义一个统一的封装包格式。这个格式包含四个部分任务的唯一ID、任务的类型标识、携带的负载数据统一JSON格式、以及结果的状态是否成功、错误码、失败原因。每个Agent在接收任务时必须先校验封装包的格式格式不对直接返回错误而不是强行跑下去。这个约束让Agent之间形成了一种接口契约就像微服务之间的API文档一样。联调阶段我踩过一次大坑日志Agent返回的时间格式是2025-08-01 14:32:11但数据Agent只认时间戳毫秒值导致中间环节处理异常最后排查了半天才发现是两个Agent的时间格式定义不一致。从那以后公共字段的类型和格式全部在注册表里统一声明不允许各自定义。4.3 协作中的失败处理多Agent协作的容错比单Agent复杂得多。单Agent失败只需要告诉用户我干不了多Agent协作中一个子任务失败主任务可能还有挽救的余地。我的处理策略是区分致命失败和可降级失败。致命失败是指子任务的结果是主任务必需的拿不到就完不成比如查订单这个意图缺少订单号。这种失败直接中止整个任务并向用户说明。可降级失败是子任务失败但主任务还能继续只是结果不完整。比如排查订单失败率任务里发布Agent查询失败但数据和日志已经拿到了主管Agent可以先结合数据分析出一个初步结论在报告里标注发布变更记录暂未获取到以下结论基于数据和日志分析。这种降级处理极大提升了任务的成功率用户拿到一份不完美的报告也好过等半天拿到一个执行失败。5. 让Agent稳定干活的基础设施层模型能力再强没有一层稳如磐石的基础设施兜底生产环境根本跑不起来。这一节讲的是Agent背后那些看不见但决定了生死的组件。5.1 任务队列与并发控制群里的消息是不可控的。可能一整天没人提问也可能下午两点同时来了三十条消息。如果每个任务到达后立即开始执行并发一高下游的数据库、日志服务、第三方接口全部被打满然后产生连锁故障。我引入了任务队列做缓冲。所有解析完成的任务先进入消息队列由一个调度器按照配置的并发上限我这边根据下游服务的承受能力设置为5个并发任务取出执行其余任务在队列里等待。这样即使瞬间来三十个请求下游服务始终只承受5个并发用户体验是任务排了一会儿队但系统不会被打挂。5.2 超时控制与自动重试大模型推理慢下游接口也可能慢。如果没有超时控制一个任务可能卡在那里十几分钟不返回把并发槽位全部占满。超时控制要分层设置。我给每个环节都设了独立的超时时间大模型文本生成设60秒、外部API调用设15秒、数据库查询设20秒。任何一层超时直接按失败处理。然后有一个默认的重试策略可以重试的失败超时、网络抖动、下游5XX错误最多重试两次每次退避时间递增不可重试的失败参数格式错误、权限拒绝、业务逻辑报错直接返回错误不浪费重试机会。5.3 幂等设计与故障恢复Agent执行任务时如果中途进程崩溃重启之后这个任务算什么答案是任务状态被标记为执行中一直悬挂在那个状态里占了任务表的空间用户那边永远等不到结果。我炼了一整套状态机来管理任务生命周期待执行、执行中、成功、失败、超时、已取消、待确认。每个状态之间只有明确的合法迁移路径。同时加了一个恢复机制服务重启后扫描所有处于执行中且超过5分钟没有心跳的任务标记为失败通知用户重新提交。配合前面说的消息ID排重就实现了任务系统的最终一致性。热词里有一个agent execution terminated due to error这确实是生产环境最常见的报错之一。它的根源多半就是上面说的——没有状态机、没有超时、没有恢复机制Agent挂着挂着就被运行环境杀掉了。这套基础设施不是锦上添花是生存刚需。5.4 限流与成本控制Agent基础设施的成本大头是大模型API调用费用。一个复杂的多Agent任务可能触发几十次模型推理调用单个任务算下来成本不小。成本控制从三层入手。第一层是入口限流群里每分钟最多接受多少条指令超过的部分提示当前繁忙请稍后再试。第二层是上下文压缩在发给模型的prompt里优先使用精简后的信息摘要而不是全量日志既省钱又减少噪音。第三层是结果缓存完全相同的请求例如查询同一个订单的同一类信息在一定时间内的结果直接复用不重复调模型。6. Agent的记忆体系热词里有一条agent记忆这是很多人做Agent时漏掉的一块却决定了Agent的体验上限。一个没有记忆的Agent每次回答都是初次见面哪怕同一个用户昨天刚问过同样的问题它也是一脸茫然。6.1 短期记忆单次任务的上下文在单次任务内部上下文管理是必须做好的。一个大模型调用的输出要能作为下一次调用的输入。我在代码里维护了一个上下文对象按顺序记录这次任务里每一轮关键步骤的输入和输出。这个对象会随任务一起传递给各个Agent保证它们能看到前面已经发生了什么而不是各算各的。短期记忆的坑在于上下文长度。环节一多上下文膨胀得很快模型输入token数飙高延迟和成本一起上升。我后来加了一个压缩逻辑超过一定长度后把前面对话的中间过程提炼成一段摘要只保留摘要和最近几轮的完整内容。这个策略让token消耗下降了约40%同时没有明显影响任务质量。6.2 长期记忆团队知识沉淀长期记忆是更值钱的部分。我设计了一个经验库专门存放两类内容。一类是问答沉淀每当Agent完成一个任务后系统会判断这个任务是否具备可复用的价值。如果用户给了明确的正面反馈回复可以、对的、搞定就把这次问题的解析结果和执行路径存入经验库。下次同一个用户或者不同用户问起类似问题时可以直接从经验库命中省去一整轮模型推理。另一类是操作偏好比如某个团队喜欢报表里先放结论再放明细某个用户要求日志查询默认只看最近一小时的。这些偏好在初次出现时由Agent识别并记录后续同类任务自动适配。这个功能让Agent用着用着就越来越懂你了。6.3 记忆的权限边界记忆功能很容易越界。一个Agent记住了用户A的偏好如果这些信息可以被用户B问出来那就是隐私事故。我把记忆严格按可见范围隔离个人记忆只有本人能触发使用团队记忆只有团队成员可以共享跨部门的知识必须经过管理员审核才能进入全局库。隔离是在存储层就做好的查询时自动带上权限过滤条件而不是等模型生成结果后再做敏感信息识别。7. 可观测性Agent表现出玄学行为时怎么排查做Agent系统最头疼的时刻不是功能不工作而是功能时好时坏。同一个问题用户上午问得到正确答案下午问就答错了而且没有任何报错。这种问题不解决团队对系统的信任会迅速崩塌。7.1 全链路Trace从钉群消息到最终交付排查玄学行为的核心工具是全链路追踪。每一条钉群消息从进入系统开始就生成一个Trace ID这个ID贯穿消息解析、意图分类、路由决策、任务执行、结果生成的每一个环节。每一层日志都必须带上这个Trace ID。有了Trace ID用户反馈刚才那个问题答错了时我可以在日志平台里一搜直接看到这条消息走了哪些节点、每个节点的输入输出是什么、在哪一步开始偏离。本质上和排查一条慢SQL的链路追踪是一个思路。没有这个机制你面对大模型这种不可解释的组件时会束手无策。7.2 输入输出快照与回归测试集除了链路追踪我还有一个更笨但更有效的手段给每次模型调用都做快照。模型调用的输入prompt、模型版本、参数配置、输出结果全部落库存档。这个快照库越积越多慢慢就成了一个金矿——每当模型输出异常时我可以回溯到上一次正常输出时的快照对比两次输入差异通常几分钟内就能定位问题是出在prompt变更、模型升级、还是输入格式变化。更重要的用途是构造回归测试集。我会把历史快照里用户的真实提问 我们期望Agent执行的正确动作 正确的结果整理成测试用例集。每次调整prompt、更换模型、修改技能或路由逻辑之前先跑一遍回归集能明显降低修好一个bug带出两个新bug的概率。7.3 指标监控与告警最后一层是监控指标。我重点盯四个指标任务成功率成功完成的任务占比、平均响应时长从消息到结果回到群里的耗时、模型调用延迟、模型调用费用。每个指标都设了阈值告警比如任务成功率低于85%就告警。这套监控的实时性要求不用太高分钟级就够重点是能通过趋势发现问题。上线初期我收到过一条告警任务成功率从93%逐步掉到80%SSE查指标发现是某个Skill的成功率断崖式下跌。点进去看快照发现是下游监控系统做了一次接口升级返回的数据结构变了Skill里解析数据的代码还在用旧字段。这种问题没有指标和快照几乎不可能在用户大规模反馈前发现。8. 安全与权限让Agent在群里懂事地干活Agent有权限执行命令和操作数据这本身就是一把双刃剑。能力越强风险越大。群里随便一个人都可能成为攻击入口安全问题怎么强调都不过分。8.1 命令白名单与权限分级我在设计上坚持一个原则Agent的能力边界必须显式声明不能靠模型自觉。生产环境的所有可执行操作都必须在后台登记成允许的操作。没有登记的操作无论模型怎么生成执行层都直接拒绝。权限分级是这样做的管理员、普通成员、只读访客三个级别。管理员可以触发修改类操作比如修改配置、执行发布普通成员只能发起查询类和分析类任务只读访客只有查询权限而且查询范围也有数据隔离。权限判断放在路由节点之后、执行节点之前每次操作都做一次校验不允许跳过。8.2 敏感操作的人工审批流高危操作必须有人工审批环节。我定义了一批准入条件涉及删除、修改、发布、以及查询财务或个人信息类数据的操作都算高危操作。这类操作在执行之前会生成一个审批卡片发送到指定的审批群里要求有权限的管理员回复同意才能继续。这个流程加进去之后确实会增加一些使用成本。But users can have more choices比让Agent在无人监督的情况下执行删数据之类的操作要安全得多。有一次测试人员想试试系统会不会执行一个删除指令Agent生成了确认要删除吗请输入确认执行的卡片测试人员回复确认后依然被安全拦截因为审批人维度不过关。这条测试记录后来成了我们给团队做安全培训的经典案例。8.3 输出内容的合规过滤Agent不仅能执行操作还能回答问题。如果用户问的是别的同事的工资、某个部门的绩效数据甚至企业内部的一些敏感信息Agent不应该回答。我加了一层输出过滤在结果返回群里之前先过一个脱敏和合规检测服务。这个服务对生成结果进行扫描命中敏感数据身份证号、手机号、工资、绩效、合同信息等的内容会被打码或直接拦截。同时按最小必要原则处理数据查询类任务——比如查订单信息时默认只返回订单号、状态、金额、时间等必要字段用户的手机号、地址等隐私字段默认不返回除非有额外权限。安全是一个系统工程不是加一个AI安全模块就完事了。权限模型、审批流、脱敏规则、审计日志每一层都必须落实到位。9. Agent的测试评估与踩坑实录9.1 从Demo到稳定系统的测试方法Agent的测试比传统软件测试难很多难在输出不确定性。传统接口测试断言的是返回200且body里的某个字段等于expectedAgent系统的输出是自然语言同一个问题每次答案都可能有细微差别没法做字符串级断言。我摸索出的方法是分层测试。第一层是单元测试给每个Skill灌入预构造的输入断言它调用了正确的下游接口、传参正确、返回结果符合schema。第二层是意图路由测试用历史真实消息做输入断言意图分类是否正确、参数抽取是否完整、路由到了正确的Agent。第三层是端到端回归测试在测试环境里放入真实数据走完整链路人工评判输出质量。前两层可以全自动化放进CI里每次提交都跑第三层的频率低一些但每次prompt或模型改动时必须跑一轮。9.2 两个印象最深的坑第一个坑是**All Tools参数惹的祸**。当时给模型配置工具调用时把工具选择模式设成了让模型自己决定用不用工具结果在部分场景下模型明明应该调用日志查询工具却选择根据我的知识直接回答答案自然是编的。后来在代码里强制指定了必须使用工具模型就不再跳过工具调用了。这个问题的教训是工具调用的决策权要交给系统而不是交给模型尤其在工具是唯一正确答案来源的场景下。第二个坑是重复推送导致的双重执行。有一次我在灰度环境测试发现同一个任务被Agent执行了两次排查后确认是消息补偿机制在连接断开后重新推送了同一批消息而新加的去重逻辑在灰度环境没有生效。那次之后我把消息去重逻辑提到网关最前端并且写了一条硬性规定任何接入消息的系统组件第一行逻辑必须是幂等去重没有例外。9.3 我最终的体会回看整个建设过程这类系统最难的不是某一个技术点而是如何让各个环节形成一个自洽的整体。消息接入、意图解析、路由决策、Agent执行、任务队列、记忆系统、可观测性、安全防护这些组件单独拿出来都不算黑科技但组合在一起时任何一个环节的薄弱都会拉低整个系统的体验下限。我也越来越认可一个观点Agent基础设施本质上是在用工程手段驯服大模型的不确定性。不确定性的来源包括输出的随机性、工具调用的误判、多Agent协作中信息传递的损耗、还有下游系统的不可控故障。基础设施的每一个组件都是为了在这些不确定性出现时系统依然能给出确定性的结果。如果你也想在团队里搭建类似的Agent基础设施我的建议是不要一上来就追求大而全。先让一条最简单的链路完整跑通比如群里提问-查订单-群里回复然后再逐步增加技能、Agent、记忆、审批和监控。稳扎稳打地加每一步都确保系统仍然是可控的再用滚动的方式持续上新能力。这个过程比直接搬一堆框架拼一个看起来很酷的Demo更有价值。那些Demo撑不过真实流量的考验而这个一步一步长出来的系统才是团队真正愿意每天依赖的数字同事。
返回列表