提示词模板
Outlines 提供了一种强大的领域特定语言,用于编写和管理提示词,我们称之为 提示词函数。提示词函数是 Python 函数,其文档字符串中包含提示词模板,其参数对应于提示词中使用的变量。调用时,提示词函数会返回使用参数值渲染后的模板。
提示词函数的目的是解决提示词设计中的几个常见问题:
- 快速构建复杂的提示词容易导致代码混乱。这个问题已经在 Web 开发社区通过模板化得到了解决,为什么不在这里使用它呢?
- 组合提示词很困难。为什么不直接组合函数呢?
- 将提示词与代码分离。函数封装允许提示词与代码之间实现清晰的分离。此外,就像任何函数一样,提示词函数可以从其他模块导入。
Outlines 使用 Jinja 模板引擎 来渲染提示词,这使得轻松组合复杂的提示词成为可能。
提示词渲染
提示词函数在渲染提示词方面有其自己的约定。这些约定旨在避免常见的提示词错误,但如果您正在进行一些不寻常的操作,可能会产生意想不到的后果。我们建议在使用提示词之前始终打印它。如果您想了解更多信息,还可以阅读参考部分。
你的第一个提示词
以下片段展示了一个非常简单的提示词。花括号 {{ }}
中的变量是您将传递给提示词函数的参数值的占位符。
如果函数的参数中缺少变量,Jinja2 将抛出 UndefinedError
异常
Traceback (most recent call last):
File "<stdin>", line 9, in <module>
File "/home/remi/projects/normal/outlines/outlines/templates.py", line 38, in __call__
return render(self.template, **bound_arguments.arguments)
File "/home/remi/projects/normal/outlines/outlines/templates.py", line 213, in render
return jinja_template.render(**values)
File "/home/remi/micromamba/envs/outlines/lib/python3.9/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/home/remi/micromamba/envs/outlines/lib/python3.9/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
jinja2.exceptions.UndefinedError: 'surname' is undefined
从文件中导入提示词
Outlines 允许您从文本文件中读取提示词模板。这样您就可以构建“空白精确”的提示词,并将它们与代码独立开来版本控制。自从 Outlines 发布以来,我们发现自己经常采用这种模式
少样本提示
少样本提示词可能导致代码混乱。提示词函数允许您在模板中遍历列表或字典。在下面的示例中,我们演示了如何通过将一个包含键 question
和 answer
的字典列表传递给提示词函数来生成提示词
{{ instructions }}
Examples
--------
{% for example in examples %}
Q: {{ example.question }}
A: {{ example.answer }}
{% endfor %}
Question
--------
Q: {{ question }}
A:
from outlines import Template
instructions = "Please answer the following question following the examples"
examples = [
{"question": "2+2=?", "answer":4},
{"question": "3+3=?", "answer":6}
]
question = "4+4 = ?"
few_shots = Template.from_file("prompt.txt")
prompt = few_shots(instructions, examples, question)
print(prompt)
条件、过滤器等
Jinja2 除了循环之外还有许多此处未描述的特性:条件判断、过滤、格式化等。有关模板语言语法的更多信息,请参阅 Jinja 文档。Jinja 语法功能强大,如果您正在构建复杂的提示词,我们建议您花一些时间阅读他们的文档。
工具
有几个项目(例如Toolformer、ViperGPT、AutoGPT等)表明,通过在提示词中描述外部函数的功能,我们可以“教”语言模型使用这些函数。在这些项目中,相同的信息通常会重复两次:函数实现、名称、文档字符串或参数被复制粘贴到提示词中。这既繁琐又容易出错;您可以直接从 Outlines 提示词函数中提取这些信息。
from outlines import Template
def my_tool(arg1: str, arg2: int):
"""Tool description.
The rest of the docstring
"""
pass
prompt = """{{ question }}
COMMANDS
1. {{ tool | name }}: {{ tool | description }}, args: {{ tool | args }}
{{ tool | source }}
"""
tool_prompt = Template.from_string(prompt)
prompt = tool_prompt("Can you do something?", my_tool)
print(prompt)
JSON 响应格式
为了用语言模型构建可靠的链,我们通常需要指示它们以我们期望的格式返回响应。
如果没有提示词模板,创建解析函数(例如 Pydantic 模型)和在提示词中写入期望的 Schema 之间,信息会被重复两次。这可能导致难以调试的错误。
Outlines 允许您直接从 Outlines 提示词函数中提取 Pydantic 模型的 JSON Schema,或美观地打印字典。
```python from pydantic import BaseModel, Field
from outlines import Template
class MyResponse(BaseModel):
field1: int = Field(description="an int")
field2: str
my_prompt = Template.from_string("""{{ response_model | schema }}""")
prompt = my_prompt(MyResponse)
print(prompt)
# {
# "field1": "an int",
# "field2": "<field2>"
# }
```
格式约定
提示词模板在渲染从字符串读取的模板时有其约定,这些约定旨在避免提示词错误并帮助格式化。
空白字符
如果您有使用三引号字符串的经验,您就会知道缩进会影响字符串的格式。提示词函数遵循一些约定,这样您在编写提示词时就不必考虑缩进。
首先,无论您是紧接在三引号之后开始提示词,还是在下一行开始,都不会影响格式化
缩进是相对于文档字符串的第二行计算的,并且会移除开头的空格
不会移除尾随的空白字符,除非它们紧跟在换行符 \
后面(参见换行)。
换行
您可以使用反斜杠 \
来断开长文本行。它将渲染为单行