mirror of
https://github.com/eryajf/chatgpt-dingtalk.git
synced 2025-12-24 12:57:50 +08:00
* 将ai交互切换为go-openai * add stream * ✨ feat(stream): 优化流式响应机制,实现实时卡片更新 - 将固定1.5秒更新改为基于300ms最小间隔的实时更新策略 - 新增内容缓冲区机制,避免过于频繁的API调用 - 改进流式中断处理,保护已接收的内容不丢失 🔧 chore(llm): 优化HTTP客户端配置 - 增加连接池设置(MaxIdleConns: 100, MaxIdleConnsPerHost: 10) - 设置空闲连接超时时间为90秒 - 添加HTTP/2禁用选项注释,用于解决流式错误问题 📝 docs(stream): 更新流式更新策略文档 - 详细说明实时流式更新机制和缓冲策略 - 新增HTTP/2流式错误的故障排除指南 - 更新配置参数说明和建议范围 🐛 fix(stream): 修复流式中断时的内容丢失问题 - 在流式接收中断时,确保已接收的内容不会丢失 - 改进错误处理逻辑,区分有内容和无内容的情况 * modify ai
8.2 KiB
8.2 KiB
流式输出功能使用指南
功能概述
项目已支持钉钉机器人的流式输出功能,可以让 AI 回答像打字一样逐字显示,提供更好的用户体验。
两种流式模式
1. 简化流式模式(推荐快速开始)
特点:
- 无需配置钉钉卡片模板
- 直接使用累积内容一次性回复
- 配置简单,开箱即用
配置方式:
在 config.yml 中添加:
# 启用流式输出
stream_mode: true
2. 高级流式卡片模式
特点:
- 使用钉钉互动卡片实现真正的流式更新
- 内容逐步显示,类似 ChatGPT 网页版效果
- 需要在钉钉开放平台创建卡片模板
配置方式:
在 config.yml 中添加:
# 启用流式输出
stream_mode: true
# 钉钉卡片模板ID (可选,用于高级流式卡片模式)
card_template_id: "your-card-template-id"
配置钉钉卡片模板(高级模式)
步骤 1: 创建卡片模板
- 登录 钉钉开放平台
- 进入你的应用 -> 互动卡片 -> 卡片模板管理
- 创建新模板,使用以下 JSON Schema:
{
"type": "object",
"properties": {
"content": {
"type": "string",
"title": "内容"
}
}
}
步骤 2: 设计卡片样式
在卡片编辑器中,添加一个 Markdown 组件来显示 content 字段:
{
"type": "markdown",
"text": "{{content}}"
}
步骤 3: 发布并获取模板ID
- 保存并发布卡片模板
- 复制模板ID(类似:
4d18414c-aabc-4ec8-9e67-4ceefeada72a.schema) - 将模板ID填入
config.yml的card_template_id字段
完整配置示例
# 日志级别
log_level: "info"
# OpenAI 配置
api_key: "sk-..."
model: "gpt-4o"
base_url: "" # 可选,用于 API 中转
# 流式输出配置
stream_mode: true # 启用流式输出
card_template_id: "" # 可选:钉钉卡片模板ID
# 其他配置...
session_timeout: 600s
max_question_len: 2048
max_answer_len: 2048
max_text: 4096
default_mode: "单聊"
实现原理
简化模式流程
用户提问 → OpenAI 流式响应 → 累积完整内容 → 一次性回复
高级卡片模式流程
用户提问
↓
创建钉钉卡片(空内容)
↓
发送初始状态 "稍等,让我想一想..."
↓
OpenAI 流式响应
↓
接收到内容 → 立即累积到缓冲区
↓
距离上次更新超过300ms? → 是 → 更新卡片
↓ 否 ↓
继续接收 ←-----------┘
↓
流式结束,发送最终内容(标记为完成)
技术架构
新增文件
-
- 实现 OpenAI 流式响应
- 提供
SingleQaStream()和ContextQaStream()API - 支持 ChatCompletion 流式调用
-
- 实现钉钉流式卡片更新
- 封装钉钉 Streaming Update API
- 提供
UpdateAIStreamCard()方法
-
- 实现流式处理逻辑
DoStream()- 简化流式模式DoStreamWithCard()- 高级卡片模式- 包含定时更新和错误处理
改动文件
-
- 添加
StreamMode配置项 - 添加
CardTemplateID配置项
- 添加
-
pkg/process/process_request.go
- 根据配置自动选择流式或普通模式
- 支持流式卡片和流式普通两种方式
API 使用示例
在代码中使用流式 API
import "github.com/eryajf/chatgpt-dingtalk/pkg/llm"
// 单聊流式
contentCh, cleanup, err := llm.SingleQaStream("你好", "user123")
if err != nil {
log.Fatal(err)
}
defer cleanup()
for content := range contentCh {
fmt.Print(content) // 逐块输出
}
// 串聊流式
client, contentCh, err := llm.ContextQaStream("继续", "user123")
if err != nil {
log.Fatal(err)
}
defer client.Close()
fullAnswer := ""
for content := range contentCh {
fullAnswer += content
fmt.Print(content)
}
// 保存对话上下文
client.ChatContext.SaveConversation("user123")
性能优化
流式更新策略
高级卡片模式采用实时流式更新策略:
- 从大模型接收到内容后立即更新卡片
- 使用缓冲机制避免更新过于频繁(默认最小间隔 300ms)
- 这样可以实现真正的实时流式体验,类似 ChatGPT 网页版
可以在 pkg/process/stream.go 中修改最小更新间隔:
minUpdateInterval := 300 * time.Millisecond // 修改这里
建议范围:200ms - 500ms
- 更小的间隔:更实时,但 API 调用更频繁
- 更大的间隔:API 调用较少,但流式感觉不明显
流式模式选择建议
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 快速部署 | 简化模式 | 无需额外配置 |
| 追求体验 | 高级卡片模式 | 真正的流式显示 |
| 高频使用 | 简化模式 | 减少 API 调用 |
| 演示展示 | 高级卡片模式 | 视觉效果更好 |
兼容性
- ✅ 保持原有非流式模式完全兼容
- ✅ 支持单聊和串聊两种对话模式
- ✅ 支持所有 OpenAI 兼容的模型
- ✅ 支持 Azure OpenAI
- ✅ 保留敏感词过滤、请求限制等功能
故障排查
问题 1: 流式模式不生效
检查项:
- 确认
config.yml中stream_mode: true - 重启应用以加载新配置
- 查看日志是否有错误信息
问题 2: 卡片模式无法显示 / 日志显示 "robot code is empty"
原因: 这是正常的降级行为
说明:
- 高级卡片模式需要通过
credentials配置才能工作 - 如果没有配置
credentials,系统会自动降级为简化流式模式 - 简化流式模式不需要卡片,依然可以正常工作
解决方案:
- 如果想使用高级卡片模式,需要在
config.yml中配置credentials:credentials: - client_id: "your-app-key" client_secret: "your-app-secret" - 如果不需要卡片模式,可以忽略这个警告,或者将
card_template_id留空
问题 3: 卡片模板配置正确但不显示
检查项:
- 确认卡片模板ID正确
- 确认卡片模板已发布
- 确认钉钉应用有卡片权限
- 确认
credentials配置正确 - 查看日志是否有降级提示
问题 4: 流式响应中断
可能原因:
- OpenAI API 超时 - 检查网络连接
- 钉钉 Access Token 过期 - 会自动刷新
- 上下文超过限制 - 减少
max_text配置
问题 5: HTTP/2 流式错误 "stream error: INTERNAL_ERROR"
错误信息:
Post "https://api.xxx.com/v1/completions": stream error: stream ID 5; INTERNAL_ERROR; received from peer
可能原因:
- 上游 API 服务器内部错误或资源不足
- 网络不稳定,长连接中断
- HTTP/2 连接管理问题
解决方案:
-
已优化: 代码已优化 HTTP 客户端配置,增加连接池和超时设置
-
部分内容保护: 如果已接收到部分内容,不会因错误而丢失
-
禁用 HTTP/2 (如果问题频繁): 在 pkg/llm/client.go 中取消注释:
Transport: &http.Transport{ // ... ForceAttemptHTTP2: false, // 取消注释这行 }注意:禁用 HTTP/2 会降低性能,但可能更稳定
-
检查 API 服务器: 如果使用中转服务,检查中转服务器的健康状况和资源
智能降级机制
系统实现了智能降级机制,确保即使高级功能无法使用,基础功能依然可用:
尝试高级卡片模式
↓
检查 RobotCode 是否存在
↓ (否)
降级为简化流式模式
↓
检查 credentials 配置
↓ (无配置)
降级为简化流式模式
↓
尝试创建卡片
↓ (失败)
降级为简化流式模式
↓
正常流式输出
这意味着:
- ✅ 即使配置不完整,流式功能依然可用
- ✅ 不会因为卡片失败而导致整个功能不可用
- ✅ 日志会清楚地告诉你当前使用的是哪种模式
参考资料
贡献
欢迎提交 Issue 和 Pull Request 来改进流式功能!