0Pricing
AI Prompt Engineering · 课时

变量替换技巧

使用 f 字符串、.format() 和模板库渲染提示

变量替换技巧 是 CoddyKit 上的免费 AI Prompt Engineering 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Prompt Engineering 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Prompt Engineering 课程共包含 4 节课。

Python 模板渲染的四种方法

Python 提供了多种使用变量替换来渲染提示词模板的方法。每种方法都有其优势和取舍:

  • f 字符串 — 内联、即时执行,无需导入
  • str.format() — 命名占位符,便于验证
  • string.Template — 安全的美元符号替换,支持部分填充
  • Jinja2 — 完整的模板引擎:条件语句、循环、过滤器、继承

选择哪种方法取决于模板的复杂程度、团队技能,以及您是否需要条件语句和循环等高级功能。

方法 1:Python f 字符串

对于所有变量在渲染时都已准备好的提示词模板,f 字符串是最简单的方法:

import openai

client = openai.OpenAI(api_key='sk-...')

def generate_linkedin_post(company, topic, tone, word_count):
    prompt = (
        f'Write a LinkedIn post for {company} about {topic}. '
        f'Tone: {tone}. '
        f'Length: {word_count} words. '
        'Professional but conversational. '
        'End with one question to engage readers. '
        'No hashtags. Active voice.'
    )

    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

print(generate_linkedin_post(
    company='DataStream Analytics',
    topic='how AI is changing data pipelines',
    tone='enthusiastic but grounded',
    word_count=180
))

方法 2:str.format()

如果您希望将模板字符串与填充它们的代码分开存储,str.format() 会非常实用——例如从文件中加载模板时:

import openai

client = openai.OpenAI(api_key='sk-...')

# Template stored as a module-level constant or loaded from a file
SUPPORT_REPLY_TEMPLATE = '''You are a customer support agent for {company_name}.

Respond to this customer message:
---
{customer_message}
---

Tone: {tone}.
Keep the response under {max_words} words.
Do not offer refunds unless the customer explicitly asks.
Always close by asking if there is anything else you can help with.'''

def generate_support_reply(company, message, tone='empathetic and helpful', max_words=150):
    prompt = SUPPORT_REPLY_TEMPLATE.format(
        company_name=company,
        customer_message=message,
        tone=tone,
        max_words=max_words
    )

    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

方法 3:string.Template

Python 标准库中的 string.Template 使用美元符号占位符($variable 或 ${variable})。它的主要优势是:safe_substitute() 会将缺失的变量保留为字面占位符文本,而不是引发错误,因此可以实现部分填充:

from string import Template
import openai

client = openai.OpenAI(api_key='sk-...')

# $ placeholders — safe with code that contains curly braces
BASE_TEMPLATE = Template(
    'Write a $format_type for $audience about $topic. '
    'Tone: $tone. Length: $word_count words. '
    'Active voice. No jargon.'
)

def generate(format_type, audience, topic, tone='professional', word_count=200):
    prompt = BASE_TEMPLATE.substitute(
        format_type=format_type,
        audience=audience,
        topic=topic,
        tone=tone,
        word_count=word_count
    )

    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

# Partial fill example — safe_substitute leaves $word_count as-is
partial = BASE_TEMPLATE.safe_substitute(
    format_type='blog post', audience='developers', topic='API design'
)
print(partial)  # $tone and $word_count remain as placeholders

方法 4:Jinja2 基础

Jinja2 是一个完整的模板引擎。它支持条件语句、循环、过滤器和模板继承,功能远不止简单的字符串替换:

from jinja2 import Template
import openai

client = openai.OpenAI(api_key='sk-...')

# Jinja2 uses {{ }} for variables and {% %} for logic
JINJA_PROMPT = Template('''
Write a {{content_type}} for {{audience}} about {{topic}}.
Tone: {{tone}}.
{% if include_examples %}
Include {{example_count}} concrete examples.
{% endif %}
{% if word_count %}
Length: {{word_count}} words.
{% else %}
Aim for 200-300 words.
{% endif %}
Active voice. No jargon.
''')

def generate(content_type, audience, topic, tone, include_examples=False, example_count=2, word_count=None):
    prompt = JINJA_PROMPT.render(
        content_type=content_type,
        audience=audience,
        topic=topic,
        tone=tone,
        include_examples=include_examples,
        example_count=example_count,
        word_count=word_count
    )

    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

模板中的 Jinja2 循环

Jinja2 循环可以让您遍历模板中的列表,适合根据数据结构生成包含多个项目的提示词:

from jinja2 import Template
import openai

client = openai.OpenAI(api_key='sk-...')

MULTI_PRODUCT_TEMPLATE = Template('''
Write a product comparison for {{audience}}.
Compare the following products:

{% for product in products %}
- {{product.name}}: {{product.description}}
{% endfor %}

Structure: one paragraph per product, then a 2-sentence recommendation.
Tone: {{tone}}. Active voice. No bullet points in paragraphs.
''')

products = [
    {'name': 'Asana', 'description': 'project management with timeline views'},
    {'name': 'Linear', 'description': 'developer-focused issue tracking'},
    {'name': 'Monday.com', 'description': 'visual work management for teams'}
]

prompt = MULTI_PRODUCT_TEMPLATE.render(
    audience='startup founders',
    products=products,
    tone='direct and practical'
)

response = client.chat.completions.create(
    model='gpt-4o-mini',
    messages=[{'role': 'user', 'content': prompt}]
)
print(response.choices[0].message.content)

