Skip to content

在 API 调用中从 AI 代理发送电话呼叫。或者,直接从配置的电话号码呼叫机器人!Send a phone call from AI agent, in an API call. Or, directly call the bot from the configured phone number!

License

Notifications You must be signed in to change notification settings

yuanzhongqiao/call-center-ai

 
 

Repository files navigation

呼叫中心 AI

使用 Azure 和 OpenAI GPT 的 AI 驱动的呼叫中心解决方案。

上次发布日期 项目许可证

在 GitHub Codespaces 中打开

概述

在 API 调用中从 AI 代理发送电话呼叫。或者,直接从配置的电话号码呼叫机器人!

保险、IT 支持、客户服务等。机器人可以在几秒钟内(真的)进行自定义以满足您的需求。

# Ask the bot to call a phone number
data='{
  "bot_company": "Contoso",
  "bot_name": "Amélie",
  "phone_number": "+11234567890",
  "task": "Help the customer with their digital workplace. Assistant is working for the IT support department. The objective is to help the customer with their issue and gather information in the claim.",
  "agent_phone_number": "+33612345678",
  "claim": [
    {
      "name": "hardware_info",
      "type": "text"
    },
    {
      "name": "first_seen",
      "type": "datetime"
    },
    {
      "name": "building_location",
      "type": "text"
    }
  ]
}'

curl
--header 'Content-Type: application/json'
--request POST
--url https://xxx/call
--data $data

特征

注意

这个项目是一个概念验证。它不打算用于生产。这演示了如何结合使用 Azure 通信服务、Azure 认知服务和 Azure OpenAI 来构建自动化呼叫中心解决方案。

  • 在公共网站上访问索赔
  • 访问客户对话历史记录
  • 允许用户更改对话的语言
  • Assistant 可以向用户发送 SMS 以获���更多信息
  • ���以从电话号码调用 Bot
  • 机器人使用多种语音音调(例如,happy、sad、neutral)来保持对话的吸引力
  • 机器人可以理解公司产品(= 词典)(例如,特定保险产品的名称)
  • 自行创建一个任务的待办事项列表以完成声明
  • 可自定义的提示
  • 需要时脱离人工代理
  • 从 LLM 中过滤掉不适当的内容,例如亵渎性语言或同意的公司名称
  • 使用 GPT-4o 和 GPT 4o-mini 深入了解客户要求
  • 遵循声明的特定数据架构
  • 可以访问文档数据库(小样本培训 / RAG)
  • 帮助用户查找完成索赔所需的信息
  • 越狱检测
  • 通过 usign a Redis 缓存降低 AI 搜索成本
  • 使用 Application Insights 进行监控和跟踪
  • 使用功能标志执行用户测试
  • 在对话期间接收 SMS 以获取明确措辞
  • 记录审计和质量保证的电话
  • 响应从 LLM 流式传输给用户,以避免长时间停顿
  • 通话后发送短信报告
  • 脱离会话后收回对话
  • 需要时回拨用户
  • 模拟 IVR 工作流程

演示

YouTube 上提供了法语演示。不要犹豫,以 x1.5 的速度观看演示,以快速了解该项目。

法语演示

演示中显示的主要交互:

  1. 用户呼叫中心
  2. 机器人回答并开始对话
  3. 机器人将 conversation、claim 和 todo list 存储在数据库中

调用期间存储的数据提取:

