Como criar um chatbot de IA com Milvus e Towhee

Aug 18, 202311 min read

Milvus, um banco de dados vetorial de código aberto, é a espinha dorsal perfeita para qualquer aplicação de IA que exija recursos eficientes e escaláveis de busca vetorial, tornando-o uma escolha de destaque para o gerenciamento de dados do seu chatbot. Towhee é um framework emergente para fluxos de trabalho de machine learning que simplifica o processo de implementação e orquestração de modelos complexos de ML. Ele também torna o desenvolvimento da sua aplicação gerenciável e fácil de entender.

Neste tutorial, você aprenderá como criar um chatbot de IA simples com Python usando Milvus e Towhee. Você se concentrará em como ingerir dados não estruturados, analisá-los, armazená-los com embeddings e processar consultas.

Configurando seu ambiente

Primeiro, crie um ambiente virtual Python para executar seu chatbot.

Aqui está uma sessão de shell do Linux. Ela cria o ambiente, ativa-o e atualiza o pip para a versão mais recente.

[egoebelbecker@ares milvus_chatbot]$ python -m venv ./chatbot_venv
[egoebelbecker@ares milvus_chatbot]$ source chatbot_venv/bin/activate
(chatbot_venv) [egoebelbecker@ares milvus_chatbot]$ pip install --upgrade pip
Requirement already satisfied: pip in ./chatbot_venv/lib64/python3.11/site-packages (22.2.2)
Collecting pip
  Using cached pip-23.1.2-py3-none-any.whl (2.1 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 22.2.2
    Uninstalling pip-22.2.2:
      Successfully uninstalled pip-22.2.2
Successfully installed pip-23.1.2

Em seguida, instale os pacotes necessários para executar o código: pandas, jupyter, langchain, towhee, unstructured, milvus, pymilvus, sentence_transformers e gradio.

(chatbot_venv) [egoebelbecker@ares milvus_chatbot]$ pip install pandas jupyter langchain towhee unstructured milvus pymilvus sentence_transformers gradio
Coletando pandas
  Obtendo informações de dependência para pandas de https://files.pythonhosted.org/packages/d0/28/88b81881c056376254618fad622a5e94b5126db8c61157ea1910cd1c040a/pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata
  Usando pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata em cache (18 kB)
Coletando jupyter
  Usando jupyter-1.0.0-py2.py3-none-any.whl em cache (2.7 kB)
(corte)
Instalando pacotes coletados: webencodings, wcwidth, pytz, pure-eval, ptyprocess, pickleshare, json5, ipython-genutils, filetype, fastjsonschema, executing, backcall, zipp, XlsxWriter, xlrd, widgetsnbextension, websocket-client, webcolors, urllib3, uri-template, tzdata, typing-extensions, traitlets, tqdm, tornado, tinycss2, tenacity, tabulate, soupsieve, sniffio, six, send2trash, rpds-py, rfc3986-validator, rfc3986, regex, pyzmq, PyYAML, python-magic, python-json-logger, pypandoc, pygments, pycparser, psutil, prompt-toolkit, prometheus-client, platformdirs, pkginfo, pillow, pexpect, parso, pandocfilters, packaging, overrides, olefile, numpy, nest-asyncio, mypy-extensions, multidict, more-itertools, mistune, mdurl, markupsafe, markdown, lxml, jupyterlab-widgets, jupyterlab-pygments, jsonpointer, joblib, jeepney, idna, greenlet, frozenlist, fqdn, et-xmlfile, docutils, defusedxml, decorator, debugpy, click, charset-normalizer, chardet, certifi, babel, attrs, async-timeout, async-lru, yarl, typing-inspect, terminado, SQLAlchemy, rfc3339-validator, requests, referencing, qtpy, python-pptx, python-docx, python-dateutil, pydantic, pdf2image, openpyxl, numexpr, nltk, msg-parser, matplotlib-inline, marshmallow, markdown-it-py, jupyter-core, jinja2, jedi, jaraco.classes, importlib-metadata, comm, cffi, bleach, beautifulsoup4, asttokens, anyio, aiosignal, stack-data, rich, requests-toolbelt, readme-renderer, pandas, openapi-schema-pydantic, langsmith, jupyter-server-terminals, jupyter-client, jsonschema-specifications, dataclasses-json, cryptography, arrow, argon2-cffi-bindings, aiohttp, SecretStorage, pdfminer.six, langchain, jsonschema, isoduration, ipython, argon2-cffi, unstructured, nbformat, keyring, ipykernel, twine, qtconsole, nbclient, jupyter-events, jupyter-console, ipywidgets, towhee, nbconvert, jupyter-server, notebook-shim, jupyterlab-server, jupyter-lsp, jupyterlab, notebook, jupyter
Instalado com sucesso PyYAML-6.0.1 SQLAlchemy-2.0.19 SecretStorage-3.3.3 XlsxWriter-3.1.2 aiohttp-3.8.5 aiosignal-1.3.1 anyio-3.7.1 argon2-cffi-21.3.0 argon2-cffi-bindings-21.2.0 arrow-1.2.3 asttokens-2.2.1 async-lru-2.0.4 async-timeout-4.0.2 attrs-23.1.0 babel-2.12.1 backcall-0.2.0 beautifulsoup4-4.12.2 bleach-6.0.0 certifi-2023.7.22 cffi-1.15.1 chardet-5.1.0 charset-normalizer-3.2.0 click-8.1.6 comm-0.1.3 cryptography-41.0.2 dataclasses-json-0.5.14 debugpy-1.6.7 decorator-5.1.1 defusedxml-0.7.1 docutils-0.20.1 et-xmlfile-1.1.0 executing-1.2.0 fastjsonschema-2.18.0 filetype-1.2.0 fqdn-1.5.1 frozenlist-1.4.0 greenlet-2.0.2 idna-3.4 importlib-metadata-6.8.0 ipykernel-6.25.0 ipython-8.14.0 ipython-genutils-0.2.0 ipywidgets-8.0.7 isoduration-20.11.0 jaraco.classes-3.3.0 jedi-0.19.0 jeepney-0.8.0 jinja2-3.1.2 joblib-1.3.1 json5-0.9.14 jsonpointer-2.4 jsonschema-4.18.4 jsonschema-specifications-2023.7.1 jupyter-1.0.0 jupyter-client-8.3.0 jupyter-console-6.6.3 jupyter-core-5.3.1 jupyter-events-0.7.0 jupyter-lsp-2.2.0 jupyter-server-2.7.0 jupyter-server-terminals-0.4.4 jupyterlab-4.0.3 jupyterlab-pygments-0.2.2 jupyterlab-server-2.24.0 jupyterlab-widgets-3.0.8 keyring-24.2.0 langchain-0.0.248 langsmith-0.0.15 lxml-4.9.3 markdown-3.4.4 markdown-it-py-3.0.0 markupsafe-2.1.3 marshmallow-3.20.1 matplotlib-inline-0.1.6 mdurl-0.1.2 mistune-3.0.1 more-itertools-10.0.0 msg-parser-1.2.0 multidict-6.0.4 mypy-extensions-1.0.0 nbclient-0.8.0 nbconvert-7.7.3 nbformat-5.9.2 nest-asyncio-1.5.7 nltk-3.8.1 notebook-7.0.1 notebook-shim-0.2.3 numexpr-2.8.4 numpy-1.25.2 olefile-0.46 openapi-schema-pydantic-1.2.4 openpyxl-3.1.2 overrides-7.3.1 packaging-23.1 pandas-2.0.3 pandocfilters-1.5.0 parso-0.8.3 pdf2image-1.16.3 pdfminer.six-20221105 pexpect-4.8.0 pickleshare-0.7.5 pillow-10.0.0 pkginfo-1.9.6 platformdirs-3.10.0 prometheus-client-0.17.1 prompt-toolkit-3.0.39 psutil-5.9.5 ptyprocess-0.7.0 pure-eval-0.2.2 pycparser-2.21 pydantic-1.10.12 pygments-2.15.1 pypandoc-1.11 python-dateutil-2.8.2 python-docx-0.8.11 python-json-logger-2.0.7 python-magic-0.4.27 python-pptx-0.6.21 pytz-2023.3 pyzmq-25.1.0 qtconsole-5.4.3 qtpy-2.3.1 readme-renderer-40.0 referencing-0.30.0 regex-2023.6.3 requests-2.31.0 requests-toolbelt-1.0.0 rfc3339-validator-0.1.4 rfc3986-2.0.0 rfc3986-validator-0.1.1 rich-13.5.1 rpds-py-0.9.2 send2trash-1.8.2 six-1.16.0 sniffio-1.3.0 soupsieve-2.4.1 stack-data-0.6.2 tabulate-0.9.0 tenacity-8.2.2 terminado-0.17.1 tinycss2-1.2.1 tornado-6.3.2 towhee-1.1.1 tqdm-4.65.0 traitlets-5.9.0 twine-4.0.2 typing-extensions-4.7.1 typing-inspect-0.9.0 tzdata-2023.3 unstructured-0.8.7 uri-template-1.3.0 urllib3-2.0.4 wcwidth-0.2.6 webcolors-1.13 webencodings-0.5.1 websocket-client-1.6.1 widgetsnbextension-4.0.8 xlrd-2.0.1 yarl-1.9.2 zipp-3.16.2
(chatbot_venv) [egoebelbecker@ares milvus_chatbot]$ 

Você pode encontrar um notebook Jupyter com o código para este tutorial aqui. Baixe-o, inicie o Jupyter e carregue o notebook:

chatbot_venv) [egoebelbecker@ares milvus_chatbot]$ jupyter notebook milvus_chatbot.ipynb 
[I 2023-07-31 11:29:01.748 ServerApp] Package notebook took 0.0000s to import
[I 2023-07-31 11:29:01.759 ServerApp] Package jupyter_lsp took 0.0108s to import
[W 2023-07-31 11:29:01.759 ServerApp] A `_jupyter_server_extension_points` function was not found in jupyter_lsp. Instead, a `_jupyter_server_extension_paths` function was found and will be used for now. This function name will be deprecated in future releases of Jupyter Server.
[I 2023-07-31 11:29:01.764 ServerApp] Package jupyter_server_terminals took 0.0045s to import
[I 2023-07-31 11:29:01.765 ServerApp] Package jupyterlab took 0.0000s to import
[I 2023-07-31 11:29:02.124 ServerApp] Package notebook_shim took 0.0000s to import

