本地大模型编程实战(14)初探智能体Agent(1)

embedded/2025/2/12 13:34:46/

文章目录

    • 了解 `Agent(智能体)`
      • `tool(工具)` 与 `Agent(智能体)` 的区别
      • `ReAct(Reasoning + Acting)`
      • `ReAct` 的核心思路
    • 准备
    • 建立矢量数据库
      • 数据文件
      • 处理本地矢量库的类
      • 嵌入文本
    • 创建 `Agent智能体`
    • 测试
      • 定义测试方法
      • 使用 `shaw/dmeta-embedding-zh` 和 `qwen2.5`
      • 文本嵌入和检索
    • 总结
    • 代码


在前面的文章中,我们了解了 LLM(大语言模型) 如何使用 tool(工具) ,现在我们开始进一步,初探 Agent(智能体) 的玩法。
其中的 tool(工具) 用于从矢量数据库中查询信息,这种方式在 RAG(Retrieval Augmented Generation,检索增强生成) 也很常用。在这种场景中,能否准确的查询出有用信息很关键,为此我们本次将使用多种大模型进行对比演练。包括:

  • 多语言通用 LLM: llma3.1 , deepseek-r1 , qwen2.5
  • 专用于嵌入检索的大模型: shaw/dmeta-embedding-zh , milkey/m3e , mxbai-embed-large , nomic-embed-text , all-minilm:33m

了解 Agent(智能体)

tool(工具)Agent(智能体) 的区别

工具往往用于大语言模型调用其它功能,比如:搜索、数据库查询、计算等;Agent(智能体) 是一个可以使用 LLM 处理复杂任务的智能体;它通常会决定:

  • 何时调用 tool(工具)
  • 选择哪个工具
  • 处理工具返回的结果

ReAct(Reasoning + Acting)

ReAct(Reasoning + Acting)是一种用于 Agent(智能体) 的决策方式,它结合了推理(Reasoning)和行动(Acting),让智能体能更灵活地思考和执行任务。
简单来说,ReAct智能体在做事情之前,先思考一下,然后再决定下一步行动,而不是盲目执行。

ReAct 的核心思路

  • 观察环境(Observations):获取当前任务或问题的信息。
  • 推理(Reasoning):分析当前信息,思考如何解决问题。
  • 执行行动(Acting):基于推理结果,采取具体的行动(比如调用工具、查询数据库、与用户交互等)。
  • 循环执行智能体会不断重复观察 → 推理 → 行动的过程,直到任务完成。

关于 ReAct 的更多内容,请参阅:ReACT Agent Model

准备

在正式开始撸代码之前,需要准备一下编程环境。

  1. 计算机
    本文涉及的所有代码可以在没有显存的环境中执行。 我使用的机器配置为:

    • CPU: Intel i5-8400 2.80GHz
    • 内存: 16GB
  2. Visual Studio Code 和 venv
    这是很受欢迎的开发工具,相关文章的代码可以在 Visual Studio Code 中开发和调试。 我们用 pythonvenv 创建虚拟环境, 详见:
    在Visual Studio Code中配置venv。

  3. Ollama
    Ollama 平台上部署本地大模型非常方便,基于此平台,我们可以让 langchain 使用 llama3.1qwen2.5deepseek 等各种本地大模型。详见:
    在langchian中使用本地部署的llama3.1大模型 。

建立矢量数据库

我们这里收集了一些动物的信息,并定义了通用的处理本地矢量数据的方法,方便后面对不同的模型进行对比测试。

将文本转化成矢量的过程称之为 嵌入 ,语义相近的文本转化的矢量之间的空间距离较短,所以在做矢量检索时,可以根据语义而不是关键词来查找相近的结果。

数据文件

我们这里使用一个简单的 csv 格式的数据文件,每一行是一种动物特征的说明,格式如下:

名称,学名,特点,作用
狗,Canis lupus familiaris,忠诚、聪明、社交性强,看家护院、导盲、搜救、警务、情感陪伴
猫,Felis catus,独立、高冷、善于捕鼠,消灭害鼠、陪伴、缓解压力

处理本地矢量库的类

这里简单封装了 Chroma 对文本进行嵌入处理的方法,供参考:

