搭建自己的ai客服

搭建自己的ai客服

本节介绍的ai客服搭建主要服务于初学者,一套下来希望你对前进的道路更加坚定!那我们开始吧

1.准备工作

1.Agent角色设定

随心设计好Agent的角色,并完成相应的个性化文档供大模型学习

在这里插入图片描述

在这里插入图片描述

这里的话建议提前构思好,写好专家文档txt,可以与我不一样,无所谓的。

2.准备好openai的key

本文中调用的是openai的gpt-3.5-turbo,经济实惠

2.搭建flask框架(pycharm)

这里的话代码自己研究研究,可以拓展tools的,不懂问问GPT

1.安装环境

pip install -r requirements.txt

requirements.txt内容:

annotated-types==0.6.0
anyio==3.7.1
blinker==1.7.0
certifi==2023.7.22
charset-normalizer==3.3.2
click==8.1.7
distro==1.8.0
exceptiongroup==1.1.3
flask==3.0.0
functions==0.7.0
h11==0.14.0
httpcore==1.0.2
httpx==0.25.1
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
openai==1.2.3
packaging==23.2
pydantic==2.4.2
pydantic-core==2.10.1
requests==2.31.0
sniffio==1.3.0
tqdm==4.66.1
typing-extensions==4.8.0
urllib3==2.1.0
werkzeug==3.0.1
2.app.py源码(框架运行)
import json
import os
import time
from flask import Flask, request, jsonify
import openai
from openai import OpenAI
import functions

from packaging import version


required_version = version.parse("1.1.1")
current_version = version.parse(openai.__version__)
OPENAI_API_KEY = '<填你自己的openai-key>'
#OPENAI_API_BASE ='https://api.novelnetwork.online/v1'
if current_version < required_version:
  raise ValueError(
      f"Error: OpenAI version {openai.__version__} is less than the required version 1.1.1"
  )
else:
  print("OpenAI version is compatible.")

# Flask常规操作
app = Flask(__name__)

# KEY写自己的
client = OpenAI(api_key=OPENAI_API_KEY)#,base_url=OPENAI_API_BASE)

# 加载助手
assistant_id = functions.create_assistant(
    client)  # this function comes from "functions.py"


# 得到对话请求
@app.route('/start', methods=['GET'])
def start_conversation():
  print("Starting a new conversation...")
  thread = client.beta.threads.create()
  print(f"New thread created with ID: {thread.id}")
  return jsonify({"thread_id": thread.id})


# 调用GPT和API产生结果
@app.route('/chat', methods=['POST'])
def chat():
  data = request.json
  thread_id = data.get('thread_id')
  user_input = data.get('message', '')

  if not thread_id:
    print("Error: Missing thread_id")
    return jsonify({"error": "Missing thread_id"}), 400

  print(f"Received message: {user_input} for thread ID: {thread_id}")


  client.beta.threads.messages.create(thread_id=thread_id,
                                      role="user",
                                      content=user_input)

  run = client.beta.threads.runs.create(thread_id=thread_id,
                                        assistant_id=assistant_id)

  # 是否需要调用API
  while True:
    run_status = client.beta.threads.runs.retrieve(thread_id=thread_id,
                                                   run_id=run.id)
    # print(f"Run status: {run_status.status}")
    if run_status.status == 'completed':
      break
    elif run_status.status == 'requires_action':
      # 处理各种API
      for tool_call in run_status.required_action.submit_tool_outputs.tool_calls:
        if tool_call.function.name == "create_lead":
          # Process lead creation
          arguments = json.loads(tool_call.function.arguments)
          output = functions.create_lead(arguments["name"], arguments["phone"],
                                          arguments["wechat"], arguments["address"], arguments["summary"], arguments["intention"])
          client.beta.threads.runs.submit_tool_outputs(thread_id=thread_id,
                                                       run_id=run.id,
                                                       tool_outputs=[{
                                                           "tool_call_id":
                                                           tool_call.id,
                                                           "output":
                                                           json.dumps(output)
                                                       }])
      time.sleep(1)  # Wait for a second before checking again

  # 返回结果
  messages = client.beta.threads.messages.list(thread_id=thread_id)
  response = messages.data[0].content[0].text.value

  print(f"Assistant response: {response}")
  return jsonify({"response": response})


if __name__ == '__main__':
  app.run(host='0.0.0.0', port=8080)
3.functions.py源码
import json
import requests
import os
from openai import OpenAI
import openai
from prompts import assistant_instructions


#注意你复制完可能要加上Bearer这个前缀
AIRTABLE_API_KEY = '<填你自己的airtable-key>'
OPENAI_API_KEY = '<填你自己的openai-key>'
#OPENAI_API_BASE ='https://api.novelnetwork.online/v1'
# Init OpenAI Client
client = OpenAI(api_key=OPENAI_API_KEY)#,base_url=OPENAI_API_BASE)