{
  "claim": {
    "incident_datetime": "2024-10-08T02:00:00",
    "incident_description": "La trottinette électrique fait des bruits bizarres et émet de la fumée blanche.",
    "incident_location": "46 rue du Charles de Gaulle",
    "injuries": "Douleur au genou suite à une chute.",
    "involved_parties": "Lesne",
    "policy_number": "B02131325XPGOLMP"
  },
  "messages": [
    {
      "created_at": "2024-10-08T11:23:41.824758Z",
      "action": "call",
      "content": "",
      "persona": "human",
      "style": "none",
      "tool_calls": []
    },
    {
      "created_at": "2024-10-08T11:23:55.421654Z",
      "action": "talk",
      "content": "Bonjour, je m'appelle Amélie, de Contoso Assurance ! Comment puis-je vous aider aujourd'hui ?",
      "persona": "assistant",
      "style": "cheerful",
      "tool_calls": []
    },
    {
      "created_at": "2024-10-08T11:24:19.972737Z",
      "action": "talk",
      "content": "Oui bien sûr. Bonjour, je vous appelle parce que j'ai un problème avec ma trottinette électrique. Elle marche plus depuis ce matin, elle fait des bruits bizarres et il y a une fumée blanche qui sort de la trottinette.",
      "persona": "human",
      "style": "none",
      "tool_calls": []
    }
  ],
  "next": {
    "action": "case_closed",
    "justification": "The customer provided all necessary information for the claim, and they expressed satisfaction with the assistance received. No further action is required at this time."
  },
  "synthesis": {
    "long": "You reported an issue with your electric scooter, which started making strange noises and emitting white smoke. This incident occurred at 2:00 AM while you were riding it, leading to a fall and resulting in knee pain. The location of the incident was noted, and your policy details were confirmed. I have documented all the necessary information to file your claim. Please take care of your knee, and feel free to reach out if you need further assistance.",
    "satisfaction": "high",
    "short": "the breakdown of your scooter",
    "improvement_suggestions": "Ensure that the assistant provides clear next steps and offers to schedule follow-up calls proactively to enhance customer support."
  },
  ...
}

通话后的用户报告

报告位于 (如 )。它显示对话历史记录、索赔数据和提醒。https://[your_domain]/report/[phone_number]http://localhost:8080/report/%2B133658471534

用户报告

高级架构

<details class="details-reset details-overlay details-overlay-dark" style="display: contents">
  <summary role="button" aria-label="“打开”对话框" class="btn my-2 mr-2 p-0 d-inline-flex" aria-haspopup="dialog" _mstaria-label="154752" _msthash="335">
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="octicon m-2">
      <path fill-rule="evenodd" d="M3.72 3.72a.75.75 0 011.06 1.06L2.56 7h10.88l-2.22-2.22a.75.75 0 011.06-1.06l3.5 3.5a.75.75 0 010 1.06l-3.5 3.5a.75.75 0 11-1.06-1.06l2.22-2.22H2.56l2.22 2.22a.75.75 0 11-1.06 1.06l-3.5-3.5a.75.75 0 010-1.06l3.5-3.5z"></path>
    </svg>
  </summary>
  <details-dialog class="Box Box--overlay render-full-screen d-flex flex-column anim-fade-in fast" aria-label="mermaid rendered container" role="dialog" aria-modal="true" _msthidden="1" _mstaria-label="611598" _msthash="336">
    <div _msthidden="1">
      <button aria-label="Close dialog" data-close-dialog="" type="button" data-view-component="true" class="Link--muted btn-link position-absolute render-full-screen-close" _msthidden="A" _mstaria-label="177619" _msthash="337">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:text-bottom" class="octicon octicon-x">
          <path fill-rule="evenodd" d="M5.72 5.72a.75.75 0 011.06 0L12 10.94l5.22-5.22a.75.75 0 111.06 1.06L13.06 12l5.22 5.22a.75.75 0 11-1.06 1.06L12 13.06l-5.22 5.22a.75.75 0 01-1.06-1.06L10.94 12 5.72 6.78a.75.75 0 010-1.06z"></path>
        </svg>
      </button>
      <div class="Box-body border-0" role="presentation"></div>
    </div>
  </details-dialog>
