Skip to main content
Google El Carro Oracle Operator 提供了一种在 Kubernetes 中运行 Oracle 数据库的方式,是一个可移植、开源、 社区驱动、无供应商锁定的容器编排系统。El Carro 提供强大的声明式 API,用于全面一致的配置和部署,以及实时操作和监控。 借助 El Carro LangChain 集成,扩展 Oracle 数据库的能力,构建 AI 驱动的体验。
本指南介绍如何使用 El Carro LangChain 集成,通过 ElCarroLoaderElCarroDocumentSaver 保存、加载和删除 LangChain 文档。 该集成适用于任何 Oracle 数据库,无论其运行在何处。 GitHub 上了解更多关于该软件包的信息。 Open In Colab

开始之前

请完成 README 中的入门指南部分,以设置您的 El Carro Oracle 数据库。

🦜🔗 安装库

该集成位于独立的 langchain-google-el-carro 包中,需要单独安装。
pip install -qU langchain-google-el-carro

基本用法

设置 Oracle 数据库连接

填写以下变量,输入您的 Oracle 数据库连接详情。
# @title Set Your Values Here { display-mode: "form" }
HOST = "127.0.0.1"  # @param {type: "string"}
PORT = 3307  # @param {type: "integer"}
DATABASE = "my-database"  # @param {type: "string"}
TABLE_NAME = "message_store"  # @param {type: "string"}
USER = "my-user"  # @param {type: "string"}
PASSWORD = input("Please provide a password to be used for the database user: ")
如果您正在使用 El Carro,可以在 El Carro Kubernetes 实例的状态中找到主机名和端口值。 请使用您为 PDB 创建的用户密码。 示例输出:
kubectl get -w instances.oracle.db.anthosapis.com -n db
NAME   DB ENGINE   VERSION   EDITION      ENDPOINT      URL                DB NAMES   BACKUP ID   READYSTATUS   READYREASON        DBREADYSTATUS   DBREADYREASON

mydb   Oracle      18c       Express      mydb-svc.db   34.71.69.25:6021   ['pdbname']            TRUE          CreateComplete     True            CreateComplete

ElCarroEngine 连接池

ElCarroEngine 为您的 Oracle 数据库配置连接池,支持应用程序成功建立连接,并遵循行业最佳实践。
from langchain_google_el_carro import ElCarroEngine

elcarro_engine = ElCarroEngine.from_instance(
    db_host=HOST,
    db_port=PORT,
    db_name=DATABASE,
    db_user=USER,
    db_password=PASSWORD,
)

初始化表

通过 elcarro_engine.init_document_table(<table_name>) 初始化一个默认结构的表。表列为:
  • page_content(类型:text)
  • langchain_metadata(类型:JSON)
elcarro_engine.drop_document_table(TABLE_NAME)
elcarro_engine.init_document_table(
    table_name=TABLE_NAME,
)

保存文档

使用 ElCarroDocumentSaver.add_documents(<documents>) 保存 LangChain 文档。 要初始化 ElCarroDocumentSaver 类,您需要提供以下两项:
  1. elcarro_engine - ElCarroEngine 引擎的实例。
  2. table_name - Oracle 数据库中用于存储 LangChain 文档的表名。
from langchain_core.documents import Document
from langchain_google_el_carro import ElCarroDocumentSaver

doc = Document(
    page_content="Banana",
    metadata={"type": "fruit", "weight": 100, "organic": 1},
)

saver = ElCarroDocumentSaver(
    elcarro_engine=elcarro_engine,
    table_name=TABLE_NAME,
)
saver.add_documents([doc])

加载文档

使用 ElCarroLoader.load()ElCarroLoader.lazy_load() 加载 LangChain 文档。 lazy_load 返回一个生成器,仅在迭代时查询数据库。 要初始化 ElCarroLoader 类,您需要提供:
  1. elcarro_engine - ElCarroEngine 引擎的实例。
  2. table_name - Oracle 数据库中用于存储 LangChain 文档的表名。
