Files
shop-platform/docs/api_kefu.md

18 KiB
Raw Blame History

智能客服API接口文档

一、接口说明

本接口用于连接微信小程序与Dify聊天机器人实现智能客服功能。支持流式和非流式两种响应模式具备完整的事务保护、数据一致性和状态管理功能。

二、配置说明

1. 安装插件

在ThinkPHP后台的插件管理页面中找到智能客服插件aikefu并点击安装按钮。

2. 配置插件

  1. 进入智能客服配置页面
  2. 输入从Dify平台获取的API密钥
  3. 配置API基础地址默认https://api.dify.ai/v1
  4. 配置聊天接口端点(默认:/chat-messages
  5. 启用智能客服功能

3. 获取Dify API密钥

  1. 登录Dify平台
  2. 进入工作台
  3. 选择您的聊天机器人项目
  4. 点击"发布"按钮
  5. 在API访问页面获取API密钥

三、接口列表

1. 系统健康检查

接口地址/api/kefu/health

请求方式POST

请求参数

参数名 类型 必填 说明
uniacid int 站点ID
check_type string 检查类型full完整、basic基础、ai_serviceAI服务默认full

响应示例

{
  "code": 0,
  "message": "success",
  "data": {
    "status": "healthy",
    "check_id": "health_56789",
    "timestamp": "2023-12-25 10:30:45",
    "total_checks": 2,
    "passed_checks": 2,
    "failed_checks": 0,
    "response_time_ms": 170,
    "components": {
      "ai_service": {
        "status": "healthy",
        "message": "AI服务正常",
        "response_time_ms": 150
      },
      "database": {
        "status": "healthy",
        "message": "数据库连接正常",
        "response_time_ms": 20
      }
    },
    "warnings": [],
    "errors": []
  }
}

2. 获取服务配置信息

接口地址/api/kefu/info

请求方式POST

请求参数

参数名 类型 必填 说明
uniacid int 站点ID
member_id int 会员ID
token string 访问令牌

响应示例

{
  "code": 0,
  "message": "success",
  "data": {
    "enabled": true,
    "status": "enabled"
  }
}

3. 智能客服聊天接口

接口地址/api/kefu/chat

请求方式POST 或 GET流式模式支持EventSource

请求参数

参数名 类型 必填 说明
query string 用户输入的消息内容
user_id string 用户ID默认使用当前登录会员ID
conversation_id string 会话ID第一次聊天可不传系统会自动创建
stream bool 是否使用流式响应默认false
response_mode string 响应模式streaming流式、blocking阻塞默认streaming
uniacid int 站点ID

响应示例

非流式响应stream=false 或 response_mode=blocking

{
  "code": 0,
  "message": "success",
  "data": {
    "conversation_id": "conv_123456789",
    "answer": "您好,我是智能客服,有什么可以帮助您的?",
    "message_id": "msg_123456789",
    "finish_reason": "stop",
    "usage": {
      "prompt_tokens": 10,
      "completion_tokens": 20,
      "total_tokens": 30
    }
  }
}

流式响应stream=true 或 response_mode=streaming

响应格式Server-Sent Events (SSE)

响应示例

data: {"event":"message","answer":"您好","conversation_id":"conv_123456789","message_id":"msg_123456789"}

data: {"event":"message","answer":",我是智能客服,","conversation_id":"conv_123456789","message_id":"msg_123456789"}

data: {"event":"message","answer":"有什么可以帮助您的?","conversation_id":"conv_123456789","message_id":"msg_123456789"}

data: {"event":"message_end","conversation_id":"conv_123456789","message_id":"msg_123456789"}

data: {"event":"done","data":{"conversation_id":"conv_123456789","message_id":"msg_123456789","content":"您好,我是智能客服,有什么可以帮助您的?"}}

data: {"event":"close","data":{"conversation_id":"conv_123456789","message_id":"msg_123456789"}}

4. 获取会话历史

接口地址/api/kefu/getHistory

请求方式POST

请求参数

参数名 类型 必填 说明
uniacid int 站点ID
conversation_id string 会话ID
user_id string 用户ID默认使用当前登录会员ID
limit int 每页条数默认20
offset int 偏移量默认0
member_id int 会员ID
token string 访问令牌

响应示例

{
  "code": 0,
  "message": "success",
  "data": {
    "messages": [
      {
        "id": "msg_123456789",
        "role": "user",
        "content": "您好",
        "create_time": 1703505845
      },
      {
        "id": "msg_123456790",
        "role": "assistant",
        "content": "您好,我是智能客服,有什么可以帮助您的?",
        "create_time": 1703505846
      }
    ],
    "total": 2,
    "page_info": {
      "limit": 20,
      "offset": 0
    }
  }
}

5. 清除会话历史

接口地址/api/kefu/clearConversation

请求方式POST

请求参数

参数名 类型 必填 说明
uniacid int 站点ID
conversation_id string 与user_id二选一 会话ID与user_id二选一
user_id string 与conversation_id二选一 用户ID默认使用当前登录会员ID与conversation_id二选一
member_id int 会员ID
token string 访问令牌

响应示例

{
  "code": 0,
  "message": "success",
  "data": {}
}

四、前端调用示例

1. 非流式聊天Fetch API

// 非流式聊天
async function chatWithAI(message, conversationId = '') {
  try {
    const formData = new FormData();
    formData.append('query', message);
    formData.append('uniacid', '1');
    formData.append('stream', 'false');
    formData.append('response_mode', 'blocking');
    
    if (conversationId) {
      formData.append('conversation_id', conversationId);
    }
    
    const response = await fetch('/api/kefu/chat', {
      method: 'POST',
      body: formData
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    const result = await response.json();
    
    if (result.code === 0) {
      return result.data;
    } else {
      console.error('聊天失败:', result.message);
      return null;
    }
  } catch (error) {
    console.error('聊天请求失败:', error);
    return null;
  }
}

2. 流式聊天EventSource

// EventSource 流式聊天
function chatWithAIEventSource(message, conversationId = '', onMessage, onComplete, onError) {
  // 关闭之前的连接
  if (window.currentEventSource) {
    window.currentEventSource.close();
  }
  
  // 构建请求参数
  const params = new URLSearchParams({
    uniacid: '1',
    user_id: '123456',
    query: message,
    conversation_id: conversationId || '',
    stream: 'true'
  });
  
  const url = `/api/kefu/chat?${params.toString()}`;
  
  try {
    const eventSource = new EventSource(url);
    window.currentEventSource = eventSource;
    
    let aiMessage = '';
    
    // 监听消息事件
    eventSource.addEventListener('message', (event) => {
      try {
        const data = JSON.parse(event.data);
        
        if (data.event === 'message') {
          // 更新 AI 消息
          aiMessage += data.answer || '';
          if (onMessage) onMessage(data.answer || '');
        }
        
        if (data.event === 'message_end') {
          // 对话完成
          if (onComplete) onComplete({ 
            conversation_id: data.conversation_id,
            message: aiMessage 
          });
        }
        
        if (data.conversation_id) {
          conversationId = data.conversation_id;
        }
      } catch (error) {
        console.error('解析消息失败:', error);
      }
    });
    
    // 监听完成事件
    eventSource.addEventListener('done', (event) => {
      try {
        const data = JSON.parse(event.data);
        if (onComplete) onComplete(data);
      } catch (error) {
        console.error('解析完成事件失败:', error);
      }
    });
    
    // 监听关闭事件
    eventSource.addEventListener('close', (event) => {
      try {
        const data = JSON.parse(event.data);
        console.log('连接正常结束:', data);
      } catch (error) {
        console.error('解析关闭事件失败:', error);
      }
      window.currentEventSource = null;
    });
    
    // 监听错误事件
    eventSource.addEventListener('error', (error) => {
      console.error('EventSource错误:', error);
      if (onError) onError({ error: 'EventSource连接错误' });
      window.currentEventSource = null;
    });
    
    return eventSource;
    
  } catch (error) {
    console.error('创建EventSource失败:', error);
    if (onError) onError({ error: error.message });
    return null;
  }
}

3. 流式聊天Fetch API

// Fetch API 流式聊天
async function chatWithAIFetchStream(message, conversationId = '', onMessage, onComplete, onError) {
  try {
    // 构建请求体
    const formData = new FormData();
    formData.append('uniacid', '1');
    formData.append('user_id', '123456');
    formData.append('query', message);
    formData.append('conversation_id', conversationId || '');
    formData.append('stream', 'true');
    
    const response = await fetch('/api/kefu/chat', {
      method: 'POST',
      body: formData,
      headers: {
        'Accept': 'text/event-stream'
      }
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    if (!response.body) {
      throw new Error('响应体不可用');
    }
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let buffer = '';
    let aiMessage = '';
    
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      
      // 解码新接收的数据
      buffer += decoder.decode(value, { stream: true });
      
      // 处理缓冲的数据,按行分割
      let lineEnd;
      while ((lineEnd = buffer.indexOf('\n')) !== -1) {
        const line = buffer.substring(0, lineEnd);
        buffer = buffer.substring(lineEnd + 1);
        
        if (line.startsWith('data: ')) {
          try {
            const data = JSON.parse(line.substring(6));
            
            if (data.event === 'message') {
              aiMessage += data.answer || '';
              if (onMessage) onMessage(data.answer || '');
            } else if (data.event === 'message_end') {
              if (onComplete) onComplete({
                conversation_id: data.conversation_id,
                message: aiMessage
              });
            } else if (data.event === 'done' && onComplete) {
              onComplete(data);
            } else if (data.event === 'error' && onError) {
              onError(data);
            }
            
            if (data.conversation_id) {
              conversationId = data.conversation_id;
            }
          } catch (e) {
            console.warn('解析流式数据失败:', e);
          }
        }
      }
    }
    
    // 处理剩余的缓冲数据
    if (buffer.startsWith('data: ')) {
      try {
        const data = JSON.parse(buffer.substring(6));
        if (data.event === 'message' && onMessage) {
          onMessage(data.answer || '');
        } else if (data.event === 'done' && onComplete) {
          onComplete(data);
        }
      } catch (e) {
        console.warn('解析剩余数据失败:', e);
      }
    }
    
  } catch (error) {
    console.error('Fetch流式聊天请求失败:', error);
    if (onError) onError({ error: error.message });
  }
}

4. Uniapp调用示例

// Uniapp 非流式调用
async function chatWithAI(message, conversationId = '') {
  try {
    const res = await uni.request({
      url: '/api/kefu/chat',
      method: 'POST',
      data: {
        query: message,
        uniacid: 1,
        conversation_id: conversationId,
        response_mode: 'blocking'
      }
    });
    
    if (res[1].data.code === 0) {
      return res[1].data.data;
    } else {
      console.error('聊天失败:', res[1].data.message);
      return null;
    }
  } catch (error) {
    console.error('聊天请求失败:', error);
    return null;
  }
}

// Uniapp 获取历史记录
async function getChatHistory(conversationId, limit = 20, offset = 0) {
  try {
    const res = await uni.request({
      url: '/api/kefu/getHistory',
      method: 'POST',
      data: {
        uniacid: 1,
        conversation_id: conversationId,
        limit: limit,
        offset: offset
      }
    });
    
    if (res[1].data.code === 0) {
      return res[1].data.data;
    } else {
      console.error('获取历史记录失败:', res[1].data.message);
      return null;
    }
  } catch (error) {
    console.error('获取历史记录请求失败:', error);
    return null;
  }
}

// Uniapp 健康检查
async function checkHealth(checkType = 'full') {
  try {
    const res = await uni.request({
      url: '/api/kefu/health',
      method: 'POST',
      data: {
        uniacid: 1,
        check_type: checkType
      }
    });
    
    if (res[1].data.code === 0) {
      return res[1].data.data;
    } else {
      console.error('健康检查失败:', res[1].data.message);
      return null;
    }
  } catch (error) {
    console.error('健康检查请求失败:', error);
    return null;
  }
}

五、使用流程

  1. 初始化检查:小程序端启动时,调用healthinfo接口检查服务状态
  2. 获取会话:进入客服页面时,系统会自动创建或使用已有会话
  3. 发送消息:用户输入消息后,调用chat接口发送消息,获取机器人回复
  4. 显示消息:将用户消息和机器人回复显示在聊天界面
  5. 加载历史记录:需要时调用getHistory接口加载历史消息
  6. 维护会话保持会话ID用于后续消息交流
  7. 清理数据:根据用户需求调用clearConversation接口清理历史数据

六、数据存储机制

1. 存储状态

状态值 含义 说明
streaming 流式中 正在进行流式输出的临时数据
completed 已完成 正常完成的对话数据
failed 失败 流式过程中发生失败的数据

2. 事务保护

  • 流式对话使用临时会话ID机制失败时自动回滚
  • 非流式对话:完整的事务保护,确保数据一致性
  • 重复检查:避免重复存储相同消息

3. 数据一致性

  • 用户消息和助手消息通过conversation_id关联
  • 会话状态实时更新,便于管理和监控
  • 详细的日志记录,便于问题排查

七、注意事项

  1. 必填参数:所有接口都需要uniacid站点ID参数
  2. 参数更新:新版本使用query替代message,使用uniacid替代site_id
  3. 事件驱动:后端采用事件驱动架构,所有业务逻辑通过事件处理器执行
  4. 安全性请确保Dify API密钥的安全性不要泄露给前端
  5. 用户标识建议对用户ID进行加密处理避免直接使用敏感信息
  6. 流式体验:推荐使用stream: true参数获得更好的用户体验
  7. 会话管理:建议实现会话管理机制,定期清理过期会话
  8. 频率限制:建议添加请求频率限制,防止恶意请求
  9. 生产环境在生产环境中建议关闭DEBUG模式
  10. 数据完整性:系统已内置事务保护和重复检查机制

八、测试建议

  1. 基础检查:首先调用health接口检查系统状态
  2. 配置验证:调用info接口验证配置信息
  3. 接口测试使用Postman或类似工具测试各个API接口
  4. 流式测试:测试chat接口的流式响应功能
  5. 完整流程:在小程序端集成并测试完整流程
  6. 边界测试:模拟不同场景下的用户输入,测试机器人回复效果
  7. 压力测试:测试接口在高并发情况下的表现
  8. 数据验证:检查非流式对话的存储完整性和一致性

九、常见问题

1. 接口返回400错误

原因:缺少必填参数uniacid或参数格式错误 解决方法确保请求中包含有效的站点ID参数名已更新为uniacid

2. 健康检查返回503错误

原因AI服务配置不完整或服务异常 解决方法检查插件配置和Dify API服务状态

3. 接口返回401错误

原因Dify API密钥无效或过期 解决方法重新获取有效的API密钥并更新插件配置

4. 接口返回500错误

原因后端服务器错误或Dify API服务异常 解决方法查看服务器日志检查Dify API服务状态

5. 机器人回复为空

原因Dify聊天机器人配置问题或请求参数错误 解决方法检查Dify机器人配置验证请求参数是否正确

6. 流式响应无法解析

原因客户端不支持SSE或解析方式错误 解决方法使用正确的方式解析Server-Sent Events格式参考前端示例代码

7. 会话ID无效

原因:会话已过期或不存在 解决方法创建新会话获取新的会话ID

8. 参数不匹配

原因:使用了旧版本的参数名称 解决方法:更新参数:messagequerysite_iduniacid

十、性能优化建议

  1. 缓存配置:可对info接口返回的配置信息进行客户端缓存
  2. 连接复用HTTP请求使用连接池减少建立连接的开销
  3. 压缩传输启用gzip压缩减少传输数据量
  4. 分页加载:历史记录使用分页加载,避免一次性加载大量数据
  5. CDN加速静态资源使用CDN加速访问
  6. 监控告警:建立接口性能监控和告警机制
  7. 数据清理:定期清理过期和失败状态的垃圾数据
  8. 索引优化:为常用查询字段添加数据库索引

文档更新时间2025-12-10
版本v2.1
兼容性:向后兼容,推荐使用标准的uniacid参数