企业内部把 AI 助手接进企业微信,这件事在过去一年里已经从"演示给人看"走到了"每天有人真在用"。最近有家企微生态服务商把自己家的 AI 聊天产品直接对接到了 Agent 层,给这个智能体起了个挺接地气的名字,下文我就按内部叫法称它"圆子"。它不是一个只会关键词匹配的自动回复机器人,而是能读上下文、能调业务系统、能在信息不全时主动追问的企业微信 AI Agent。说白了,它把过去"人去找功能、翻菜单、填表单"的路径,改成了"直接在聊天框里说一句话"。这篇内容我会从架构、能力配置、实操搭建到踩坑排查完整拆一遍企微 AI 聊天落地这件事,适合企微管理员、做内部工具的开发者、以及正在给客户做智能体实施的同学参考,新手也能照着最小可用版本先跑通一条链路。
1. 先把概念掰开:企微里的 AI Agent 和以前的机器人差在哪
1.1 从"关键词回复"到"自己决定下一步"的三级跳
我见过太多企业把"智能客服"四个字理解成一张关键词表加一棵菜单树,用户点"1"查订单,点"2"转人工。这种形态的本质是人替机器想好了所有分支,机器只负责匹配。第二级是接了大模型的问答机器人,能理解自然语言了,但它的能力边界还是"把知识说给你听",说完就结束,流程该走还得人去走。第三级才是 Agent:它能判断"这句话背后要办的是什么事",自己决定调哪个接口、要不要追问、办完之后回什么。
这个差别在企微场景里特别明显。举个我自己遇到过的例子,销售在群里发一句"帮我查下这单到哪了,客户催得急",关键词机器人会因为没匹配到订单号直接回一句"请提供订单号",然后销售得再去翻系统。而 Agent 会先做槽位判断:缺订单号,那就从当前会话上下文、从发送人身份绑定的最近订单里补;补不到才追问,而且追问的方式是"你指的是上周那笔华东的单子吗",而不是"请输入订单号"。这中间差的就是状态管理、工具调用和身份映射三件事。
所以判断一个东西是不是真 Agent,我一般看三条:有没有多轮状态、能不能调用外部工具并回写、出错时会不会自己换策略。三条占两条以下,基本还是聊天机器人的包装。
1.2 为什么入口偏偏是企业微信
做内部工具的人都知道一个残酷事实:新做一个 App,日活大概率死在装机这一步。企业微信绕过了这个问题——员工本来每天就要在里面打卡、审批、看通知,聊天窗口是天然的高频入口。你不需要教育用户"去打开某个系统",你只需要让他"在原来的地方多说一句话"。
更实际的是身份。企微的会话天生带着userid,这个 userid 在后端可以对上 HR 系统、对上权限系统、对上业务库里的负责人字段。这意味着 Agent 拿到一句话的同时,就已经知道"说话的人是谁、在哪个部门、能看哪些数据"。这一点在公域聊天工具里是做不到的,你得自己做一套绑定流程,还容易出错。
再往下是组织关系。企微的部门树、上级关系、群成员列表,本身就是一张现成的权限图。做审批类、查询类 Agent 的时候,你可以直接用"同部门""直属上级"这类关系做数据范围收敛,不用另建一套组织架构。这也是为什么"圆子"这类产品会优先选择企微做首发对接——通道、身份、组织三样东西平台已经给齐了,服务商只需要把 Agent 的脑子接上去。
1.3 "率先对接"这四个字,实际意味着什么
服务商抢首发,外行看是营销动作,内行看是工程适配的窗口期。Agent 接企微,难的从来不是调模型,而是把消息通道的坑趟平:加密回调怎么验、5 秒超时怎么破、access_token 怎么缓存不出并发事故、群聊里 @ 机器人和私聊的消息结构差在哪。这些细节官方文档都写了,但写到能稳定跑,中间隔着几十个线上事故。
抢先对接的实际价值在于,它把一套已经趟过坑的适配层封装好了,客户不用从零写加解密、不用自己处理超时兜底。对实施方来说,这能省掉大概两周的联调时间。但也要清醒:封装层能解决通道问题,解决不了业务问题。知识库怎么切、工具怎么注册、权限怎么收敛,这些还是得自己来。我在后面几节会把这几件事拆到能直接抄的程度。
2. 架构拆解:一条消息从员工手机到 Agent 再回来,中间过了几道手
2.1 消息链路的全景,以及每一跳的时间预算
先把链路摆出来,不然后面聊优化都是空谈。员工在企微里发一句话,大致要经过:企微服务端 → 你的回调地址(验签、解密)→ 消息路由(判断是私聊还是群聊、是不是 @ 了机器人)→ 身份与会话上下文装载 → 意图识别 → 知识检索或工具调用 → 大模型生成 → 回复封装 → 调企微发送接口 → 回到用户手机。
这条链路上有个硬约束:企微的被动回复要求 5 秒内返回。超过这个时间,被动回复通道就废了,你必须改成"先回一个占位消息,再异步推送结果"。所以时间预算必须提前算,我的经验分配是这样的:
| 环节 | 预算 | 说明 |
|---|---|---|
| 验签 + 解密 | 50ms | 纯 CPU 计算,注意别每次都重新初始化加解密对象 |
| 身份与上下文装载 | 150ms | 走缓存,别每次查库 |
| 意图识别 | 300ms | 小模型或规则前置,别直接丢给大模型 |
| 知识检索 | 600ms | 向量库 + 关键词混合召回 |
| 工具调用 | 800ms | 内部接口,必须设超时 |
| 大模型生成 | 2000ms | 首 token 时间,流式可以放宽 |
| 回复封装与发送 | 200ms | 含一次 HTTP 往返 |
| 余量 | 900ms | 留给网络抖动和重试 |
加起来 5 秒刚好卡满,实际跑起来一定会超。所以我的建议是:凡是涉及工具调用的意图,一律走异步推送,不要赌被动回复。占位消息发一句"正在查,稍等",用户体验反而更好,因为他知道系统收到了。
2.2 会话上下文和员工身份,是怎么对上的
这块是新手上手最容易翻车的地方。企微的私聊消息体里带FromUserName,那是一个加密过的外部联系人标识或者内部 userid,具体是哪个取决于消息来源。内部员工发消息,FromUserName就是 userid,你可以直接拿它去查人员信息。但如果是外部联系人发给你的应用,那这个字段就不是 userid 了,得走另一套映射。
群聊更绕。群里 @ 机器人,消息体里会带ChatId,你要拿 ChatId 去查群信息,再判断这个群里有哪些人、说话的人有没有权限触发这个动作。我见过一个事故:某团队做了个"查薪资"的 Agent,私聊里做了权限校验,群聊分支忘了做,结果有人在群里 @ 了一下,Agent 直接把某位同事的薪资结构回在了群里。这种事故一次就够让项目下线的。
正确的做法是把权限校验放在路由层,而不是放在业务层。任何消息进来,先过一道"这个人 + 这个场景 + 这个动作"的三元组校验,通过了才往后走。业务代码里不要再做权限判断,否则一定会漏。
2.3 工具调用与业务系统回写,边界画在哪
Agent 调工具这件事,最怕的是"能读不能写"或者"能写不能撤"。我的做法是给工具分三级:
- 只读类:查订单、查库存、查制度、查排班。风险低,可以放宽,允许 Agent 自主调用。
- 低频写类:提交工单、发起审批、登记工时。风险中,必须二次确认,让用户在聊天里回一句"确认"再执行。
- 高危写类:改价格、改权限、删数据。这类我建议根本不开放给 Agent 自主调用,最多让 Agent 生成一个待办链接,跳转人工操作。
回写的时候还有个细节:幂等。用户手抖发了两遍"提交报销",Agent 不能给他建两张单子。做法是给每次工具调用生成一个基于userid + 意图 + 时间窗的幂等键,服务端去重。这个键我一般用hash(userid + intent + 参数指纹 + 5分钟窗口),实测能挡掉绝大部分重复提交。
2.4 几个必须在上线前想清楚的边界
第一是数据出境。Agent 的推理如果走外部 API,那你得清楚哪些字段不能出。我的做法是在网关层做一次脱敏过滤,手机号、身份证、银行卡、详细地址这类字段在送入模型前统一打码,回来之后再按需还原。别指望提示词拦得住,提示词是软约束,网关是硬约束。
第二是审计。企微本身有会话内容存档能力,但那是平台层的。你自己的 Agent 侧还得有一份"谁在什么时候问了什么、Agent 调了什么工具、返回了什么"的完整日志。这份日志在出问题的时候是唯一的证据链,别省这个存储。
第三是降级。模型服务挂了、向量库挂了、业务接口挂了,Agent 得有话说。我的标准是三档降级:先降级到纯检索(不走模型生成,直接返回命中的知识片段),再降级到固定话术加人工入口,最后降级到"服务繁忙,请稍后再试"。任何一档都比"转圈圈没反应"强。
3. 核心能力落地:知识库、意图、工具三件套怎么配
3.1 知识库不是把文档丢进去就完事
这是我最想吐槽的一点。很多人以为接个向量库、把公司制度 PDF 全灌进去,Agent 就聪明了。实际结果是:问"年假怎么算",它把三份不同年份的制度文件混在一起答,答案自相矛盾。
问题出在切片和元数据上。我的做法是先按文档结构切,不按固定字数切:一份制度文件,先按"章—条"切成块,每块控制在 300 到 500 字,重叠 50 字。切完之后给每块打上元数据——生效日期、适用范围、文档版本、所属部门。检索的时候,先用元数据做一层硬过滤(比如只取最新生效且适用当前员工所在地区的版本),再做向量召回。
切片大小为什么是 300 到 500 字?太短,语义不完整,模型拿到的上下文缺主语;太长,召回精度下降,一个块里塞了三件事,模型容易抓错重点。500 字大约对应中文 250 到 350 个 token,配合 top-5 召回,塞进上下文大概 1500 token,成本可控。
还有一步很多人省了:混合检索。纯向量召回对"专有名词、编号、人名"很不友好,用户问"GB-2024-017 这份文件怎么说的",向量搜出来大概率是垃圾。必须加一路关键词检索(BM25 就行),两路结果做加权融合。我一般的权重是向量 0.6、关键词 0.4,实际跑下来比单路强不少。
3.2 意图路由和兜底话术,决定了体验的下限
意图识别的目标不是"分类准确率 99%",而是把不该大模型回答的问题提前拦掉。我一般分四类:
| 意图类型 | 典型例子 | 处理策略 |
|---|---|---|
| 寒暄闲聊 | "在吗""你是谁" | 固定话术,秒回,不进模型 |
| 知识问答 | "出差住宿标准多少" | 走 RAG,带引用来源 |
| 业务查询 | "我这个月还剩几天调休" | 走工具调用,参数从身份补 |
| 流程办理 | "帮我请下周三的假" | 走工具 + 二次确认 |
| 越界/敏感 | 涉及他人隐私、薪酬 | 直接拒绝,记录审计 |
第五类一定要有。用户问"张三工资多少",Agent 不能含糊其辞,要明确说"这个我没法查,你可以走人事渠道"。含糊的回答会被用户当成"它能查但不愿意说",反而引发更多追问。
兜底话术也有讲究。我最常见到的错误兜底是"抱歉,我不太理解您的问题"。这句话把责任推给用户,体验极差。更好的兜底是给方向:"这个问题我拿不准,你可以试试问我:报销标准、调休余额、审批进度,或者直接找行政小助手。"把可选项摆出来,用户下一步就能走通。
3.3 工具注册与参数校验,别把大模型当程序员
Agent 调工具靠的是 function calling,你把工具的 name、description、参数 schema 给模型,模型决定调不调、怎么填参数。这里有个反直觉的经验:description 写得越像给人看的说明书,模型用得越准。
反例是这样写的:"query_leave_balance:查询假期余额,参数 user_id。"模型看到这个,会自己去猜 user_id 填什么。 正例应该写:"query_leave_balance:查询某位员工当前年度的假期余额。当用户询问自己还剩多少年假、调休、病假时使用。注意:这个工具只能查当前登录人自己的、不能查他人的,查他人请引导用户走人事流程。参数 user_id 由系统自动注入,模型无需填写。"
差别就在于,第二版把使用时机、边界、参数来源都说清楚了。我实测下来,工具误调率能降一半以上。
参数校验一定要在服务端做,不能信模型。模型会给你填出date: "下周三"这种值,也会填出user_id: "张三"。服务端收到之后先做类型和范围校验,不合法就返回一个结构化的错误信息给模型,让它重新组织。这个"错误回传—重试"的循环最多给两轮,超过就转人工,别让它无限试。
3.4 效果怎么评,别只看"感觉挺聪明"
上线前必须有一套评估集。我的做法是从真实会话里抽样 200 条,人工标注标准答案,分成知识类、查询类、办理类、越界类四组,每组 50 条。每次改提示词、换模型、调切片,都跑一遍,看四个指标:
| 指标 | 含义 | 我的及格线 |
|---|---|---|
| 首答命中率 | 第一轮就答对的比例 | 知识类 ≥ 85% |
| 追问有效率 | 追问后用户能补充有效信息的比例 | ≥ 70% |
| 工具调用准确率 | 该调的调了、不该调的没调 | ≥ 95% |
| 越界拒绝率 | 敏感问题被正确拒绝 | 100% |
越界拒绝率我要求是 100%,这条没有妥协空间。其它三个指标可以迭代,这条不行。
4. 实操:从零搭一个能跑通的最小可用版本
4.1 环境与账号准备,先把通道打通
先说前置条件。你需要在企微管理后台建一个自建应用,拿到CorpID、AgentId、Secret三个值。然后在应用的"接收消息"设置里配置URL、Token、EncodingAESKey。配置的时候企微会立刻发一个 GET 请求来验证,你必须当场解密echostr并返回明文,否则保存不了。
依赖方面,Python 环境装这几个就够跑通最小版本:
pip install flask requests pycryptodome redis其中pycryptodome是给消息解密用的,redis用来缓存 access_token 和会话上下文。这个 token 有效期 7200 秒,且有调用频次限制,必须缓存。我见过最蠢的写法是每次请求都去换一次 token,几百人的企业跑两天就被限流了。
缓存的写法要注意并发。多个 worker 同时发现 token 过期,会一起冲去刷新,触发限流。正确做法是加一把分布式锁,只让一个 worker 去刷,其它等结果:
import time, redis, requests r = redis.Redis() LOCK_KEY = "qy:token:lock" TOKEN_KEY = "qy:token:value" def get_access_token(corp_id, secret): cached = r.get(TOKEN_KEY) if cached: return cached.decode() # 抢锁,锁过期时间给 10 秒,防止死锁 if r.set(LOCK_KEY, "1", nx=True, ex=10): try: resp = requests.get( "https://qyapi.weixin.qq.com/cgi-bin/gettoken", params={"corpid": corp_id, "corpsecret": secret}, timeout=5, ).json() token = resp["access_token"] # 提前 300 秒过期,留出安全边界 r.setex(TOKEN_KEY, resp["expires_in"] - 300, token) return token finally: r.delete(LOCK_KEY) # 没抢到锁,等一会儿读缓存 for _ in range(20): time.sleep(0.2) cached = r.get(TOKEN_KEY) if cached: return cached.decode() raise RuntimeError("token 获取超时")这段代码的关键在expires_in - 300,提前过期是为了避免"刚好在过期瞬间拿到一个已经失效的 token"。
4.2 回调接收与验签,这是最容易卡住的一步
企微的消息是加密的 XML,验签用 SHA1。很多人卡在这里是因为排序写错或者编码写错。验签的逻辑是把token、timestamp、nonce、encrypt四个字符串按字典序排序,拼成一个字符串做 SHA1。注意是字典序,不是按参数顺序。
import hashlib, base64 from Crypto.Cipher import AES def verify_signature(token, timestamp, nonce, encrypt, msg_signature): items = sorted([token, timestamp, nonce, encrypt]) sha1 = hashlib.sha1("".join(items).encode("utf-8")).hexdigest() return sha1 == msg_signature def decrypt_msg(encoding_aes_key, encrypt): aes_key = base64.b64decode(encoding_aes_key + "=") iv = aes_key[:16] cipher = AES.new(aes_key, AES.MODE_CBC, iv) plain = cipher.decrypt(base64.b64decode(encrypt)) # 去 padding pad = plain[-1] plain = plain[:-pad] # 前 16 字节是随机串,接着 4 字节是长度 content_len = int.from_bytes(plain[16:20], "big") return plain[20:20 + content_len].decode("utf-8")有一个坑要提醒:EncodingAESKey是 43 位字符串,base64 解码前要补一个=才能得到 32 字节的 key。少补这个等号,解密会直接抛异常,而且报错信息很不友好,容易让人以为是 key 配错了。
接收消息的路由大概长这样:
@app.route("/qy/callback", methods=["GET", "POST"]) def callback(): args = request.args msg_signature = args.get("msg_signature") timestamp = args.get("timestamp") nonce = args.get("nonce") if request.method == "GET": echostr = args.get("echostr") if not verify_signature(TOKEN, timestamp, nonce, echostr, msg_signature): return "invalid", 403 return decrypt_msg(AES_KEY, echostr) body = request.get_data(as_text=True) encrypt = extract_encrypt_from_xml(body) # 从 <Encrypt> 节点取值 if not verify_signature(TOKEN, timestamp, nonce, encrypt, msg_signature): return "invalid", 403 plain_xml = decrypt_msg(AES_KEY, encrypt) # 异步处理,先给企微回 200,避免 5 秒超时 task_queue.enqueue(handle_message, plain_xml) return ""先入队再返回这个模式,是我强烈建议的。不管后面多快,都别在回调里同步做业务,一旦超时,企微会重试三次,你的 Agent 就会给同一个人回三遍一样的话。
4.3 消息分发与 Agent 调用,把上下文拼装好
消息进来之后要做三件事:判断消息类型、装载上下文、调 Agent。判断类型是为了过滤掉非文本消息(图片、语音、文件),最小版本里可以先不做多模态,直接回一句"这个我还看不懂,先发文字吧"。
上下文拼装是重点。我一般分三层:临时上下文(最近 5 轮对话)、身份上下文(userid、部门、角色)、业务上下文(当前正在办理的任务状态)。三层拼成一个结构化的 prompt 前缀,别全塞进对话历史里,那样 token 消耗会失控。
def build_agent_request(userid, user_text, session_id): profile = get_user_profile(userid) # 带缓存 history = get_history(session_id, limit=5) # 最近 5 轮 task = get_pending_task(userid) # 有没有正在办的事 return { "session_id": session_id, "userid": userid, "messages": history + [{"role": "user", "content": user_text}], "context": { "dept": profile["dept"], "role": profile["role"], "pending_task": task, }, "tools": load_tools_for_role(profile["role"]), # 按角色裁剪工具集 "max_tokens": 800, }注意load_tools_for_role这一步:按角色裁剪工具集。普通员工不需要"审批权限管理"这种工具,给了它只会增加误调概率,还增加 prompt 长度。我一般把工具集控制在 8 个以内,多了模型选择困难。
回复发送用应用消息接口,注意 markdown 消息类型在企微里支持有限,复杂排版用template_card更稳:
def send_text(userid, content, token): return requests.post( "https://qyapi.weixin.qq.com/cgi-bin/message/send", params={"access_token": token}, json={ "touser": userid, "msgtype": "text", "agentid": AGENT_ID, "text": {"content": content[:2048]}, }, timeout=5, ).json()content[:2048]这个截断别省,企微对文本消息有长度限制,超了直接报错,而且报错码是errcode: 40058,不在常见错误列表里,第一次遇到会查很久。
4.4 灰度与回滚,别一上来就全员开放
我的习惯是分三批放量:第一批是内部团队自己,跑三天,主要看崩溃和超时;第二批是一个配合度高的业务部门,跑一周,主要看意图覆盖和知识盲区;第三批才是全员。每一批都要看同一组指标:日活、人均会话数、追问率、转人工率、负反馈率。
回滚方案必须提前准备,而且不能是"改代码重新发版"这种重操作。我一般做一个开关位:配置中心里放一个agent_enabled的开关,关掉之后 Agent 自动降级成"返回固定话术 + 人工入口",用户侧感知是"这个助手今天不太聪明",而不是"这个功能没了"。这个设计在模型供应商出故障的时候特别有用。
5. 踩坑实录:常见问题与排查速查表
5.1 消息收不到,先查这四处
这是最高频的问题,我按排查顺序列一下。第一,看回调 URL 能不能从公网访问,本地开发用内网穿透,但要注意穿透工具的域名经常变,变了就得重配,忘了配就是全挂。第二,看验签是否通过,msg_signature对不上大概率是排序写错或者EncodingAESKey少补了等号。第三,看返回内容,GET 验证必须返回解密后的echostr明文,返回 "success" 是不行的。第四,看应用可见范围,应用没开给这个部门,消息压根不会推给你。
还有一种隐蔽情况:所有配置都对,但就是不回。这时候去看日志里有没有收到 POST。如果收到了但没回,多半是异常被吞了。Python 里try/except: pass这种写法是万恶之源,至少打个日志。
5.2 回答跑偏和幻觉,八成是检索的锅
用户说"它胡说八道",第一反应不该是换模型,而是去捞那一条会话的检索结果。我排查的顺序是:检索有没有召回正确文档?召回了,排序对不对?排序对,切片里是不是被截断了?三层查完,通常问题就定位了。
我遇到过一个典型案例:制度文档是扫描版 PDF,OCR 出来的文本把"15 天"识别成了"1S 天",向量检索照样能召回(语义接近),但模型看到"1S 天"就开始瞎猜。这种问题只能靠入库前的质量校验解决,比如检测文档里非法字符比例,超过阈值就拦下来人工处理。
另一种幻觉来源是知识库里压根没有。用户问"公司有没有宠物友好政策",知识库没有,模型不甘心说不知道,就开始编。解法是在 prompt 里加一句硬约束:"如果检索结果里没有明确依据,直接回答'这个我没有查到',不要推测。"这句话实测很有效,代价是拒答率会上升,需要和业务方提前对齐预期。
5.3 权限、存档和合规,这几条红线碰不得
Agent 一旦能查数据,权限就是命门。我的三条铁律:能查自己不能查别人(除非角色明确允许)、能查汇总不能查明细(敏感字段)、所有查询留痕。第三条尤其重要,出问题的时候你得能回答"是谁在什么时候查了什么"。
会话存档这块,企微有平台级能力,但需要单独开通并做加密处理,涉及员工知情同意,这块要走正式流程,不能想当然。我的建议是:Agent 自己的对话日志单独存一份,加密存储,设置访问审批,保留周期按内部制度来。别图省事把明文日志丢在共享盘上。
另外一个容易忽略的点是外部联系人。如果你的应用同时服务内部员工和外部客户,这两类消息的处理逻辑必须分开。外部客户那边,Agent 说的话代表企业,措辞、承诺、数据范围都要更保守,我一般会单独配一套更严格的 prompt 和工具白名单。
5.4 成本和并发,跑起来才知道疼
成本主要来自两块:模型 token 和向量检索。token 这块,我做过一个粗算:一次典型问答,system prompt 约 600 token,上下文约 400 token,检索结果约 1500 token,输出约 300 token,合计约 2800 token。一千人规模的企业,日均 3000 次会话,一天大概 840 万 token。这个量级下,prompt 瘦身和检索结果裁剪就是真金白银。
几个省钱的做法:把历史对话从 5 轮压到 3 轮、检索结果只取 top-3 且每段做摘要、把固定的 system prompt 做成缓存前缀(很多模型服务对相同前缀有缓存优惠)。还有一个反直觉的:简单意图别进大模型。寒暄、菜单、状态查询这类,用小模型或者规则处理,能省掉三成调用量。
并发这块,主要盯两个点:模型服务的 QPS 限制和企微接口的频次限制。前者超了会 429,后者超了会返回频次错误码。我的做法是给每条链路单独设一个令牌桶,桶满了就排队,排队超过 3 秒直接走降级话术,别让用户干等。
5.5 排查速查表
| 现象 | 高概率原因 | 处理动作 |
|---|---|---|
| 保存回调配置失败 | echostr 未解密或返回了错误内容 | 检查 GET 分支,返回明文 |
| 消息重复回复 | 回调内同步处理超时,企微重试 | 改先入队再返回 200 |
| 回复内容被截断 | 文本超过接口长度限制 | 截断到 2048 字或改卡片消息 |
| token 频繁失效 | 多处并发刷新 | 加分布式锁 + 提前 300 秒过期 |
| 回答张冠李戴 | 检索召回了旧版本文档 | 元数据加生效日期过滤 |
| 工具误调 | description 写得模糊,工具集过大 | 重写说明,按角色裁剪 |
| 群聊里回复错人 | 未区分 @ 对象与发送人 | 用 @ 的 userid 而非 FromUserName |
| 高峰期大量超时 | 模型 QPS 打满 | 令牌桶 + 异步推送改造 |
6. 上线之后:让这个 Agent 真的被用起来
6.1 冷启动阶段,先给一个"必用场景"
技术跑通和业务用起来是两件事。我见过好几个 Agent 做得很完整,但日活一直在两位数徘徊,原因很统一:没有必须用它才能办的事。用户试一次,觉得"还挺聪明",然后就忘了。
破局的办法是绑定一个高频且必须的动作。比如把"查剩余年假"这个功能只在 Agent 里提供入口,原来的菜单页下掉,用户想查就得来聊天。这听着有点霸道,但冷启动阶段是有效的。等日活起来了,再慢慢扩展场景。选场景的标准我总结成三条:每天有人问、答案有确定来源、错了后果可控。查假期余额、查审批进度、查报销标准,这三个几乎百试百灵。
另一个有效动作是群里主动推送。每周一早上在部门群里推一条"本周待办提醒",带上"回复数字查详情"的引导。推送本身不解决什么,但它把 Agent 塞进了用户的视野,比任何培训都管用。
6.2 用数据找迭代方向,别靠拍脑袋
上线之后我每周看四张表。第一张是意图分布,看哪些问题集中,集中但答不好的,优先补知识库或补工具。第二张是未命中清单,就是走兜底的那些问题,这是最有价值的迭代输入,我一般每周挑 top-20 人工看一遍,能归类就归类,不能归类的就承认覆盖不到。第三张是追问率,追问率高说明首次回答信息不足,通常是槽位设计有问题。第四张是负反馈率,用户点了"没用"的那些会话,逐条看。
有一点要提醒:别追求把兜底率降到零。兜底率降到很低的时候,往往意味着你把不该答的也硬答了,这时候错误率的上升比覆盖率更伤体验。我个人的舒适区是兜底率 8% 到 15%。
6.3 后续可扩展的方向
跑通单点之后,往下延伸有几个方向。一是多 Agent 协作,把人事、财务、IT 各自做成独立 Agent,用一个路由层做分发,好处是每个 Agent 的知识库和工具集都更聚焦,坏处是跨域问题会来回踢皮球,需要设计一个"主 Agent 兜底"的机制。二是主动式 Agent,不等用户问,根据业务事件主动推消息,比如审批快超时了提醒一句,这个价值很大但打扰成本也高,需要严格的消息频控。三是群内协作场景,让 Agent 在项目群里做记录、做汇总、做提醒,这块的难点是消息量大、噪音多,得先做一层消息聚合。
我个人最看好第二个方向。查询类能力解决的是"省时间",主动提醒解决的是"防出错",后者在企业管理场景里的价值往往更高,也更容易被管理层感知到。但前提是前面那套权限、审计、降级都跑稳了,不然主动推错消息,比不推还糟糕。
踩过几次坑之后我最大的体会是:企微 AI Agent 这个事,通道和模型都不是壁垒,把权限和检索做扎实才是。前者决定它能不能上线,后者决定它上线之后会不会被骂。至于"圆子"这类封装好的产品,它帮你省掉的是通道联调那两周,省不掉的是业务梳理和知识治理那两个月。想清楚这个分工,项目成功率会高很多。