ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

langchain-chroma向量库和agents组件

langchain-chroma向量库和agents组件

定义函数, 演示: Indexes -> 索引向量数据库.

# 完整RAG前置4步逻辑: Load(加载各类知识库文件) -> Split(长文本切小块) -> Embed&Store(小块转向量,存到向量数据库) -> Retrieval(用户问题向量化,召回最匹配的知识库片段给大模型做参考)

def dm03_index_vector_db():

# 回顾: 完整RAG知识库构建流程: 加载txt文档 -> 文本分块 -> 向量化存入Chroma本地向量库 -> 相似度检索查询

from langchain_text_splitters import CharacterTextSplitter # 导入文本分割器

from langchain_chroma import Chroma # 轻量级本地向量数据库

from langchain_community.document_loaders import TextLoader # 导入纯文本加载器

from langchain_ollama import OllamaEmbeddings # 本地嵌入向量模型

# ---------------------------------- 步骤1: 加载本地txt知识库文档 ----------------------------------

# 1. 实例化txt加载器, 指定文件路径 和 编码.

loader = TextLoader('./data/pku.txt', encoding='utf8')

# 2. 读取文件, 返回包裹全文的Document对象列表

docs = loader.load()

print(f'docs: {docs}')

# ---------------------------------- 步骤2: 长文档切割分块 ----------------------------------

# 1. 初始化字符文本分割器.

# 参1: 分割符. 参2: 每块最大字符长度. 参3: 重叠字符长度.

text_splitter = CharacterTextSplitter(separator="\n\n", chunk_size=200, chunk_overlap=30)

# 2. 使用分割器, 对Document对象列表进行文本块切割, 生成多份小块Document对象.

split_docs = text_splitter.split_documents(docs)

print(f'split_docs: {split_docs}')

# ---------------------------------- 步骤3: 向量化并持久化存入Chroma向量库 ----------------------------------

# 1. 加载本地专用向量化模型mxbai-embed-large, 负责把文本转为数值向量.

embeddings = OllamaEmbeddings(model="mxbai-embed-large")

# 2. 新建/写入向量库: 自动对split_docs每一块文本生成向量, 存入本地向量数据库.

chromaDB = Chroma.from_documents(

documents=split_docs, # 分块后的文档列表

embedding=embeddings, # 向量化模型

persist_directory='./chromaDB' # 持久化文件夹, 向量, 元数据都会存在这里.

)

# 3.扩展说明: 如果向量库已经提前建好,数据已存入, 后续程序可直接加载使用, 无需重复向量化.

# chromaDB = Chroma(persist_directory='./chromaDB', embedding_function=embeddings)

# ---------------------------------- 步骤4: 相似度检索查询 ----------------------------------

# 1. 定义变量, 记录: 用户提问.

query = '1937年北京大学发生了什么?'

# 2. 获取与用户提问最相似的2个文本块.

# similarity_search(): 将问句向量化, 匹配库中距离最近的k条文本块.

result = chromaDB.similarity_search(query, k=2)

# 3. 打印结果.

print(f'result: {result}')

agents

Agent 概念

Agent(智能体)是一种能够感知环境、进行决策和执行动作的智能实体。不同于传统的人工智能,Agent 具备通过主动思考、调用工具去逐步完成给定目标的能力。

为什么要调用工具?

  • 因为大模型虽然非常强大,但是也具备一定的局限性,比如不能回答实时信息、处理数学逻辑问题仍然非常的初级等等。因此,可以借助第三方工具来辅助大模型的应用。

从大模型的角度来看,Agent其实就是基于大模型的语义理解和推理能力,让大模型拥有解决复杂问题时的任务规划能力,并调用外部工具来执行各种任务,利用向量数据库保留“记忆”的一个智能体。

负责思考, 理解 安排做事步骤 记前事
Agent = 大模型 + 任务规划 (Planning) + 使用外部工具执行任务 (Tools&Action) + 记忆
(Memory) Agent = 聪明的小助手, 能感知周围, 拿主意, 还能动手做事儿.
和传统AI不同 -> 它会自己琢磨, 用工具一步步把目标完成.
把Agent比作一个人的话, 他应该有大脑 (语义理解、存储记忆、推理规划、专业知识)、五官
(接收文本、视觉输入、听觉输入等)、四肢 (使用工具完成各种具体任务) 等主要部件
Agent = 人. 大脑 -> 大模型, 负责理解话, 记东西, 推理规则, 懂专业知识.
五官 -> 接收信息, 看文字, 图片, 听声音...
四肢 -> 用工具干活, 用外卖软件找吃的, 用地图找路

案例:

演示如何使用LangChain的Agent(代理)功能, 结合工具(例如: 维基百科查询, 数学计算...)完成复杂任务.

