Bootstrap

5.tree of thought 源码 (prompts 类)

本教程将介绍prompts类, 以及相关的测试案例。

1. 导入必要的库

首先,导入一些必要的库:

import json
from textwrap import dedent
from typing import List

from langchain_core.output_parsers import BaseOutputParser
from langchain_core.prompts import PromptTemplate

from langchain_experimental.tot.thought import ThoughtValidity

2. 定义思维链提示模板

接下来,定义一个用于生成思维链提示的函数:

def get_cot_prompt() -> PromptTemplate:
    """获取思维链(CoT)的提示模板。"""

    return PromptTemplate(
        template_format="jinja2",
        input_variables=["problem_description", "thoughts"],
        template=dedent(
            """
            You are an intelligent agent that is generating one thought at a time in
            a tree of thoughts setting.

            PROBLEM 
            
            {{problem_description}}
            
            {% if thoughts %}
            THOUGHTS
            
            {% for thought in thoughts %}
            {{ thought }}
            {% endfor %}
            {% endif %}
            
            Let's think step by step.
            """
        ).strip(),
    )

使用思维链提示模板

使用定义好的模板来生成具体的提示:

cot_prompt = get_cot_prompt()
problem_description = "Find the largest prime number less than 100."
thoughts = [
    "The largest prime number less than 100 is less than 100.",
    "Prime numbers are divisible only by 1 and themselves."
]
cot_prompt_result = cot_prompt.format(problem_description=problem_description, thoughts=thoughts)

print("Chain of Thought Prompt:")
print(cot_prompt_result)

输出结果如下:

Chain of Thought Prompt:
You are an intelligent agent that is generating one thought at a time in
a tree of thoughts setting.

PROBLEM 

Find the largest prime number less than 100.


THOUGHTS


The largest prime number less than 100 is less than 100.

Prime numbers are divisible only by 1 and themselves.



Let's think step by step.

3. 定义 JSON 列表输出解析器

为了解析模型输出的 JSON 格式数据,定义一个输出解析器:

class JSONListOutputParser(BaseOutputParser):
    """解析 PROPOSE_PROMPT 响应的输出。"""

    @property
    def _type(self) -> str:
        return "json_list"

    def parse(self, text: str) -> List[str]:
        """解析 LLM 调用的输出。"""

        json_string = text.split("```json")[1].strip().strip("```").strip()
        try:
            return json.loads(json_string)
        except json.JSONDecodeError:
            return []

使用 JSON 列表输出解析器

使用这个解析器来解析模型输出的 JSON 数据:

llm_response = """
```json
[
    "Verify divisibility by all numbers less than sqrt(n).",
    "Use a sieve algorithm to find all primes.",
    "Iterate from 99 downward until a prime is found."
]
```"""

output_parser = JSONListOutputParser()
parsed_output = output_parser.parse(llm_response)
print("\nParsed JSON List Output:")
print(parsed_output)

输出结果如下:

Parsed JSON List Output:
['Verify divisibility by all numbers less than sqrt(n).', 'Use a sieve algorithm to find all primes.', 'Iterate from 99 downward until a prime is found.']

4. 定义提议提示模板

接下来,定义一个用于生成提议提示的函数:

def get_propose_prompt() -> PromptTemplate:
    """获取 PROPOSE_PROMPT 链的提示模板。"""

    return PromptTemplate(
        template_format="jinja2",
        input_variables=["problem_description", "thoughts", "n"],
        output_parser=JSONListOutputParser(),
        template=dedent(
            """
                You are an intelligent agent that is generating thoughts in a tree of
                thoughts setting.
                
                The output should be a markdown code snippet formatted as a JSON list of
                strings, including the leading and trailing "```json" and "```":
                
                ```json
                [
                "<thought-1>",
                "<thought-2>",
                "<thought-3>"
                ]
                ```
                
                PROBLEM
                
                {{ problem_description }}
                
                {% if thoughts %}
                VALID THOUGHTS
                
                {% for thought in thoughts %}
                {{ thought }}
                {% endfor %}
                
                Possible next {{ n }} valid thoughts based on the last valid thought:
                {% else %}
                
                Possible next {{ n }} valid thoughts based on the PROBLEM:
                {%- endif -%}
                """
        ).strip(),
    )

