paint-brush
如何构建人工智能搜索驱动的个人助理应用程序经过@lablab
6,036 讀數
6,036 讀數

如何构建人工智能搜索驱动的个人助理应用程序

经过 lablab.ai hackathons28m2023/07/04
Read on Terminal Reader

太長; 讀書

Anthropic 是一家专注于开发先进人工智能系统的研究组织。他们的最新作品 Claude 是下一代人工智能助手,旨在提供帮助、诚实且无害。 LangChain是一个构建端到端语言模型应用程序的工具。它提供了一个强大的框架,可以简化创建、管理和部署语言学习模型的过程。
featured image - 如何构建人工智能搜索驱动的个人助理应用程序
lablab.ai hackathons HackerNoon profile picture
0-item
1-item

在本文中,我们将向您展示如何结合两种技术( LangChainAnthropic )并创建一个基于搜索的个人助理。


我们的黑客马拉松参与者正在创造越来越多的人工智能产品。开发人员的下一个机会是我们与Google Cloud Vertex AI联合举办的黑客马拉松,每位参与者都有机会使用Google Cloud的最新技术创建自己的AI 应用程序。在这里,我们将讨论人工智能的一项日益重要的应用:搜索引擎



它是什么?

支持搜索的个人助理是一种数字助理,它使用搜索引擎技术帮助用户完成查找信息、预订、设置提醒和发送消息等任务。这些助手使用搜索算法收集和分析来自各种来源的数据,以有用且简洁的方式将其呈现给用户。


搜索驱动的个人助理的典型例子是Google AssistantSiriAlexaCortana 。这些助手有效地利用其搜索功能来提供准确且相关的信息、完成任务并在与用户交互时改进其响应。


介绍 Anthropic 的克劳德

Anthropic 是一家专注于开发先进人工智能系统的研究组织。他们的最新作品 Claude 是下一代人工智能助手,旨在提供帮助、诚实且无害。这种尖端模型确保了各种任务的高度可靠性和可预测性。


克劳德的主要特点包括:

  • 多功能会话和文本处理功能

  • 将维护用户安全和隐私作为首要任务


Claude 的主要用例是:

  • 总结

  • 搜索

  • 创意和协作写作

  • 问答

  • 编码协助


这些功能使 Claude 成为适用于各种应用程序的理想人工智能工具,为不同领域的用户提供支持。

浪链简介

LangChain是一个用于构建端到端语言模型应用程序的多功能工具。它提供了一个强大的框架,可以简化创建、管理和部署语言学习模型 (LLM) 的过程。法学硕士是先进的人工智能模型,旨在理解、生成和操作各种语言和任务的类人文本。


浪链的主要特点包括:


  • 有效管理法学硕士的提示

  • 能够为复杂的工作流程创建任务链

  • 向人工智能添加状态,使其能够记住之前交互的信息


这些功能使 LangChain 成为一个强大且用户友好的平台,可以在不同的应用程序中发挥语言模型的潜力。

先决条件

  • Python基础知识
  • Typescipt 和/或 React 的基本知识
  • 访问 Anthropic 的 Claude API
  • 访问 SerpApi 的 Web 搜索 API

大纲

  1. 初始化项目
  2. 使用 Claude 和 LangCHain 构建 AI 助手应用程序的前端
  3. 编写项目文件
  4. 测试AI助手应用程序

讨论

初始化项目

