Skip to main content

连接到特征库

 连接到特征库


特征库是传统机器学习中的一个概念,可确保输入模型的数据是最新且相关的。有关这方面的更多信息,请参阅此处。


在考虑将 LLM 应用程序投入生产时,这一概念极为重要。为了个性化 LLM 应用程序,您可能希望将 LLM 与特定用户的最新信息结合起来。特征库是保持数据新鲜度的绝佳方式,而 LangChain 则提供了将这些数据与 LLM 结合起来的简便方法。


在本笔记本中,我们将展示如何将提示模板连接到特征库。其基本思想是在提示模板中调用特征库来检索值,然后将这些值格式化到提示中。


盛宴


首先,我们将使用流行的开源特征库框架 Feast。


我们假设你已经执行了 README 中的入门步骤。我们将以入门中的示例为基础,创建 LLMChain,向特定驱动程序写入有关其最新统计数据的说明。


加载盛宴存储


同样,应根据 Feast README 中的说明进行设置


from feast import FeatureStore


# You may need to update the path depending on where you stored it

feast_repo_path = "../../../../../my_feature_repo/feature_repo/"

store = FeatureStore(repo_path=feast_repo_path)


提示


在这里,我们将设置一个自定义的 FeastPromptTemplate。该提示模板将输入一个驾驶员 ID,查找他们的统计数据,并将这些统计数据格式化为一个提示。


请注意,该提示模板的输入只有 driver_id,因为这是唯一一个用户定义的变量(所有其他变量都在提示模板内查找)。

from langchain.prompts import PromptTemplate, StringPromptTemplate

template = """Given the driver's up to date stats, write them note relaying those stats to them.

If they have a conversation rate above .5, give them a compliment. Otherwise, make a silly joke about chickens at the end to make them feel better


Here are the drivers stats:

Conversation rate: {conv_rate}

Acceptance rate: {acc_rate}

Average Daily Trips: {avg_daily_trips}


Your response:"""

prompt = PromptTemplate.from_template(template)


class FeastPromptTemplate(StringPromptTemplate):

    def format(self, **kwargs) -> str:

        driver_id = kwargs.pop("driver_id")

        feature_vector = store.get_online_features(

            features=[

                "driver_hourly_stats:conv_rate",

                "driver_hourly_stats:acc_rate",

                "driver_hourly_stats:avg_daily_trips",

            ],

            entity_rows=[{"driver_id": driver_id}],

        ).to_dict()

        kwargs["conv_rate"] = feature_vector["conv_rate"][0]

        kwargs["acc_rate"] = feature_vector["acc_rate"][0]

        kwargs["avg_daily_trips"] = feature_vector["avg_daily_trips"][0]

        return prompt.format(**kwargs)


prompt_template = FeastPromptTemplate(input_variables=["driver_id"])

print(prompt_template.format(driver_id=1001))


    Given the driver's up to date stats, write them note relaying those stats to them.

    If they have a conversation rate above .5, give them a compliment. Otherwise, make a silly joke about chickens at the end to make them feel better

    

    Here are the drivers stats:

    Conversation rate: 0.4745151400566101

    Acceptance rate: 0.055561766028404236

    Average Daily Trips: 936

    

    Your response:

在链中使用

现在我们可以在链中使用它,成功创建一个由功能存储支持的个性化链

from langchain.chat_models import ChatOpenAI

from langchain.chains import LLMChain

chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)

chain.run(1001)

    "Hi there! I wanted to update you on your current stats. Your acceptance rate is 0.055561766028404236 and your average daily trips are 936. While your conversation rate is currently 0.4745151400566101, I have no doubt that with a little extra effort, you'll be able to exceed that .5 mark! Keep up the great work! And remember, even chickens can't always cross the road, but they still give it their best shot."


Tecton


上面,我们展示了如何将流行的开源自管理功能商店 Feast 与 LangChain 结合使用。下面的示例将展示使用 Tecton 进行类似的集成。Tecton 是一个完全托管的功能平台,用于协调从转换到在线服务的整个 ML 功能生命周期,并提供企业级 SLA。


前提条件