from langchain_google_el_carro import ElCarroLoader

loader = ElCarroLoader(elcarro_engine=elcarro_engine, table_name=TABLE_NAME)
docs = loader.lazy_load()
for doc in docs:
    print("Loaded documents:", doc)

通过查询加载文档

除了从表中加载文档外,我们还可以选择从 SQL 查询生成的视图中加载文档。例如:
from langchain_google_el_carro import ElCarroLoader

loader = ElCarroLoader(
    elcarro_engine=elcarro_engine,
    query=f"SELECT * FROM {TABLE_NAME} WHERE json_value(langchain_metadata, '$.organic') = '1'",
)
onedoc = loader.load()
print(onedoc)
SQL 查询生成的视图可能与默认表的结构不同。在这种情况下,ElCarroLoader 的行为与从非默认结构的表加载相同。请参阅加载自定义页面内容和元数据的文档章节。

删除文档

使用 ElCarroDocumentSaver.delete(<documents>) 从 Oracle 表中删除一组 LangChain 文档。 对于具有默认结构(page_content, langchain_metadata)的表,删除条件为: 如果列表中存在某个 document,满足以下条件,则应删除对应的 row
  • document.page_content 等于 row[page_content]
  • document.metadata 等于 row[langchain_metadata]
docs = loader.load()
print("Documents before delete:", docs)
saver.delete(onedoc)
print("Documents after delete:", loader.load())

高级用法

加载自定义页面内容和元数据的文档

首先,我们准备一个非默认结构的示例表,并填充一些任意数据。
import sqlalchemy

create_table_query = f"""CREATE TABLE {TABLE_NAME} (
    fruit_id NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
    fruit_name VARCHAR2(100) NOT NULL,
    variety VARCHAR2(50),
    quantity_in_stock NUMBER(10) NOT NULL,
    price_per_unit NUMBER(6,2) NOT NULL,
    organic NUMBER(3) NOT NULL
)"""
elcarro_engine.drop_document_table(TABLE_NAME)

with elcarro_engine.connect() as conn:
    conn.execute(sqlalchemy.text(create_table_query))
    conn.commit()
    conn.execute(
        sqlalchemy.text(
            f"""
            INSERT INTO {TABLE_NAME} (fruit_name, variety, quantity_in_stock, price_per_unit, organic)
            VALUES ('Apple', 'Granny Smith', 150, 0.99, 1)
            """
        )
    )
    conn.execute(
        sqlalchemy.text(
            f"""
            INSERT INTO {TABLE_NAME} (fruit_name, variety, quantity_in_stock, price_per_unit, organic)
            VALUES ('Banana', 'Cavendish', 200, 0.59, 0)
            """
        )
    )
    conn.execute(
        sqlalchemy.text(
            f"""
            INSERT INTO {TABLE_NAME} (fruit_name, variety, quantity_in_stock, price_per_unit, organic)
            VALUES ('Orange', 'Navel', 80, 1.29, 1)
            """
        )
    )
    conn.commit()
如果仍使用 ElCarroLoader 的默认参数从此示例表加载 LangChain 文档, 则加载文档的 page_content 将是表的第一列, metadata 将由所有其他列的键值对组成。
loader = ElCarroLoader(
    elcarro_engine=elcarro_engine,
    table_name=TABLE_NAME,
)
loaded_docs = loader.load()
print(f"Loaded Documents: [{loaded_docs}]")
我们可以在初始化 ElCarroLoader 时,通过设置 content_columnsmetadata_columns 来指定要加载的内容和元数据。
  1. content_columns:要写入文档 page_content 的列。
  2. metadata_columns:要写入文档 metadata 的列。
