使用 LangChain 和 Chainlit 将外部 API 集成到聊天机器人应用程序

在本文中,我们将了解如何将聊天机器人应用程序与外部 API 集成。在之前关于构建聊天机器人应用程序的文章中,我们介绍了使用 LangChain 和 OpenAI 创建具有特定功能的聊天机器人的基础知识,以及如何使用 Chainlit 为我们的聊天机器人构建 Web 应用程序。如果你没看过之前的系列,我建议你查看以前的文章,了解详细的步骤。《使用 LangChain 和 OpenAI 构建自己的聊天机器人》《使用 Chainlit 和 LangChain 构建聊天机器人应用程序》

本文将重点介绍如何通过将我们的聊天机器人 Scoopsie (冰淇淋助手)连接到外部 API 来增强它。您可以将 API 视为一种在程序内和程序之间提取和共享数据的可访问方式。用户可以向 API 发出请求来获取或发送数据,API 会以一些信息进行响应。我们将 Scoopsie 连接到一个 API,以从虚构的冰淇淋店获取信息,并使用这些响应来提供信息。对于大多数聊天机器人应用程序,将自定义聊天机器人链接到外部 API 可能非常有用,在某些情况下甚至是必要的。

目前我们使用 LLMChain 查询 OpenAI 的 GPT-3.5 模型来回答用户的冰淇淋相关查询:chatbot.py

python 复制代码
import chainlit as cl  
from langchain_openai import OpenAI  
from langchain.chains import LLMChain  
from prompts import ice_cream_assistant_prompt_template  
from langchain.memory.buffer import ConversationBufferMemory  
  
from dotenv import load_dotenv  
  
load_dotenv()  
  
@cl.on_chat_start  
def query_llm():  
	llm = OpenAI(model='gpt-3.5-turbo-instruct', temperature=0)  
	conversation_memory = ConversationBufferMemory(memory_key="chat_history", max_len=50, return_messages=True)  
	llm_chain = LLMChain(llm=llm, prompt=ice_cream_assistant_prompt_template, memory=conversation_memory)  
	cl.user_session.set("llm_chain", llm_chain)  
  
  
@cl.on_message  
async def query_llm(message: cl.Message):  
	llm_chain = cl.user_session.get("llm_chain")  
	response = await llm_chain.acall(message.content, callbacks=[cl.AsyncLangchainCallbackHandler()])  
	await cl.Message(response["text"]).send()

创建虚构的商店 API

我们将首先创建一个 API 来连接到 Scoopsie。此 API 表示一个虚构的冰淇淋店,允许用户检索商店的菜单以及其他信息,例如自定义、用户评论和特别优惠。我们将利用 Flask(一个用于 Web 开发的 Python 框架)在不同的 API 端点中对上述信息进行编码。这些包括:

  1. /menu:用于检索风味和浇头菜单的端点。GET
  2. /customizations:用于检索自定义项的端点GET
  3. /special-offers:用于检索特别优惠的端点。GET
  4. /user-reviews:用于检索用户评论的端点。GET

为了让 Scoopsie 专注于提供信息,而不是处理交易或处理订单,我们将当前的范围限制在这些信息端点上。但是,您可以扩展此 API 以包含其他端点,例如允许用户提交订单的 POST 端点或其他 GET 端点。

第 1 步

让我们创建一个名为 Python 脚本,用于存储静态数据,如菜单、特别优惠、客户评论和自定义选项。以下是我们如何构建它:data_store.py

python 复制代码
# Example menu, special offers, customer reviews, and customizations  
menu = {  
	"flavors": [  
		{"flavorName": "Strawberry", "count": 50},  
		{"flavorName": "Chocolate", "count": 75}  
		],  
		"toppings": [  
		{"toppingName": "Hot Fudge", "count": 50},  
		{"toppingName": "Sprinkles", "count": 2000},  
		{"toppingName": "Whipped Cream", "count": 50}  
	]  
}  
special_offers = {  
	"offers": [  
		{"offerName": "Two for Tuesday", "details": "Buy one get one free on all ice cream flavors every Tuesday."},  
		{"offerName": "Winter Wonderland Discount", "details": "25% off on all orders above $20 during the winter season."}  
	]  
}  
customer_reviews = {  
	"reviews": [  
		{"userName": "andrew_1", "rating": 5, "comment": "Loved the chocolate flavor!"},  
		{"userName": "john", "rating": 4, "comment": "Great place, but always crowded."},  
		{"userName": "allison", "rating": 5, "comment": "Love the ice-creams and Scoopsie is super helpful!"}  
	]  
}  
customizations = {  
	"options": [  
		{"customizationName": "Sugar-Free", "details": "Available for most flavors."},  
		{"customizationName": "Extra Toppings", "details": "Choose as many toppings as you want for an extra $5!"}  
	]  
}