# 创建一个表单数据
def create_lead(name, phone, wechat,address,summary,intention):
  url = "<替换成自己的在线表单地址>"  # 替换自己的(后续有讲)
  headers = {
      "Authorization": AIRTABLE_API_KEY,
      "Content-Type": "application/json"
  }
  data = {
      "records": [{
          "fields": {
              "Name": name,
              "Phone": phone,
              "Wechat": wechat,
              "Address": address,
              "Summary": summary,
              "Intention": intention
          }
      }]
  }
  response = requests.post(url, headers=headers, json=data)
  if response.status_code == 200:
    print("Lead created successfully.")
    return response.json()
  else:
    print(f"Failed to create lead: {response.text}")

# 创建助手
def create_assistant(client):
  assistant_file_path = 'assistant.json'

  # 如果json不存在就创建一个,如果换本地知识库要删除原来的
  if os.path.exists(assistant_file_path):
    with open(assistant_file_path, 'r') as file:
      assistant_data = json.load(file)
      assistant_id = assistant_data['assistant_id']
      print("Loaded existing assistant ID.")
  else:
    file = client.files.create(file=open("<填写ai要学习的文档地址>", "rb"),
                               purpose='assistants')

    assistant = client.beta.assistants.create(
        # 这里面要调用你写好的指令和接下来会用到的API
        instructions=assistant_instructions,
        model="gpt-3.5-turbo",
        tools=[
            {
                "type": "retrieval"  # This adds the knowledge base as a tool
            },
            {
                "type": "function",  # 写表单
                "function": {
                    "name": "create_lead",
                    "description":
                    "Capture lead details and save to Airtable.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "name": {
                                "type": "string",
                                "description": "Name of the lead."
                            },
                            "phone": {
                                "type": "string",
                                "description": "Phone number of the lead."
                            },
                            "wechat": {
                                "type": "string",
                                "description": "Phone number of the lead."
                            },
                            "address": {
                                "type": "string",
                                "description": "Address of the lead."
                            },
                            "summary": {
                                "type": "string",
                                "description": "Summarize students’ questions."
                            },
                            "intention": {
                                "type": "string",
                                "description": "Students’ purchase intention."
                            }
                        },
                        "required": ["name", "phone","wechat","address","summary","intention"]
                    }
                }
            }
        ],
        file_ids=[file.id])

    # 要创建一个新的json
    with open(assistant_file_path, 'w') as file:
      json.dump({'assistant_id': assistant.id}, file)
      print("Created a new assistant and saved the ID.")

    assistant_id = assistant.id

  return assistant_id
4.prompts.py源码
assistant_instructions = """
本助手的角色是金牌销售员,擅长根据你学习到的销售话语与客户进行交流。请你用中文描述学员所咨询问题和答案以及客户的购买意向是否强烈,以便销售团队进行进一步营销,不要发给客户我们已经记录信息了。注意每回答一次学员的问题都尽可能要求他留下详细的信息,因为你的核心目的是销售,只有获取到手机号或者微信号
这两个关键信息后,本助手才需要调用create_lead函数来生成表单,需要向该函数提供学员的姓名,电话,微信号,地址,总结的问题和购买意向这六项参数,如果部分信息未知可以用null来替换;如果客户未提供关键信息则不需要调用。
"""

设置ai的提示词,可自行修改,注意写好prompt的三要素:指令、上下文、角色。

3.运行flask并发布公网

1.运行

在这里插入图片描述

flask框架正常运行的样式,这里没有直接写与前端交互的代码,所以第一个http请求会报404,因为我们这个ai的需求其实是嵌入式的(嵌入网页里头,后面会讲嵌入式的前端怎么处理)

2.发布公网

参考文章网址https://blog.csdn.net/fq157856469/article/details/135271176?ops_request_misc=&request_id=&biz_id=102&utm_term=flask%E6%90%AD%E5%BB%BA%E5%85%AC%E7%BD%91%E6%9C%8D%E5%8A%A1%E5%99%A8&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-135271176.142v100pc_search_result_base1&spm=1018.2226.3001.4187

1.注册Cpolar(内网穿透)

由于我们的flask框架运行在局域网,要实现公网的ai嵌入需要内网穿透(这里需要花99块买个二级子域名的权限,舍不着孩子套不着ai)

https://www.cpolar.com

点击官网地址进行注册下载客户端

在这里插入图片描述

点进去
在这里插入图片描述

进入创建隧道

在这里插入图片描述

创建隧道后,隧道名称任意修改,本地地址改为flask运行的端口,我的是5000,其他不动。

进入隧道列表查看

在这里插入图片描述

点击编辑

在这里插入图片描述

点击二级子域名,sub Domain随便填,地区与创建时对应,我一开始没冲钱,想着白嫖,后面才知道随机域名对现实生产环境没什么卵用,要二级子域名公网的地址才能稳定,这里就麻烦了一点。你们要是提前冲好,一开始创建时就可以设置二级子域名了。

在这里插入图片描述

