探索人工智能的世界:构建智能问答系统之实战篇

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介: 【6月更文挑战第8天】本文档介绍了如何使用Python进行Milvus数据库操作,包括环境安装、基本操作如连接数据库、创建集合、插入和查询向量数据、创建索引、删除数据等。此外,还展示了使用LangChain库与HuggingFaceEmbeddings集成,简化操作。最后,演示了如何结合openai模型定制交互式问答系统。整个过程旨在帮助读者理解如何将预训练模型与数据库集成以实现特定任务。

引言

前面我们已经做好了必要的准备工作,包括对相关知识点的了解以及环境的安装。今天我们将重点关注代码方面的内容。如果你已经具备了Java编程基础,那么理解Python语法应该不会成为问题,毕竟只是语法的差异而已。随着时间的推移,你自然会逐渐熟悉和掌握这门语言。现在让我们开始吧!

环境安装命令

在使用之前,我们需要先进行一些必要的准备工作,其中包括执行一些命令。如果你已经仔细阅读了Milvus的官方文档,你应该已经了解到了这一点。下面是需要执行的一些命令示例:

pip3 install langchain

pip3 install openai

pip3 install protobuf==3.20.0

pip3 install grpcio-tools

python3 -m pip install pymilvus==2.3.2

python3 -c "from pymilvus import Collection"

快速入门

现在,我们来尝试使用官方示例,看看在没有集成LangChain的情况下,我们需要编写多少代码才能完成插入、查询等操作。官方示例已经在前面的注释中详细讲解了所有的流程。总体流程如下:

  1. 连接到数据库
  2. 创建集合(这里还有分区的概念,我们不深入讨论)
  3. 插入向量数据(我看官方文档就简单插入了一些数字...)
  4. 创建索引(根据官方文档的说法,通常在一定数据量下是不会经常创建索引的)
  5. 查询数据
  6. 删除数据
  7. 断开与数据库的连接

通过以上步骤,你会发现与连接MySQL数据库的操作非常相似。

# hello_milvus.py demonstrates the basic operations of PyMilvus, a Python SDK of Milvus.
# 1. connect to Milvus
# 2. create collection
# 3. insert data
# 4. create index
# 5. search, query, and hybrid search on entities
# 6. delete entities by PK
# 7. drop collection
import time

import numpy as np
from pymilvus import (
    connections,
    utility,
    FieldSchema, CollectionSchema, DataType,
    Collection,
)

fmt = "\n=== {:30} ===\n"
search_latency_fmt = "search latency = {:.4f}s"
num_entities, dim = 3000, 8

#################################################################################
# 1. connect to Milvus
# Add a new connection alias `default` for Milvus server in `localhost:19530`
# Actually the "default" alias is a buildin in PyMilvus.
# If the address of Milvus is the same as `localhost:19530`, you can omit all
# parameters and call the method as: `connections.connect()`.
#
# Note: the `using` parameter of the following methods is default to "default".
print(fmt.format("start connecting to Milvus"))
connections.connect("default", host="localhost", port="19530")

has = utility.has_collection("hello_milvus")
print(f"Does collection hello_milvus exist in Milvus: {has}")

#################################################################################
# 2. create collection
# We're going to create a collection with 3 fields.
# +-+------------+------------+------------------+------------------------------+
# | | field name | field type | other attributes |       field description      |
# +-+------------+------------+------------------+------------------------------+
# |1|    "pk"    |   VarChar  |  is_primary=True |      "primary field"         |
# | |            |            |   auto_id=False  |                              |
# +-+------------+------------+------------------+------------------------------+
# |2|  "random"  |    Double  |                  |      "a double field"        |
# +-+------------+------------+------------------+------------------------------+
# |3|"embeddings"| FloatVector|     dim=8        |  "float vector with dim 8"   |
# +-+------------+------------+------------------+------------------------------+
fields = [
    FieldSchema(name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=False, max_length=100),
    FieldSchema(name="random", dtype=DataType.DOUBLE),
    FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=dim)
]

schema = CollectionSchema(fields, "hello_milvus is the simplest demo to introduce the APIs")

print(fmt.format("Create collection `hello_milvus`"))
hello_milvus = Collection("hello_milvus", schema, consistency_level="Strong")

################################################################################
# 3. insert data
# We are going to insert 3000 rows of data into `hello_milvus`
# Data to be inserted must be organized in fields.
#
# The insert() method returns:
# - either automatically generated primary keys by Milvus if auto_id=True in the schema;
# - or the existing primary key field from the entities if auto_id=False in the schema.

