组件一 :Prompts(终)

62 阅读4分钟

上节我们说到公共模板:

:::tips instruction:

template + partial_variables

context:

并没有在公用模板中体现,目前调用的都是模型本身的知识库,并没有提供给模型额外的知识来源

prompt input:

input_variables

output indicator:

并没有在公用模板中体现,目前未指定模型的引导词

:::

chat模板在公共模板的基础上,在context方面增加了额外知识,但这个额外知识是通过用户询问的方式得到的。不可避免地,知识量和贴合度都很低,但是导向性比较高,通过一次又一次的提问,模型会被导向你的问题。

但是往往在调用模型的过程中,我们需要的不是给模型一个清晰的,和“我们想的”一样的问题。而是模型不够“聪明”,它理解不了你的问题,或是它能理解你的问题,但是它的知识库中不包含你这个问题的相关知识。

好比是你问你的英语老师:“如何平衡指令流水线设计中结构相关、数据相关和控制相关三者的影响”。你的问题很明晰(其实这不算个严格意义上的“问题”,应该算“讨论”),但是英语老师因为没有相应的知识储备,难以回答你的问题。

这个时候就对 context 提出了更高的要求:你提供的context需要有更高的知识密度,更高的问题相关性和贴合度。

langchain为了解决这个问题,在公用模板上特化了context的部分,也就是我们今天要着重描写的FewShotPromptTemplate。

# 1. 创建一些示例
samples = [
        {
            "state": "难过",
            "coquetry": "主人不要难过喵~乖猫猫给主人舔舔眼泪喵~"
        },
        {
            "state": "开心",
            "coquetry": "主人开心喵~主人开心猫猫也开心喵~"
        },
        {
            "state": "懊恼",
            "coquetry": "主人不要懊恼喵~猫猫跟主人贴贴喵~"
        }
    ]

__import__("pysqlite3")
import sys

sys.modules["sqlite3"] = sys.modules.pop("pysqlite3")

# 2. 创建一个提示模板
from langchain.prompts.prompt import PromptTemplate

template = """
            主人状态:{state}\n
            撒娇内容:{coquetry}\n
    """
prompt_sample = PromptTemplate(
    input_variable=["state", "coquetry"],
    template=template,
)
print(prompt_sample.format(**samples[0]))

# 3. 创建一个FewShotPromptTemplate对象
from langchain.prompts.few_shot import FewShotPromptTemplate

prompt = FewShotPromptTemplate(
    examples=samples,
    example_prompt=prompt_sample,
    suffix="主人状态:{state}",
    input_variables=["state"],
)
print(prompt.format(state="愤怒"))

# 4. 把提示传递给大模型
import os

# os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model=os.environ.get("LLM_MODELEND"),
)
result = model(prompt.format(state="愤怒"))
print(result)

# 5. 使用示例选择器
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain_community.vectorstores import Chroma

# 初始化Embedding类
from volcenginesdkarkruntime import Ark
from typing import List, Any
from langchain.embeddings.base import Embeddings
from langchain.pydantic_v1 import BaseModel


class DoubaoEmbeddings(BaseModel, Embeddings):
    client: Ark = None
    api_key: str = ""
    model: str

    def __init__(self, **data: Any):
        super().__init__(**data)
        if self.api_key == "":
            self.api_key = os.environ["OPENAI_API_KEY"]
        self.client = Ark(
            base_url=os.environ["OPENAI_BASE_URL"],
            api_key=self.api_key
        )

    def embed_query(self, text: str) -> List[float]:
        """
        生成输入文本的 embedding.
        Args:
            texts (str): 要生成 embedding 的文本.
        Return:
            embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.
        """
        embeddings = self.client.embeddings.create(model=self.model, input=text)
        return embeddings.data[0].embedding

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        return [self.embed_query(text) for text in texts]

    class Config:
        arbitrary_types_allowed = True


# 初始化示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
    samples,
    DoubaoEmbeddings(
        model=os.environ.get("EMBEDDING_MODELEND"),
    ),
    Chroma,
    k=1,
)

# 创建一个使用示例选择器的FewShotPromptTemplate对象
prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=prompt_sample,
    suffix="主人状态: {state}",
    input_variables=["state"],
)
print(prompt.format(flower_type="愤怒"))

:::tips 主人状态:难过

撒娇内容:主人不要难过喵乖猫猫给主人舔舔眼泪喵

主人状态:难过

撒娇内容:主人不要难过喵乖猫猫给主人舔舔眼泪喵

主人状态:开心

撒娇内容:主人开心喵主人开心猫猫也开心喵

主人状态:懊恼

撒娇内容:主人不要懊恼喵猫猫跟主人贴贴喵

主人状态:愤怒

result = model(prompt.format(state="愤怒"))

content='主人不要愤怒喵猫猫给主人顺顺毛喵' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 94, 'total_tokens': 107}, 'model_name': 'Doubao-pro-32k', 'system_fingerprint': '', 'finish_reason': 'stop', 'logprobs': None} id='run-60c6da38-dda3-4e5f-8139-4238365f63d5-0' usage_metadata={'input_tokens': 94, 'output_tokens': 13, 'total_tokens': 107}

:::

这是示例代码,下面我将针对示例代码给出相关讲解:

:::tips 通过注释,我们不难看出这段代码共分为五步:

  1. 创建一些示例,即我们给出的额外知识
  2. 通过公有模板创建相关示例的格式的模板对象
  3. 通过第一步创建的示例和第二步创建的模板对象来构造FewShotPromptTemplate对象
  4. 调用模型获得输出
  5. 创建示例选择器来筛选示例

这是很简单接口调用,现在让我们一起调教小猫娘吧。