app.py(Flask 应用程序入口点)🐍

  1. 安装 Flask :首先,请确保您的环境中安装了 Flask。您可以使用pip执行此操作:

     pip install Flask


  2. 创建新目录:为您的项目创建一个新目录并导航到它:

     mkdir claude-langchain cd claude-langchain


  3. 设置虚拟环境(可选) :处理 Python 项目时使用虚拟环境是一个很好的做法。您可以使用venv或您选择的任何其他工具创建一个:

     python -m venv venv source venv/bin/activate (Linux/Mac) venv\Scripts\activate (Windows)


  4. 创建一个main.py文件:创建一个main.py文件来编写 Flask 应用程序代码:

     touch app.py # Linux/Mac echo.>app.py # Windows


  5. 编写 Flask 应用程序代码:在您喜欢的代码编辑器中打开main.py文件并添加以下代码:

     from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.run()


  6. 运行 Flask 应用程序:保存main.py文件并在终端/命令提示符中运行以下命令:

     python main.py


  7. 打开浏览器: 打开您首选的网络浏览器并导航至http://127.0.0.1:5000/ 。您应该看到“Hello, World!”显示在网页上。


就是这样!您已成功初始化 Flask 项目并创建了一个简单的应用程序。

.env 🌏

  1. 安装 python-dotenv 和 langchain :为了使用.env文件轻松管理环境变量,我们将使用python-dotenv包。同时,我们也安装langchain 。使用pip安装这两个包:

     pip install python-dotenv langchain


  2. 创建.env文件:在项目根目录中创建.env文件:

     touch .env # Linux/Mac echo.>.env # Windows


  3. 添加环境变量:在您喜欢的代码编辑器中打开.env文件并添加环境变量。每个变量都应占新行,格式为 KEY=VALUE:

     ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxx SERPAPI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    请注意,您需要拥有Anthropic 的 Claude模型和SerpAPI的网络搜索服务的 API 密钥。


  4. 加载环境变量:修改main.py文件以使用python-dotenv.env文件加载环境变量。更新您的main.py ,如下所示:

     import os from flask import Flask from dotenv import load_dotenv load_dotenv() app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.run()


  5. 忽略版本控制中的.env文件:重要的是不要在版本控制中共享敏感信息(例如密钥)。如果您使用的是 Git,请将以下行添加到您的.gitignore文件中(如果没有,请创建一个):

     .env


现在,您的 Flask 项目已设置为使用.env文件中的环境变量。您可以根据需要添加更多变量并使用os.environ.get('KEY')访问它们。请记住将.env文件保持私有,并且切勿将其提交给版本控制。

使用 Claude 和 LangChain 构建 AI 助手应用程序的前端

本教程专为对 Node.js、npm、React 和 Typescript 有基本了解的中级用户而设计。我们将使用包含这些技术的堆栈以及用于样式设置的 Tailwind CSS。选择该堆栈是因为其稳健性、多功能性以及社区对这些技术的强大支持。此外,我们将集成 Anthropic 的 Claude 模型和 LangChain,这两种强大的人工智能技术将使我们的应用程序能够生成准确的、类似人类的文本响应。

安装 Node.js 和 NPM

  1. 官方网站下载适合您的操作系统的 Node.js 安装程序。

  2. 按照安装提示安装 Node.js 和 npm。建议大多数用户使用 LTS(长期支持)版本。

  3. 安装后,通过从终端检查 Node.js 和 npm 的版本来验证安装:

    节点-v npm -v

设置项目环境

安装创建反应应用程序

Create React App (CRA)是一个命令行实用程序,可帮助我们创建新的 React.js 应用程序。我们将通过 npm 全局安装它:

 npm install -g create-react-app
使用 Typescript 创建新的 React 项目

我们将使用 CRA 和 Typescript 模板来创建一个名为ai-assistant-claude的新项目。

 npx create-react-app ai-assistant-claude --template typescript

此命令在我们的当前目录中创建一个名为ai-assistant-claude的新目录,其中包含一个支持 Typescript 的新 React 应用程序。

集成 TailwindCSS

安装 TailwindCSS

本教程中遵循的步骤基于官方 Tailwind CSS 文档。请参阅这些文档以获取更多最新说明。

我们将首先安装 TailwindCSS 并初始化项目中的库:

 npm install -D tailwindcss npx tailwindcss init
配置模板路径