print(fmt.format("Start inserting entities"))
rng = np.random.default_rng(seed=19530)
entities = [
    # provide the pk field because `auto_id` is set to False
    [str(i) for i in range(num_entities)],
    rng.random(num_entities).tolist(),  # field random, only supports list
    rng.random((num_entities, dim)),  # field embeddings, supports numpy.ndarray and list
]

insert_result = hello_milvus.insert(entities)

hello_milvus.flush()
print(f"Number of entities in Milvus: {hello_milvus.num_entities}")  # check the num_entities

################################################################################
# 4. create index
# We are going to create an IVF_FLAT index for hello_milvus collection.
# create_index() can only be applied to `FloatVector` and `BinaryVector` fields.
print(fmt.format("Start Creating index IVF_FLAT"))
index = {
    "index_type": "IVF_FLAT",
    "metric_type": "L2",
    "params": {"nlist": 128},
}

hello_milvus.create_index("embeddings", index)

################################################################################
# 5. search, query, and hybrid search
# After data were inserted into Milvus and indexed, you can perform:
# - search based on vector similarity
# - query based on scalar filtering(boolean, int, etc.)
# - hybrid search based on vector similarity and scalar filtering.
#

# Before conducting a search or a query, you need to load the data in `hello_milvus` into memory.
print(fmt.format("Start loading"))
hello_milvus.load()

# -----------------------------------------------------------------------------
# search based on vector similarity
print(fmt.format("Start searching based on vector similarity"))
vectors_to_search = entities[-1][-2:]
search_params = {
    "metric_type": "L2",
    "params": {"nprobe": 10},
}

start_time = time.time()
result = hello_milvus.search(vectors_to_search, "embeddings", search_params, limit=3, output_fields=["random"])
end_time = time.time()

for hits in result:
    for hit in hits:
        print(f"hit: {hit}, random field: {hit.entity.get('random')}")
print(search_latency_fmt.format(end_time - start_time))

# -----------------------------------------------------------------------------
# query based on scalar filtering(boolean, int, etc.)
print(fmt.format("Start querying with `random > 0.5`"))

start_time = time.time()
result = hello_milvus.query(expr="random > 0.5", output_fields=["random", "embeddings"])
end_time = time.time()

print(f"query result:\n-{result[0]}")
print(search_latency_fmt.format(end_time - start_time))

# -----------------------------------------------------------------------------
# pagination
r1 = hello_milvus.query(expr="random > 0.5", limit=4, output_fields=["random"])
r2 = hello_milvus.query(expr="random > 0.5", offset=1, limit=3, output_fields=["random"])
print(f"query pagination(limit=4):\n\t{r1}")
print(f"query pagination(offset=1, limit=3):\n\t{r2}")

# -----------------------------------------------------------------------------
# hybrid search
print(fmt.format("Start hybrid searching with `random > 0.5`"))

start_time = time.time()
result = hello_milvus.search(vectors_to_search, "embeddings", search_params, limit=3, expr="random > 0.5",
                             output_fields=["random"])
end_time = time.time()

for hits in result:
    for hit in hits:
        print(f"hit: {hit}, random field: {hit.entity.get('random')}")
print(search_latency_fmt.format(end_time - start_time))

###############################################################################
# 6. delete entities by PK
# You can delete entities by their PK values using boolean expressions.
ids = insert_result.primary_keys

expr = f'pk in ["{ids[0]}" , "{ids[1]}"]'
print(fmt.format(f"Start deleting with expr `{expr}`"))

result = hello_milvus.query(expr=expr, output_fields=["random", "embeddings"])
print(f"query before delete by expr=`{expr}` -> result: \n-{result[0]}\n-{result[1]}\n")

hello_milvus.delete(expr)

result = hello_milvus.query(expr=expr, output_fields=["random", "embeddings"])
print(f"query after delete by expr=`{expr}` -> result: {result}\n")

###############################################################################
# 7. drop collection
# Finally, drop the hello_milvus collection
print(fmt.format("Drop collection `hello_milvus`"))
utility.drop_collection("hello_milvus")

升级版

现在,让我们来看一下使用LangChain版本的代码。由于我们使用的是封装好的Milvus,所以我们需要一个嵌入模型。在这里,我们选择了HuggingFaceEmbeddings中的sensenova/piccolo-base-zh模型作为示例,当然你也可以选择其他模型,这里没有限制。只要能将其作为一个变量传递给LangChain定义的函数调用即可。

下面是一个简单的示例,包括数据库连接、插入数据、查询以及得分情况的定义:

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Milvus 