Criando um chatbot

Agora, vamos trabalhar no chatbot.

Armazenamento de documentos

O bot precisa armazenar trechos de documentos e os embeddings que o Towhee extrai deles. É para isso que você usará o Milvus. Você já instalou o Milvus Lite, uma versão leve do Milvus, acima com a biblioteca milvus.

Você pode executar um servidor pela linha de comando:

(chatbot_venv) [egoebelbecker@ares milvus_chatbot]$ milvus-server

    __  _________ _   ____  ______
   /  |/  /  _/ /| | / / / / / __/
  / /|_/ // // /_| |/ / /_/ /\ \
 /_/  /_/___/____/___/\____/___/ {Lite}

 Welcome to use Milvus!

 Version:   v2.2.12-lite
 Process:   139309
 Started:   2023-07-31 12:43:43
 Config:    /home/egoebelbecker/.milvus.io/milvus-server/2.2.12/configs/milvus.yaml
 Logs:      /home/egoebelbecker/.milvus.io/milvus-server/2.2.12/logs

 Ctrl+C to exit …

Ou, como parte do código da sua aplicação, como mostrado no notebook:

from milvus import default_server

# Start Milvus service
default_server.start()

# # Stop Milvus service
# default_server.stop()

Defina variáveis da aplicação e obtenha a chave de API da OpenAI