例如,content_columns 中各列的值将以空格分隔的字符串拼接,作为加载文档的 page_content, 加载文档的 metadata 将只包含 metadata_columns 中指定列的键值对。
loader = ElCarroLoader(
    elcarro_engine=elcarro_engine,
    table_name=TABLE_NAME,
    content_columns=[
        "variety",
        "quantity_in_stock",
        "price_per_unit",
        "organic",
    ],
    metadata_columns=["fruit_id", "fruit_name"],
)
loaded_docs = loader.load()
print(f"Loaded Documents: [{loaded_docs}]")

保存带自定义页面内容和元数据的文档

要将 LangChain 文档保存到带有自定义元数据字段的表中, 我们需要先通过 ElCarroEngine.init_document_table() 创建这样的表, 并指定所需的 metadata_columns 列表。在此示例中, 创建的表将具有以下列:
  • content(类型:text):用于存储水果描述。
  • type(类型 VARCHAR2(200)):用于存储水果类型。
  • weight(类型 INT):用于存储水果重量。
  • extra_json_metadata(类型:JSON):用于存储水果的其他元数据信息。
我们可以通过 elcarro_engine.init_document_table() 使用以下参数创建表:
  1. table_name:Oracle 数据库中用于存储 LangChain 文档的表名。
  2. metadata_columnssqlalchemy.Column 列表,指定所需的元数据列。
  3. content_column:存储 LangChain 文档 page_content 的列名。默认值:"page_content", "VARCHAR2(4000)"
  4. metadata_json_column:存储 LangChain 文档额外 JSON metadata 的列名。默认值:"langchain_metadata", "VARCHAR2(4000)"
elcarro_engine.drop_document_table(TABLE_NAME)
elcarro_engine.init_document_table(
    table_name=TABLE_NAME,
    metadata_columns=[
        sqlalchemy.Column("type", sqlalchemy.dialects.oracle.VARCHAR2(200)),
        sqlalchemy.Column("weight", sqlalchemy.INT),
    ],
    content_column="content",
    metadata_json_column="extra_json_metadata",
)
使用 ElCarroDocumentSaver.add_documents(<documents>) 保存文档。如示例所示:
  • document.page_content 将保存到 content 列。
  • document.metadata.type 将保存到 type 列。
  • document.metadata.weight 将保存到 weight 列。
  • document.metadata.organic 将以 JSON 格式保存到 extra_json_metadata 列。
doc = Document(
    page_content="Banana",
    metadata={"type": "fruit", "weight": 100, "organic": 1},
)

print(f"Original Document: [{doc}]")

saver = ElCarroDocumentSaver(
    elcarro_engine=elcarro_engine,
    table_name=TABLE_NAME,
    content_column="content",
    metadata_json_column="extra_json_metadata",
)
saver.add_documents([doc])

loader = ElCarroLoader(
    elcarro_engine=elcarro_engine,
    table_name=TABLE_NAME,
    content_columns=["content"],
    metadata_columns=[
        "type",
        "weight",
    ],
    metadata_json_column="extra_json_metadata",
)

loaded_docs = loader.load()
print(f"Loaded Document: [{loaded_docs[0]}]")

删除带自定义页面内容和元数据的文档

我们也可以通过 ElCarroDocumentSaver.delete(<documents>) 从带有自定义元数据列的表中删除文档。删除条件为: 如果列表中存在某个 document,满足以下条件,则应删除对应的 row
  • document.page_content 等于 row[page_content]
  • 对于 document.metadata 中的每个元数据字段 k
    • document.metadata[k] 等于 row[k]document.metadata[k] 等于 row[langchain_metadata][k]
  • row 中没有 document.metadata 中不存在的额外元数据字段。
loader = ElCarroLoader(elcarro_engine=elcarro_engine, table_name=TABLE_NAME)
saver.delete(loader.load())
print(f"Documents left: {len(loader.load())}")

更多示例

请参阅 demo_doc_loader_basic.pydemo_doc_loader_advanced.py 获取完整的代码示例。