Tecton 部署(在 https://tecton.ai 注册)

TECTON_API_KEY 环境变量设置为有效的服务账户密钥

定义和加载功能


我们将使用 Tecton 教程中的 user_transaction_counts 功能视图作为功能服务的一部分。为简单起见,我们只使用一个特征视图;不过,更复杂的应用程序可能需要更多特征视图来检索提示所需的特征。


user_transaction_metrics = FeatureService(
    name = "user_transaction_metrics",
    features = [user_transaction_counts]
)

上述功能服务预计将应用于实时工作区。在本例中,我们将使用 "prod "工作区。

import tecton

workspace = tecton.get_workspace("prod")
feature_service = workspace.get_feature_service("user_transaction_metrics")

提示

在这里,我们将设置一个自定义的 TectonPromptTemplate。该提示模板将接收一个用户 ID,查找他们的统计数据,并将这些统计数据格式化为一个提示。

请注意,这个提示模板的输入只有 user_id,因为这是唯一一个用户定义的变量(所有其他变量都在提示模板内查找)。

from langchain.prompts import PromptTemplate, StringPromptTemplate

template = """Given the vendor's up to date transaction stats, write them a note based on the following rules:

1. If they had a transaction in the last day, write a short congratulations message on their recent sales
2. If no transaction in the last day, but they had a transaction in the last 30 days, playfully encourage them to sell more.
3. Always add a silly joke about chickens at the end

Here are the vendor's stats:
Number of Transactions Last Day: {transaction_count_1d}
Number of Transactions Last 30 Days: {transaction_count_30d}

Your response:"""
prompt = PromptTemplate.from_template(template)

class TectonPromptTemplate(StringPromptTemplate):
    def format(self, **kwargs) -> str:
        user_id = kwargs.pop("user_id")
        feature_vector = feature_service.get_online_features(
            join_keys={"user_id": user_id}
        ).to_dict()
        kwargs["transaction_count_1d"] = feature_vector[
            "user_transaction_counts.transaction_count_1d_1d"
        ]
        kwargs["transaction_count_30d"] = feature_vector[
            "user_transaction_counts.transaction_count_30d_1d"
        ]
        return prompt.format(**kwargs)

prompt_template = TectonPromptTemplate(input_variables=["user_id"])

print(prompt_template.format(user_id="user_469998441571"))

    Given the vendor's up to date transaction stats, write them a note based on the following rules:
    
    1. If they had a transaction in the last day, write a short congratulations message on their recent sales
    2. If no transaction in the last day, but they had a transaction in the last 30 days, playfully encourage them to sell more.
    3. Always add a silly joke about chickens at the end
    
    Here are the vendor's stats:
    Number of Transactions Last Day: 657
    Number of Transactions Last 30 Days: 20326
    
    Your response:

在连锁店中使用

现在我们可以在连锁店中使用它,成功创建一个连锁店,在 Tecton 功能平台的支持下实现个性化定制

from langchain.chat_models import ChatOpenAI
from langchain.chains import LLMChain

chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)
chain.run("user_469998441571")

    'Wow, congratulations on your recent sales! Your business is really soaring like a chicken on a hot air balloon! Keep up the great work!'

功能表单

最后,我们将使用开源的企业级特征存储 Featureform 来运行相同的示例。Featureform 允许您与 Spark 或本地等基础架构协同工作,以定义特征转换。

初始化 Featureform

您可以按照 README 中的说明在 Featureform 中初始化转换和特征。

import featureform as ff

client = ff.Client(host="demo.featureform.com")

提示

在这里,我们将设置一个自定义功能表单提示模板(FeatureformPromptTemplate)。该提示模板将输入用户每次交易的平均支付金额。

请注意,该提示模板的输入仅为 avg_transaction,因为这是唯一由用户定义的变量(所有其他变量均在提示模板内查找)。

from langchain.prompts import PromptTemplate, StringPromptTemplate

template = """Given the amount a user spends on average per transaction, let them know if they are a high roller. Otherwise, make a silly joke about chickens at the end to make them feel better

Here are the user's stats:
Average Amount per Transaction: ${avg_transcation}

Your response:"""
prompt = PromptTemplate.from_template(template)

class FeatureformPromptTemplate(StringPromptTemplate):
    def format(self, **kwargs) -> str:
        user_id = kwargs.pop("user_id")
        fpf = client.features([("avg_transactions", "quickstart")], {"user": user_id})
        return prompt.format(**kwargs)

prompt_template = FeatureformPrompTemplate(input_variables=["user_id"])

print(prompt_template.format(user_id="C1410926"))

在链中使用

现在我们可以在一个链中使用它,成功创建一个由 Featureform 功能平台支持的实现个性化的链

from langchain.chat_models import ChatOpenAI
from langchain.chains import LLMChain

chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)

chain.run("C1410926")

Comments

Popular posts from this blog

Think in 2B SaaS