您可以调整上述脚本以更好地满足您的特定需求。这些示例显示了每个类别的可能属性。在实际应用中,将这些数据存储在数据库中进行动态检索更为合适。

步骤 2

让我们在一个名为 ice_cream_store_app.py 的文件中设置我们的 Flask 应用程序,我们将从data_store.py中导入数据。我们可以从导入所需的库并初始化 Flask 应用程序开始:

python 复制代码
from flask import Flask, jsonify  
from data_store import menu, special_offers, customer_reviews, customizations  
  
app = Flask(__name__)

步骤 3

现在,让我们配置 API 端点函数。在 Flask 中,由于 Flask 的路由机制,这些函数直接响应 Web 请求,而不需要显式参数。

以下是端点函数:

python 复制代码
@app.route('/menu', methods=['GET'])  
def get_menu():  
	"""  
	Retrieves the menu data.  
	Returns:  
	A tuple containing the menu data as JSON and the HTTP status code.  
	"""  
	return jsonify(menu), 200  
  
@app.route('/special-offers', methods=['GET'])  
def get_special_offers():  
	"""  
	Retrieves the special offers data.  
	Returns:  
	A tuple containing the special offers data as JSON and the HTTP status code.  
	"""  
	return jsonify(special_offers), 200  
  
@app.route('/customer-reviews', methods=['GET'])  
def get_customer_reviews():  
	"""  
	Retrieves customer reviews data.  
	Returns:  
	A tuple containing the customer reviews data as JSON and the HTTP status code.  
	"""  
	return jsonify(customer_reviews), 200  
  
@app.route('/customizations', methods=['GET'])  
def get_customizations():  
	"""  
	Retrieves the customizations data.  
	Returns:  
	A tuple containing the customizations data as JSON and the HTTP status code.  
	"""  
	return jsonify(customizations), 200

对于上面的每个函数,用于将 Python 字典转换为 JSON 格式,然后返回成功查询的状态代码。200

步骤 4

最后,让我们将以下代码添加到我们的脚本中:ice_cream_store_app.py

python 复制代码
if __name__ == '__main__':  
	app.run(debug=True)

可以通过在终端中运行以下命令来启动 API:

python 复制代码
python ice_cream_store_app.py

应用程序运行后,您可以使用 Postman 等工具或使用 Web 浏览器查看特定端点

Ice-Cream Shop API 端点

LangChain的APIChain解释

LangChain中的链通过将复杂任务作为一系列更简单的连接操作来执行,从而简化了复杂的任务。这些链通常包含 LLM、PromptTemplates、输出解析器或外部第三方 API 等元素,我们将在本教程中重点介绍这些元素。我在关于该系列的第一篇文章中更详细地介绍了 LangChain 的 Chain 功能,您可以在此处访问。

以前,我们利用 LangChain 的 LLMChain 与 LLM 进行直接交互。现在,为了扩展 Scoopsie 与外部 API 交互的功能,我们将使用 APIChain。APIChain是一个LangChain模块,旨在将用户输入格式化为API请求。这将使我们的聊天机器人能够向外部 API 发送请求并接收来自外部 API 的响应,从而扩展其功能。

APIChain 可以配置为处理不同的 HTTP 方法(GET、POST、PUT、DELETE 等)、设置请求头并管理请求的正文。它还支持 JSON 有效负载,这些负载通常用于 RESTful API 通信。

从LangChain设置API Chain

第 1 步

我们首先将LangChain的APIChain模块以及其他必需的模块导入到我们的文件中。此脚本将托管我们所有的应用程序逻辑。您可以设置必要的环境变量,例如脚本中的 ,这些变量可由 python 库访问。chatbot.py OPENAI_API_KEY .env dotenv

python 复制代码
import chainlit as cl  
from langchain_openai import OpenAI  
from langchain.chains import LLMChain, APIChain  
from langchain.memory.buffer import ConversationBufferMemory  
from dotenv import load_dotenv  
  
load_dotenv()

步骤 2

对于 APIChain 类,我们需要字符串格式的外部 API 文档来访问端点详细信息。本文档应概述 API 的端点、方法、参数和预期响应。这有助于 LLM 制定 API 请求并解析响应。将此信息定义为字典,然后将其转换为字符串以供以后使用会很有帮助。

让我们创建一个新的 python 脚本,该脚本名为虚构商店的 API,并添加文档:api_docs.py

python 复制代码
import json  
  