使用提议提示模板

我们可以使用定义好的模板来生成具体的提议提示:

propose_prompt = get_propose_prompt()
thoughts_for_proposal = [
    "Prime numbers less than 100 are ...",
    "Next step is ..."
]
propose_prompt_result = propose_prompt.format(
    problem_description=problem_description,
    thoughts=thoughts_for_proposal,
    n=3
)

print("\nPropose Prompt:")
print(propose_prompt_result)

输出结果如下:

Propose Prompt:
You are an intelligent agent that is generating thoughts in a tree of
thoughts setting.

The output should be a markdown code snippet formatted as a JSON list of
strings, including the leading and trailing "```json" and "```":

```json
[
"<thought-1>",
"<thought-2>",
"<thought-3>"
]  ```

PROBLEM

Find the largest prime number less than 100.


VALID THOUGHTS


Prime numbers less than 100 are ...

Next step is ...


Possible next 3 valid thoughts based on the last valid thought:

5. 定义检查器输出解析器

为了验证思维链中的各个步骤,我们定义一个检查器输出解析器:

class CheckerOutputParser(BaseOutputParser):
    """解析并检查语言模型的输出。"""

    def parse(self, text: str) -> ThoughtValidity:
        """解析语言模型的输出。"""
        text = text.upper()
        if "INVALID" in text:
            return ThoughtValidity.INVALID
        elif "INTERMEDIATE" in text:
            return ThoughtValidity.VALID_INTERMEDIATE
        elif "VALID" in text:
            return ThoughtValidity.VALID_FINAL
        else:
            return ThoughtValidity.INVALID

    @property
    def _type(self) -> str:
        return "tot_llm_checker_output"

定义检查器提示模板

定义一个检查器提示模板:

CHECKER_PROMPT = PromptTemplate(
    input_variables=["problem_description", "thoughts"],
    template=dedent(
        """
        You are an intelligent agent, validating thoughts of another intelligent agent.

        PROBLEM 
        
        {problem_description}

        THOUGHTS
        
        {thoughts}

        Evaluate the thoughts and respond with one word.

        - Respond VALID if the last thought is a valid final solution to the
        problem.
        - Respond INVALID if the last thought is invalid.
        - Respond INTERMEDIATE if the last thought is valid but not the final
        solution to the problem.

        This chain of thoughts is"""
    ).strip(),
    output_parser=CheckerOutputParser(),
)

使用检查器提示模板和解析器

使用定义好的模板和解析器来验证思维链中的各个步骤:

problem_description = "Find the largest prime number less than 100."
thoughts = [
    "The largest prime number less than 100 is less than 100.",
    "Prime numbers are divisible only by 1 and themselves."
]
checker_prompt = CHECKER_PROMPT.format(
    problem_description=problem_description,
    thoughts="\n".join(thoughts)
)

print("\nChecker Prompt:")
print(checker_prompt)

输出结果如下:

Checker Prompt:
You are an intelligent agent, validating thoughts of another intelligent agent.

PROBLEM 

Find the largest prime number less than 100.

THOUGHTS

The largest prime number less than 100 is less than 100.
Prime numbers are divisible only by 1 and themselves.

Evaluate the thoughts and respond with one word.

- Respond VALID if the last thought is a valid final solution to the
problem.
- Respond INVALID if the last thought is invalid.
- Respond INTERMEDIATE if the last thought is valid but not the final
solution to the problem.

This chain of thoughts is

模拟 LLM 响应并解析

模拟一个 LLM 响应并使用解析器来验证思维链的有效性:

# 模拟 LLM 响应
llm_checker_response = "INTERMEDIATE"

checker_parser = CHECKER_PROMPT.output_parser
validity = checker_parser.parse(llm_checker_response)
print("\nThought Validity:")
print(validity)

输出结果如下:

Thought Validity:
ThoughtValidity.VALID_INTERMEDIATE

参考链接:https://github.com/langchain-ai/langchain-experimental/blob/main/libs/experimental/langchain_experimental/tot/prompts.py

如果有任何问题,欢迎在评论区提问。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;