Em seguida, defina algumas variáveis e limpe quaisquer arquivos SQLite restantes. Usaremos SQLite abaixo para o histórico de chat.

  • MILVUS_URI - as informações de conexão para os servidores Milvus. Analisadas em host e porta.
  • MILVUS_HOST - o host onde o Milvus está em execução.
  • MILVUS_PORT - a porta em que o servidor escuta.
  • DROP_EXIST - descartar coleções Milvus existentes na inicialização.
  • EMBED_MODEL - o modelo sentence_transformers que o código usará para criar embeddings
  • COLLECTION_NAME - nome da coleção Milvus para dados e embeddings
  • DIM - a dimensão dos embeddings que o modelo cria para cada trecho de texto
  • OPENAI_API_KEY - chave para a API do LLM

import getpass
import os

MILVUS_URI = 'http://localhost:19530'
[MILVUS_HOST, MILVUS_PORT] = MILVUS_URI.split('://')[1].split(':')
DROP_EXIST = True
EMBED_MODEL = 'all-mpnet-base-v2'
COLLECTION_NAME = 'chatbot_demo'
DIM = 768

OPENAI_API_KEY = getpass.getpass('Enter your OpenAI API key: ')

if os.path.exists('./sqlite.db'):
    os.remove('./sqlite.db')

