version 是不可变快照,label 是可移动指针。 每次
create_prompt同名 prompt 都会生成一个递增的 version(v1、v2、v3…),版本内容永不改变;label(如production、staging)是贴在某个 version 上的标签,可以随时撕下来贴到另一个 version。生产代码永远按 label 拉取,发布即「移动 label」,回滚即「把 label 移回旧 version」——代码一行不改。
一、两种 Prompt 类型:text 与 chat
Langfuse 的 prompt 有两种 type:text(单段字符串模板,适合 completion 风格或作为 system 片段)和 chat(消息数组,每条含 role 与 content,对应 OpenAI/Anthropic 的 messages 格式)。模板变量统一用双花括号 {{variable}} 占位,由 compile() 在运行时填充。
# 安装最新 v3 SDK(v3 起 client 为单例,用 get_client 获取)
pip install -U "langfuse>=3.0.0" openai
# 三个环境变量(项目 Settings 页生成 key)
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_HOST="https://cloud.langfuse.com" # 自托管换成你的地址
from langfuse import get_client
langfuse = get_client() # 自动读取上面三个环境变量,进程内单例
# ---------- 1) 创建一个 text 类型 prompt ----------
langfuse.create_prompt(
name="summary-prompt", # prompt 的唯一名字(跨版本不变)
type="text",
prompt="请用一句话总结下面的文本,保持 {{tone}} 的语气:\n\n{{document}}",
labels=["production"], # 创建时直接打上 production 标签
config={ # config 是任意 JSON,随版本一起存
"model": "gpt-4o-mini",
"temperature": 0.3,
},
)
# ---------- 2) 创建一个 chat 类型 prompt ----------
langfuse.create_prompt(
name="support-agent",
type="chat",
prompt=[
{"role": "system", "content": "你是 {{product}} 的客服,语气友好、回答简洁。"},
{"role": "user", "content": "{{question}}"},
],
labels=["production"],
config={"model": "gpt-4o", "temperature": 0.7},
)
print("两个 prompt 已创建并发布到 production")
二、拉取 Prompt:label / version、缓存与 fallback
运行时用 get_prompt(name) 拉取。不传任何选择参数时默认拉 production label 的版本。生产环境真正要关心的是另外两个参数:cache_ttl_seconds(本地缓存有效期)和 fallback(Langfuse 不可达时的兜底内容)。配置好这两个,拉 prompt 就不会给主链路加延迟,也不会因为 Langfuse 抖动而阻断业务。
from langfuse import get_client
from openai import OpenAI
langfuse = get_client()
oai = OpenAI()
# ---------- 按 label 拉取(线上推荐写法)----------
# 默认就是 label="production";显式写出来意图更清晰
prompt = langfuse.get_prompt(
"support-agent",
label="production",
# 缓存 5 分钟:首次拉远端,之后 300s 内命中本地缓存(0 延迟);
# 过期后后台异步刷新,不阻塞当前请求 —— 默认 60s,生产可调大
cache_ttl_seconds=300,
# 兜底:万一 Langfuse 不可达且本地无缓存,用它而不是抛异常阻断业务
# chat 类型 fallback 必须是消息数组;text 类型则传字符串
fallback=[
{"role": "system", "content": "你是客服,请简洁回答。"},
{"role": "user", "content": "{{question}}"},
],
)
# ---------- 按 version 拉取(调试/复现特定版本时用)----------
prompt_v2 = langfuse.get_prompt("support-agent", version=2)
# ---------- 按自定义 label 拉取(灰度环境)----------
prompt_staging = langfuse.get_prompt("support-agent", label="staging")
print("当前版本号:", prompt.version, "| 是否命中 fallback:", prompt.is_fallback)
| 拉取方式 | 写法 | 适用场景 | 升级行为 |
|---|---|---|---|
| 按 production label | get_prompt(name) | 生产主链路(默认) | label 移动后自动生效,代码不改 |
| 按自定义 label | get_prompt(name, label="staging") | 灰度 / A-B / 预发环境 | 对应 label 移动后生效 |
| 按 version 锁定 | get_prompt(name, version=3) | 调试、复现 bug、回归测试 | 永远拿到该不可变快照,绝不漂移 |
| latest label | get_prompt(name, label="latest") | 拿最新创建的版本(含未发布) | 每次创建都会变,慎用于生产 |
三、compile 编译模板变量
拉到的 prompt 还是带 {{变量}} 的模板,调 compile(**变量) 把值填进去。text 类型返回编译后的字符串,chat 类型返回可直接喂给 OpenAI/Anthropic 的 messages 列表。模型参数从 prompt.config 取,做到「Prompt 文本和模型配置一起版本化」。
# ---------- chat 类型:compile 后直接喂给 openai ----------
messages = prompt.compile(
product="Langfuse",
question="怎么回滚一个 prompt 版本?",
)
# messages 形如:
# [{"role": "system", "content": "你是 Langfuse 的客服,语气友好、回答简洁。"},
# {"role": "user", "content": "怎么回滚一个 prompt 版本?"}]
response = oai.chat.completions.create(
model=prompt.config["model"], # 模型也来自版本化的 config
temperature=prompt.config["temperature"],
messages=messages,
)
print(response.choices[0].message.content)
# ---------- text 类型:compile 返回字符串 ----------
text_prompt = langfuse.get_prompt("summary-prompt") # 默认 production
compiled_text = text_prompt.compile(
tone="专业",
document="Langfuse 是一个开源的 LLM 工程平台……",
)
print(compiled_text) # 已填好变量的完整字符串
四、把 Prompt link 到 Generation:按版本追指标
Prompt Management 真正的价值在闭环:把拉到的 prompt 对象关联到对应的 generation,Langfuse 就能在 Dashboard 里按 prompt 名 + 版本 聚合调用次数、Token、成本、延迟,以及后续打的质量分数。这样「v3 比 v2 贵了 20% 但准确率高 5 个点」这种判断才有数据支撑。
from langfuse import get_client, observe
from langfuse.openai import openai # 用 langfuse 包装版,自动捕获 generation
langfuse = get_client()
@observe()
def answer(question: str) -> str:
# 1) 拉取已版本化的 prompt(自带缓存与 fallback)
prompt = langfuse.get_prompt("support-agent", label="production")
# 2) compile 填充变量
messages = prompt.compile(product="Langfuse", question=question)
# 3) 调用模型,关键:把 prompt 对象通过 langfuse_prompt 关联到这次 generation
# 这样该 generation 会被标注上 prompt 名 + version,可在 Dashboard 按版本聚合
resp = openai.chat.completions.create(
model=prompt.config["model"],
temperature=prompt.config["temperature"],
messages=messages,
langfuse_prompt=prompt, # <-- link prompt -> generation
)
return resp.choices[0].message.content
print(answer("怎么做 prompt 灰度发布?"))
# 如果你不用 langfuse.openai 包装,而是手动建 generation,则这样关联:
with langfuse.start_as_current_generation(
name="manual-gen",
model=prompt.config["model"],
prompt=prompt, # <-- 同样把 prompt 对象传进来即可关联
) as gen:
gen.update(output="...模型输出...")
langfuse.flush() # 脚本/短任务结束前 flush,确保事件上报
✓推荐做法
- 生产代码统一 get_prompt(name, label="production"),发布即移动 label,回滚即把 label 移回旧版本
- 为 get_prompt 设置合理的 cache_ttl_seconds(如 60~300s)并提供 fallback,让主链路零额外延迟、宕机不阻断
- 每次调用都用 langfuse_prompt= / prompt= 把版本关联到 generation,积累版本级指标
- 把 model、temperature 等放进 prompt 的 config,和文本一起版本化,避免代码与 Prompt 配置漂移
✗不推荐
- 不要把 Prompt 文本继续硬编码在代码里——那样改一个字就得发版,也没有版本与指标
- 不要在生产用 label="latest",它会随任何一次 create 漂移,等于没有发布控制
- 不要把 cache_ttl_seconds 设成 0 来「保证最新」——会给每个请求加一跳同步网络往返
- 不要忽略 is_fallback=True:那是降级信号,不监控就等于在裸奔
⚠常见误区
- compile 缺变量不报错,错拼变量名会把 {{var}} 字面量发给模型
- chat 类型的 fallback 必须是消息数组、text 类型必须是字符串,类型不匹配会出错
- 短生命周期脚本忘记 flush(),事件还在队列里进程就退出了,Dashboard 看不到数据
在 Langfuse Dashboard 的 Prompts 页能看到 production label 指向预期 version,且对应 generation 能按版本展示成本/Token/延迟,回滚只需在 UI 移动 label、代码零改动。
拉 prompt 让接口变慢了
- 典型表现
- 接入 get_prompt 后每个请求都多了几十到几百毫秒
- 判断标准
- P99 延迟里 get_prompt 的网络耗时趋近于 0
- 解决方向
- 设置 cache_ttl_seconds(如 300),首次后命中本地缓存,过期靠后台异步刷新;切勿设为 0
Langfuse 抖动导致业务报错
- 典型表现
- Langfuse 短暂不可达时,get_prompt 抛异常把主链路打挂
- 判断标准
- Langfuse 宕机时业务仍能用兜底 prompt 正常返回
- 解决方向
- 给 get_prompt 传 fallback(chat 传数组 / text 传字符串),并对 prompt.is_fallback 加告警
说不清线上跑的是哪版 prompt
- 典型表现
- 改了 prompt 后效果变化,但无法定位是哪个版本、也无法对比
- 判断标准
- 每条 generation 都带 prompt 名 + version,可在 Dashboard 按版本聚合
- 解决方向
- 调用时用 langfuse_prompt=prompt(包装版)或 prompt=prompt(手动 generation)做关联
改了 prompt 没生效
- 典型表现
- 在 UI 创建了新版本,但线上还在跑旧内容
- 判断标准
- 新版本被打上 production label 后,缓存过期或重启即生效
- 解决方向
- 确认新版本已贴 production label(移动指针),并等待 cache_ttl_seconds 过期或重启进程清缓存
Prompt 不是字符串常量,而是带版本、可灰度、可回滚、可度量的产品资产——这正是它该从代码里搬进 Langfuse 的理由。
— Langfuse Prompt Management 设计理念