Files
qiweimanager-master/plan.md

1239 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 企业微信自动客服改造方案
## 1. 目标概述
当前项目已经具备企业微信消息管理能力,后端 `helper.exe` 通过 DLL 注入、Socket 回调、本地 HTTP 服务和 `requestdata` / `eventdata` 模板,能够接收企业微信事件并发送企业微信消息。
本次需求是在现有能力上增加“自动客服”模块:
- 前端提供一键开启入口。
- 后端自动监听企业微信消息。
- 私聊客户消息自动处理。
- 群聊消息仅在用户 @ 当前机器人时处理。
- 根据本地知识库检索内容。
- 调用 AI 根据知识库内容生成回复。
- 能回答则自动回复客户。
- 不能回答、AI 失败或知识库低匹配时,自动私信指定同事转人工处理。
## 2. 当前项目基础
### 2.1 技术结构
项目当前是:
- 桌面端Wails
- 后端主程序Go`qiweimanager.exe`
- 辅助进程Go`helper.exe`
- 前端Vue 3 + Vite + Element Plus
- 本地 HTTP 服务:默认 `http://localhost:10001`
- 企业微信底层通信:`Helper_4.1.33.6009.dll``Loader_4.1.33.6009.dll`
- 发送消息模板:`requestdata/*.json`
- 接收事件模板:`eventdata/*.json`
### 2.2 已有关键能力
现有项目已经支持:
- 启动/注入企业微信:`type=10000`
- 发送文本消息:`requestdata/sendVWorkTextMessage.json`
- 群 @ 消息:`requestdata/sendVWorkGroupAtMessage.json`
- 获取群列表:`requestdata/getVWorkGroupList.json`
- 获取内部好友列表:`requestdata/getVWorkInternalFriendList.json`
- 获取外部联系人列表:`requestdata/getVWorkExternalFriendList.json`
- 接收企业微信消息回调:`helper.go` 中的 `MyRecvCallback`
- 事件转换:`TransformData` 使用 `eventdata/<type>.json`
- 本地 HTTP 管理页面:`http://localhost:10001/`
- 操作日志和前端配置管理
### 2.3 最适合接入的位置
自动客服的核心入口建议放在:
```text
helper/helper.go
MyRecvCallback(...)
```
原因:
- 这里能拿到所有企业微信入站事件。
- 当前已经在这里做了消息解析、时间过滤、ResponseChannel 判断、回调转发。
- 自动客服需要的是“被动监听消息”,不是主动请求响应,所以这里最自然。
- 可保持现有 `/api/send-wxwork-data``/api/third-party-request` 和 callback 功能不被破坏。
## 3. 总体架构设计
### 3.1 新增模块
建议新增以下模块:
```text
config/
types.go # 增加 AutoReplyConfig 配置结构
helper/
auto_reply.go # 自动客服主流程
auto_reply_ai.go # AI 调用适配
auto_reply_knowledge.go # 本地知识库解析、索引、检索
auto_reply_handoff.go # 转人工通知
auto_reply_status.go # 状态统计、运行记录
auto_reply_http.go # helper 侧自动客服 HTTP 接口
frontend/src/
components/AutoReply.vue # 自动客服配置和状态页面
```
如果希望少建文件,也可以把 helper 侧先合并为 2 到 3 个文件,但不建议全部塞进 `helper.go`,否则后续维护会变得很吃力。
### 3.2 消息处理链路
整体链路如下:
```text
企业微信收到消息
DLL Socket 回调
helper.go / MyRecvCallback
解析原始 JSON
判断是否是主动请求响应
如果是响应:继续走现有 ResponseChannel
如果是独立入站消息:进入自动客服判断
转换 eventdata 结构
判断是否需要处理
知识库检索
AI 生成回复
发送企业微信文本消息
失败或无法回答时私信指定同事
```
### 3.3 不破坏现有功能的原则
自动客服必须做到:
- 不影响当前前端“启动企微”。
- 不影响现有 requestdata 模板调用。
- 不影响第三方 callback。
- 不影响本地 dashboard。
- 不影响主动请求等待回调的逻辑。
- 自动客服出错不能导致 `helper.exe` 崩溃。
- 自动客服处理必须异步,不阻塞 `MyRecvCallback`
## 4. 配置设计
### 4.1 在 config 中新增 autoReplyConfig
建议在 `config/types.go` 中新增:
```go
type AutoReplyConfig struct {
Enabled bool `json:"enabled"`
Listen ListenConfig `json:"listen"`
Knowledge KnowledgeConfig `json:"knowledge"`
AI AIConfig `json:"ai"`
Handoff HandoffConfig `json:"handoff"`
ReplyPolicy ReplyPolicyConfig `json:"replyPolicy"`
}
type ListenConfig struct {
EnablePrivateChat bool `json:"enablePrivateChat"`
EnableGroupChat bool `json:"enableGroupChat"`
GroupTriggerMode string `json:"groupTriggerMode"`
IgnoreSelfMessage bool `json:"ignoreSelfMessage"`
DeduplicateSeconds int `json:"deduplicateSeconds"`
}
type KnowledgeConfig struct {
Directory string `json:"directory"`
IndexPath string `json:"indexPath"`
SupportedExtensions []string `json:"supportedExtensions"`
TopK int `json:"topK"`
MinScore float64 `json:"minScore"`
AutoRebuildOnStart bool `json:"autoRebuildOnStart"`
}
type AIConfig struct {
Provider string `json:"provider"`
BaseURL string `json:"baseUrl"`
APIKey string `json:"apiKey"`
Model string `json:"model"`
TimeoutSeconds int `json:"timeoutSeconds"`
Temperature float64 `json:"temperature"`
MaxTokens int `json:"maxTokens"`
}
type HandoffConfig struct {
HumanUserID string `json:"humanUserId"`
HumanConversationID string `json:"humanConversationId"`
MessageTemplate string `json:"messageTemplate"`
IncludeKnowledgeHits bool `json:"includeKnowledgeHits"`
}
type ReplyPolicyConfig struct {
UnknownAnswerToken string `json:"unknownAnswerToken"`
MaxQuestionLength int `json:"maxQuestionLength"`
CooldownSeconds int `json:"cooldownSeconds"`
}
```
并把它挂到现有配置:
```go
type Config struct {
CallbackConfig CallbackConfig `json:"callbackConfig"`
AutoReplyConfig AutoReplyConfig `json:"autoReplyConfig"`
LastUpdated int64 `json:"lastUpdated"`
}
```
### 4.2 默认配置
默认值建议:
```json
{
"autoReplyConfig": {
"enabled": false,
"listen": {
"enablePrivateChat": true,
"enableGroupChat": true,
"groupTriggerMode": "mention_only",
"ignoreSelfMessage": true,
"deduplicateSeconds": 300
},
"knowledge": {
"directory": "config/knowledge",
"indexPath": "config/knowledge/index.json",
"supportedExtensions": [".md", ".txt", ".csv", ".xlsx", ".docx", ".pdf"],
"topK": 5,
"minScore": 0.35,
"autoRebuildOnStart": false
},
"ai": {
"provider": "openai_compatible",
"baseUrl": "",
"apiKey": "",
"model": "",
"timeoutSeconds": 25,
"temperature": 0.2,
"maxTokens": 800
},
"handoff": {
"humanUserId": "",
"humanConversationId": "",
"messageTemplate": "客户问题需要人工处理:\n客户{{customerName}}\n问题{{question}}\n来源{{source}}\n会话{{conversationId}}\n原因{{reason}}",
"includeKnowledgeHits": true
},
"replyPolicy": {
"unknownAnswerToken": "NO_ANSWER",
"maxQuestionLength": 1000,
"cooldownSeconds": 3
}
}
}
```
## 5. 前端改造方案
### 5.1 新增菜单
`frontend/src/App.vue` 左侧菜单新增:
```text
自动客服
```
建议位置:
```text
系统首页
企微账号
自动客服
操作记录
回调配置
```
### 5.2 新增 AutoReply.vue 页面
页面模块建议分为 6 块:
1. 运行状态
2. 一键开启/关闭
3. AI 配置
4. 知识库配置
5. 人工接管配置
6. 最近处理记录
### 5.3 运行状态区
显示:
- 自动客服状态:未开启 / 运行中 / 错误
- helper 连接状态
- 当前活跃企微账号数
- 知识库文件数
- 知识库切片数
- 今日处理消息数
- 今日自动回复数
- 今日转人工数
- 今日 AI 失败数
- 今日忽略消息数
### 5.4 一键开启按钮
按钮行为:
```text
点击“一键开启自动客服”
保存当前自动客服配置
调用启动企微 type=10000
通知 helper reload 配置
如果知识库索引不存在,提示并重建索引
自动客服状态变为运行中
```
对应 Wails 方法:
```go
SetAutoReplyEnabled(true)
```
### 5.5 AI 配置区
字段:
- AI 类型:
- OpenAI 兼容接口
- 本地模型接口
- Base URL
- API Key
- Model
- Timeout
- Temperature
- Max Tokens
- 测试连接按钮
OpenAI 兼容接口示例:
```text
https://api.openai.com/v1
https://api.deepseek.com/v1
http://localhost:1234/v1
```
本地模型接口示例:
```text
http://localhost:11434
```
### 5.6 知识库配置区
字段:
- 本地知识库目录
- 支持格式展示md、txt、csv、xlsx、docx、pdf
- TopK
- 最低匹配分数
- 重建知识库索引按钮
- 上次索引时间
- 索引结果
### 5.7 人工接管配置区
字段:
- 指定同事 user_id
- 指定同事 conversation_id
- 转人工消息模板
- 是否附带知识库命中片段
- 测试发送按钮
说明:
- 最稳妥方式是配置 `humanConversationId`
- 如果只配置 `humanUserId`,后端按 `S:<robotId>_<humanUserId>` 推导 conversationId。
- 页面必须提供“测试发送”,确认能私信到指定同事。
## 6. Wails 后端接口方案
`app.go` 中新增方法:
```go
func (a *App) GetAutoReplyConfig() interface{}
func (a *App) SaveAutoReplyConfig(jsonData string) (bool, string)
func (a *App) SetAutoReplyEnabled(enabled bool) (bool, string)
func (a *App) GetAutoReplyStatus() interface{}
func (a *App) RebuildKnowledgeIndex() interface{}
func (a *App) TestAIConnection() interface{}
func (a *App) TestHumanHandoff() interface{}
```
这些方法主要负责:
- 读写 `config/config.json`
- 转发请求到 `helper.exe`
- 返回统一格式给前端
统一返回格式建议:
```json
{
"success": true,
"message": "ok",
"data": {}
}
```
失败时:
```json
{
"success": false,
"message": "错误原因",
"data": null
}
```
## 7. helper HTTP 接口方案
在 helper 本地 HTTP 服务中新增:
```text
GET /api/auto-reply/status
POST /api/auto-reply/reload
POST /api/auto-reply/rebuild-knowledge
POST /api/auto-reply/test-ai
POST /api/auto-reply/test-handoff
```
### 7.1 GET /api/auto-reply/status
返回:
```json
{
"success": true,
"data": {
"enabled": true,
"running": true,
"lastError": "",
"knowledgeFileCount": 10,
"knowledgeChunkCount": 320,
"todayReceived": 100,
"todayReplied": 60,
"todayHandoff": 12,
"todayIgnored": 28,
"lastMessages": []
}
}
```
### 7.2 POST /api/auto-reply/reload
用途:
- 重新加载 `config/config.json`
- 重新初始化自动客服配置
- 不重启 helper
### 7.3 POST /api/auto-reply/rebuild-knowledge
用途:
- 扫描本地知识库目录
- 解析文档
- 构建索引
- 写入 `config/knowledge/index.json`
### 7.4 POST /api/auto-reply/test-ai
用途:
- 使用当前 AI 配置发起一次测试请求
- 不进入企业微信消息流程
### 7.5 POST /api/auto-reply/test-handoff
用途:
- 给指定同事发送一条测试私信
- 验证 `humanConversationId``humanUserId` 是否正确
## 8. 自动客服消息判断规则
### 8.1 只处理文本消息
当前文本消息模板主要是:
```text
eventdata/11041.json
event = 20002
```
自动客服初版只处理:
```json
{
"event": "20002",
"data": {
"message": "...",
"conversationId": "...",
"fromWxId": "...",
"toWxId": "...",
"fromNickName": "...",
"atWxIdList": []
}
}
```
非文本消息处理策略:
- 图片:转人工
- 文件:转人工
- 语音:转人工
- 视频:转人工
- 位置:转人工
- 链接:转人工
- 名片:转人工
### 8.2 私聊处理规则
私聊消息满足:
- 不是群聊 conversationId
- 不是机器人自己发出的消息
- 文本内容不为空
- 没有重复处理过
则自动处理。
### 8.3 群聊处理规则
群聊消息必须满足:
- 是群聊 conversationId
- 文本消息
- 不是机器人自己发出的消息
- `atWxIdList` 包含当前机器人 ID或文本内容包含 @ 当前机器人昵称
- 未重复处理
未 @ 机器人时:
- 不回复
- 计入 ignored
- dashboard 可记录原因:`group message without mention`
### 8.4 自己消息过滤
如果满足以下任一条件,忽略:
- `fromWxId == robotId`
- `fromWxId == 当前登录企微 user_id`
- 原始消息标记为自己发送
- `sender == receiver` 且能确认是本机消息
### 8.5 去重策略
使用以下字段生成去重 key
```text
robotId + conversationId + serverId
```
如果没有 `serverId`
```text
robotId + conversationId + localId + sendTime + fromWxId
```
默认 300 秒内重复消息不处理。
## 9. 知识库方案
### 9.1 本地目录
默认目录:
```text
config/knowledge/
```
建议结构:
```text
config/knowledge/
faq.md
product.md
price.xlsx
after-sales.docx
policy.pdf
index.json
```
### 9.2 支持格式
用户选择“全都支持”,因此初版支持:
- `.md`
- `.txt`
- `.csv`
- `.xlsx`
- `.docx`
- `.pdf`
### 9.3 解析策略
不同文件策略:
- Markdown/TXT按标题和段落切分。
- CSV按行切分每行拼接字段名和值。
- Excel按 sheet + 行切分。
- DOCX提取段落文本后切分。
- PDF提取页面文本后切分。
每个 chunk 建议结构:
```json
{
"id": "hash",
"source": "faq.md",
"title": "售后政策",
"content": "具体内容",
"line": 12,
"page": 0,
"updatedAt": 1710000000,
"hash": "..."
}
```
### 9.4 检索策略
初版不引入向量库,使用本地关键词 / BM25 风格检索:
- 中文分词可先用 rune bigram + keyword 简化实现。
- 英文按空格和标点切词。
- 计算 query 和 chunk 的相关度。
- 返回 topK。
- 最高分低于 `minScore` 时认为知识库无法回答。
默认:
```text
topK = 5
minScore = 0.35
```
### 9.5 后续增强方向
后续可以升级为:
- 本地 embedding
- OpenAI embedding
- SQLite FTS5
- 向量数据库
- 混合检索
但初版不建议一开始引入复杂依赖,先把闭环跑通。
## 10. AI 调用方案
### 10.1 OpenAI 兼容接口
请求:
```text
POST {baseUrl}/chat/completions
Authorization: Bearer {apiKey}
```
如果用户填写的 `baseUrl` 是:
```text
https://api.openai.com/v1
```
则最终请求:
```text
https://api.openai.com/v1/chat/completions
```
请求体:
```json
{
"model": "gpt-4.1-mini",
"temperature": 0.2,
"max_tokens": 800,
"messages": [
{
"role": "system",
"content": "你是企业微信客服助手,只能基于知识库回答。知识库没有答案时输出 NO_ANSWER。"
},
{
"role": "user",
"content": "客户问题 + 知识库片段"
}
]
}
```
### 10.2 本地模型接口
默认适配 Ollama
```text
POST {baseUrl}/api/chat
```
请求体:
```json
{
"model": "qwen2.5",
"stream": false,
"messages": [
{
"role": "system",
"content": "你是企业微信客服助手,只能基于知识库回答。知识库没有答案时输出 NO_ANSWER。"
},
{
"role": "user",
"content": "客户问题 + 知识库片段"
}
]
}
```
如果本地模型提供 OpenAI-compatible 接口,则用户直接选择 OpenAI 兼容模式即可。
### 10.3 Prompt 约束
系统提示词建议:
```text
你是企业微信客服助手。
你只能根据提供的知识库片段回答客户问题。
如果知识库片段不能支持答案,必须只输出 NO_ANSWER。
不要编造政策、价格、承诺、库存、物流时效。
回答要简洁、礼貌、像真人客服。
如果客户要求人工、投诉、退款、合同、发票、价格特殊审批,也输出 NO_ANSWER。
```
用户消息格式:
```text
客户昵称:{{fromNickName}}
客户问题:{{question}}
知识库片段:
[1] {{chunk1}}
[2] {{chunk2}}
[3] {{chunk3}}
请基于知识库回答。
```
### 10.4 AI 无法回答判定
以下情况触发转人工:
- 知识库最高分低于阈值。
- AI 返回 `NO_ANSWER`
- AI 返回空字符串。
- AI HTTP 调用失败。
- AI 超时。
- AI 返回结构无法解析。
- 消息是非文本。
- 客户明确要求人工客服。
- 客户问题超过最大长度。
- 命中敏感业务关键词,例如退款、投诉、合同、发票、赔偿等。
## 11. 自动回复发送方案
### 11.1 私聊回复
使用已有模板:
```text
requestdata/sendVWorkTextMessage.json
```
转换后的底层 type
```json
{
"type": 11029,
"data": {
"conversation_id": "{{conversationId}}",
"content": "{{answer}}"
}
}
```
调用方式:
```go
sendTextToConversation(clientId, conversationId, answer)
```
### 11.2 群聊回复
群聊 @ 机器人后,默认回复到原群:
```text
conversationId = 原消息 conversationId
```
可选策略:
- 默认不 @ 提问人,只回复文本。
- 后续可以增加 `replyWithAtSender` 开关,使用 `sendVWorkGroupAtMessage`
初版建议默认不 @,避免 atList 字段兼容问题带来发送失败。
## 12. 转人工私信方案
### 12.1 私信对象配置
用户要求:
```text
直接发私信给指定同事的企业微信
```
因此配置:
```json
{
"humanUserId": "指定同事user_id",
"humanConversationId": "指定同事私聊conversation_id"
}
```
优先级:
1. 如果配置了 `humanConversationId`,直接使用。
2. 如果没有配置,则使用 `S:<robotId>_<humanUserId>` 推导。
3. 如果推导失败或发送失败,记录错误并在前端状态展示。
### 12.2 转人工消息内容
默认模板:
```text
客户问题需要人工处理
客户:{{customerName}}
客户ID{{fromWxId}}
来源:{{source}}
会话ID{{conversationId}}
问题:{{question}}
原因:{{reason}}
时间:{{time}}
请及时处理。
```
如果开启 `includeKnowledgeHits`,追加:
```text
知识库候选:
1. {{source}} / score={{score}}
2. {{source}} / score={{score}}
```
### 12.3 转人工触发原因枚举
建议原因:
```text
knowledge_low_score
ai_no_answer
ai_timeout
ai_http_error
ai_parse_error
non_text_message
manual_keyword
send_reply_failed
config_missing
```
前端展示时转成中文。
## 13. 状态统计和运行记录
新增内存状态对象:
```go
type AutoReplyStatus struct {
Enabled bool
Running bool
LastError string
KnowledgeFileCount int
KnowledgeChunkCount int
KnowledgeLastIndexedAt int64
TodayReceived int
TodayReplied int
TodayHandoff int
TodayIgnored int
TodayAIFailed int
LastMessages []AutoReplyRecord
}
```
运行记录:
```go
type AutoReplyRecord struct {
ID int64
Time string
RobotID string
ConversationID string
Source string
FromWxID string
FromNickName string
Question string
Action string
Reason string
Answer string
}
```
`Action` 可选:
```text
ignored
replied
handoff
failed
```
## 14. 错误处理策略
### 14.1 自动客服不能影响主流程
自动客服所有处理都必须:
- `recover` panic
- 写日志
- 更新状态
- 不向外抛出导致 `MyRecvCallback` 异常
### 14.2 AI 超时
默认:
```text
25 秒
```
超时后:
- 不继续等待。
- 转人工。
- 状态计入 `TodayAIFailed``TodayHandoff`
### 14.3 发送失败
自动回复发送失败时:
- 记录失败。
- 转人工通知。
- 如果转人工也失败,写入 `LastError`
### 14.4 知识库索引失败
单个文件失败:
- 不影响其他文件。
- 在前端显示失败文件。
- 写入日志。
全部失败:
- 自动客服仍可开启。
- 所有问题都会因为知识库低分而转人工。
## 15. 实施步骤
### 阶段一:配置和接口骨架
1. 扩展 `config/types.go`,加入自动客服配置结构。
2. 修改默认配置生成逻辑。
3.`app.go` 增加 Wails 方法:
- `GetAutoReplyConfig`
- `SaveAutoReplyConfig`
- `SetAutoReplyEnabled`
- `GetAutoReplyStatus`
4. 在 helper HTTP server 增加自动客服路由。
5. 确认现有编译不受影响。
### 阶段二:前端自动客服页面
1. 新增 `frontend/src/components/AutoReply.vue`
2. 修改 `App.vue` 侧边栏,增加“自动客服”菜单。
3. 实现配置读取、保存、开关、状态刷新。
4. 实现测试 AI、测试人工私信、重建知识库按钮。
5. 保持当前 UI 风格,不做大规模视觉重构。
### 阶段三:知识库模块
1. 创建 `helper/auto_reply_knowledge.go`
2. 实现本地目录扫描。
3. 实现 `.md/.txt/.csv` 解析。
4. 实现 `.xlsx/.docx/.pdf` 解析。
5. 实现 chunk 切分。
6. 实现索引保存和加载。
7. 实现关键词/BM25 风格检索。
8. 将统计信息暴露给状态接口。
### 阶段四AI 模块
1. 创建 `helper/auto_reply_ai.go`
2. 实现 OpenAI-compatible 调用。
3. 实现 Ollama 本地模型调用。
4. 实现 prompt 构造。
5. 实现 `NO_ANSWER` 判断。
6. 实现 AI 测试接口。
### 阶段五:消息监听和自动回复
1. 创建 `helper/auto_reply.go`
2.`MyRecvCallback` 中接入自动客服入口。
3. 确保 ResponseChannel 响应不触发自动客服。
4. 实现文本消息过滤。
5. 实现私聊自动处理。
6. 实现群聊 @ 机器人处理。
7. 实现去重。
8. 实现调用知识库 + AI + 发送回复。
### 阶段六:转人工私信
1. 创建 `helper/auto_reply_handoff.go`
2. 实现转人工消息模板渲染。
3. 实现指定同事私信发送。
4. 实现测试发送。
5. 自动回复失败时触发转人工。
### 阶段七:测试和验证
1. 增加 Go 单元测试。
2. 增加 mock AI server 测试。
3. 前端执行 `npm run build`
4. Go 执行 `go test ./...`
5. 构建 helper。
6. 构建 Wails。
7. 实机验证私聊、群聊 @、群聊未 @、转人工。
## 16. 测试用例
### 16.1 私聊文本自动回复
输入:
```json
{
"event": "20002",
"data": {
"conversationId": "S:customer_robot",
"fromWxId": "customer",
"toWxId": "robot",
"message": "你们营业时间是几点?"
}
}
```
预期:
- 检索知识库。
- 调用 AI。
- 发送回复到原 conversationId。
- 状态 `TodayReplied +1`
### 16.2 群聊未 @ 不回复
输入:
```json
{
"event": "20002",
"data": {
"conversationId": "R:group",
"fromWxId": "customer",
"message": "你们营业时间是几点?",
"atWxIdList": []
}
}
```
预期:
- 不调用 AI。
- 不发送消息。
- 状态 `TodayIgnored +1`
### 16.3 群聊 @ 机器人自动回复
输入:
```json
{
"event": "20002",
"data": {
"conversationId": "R:group",
"fromWxId": "customer",
"message": "@机器人 你们营业时间是几点?",
"atWxIdList": ["robot"]
}
}
```
预期:
- 调用知识库。
- 调用 AI。
- 回复到原群。
### 16.4 知识库无答案转人工
输入:
```text
你们能不能帮我办理完全无关的问题?
```
预期:
- 检索低分。
- 不调用或不采纳 AI。
- 私信指定同事。
- 状态 `TodayHandoff +1`
### 16.5 AI 返回 NO_ANSWER 转人工
AI 输出:
```text
NO_ANSWER
```
预期:
- 不回复客户。
- 私信指定同事。
- 状态 `TodayAIFailed +1``TodayHandoff +1`
### 16.6 AI 超时转人工
预期:
- 超过 timeout 后触发转人工。
- 不阻塞后续消息处理。
### 16.7 重复消息不重复回复
同一个 `serverId` 连续进入两次。
预期:
- 第一次处理。
- 第二次忽略。
## 17. 验收标准
完成后应满足:
- 前端有“自动客服”页面。
- 能一键开启/关闭自动客服。
- 能配置 AI 接口。
- 能配置本地知识库目录。
- 能重建知识库索引。
- 能测试 AI 连接。
- 能配置指定人工同事并测试私信。
- 私聊客户文本消息能自动回复。
- 群聊只有 @ 机器人时才自动回复。
- 未 @ 的群消息不会回复。
- AI 无法回答时能私信指定同事。
- 自动客服处理失败不影响现有企业微信管理能力。
- 原有 `http://localhost:10001/` dashboard 和 requestdata 接口保持可用。
## 18. 风险点和注意事项
### 18.1 conversationId 推导风险
私信指定同事最好配置明确的 `humanConversationId`
如果只配置 `humanUserId`,按 `S:<robotId>_<humanUserId>` 推导可能因企业微信内部规则不同而失败,因此必须提供“测试发送”。
### 18.2 群聊 @ 判断风险
有些事件可能 `atWxIdList` 不完整,因此群聊触发判断应同时支持:
- `atWxIdList` 包含机器人 ID
- 文本内容包含 `@机器人昵称`
### 18.3 AI 胡答风险
必须强制 AI 只基于知识库回答。
如果知识库没有答案AI 必须输出 `NO_ANSWER`
### 18.4 文件解析依赖风险
`.xlsx/.docx/.pdf` 支持会引入新依赖或额外解析逻辑。
如果希望第一版更稳,可以先实现 `.md/.txt/.csv`,但本需求要求“全都支持”,因此计划里按全格式支持实现。
### 18.5 不阻塞 DLL 回调
AI 调用和知识库检索都不能直接阻塞 `MyRecvCallback`
应通过 goroutine + 队列处理。
## 19. 建议的默认上线策略
第一版建议:
- 先只开启私聊自动回复。
- 群聊只开 @ 机器人触发。
- 最低知识库分数先设置偏高,例如 `0.4`
- AI 无答案严格转人工。
- 所有转人工消息都附带原始 conversationId 和客户 ID。
- 开启详细日志,方便回放和排查。
## 20. 后续增强方向
后续可以继续增加:
- 多机器人分别配置知识库。
- 不同群使用不同知识库。
- 客户画像和历史上下文。
- 工单系统对接。
- 向量检索。
- 对话记忆。
- 人工接管后暂停自动回复。
- 黑名单/白名单群配置。
- 敏感词和合规审核。
- 前端消息实时流展示。