model_name = "sensenova/piccolo-base-zh"
embeddings = HuggingFaceEmbeddings(model_name=model_name) 

print("链接数据库")
vector_db = Milvus(
    embeddings,
    connection_args={"host": "localhost", "port": "19530"},
    collection_name="hello_milvus",
) 
print("简单传入几个值")
vector_db.add_texts(["12345678","789","努力的小雨是一个知名博主,其名下有公众号【灵墨AI探索室】,博客:稀土掘金、博客园、51CTO及腾讯云等","你好啊","我不好"])

print("查询前3个最相似的结果")
docs = vector_db.similarity_search_with_score("你好啊",3)

print("查看其得分情况,分值越低越接近")
for text in docs:
    print('文本:%s,得分:%s'%(text[0].page_content,text[1]))

image

注意,以上代码只是一个简单示例,具体的实现可能会根据你的具体需求进行调整和优化。

在langchain版本的代码中,如果你想要执行除了自己需要开启docker中的milvus容器之外的操作,还需要确保你拥有网络代理。这里不多赘述,因为HuggingFace社区并不在国内。

个人定制版

接下来,我们将详细了解如何调用openai模型来回答问题!

from dotenv import load_dotenv
from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate; 
from langchain import PromptTemplate
from langchain.chains import LLMChain 
from langchain.chat_models.openai import ChatOpenAI 
from langchain.schema import BaseOutputParser

# 加载env环境变量里的key值
load_dotenv()
# 格式化输出
class CommaSeparatedListOutputParser(BaseOutputParser):
    """Parse the output of an LLM call to a comma-separated list."""

    def parse(self, text: str):
        """Parse the output of an LLM call."""
        return text.strip().split(", ")
# 先从数据库查询问题解
docs = vector_db.similarity_search("努力的小雨是谁?")
doc = docs[0].page_content

chat = ChatOpenAI(model_name='gpt-3.5-turbo', temperature=0)
template = "请根据我提供的资料回答问题,资料: {input_docs}"
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

# chat_prompt.format_messages(input_docs=doc, text="努力的小雨是谁?")
chain = LLMChain(
    llm=chat,
    prompt=chat_prompt,
    output_parser=CommaSeparatedListOutputParser()
)
chain.run(input_docs=doc, text="努力的小雨是谁?")

当你成功运行完代码后,你将会得到你所期望的答案。如下图所示,这些答案将会展示在你的屏幕上。不然,如果系统不知道这些问题的答案,那它又如何能够给出正确的回答呢?

image

总结

通过本系列文章的学习,我们已经对个人或企业知识库有了一定的了解。尽管OpenAI已经提供了私有知识库的部署选项,但是其高昂的成本对于一些企业来说可能是难以承受的。无论将来国内企业是否会提供个人或企业知识库的解决方案,我们都需要对其原理有一些了解。无论我们的预算多少,都可以找到适合自己的玩法,因为不同预算的玩法也会有所不同。