Execute este código para definir as variáveis e responder ao prompt da chave de API.

Pipeline de exemplo

Em seguida, é hora de baixar alguns dados e armazená-los no Milvus. Mas antes de fazer isso, vamos ver um pipeline de exemplo para baixar e processar dados não estruturados.

Você usará as páginas da documentação do Towhee para este exemplo. Você pode experimentar sites diferentes para ver como o código processa diferentes conjuntos de dados.

Este código usa pipelines do Towhee:

  • input - inicia um novo pipeline com a fonte passada para ele
  • map - usa ops.text_loader() para recuperar a URL e mapeá-la para 'doc'
  • flat_map - usa ops.text_splitter() para processar o documento em "trechos" para armazenamento
  • output - fecha e prepara o pipeline para uso

Passe este pipeline para DataCollection para ver como ele funciona.

from towhee import pipe, ops, DataCollection

pipe_load = (
    pipe.input('source')
        .map('source', 'doc', ops.text_loader())
        .flat_map('doc', 'doc_chunks', ops.text_splitter(chunk_size=300))
        .output('source', 'doc_chunks')
)
DataCollection(pipe_load('https://towhee.io')).show()

Aqui está a saída de show():

O pipeline criou cinco chunks a partir do documento.

Pipeline de embedding de exemplo

O pipeline recuperou os dados e criou chunks. Você também precisa criar embeddings. Vamos dar uma olhada em outro pipeline de exemplo.

Este usa map() para executar ops.sentence_embedding.sbert() em cada chunk. Neste exemplo, estamos passando um único bloco de texto.

pipe_embed = (
    pipe.input('doc_chunk')
        .map('doc_chunk', 'vec', ops.sentence_embedding.sbert(model_name=EMBED_MODEL))
        .map('vec', 'vec', ops.np_normalize())
        .output('doc_chunk', 'vec')
)

text = '''SOTA Models

We provide 700+ pre-trained embedding models spanning 5 fields (CV, NLP, Multimodal, Audio, Medical), 15 tasks, and 140+ model architectures.
These include BERT, CLIP, ViT, SwinTransformer, data2vec, etc.
'''

DataCollection(pipe_embed(text)).show()

Execute este código para ver como o pipeline processa o único bloco de texto.

Preparar o Milvus