</details>
<iframe title="File display" role="presentation" class="render-viewer" sandbox="allow-scripts allow-same-origin allow-top-navigation allow-popups" src="https://viewscreen.githubusercontent.com/markdown/mermaid?docs_host=https%3A%2F%2Fdocs.github.com&color_mode=light#23af2562-ae28-4569-9283-dc8c5bf20749" name="23af2562-ae28-4569-9283-dc8c5bf20749" data-content="{"data":"---\ntitle: System diagram (C4 model)\n---\ngraph\n user([\"User\"])\n agent([\"Agent\"])\n\n app[\"Call Center AI\"]\n\n app -- Transfer to --&gt; agent\n app -. Send voice .-&gt; user\n user -- Call --&gt; app\n"}"> </iframe>
Loading
---
title: System diagram (C4 model)
---
graph
  user(["User"])
  agent(["Agent"])
Loading

组件级架构

<details class="details-reset details-overlay details-overlay-dark" style="display: contents">
  <summary role="button" aria-label="“打开”对话框" class="btn my-2 mr-2 p-0 d-inline-flex" aria-haspopup="dialog" _mstaria-label="154752" _msthash="344">
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="octicon m-2">
      <path fill-rule="evenodd" d="M3.72 3.72a.75.75 0 011.06 1.06L2.56 7h10.88l-2.22-2.22a.75.75 0 011.06-1.06l3.5 3.5a.75.75 0 010 1.06l-3.5 3.5a.75.75 0 11-1.06-1.06l2.22-2.22H2.56l2.22 2.22a.75.75 0 11-1.06 1.06l-3.5-3.5a.75.75 0 010-1.06l3.5-3.5z"></path>
    </svg>
  </summary>
  <details-dialog class="Box Box--overlay render-full-screen d-flex flex-column anim-fade-in fast" aria-label="mermaid rendered container" role="dialog" aria-modal="true" _msthidden="1" _mstaria-label="611598" _msthash="345">
    <div _msthidden="1">
      <button aria-label="Close dialog" data-close-dialog="" type="button" data-view-component="true" class="Link--muted btn-link position-absolute render-full-screen-close" _msthidden="A" _mstaria-label="177619" _msthash="346">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:text-bottom" class="octicon octicon-x">
          <path fill-rule="evenodd" d="M5.72 5.72a.75.75 0 011.06 0L12 10.94l5.22-5.22a.75.75 0 111.06 1.06L13.06 12l5.22 5.22a.75.75 0 11-1.06 1.06L12 13.06l-5.22 5.22a.75.75 0 01-1.06-1.06L10.94 12 5.72 6.78a.75.75 0 010-1.06z"></path>
        </svg>
      </button>
      <div class="Box-body border-0" role="presentation"></div>
    </div>
  </details-dialog>
</details>
<iframe title="File display" role="presentation" class="render-viewer" sandbox="allow-scripts allow-same-origin allow-top-navigation allow-popups" src="https://viewscreen.githubusercontent.com/markdown/mermaid?docs_host=https%3A%2F%2Fdocs.github.com&color_mode=light#27487e82-f6d6-4b8a-926f-6b1e5681ec7a" name="27487e82-f6d6-4b8a-926f-6b1e5681ec7a" data-content="{"data":"---\ntitle: Claim AI component diagram (C4 model)\n---\ngraph LR\n agent([\"Agent\"])\n user([\"User\"])\n\n subgraph \"Claim AI\"\n ada[\"Embedding&lt;br&gt;(ADA)\"]\n app[\"App&lt;br&gt;(Container App)\"]\n communication_services[\"Call &amp; SMS gateway&lt;br&gt;(Communication Services)\"]\n db[(\"Conversations and claims&lt;br&gt;(Cosmos DB / SQLite)\")]\n eventgrid[\"Broker&lt;br&gt;(Event Grid)\"]\n gpt[\"LLM&lt;br&gt;(GPT-4o)\"]\n queues[(\"Queues&lt;br&gt;(Azure Storage)\")]\n redis[(\"Cache&lt;br&gt;(Redis)\")]\n search[(\"RAG&lt;br&gt;(AI Search)\")]\n sounds[(\"Sounds&lt;br&gt;(Azure Storage)\")]\n sst[\"Speech-to-Text&lt;br&gt;(Cognitive Services)\"]\n translation[\"Translation&lt;br&gt;(Cognitive Services)\"]\n tts[\"Text-to-Speech&lt;br&gt;(Cognitive Services)\"]\n end\n\n app -- Respond with text --&gt; communication_services\n app -- Ask for translation --&gt; translation\n app -- Ask to transfer --&gt; communication_services\n app -- Few-shot training --&gt; search\n app -- Generate completion --&gt; gpt\n app -- Get cached data --&gt; redis\n app -- Save conversation --&gt; db\n app -- Send SMS report --&gt; communication_services\n app -. Watch .-&gt; queues\n\n communication_services -- Generate voice --&gt; tts\n communication_services -- Load sound --&gt; sounds\n communication_services -- Notifies --&gt; eventgrid\n communication_services -- Send SMS --&gt; user\n communication_services -- Transfer to --&gt; agent\n communication_services -- Transform voice --&gt; sst\n communication_services -. Send voice .-&gt; user\n\n eventgrid -- Push to --&gt; queues\n\n search -- Generate embeddings --&gt; ada\n\n user -- Call --&gt; communication_services\n"}"> </iframe>
Loading
---
title: Claim AI component diagram (C4 model)
---
graph LR
  agent(["Agent"])
  user(["User"])
Loading

序列图

<details class="details-reset details-overlay details-overlay-dark" style="display: contents">
  <summary role="button" aria-label="“打开”对话框" class="btn my-2 mr-2 p-0 d-inline-flex" aria-haspopup="dialog" _mstaria-label="154752" _msthash="353">
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="octicon m-2">
      <path fill-rule="evenodd" d="M3.72 3.72a.75.75 0 011.06 1.06L2.56 7h10.88l-2.22-2.22a.75.75 0 011.06-1.06l3.5 3.5a.75.75 0 010 1.06l-3.5 3.5a.75.75 0 11-1.06-1.06l2.22-2.22H2.56l2.22 2.22a.75.75 0 11-1.06 1.06l-3.5-3.5a.75.75 0 010-1.06l3.5-3.5z"></path>
    </svg>
  </summary>
  <details-dialog class="Box Box--overlay render-full-screen d-flex flex-column anim-fade-in fast" aria-label="mermaid rendered container" role="dialog" aria-modal="true" _msthidden="1" _mstaria-label="611598" _msthash="354">
    <div _msthidden="1">
      <button aria-label="Close dialog" data-close-dialog="" type="button" data-view-component="true" class="Link--muted btn-link position-absolute render-full-screen-close" _msthidden="A" _mstaria-label="177619" _msthash="355">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" style="display:inline-block;vertical-align:text-bottom" class="octicon octicon-x">
          <path fill-rule="evenodd" d="M5.72 5.72a.75.75 0 011.06 0L12 10.94l5.22-5.22a.75.75 0 111.06 1.06L13.06 12l5.22 5.22a.75.75 0 11-1.06 1.06L12 13.06l-5.22 5.22a.75.75 0 01-1.06-1.06L10.94 12 5.72 6.78a.75.75 0 010-1.06z"></path>
        </svg>
      </button>
      <div class="Box-body border-0" role="presentation"></div>
    </div>
  </details-dialog>
</details>
<iframe title="File display" role="presentation" class="render-viewer" sandbox="allow-scripts allow-same-origin allow-top-navigation allow-popups" src="https://viewscreen.githubusercontent.com/markdown/mermaid?docs_host=https%3A%2F%2Fdocs.github.com&color_mode=light#df9b02ec-4ae5-4580-97eb-9b61f67b96de" name="df9b02ec-4ae5-4580-97eb-9b61f67b96de" data-content="{"data":"sequenceDiagram\n autonumber\n\n actor Customer\n participant PSTN\n participant Text to Speech\n participant Speech to Text\n actor Human agent\n participant Event Grid\n participant Communication Services\n participant App\n participant Cosmos DB\n participant OpenAI GPT\n participant AI Search\n\n App-&gt;&gt;Event Grid: Subscribe to events\n Customer-&gt;&gt;PSTN: Initiate a call\n PSTN-&gt;&gt;Communication Services: Forward call\n Communication Services-&gt;&gt;Event Grid: New call event\n Event Grid-&gt;&gt;App: Send event to event URL (HTTP webhook)\n activate App\n App-&gt;&gt;Communication Services: Accept the call and give inbound URL\n deactivate App\n Communication Services-&gt;&gt;Speech to Text: Transform speech to text\n\n Communication Services-&gt;&gt;App: Send text to the inbound URL\n activate App\n alt First call\n App-&gt;&gt;Communication Services: Send static SSML text\n else Callback\n App-&gt;&gt;AI Search: Gather training data\n App-&gt;&gt;OpenAI GPT: Ask for a completion\n OpenAI GPT--&gt;&gt;App: Respond (HTTP/2 SSE)\n loop Over buffer\n loop Over multiple tools\n alt Is this a claim data update?\n App-&gt;&gt;Cosmos DB: Update claim data\n else Does the user want the human agent?\n App-&gt;&gt;Communication Services: Send static SSML text\n App-&gt;&gt;Communication Services: Transfer to a human\n Communication Services-&gt;&gt;Human agent: Call the phone number\n else Should we end the call?\n App-&gt;&gt;Communication Services: Send static SSML text\n App-&gt;&gt;Communication Services: End the call\n end\n end\n end\n App-&gt;&gt;Cosmos DB: Persist conversation\n end\n deactivate App\n Communication Services-&gt;&gt;PSTN: Send voice\n PSTN-&gt;&gt;Customer: Forward voice\n"}"> </iframe>
Loading
sequenceDiagram
    autonumber
Loading

部署

先决条件

首选使用 GitHub Codespaces 快速入门。环境将使用所有必需的工具自动设置。

在 macOS 中,使用 Homebrew 时,只需键入 .make brew

对于其他系统,请确保已安装以下内容:

然后,需要 Azure 资源:

  • 喜欢使用小写字母,并且不使用短划线以外的特殊字符(例如ccai-customer-a)
  • 与资源组同名
  • 启用系统托管标识
  • 从通信服务资源
  • 允许入站和出站通信
  • 启用语音(必需)和短信(可选)功能

现在,先决条件已配置(本地 + Azure),可以完成部署。

远程(在 Azure 上)

GitHub Actions 上提供了预构建的容器映像,它将用于在 Azure 上部署解决方案:

  • 来自分支的最新版本:ghcr.io/clemlesne/call-center-ai:main
  • 特定标签:(推荐)ghcr.io/clemlesne/call-center-ai:0.1.0

1. 创建 light 配置文件

本地配置文件名为 。安装脚本(包括 Makefile 和 Bicep)将使用它来配置 Azure 资源。config.yaml

使用以下内容填充文件(必须根据您的需要进行自定义):

# config.yaml
conversation:
  initiate:
    # Phone number the bot will transfer the call to if customer asks for a human agent
    agent_phone_number: "+33612345678"
    bot_company: Contoso
    bot_name: Amélie
    lang: {}

communication_services: # Phone number purshased from Communication Services phone_number: "+33612345678"

sms: {}

prompts: llm: {} tts: {}

2. 连接到 Azure 环境

az login

3. 运行部署自动化

make deploy name=my-rg-name
  • 等待部署完成
  • 名为trainings
  • 名为default

5. 获取日志

make logs name=my-rg-name

本地(在您的计算机上)

1. 创建完整的配置文件

提示

若要使用服务主体向 Azure 进行身份验证,还可以在文件中添加以下内容:.env

AZURE_CLIENT_ID=xxx
AZURE_CLIENT_SECRET=xxx
AZURE_TENANT_ID=xxx

提示

如果应用程序已部署在 Azure 上,则可以运行以将配置从 Azure Function App 复制到本地计算机。make name=my-rg-name sync-local-config

本地配置文件名为 :config.yaml

# config.yaml
resources:
  public_url: https://xxx.blob.core.windows.net/public

conversation: initiate: agent_phone_number: "+33612345678" bot_company: Contoso bot_name: Robert

communication_services: access_key: xxx call_queue_name: call-33612345678 endpoint: https://xxx.france.communication.azure.com phone_number: "+33612345678" post_queue_name: post-33612345678 recording_container_url: https://xxx.blob.core.windows.net/recordings resource_id: xxx sms_queue_name: sms-33612345678

cognitive_service: # Must be of type "AI services multi-service account" endpoint: https://xxx.cognitiveservices.azure.com

llm: fast: mode: azure_openai azure_openai: context: 16385 deployment: gpt-4o-mini-2024-07-18 endpoint: https://xxx.openai.azure.com model: gpt-4o-mini streaming: true slow: mode: azure_openai azure_openai: context: 128000 deployment: gpt-4o-2024-08-06 endpoint: https://xxx.openai.azure.com model: gpt-4o streaming: true

ai_search: access_key: xxx endpoint: https://xxx.search.windows.net index: trainings

ai_translation: access_key: xxx endpoint: https://xxx.cognitiveservices.azure.com

2. 运行部署自动化

make deploy-bicep deploy-post name=my-rg-name
  • 这将在没有 API 服务器的情况下部署 Azure 资源,从而允许您在本地测试机器人
  • 等待部署完成

3. 初始化本地函数配置

复制到 ,然后填写必填字段:local.example.settings.jsonlocal.settings.json

  • APPLICATIONINSIGHTS_CONNECTION_STRING作为 Application Insights 资源的连接字符串
  • AzureWebJobsStorage作为 Azure 存储帐户的连接字符串

4. 连接到 Azure Dev 隧道

重要

Tunnel 需要在单独的终端中运行,因为它需要一直运行

# Log in once
devtunnel login

# Start the tunnel make tunnel

<clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w" value="# Log in once devtunnel login

Start the tunnel

make tunnel" tabindex="0" role="button">

5. 使用代码快速迭代

注意

要覆盖特定的配置值,您可以使用环境变量���例如,要覆盖该值,您可以使用变量:llm.fast.endpointLLM__FAST__ENDPOINT

LLM__FAST__ENDPOINT=https://xxx.openai.azure.com

注意

此外,还可以使用脚本来测试应用程序,而无需打电话(= 没有通信服务)。使用以下命令运行脚本:local.py

python3 -m tests.local
make dev
  • 文件更改时会自动重新加载代码,无需重新启动服务器
  • API 服务器位于http://localhost:8080

高级用法

启用通话录音

默认情况下,通话录音处于关闭状态。要启用它:

  1. 在 Azure 存储帐户中创建新容器(即 ),如果您在 Azure 上部署了解决方案,则它已经完成recordings
  2. 将应用程序配置中的功能标志更新为recording_enabledtrue

使用 AI Search 添加我的自定义训练数据

训练数据存储在 AI Search 上,供机器人按需检索。

所需的索引架构:

字段名称 Type 检索 搜索 尺寸 矢量化器
Edm.String 是的 是的
上下文 Edm.String 是的 是的
created_at Edm.String 是的
document_synthesis Edm.String 是的 是的
file_path Edm.String 是的
身份证 Edm.String 是的
问题 Edm.String 是的 是的
向量 Collection(Edm.Single) 是的 1536 OpenAI ADA

用于填充索引的软件包含在 Synthetic RAG Index 存储库中

自定义语言

该机器人可以在多种语言中使用。它可以理解用户选择的语言。

请参阅 Text-to-Speech 服务支持的语言列表

# config.yaml
conversation:
  initiate:
    lang:
      default_short_code: fr-FR
      availables:
        - pronunciations_en: ["French", "FR", "France"]
          short_code: fr-FR
          voice: fr-FR-DeniseNeural
        - pronunciations_en: ["Chinese", "ZH", "China"]
          short_code: zh-CN
          voice: zh-CN-XiaoqiuNeural

如果生成并部署了 Azure 语音自定义神经语音 (CNV),请在语言配置上添加字段:custom_voice_endpoint_id

# config.yaml
conversation:
  initiate:
    lang:
      default_short_code: fr-FR
      availables:
        - pronunciations_en: ["French", "FR", "France"]
          short_code: fr-FR
          voice: xxx
          custom_voice_endpoint_id: xxx

自定义审核级别

为每个类别的内容安全定义了级别。分数越高,审核越严格,从 0 到 7。审核适用于所有机器人数据,包括网页和对话。在 Azure OpenAI 内容筛选器中配置它们。

自定义声明数据架构

完全支持数据架构的自定义。您可以根据需要添加或删除字段,具体取决于要求。

默认情况下,的 架构由以下部分组成:

  • caller_email (email)
  • caller_name (text)
  • caller_phone (phone_number)

验证值以确保数据格式提交到您的架构。它们可以是:

  • datetime
  • email
  • phone_number (E164格式)
  • text

最后,可以提供可选说明。描述必须简短且有意义,它将传递给 LLM。

入站呼叫的默认架构在配置中定义:

# config.yaml
conversation:
  default_initiate:
    claim:
      - name: additional_notes
        type: text
        # description: xxx
      - name: device_info
        type: text
        # description: xxx
      - name: incident_datetime
        type: datetime
        # description: xxx

通过在 API 调用中添加字段,可以为每个调用自定义声明架构。claimPOST /call

自定义呼叫目标

目标是机器人在通话期间将执行的操作的描述。它用于为 LLM 提供上下文。它应该简短、有意义,并且用英文书写。

此解决方案是特权,而不是覆盖 LLM 提示符。

入站呼叫的默认任务在配置中定义:

# config.yaml
conversation:
  initiate:
    task: |
      Help the customer with their insurance claim. Assistant requires data from the customer to fill the claim. The latest claim data will be given. Assistant role is not over until all the relevant data is gathered.

通过在 API 调用中添加字段,可以为每个调用自定义 Task。taskPOST /call

自定义对话

对话选项表示为功能。它们可以通过应用程序配置进行配置,而无需重新部署或重新启动应用程序。更新功能后,需要延迟 60 秒才能使更改生效。

|姓名 |描述 |类型 |默认 | |-|-|-| | |机器人应答的硬超��(以秒为单位)。| |180 元 | | |机器人应答的软超时(以秒为单位)。| |30 元 | | |回调的超时时间(以小时为单位)。| |72 元 | | |电话静音的超时时间(以秒为单位)。| |1 | | |是否开启通话录音。| |假 | | |是否使用较慢的 LLM 进行聊天。| |真 | | |语音识别的最大重试次数。| |2 |answer_hard_timeout_secintanswer_soft_timeout_secintcallback_timeout_hourintphone_silence_timeout_secintrecording_enabledboolslow_llm_for_chatboolvoice_recognition_retry_maxint

将 OpenAI 兼容模型用于 LLM

要使用与 OpenAI 补全 API 兼容的模型,您需要创建一个账户并获取以下信息:

  • API 密钥
  • 上下文窗口大小
  • 端点 URL
  • 型号名称
  • 流式处理功能

然后,在文件中添加以下内容:config.yaml

# config.yaml
llm:
  fast:
    mode: openai
    openai:
      context: 128000
      endpoint: https://api.openai.com
      model: gpt-4o-mini
      streaming: true
  slow:
    mode: openai
    openai:
      context: 128000
      endpoint: https://api.openai.com
      model: gpt-4o
      streaming: true

使用 Twilio 进行短信

要使用 Twilio 进行短信,您需要创建一个帐户并获取以下信息:

  • 帐户 SID
  • 身份验证令牌
  • 电话号码

然后,在文件中添加以下内容:config.yaml

# config.yaml
sms:
  mode: twilio
  twilio:
    account_sid: xxx
    auth_token: xxx
    phone_number: "+33612345678"

自定义提示

请注意,提示示例包含占位符。这些占位符将替换为具有相应数据的机器人。例如,在内部替换为 bot 名称。{xxx}{bot_name}

请务必用英文编写所有 TTS 提示。此语言用作对话翻译的枢轴语言。

# config.yaml
prompts:
  tts:
    hello_tpl: |
      Hello, I'm {bot_name}, from {bot_company}! I'm an IT support specialist.

      Here's how I work: when I'm working, you'll hear a little music; then, at the beep, it's your turn to speak. You can speak to me naturally, I'll understand.

      Examples:
      - "I've got a problem with my computer, it won't turn on".
      - "The external screen is flashing, I don't know why".

      What's your problem?
  llm:
    default_system_tpl: |
      Assistant is called {bot_name} and is in a call center for the company {bot_company} as an expert with 20 years of experience in IT service.

      # Context
      Today is {date}. Customer is calling from {phone_number}. Call center number is {bot_phone_number}.
    chat_system_tpl: |
      # Objective
      Provide internal IT support to employees. Assistant requires data from the employee to provide IT support. The assistant's role is not over until the issue is resolved or the request is fulfilled.

      # Rules
      - Answers in {default_lang}, even if the customer speaks another language
      - Cannot talk about any topic other than IT support
      - Is polite, helpful, and professional
      - Rephrase the employee's questions as statements and answer them
      - Use additional context to enhance the conversation with useful details
      - When the employee says a word and then spells out letters, this means that the word is written in the way the employee spelled it (e.g. "I work in Paris PARIS", "My name is John JOHN", "My email is Clemence CLEMENCE at gmail GMAIL dot com COM")
      - You work for {bot_company}, not someone else

      # Required employee data to be gathered by the assistant
      - Department
      - Description of the IT issue or request
      - Employee name
      - Location

      # General process to follow
      1. Gather information to know the employee's identity (e.g. name, department)
      2. Gather details about the IT issue or request to understand the situation (e.g. description, location)
      3. Provide initial troubleshooting steps or solutions
      4. Gather additional information if needed (e.g. error messages, screenshots)
      5. Be proactive and create reminders for follow-up or further assistance

      # Support status
      {claim}

      # Reminders
      {reminders}

优化响应延迟

延迟主要来自两件事:

  • 事实上,Azure 通信服务在转发音频的方式上是连续的(从技术上讲,它只处理文本,而不是音频,并且一旦转换了整个音频,就会等待指定的空白时间)
  • LLM,更具体地说是 API 调用和推断的第一个句子之间的延迟,可能会很长(因为句子一旦可用,就会一个接一个地发送),如果它产生幻觉并返回空答案,则甚至更长(这种情况经常发生,并且 applicatoipn 会重试调用)

从现在开始,您唯一能做的就是 LLM 部分。这可以通过 Azure 上的 PTU 或使用不太智能的模型来实现,例如(在最新版本上默认选择)。使用 Azure OpenAI 上的 PTU,在某些情况下可以将延迟除以 2。gpt-4o-mini

该应用程序本机连接到 Azure Application Insights,因此您可以监控响应时间并查看时间花费在哪里。这是识别瓶颈的良好开端。

如果您有任何优化响应延迟的想法,请随时提出问题或提出 PR。

Q&A (问答)

为什么不使用 LLM 框架?

在开发时,没有 LLM 框架可用于处理所有这些功能:具有多工具的流功能、可用性问题的备份模型、触发工具中的回调机制。因此,直接使用 OpenAI SDK,并实施了一些算法来处理可靠性。

About

在 API 调用中从 AI 代理发送电话呼叫。或者,直接从配置的电话号码呼叫机器人!Send a phone call from AI agent, in an API call. Or, directly call the bot from the configured phone number!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 85.1%
  • Bicep 7.5%
  • Jinja 5.1%
  • Makefile 1.9%
  • Dockerfile 0.4%