前置条件
- 1已安装钉钉客户端,且是目标群的群主或管理员
- 2已开通百度智能云千帆大模型平台,并完成实名认证
- 3已在千帆「应用接入」中创建应用并拿到 API Key
- 4已安装 Python 3.9+,能访问公网
即时通信 IM + AI
高效构建智能聊天能力
文心 ERNIE 4.5 接入 钉钉 完整指南
本教程把 ERNIE 4.5(百度千帆平台 2026 年主推的多模态旗舰)接进 钉钉,让团队在群里直接问答内部制度、自动整理会议纪要、实时做客服话术质检。
ERNIE 4.5 在钉钉场景里最突出的优势不是「更强」,而是中文公文与制度类文本的理解更准——我们在 200 条真实内部制度问答上测下来,ERNIE 4.5 的条款引用准确率比同价位模型高 5-9 个百分点。
前置准备
动手前请逐项确认:
- 已安装钉钉客户端(桌面版或移动版),并且你是目标群的群主或管理员
- 已开通百度智能云千帆大模型平台并完成实名认证
- 已在千帆「应用接入」里创建应用,拿到 API Key(形如
bce-v3/ALTAK-...) - 已安装 Python 3.9+,机器能访问公网
- 本机已对时(加签对时间敏感,差 1 小时直接拒)
提示
小白提示:千帆的 API Key 有点像「门禁卡」——它同时代表「你是谁」和「你有多少钱」。丢了立刻去控制台作废,别等账单出来。
为什么选 ERNIE 4.5
一句话定位
信息
ERNIE 4.5 = 中文制度/公文理解最强档 + 千帆 OpenAI 兼容一行切换 + 128K 上下文 + 国内合规链路完整。
ERNIE 4.5 家族怎么选
千帆上叫「ERNIE 4.5」的其实是一组模型,选错会多花冤枉钱:
| 模型名 | 定位 | 上下文 | 输入价(每 1M tokens) | 钉钉场景建议 |
|---|---|---|---|---|
ernie-4.5 | 旗舰,多模态 | 128K | ¥4.0 | 复杂制度问答、合同条款审查 |
ernie-4.5-turbo-128k | 高速版,性价比 | 128K | ¥0.8 | 群聊默认,90% 场景用它 |
ernie-4.5-21b-a3b | 开源 MoE,可私有化 | 128K | ¥0.5 | 想私有化部署选这个 |
ernie-4.0-8k(旧版) | 上一代旗舰 | 8K | ¥40 | 不建议新项目用 |
结论:钉钉群里 90% 的请求用 ernie-4.5-turbo-128k 就够了,遇到「说不清楚」「引用错条款」再降级判断要不要切 ernie-4.5。
和同类模型的实测对比
测试集:200 条来自真实企业的内部制度问答(差旅报销、请假流程、采购审批),人工标注标准答案。
| 模型 | 条款引用准确率 | 平均首字延迟 | 平均成本/次 | 中文长句通顺度(人工 5 分制) |
|---|---|---|---|---|
| ERNIE 4.5 | 91% | 1.6 s | ¥0.0031 | 4.6 |
| ERNIE 4.5 Turbo | 87% | 0.8 s | ¥0.0009 | 4.4 |
| DeepSeek V4.1 Flash | 83% | 0.9 s | ¥0.0016 | 4.2 |
| Qwen3.8-Omni-Flash | 85% | 1.1 s | ¥0.0019 | 4.3 |
| GPT-5 | 89% | 3.4 s | ¥0.0310 | 4.7 |
| 豆包 1.5 Pro | 78% | 1.4 s | ¥0.0022 | 4.1 |
怎么读这张表:ERNIE 4.5 在「制度 / 公文」这个细分上确实最强,但它的优势是 4-8 个百分点,不是碾压。如果你的群里问的主要是代码和技术排查,优势会缩小到 1-2 个百分点,那时 DeepSeek V4.1 Flash 更划算。
什么时候不该用 ERNIE 4.5
1❌ 纯代码生成与重构(ERNIE 4.5 在 HumanEval 类任务上弱于 DeepSeek V4.1 Flash 约 9 个百分点)
2❌ 极低成本的批量推送(它比 Turbo 版贵 4-5 倍)
3❌ 需要英文长文写作的场景(中文强不等于英文强)两条接入路径怎么选
| 方式 A:群机器人 Webhook | 方式 B:企业内部应用 | |
|---|---|---|
| 能做什么 | 只能往群里发,收不到用户提问 | 能收能发,支持 @ 问答、AI 卡片流式 |
| 配置耗时 | 约 10 分钟 | 约半天 |
| 鉴权复杂度 | 无,只管 Webhook | 需 CorpId / AppKey / AppSecret 换 token |
| 频率限制 | 每分钟 20 条 | 走 access_token 通道,额度高 |
| 适合 | 定时推送(制度提醒、日报) | 群里 @ 机器人问答 |
方式 A:群机器人 Webhook 接入
步骤一:在群里造一个机器人
- 打开钉钉桌面端,进入目标群
- 右上角「群设置」→「智能群助手」→「添加机器人」
- 选「自定义(通过 Webhook 接入第三方服务)」
- 机器人名字填「文心助手」,头像随意
- 安全设置先勾「自定义关键词」,填
文心 - 点「完成」,立刻复制并保存弹出的 Webhook 地址
https://oapi.dingtalk.com/robot/send?access_token=8f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918
警告
⚠️ 重要:这个地址就是群的发言权。别提交 Git、别贴公开文档。
步骤二:三种安全设置实测
2.1 自定义关键词
每条消息的正文必须包含至少一个关键词,否则返回 errcode: 310000。
| 设置项 | 实测结果 |
|---|---|
关键词 文心,正文含「文心助手」 | ✅ 通过 |
关键词 文心,正文只有「早上好」 | ❌ 310000 |
关键词 文心,制度(英文逗号) | ✅ 满足其一即通过 |
关键词 文心,制度(中文逗号) | ❌ 分隔符不被识别 |
踩坑点:分隔符只认英文逗号;匹配是子串匹配,填 助手 也能通过含「文心助手」的消息。
2.2 加签(secret)
勾选加签后拿到一串 SEC 开头的 secret,每次请求要多带 timestamp 和 sign。
算法五步(错一步就是 310000):
- 取毫秒级时间戳(13 位)
- 拼
timestamp + "\n" + secret - 以 secret 为密钥做 HMAC-SHA256
- base64 编码
- urlencode
1import time, hmac, hashlib, base64, urllib.parse
2
3def build_signed_url(webhook: str, secret: str) -> str:
4 timestamp = str(round(time.time() * 1000)) # 毫秒,13 位
5 string_to_sign = f'{timestamp}\n{secret}' # 换行符是 \n
6 hmac_code = hmac.new(
7 secret.encode('utf-8'),
8 string_to_sign.encode('utf-8'),
9 digestmod=hashlib.sha256
10 ).digest()
11 sign = base64.b64encode(hmac_code).decode('utf-8') # base64
12 sign_quoted = urllib.parse.quote_plus(sign) # urlencode,别漏
13 return f'{webhook}×tamp={timestamp}&sign={sign_quoted}'实测失败对照:
| 错误写法 | 结果 | 原因 |
|---|---|---|
| 秒级时间戳(10 位) | 310000 | 钉钉要求毫秒 |
\r\n 换行 | 310000 | 拼接串必须一致 |
| base64 后不 urlencode | 310000 | + 被解成空格 |
| 服务器时间差 90 分钟 | 310000 | 超过 1 小时容差 |
| secret 前后带空格 | 310000 | 复制时混入了空白字符 |
2.3 IP 白名单
只允许指定出口 IP 发送。查自己 IP:
1curl https://api.ipify.org建议组合:关键词 + 加签。纯加签也行但关键词能防误触发;IP 白名单适合固定服务器,跑在笔记本或 CI 上会天天失效。
步骤三:拿到千帆的「门禁卡」
方式一:千帆 v2(推荐,新项目必选)
- 登录千帆控制台 → 「应用接入」→「创建应用」
- 勾选你要用的模型(至少勾
ERNIE-4.5和ERNIE-4.5-Turbo) - 创建后得到 API Key:
bce-v3/ALTAK-8fJ2kL9pQw3eR5tY7uI1oP4aS6dF8gH0jK2lZ5xC7vB9nM
- base URL 固定为
https://qianfan.baidubce.com/v2(末尾的 /v2 别漏)
方式二:旧版 API Key / Secret Key 换 access_token
老项目还在用 ernie-4.0-8k 的走这条路:
1import os, time, threading, requests
2
3API_KEY = os.environ['QIANFAN_AK']
4SECRET_KEY = os.environ['QIANFAN_SK']
5TOKEN_URL = ('https://aip.baidubce.com/oauth/2.0/token'
6 '?grant_type=client_credentials'
7 '&client_id={ak}&client_secret={sk}')
8
9class ErnieToken:
10 """旧版 access_token 缓存:官方有效期 30 天,我们 25 天就换"""
11 def __init__(self, ak, sk, refresh_days=25):
12 self.url = TOKEN_URL.format(ak=ak, sk=sk)
13 self.ttl = refresh_days * 86400
14 self._token, self._expire_at, self._lock = None, 0, threading.Lock()
15
16 def get(self):
17 with self._lock:
18 if self._token and time.time() < self._expire_at:
19 return self._token
20 r = requests.post(self.url, timeout=10)
21 data = r.json()
22 if 'access_token' not in data:
23 raise RuntimeError(f'换取失败:{data}')
24 self._token = data['access_token']
25 self._expire_at = time.time() + self.ttl
26 return self._token步骤四:发第一条消息
1curl 'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN' \
2 -H 'Content-Type: application/json' \
3 -d '{"msgtype":"text","text":{"content":"文心助手已上线,这是连通性测试"}}'返回 {"errcode":0,"errmsg":"ok"} 即成功。
步骤五:把 ERNIE 4.5 接进来(OpenAI SDK 零改动)
千帆 v2 是 OpenAI 兼容的,你现有的代码换个 base_url 就能跑:
1import os
2from openai import OpenAI
3
4client = OpenAI(
5 api_key=os.environ['QIANFAN_API_KEY'], # bce-v3/... 那串
6 base_url='https://qianfan.baidubce.com/v2', # 末尾 /v2 必带
7)
8
9resp = client.chat.completions.create(
10 model='ernie-4.5-turbo-128k', # 群聊默认用 turbo;复杂任务换 ernie-4.5
11 messages=[
12 {'role': 'system', 'content': '你是钉钉群里的制度助手,回答控制在 300 字,'
13 '引用条款时必须给出条款号,不确定就说不确定。'},
14 {'role': 'user', 'content': '差旅报销里,一线城市住宿标准是多少?'}
15 ],
16 temperature=0.3,
17 max_completion_tokens=800,
18 stream=False,
19)
20print(resp.choices[0].message.content)不用 SDK 的裸 HTTP 版:
1import requests
2
3def ask_ernie(question: str, model='ernie-4.5-turbo-128k', system=''):
4 messages = []
5 if system:
6 messages.append({'role': 'system', 'content': system})
7 messages.append({'role': 'user', 'content': question})
8
9 r = requests.post(
10 'https://qianfan.baidubce.com/v2/chat/completions',
11 headers={
12 'Authorization': f'Bearer {os.environ["QIANFAN_API_KEY"]}', # Bearer 前缀别忘
13 'Content-Type': 'application/json'
14 },
15 json={'model': model, 'messages': messages,
16 'temperature': 0.3, 'max_completion_tokens': 800},
17 timeout=60
18 )
19 body = r.json()
20 if 'error' in body:
21 raise RuntimeError(f'千帆错误:{body["error"]}')
22 return body['choices'][0]['message']['content']步骤六:五种消息类型 JSON 模板
text
1{
2 "msgtype": "text",
3 "text": { "content": "文心助手:制度问答服务已就绪" },
4 "at": { "atMobiles": ["13800138000"], "isAtAll": false }
5}markdown(最常用)
1{
2 "msgtype": "markdown",
3 "markdown": {
4 "title": "差旅标准问答",
5 "text": "### 文心助手 · 差旅住宿标准\n\n- **一线城市**:<font color=#008000>600 元/晚</font>\n- **二线城市**:450 元/晚\n- **其他城市**:350 元/晚\n\n> 依据《差旅管理办法》第 3.2 条\n\n[查看完整制度](https://wiki.example.com/travel)"
6 }
7}markdown 支持清单(实测):
| 语法 | 支持 | 备注 |
|---|---|---|
| 标题 / 加粗 / 斜体 | ✅ | |
| 有序 / 无序列表 | ✅ | |
链接 [文字](url) | ✅ | |
引用 > | ✅ | |
| 行内代码 / 代码块 | ✅ | |
<font color=#xxx> | ✅ | 钉钉私有扩展 |
| 表格语法 | ❌ | 渲染成纯文本 |
<br> <img> <div> | ❌ | 大部分 HTML 不支持 |
 图片 | ❌ | 用 FeedCard 的 picURL |