Agora, você precisa de uma collection para armazenar os dados. Este bloco define create_collection(), que usa MILVUS_HOST e MILVUS_PORT para se conectar ao Milvus, descartar quaisquer collections existentes com o nome especificado e criar uma nova com este schema:

  • id - um identificador inteiro
  • embedding - um vetor de floats para os embeddings
  • text - o texto correspondente aos embeddings
from pymilvus import (
    connections, utility, Collection,
    CollectionSchema, FieldSchema, DataType
)

def create_collection(collection_name):
    connections.connect(host=MILVUS_HOST, port=MILVUS_PORT)
    
    has_collection = utility.has_collection(collection_name)
    
    if has_collection:
        collection = Collection(collection_name)
        if DROP_EXIST:
            collection.drop()
        else:
            return collection

    # Create collection
    fields = [
        FieldSchema(name='id', dtype=DataType.INT64, is_primary=True, auto_id=True),
        FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, dim=DIM),
        FieldSchema(name='text', dtype=DataType.VARCHAR, max_length=500)
    ]
    schema = CollectionSchema(
        fields=fields,
        description="Towhee demo",
        enable_dynamic_field=True
        )
    collection = Collection(name=collection_name, schema=schema)
    
    index_params = {
        'metric_type': 'IP',
        'index_type': 'IVF_FLAT',
        'params': {'nlist': 1024}
        }
    collection.create_index(
        field_name='embedding', 
        index_params=index_params
    )
    return collection

Pipeline de inserção

É hora de processar seu texto de entrada e inseri-lo no Milvus. Vamos começar com um pipeline que consolida o que você aprendeu acima.

Esta função:

  • Cria a nova collection
  • Recupera os dados
  • Divide-os em chunks
  • Cria embeddings usando EMBED_MODEL
  • Insere o texto e os embeddings no Milvus
load_data = (
    pipe.input('collection_name', 'source')
        .map('collection_name', 'collection', create_collection)
        .map('source', 'doc', ops.text_loader())
        .flat_map('doc', 'doc_chunk', ops.text_splitter(chunk_size=300))
        .map('doc_chunk', 'vec', ops.sentence_embedding.sbert(model_name=EMBED_MODEL))
        .map('vec', 'vec', ops.np_normalize())
        .map(('collection_name', 'vec', 'doc_chunk'), 'mr',
             ops.ann_insert.osschat_milvus(host=MILVUS_HOST, port=MILVUS_PORT))
        .output('mr')
)

Aqui está em ação. Execute-o na página da Wikipedia sobre Frodo Baggins.

project_name = 'towhee_demo'
data_source = 'https://en.wikipedia.org/wiki/Frodo_Baggins'
mr = load_data(COLLECTION_NAME, data_source)

print('Fragmentos do documento inseridos:', len(mr.to_list()))

Ele insere 408 fragmentos com embeddings:

2023-07-31 16:50:53,369 - 139993906521792 - node.py-node:167 - INFO: Begin to run Node-_input
2023-07-31 16:50:53,371 - 139993906521792 - node.py-node:167 - INFO: Begin to run Node-create_collection-0
2023-07-31 16:50:53,373 - 139993881343680 - node.py-node:167 - INFO: Begin to run Node-text-loader-1
2023-07-31 16:50:53,374 - 139993898129088 - node.py-node:167 - INFO: Begin to run Node-text-splitter-2
2023-07-31 16:50:53,376 - 139993872950976 - node.py-node:167 - INFO: Begin to run Node-sentence-embedding/sbert-3
2023-07-31 16:50:53,377 - 139993385268928 - node.py-node:167 - INFO: Begin to run Node-np-normalize-4
2023-07-31 16:50:53,378 - 139993376876224 - node.py-node:167 - INFO: Begin to run Node-ann-insert/osschat-milvus-5
2023-07-31 16:50:53,379 - 139993368483520 - node.py-node:167 - INFO: Begin to run Node-_output