这就是发布到公网的地址,你可以上浏览器搜搜,能搜出来(可能是404 not found 别忘了前端没做呢)就行

4.前端嵌入实现

1.注册Voiceflow

这是一个拖拽式的模块化的前端生成工具,这里是他的使用说明

https://learn.voiceflow.com/hc/en-us/articles/10569376208781-Launching-to-your-Website

了解了他的相关作用我们创建一个Agent并进入他的工作空间

在这里插入图片描述

在这里插入图片描述

2.逻辑编写

按如下方式连线,整个流程按照箭头指向来完成

在这里插入图片描述

注意几个细节

在这里插入图片描述

/start前放你发布到公网的网址

下面的Capture Response不要改动,这是传参的

可以点击send Request来看看能不能发送get请求,200就ok

在这里插入图片描述

在这里插入图片描述

同样的/chat前网址做一个替换

其余保持不变

也可以发送一下请求看看可以没

5.外部API的调用

1.注册Airtable

https://airtable.com/

在这里插入图片描述

2.创表

新建一个工作区间,并进行如图所示的创表

在这里插入图片描述

注意

在这里插入图片描述

每个标签的数据格式都要时text的(single还是long都没事)

3.获取表单的token值

在这里插入图片描述

点击这个

在这里插入图片描述

在这里插入图片描述

给读写权限并制定表名,创建token

记得保存好,只会出现一次

然后回到表单位置,看网址部分

在这里插入图片描述

在这里插入图片描述

进行替换

4.用postman测试api联通

在网上下载安装postman

进入postman新建connections

在这里插入图片描述

把刚刚换好的地址填进去,发送

第一次发送一般不成功,还要点击headers(7)这里添加

在这里插入图片描述

key值不变动,value换成你刚刚获取的token值,对Bearer 后的进行替换,再次发送,出现200就ok

一般作项目开发都是先想好要调哪些api,然后测试api连不连得上,然后才应用到代码中,postman就显得很重要了

6.在线调试

重新回到Voiceflow,点击run,点击agent test进行测试,在pycharm中也可以进行调试

在这里插入图片描述

在这里插入图片描述

这里的话就多根据ai反馈调整prompt的书写,我的prompt写的不咋地,可能很多业务场景都给不出很好的回复,这也是以后我们学习大模型微调的意义

在这里插入图片描述

在这里插入图片描述

这里的话提示词可能设的不大好,summary和intention都是英文,大家自己改改看,我这里就演示下流程哈

7.部署上线

这里当然不可能直接部署到别人网站去,我们可以随便找个html文件

1.集成voiceflow的agent

在这里插入图片描述

发布版本,并点击弹窗的链接

在这里插入图片描述

在这里插入图片描述

general和appearance可以调整ai嵌入的样式,自行修改

复制这个黑框框的内容

2.嵌入到HTML中

随便打开一个html,把刚刚复制的嵌入到前

在这里插入图片描述

在这里插入图片描述

再次点击

在这里插入图片描述

可以看到右下角出现了个小圆圈,点击即可进入ai会话

在这里插入图片描述

恭喜你已经全部完成啦!!!!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
/** * @brief Callback function for dynamic reconfiguration of DWA planner parameters * * @param config Reference to the configuration object that stores the updated parameters * @param level The level of reconfiguration, unused in this function */ void DWAPlannerROS::reconfigureCB(DWAPlannerConfig &config, uint32_t level) { // If the setup has been completed and restore_defaults flag is set, restore default configuration if (setup_ && config.restore_defaults) { config = default_config_; config.restore_defaults = false; } // If setup has not been completed, store default configuration and set the setup flag to true if ( ! setup_) { default_config_ = config; setup_ = true; } // Update generic local planner parameters base_local_planner::LocalPlannerLimits limits; limits.max_vel_trans = config.max_vel_trans; limits.min_vel_trans = config.min_vel_trans; limits.max_vel_x = config.max_vel_x; limits.min_vel_x = config.min_vel_x; limits.max_vel_y = config.max_vel_y; limits.min_vel_y = config.min_vel_y; limits.max_vel_theta = config.max_vel_theta; limits.min_vel_theta = config.min_vel_theta; limits.acc_lim_x = config.acc_lim_x; limits.acc_lim_y = config.acc_lim_y; limits.acc_lim_theta = config.acc_lim_theta; limits.acc_lim_trans = config.acc_lim_trans; limits.xy_goal_tolerance = config.xy_goal_tolerance; limits.yaw_goal_tolerance = config.yaw_goal_tolerance; limits.prune_plan = config.prune_plan; limits.trans_stopped_vel = config.trans_stopped_vel; limits.theta_stopped_vel = config.theta_stopped_vel; // Call reconfigureCB function of the planner_util_ object with updated limits and restore_defaults flag planner_util_.reconfigureCB(limits, config.restore_defaults); // Call reconfigure function of the dp_ object with updated configuration dp_->reconfigure(config); }
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过于真实呢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值