変数置換のテクニック
プロンプトを生成するための f-string、.format()、テンプレートライブラリを学びます。
「変数置換のテクニック」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。
テンプレートレンダリングの4つのPythonアプローチ
Pythonでは、変数を置換してプロンプトテンプレートをレンダリングする方法がいくつかあります。それぞれに長所とトレードオフがあります:
- f-strings — インラインで即時に使え、インポートが不要
- str.format() — 名前付きプレースホルダーを使え、検証しやすい
- string.Template — 安全なドル記号置換に対応し、一部だけ埋めることも可能
- Jinja2 — 条件分岐、ループ、フィルター、継承に対応する完全なテンプレートエンジン
適切なアプローチは、テンプレートの複雑さ、チームのスキル、条件分岐やループなどの高度な機能が必要かどうかによって決まります。
アプローチ1: Pythonのf-string
f-stringは、すべての変数がレンダリング時に利用できるプロンプトテンプレートに最も適した、簡単なアプローチです:
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 }}— topicを大文字に変換{{ word_count | default(200) }}— word_countが指定されていない場合は200を使用{{ audience | title }}— audience文字列をタイトルケースに変換{{ items | join(', ') }}— リストをカンマで連結
フィルターを使うと、変換ロジックをテンプレートを呼び出すPythonコードではなくテンプレート内に記述できます。そのため、テンプレートがより自己完結的で移植しやすくなります。
ファイルからのテンプレートの読み込み
大規模または複雑なテンプレートを別々のテキストファイルに保存すると、Pythonコードをすっきり保てます。Jinja2のEnvironmentと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-strings — 素早いスクリプト、一度限りの自動化、インラインで読める短いテンプレート
- 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には、プロンプトテンプレートをレンダリングする4つのアプローチがあります。f-strings(インラインで簡単)、str.format()(名前付きプレースホルダー、変数が欠けている場合はKeyError)、string.Template(ドル記号構文、安全な部分置換)、Jinja2(条件分岐、ループ、フィルター、ファイル読み込みに対応する完全なエンジン)です。
複雑さに合わせてアプローチを選択してください。素早いスクリプトにはf-strings、保存したテンプレートにはstr.format()、コンテンツに波括弧が含まれる場合にはstring.Template、条件分岐やループ、ファイルベースのテンプレートが必要な場合にはJinja2を使います。レンダリングは必ずAPI呼び出しとは分けてテストしてください。
よくある質問
「変数置換のテクニック」レッスンは無料ですか?
はい。「変数置換のテクニック」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。
「変数置換のテクニック」で何を学びますか?
プロンプトを生成するための f-string、.format()、テンプレートライブラリを学びます。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Prompt Engineeringを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「変数置換のテクニック」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Prompt Engineeringレッスンでコードを書いて実行できますか?
はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。