(snip)

Categorias:
2023-07-31 18:07:53,530 - 140552729257664 - logger.py-logger:14 - DETAIL: Ignorando sentença porque não excede 5 tokens de palavras
Categorias
2023-07-31 18:07:53,532 - 140552729257664 - logger.py-logger:14 - DETAIL: Ignorando sentença porque não excede 3 tokens de palavras
Categorias ocultas
2023-07-31 18:07:53,533 - 140552729257664 - logger.py-logger:14 - DETAIL: Ignorando sentença porque não excede 3 tokens de palavras
Categorias ocultas
2023-07-31 18:07:53,533 - 140552729257664 - logger.py-logger:14 - DETAIL: Não narrativo. O texto não contém um verbo:

Categorias ocultas: 
2023-07-31 18:07:53,534 - 140552729257664 - logger.py-logger:14 - DETAIL: Ignorando sentença porque não excede 5 tokens de palavras
Categorias ocultas

Fragmentos do documento inseridos: 408

Pesquisar na base de conhecimento

Agora, com os embeddings e o texto armazenados no Milvus, você pode pesquisá-los.

Esta função cria um pipeline de consulta. A etapa mais importante é esta:

ops.ann_search.osschat_milvus(host=MILVUS_HOST, port=MILVUS_PORT, 
                              **{'metric_type': 'IP', 'limit': 3, 'output_fields': ['text']}))

O osschat_milvus pesquisa os embeddings em busca de correspondências com o texto enviado.

Aqui está o pipeline completo:

pipe_search = (
    pipe.input('collection_name', 'query')
        .map('query', 'query_vec', ops.sentence_embedding.sbert(model_name=EMBED_MODEL))
        .map('query_vec', 'query_vec', ops.np_normalize())
        .map(('collection_name', 'query_vec'), 'search_res',
             ops.ann_search.osschat_milvus(host=MILVUS_HOST, port=MILVUS_PORT,
                                           **{'metric_type': 'IP', 'limit': 3, 'output_fields': ['text']}))
        .flat_map('search_res', ('id', 'score', 'text'), lambda x: (x[0], x[1], x[2]))
        .output('query', 'text', 'score')
)

Experimente:

query = 'Who is Frodo Baggins?'
DataCollection(pipe_search(project_name, query)).show()

O modelo faz um bom trabalho ao recuperar três nós estreitamente correspondentes:

Adicionar um LLM

Agora, é hora de adicionar um grande modelo de linguagem (LLM) para que os usuários possam manter uma conversa com o chatbot. Usaremos o ChatGPT e a API da OpenAI neste exemplo.

Histórico de chat

Para obter melhores resultados do LLM, você precisa armazenar o histórico de chat e apresentá-lo com as consultas. Você usará SQLite para esta etapa.

Aqui está uma função para recuperar o histórico:

pipe_get_history = (
    pipe.input('collection_name', 'session')
        .map(('collection_name', 'session'), 'history', ops.chat_message_histories.sql(method='get'))
        .output('collection_name', 'session', 'history')
)

Aqui está a função para armazená-lo:

pipe_add_history = (
    pipe.input('collection_name', 'session', 'question', 'answer')
        .map(('collection_name', 'session', 'question', 'answer'), 'history', ops.chat_message_histories.sql(method='add'))
        .output('history')
)

Pipeline de consulta LLM

Agora, precisamos de um pipeline para enviar consultas ao ChatGPT.

Este pipeline:

  • pesquisa no Milvus usando a consulta do usuário
  • coleta o histórico atual do chat
  • envia a consulta, a pesquisa no Milvus e o histórico do chat para o ChatGPT
  • Acrescenta o resultado do ChatGPT ao histórico do chat
  • Retorna o resultado ao chamador