相关实践学习
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
相关文章
|
7天前
|
机器学习/深度学习 人工智能 算法
【乐器识别系统】图像识别+人工智能+深度学习+Python+TensorFlow+卷积神经网络+模型训练
乐器识别系统。使用Python为主要编程语言,基于人工智能框架库TensorFlow搭建ResNet50卷积神经网络算法,通过对30种乐器('迪吉里杜管', '铃鼓', '木琴', '手风琴', '阿尔卑斯号角', '风笛', '班卓琴', '邦戈鼓', '卡萨巴', '响板', '单簧管', '古钢琴', '手风琴(六角形)', '鼓', '扬琴', '长笛', '刮瓜', '吉他', '口琴', '竖琴', '沙槌', '陶笛', '钢琴', '萨克斯管', '锡塔尔琴', '钢鼓', '长号', '小号', '大号', '小提琴')的图像数据集进行训练,得到一个训练精度较高的模型,并将其
19 0
【乐器识别系统】图像识别+人工智能+深度学习+Python+TensorFlow+卷积神经网络+模型训练
|
4天前
|
机器学习/深度学习 人工智能 算法
【服装识别系统】图像识别+Python+人工智能+深度学习+算法模型+TensorFlow
服装识别系统,本系统作为图像识别方面的一个典型应用,使用Python作为主要编程语言,并通过TensorFlow搭建ResNet50卷积神经算法网络模型,通过对18种不同的服装('黑色连衣裙', '黑色衬衫', '黑色鞋子', '黑色短裤', '蓝色连衣裙', '蓝色衬衫', '蓝色鞋子', '蓝色短裤', '棕色鞋子', '棕色短裤', '绿色衬衫', '绿色鞋子', '绿色短裤', '红色连衣裙', '红色鞋子', '白色连衣裙', '白色鞋子', '白色短裤')数据集进行训练,最后得到一个识别精度较高的H5格式模型文件,然后基于Django搭建Web网页端可视化操作界面,实现用户在界面中
20 1
【服装识别系统】图像识别+Python+人工智能+深度学习+算法模型+TensorFlow
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
人工智能平台PAI产品使用合集之如何配置cluster系统自动生成分布式参数
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
4天前
|
人工智能 自然语言处理 小程序
政务VR导航:跨界融合AI人工智能与大数据分析,打造全方位智能政务服务
政务大厅引入智能导航系统,解决寻路难、指引不足及咨询台压力大的问题。VR导视与AI助手提供在线预览、VR路线指引、智能客服和小程序服务,提高办事效率,减轻咨询台工作,优化群众体验,塑造智慧政务形象。通过线上线下结合,实现政务服务的高效便民。
18 0
政务VR导航:跨界融合AI人工智能与大数据分析,打造全方位智能政务服务
|
6天前
|
机器学习/深度学习 人工智能 运维
智能运维:利用人工智能优化IT基础设施管理
【6月更文挑战第30天】随着企业对信息技术的依赖性不断增强,传统的运维管理方法已无法满足现代业务的需求。智能运维(AIOps)作为一种新兴的运维模式,通过集成大数据、机器学习和自动化技术,旨在提高运维效率,减少系统故障时间,并提升用户体验。本文将探讨智能运维的核心概念、实施步骤及其对企业IT基础设施管理的积极影响,同时也会讨论在实际应用中可能遇到的挑战与解决方案。
21 2
|
3天前
|
机器学习/深度学习 人工智能 算法
【坚果识别】果实识别+图像识别系统+Python+计算机课设+人工智能课设+卷积算法
坚果识别系统,使用Python语言进行开发,通过TensorFlow搭建卷积神经网络算法模型,对10种坚果果实('杏仁', '巴西坚果', '腰果', '椰子', '榛子', '夏威夷果', '山核桃', '松子', '开心果', '核桃')等图片数据集进行训练,得到一个识别精度较高的模型文件,让后使用Django搭建Web网页端界面操作平台,实现用户上传一张坚果图片 识别其名称。
9 0
|
4天前
|
机器学习/深度学习 人工智能 监控
智能增强:人工智能在个性化学习中的应用
【7月更文挑战第3天】随着人工智能技术的飞速发展,教育领域正经历着一场革命。本文将探讨AI如何通过智能增强技术,实现个性化学习,从而提高教育质量和效率。我们将分析AI在识别学生需求、适应不同学习风格、提供实时反馈和调整教学内容方面的能力,并讨论这些技术对传统教育模式的影响,以及未来可能的发展方向。
11 0
|
5天前
|
机器学习/深度学习 人工智能 运维
智能化运维的演进之路:从自动化到人工智能
本文将探索智能化运维(AIOps)的发展脉络,从早期的脚本自动化到现今集成人工智能技术的高级阶段。文章将基于最新的行业报告、学术论文和案例研究,深入分析AIOps如何通过数据驱动的方法提升运维效率和预测性维护的能力,以及这一转变对IT运维专业人员技能要求的影响。
|
5天前
|
机器学习/深度学习 数据采集 人工智能
AI(人工智能)大模型:智能新突破与挑战
在人工智能的发展历程中,我们始终追求的是大模型的智能化。这包括对复杂环境的理解力、面对未知情况的泛化能力,以及在各种情况下的适应性。这些因素是衡量一个智能模型优秀与否的关键。而提升大模型在这些方面的表现,不仅能够推动人工智能的发展,更能够拓宽其应用的范围。因此,寻找并采取有效的策略,使大模型走向更加聪明,是我们在未来人工智能发展中必须要面对和解决的重要问题。
6 0
|
6天前
|
机器学习/深度学习 人工智能 算法
人工智能与创造力:探索AI在艺术创作中的角色
【6月更文挑战第30天】本文深入探讨了人工智能(AI)如何在艺术领域内重新定义创造力的概念。通过分析AI技术在绘画、音乐和文学创作中的应用案例,我们揭示了AI不仅能够模仿传统艺术形式,还能开创全新艺术风格的可能性。文章还讨论了AI艺术对知识产权法的挑战,以及公众对于由机器创造的艺术作品的接受度问题。