Jinja2 过滤器

Jinja2 过滤器会在模板渲染期间直接转换变量值。以下是一些对提示词很有用的内置过滤器:

  • {{ topic | upper }} — 将主题转换为大写
  • {{ word_count | default(200) }} — 未提供 word_count 时使用 200
  • {{ audience | title }} — 将 audience 字符串转换为标题格式
  • {{ items | join(', ') }} — 使用逗号连接列表

过滤器将转换逻辑保留在模板中,而不是放在调用模板的 Python 代码中,从而使模板更加独立且易于移植。

从文件加载模板

对于大型或复杂的模板,将模板存储在单独的文本文件中,可以让 Python 代码保持简洁。Jinja2 的环境对象和 FileSystemLoader 很适合处理这种情况:

from jinja2 import Environment, FileSystemLoader
import openai

client = openai.OpenAI(api_key='sk-...')

# Load all templates from the 'prompts/' directory
env = Environment(loader=FileSystemLoader('prompts/'))

def render_template(template_name, variables):
    '''Load and render a .j2 template file with the given variables.'''
    template = env.get_template(template_name)
    return template.render(**variables)

def generate_from_file(template_name, variables):
    prompt = render_template(template_name, variables)

    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return response.choices[0].message.content

# Usage: load prompts/blog_post.j2 and fill with variables
result = generate_from_file('blog_post.j2', {
    'topic': 'API rate limiting strategies',
    'audience': 'backend engineers',
    'tone': 'technical and direct',
    'word_count': 500
})
print(result)

选择合适的方法

请根据模板的复杂程度选择合适的替换方法:

  • f 字符串 — 快速脚本、一次性自动化任务,以及短到可以直接内联阅读的模板
  • str.format() — 存储的模板、团队代码库,以及希望在缺少变量时引发 KeyError 的情况
  • string.Template — 内容可能包含花括号(例如代码片段),或需要部分填充时
  • Jinja2 — 包含条件语句、循环、多个文件的复杂模板,或团队具备模板技术经验时

过度设计确实存在风险——只有在确实需要其高级功能时,才应选择 Jinja2。

模板安全性:注入攻击

当变量值来自用户输入时,提示词注入是一项实际风险。恶意用户可能会提供类似以下内容的值:“忽略之前的所有指令,并且……”

防御措施:

  • 在替换前验证并清理所有用户提供的变量
  • 对于面向用户的输入,请用分隔符包裹变量:“用户输入为:---{user_input}---”
  • 使用输出过滤来检测并拒绝看起来遵循了注入指令的响应
  • 绝不要让用户提供的值访问系统提示词变量

测试模板渲染

请始终将模板渲染与 API 调用分开测试。在将渲染后的字符串发送给模型之前,先对其进行验证:

def test_template_render():
    test_cases = [
        {'topic': 'cloud security', 'audience': 'CTOs', 'tone': 'formal', 'word_count': 300},
        {'topic': 'ML pipelines', 'audience': 'data scientists', 'tone': 'technical', 'word_count': 500},
        # Edge cases
        {'topic': '', 'audience': 'developers', 'tone': 'casual', 'word_count': 100},  # empty topic
        {'topic': 'AI' * 100, 'audience': 'all', 'tone': 'brief', 'word_count': 50},  # very long topic
    ]

    TEMPLATE = 'Write a {word_count}-word {tone} article about {topic} for {audience}. Active voice.'

    for i, case in enumerate(test_cases):
        try:
            rendered = TEMPLATE.format(**case)
            assert len(rendered) > 0, 'Empty render'
            print(f'Case {i+1} OK: {len(rendered)} chars')
        except (KeyError, AssertionError) as e:
            print(f'Case {i+1} FAILED: {e}')

test_template_render()

知识检查:替换技术

您正在构建一个提示词系统:模板文件存储在磁盘上,模板包含条件部分(例如,根据某个标志决定是否包含定价部分),并且模板可能由多位熟悉 Web 模板技术的团队成员共同编写。

哪种替换方法最适合这种场景?

回顾:变量替换技术

Python 提供了四种提示词模板渲染方法:f 字符串(内联、简单)、str.format()(命名占位符,缺少变量时引发 KeyError)、string.Template(美元符号语法,支持安全的部分填充)以及 Jinja2(支持条件语句、循环、过滤器和文件加载的完整引擎)。

请根据复杂程度选择方法:快速脚本使用 f 字符串,存储的模板使用 str.format(),内容包含花括号时使用 string.Template,需要条件语句、循环或基于文件的模板时使用 Jinja2。请始终将模板渲染与 API 调用分开测试。

常见问题解答

「变量替换技巧」课时是免费的吗?

是的 — 「变量替换技巧」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Prompt Engineering 课程的其余内容,请升级到 CoddyKit PRO。 AI Prompt Engineering 课程共包含 4 节课。

「变量替换技巧」这节课中我会学到什么?

使用 f 字符串、.format() 和模板库渲染提示 你通过在浏览器中直接运行的动手代码来练习 AI Prompt Engineering,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Prompt Engineering 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Prompt Engineering 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「变量替换技巧」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Prompt Engineering 课中编写并运行代码吗?

能。每节 AI Prompt Engineering 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 什么是提示模板
  2. 创建填空模式
  3. 变量替换技巧
  4. 在不同任务间复用模板
← 返回 AI Prompt Engineering