这数年2B SaaS创业经历,让我自己从一个对2B SaaS有着盲目疯狂热情的人,变的逐渐趋于冷静。如何推动建立一个健康的SaaS产品和公司,成了我特别想去思考和解决的问题。 这几年,个人和公司一直都是在野蛮生长,销售驱动的模型下,产品,销售,交付,客户成功都在疲于奔命完成财务业绩。在没有坚持跑出一套聚焦于SaaS领域,可以合力的运作体系下,争执和冲突便成了家常便饭。 销售往往因产品没有某个功能,吐槽产品不给力。因为研发不能按时做出一个客户要的功能,吐槽产品无能,因为找不到客户,所以开始盯着老客户的增购业绩,盯着传统实施项目规模带来的业绩收益。 交付因为销售的过度承诺,卖出产品没有的功能,或者实施过程中细节点产品不支持的能力,吐槽销售,吐槽研发,实施过程变得举步维艰。 CS因为交付质量,产品功能,系统服务的稳定性,导致客户关系紧张,出问题后花费大量时间灭火。或者处理因为bug带来的系统数据不一致的问题。在发生了集成对接的情况下,甚至要协调下游各个系统修复数据,带来的服务成本的增长。增购也就自然而然变得困难。 产研觉得产品功能自己都无法进行规划管理,总是被动的被销售和交付过程中客户的紧急需求干扰,仓促设计的结果就是应用架构设计上的疏忽,开发的bug,业务场景的缺失。 上述的过程,可能很多初始的SaaS创业团队都会碰到,特别是2B领域的。协同的不好,矛盾冲突屡屡发生,不产生合力的情况下,为了维持高业绩增长的要求,内部的负担愈发严重,跑的越来越慢,整体的服务质量情况却没有一个明显的提升。由此引发的各个职能的一线的员工的工作感受也越来越差。推诿,委屈,困惑,气忿等负面情绪也与日俱增。 因此,如何科学的构建一个可以上下协同的组织,如何管理需求,如何管理迭代,如何找到目标客户,如何快速的实施落地,如何更好的保持客户粘性,给客户带来持续不断的新鲜感,配合客户业务的发展需要,就需要进行一套科学的管理办法。无序和杂乱只会让增长越来越缓慢。

MAC Homebrew安装了zookeeper 但是stop时报错

执行下面的命令的时候报错,找不到对应路径下的pid文件。 zkserver stop /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Stopping zookeeper ... no zookeeper to stop (could not find file /usr/local/var/run/zookeeper/data/zookeeper_server.pid) 查了网上很多地方,很多人说是data路径中的空格问题,但是查了配置文件发现并不是。 错误信息里面说是pid文件找不到路径,所以,怀疑是读写权限或者是别的什么异常原因导致当时pid文件没有生成。 试着用sudo权限重新执行 sudo zkserver restart Password: /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Stopping zookeeper ... no zookeeper to stop (could not find file /usr/local/var/run/zookeeper/data/zookeeper_server.pid) /usr/bin/java ZooKeeper JMX enabled by default 结果在目录下找到了对应的pid文件。 查看pid文件内容,发现就是一个进程id。这时候考虑修改pid文件的内容,把当前停不下来的进程编号写进去。 然后重新执行了zkserver stop命令。 sudo zkserver stop /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Stopping zookeeper ... STOPPED 搞定...

FAISS Vector DB 学习笔记(一)

 1. 安装Faiss: 按照Faiss官方资源库提供的安装说明,确保你有必要的依赖和兼容的硬件(如果使用GPU加速)。 2. 2.准备好你的数据: Faiss使用密集向量工作,所以确保你的数据以浮点数组或矩阵的形式表示,其中每一行对应一个向量。确保你的向量的尺寸是一致的。 3. 导入必要的模块: 在你的Python脚本中,导入所需的Faiss模块: ``python import faiss import numpy as np ``` 4. 创建一个索引: 根据你的需要,选择适当的索引类型。下面是一个创建IndexFlatL2索引的例子: ```python d = 128  # Dimension of your vectors index = faiss.IndexFlatL2(d)  # Initialize the index ``` 你可以探索其他的索引类型,比如IndexIVFFlat或IndexHNSW,这取决于你愿意做出的折衷。 5. 为索引添加向量: 一旦你初始化了你的索引,使用`add'方法将你的向量添加到它里面。传入一个NumPy数组或一个兼容的数据结构: ``python vectors = np.random.random((1000, d)).astype('float32')  # Example vectors index.add(vectors)  # Add the vectors to the index ``` 6. 进行相似性搜索: 要为一个查询向量找到最近的邻居,可以使用`search`方法。传入查询向量和需要检索的近邻数量: ``python k = 5  # Number of nearest neighbors to retrieve query_vector = np.random.random((1, d)).astype('float32')  # Example query vector D, I = index.search(query_vector, k)  # Perform the search ``` 返回的`D`数组包含与最近的邻居的距离,`I`数组包含它们在原始数据集中的相应索引。 7. 自定义和优化: Faiss...