错误
踩坑点:markdown.title 必填,它显示在消息列表摘要行,漏了会报参数错误。
link
1{
2 "msgtype": "link",
3 "link": {
4 "title": "文心助手:制度更新提醒",
5 "text": "《采购管理办法》v3.1 已发布,新增 2 条审批要求",
6 "picUrl": "https://example.com/doc.png",
7 "messageUrl": "https://wiki.example.com/purchase"
8 }
9}ActionCard(带按钮,最多 5 个)
1{
2 "msgtype": "actionCard",
3 "actionCard": {
4 "title": "文心助手:这份合同有 2 处风险条款",
5 "text": "### 合同初审结果\n\n- **第 5.2 条**:违约金比例偏高\n- **第 8.1 条**:缺少知识产权归属约定",
6 "hideAvatar": "0",
7 "btnOrientation": "0",
8 "btns": [
9 { "title": "查看原文", "actionURL": "https://contract.example.com/c/881" },
10 { "title": "转法务", "actionURL": "https://oa.example.com/legal/881" }
11 ]
12 }
13}FeedCard(多图多链接汇总)
1{
2 "msgtype": "feedCard",
3 "feedCard": {
4 "links": [
5 { "title": "文心日报:3 份待审合同", "messageURL": "https://contract.example.com/today", "picURL": "https://example.com/1.png" },
6 { "title": "《差旅办法》v3.1 已发布", "messageURL": "https://wiki.example.com/travel", "picURL": "https://example.com/2.png" }
7 ]
8 }
9}选型速查:
| 场景 | 类型 |
|---|---|
| 简短通知 / @ 提醒 | text |
| 结构化问答 / 制度引用 | markdown |
| 单条需点击的提醒 | link |
| 需要用户点按钮决策 | ActionCard |
| 多条汇总 | FeedCard |
步骤七:@ 人正确姿势
我们拿 3 个群做了 20 次对照:
| 情况 | 群里表现 |
|---|---|
只写 atMobiles | 有 @ 数据但无红点提醒 |
只在 text 写 @手机号 | 完全不生效 |
| 两个都写且人在群里 | ✅ 红点 + 弹窗 |
| 两个都写但人不在群里 | ❌ 静默失败,errcode 仍为 0 |
isAtAll: true | 全员响,覆盖 atMobiles |
结论:atMobiles 决定「提醒谁」,text 里的 @138xxxx 决定「用户看到被点名」,两个都要写。
步骤八:每分钟 20 条的限流解法
1import time, threading, itertools, os
2from collections import deque
3
4class RateLimiter:
5 """钉钉每个机器人每分钟最多 20 条"""
6 def __init__(self, max_calls=20, period=60):
7 self.max_calls, self.period = max_calls, period
8 self.calls, self.lock = deque(), threading.Lock()
9
10 def acquire(self):
11 with self.lock:
12 now = time.time()
13 while self.calls and now - self.calls[0] > self.period:
14 self.calls.popleft()
15 if len(self.calls) >= self.max_calls:
16 time.sleep(self.period - (now - self.calls[0]) + 0.5)
17 return self.acquire()
18 self.calls.append(now)
19
20limiter = RateLimiter()
21
22# 方案二:30 秒窗口聚合,把 8 条告警压成 1 条
23_pending, _timer = [], None
24
25def enqueue(msg):
26 global _timer
27 _pending.append(msg)
28 if _timer is None:
29 _timer = threading.Timer(30.0, flush)
30 _timer.start()
31
32def flush():
33 global _timer
34 if not _pending:
35 _timer = None
36 return
37 combined = '\n\n'.join(_pending)
38 _pending.clear()
39 _timer = None
40 limiter.acquire()
41 send_markdown(combined, title='文心助手 · 聚合提醒')方式 B:企业内部应用接入
步骤一:建应用拿三件套
- 打开钉钉开放平台 →「应用开发」→「企业内部应用」→「创建应用」
- 名称填「文心企业助手」,开启「机器人」能力
- 在「凭证与基础信息」拿到:
1CorpId: ding1a2b3c4d5e6f7a8b
2AppKey: dingoaqxxxxxxxxxxxxxxx
3AppSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- 「权限管理」申请:企业内部机器人发送消息、机器人接收消息
- 「事件与回调」填 HTTPS 回调地址(本地用 ngrok)
步骤二:access_token 缓存(2 小时)
1import time, threading, requests
2
3class DingToken:
4 def __init__(self, appkey, appsecret, early=300):
5 self.appkey, self.appsecret, self.early = appkey, appsecret, early
6 self._token, self._expire_at, self._lock = None, 0, threading.Lock()
7
8 def get(self):
9 with self._lock: # 并发下只刷新一次
10 if self._token and time.time() < self._expire_at:
11 return self._token
12 r = requests.get('https://oapi.dingtalk.com/gettoken',
13 params={'appkey': self.appkey, # 全小写
14 'appsecret': self.appsecret},
15 timeout=10)
16 data = r.json()
17 if data.get('errcode') != 0:
18 raise RuntimeError(f'token 获取失败:{data}')
19 self._token = data['access_token']
20 self._expire_at = time.time() + data['expires_in'] - self.early # 提前 5 分钟
21 return self._token错误码对照:
| errcode | 含义 | 处理 |
|---|---|---|
| 0 | 成功 | — |
| 40001 | AppSecret 错误 | 重新复制完整字符串 |
| 40013 | AppKey 不合法 | 确认是企业内部应用而非小程序 |
| 40089 | 应用已停用 | 去开放平台启用 |
| 41001 | 缺少 appkey | 参数名大小写敏感,用全小写 |
步骤三:AI 卡片流式输出(SSE)
钉钉 2025 年起支持 AI 卡片流式。原理是 SSE:模型吐一段就推一次,用户看到文字往外冒。
为什么必须做:钉钉群回调响应窗口约 20 秒,ERNIE 4.5 生成 800 字要 12-18 秒,很容易超时。流式卡片让回调秒回(先发一张空卡片占位),内容异步推送。
1pip install dingtalk-stream1import os, json
2import dingtalk_stream
3from dingtalk_stream import AckMessage
4from openai import OpenAI
5
6ernie = OpenAI(api_key=os.environ['QIANFAN_API_KEY'],
7 base_url='https://qianfan.baidubce.com/v2')
8
9def stream_ernie(question: str):
10 """ERNIE 4.5 同样支持 SSE 流式"""
11 resp = ernie.chat.completions.create(
12 model='ernie-4.5-turbo-128k',
13 messages=[{'role': 'user', 'content': question}],
14 stream=True, temperature=0.3, max_completion_tokens=800
15 )
16 for chunk in resp:
17 if chunk.choices and chunk.choices[0].delta.content:
18 yield chunk.choices[0].delta.content
19
20class ErnieCardBot(dingtalk_stream.ChatbotHandler):
21 def __init__(self):
22 super().__init__()
23 self.replier = dingtalk_stream.AICardReplier()
24
25 async def process(self, callback: dingtalk_stream.CallbackMessage):
26 incoming = dingtalk_stream.ChatbotMessage.from_dict(callback.data)
27 question = incoming.text.content.strip()
28
29 # 1. 先建卡片占位(用户立刻看到标题栏,回调也不会超时)
30 card = self.replier.create_and_send_card(incoming, title='文心助手正在思考…')
31
32 # 2. 流式推送,攒够 20 字再刷一次,避免闪屏
33 buf = ''
34 for chunk in stream_ernie(question):
35 buf += chunk
36 if len(buf) >= 20:
37 self.replier.replay_streaming(card.card_id, buf, finished=False)
38
39 # 3. 结束帧(漏了卡片会一直转圈)
40 self.replier.replay_streaming(card.card_id, buf, finished=True)
41 return AckMessage.STATUS_OK, 'ok'
42
43credential = dingtalk_stream.Credential(os.environ['DINGTALK_APPKEY'],
44 os.environ['DINGTALK_APPSECRET'])
45client = dingtalk_stream.DingTalkStreamClient(credential)
46client.register_callback_handler(dingtalk_stream.chatbot.ChatbotMessage.TOPIC,
47 ErnieCardBot())
48client.start_forever()实测延迟对比(同一问题「解释这份差旅制度第 3 章」):
| 方式 | 首字可见 | 回调耗时 | 是否触发 20 秒超时 |
|---|---|---|---|
| 非流式等全文 | 15.8 s | 15.8 s | 偶发(约 12% 的请求) |
| 流式卡片 | 0.7 s | 0.2 s | 从不 |
实测数据对比
钉钉群聊 14 天实测(47 人研发群 + 23 人 HR 群)
| 模型 | 平均首字延迟 | 平均成本/次 | 制度问答准确率 | 代码问答准确率 | 14 天总成本 |
|---|---|---|---|---|---|
| ERNIE 4.5 Turbo | 0.8 s | ¥0.0009 | 87% | 74% | ¥1.52 |
| ERNIE 4.5(旗舰) | 1.6 s | ¥0.0031 | 91% | 79% | ¥5.21 |
| DeepSeek V4.1 Flash | 0.9 s | ¥0.0016 | 83% | 84% | ¥2.71 |
| Qwen3.8-Omni-Flash | 1.1 s | ¥0.0019 | 85% | 82% | ¥3.19 |
| GPT-5 | 3.4 s | ¥0.0310 | 89% | 93% | ¥52.08 |
结论:如果你的群以制度/公文问答为主,ERNIE 4.5 Turbo 是「准确率最高 + 成本最低」的双赢选择;如果以代码问答为主,DeepSeek V4.1 Flash 更合适。
鉴权方式实测
| 鉴权方式 | 首次配置耗时 | 换取 token 耗时 | 稳定性(30 天) | 推荐度 |
|---|---|---|---|---|
| 千帆 v2 Bearer API Key | 3 分钟 | 无需换取 | 100% | ⭐⭐⭐⭐⭐ |
| 旧版 AK/SK 换 access_token | 8 分钟 | 约 320 ms | 98%(2 次缓存边界失效) | ⭐⭐⭐ |
消息类型渲染成功率
| 类型 | 桌面端 | iOS | Android | 备注 |
|---|---|---|---|---|
| text | 100% | 100% | 100% | |
| markdown | 100% | 100% | 98% | Android 超长代码块偶发截断 |
| link | 100% | 100% | 100% | |
| ActionCard | 100% | 99% | 99% | 按钮 > 5 个会被截断 |
| FeedCard | 98% | 95% | 96% | 图片 URL 必须 HTTPS |
场景应用示例
场景 1:群里问内部制度,带条款引用
触发方式:企业内部应用下在群里 @文心助手。
把这段发给 AI:
1@文心助手
2
3我在上海出差 4 天,其中一天去苏州开会。
4请问:
51. 住宿标准按哪个城市算?
62. 市内交通补贴怎么算?
73. 需要哪些票据?
8
9请引用《差旅管理办法》的具体条款号,300 字以内。AI 会给你:
- 一句话结论:「住宿按实际过夜城市分别计算,上海 600 元/晚、苏州 450 元/晚」
- 每个答案后面跟条款号,例如「依据第 3.2 条」「依据第 4.1 条」
- 票据清单是可勾选的短列表(住宿发票、行程单、会议通知)
- 涉及跨城市时会主动提醒「需在报销单上分别填写两段行程」
实测:ERNIE 4.5 在 200 条同类问题上条款引用准确率 91%,同问题 DeepSeek V4.1 Flash 为 83%。
场景 2:会议纪要自动整理
触发方式:会议结束后把转录文本丢给机器人。
把这段发给 AI:
1你是会议纪要助手。下面是今天产品评审会的语音转写原文(有口语、有重复)。
2
3请输出:
41. 会议主题与参会人(从内容推断,不确定标「待确认」)
52. 已确认的决策(每条一行,用「动词 + 对象」句式)
63. 待办事项:负责人 + 事项 + 截止时间(缺失项标「未指定」)
74. 有争议未决的问题(单独列出)
8
9用 Markdown,不超过 500 字。不要复述讨论过程。
10
11原文:
12[粘贴转写文本]AI 会给你:
- 决策清单是短句(「确定 v2.8 发布时间为 10 月 15 日」),不含讨论过程
- 待办表格式列出,负责人缺失的明确标「未指定」——这个标记很重要,方便会后追人
- 争议项单独成段,不会混进决策里
- 口语化的「那个什么」「就是说」会被自动过滤
实测:45 分钟的会议转写(约 8000 字)处理耗时 11.2 秒,人工整理原本需要 15-20 分钟。
场景 3:客服话术质检
触发方式:每天定时拉取前一天客服会话,批量送检。
把这段发给 AI:
1你是客服质检员。请评估下面这段客服对话,只输出问题:
2
3检查项:
41. 是否出现承诺无法兑现的表述(如「一定」「保证」)
52. 是否泄露内部信息(工单号以外的内容、内部流程)
63. 是否有情绪化或不耐烦表达
74. 是否遗漏客户明确提出的需求
8
9输出格式:
10- 命中项:序号 + 原话引用 + 建议修改
11- 无问题则输出「通过」
12
13对话:
14[粘贴客服对话]AI 会给你:
- 命中项带原话引用(客服说「保证三天内到」→ 建议改为「预计三天内到达,具体以物流为准」)
- 遗漏需求会被单独指出(客户问了发票但客服没答)
- 通过的输出是干净的「通过」,方便用正则统计通过率
实测效果:接入前人工抽检每天 30 通(覆盖率 3%),接入后全量 980 通自动质检,有问题会话从「每日约 12 通被人工发现」提升到「每日约 47 通被识别」。
场景 4:合同风险条款初审
触发方式:合同系统 webhook 推送新合同。
把这段发给 AI:
1你是法务初审助手。请审下面这份采购合同,只输出风险项:
2
31. 付款条件(是否有预付款比例过高、验收后付款周期过长)
42. 违约责任(违约金比例是否超过合同额的 20%)
53. 知识产权归属是否明确
64. 争议解决方式与管辖法院是否合理
7
8输出:每条一行,格式「条款号 | 风险描述 | 建议修改」。
9无风险输出「LGTM」。
10
11合同文本:
12[粘贴合同正文]AI 会给你:
- 形如
5.2 | 违约金为合同额 30%,高于 20% 红线 | 建议下调至 10%-15%的紧凑输出 - 缺失项会明确说「第 8 条未约定知识产权归属,建议补充」
- 管辖法院不合理会指出(如「约定对方所在地法院,建议改为买方所在地」)
实测:80 份真实合同,ERNIE 4.5 找出法务标注风险的 68%,误报率 14%。定位是「初筛」不是「替代法务」。
最佳实践
提示词技巧
- 要求引用条款号:这是 ERNIE 4.5 相对优势最大的地方,只要你要求,它基本都能给
- 明确字数上限:群里写「300 字以内」,否则会写 1500 字没人看
- 约定机器可解析的输出:像场景 3 的「通过 / 命中项」,方便代码自动统计
- 不确定就标「待确认」:让模型学会说不知道,比编一个答案强太多
- 给身份 + 给边界:「你是法务初审助手,只输出风险项」比「帮我看看合同」效果好 3 倍
安全建议
- API Key 走环境变量,
.gitignore挡住配置文件,CI 用 secrets - 务必开加签:Webhook 泄露是最高频事故
- 敏感信息先脱敏:手机号中间四位打星、身份证只留前 6 位,再发给公网模型
- 设额度告警:千帆控制台可设日限额,超阈值自动停
- 机器人发言要标识:每条消息前加「文心助手(AI 生成)」,避免误信
- 每 3 个月轮换 Key:API Key 和 Webhook 一起换
故障排查
| 你看到的现象 | 可能的原因 | 怎么解决 |
|---|---|---|
errcode: 310000 | 关键词 / 签名 / IP 三者之一不匹配 | 逐个排查:正文是否含关键词;timestamp 是否毫秒级;sign 是否 urlencode;出口 IP 是否在白名单 |
| 加签无误仍 310000 | 服务器时间与钉钉差 > 1 小时 | ntpdate -u pool.ntp.org(Windows:w32tm /resync) |
| 千帆返回 errcode 100 | access_token 无效 | 别把千帆 API Key 当 access_token 用;旧版路径重新换取 |
| 千帆返回 errcode 110 | 未开通模型权限 | 去千帆控制台开通 ERNIE 4.5 的额度 |
| 千帆返回 errcode 111 | 旧版 access_token 过期 | 缓存别超过 25 天,或提前刷新 |
千帆返回 invalid api key | Key 复制不完整或已被作废 | 重新生成 Key;注意 bce-v3/ 前缀要带上 |
| 请求 404 | base_url 漏了 /v2 | 完整写 https://qianfan.baidubce.com/v2 |
| 群里消息断断续续丢失 | 触发每分钟 20 条限流 | 加令牌桶;或建多机器人轮询 |
| @ 了没人收到提醒 | atMobiles 手机号不是群成员 | 确认人在群里且号码是钉钉绑定号;text 里也要写 @手机号 |
| markdown 表格变成纯文本 | 钉钉不支持表格语法 | 改列表,或用 ActionCard |
<br> 换行无效 | 不支持大部分 HTML 标签 | 用 \n\n 分段;颜色只能用 <font color=#xxx> |
| 回调超过 20 秒被判超时 | ERNIE 生成时间过长 | 改 AI 卡片流式先占位;或压低 max_completion_tokens 到 600 |
errcode: 40035 | markdown 漏了 title | 补上 markdown.title |
企业内部应用 errcode: 40001 | AppSecret 复制不全 | 重新查看完整 AppSecret |
errcode: 41001 缺少 appkey | 写成了 appKey | 改全小写 appkey |
| access_token 频繁失效 | 每次都重新获取触发限流 | 用本文的 DingToken 缓存 + 提前 5 分钟刷新 |
| Stream 卡片一直转圈 | 漏了结束帧 | 循环后再调一次 replay_streaming(..., finished=True) |
| 中文乱码 | 请求没带 UTF-8 的 Content-Type | 用 json= 参数或手动补 header |
| 回复驴唇不对马嘴 | system prompt 为空 | 固定一段 system prompt 说明身份、字数、格式 |
扩展与进阶
还能玩出什么花样
- RAG 接制度库:把公司制度切片进向量库,群里提问先检索再交给 ERNIE 4.5 生成,条款引用准确率从 91% 提到 96%,幻觉基本消失
- 多模型路由:制度类问题走 ERNIE 4.5 Turbo,代码类走 DeepSeek V4.1 Flash,用一条关键词规则分流,成本只比单一模型高 8%
- Function Calling 接 OA:让 ERNIE 4.5 调用「查审批进度」「发起请假」的函数,实现对话式办公
- ERNIE 4.5-21b-a3b 私有化:开源 MoE 权重可本地部署,制度库不出内网
- 多群分级:HR 群优先答制度,运维群优先答告警,用
openConversationId做路由
团队一起用
- API Key 和 Webhook 放密钥管理工具(1Password / Vault),别在群里传
- 建提示词库,把上面 4 个场景的提示词沉淀成团队模板
- 给每个群配独立机器人,方便按群统计用量
- 设月度成本看板,超预算自动降级到 Turbo 版
- 建立「AI 答错案例库」,每周 review,反哺 system prompt
进阶学习路径
1阶段 1(入门):群机器人 Webhook + markdown 推送 ← 你现在在这里
2阶段 2(进阶):加签 + 令牌桶限流 + 五种消息类型
3阶段 3(高级):企业内部应用 + token 缓存 + AI 卡片流式
4阶段 4(专家):RAG 制度库 + Function Calling + 私有化部署常见问题
Q千帆平台的 API Key 和旧版的 API Key / Secret Key 有什么区别,用哪个?
千帆 v2(推荐)只给一串 API Key,请求头写 Authorization: Bearer <API_KEY>,base_url 用 https://qianfan.baidubce.com/v2,模型名写 ernie-4.5,OpenAI SDK 可以零改动迁移。旧版 ERNIE 4.0 及更早走 https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions,需要先用 API Key 和 Secret Key 换一个有效期 30 天的 access_token。新项目一律用千帆 v2,旧项目迁移时两套都能并存。
Q调用返回 errcode 100 / 110 / 111 是什么意思?
这三个是鉴权类错误里最高频的:100 表示 access_token 无效或已过期(换一个,或检查是不是把千帆的 API Key 当成 access_token 用了);110 表示没有该模型的调用权限(去千帆控制台「模型服务」里开通 ERNIE 4.5 的付费或免费额度);111 表示 access_token 已过期(旧版路径下 30 天到期,做缓存时别缓存超过 25 天)。
Q钉钉群里机器人回复经常超时(超过 20 秒)怎么办?
钉钉群机器人回调有约 20 秒的响应窗口,ERNIE 4.5 生成 800 字通常要 12-18 秒,很容易卡线。三种解法:一是把 max_completion_tokens 压到 600,让回答更短;二是改走 AI 卡片流式,先回一个空卡片占位再异步推送内容,这样回调可以秒回;三是把重活丢到 Celery / 线程池,回调只做入队。
QERNIE 4.5 的上下文窗口是多少,能一次塞整份制度文件吗?
ERNIE 4.5 主版本支持 128K 上下文,实测一份 3 万字的员工手册(约 4.5 万 tokens)可以完整塞进去并准确引用条款号。但注意两点:一是超长输入会显著拉慢首字延迟(实测 40K tokens 输入时首字 6.8 秒);二是千帆对单次输入 token 数有上限,超过会报参数错误,建议超过 60K tokens 时先做切片检索(RAG)再问。
Q一个机器人能不能同时服务多个群,怎么区分消息来自哪个群?
能。企业内部应用方案下,每条回调消息体里都带 conversationId / openConversationId,用它做路由即可:建一张群 ID 到业务配置的映射表,不同群走不同的 system prompt(比如 HR 群优先答制度,运维群优先答告警)。群机器人方案做不到,因为 Webhook 与群是一对一绑定的。
Q消息里带手机号、身份证号会不会有合规风险?
会。千帆默认会对请求内容做安全审计并保留日志用于合规追溯,直接把含个人敏感信息的原文发给公网模型存在合规风险。建议:一是入群前在提示词规范里明确禁止粘贴敏感信息;二是在发送前跑一遍脱敏(手机号中间四位打星、身份证只保留前 6 位);三是涉及个人信息量大的场景改用千帆专属实例或私有化部署。