chat = (
    pipe.input('collection_name', 'query', 'session')
        .map('query', 'query_vec', ops.sentence_embedding.sbert(model_name=EMBED_MODEL))
        .map('query_vec', 'query_vec', ops.np_normalize())
        .map(('collection_name', 'query_vec'), 'search_res',
            ops.ann_search.osschat_milvus(host=MILVUS_HOST,
                                        port=MILVUS_PORT,
                                        **{'metric_type': 'IP', 'limit': 3, 'output_fields': ['text']}))
        .map('search_res', 'knowledge', lambda y: [x[2] for x in y])
        .map(('collection_name', 'session'), 'history', ops.chat_message_histories.sql(method='get'))
        .map(('query', 'knowledge', 'history'), 'messages', ops.prompt.question_answer())
        .map('messages', 'answer', ops.LLM.OpenAI(api_key=OPENAI_API_KEY,
                                                model_name='gpt-3.5-turbo',
                                                temperature=0.8))
        .map(('collection_name', 'session', 'query', 'answer'), 'new_history', ops.chat_message_histories.sql(method='add'))
        .output('query', 'history', 'answer', )
)

Vamos testar este pipeline antes de conectá-lo a uma GUI:

new_query = 'Where did Frodo take the ring?'
DataCollection(chat(COLLECTION_NAME, new_query, session_id)).show()

Aqui estão a saída e os resultados no notebook:

O pipeline funciona. Vamos montar uma interface Gradio.

GUI Gradio

Primeiro, você precisa de funções para criar um identificador de sessão e responder a consultas da interface.

Estas funções criam um ID de sessão usando um UUID e aceitam uma sessão e uma consulta para o pipeline de consulta.

import uuid
import io

def create_session_id():
    uid = str(uuid.uuid4())
    suid = ''.join(uid.split('-'))
    return 'sess_' + suid

def respond(session, query):
    res = chat(COLLECTION_NAME, query, session).get_dict()
    answer = res['answer']
    response = res['history']
    response.append((query, answer))
    return response

Em seguida, a interface Gradio usa estas funções para criar um chatbot.

Ela usa a API Blocks para criar uma interface ChatBot. O botão Send Message usa a função respond para enviar solicitações ao ChatGPT.

import gradio as gr

with gr.Blocks() as demo:
    session_id = gr.State(create_session_id)

    with gr.Row():
        with gr.Column(scale=2):
            gr.Markdown('''## Chat''')
            conversation = gr.Chatbot(label='conversation').style(height=300)
            question = gr.Textbox(label='question', value=None)
    
            send_btn = gr.Button('Send Message')
            send_btn.click(
                fn=respond,
                inputs=[
                    session_id,
                    question
                ],
                outputs=conversation,
            )

demo.launch(server_name='127.0.0.1', server_port=8902)

Aqui está:

Agora, você tem um chatbot inteligente baseado em LLM com Milvus!

Resumo

Neste post, criamos pipelines Towhee para ingerir dados não estruturados, processá-los para embeddings e armazenar esses embeddings no Milvus. Em seguida, criamos um pipeline de consulta para a função de chat e conectamos o chatbot a um LLM. Por fim, obtivemos um chatbot inteligente.

Este tutorial demonstra como é fácil criar aplicações com Milvus. O Milvus traz inúmeras vantagens quando integrado a aplicações, especialmente aquelas que dependem de aprendizado de máquina e inteligência artificial. Ele oferece recursos de busca e análise de similaridade vetorial altamente eficientes, escaláveis e confiáveis, essenciais em aplicações como chatbots, sistemas de recomendação e reconhecimento de imagens ou texto.

Este post foi escrito por Eric Goebelbecker. Eric trabalhou nos mercados financeiros da cidade de Nova York por 25 anos, desenvolvendo infraestrutura para dados de mercado e redes do protocolo de troca de informações financeiras (FIX). Ele adora falar sobre o que torna as equipes eficazes (ou não tão eficazes!).

Atualizado em Jul 09, 2026