接下来,我们将模板路径添加到tailwind.config.js文件中来配置它们。 ++表示您要添加的行:

 /** @type {import('tailwindcss').Config} */ module.exports = { -- content: [], ++ content: [ ++ "./src/**/*.{js,jsx,ts,tsx}", ++ ], theme: { extend: {}, }, plugins: [], }
添加 Tailwind 指令

最后,我们将 Tailwind 每个层的@tailwind指令添加到./src/index.css文件中:

 @tailwind base; @tailwind components; @tailwind utilities;

瞧! Tailwind CSS 现已集成到我们的项目中。

安装所需的库

在继续进行编码部分之前,让我们通过安装必要的库(例如fontawesomereact-markdownaxiosreact-hook-form来完成准备工作。

为图标安装 FontAwesome
 npm i --save @fortawesome/fontawesome-svg-core npm install --save @fortawesome/free-solid-svg-icons npm install --save @fortawesome/react-fontawesome
安装 React Markdown 以渲染 Markdown 内容
npm install --save react-markdown

完成这些步骤后,您的项目就已经设置好了所有必要的工具和库。接下来,我们将开始构建 AI 助手应用程序,该应用程序使用 Anthropic 的 Claude API 和 LangChain 来生成准确且类似人类的文本响应。

故障排除

如果您在安装或设置过程中遇到任何问题,以下是一些常见的解决方案:

  • 对于与 Node.js 或 npm 相关的问题,请尝试重新安装它们或查看官方Node.jsnpm文档。
  • 如果您在使用 Create React App 时遇到问题,请查阅CRA 文档以获取帮助。
  • 有关 Tailwind CSS 问题,请参阅Tailwind CSS 文档


对于任何其他问题,请查阅相应库的文档或将您的问题发布到 StackOverflow 或相关 GitHub 存储库上。

编写项目文件

在本节中,我们将返回到之前初始化的 Flask 应用程序并添加新的端点,例如/ask/search 。这些将作为我们简单聊天和高级聊天功能(后者由 Google 搜索结果提供支持)的端点。

让我们从导入必要的模块开始:


 from flask import Flask, jsonify, request from dotenv import load_dotenv from langchain.chat_models import ChatAnthropic from langchain.chains import ConversationChain from langchain.agents import Tool from langchain.agents import AgentType from langchain.utilities import SerpAPIWrapper from langchain.agents import initialize_agent from langchain.memory import ConversationBufferMemory from langchain.prompts.chat import ( ChatPromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate, ) load_dotenv() app = Flask(__name__)

上面的部分导入了所有必需的包并初始化了我们的 Flask 应用程序。

开发后端

创建基本端点

我们将首先创建一个基本端点( / )来测试我们的服务器是否正常运行:

 @app.route('/') def hello_world(): return 'Hello, World!'

通过访问根 URL,我们应该收到响应“Hello, World!”,表明我们的服务器正在按预期运行。

创建/ask端点

该端点处理我们应用程序的基本聊天功能的消息。它从请求中读取 JSON 数据,处理消息,并使用 Anthropic 的 Claude 模型和 LangChain 生成响应。

 @app.route('/ask', methods=['POST']) def ask_assistant(): # The code for /ask endpoint goes here


从请求中提取消息

首先,我们需要检查是否提供了任何数据并从中提取消息。

 data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message")


生成响应

以下代码段使用 LangChain 的ChatAnthropic()模型生成聊天响应,并使用ChatPromptTemplate来构建我们的对话。对话历史记录使用ConversationBufferMemory存储。


 llm = ChatAnthropic() input = "" message_list = [] for message in messages: if message['role'] == 'user': message_list.append( HumanMessagePromptTemplate.from_template(message['content']) ) input = message['content'] elif message['role'] == 'assistant': message_list.append( AIMessagePromptTemplate.from_template(message['content']) ) # Adding SystemMessagePromptTemplate at the beginning of the message_list message_list.insert(0, SystemMessagePromptTemplate.from_template( "The following is a friendly conversation between a human and an AI. The AI is talkative and " "provides lots of specific details from its context. The AI will respond with plain string, replace new lines with \\n which can be easily parsed and stored into JSON, and will try to keep the responses condensed, in as few lines as possible." )) message_list.insert(1, MessagesPlaceholder(variable_name="history")) message_list.insert(-1, HumanMessagePromptTemplate.from_template("{input}")) prompt = ChatPromptTemplate.from_messages(message_list) memory = ConversationBufferMemory(return_messages=True) conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm) result = conversation.predict(input=input)

发送响应

生成响应后,我们替换结果中的换行符并将其作为 JSON 对象返回。

 print(result) return jsonify({"status": "success", "message": result})
创建/search端点

/search端点与/ask类似,但包含搜索功能以提供更详细的响应。我们使用SerpAPIWrapper来添加此功能。

 @app.route('/search', methods=['POST']) def search_with_assistant(): data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message") llm = ChatAnthropic() # Get the last message with 'user' role user_messages = [msg for msg in messages if msg['role'] == 'user'] last_user_message = user_messages[-1] if user_messages else None # If there is no user message, return an error response if not last_user_message: return jsonify({"error": "No user message found"}), 400 input = last_user_message['content'] search = SerpAPIWrapper() tools = [ Tool( name = "Current Search", func=search.run, description="useful for when you need to answer questions about current events or the current state of the world" ), ] chat_history = MessagesPlaceholder(variable_name="chat_history") memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) agent_chain = initialize_agent( tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True, memory=memory, agent_kwargs = { "memory_prompts": [chat_history], "input_variables": ["input", "agent_scratchpad", "chat_history"] } ) result = agent_chain.run(input=input) print(result) return jsonify({"status": "success", "message": result})


运行 Flask 应用程序

最后,我们添加标准样板来运行Flask 应用程序。

 if __name__ == '__main__': app.run()
测试后端

如果一切顺利,这是我们最终的后端代码。

 from flask import Flask, jsonify, request from dotenv import load_dotenv from langchain.chat_models import ChatAnthropic from langchain.chains import ConversationChain from langchain.agents import Tool from langchain.agents import AgentType from langchain.utilities import SerpAPIWrapper from langchain.agents import initialize_agent from langchain.memory import ConversationBufferMemory from langchain.prompts.chat import ( ChatPromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate, ) load_dotenv() app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' @app.route('/ask', methods=['POST']) def ask_assistant(): data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message") llm = ChatAnthropic() input = "" message_list = [] for message in messages: if message['role'] == 'user': message_list.append( HumanMessagePromptTemplate.from_template(message['content']) ) input = message['content'] elif message['role'] == 'assistant': message_list.append( AIMessagePromptTemplate.from_template(message['content']) ) # Adding SystemMessagePromptTemplate at the beginning of the message_list message_list.insert(0, SystemMessagePromptTemplate.from_template( "The following is a friendly conversation between a human and an AI. The AI is talkative and " "provides lots of specific details from its context. The AI will respond with plain string, replace new lines with \\n which can be easily parsed and stored into JSON, and will try to keep the responses condensed, in as few lines as possible." )) message_list.insert(1, MessagesPlaceholder(variable_name="history")) message_list.insert(-1, HumanMessagePromptTemplate.from_template("{input}")) prompt = ChatPromptTemplate.from_messages(message_list) memory = ConversationBufferMemory(return_messages=True) conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm) result = conversation.predict(input=input) print(result) return jsonify({"status": "success", "message": result}) @app.route('/search', methods=['POST']) def search_with_assistant(): data = request.get_json() if not data: return jsonify({"error": "No data provided"}), 400 messages = data.get("message") llm = ChatAnthropic() # Get the last message with 'user' role user_messages = [msg for msg in messages if msg['role'] == 'user'] last_user_message = user_messages[-1] if user_messages else None # If there is no user message, return an error response if not last_user_message: return jsonify({"error": "No user message found"}), 400 input = last_user_message['content'] search = SerpAPIWrapper() tools = [ Tool( name = "Current Search", func=search.run, description="useful for when you need to answer questions about current events or the current state of the world" ), ] chat_history = MessagesPlaceholder(variable_name="chat_history") memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) agent_chain = initialize_agent( tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True, memory=memory, agent_kwargs = { "memory_prompts": [chat_history], "input_variables": ["input", "agent_scratchpad", "chat_history"] } ) result = agent_chain.run(input=input) print(result) return jsonify({"status": "success", "message": result}) if __name__ == '__main__': app.run()


现在,让我们测试我们的应用程序。使用此命令运行后端应用程序,另请确保我们的虚拟环境已激活。

 flask run


如果我们的终端返回此输出,我们就会知道一切都会好起来。


话不多说,让我们测试我们的两个端点: /ask/search 。为了区分两者,让我们向它们发送相似的有效负载。打开您的 REST API 测试和文档软件,或者仅使用 cURL。但在本教程中,我将使用Insomnia


我们首先使用以下有效负载调用/ask端点。假设我询问了电子游戏“ 塞尔达传说:荒野之息”的续集。它会错误地回答。这是可以预料的,因为该模型的训练截至 2021 年底,目前还没有关于续集的公告。


/search端点怎么样?如果您注意到我们之前的代码,就会发现该端点是使用更复杂的链来处理的,该链利用了代理。


通过使用代理,我们可以通过为人工智能提供更多的工具来赋予人工智能更多的决策权,而不仅仅是它自己的模型,正如我们已经证明的那样,它有自己的缺陷。


为了演示/search端点的工作原理,让我们使用与之前相同的负载来调用它。


这次,效果很好!它在幕后是如何工作的?让我们看看终端中的输出。

有趣的是,这一次人工智能模型并没有立即回答,而是似乎在“思考”如何回答。在从网络搜索结果中观察到“根据新闻搜索,看起来像是发布了名为《塞尔达传说:王国之泪》的续集”后,它决定做出回答。


那么,按照这个逻辑,我们不应该只使用/search端点吗?因为它更准确,因此更智能?不完全的。通常,在基于聊天机器人的应用程序中,机器人应保留先前对话的上下文,以便它可以提供响应,就好像它“记住”了对话的整个上下文一样。让我们看看/search端点是否可以做到这一点。


让我们测试/search端点是否可以回忆起我们刚刚询问的内容。


发生这种情况是因为,虽然 LangChain 库具有内存链功能,可用于保留过去的对话,但 Web 服务器和基于其构建的 REST API 服务本质上是无状态的。这意味着,Web 服务器会将每个请求视为一个新请求。


但是,我们不是已经将之前的对话作为有效负载了吗?这是个好问题。事实证明,LangChain中使用的Agent链目前不支持处理组合提示,该提示由用户和AI的请求和响应组成。我们主要用它来为模型提供示例对话,进一步调整模型以达到我们想要的响应。


另一方面,代理通过接收单个指令来工作,并围绕该指令发展其思想链。这就是为什么,无论我们的对话持续多长时间,代理都只会响应最新的请求。


让我们测试/ask端点以注意到差异。


这一次,它使用我们过去的对话作为附加上下文来回答!现在我们意识到我们需要两个端点来构建我们的 AI Assistant 应用程序。但是,我们如何将过时但始终记住的/ask端点与容易忘记但彻底且最新的/search端点结合起来?当然是通过构建前端!

开发前端


应用程序.tsx

让我们导航回ai-assistant-claude项目目录。在此项目中,我们将开始修改 React 组件,从入口点文件App.tsx开始。

 import React from 'react'; import logo from './logo.svg'; import './App.css'; import { ChatClient } from './ChatClient'; function App() { return ( <div> <ChatClient/> </div> ); } export default App;

在上面的代码片段中,我们导入了ChatClient组件,该组件将在后续步骤中创建。然后,我们将<ChatClient/>组件包含在<div>元素中。这使用 React 组件为我们的 AI 助手应用程序设置了结构。

聊天客户端.tsx

 import React, { useState } from 'react'; import { ChatInput } from './ChatInput'; import { ChatHistory } from './ChatHistory'; export interface Message { content: string; role: string; } export const ChatClient: React.FC = () => { const [messages, setMessages] = useState<Array<Message>>([]); const [isLoading, setIsLoading] = useState(false) const handleSimpleChat = (message: string) => { // Send the message and past chat history to the backend // Update messages state with the new message let newMessages = [...messages, { content: message, role: 'user' }] setMessages(newMessages); let postData = { message: newMessages } setIsLoading(true) fetch('/ask', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }) .then((response) => response.json()) .then((data) => { if (data.status === "success") { setMessages([...newMessages, { content: data.message, role: 'assistant' }]) } setIsLoading(false) console.log('Success:', data); }) .catch((error) => { console.error('Error:', error); setIsLoading(false) }); }; const handleAdvancedChat = (message: string) => { // Trigger AI agent with Google Search functionality // Update messages state with the new message and AI response let newMessages = [...messages, { content: message, role: 'user' }] setMessages(newMessages); let postData = { message: newMessages } setIsLoading(true) fetch('/search', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }) .then((response) => response.json()) .then((data) => { if (data.status === "success") { setMessages([...newMessages, { content: data.message, role: 'assistant' }]) } console.log('Success:', data); setIsLoading(false) }) .catch((error) => { console.error('Error:', error); setIsLoading(false) }); }; return ( <div className="h-screen bg-gray-100 dark:bg-gray-900 flex items-center justify-center"> <div className='flex flex-col items-center gap-2'> <h1 className='text-white text-xl'>AI Assistant with Claude and LangChain</h1> <div className="w-full max-w-md h-[80vh] bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden flex flex-col"> <ChatHistory messages={messages} isLoading={isLoading} /> <ChatInput onSimpleChat={handleSimpleChat} onAdvancedChat={handleAdvancedChat} /> </div> </div> </div> ); };

该组件充当我们的人工智能助手的主要用户界面。如图所示,它包含一个用于显示对话历史记录的ChatHistory组件和一个用于输入文本的ChatInput组件。


该组件处理来自ChatInput组件的输入,使用此输入向后端发送请求,然后显示加载状态。如果请求成功处理,该组件还将显示从后端收到的响应。

聊天记录.tsx

 import React from 'react'; import { ReactMarkdown } from 'react-markdown/lib/react-markdown'; import { Message } from './ChatClient'; interface ChatHistoryProps { messages: Array<Message>; isLoading: boolean } export const ChatHistory: React.FC<ChatHistoryProps> = ({ messages, isLoading }) => { return ( <div className="p-4 h-full overflow-y-auto"> {messages.map((message, index) => ( <div key={index} className={`mb-3 ${ message.role === 'user' ? 'text-right' : 'text-left' }`} > <ReactMarkdown className={`inline-block px-3 py-2 rounded-md ${ index % 2 === 0 ? 'bg-gray-300 dark:bg-gray-700' : 'bg-blue-200 dark:bg-blue-900' }`} > {message.content} </ReactMarkdown> </div> ))} {isLoading && ( <div className="mb-3 text-left"> <ReactMarkdown className="inline-block px-3 py-2 rounded-md bg-blue-200 dark:bg-blue-900 animate-pulse" > {/* Put your desired loading content here */} Thinking... </ReactMarkdown> </div> )} </div> ); };

幸运的是,TailwindCSS 提供了用于简单动画的内置实用程序类,例如animate-pulse 。此类优雅地帮助指示请求正在等待响应。在此组件中,我们还区分了“用户”和“助理”的消息定位。


聊天输入.tsx

 import React, { useState } from 'react'; interface ChatInputProps { onSimpleChat: (message: string) => void; onAdvancedChat: (message: string) => void; } export const ChatInput: React.FC<ChatInputProps> = ({ onSimpleChat, onAdvancedChat }) => { const [input, setInput] = useState(''); const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => { setInput(event.target.value); }; const handleSubmit = (handler: (message: string) => void) => { handler(input); setInput(''); }; return ( <div className="flex p-4 border-t border-gray-200 dark:border-gray-700"> <input type="text" value={input} onChange={handleInputChange} placeholder="Type your message..." className="flex-grow px-3 py-2 rounded-md bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100 focus:outline-none" /> <button onClick={() => handleSubmit(onSimpleChat)} className="ml-2 px-4 py-2 font-semibold text-gray-600 bg-white dark:text-gray-400 dark:bg-gray-800 border border-gray-300 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 focus:outline-none" > Ask </button> <button onClick={() => handleSubmit(onAdvancedChat)} className="ml-2 px-4 py-2 font-semibold text-white bg-blue-500 border border-blue-600 rounded-md hover:bg-blue-400 focus:outline-none" > Ask and Search </button> </div> ); };

最后,我们在文本输入中添加了两个按钮。第一个按钮用于将输入发送到/ask端点,该端点使用 AI 模型处理输入,无需任何其他增强功能。


该端点是上下文感知的。第二个按钮,恰当地命名为“询问和搜索”,将输入发送到/search端点。除了通过人工智能模型处理输入之外,如果情况需要,此按钮还会触发人工智能驱动的网络搜索。


索引.html

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <!-- Notice the use of %PUBLIC_URL% in the tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public` folder can be referenced from the HTML. Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> -- <title>React App</title> ++ <title>Claude AI Assistant</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> </html>

作为最后的润色,我们更新了index.html页面中应用程序的标题,将其从“ React App ”更改为“ Claude AI Assistant ”。


包.json

 { "name": "ai-assistant-claude", "version": "0.1.0", "private": true, ++ "proxy": "http://localhost:5000", "dependencies": {

最后,我们将代理配置添加到package.json文件并将其设置为http://localhost:5000 。这有助于我们绕过因使用不同端口而产生的 CORS 限制。

测试AI助手应用程序

要开始测试,首先确保后端应用程序 (claude-langchain) 已在运行。


接下来,将目录更改为前端应用程序 (ai-assistant-claude) 并使用以下命令启动应用程序:

 npm start


该应用程序可能需要一些时间来构建。准备就绪后,它将自动在浏览器中打开localhost:3000


让我们测试一下上下文感知和搜索功能!首先,我们来了解一下 2021 年另一款尚未公布的游戏——SEGA最新《如龙》游戏的续作。此外,我们会询问这款游戏是否包含前作中深受喜爱的角色桐生一马。为此,请单击“询问”按钮。


给它几秒钟的时间思考...



令人惊讶的是,人工智能回答错误。 《如龙:如龙》确实是最新的《如龙》游戏,但由不同的主角春日一番主演。让我们重新表述一下这个问题,这次使用“询问和搜索”按钮。



现在,人工智能需要更长的时间来决定是否需要搜索网络。在确定需要进行网络搜索并找到满意的答案后,它将信息返回给客户端/前端。


这次的标题是《如龙外传:抹去名字的男人》,主角确实是桐生一马。


很迷人,不是吗?该代理由大型语言模型提供支持,可根据可用资源(搜索)预测需要采取哪些操作,并提供令人满意的答案。 LangChain可以轻松连接和“链接”模型、提示(对模型的指令)以及其他功能(例如代理和工具)。

结论

我们希望您喜欢构建这个应用程序并学习这些技术。对于那些有兴趣深入研究的人,您可以访问已完成的前端后端项目。


如果您想使用我们合作伙伴实现的最新技术进行构建,请加入我们,迎接下一个人工智能挑战!


*please see lablab.ai for all terms and conditions