Files
notes/resource/ai/Jinja 模板引擎.md
T
Docker7530 6b50219f55 1776654103
2026-04-20 11:01:47 +08:00

72 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
一种"带插件的文本生成器"。它允许你创建一个包含变量和逻辑的"模板"文件,然后在渲染时填入具体数据,最终生成想要的文本格式(如 HTML、JSON、Markdown 等)。
它的语法简单直观,主要有三种核心元素:
- **`{{ … }}`**:用于输出变量值,例如 `{{ user_name }}` 会在渲染时被具体的用户名替换。
- **`{% … %}`**:用于执行逻辑,例如循环 `{% for item in items %}` 或判断 `{% if user_logged_in %}`
- **`{# … #}`**:用于添加注释,不会出现在最终输出中。
### 提示词(Prompt)工程
主要用于**动态、精确地构建和管理提示词(Prompt)**。其核心价值在于将"提示词模板"与"可变数据"分离。
#### 1. 构建动态、结构化的提示词
在实际应用中,很少会发送固定的文本给 AI。你需要将用户问题、聊天历史、检索到的知识等动态拼接到提示词中。Jinja 让这件事变得优雅和可控。
**示例:一个智能客服的提示词模板**
```jinja
你是一名专业的客服助手,名叫"小智"。
请基于以下提供的资料,回答用户的问题。
如果资料中找不到答案,请直接说"不知道",不要编造。
### 参考资料:
{% for doc in search_results %}
- {{ doc.title }}: {{ doc.content }}
{% endfor %}
### 对话历史:
{% for msg in chat_history %}
{{ msg.role }}: {{ msg.content }}
{% endfor %}
### 用户当前的问题是:
{{ current_question }}
请给出你的回答:
```
在这个模板中,`search_results``chat_history``current_question` 都是变量。渲染时,Jinja 会循环填入所有搜索结果和对话记录,生成一个结构清晰、信息完整的提示词。
#### 2. 统一聊天模型的提示词格式(Chat Template
这是 Jinja 在 AI 领域最"杀手级"的应用。每个大模型(如 Llama、Mistral、ChatGLM)对聊天对话的输入格式要求都不同。**Chat Template** 就是用 Jinja 语法写的一段脚本,定义了如何将 `messages` 数组(包含 role 和 content 的对话)转换成模型能理解的单一字符串。
**一个简化的 Chat Template 示例:**
```jinja
{% for message in messages %}
{% if message['role'] == 'user' %}
{{ '[INST] ' + message['content'] + ' [/INST]' }}
{% elif message['role'] == 'assistant' %}
{{ ' ' + message['content'] + ' </s>' }}
{% endif %}
{% endfor %}
```
- **输入(Messages**: `[{"role": "user", "content": "你好"}, {"role": "assistant", "content": "你好!有什么可以帮你的?"}]`
- **输出(Prompt String**: `[INST] 你好 [/INST] 你好!有什么可以帮你的? </s>`
AI 框架如 Hugging Face Transformers 已经内置了对 Jinja Chat Template 的支持。你只需调用 `tokenizer.apply_chat_template(messages)`,它就会自动使用模型对应的 Jinja 模板来生成正确的输入,极大地简化了开发流程。
#### 3. 在 AI 工作流和数据转换中作为"胶水"
在复杂的 AI 应用(如 RAG 检索增强生成、Agent)和工作流平台(如阿里云的 AI Studio、Azure 的 Prompt Flow)中,Jinja 常被用作轻量级的**数据处理和格式化工具**。
例如,可以将检索到的多个相关文档片段,通过一个 Jinja 模板快速格式化为一个结构清晰的 Markdown 列表,再输入给大模型。
```
{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<User>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<Assistant><tool▁calls▁begin><tool▁call▁begin>' + tool['type'] + '<tool▁sep>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<tool▁call▁end>'}}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<tool▁call▁begin>' + tool['type'] + '<tool▁sep>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<tool▁call▁end>'}}{{'<tool▁calls▁end><end▁of▁sentence>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<tool▁outputs▁end>' + message['content'] + '<end▁of▁sentence>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = message['content'].replace('</think>', '').split('<think>')[-1] %}{% endif %}{{'<Assistant>' + content + '<end▁of▁sentence>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<tool▁outputs▁begin><tool▁output▁begin>' + message['content'] + '<tool▁output▁end>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\\n<tool▁output▁begin>' + message['content'] + '<tool▁output▁end>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<tool▁outputs▁end>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<Assistant>'}}{% endif %}
```