细节: 需要安装的包 -> 无需安装, 因为之前已经装过了.

pip install wikipedia

pip install numexpr

Agent相关解释:

概述:

Agent就是1个聪明的小助手, 能感知周围, 拿主意, 动手做事儿, 和传统AI不同, 它会自己琢磨, 用工具一步步把目标完成.

问: 为啥要用工具呢?

大模型存在一些弊端, 例如: 无法回答'实时的事儿', 处理数学题或者逻辑题也很初级...

问: Agent到底是啥?

从大模型的角度看, Agent靠的是'语言理解 + 推理能力'

Agent = 大模型(负责思考,理解) + 任务规划(安排做事儿步骤) + 用外部工具干活 + 记忆(记忆之前的事儿)

Agent的工作流程:

1. 用户提出任务.

2. Agent启动.

3. 大模型思考和决策(循环) -> 先思考, 然后判断要不要用工具.

4. 用户输出.

大白话解释:

你派活 -> 小助手整理需求给AI大模型 -> AI大模型判断用不用工具, 反复折腾直到把事儿做完 -> 小助手把结果给你

Agent的组成部分:

工具(Tools) + 长短期记忆(Memory) + 任务规划(Planning) + 执行(Action)

总结:

Agent就像个'会规划, 有记忆, 会用工具的助手', 把复杂的事儿办好.

"""

# ------------------------------------ step1: 查看LangChain全部内置工具名称 ------------------------------------

# 导包

from langchain_community.agent_toolkits.load_tools import get_all_tool_names

# 1. 调用函数, 获取所有官方封装好的工具名字列表.

results = get_all_tool_names()

# 2. 打印完整工具列表.

print(f'LangChain所有内置可加载工具名称: \n {results}')

# 3. 分割线.

print('♥️' * 30)

# ------------------------------------ step2: 构建带记忆, 双工具的LangChain Agent ------------------------------------

# 导包

from langchain_core.messages import HumanMessage # 用户消息封装类

from langgraph.checkpoint.memory import MemorySaver # 记忆检查点: 内存级存储对话历史, 实现多轮上下文记忆

from langchain.agents import create_agent # 创建Agent

from langchain_community.agent_toolkits.load_tools import load_tools # 加载工具

from langchain_openai import ChatOpenAI # 通用对话模型类, 兼容所有遵循OpenAI接口格式的大模型服务商.

import os # 读取系统环境变量, 存放密钥, 接口地址等敏感信息.


# 1. 初始化大模型实例.

model = ChatOpenAI(

# 大模型服务商兼容OpenAI的接口地址

base_url = os.environ.get('base_url', 'https://dashscope.aliyuncs.com/compatible-mode/v1'),

model='qwen-plus', # 模型名称

openai_api_key=os.environ.get('DASHSCOPE_API_KEY'), # 从环境变量中获取密钥

max_tokens=1000, # 限制单词模型回复最大Token数量

temperature=0 # 温度系数, 控制模型生成的随机性(越大越随机)

)

# 2. 初始化内存记忆存储对象 -> 内存检查点.

# 作用: 保存同1个thread_id下所有历史对话消息, 实现多轮上下文连贯回答.

# 缺点: 程序进程关闭后内存数据全部清空, 生产环境中可以换成 RedisCheckPointer 或者 PostgreCheckPointer...

memory = MemorySaver()

# 3. 批量加载业务所需工具.

# 工具1 'wikipedia' 联网访问维基百科, 查询客观百科知识 -> 默认: 需要搭梯子.

# 工具2 'llm-math' 独立数学计算工具...

tools = load_tools(['wikipedia', 'llm-math'], llm=model)

# 4. 创建Agent执行器核心对象.

# 参1 model: 决策大模型, 负责判断什么时候调用哪个工具, 解析工具返回结果, 整理最终回答.

# 参2 tools: 可供Agent调用的全部工具集合.

# 参3 checkpointer: 内存检查点, 存储对话历史, 实现多轮上下文连贯回答.

agent_executor = create_agent(model, tools, checkpointer=memory)

# 5. 会话管理配置参数, 相同thread_id -> 共享同一份对话记忆. 不同thread_id -> 完全隔离两套对话上下文.

config = {

"configurable": {"thread_id": "abc123"}

}

# 6. 流式执行(第1轮)用户提问.

for chunk in agent_executor.stream({"messages": [HumanMessage(content='计算一下300的25%是多少?')]}, config):

# 打印当前分片完整结构(可看到思考, 工具调用, 返回结果, 输出回答等不同节点数据. )

print(chunk)

# 打印分割线, 可读性更强.

print('-' * 30)

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进