scoopsie_api_docs = {  
	"base_url": "<http://127.0.0.1:5000/>",  
	"endpoints": {  
		"/menu": {  
			"method": "GET",  
			"description": "Retrieve the menu of flavors and customizations.",  
			"parameters": None,  
			"response": {  
				"description": "A JSON object containing available flavors and toppings along with their counts.",  
				"content_type": "application/json"  
			}  
		},  
		"/special-offers": {  
			"method": "GET",  
			"description": "Retrieve current special offers and discounts.",  
			"parameters": None,  
			"response": {  
				"description": "A JSON object listing the current special offers and discounts.",  
				"content_type": "application/json"  
			}  
		},  
		"/customer-reviews": {  
			"method": "GET",  
			"description": "Retrieve customer reviews for the ice cream store.",  
			"parameters": None,  
			"response": {  
				"description": "A JSON object containing customer reviews, ratings, and comments.",  
				"content_type": "application/json"  
			}  
		},  
		"/customizations": {  
			"method": "GET",  
			"description": "Retrieve available ice cream customizations.",  
			"parameters": None,  
			"response": {  
				"description": "A JSON object listing available customizations like toppings and sugar-free options.",  
				"content_type": "application/json"  
			}  
		}  
	}  
}  
  
# Convert the dictionary to a JSON string  
scoopsie_api_docs = json.dumps(scoopsie_api_docs, indent=2)

我已将自定义 API 的文档格式化为名为 的 Python 字典。此字典包括 API 的基本 URL,并在密钥下详细说明了我们的四个端点。每个端点都列出了其 HTTP 方法(全部为我们提供)、简明描述、接受的参数(这些端点没有)和预期的响应格式(包含相关数据的 JSON 对象)。然后,将字典转换为 JSON 字符串,使用 缩进 2 个空格以提高可读性。scoopsie_api_docs endpoints GET json.dumps

让我们在脚本中导入此 API 文档:chatbot.py

python 复制代码
from api_docs import scoopsie_api_docs

步骤 3

APIChain 需要两个提示:一个用于选择正确的 API 端点,另一个用于基于该端点创建对用户查询的简洁回复。这些提示具有默认值,但是,我们将创建自己的提示以确保个性化交互。我们可以在文件中添加以下新提示:prompts.py

python 复制代码
api_url_template = """  
Given the following API Documentation for Scoopsie's official  
ice cream store API: {api_docs}  
Your task is to construct the most efficient API URL to answer  
the user's question, ensuring the  
call is optimized to include only necessary information.  
Question: {question}  
API URL:  
"""  
api_url_prompt = PromptTemplate(input_variables=['api_docs', 'question'],  
template=api_url_template)  
  
api_response_template = """"  
With the API Documentation for Scoopsie's official API: {api_docs}  
and the specific user question: {question} in mind,  
and given this API URL: {api_url} for querying, here is the  
response from Scoopsie's API: {api_response}.  
Please provide a summary that directly addresses the user's question,  
omitting technical details like response format, and  
focusing on delivering the answer with clarity and conciseness,  
as if Scoopsie itself is providing this information.  
Summary:  
"""  
api_response_prompt = PromptTemplate(input_variables=['api_docs',  
'question',  
'api_url',  
'api_response'],  
template=api_response_template)

在这里,使用提供的 API 文档 (api_url_prompt) 为查询生成确切的 API URL。在使用 api_url_prompt 识别正确的端点后,APIChain 使用 api_response_prompt来汇总 API 的响应来回答用户的查询。让我们在脚本中导入这些提示:api_docs api_url_prompt api_response_prompt chatbot.py

python 复制代码
from prompts import api_response_prompt, api_url_prompt

步骤 4

让我们设置 APIChain 以连接我们之前创建的虚构冰淇淋店的 API。LangChain 的 APIChain 模块提供了该方法,它允许我们从 LLM 和之前定义的 api 文档加载链。我们将继续将 OpenAI 的模型用于我们的 LLM。from_llm_and_api_docs() gpt-3.5-turbo-instruct

python 复制代码
# Initialize your LLM  
llm = OpenAI(model='gpt-3.5-turbo-instruct', temperature=0)  
  
api_chain = APIChain.from_llm_and_api_docs(  
	llm=llm,  
	api_docs=scoopsie_api_docs,  
	api_url_prompt=api_url_prompt,  
	api_response_prompt=api_response_prompt,  
	verbose=True,  
	limit_to_domains=["<http://127.0.0.1:5000/>"])

上面代码中的参数限制了 APIChain 可以访问的域。根据LangChain的官方文档,默认值为空元组。这意味着默认情况下不允许任何域。根据设计,这将在实例化时引发错误。如果要默认允许所有域,则可以通过。但是,出于安全原因,不建议这样做,因为它允许恶意用户向任意 URL(包括可从服务器访问的内部 API)发出请求。为了允许我们商店的 API,我们可以指定其 URL;这将确保我们的链条在受控环境中运行。limit_to_domains``None

步骤 5