python">class LocalVectorDBChroma:"""使用Chroma在本地处理适量数据库"""def __init__(self,model_name,persist_directory,delimiter = ","):self._embedding = OllamaEmbeddings(model=model_name)self._persist_directory = persist_directoryself._delimiter = delimiterdef get_vector_store(self):return Chroma(persist_directory=self._persist_directory,embedding_function=self._embedding)def embed_documents_in_batches(self,documents,batch_size=3):"""按批次嵌入,可以显示进度。vectordb会自动持久化存储在磁盘。"""vectordb = Chroma(persist_directory=self._persist_directory,embedding_function=self._embedding)for i in tqdm(range(0, len(documents), batch_size), desc="嵌入进度"):batch = documents[i:i + batch_size]# 从文本块生成嵌入,并将嵌入存储在本地磁盘。vectordb.add_documents(batch)def embed_csv(self,src_file_path):loader = CSVLoader(file_path=src_file_path,csv_args={"delimiter": self._delimiter},autodetect_encoding=True)docs = loader.load()# 用于将长文本拆分成较小的段,便于嵌入和大模型处理。     text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)"""chunk_size: 每个文本块的最大长度/字符数chunk_overlap: 拆分的文本块之间重叠字符数"""texts = text_splitter.split_documents(docs) # 耗时较长,需要耐心等候...self.embed_documents_in_batches(texts)

建议切分文本的最小块长度大概应该是语义最聚焦的文字段落,在本文使用的 csv 文件中,每一行描述的是一种动物,其语义很集中,而且不到100个字。所以干脆就设定: chunk_size=100 。大概相当于没有切分,哈哈:)

嵌入文本

通过下面的方法,我们生成嵌入,并且将矢量数据存储在本地:

python">from common.MyVectorDB import LocalVectorDBChroma
def create_db(model_name):    """生成本地矢量数据库"""persist_directory = get_persist_directory(model_name)if os.path.exists(persist_directory):returndb = LocalVectorDBChroma(model_name,persist_directory)    db.embed_csv(src_file_path)

创建 Agent智能体

下面我们利用创建好的矢量数据库的内容,来回答问题。
Agent(智能体) 运行起来后,首先生成 tool_calls 其中包含检索参数,然后去数量数据库中检索出最相似的内容,最后基于检索出来的内容生成流畅的回答。

python">def ask_agent(embed_model_name,chat_modal_name,query):"""测试智能体"""persist_directory = get_persist_directory(embed_model_name)db = LocalVectorDBChroma(embed_model_name,persist_directory)# 基于Chroma 的 vector store 生成 检索器vector_store = db.get_vector_store()retriever = vector_store.as_retriever(search_type="similarity",search_kwargs={"k": 2},)# 将 检索器 包装为 工具tools = [retriever.as_tool(name="animal_info_retriever",description="查询动物的信息",)]llm = ChatOllama(model=chat_modal_name,temperature=0.1,verbose=True)agent = create_react_agent(llm, tools)# 显示智能体的详细内容for chunk in agent.stream({"messages": [("human", query)]}):print(chunk)print("----")

经过上述代码处理,检索矢量数据库 成为一个 工具,该工具的控制权交给了 Agent(智能体)

显然,这个智能体可以执行 RAG(Retrieval Augmented Generation,检索增强生成) 任务。

测试

我使用了不同的模型对该智能体进行了测试,使用 shaw/dmeta-embedding-zh 做嵌入和检索,使用 qwen2.5Agent(智能体) 效果貌似最好。

最近火出圈的 deepseekllama3.1qwen2.5 一样,不擅长做文本嵌入和检索,所以效果差;并且 langchain 对它的支持不好,执行 create_react_agent 时出错。

定义测试方法

python">def test_model(embed_model_name,chat_modal_name):print(f'\n---------------------{embed_model_name}-----------------------------')create_db(embed_model_name)query = "猪的学名是什么?它对人类有什么用处?"ask_agent(embed_model_name,chat_modal_name,query)query = "蜜蜂的特点是什么?它对人类社会有什么作用?"ask_agent(embed_model_name,chat_modal_name,query)

使用 shaw/dmeta-embedding-zhqwen2.5

看看输出内容:

  • 针对第一个问题:“猪的学名是什么?它对人类有什么用处?”的输出:
{'agent': {'messages': [AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-02-11T08:50:43.2931377Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3300051500, 'load_duration': 2325341200, 'prompt_eval_count': 170, 'prompt_eval_duration': 227000000, 'eval_count': 25, 'eval_duration': 409000000, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-69b92604-f8b4-47c1-b87b-b8fc1c80aa90-0', tool_calls=[{'name': 'animal_info_retriever', 'args': {'__arg1': '猪'}, 'id': '2fcf0f7d-7742-4e78-bc3a-198c17c2f6a7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 170, 'output_tokens': 25, 'total_tokens': 195})]}}
----
{'tools': {'messages': [ToolMessage(content="[Document(id='ce2ce384-0af6-4f18-a2b5-2c3a9e4efc6d', metadata={'row': 5, 'source': 'D:\\\\project\\\\programming-with-local-large-language-model\\\\server\\\\services\\\\practice\\\\assert/animals.csv'}, page_content='名称: 猪\\n学名: Sus scrofa domesticus\\n特点: 智商高,好奇心强,适应能力强\\n作用: 主要肉类来源,生物医学研究(猪心脏瓣膜移植)'), Document(id='c21cf91a-73d8-470f-a10a-2b297c37bd13', metadata={'row': 6, 'source': 'D:\\\\project\\\\programming-with-local-large-language-model\\\\server\\\\services\\\\practice\\\\assert/animals.csv'}, page_content='名 称: 鸡\\n学名: Gallus gallus domesticus\\n特点: 适应性强、繁殖快、能为人类提供大量食物\\n作用: 鸡蛋、鸡肉是全球最主要的蛋白质来源之一')]", name='animal_info_retriever', id='0c7a7414-94ab-4197-b48a-b87035adea92', tool_call_id='2fcf0f7d-7742-4e78-bc3a-198c17c2f6a7')]}}
----
{'agent': {'messages': [AIMessage(content='猪的学名为 Sus scrofa domesticus。猪对人类有很多用处,它们不仅是主要的肉类来源,还被用于生物医学研究中,例如猪心脏瓣膜移植等。', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-02-11T08:50:45.5121761Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1031134000, 'load_duration': 39932600, 'prompt_eval_count': 451, 'prompt_eval_duration': 48000000, 'eval_count': 42, 'eval_duration': 932000000, 'message': Message(role='assistant', content='猪的学名为 Sus scrofa domesticus。猪对人类有很多用处,它们不仅是主要的肉类来源,还被用于生物医学研究中,例如猪心脏瓣膜移植等。', images=None, tool_calls=None)}, id='run-9f3aa665-9fd8-4bdb-8f5e-9c5ebca0a3de-0', usage_metadata={'input_tokens': 451, 'output_tokens': 42, 'total_tokens': 493})]}}   
----

在第1行, 智能体推理出 tool_calls 内容为:

[{'name': 'animal_info_retriever', 'args': {'__arg1': '猪'}, 'id': '2fcf0f7d-7742-4e78-bc3a-198c17c2f6a7', 'type': 'tool_call'}]

可见:

  1. 智能体找对了重点,查 的相关内容。
  2. 在第2行,智能体调用了 工具方法,查询出两个最相关的文档:关于 ,很正确。
  3. 在第3行,智能体根据查询内容做了妥帖的回答。
  • 针对第二个问题:“蜜蜂的特点是什么?它对人类社会有什么作用?”的输出:
{'agent': {'messages': [AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-02-11T08:50:49.2508879Z', 'done': True, 'done_reason': 'stop', 'total_duration': 2965904700, 'load_duration': 28819600, 'prompt_eval_count': 168, 'prompt_eval_duration': 30000000, 'eval_count': 155, 'eval_duration': 2899000000, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-e4bb705d-1849-4ab7-968a-a78016266a36-0', tool_calls=[{'name': 'animal_info_retriever', 'args': {'__arg1': '蜜蜂'}, 'id': '640ef103-9ff9-4b17-b399-fc5df958a572', 'type': 'tool_call'}], usage_metadata={'input_tokens': 168, 'output_tokens': 155, 'total_tokens': 323})]}}
----
{'tools': {'messages': [ToolMessage(content="[Document(id='3f129e89-e9b5-4c4a-a626-f71773630bae', metadata={'row': 8, 'source': 'D:\\\\project\\\\programming-with-local-large-language-model\\\\server\\\\services\\\\practice\\\\assert/animals.csv'}, page_content='名称: 蜜蜂\\n学名: Apis mellifera\\n特点: 勤劳、复杂的社会结构,对生态系统至关重要\\n作用: 授粉(维持全球农业)、蜂蜜生产、人类健康(蜂胶、蜂毒疗法)'), Document(id='20c7070c-f9ef-4441-834f-08d3ed8900d0', metadata={'row': 9, 'source': 'D:\\\\project\\\\programming-with-local-large-language-model\\\\server\\\\services\\\\practice\\\\assert/animals.csv'}, page_content='名称: 老鼠\\n学名: Rattus spp.\\n特点: 繁殖快,适应力极强,人类生活的“影子伙伴”\\n作用: 害虫(传播疾病)、科学研究的重要实验动物(医学、心理学)')]", name='animal_info_retriever', id='6acbb57a-4115-46ff-97ad-c0b7bdca7b80', tool_call_id='640ef103-9ff9-4b17-b399-fc5df958a572')]}}
----
{'agent': {'messages': [AIMessage(content='根据提供的信息,蜜蜂具有以下特点和作用:\n\n**特点:**\n- 勤劳:蜜蜂是非常勤劳的昆虫。\n- 复杂的社会结构:蜜蜂有着复杂的社会组织形式。\n- 对生态系统至关重要:蜜蜂在生态系统中扮演着重要角色。\n\n**作用:**\n- 授粉(维持全球农业):蜜蜂是重要的授粉者,对农业生产具有重要作用。\n- 蜂蜜生产:蜜蜂可以产生蜂蜜等产品供人类食用和使用。\n- 人类健康(蜂胶、蜂毒疗法):蜜蜂的 副产品如蜂胶和蜂毒在传统医学中被用于治疗某些疾病。\n\n请注意,返回的信息中也列出了老鼠的相关信息,但您似乎对蜜蜂更感兴趣。如果您需要更多关于蜜蜂的信息或其他问题,请随时告诉我!', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-02-11T08:50:52.8271688Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3509658400, 'load_duration': 55295500, 'prompt_eval_count': 467, 'prompt_eval_duration': 45000000, 'eval_count': 166, 'eval_duration': 3382000000, 'message': Message(role='assistant', content='根据提供的信息,蜜蜂具有以下特点和作用:\n\n**特点:**\n- 勤劳:蜜蜂是非常勤劳的 昆虫。\n- 复杂的社会结构:蜜蜂有着复杂的社会组织形式。\n- 对生态系统至关重要:蜜蜂在生态系统中扮演着重要角色。\n\n**作用:**\n- 授粉(维持全球农业):蜜蜂是重要的授粉者,对农业生产具有重要作用。\n- 蜂蜜生 产:蜜蜂可以产生蜂蜜等产品供人类食用和使用。\n- 人类健康(蜂胶、蜂毒疗法):蜜蜂的副产品如蜂胶和蜂毒在传统医学中被用于治疗某些疾病。\n\n请注意,返回的信息中也列出了老鼠的相关信息,但您似乎对蜜蜂更感兴趣。 如果您需要更多关于蜜蜂的信息或其他问题,请随时告诉我!', images=None, tool_calls=None)}, id='run-611234fd-a1a9-4613-916c-0885228e9cbd-0', usage_metadata={'input_tokens': 467, 'output_tokens': 166, 'total_tokens': 633})]}}
----

显然,这一系列操作也很到位。

文本嵌入和检索

经过简单测试, llama3.1qwen2.5 驱动 智能体 都没有问题:它们都可以准确的推理出 tool_calls ,并可以妥善的组织语言回复。
主要的差别在于 嵌入 和 检索 的能力,我们分别跑一下这下模型,看看检索结果:

猪的学名是什么?它对人类有什么用处?蜜蜂的特点是什么?它对人类社会有什么作用?
shaw/dmeta-embedding-zh、鸡蜜蜂、老鼠
milkey/m3e、羊蜜蜂、猫
mxbai-embed-large、老鼠老鼠、蜜蜂
nomic-embed-text鸡、牛鸡、牛
all-minilm:33m马、猫马、蜜蜂
llama3.1、大象猪、蜜蜂
qwen2.5、猫猪、大象

经过上述简单对比,可见 shaw/dmeta-embedding-zhmilkey/m3e 做中文嵌入和检索最靠谱。

总结

通过上述编程演练,我们创建了一个可以查询本地知识库的智能体,这种方式也特别适合实现 RAG(Retrieval Augmented Generation,检索增强生成) 系统。
在本系统中,提供高质量回复的基础是能够根据语义准确的从矢量数据库中找到信息,我们发现,不同的模型在文本嵌入和矢量数据查询方面表现差别较大。

代码

本文涉及的所有代码以及相关资源都已经共享,参见:

  • github
  • gitee

为便于找到代码,程序文件名称最前面的编号与本系列文章的文档编号相同。

🪐感谢您观看,祝好运🪐


http://www.ppmy.cn/embedded/161602.html

相关文章

docker-compose暴露端口,但其他主机无法访问问题。

问题描述:docker-compose暴露端口,但其他主机无法访问问题。 排障思路: 执行命令:ss -antlp | grep 80,发现端口正常监听0.0.0.0:80(ps:如果是127.0.0.1:80则只能本机访问同区域网段服务器执行…

Log4j定制JSON格式日志输出

1.前言 log4j是Java中一个强大的日志记录框架,通过简单的配置便可以在程序中进行日志打印与记录。关于log4j博主最近碰到一个需求,需要将程序运行过程中的日志按给定的json模板输出,本文记录一下log4j如何配置json格式的日志打印。 2.日志配…

5.14.哈夫曼树

一.带权路径长度: 1.如结点3,从树的根到该结点的路径长度为3,该结点的权值为3,因此结点3的带权路径长度为3 * 39; 2.求树的带权路径长度举例: 二.哈夫曼树的构造: 1.结点下面的1,2&…

【前端】【面试】ref与reactive的区别

ref 与 reactive 的区别笔记 一、概述 在 Vue 3 的组合式 API 中,ref 和 reactive 是两个非常重要的响应式工具,它们都用于创建响应式数据,但在使用方式、适用场景和内部实现上存在一些区别。 二、基本使用方式 1. ref ref 用于创建一个…

Redis 集群工作原理? 如何通信?MOVED和ASKED 有什么区别

目录 Redis 集群工作原理 1. 数据分片 2. 节点角色 3. 自动故障转移 Redis 集群通信方式 1. Gossip 协议 2. TCP 通信 MOVED 和 ASK 错误的区别 1. MOVED 错误 2. ASK 错误 Redis 集群工作原理 1. 数据分片 Redis 集群采用哈希槽(Hash Slot)来实现数据的分片存储…

从词袋到Transformer:自然语言处理的演进与实战

自然语言处理(NLP)是人工智能领域中最具挑战性和吸引力的方向之一。从最早的规则系统到如今的深度学习模型,NLP技术的发展历程充满了创新与突破。本文将带你深入探讨NLP的核心技术演进,并通过代码和案例展示如何从简单的词袋模型过渡到强大的Transformer架构。 1. 词袋模型…

浅谈Deepseek MoE

文章目录 Deepseek MoE1. MoE的定义1.1 什么是MoE(Mixture of Experts)?1.2 传统MoE的架构1.2.1 专家网络(Experts)1.2.2 门控网络(Gating Network) 1.3 传统MoE的工作流程1.4 传统MoE的特点1.5…

Linux内核实时机制x - 实时性之中断响应优化

Linux内核实时机制x - 实时性之中断响应优化 在基于PREEMPT_RT的Linux实时系统,社区开发了一套测试工具集rt-test,用于测试实时系统的各种指标。 其中重点关注的指标有: 中断响应时间 Cyclitest信号混洗时间 sigwaittest死锁解除时间 ptsem…