天天看點

在langchain中使用帶簡短知識内容的prompt template

作者:flydean程式那些事

簡介

langchain中有個比較有意思的prompt template叫做FewShotPromptTemplate。

他是這句話的簡寫:”Prompt template that contains few shot examples.”

什麼意思呢?就是說在Prompt template帶了幾個比較簡單的例子。然後把這些例子發送給LLM,作為簡單的上下文環境,進而為LLM提供額外的一些關鍵資訊。

這種few shot examples非常有用,如果你希望LLM可以基于你提供的prompt中的内容進行回答的時候,就需要用到這個東西了。

你可以把Few-shot prompt templates看做是簡單的知識庫,後面我們會具體講解如何搭建自己的知識庫。

現在先提前了解一下它的魅力吧。

帶few shot examples的例子

加入現在我要問chatgpt這樣一個問題:

請問工具人的代表作是什麼?
           

因為這裡的工具人是我虛拟出來的一個人,真實并不存在,是以chatgpt的回答可能是下面這樣的:

工具人的代表作是邁克爾·佩拉的《開膛手傑克》。
           

因為chatgpt對不會的東西可能會亂回答,是以上面的答案是在合理範圍之内的。

那麼怎麼才能讓chatgpt按照我們虛構的内容進行回答呢?

答案就是在prompt中提供有用的資訊,比如下面這樣子:

問題: 請幫忙描述下古龍?
回答: 姓名:古龍,出生日期:1937年,代表作:《楚留香傳奇系列》、《陸小鳳系列》、《蕭十一郎系列》

問題: 請幫忙描述下金庸?
回答: 姓名:金庸,出生日期:1924年,代表作:《射雕英雄傳》、《神雕俠侶》、《天龍八部》

問題: 請幫忙描述下工具人?
回答: 姓名:工具人,出生日期:1988年,代表作:《工具人傳奇》、《工具人上班》、《工具人睡覺》

問題: 請問工具人的代表作是什麼?
           

下面是chatgpt的回答:

工具人的代表作是《工具人傳奇》、《工具人上班》和《工具人睡覺》。
           

是以大家想到了什麼?

沒錯,就是可以使用prompt中的資訊做知識庫,讓chatgpt從這個給定的知識庫中查詢出有用的東西,然後再用自己的語言組織起來,傳回給使用者。

在langchain中使用FewShotPromptTemplate

實際上,上面的問題和答案都是promot内容的一部分,是以可以儲存在PromptTemplate中。

而langchain有與之對應的專門的一個類叫做FewShotPromptTemplate。

上面的問答,其實可以儲存在一個json數組中,然後再在FewShotPromptTemplate中使用:

from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate

examples = [
  {
    "question": "請幫忙描述下古龍?",
    "answer": 
"""
姓名:古龍,出生日期:1937年,代表作:《楚留香傳奇系列》、《陸小鳳系列》、《蕭十一郎系列》
"""
  },
  {
    "question": "請幫忙描述下金庸?",
    "answer": 
"""
姓名:金庸,出生日期:1924年,代表作:《射雕英雄傳》、《神雕俠侶》、《天龍八部》
"""
  },
  {
    "question": "請幫忙描述下工具人?",
    "answer":
"""
姓名:工具人,出生日期:1988年,代表作:《工具人傳奇》、《工具人上班》、《工具人睡覺》
"""
  }
]
           

首先我們來看一下FewShotPromptTemplate中都有哪些屬性:

examples: Optional[List[dict]] = None
    """Examples to format into the prompt.
    Either this or example_selector should be provided."""

    example_selector: Optional[BaseExampleSelector] = None
    """ExampleSelector to choose the examples to format into the prompt.
    Either this or examples should be provided."""

    example_prompt: PromptTemplate
    """PromptTemplate used to format an individual example."""

    suffix: str
    """A prompt template string to put after the examples."""

    input_variables: List[str]
    """A list of the names of the variables the prompt template expects."""

    example_separator: str = "\n\n"
    """String separator used to join the prefix, the examples, and suffix."""

    prefix: str = ""
    """A prompt template string to put before the examples."""

    template_format: str = "f-string"
    """The format of the prompt template. Options are: 'f-string', 'jinja2'."""

    validate_template: bool = True
    """Whether or not to try validating the template."""
           

其中examples和example_selector是可選的,其他的都是必須的。

example_prompt是用來格式化一個特定example的PromptTemplate。

如下所示:

example_prompt = PromptTemplate(input_variables=["question", "answer"], template="問題: {question}\n 回答:{answer}")

print(example_prompt.format(**examples[0]))
           
問題: 請幫忙描述下古龍?
回答: 姓名:古龍,出生日期:1937年,代表作:《楚留香傳奇系列》、《陸小鳳系列》、《蕭十一郎系列》
           

上面代碼中,我們使用PromptTemplate對隊列中的資料進行了格式化。

有了examples和example_prompt,我們就可以建構FewShotPromptTemplate了:

prompt = FewShotPromptTemplate(
    examples=examples, 
    example_prompt=example_prompt, 
    suffix="問題: {input}", 
    input_variables=["input"]
)

print(prompt.format(input="請問工具人的代表作是什麼?"))
           

這裡輸出的内容和我們最開始的内容是一樣的。

使用ExampleSelector

在上面的例子中,我們實際上是把所有的shot examples都送出給了大語言模型,但實際上并不是必須的。因為有些examples跟問題是沒有關聯關系的。

是以langchain給我們提供了一個類叫做ExampleSelector,可以通過這個selector來選擇跟我們問題相關的一些examples,進而減少不必要的内容傳輸。

這裡我們使用SemanticSimilarityExampleSelector,它的作用是根據語義的相似度來選擇examples:

from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings


example_selector = SemanticSimilarityExampleSelector.from_examples(
    # 要選擇的examples
    examples,
    # embedding用來判斷文本的相似度
    OpenAIEmbeddings(),
    # 向量資料庫,用來存儲embeddings
    Chroma,
    # 最終要選擇的長度
    k=1
)

# 選擇最為相似的作為輸入
question = "請問工具人的代表作是什麼?"
selected_examples = example_selector.select_examples({"question": question})
print(f"下面是和這個問題最相似的examples: {question}")
for example in selected_examples:
    print("\n")
    for k, v in example.items():
        print(f"{k}: {v}")
           

最後,我們同樣的把ExampleSelector和FewShotPromptTemplate結合起來一起使用:

prompt = FewShotPromptTemplate(
    example_selector=example_selector, 
    example_prompt=example_prompt, 
    suffix="問題: {input}", 
    input_variables=["input"]
)

print(prompt.format(input="請問工具人的代表作是什麼?"))
           

總結

如果你有一些簡單的内容需要提供給大語言模型,那麼可以使用這個方式。但是如果你有很多内容的話,比如知識庫。這種實作就處理不了了。那麼如何建構一個知識庫應用呢?我們後續分享。