У цій статті ми розглянемо, як створити медичний чат-бот за допомогою Flask і LangChain, інтегрованого з Pinecone, OpenAI та медичною базою знань, щоб створити інтелектуального асистента, який може отримувати та обробляти інформацію з медичної книги. Розглянемо основні компоненти цієї реалізації.
Налаштування середовища
Перед тим як почати працювати з кодом, важливо чітко зрозуміти інструменти та бібліотеки, які ми будемо використовувати для роботи з медичним чат-ботом.
- Flask: Цей легкий веб-фреймворк використовується для створення бекенду чат-бота, який обробляє HTTP-запити.
- LangChain і LangGraph: Відкритий фреймворк, який допомагає зв'язувати мовні моделі та зовнішні інструменти, такі як Pinecone (векторна база даних), для виконання більш складних завдань, наприклад, отримання інформації.
- Pinecone: Векторна база даних, що використовується для зберігання та запитування великих документів або наборів даних, що є необхідним для отримання медичної інформації.
- OpenAI: Для реалізації можливостей обробки природної мови ми будемо використовувати модель GPT-4 від OpenAI для розуміння та генерування відповідей, схожих на людські.
Спочатку потрібно імпортувати необхідні бібліотеки:
from flask import Flask, render_template, request, jsonify
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_pinecone import PineconeVectorStore
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langgraph.graph import MessagesState
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import tools_condition
from langchain_core.messages import SystemMessage
from dotenv import load_dotenv
Далі потрібно налаштувати API-ключі та саму програму:
# Налаштування Flask додатку
app = Flask(__name__)
# Змінні середовища
load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["PINECONE_API_KEY"] = os.getenv("PINECONE_API_KEY")
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = os.getenv("LANGCHAIN_API_KEY")
os.environ["LANGCHAIN_PROJECT"] = "Medical Chatbot"
Це робимо окремо: Далі попередньо обробляємо книгу, щоб створити векторні embeddings у Pinecone для подальшого використання.
# Завантажуємо PDF документ
loader = PyPDFLoader("Book of Medicine.pdf")
documents = loader.load()
# Розбиваємо документ на частини
text_splitter = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200)
chunks = text_splitter.split_documents(documents)
# Налаштовуємо LLM та модель Embedding від OpenAI
llm = ChatOpenAI()
embeddings = OpenAIEmbeddings()
# Налаштовуємо VectorStore
pc = Pinecone()
index = pc.create_index(
name = "medical-chatbot",
dimension = 1536,
metric = "cosine",
spec = ServerlessSpec(
cloud = "aws",
region = "us-east-1"
)
)
vector_store = PineconeVectorStore.from_documents(documents = chunks,
embedding = embeddings,
index_name = "medical-chatbot")
Після налаштування ключів, створюємо інструмент пошуку за допомогою LangChain. У цій функції ми будемо шукати найбільш релевантні документи в Pinecone на основі запиту користувача.
Функція потім серіалізує отриманий контент, який буде використано як контекст для моделі штучного інтелекту.
@tool(response_format="content_and_artifact")
def retrieve(query: str):
"""Отримати інформацію, що стосується запиту."""
retrieved_docs = vector_store.similarity_search(query, k=2)
serialized = "\n\n".join(
(f"Source: {doc.metadata}\n" f"Content: {doc.page_content}") for doc in retrieved_docs
)
return serialized, retrieved_docs
Далі ми створюємо функцію query або respond на основі оцінки GPT:
def query_or_respond(state: MessagesState):
"""Генерація виклику інструмента для отримання даних або відповідь."""
llm_with_tools = llm.bind_tools([retrieve])
response = llm_with_tools.invoke(state["messages"])
return {"messages": [response]}
Далі йде функція generate:
def generate(state: MessagesState):
"""Генерація відповіді"""
recent_tool_messages = []
for message in reversed(state["messages"]):
if message.type == "tool":
recent_tool_messages.append(message)
else:
break
tool_messages = recent_tool_messages[::-1]
docs_content = "\n\n".join(doc.content for doc in tool_messages)
system_message_content = (
"Ви — асистент для завдань з відповідями на питання. Використовуйте наступний контекст. "
"Якщо не знаєте, скажіть про це. Використовуйте максимум три речення та залишайтеся лаконічними."
"\n\n" + docs_content
)
prompt = [SystemMessage(system_message_content)] + state["messages"]
response = llm.invoke(prompt)
return {"messages": [response]}
Нарешті, ми компілюємо граф:
graph_builder = StateGraph(MessagesState)
graph_builder.add_node(query_or_respond)
graph_builder.add_node(tools := ToolNode([retrieve]))
graph_builder.add_node(generate)
graph_builder.set_entry_point("query_or_respond")
graph_builder.add_conditional_edges("query_or_respond", tools_condition, {END: END, "tools": "tools"})
graph_builder.add_edge("tools", "generate")
graph_builder.add_edge("generate", END)
return graph_builder.compile(checkpointer=MemorySaver())
Тепер переходимо до розробки основного додатку.
Я не буду вдаватися в деталі, оскільки у вас буде можливість коригувати це за бажанням:
new_thread_id = str(uuid.uuid4())
config = {"configurable": {"thread_id": new_thread_id}}
graph = initialize_graph()
@app.route("/")
def index():
"""Відображення основного інтерфейсу для чат-бота."""
return render_template("index.html")
@app.route("/new_chat", methods=["POST"])
def new_chat():
"""Почати новий чат, скидаючи ID потоку."""
new_thread_id = str(uuid.uuid4())
config["configurable"]["thread_id"] = new_thread_id
return jsonify({"message": "Новий чат розпочато", "thread_id": config["configurable"]["thread_id"]})
@app.route("/chat_input", methods=["POST"])
def chat_input():
"""Обробка вводу користувача та генерація відповіді чат-бота."""
user_input = request.json.get("message", "")
if not user_input:
return jsonify({"error": "Ввід не надано."}), 400
input_message = HumanMessage(content=user_input)
response = []
for chunk in graph.stream({"messages": [input_message]}, config):
chunk
if "generate" in chunk:
response.append(chunk["generate"]["messages"][0].content)
elif "query_or_respond" in chunk:
response.append(chunk["query_or_respond"]["messages"][0].content)
return jsonify({"response": response})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
Ось HTML код:
Medical Chatbot
Чат-бот навчений за книгою з 3-го видання Gale Encyclopedia of Medicine (3-е видання).
Чат-бот навчений за допомогою RAG (Retrieval-Augmented Generation). Він використовує LLM від OpenAI та моделі вбудовування.
Векторні вбудовування книги зберігаються в Pinecone.
New Chat Надіслати
Надсилання вашого повідомлення...
``` Це все. Якщо у вас є питання, просто дайте знати в коментарях. Ви можете отримати доступ до реалізації на GitHub та її розгортання на Heroku за посиланням нижче: Репозиторій на GitHub: [https://github.com/Rob-Christian/Medical-Chatbot](https://github.com/Rob-Christian/Medical-Chatbot)
Перекладено з: [How to build a Medical Chatbot based on a Medicine-based Book?](https://medium.com/@rmcaduyac1_30165/how-to-build-a-medical-chatbot-based-on-a-medicine-based-book-c1acc86e64f0)