Skip to content

Commit 3a40ae0

Browse files
committed
post: prompt origanization
1 parent 0c13a7a commit 3a40ae0

File tree

26 files changed

+1876
-69
lines changed

26 files changed

+1876
-69
lines changed

content/posts/2025-08-27_py-to-go.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ draft = false
44
title = 'From Python to Go'
55
tags = ['Python', 'Go']
66
+++
7-
文章翻译: [From Python to Go: Why We Rewrote Our Ingest Pipeline at Telemetry Harbor](https://telemetryharbor.com/blog/from-python-to-go-why-we-rewrote-our-ingest-pipeline-at-telemetry-harbor/)
7+
[From Python to Go: Why We Rewrote Our Ingest Pipeline at Telemetry Harbor](https://telemetryharbor.com/blog/from-python-to-go-why-we-rewrote-our-ingest-pipeline-at-telemetry-harbor/)
88

99
我们将 Telemetry Harbor 的摄取管道从 Python FastAPI 重写为 Go,原因是遇到了严重的性能瓶颈。迁移后,效率提升了 10 倍,数据完整性因严格类型检查而得到加强,系统也拥有了稳定、可扩展的高并发时间序列数据摄取基础。
1010

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
+++
2+
date = '2025-08-28T8:00:00+08:00'
3+
draft = false
4+
title = 'Prompt Origanization'
5+
tags = ['Prompt', 'LLMs']
6+
+++
7+
8+
这篇文章旨在介绍 Python 中常用的提示词组织方式
9+
10+
### f-string
11+
使用 f 字符串填充变量得到提示词
12+
```Python
13+
def get_prompt(query: str) -> list[dict]:
14+
SYSTEM_PROMPT = f"""...
15+
...
16+
多行提示词, 也可以填充变量
17+
"""
18+
USER_PROMPT = f"""INPUT:
19+
{query}
20+
....
21+
"""
22+
return [
23+
{"role": "system", "content": SYSTEM_PROMPT},
24+
{"role": "user", "content": USER_PROMPT},
25+
]
26+
```
27+
这种方法实现简单, 速度快, 但是:
28+
1. 多行字符串由于填充变量的需要, 需写在函数内, 导致代码格式混乱
29+
2. 通过代码构造提示词, 任何修改都需要修改代码, 扩展性差
30+
31+
32+
### string.Template
33+
使用 Python 元素字符串模板
34+
```Python
35+
SYSTEM_PROMPT = string.Template("""你是一名$role
36+
多行提示词...
37+
""")
38+
39+
USER_PROMPT = string.Template("""INPUT:
40+
$query
41+
""")
42+
43+
def get_prompt(role: str, query: str) -> list[dict]:
44+
system_prompt = SYSTEM_PROMPT.subtitute(role="助手")
45+
user_prompt = USER_PROMPT.subtitute(query="问题...")
46+
return [
47+
{"role": "system", "content": system_prompt},
48+
{"role": "user", "content": user_prompt},
49+
]
50+
```
51+
使用模板字符串, 模板则不必写在函数内, 且模板字符串可以选择替换部分变量, 使用 `.safe_substitute()`方法传入一个字典, 例如 `{"query": "问题..."}`, 对没有传入的变量解析为 `$var`
52+
对比 f-string, 模板字符串更加灵活, 且可以只传入部分值
53+
54+
55+
### Jinja2
56+
Jinja2 是一个现代的设计者友好的, 仿照 Django 模板的 Python 模板语言. 它速度快, 被广泛使用, 并且提供了可选的沙箱模板执行环境保证安全:
57+
例如下面这个 `.j2` 文件内容, 构造了一个用于少样本提示的模板
58+
```Jinja
59+
{% if examples %}
60+
{% for example in examples %}
61+
INPUT:
62+
{{ example.input }}
63+
64+
OUPUT:
65+
{{ example.output }}
66+
67+
{% endfor %}
68+
{% endif %}
69+
INPUT:
70+
{{ user_input }}
71+
```
72+
导入该模板文件代码如下:
73+
```Python
74+
from jinja2 import Environment, PackageLoader # 根据需要不同也可以使用 FileSystemLoader
75+
76+
env = Environment(
77+
loader=PackageLoader("app.module.prompt", "template"),
78+
trim_blocks=True, # 移除 {% ... %} 块前后的多余空白
79+
lstrip_blocks=True, # 移除行首 {% ... %} 块前的空白
80+
)
81+
82+
def get_prompt(user_input: str) -> list[dict]:
83+
system_template = env.get_template("system_template.j2")
84+
user_template = env.get_template("user_template.j2")
85+
86+
system_data = {"var": val, ...}
87+
user_data = {
88+
"examples": [
89+
{"input": "示例输入1", "output": "示例输出1"}, # 具体样例也可以通过函数传入
90+
{"input": "示例输入2", "output": "示例输出2"},
91+
],
92+
"user_input": user_input",
93+
}
94+
95+
messages = [
96+
{"role": "system", "content": system_template.render(system_data)},
97+
{"role": "user", "content": user_template.render(user_prompt)},
98+
]
99+
100+
return messages
101+
```
102+
使用 Jinja2 模板文件的好处是:
103+
1. 方便组织提示词文件, 例如这里是将提示词文件放在 `ProjectRoot/app/module/prompt` 里面, 模板文件放在 `prompt/template` 里面, 在提示词文件中导入模板文件十分方便, 文件组织清晰, 代码可读性高, 且方便扩展
104+
2. 提示词灵活性更好, 对比 string.Template, Jinja2 模板不仅可以填充变量, 还可以在模板中插入循环和条件判断等语法, 使得代码中只需提供一个字典格式的数据即可, 无需在代码里拼凑提示词, 也方便和 RAG 系统结合使用
105+
106+
虽然 Jinja2 对比 string.Template 性能上要差一些, 但是 LLM 应用真正花时间的地方是模型的推理部分, 相比之下提示词渲染的时间几乎可以忽略不计. 如果提示词非常多, Jinja2 还提供了异步渲染功能, 可以结合异步框架进一步提升性能.
107+
108+
### Wrapping Up
109+
上面就是近期使用的一些构造提示词的方法, 分别是 `f-string``string.Template``Jinja2`.
110+
当然也有像 `langchain_core.prompts.prompt.PromptTemplate` 这样专用框架提供的提示词模板功能, 但是为了支持 LangChain LCEL 语法等原因, 导致其类型设计十分抽象, 且 LangChain 对新模型和新功能的支持比较缓慢, 加上版本不稳定, 接口经常变动, 故没有考虑使用 LangChain 框架提供的功能.(实际上, langchain 也支持使用 Jinja2 模板)
111+
总之, 上面介绍的提示词构造方法各有优劣, 应该根据你项目的复杂度, 自行选择合适的提示词构造方式.

public/archives/index.html

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,13 @@
5151
<span class="max-w-[4rem] md:max-w-none truncate">Home</span></a></li><li class="flex items-center gap-1 md:gap-2 min-w-0"><span class="text-muted-foreground/50 flex-shrink-0"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
5252
</span><span class="text-foreground flex items-center gap-0.5 md:gap-1 font-medium min-w-0 flex-shrink-0"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/></svg>
5353
<span class="max-w-[3rem] md:max-w-none truncate">Archives</span></span></li></ol></nav><header class=mb-8><div class="mb-4 flex items-center gap-3"><svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/></svg><h1 class="text-foreground text-3xl font-bold">Archives</h1></div><p class="text-muted-foreground mb-6">Browse all articles in chronological order and discover what interests you.</p><div class="text-muted-foreground flex items-center gap-4 text-sm"><div class="flex items-center gap-1"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
54-
<span>29 posts total</span></div><div class="flex items-center gap-1"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
55-
<span>Timeline view</span></div></div></header><div class=relative><div class="bg-border absolute top-0 bottom-0 left-4 w-0.5"></div><div class=mb-12><div class="relative mb-8 flex items-center"><div class="bg-primary absolute left-0 z-10 flex h-8 w-8 items-center justify-center rounded-full"><svg class="h-4 w-4 text-primary-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg></div><div class=ml-12><h2 class="text-foreground text-2xl font-bold">2025</h2><p class="text-muted-foreground text-sm">27
56-
posts</p></div></div><div class="relative mb-8"><div class="relative mb-4 flex items-center"><div class="bg-accent border-background absolute left-2 z-10 h-4 w-4 rounded-full border-2"></div><div class=ml-12><h3 class="text-foreground text-lg font-semibold">August 2025</h3><p class="text-muted-foreground text-xs">27
57-
posts</p></div></div><div class="ml-12 space-y-3"><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/from-python-to-go/ class=block>From Python to Go</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
54+
<span>30 posts total</span></div><div class="flex items-center gap-1"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
55+
<span>Timeline view</span></div></div></header><div class=relative><div class="bg-border absolute top-0 bottom-0 left-4 w-0.5"></div><div class=mb-12><div class="relative mb-8 flex items-center"><div class="bg-primary absolute left-0 z-10 flex h-8 w-8 items-center justify-center rounded-full"><svg class="h-4 w-4 text-primary-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg></div><div class=ml-12><h2 class="text-foreground text-2xl font-bold">2025</h2><p class="text-muted-foreground text-sm">28
56+
posts</p></div></div><div class="relative mb-8"><div class="relative mb-4 flex items-center"><div class="bg-accent border-background absolute left-2 z-10 h-4 w-4 rounded-full border-2"></div><div class=ml-12><h3 class="text-foreground text-lg font-semibold">August 2025</h3><p class="text-muted-foreground text-xs">28
57+
posts</p></div></div><div class="ml-12 space-y-3"><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/prompt-origanization/ class=block>Prompt Origanization</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
58+
<time datetime=2025-08-28>08-28</time></div><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3A9 9 0 113 12a9 9 0 0118 0z"/></svg>
59+
<span>3
60+
min</span></div></div></div></div></article><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/from-python-to-go/ class=block>From Python to Go</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
5861
<time datetime=2025-08-27>08-27</time></div><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3A9 9 0 113 12a9 9 0 0118 0z"/></svg>
5962
<span>3
6063
min</span></div></div></div></div></article><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/redis-set/ class=block>Redis Set</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>

0 commit comments

Comments
 (0)