在前面的教程中,我们设置了一个 LLMChain 来处理与冰淇淋相关的一般查询。我们仍然希望保留此功能,因为 Scoopsie 是一个有用的对话伙伴,同时还通过 APIChain 整合了对我们虚构商店菜单和自定义选项的访问。为了组合这些功能,我们将使用 llm_chain 用于常规查询和 api_chain 用于访问商店的 API。这需要调整我们的 Chainlit 设置,从用户会话开始就支持多个链。以下是我们如何调整装饰器:@cl.on_chat_start

python 复制代码
@cl.on_chat_start  
def setup_multiple_chains():  
	llm = OpenAI(model='gpt-3.5-turbo-instruct', temperature=0)  
	conversation_memory = ConversationBufferMemory(memory_key="chat_history", max_len=200, return_messages=True)  
	llm_chain = LLMChain(llm=llm, prompt=ice_cream_assistant_prompt, memory=conversation_memory)  
	cl.user_session.set("llm_chain", llm_chain)  
	  
	api_chain = APIChain.from_llm_and_api_docs(llm=llm, api_docs=scoopsie_api_docs, api_url_prompt=api_url_prompt, api_response_prompt=api_response_prompt, verbose=True, limit_to_domains=["<http://127.0.0.1:5000/>"]  
	)  
	cl.user_session.set("api_chain", api_chain)

在启动新的用户会话时,此设置会实例化 llm_chainapi_chain,确保 Scoopsie 能够处理各种查询。每条链都存储在用户会话中,以便于检索。

步骤 6

现在,让我们定义装饰器周围的包装函数:@cl.on_message

python 复制代码
@cl.on_message  
async def handle_message(message: cl.Message):  
	user_message = message.content.lower()  
	llm_chain = cl.user_session.get("llm_chain")  
	api_chain = cl.user_session.get("api_chain")  
	  
	if any(keyword in user_message for keyword in ["menu", "customization",  
	"offer", "review"]):  
		# If any of the keywords are in the user_message, use api_chain  
		response = await api_chain.acall(user_message,  
		callbacks=[cl.AsyncLangchainCallbackHandler()])  
	else:  
		# Default to llm_chain for handling general queries  
		response = await llm_chain.acall(user_message,  
		callbacks=[cl.AsyncLangchainCallbackHandler()])  
	response_key = "output" if "output" in response else "text"  
	await cl.Message(response.get(response_key, "")).send()

在此设置中,我们检索 and 对象。如果用户消息包含反映我们虚构商店 API 端点的关键字,则应用程序将触发 APIChain。如果不是,我们假设这是一个与冰淇淋相关的一般查询,并触发 LLMChain。这是一个简单的用例,但对于更复杂的用例,您可能需要编写更复杂的逻辑来确保触发正确的链。有关 Chainlit 装饰器以及如何有效利用它们的更多详细信息。llm_chain``api_chain

步骤 7

现在我们的应用程序代码已准备就绪,我们可以启动我们的聊天机器人了。在项目目录中打开终端并运行以下命令:

python 复制代码
chainlit run chatbot.py -w --port 8000

您可以通过在 Web 浏览器中导航到 http://localhost:8000 来访问聊天机器人。

演示

Scoopsie 的应用程序界面现已准备就绪!以下是展示聊天机器人运行情况的演示:

Scoopsie 聊天机器人演示:交互式冰淇淋助手在行动

结束语

我们已经成功地为一家虚构的冰淇淋店构建了一个 API,并将其与我们的聊天机器人集成。如上所述,您可以使用 Chainlit 访问聊天机器人的 Web 应用程序,其中可以访问常规查询和虚构商店的 API 端点。

相关推荐
阿里云云原生24 分钟前
山石网科×阿里云通义灵码,开启研发“AI智造”新时代
网络·人工智能·阿里云·ai程序员·ai程序员体验官
diemeng11191 小时前
AI前端开发技能变革时代:效率与创新的新范式
前端·人工智能
有Li1 小时前
跨中心模型自适应牙齿分割|文献速递-医学影像人工智能进展
人工智能
牧歌悠悠6 小时前
【深度学习】Unet的基础介绍
人工智能·深度学习·u-net
坚毅不拔的柠檬柠檬6 小时前
AI革命下的多元生态:DeepSeek、ChatGPT、XAI、文心一言与通义千问的行业渗透与场景重构
人工智能·chatgpt·文心一言
坚毅不拔的柠檬柠檬6 小时前
2025:人工智能重构人类文明的新纪元
人工智能·重构
jixunwulian6 小时前
DeepSeek赋能AI边缘计算网关,开启智能新时代!
人工智能·边缘计算
Archie_IT7 小时前
DeepSeek R1/V3满血版——在线体验与API调用
人工智能·深度学习·ai·自然语言处理
大数据追光猿7 小时前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
灵感素材坊8 小时前
解锁音乐创作新技能:AI音乐网站的正确使用方式
人工智能·经验分享·音视频