业务问答 Agent 准备增加一条规则:“回答必须引用知识库依据。”开发人员改完 Prompt,在几个示例上试了试,随后发布到生产。第二天点踩变多了,有人说答案太啰嗦,也有人说引用与问题无关。
“新 Prompt 好不好”太宽泛。团队需要回答几件可以查证的事:哪些请求用了新版本,负面反馈是否真的集中在这些请求上,问题来自 Prompt 还是检索数据,以及能否先恢复旧版本。版本记录、运行链路和用户反馈只有连在一起,发布才可观察,也才可回退。
Prompt 已经是运行配置
Prompt 影响模型看到的任务、上下文和输出要求。它虽然是文本,却和模型参数、工具路由一样,会改变应用行为。直接写在代码里可以运行,但每次修改都跟着代码部署;出问题时,还要从提交记录里反推线上请求究竟用了什么内容。
一个可控的 Prompt 发布机制至少需要三样东西:保留每次修改的历史快照,用一个可移动的指针决定生产流量使用哪份快照,并把真实运行记录关联回当时的版本。这是通用配置治理方法,可以由 Git、配置中心、自建服务或 Prompt 平台实现。
Langfuse 用 version 和 label 表达这层关系。同名 Prompt 每次创建都会得到新的 version ID,旧版本不会被覆盖。Label 指向某个版本,适合表达 staging、production 或实验分组。应用按 production 获取 Prompt,发布时只需把该标签移到新版本;出现异常,再把标签指回旧版本。
latest 是 Langfuse 自动维护的标签,只表示最近创建的版本。它没有说明这份 Prompt 是否通过验证,因此不适合作为默认的生产发布策略。SDK 在未指定 label 或 version 时,默认返回带 production 标签的版本。
这次修改可以按下面的节奏上线:先创建新版本,让旧版本继续承接生产流量;在开发或 staging 环境检查变量、消息结构和典型问题;确认基本行为后移动 production 标签;最后观察新版本关联的 Trace、成本、延迟和反馈。这里不需要复杂审批系统,但每次发布都应留下版本、时间和操作人。
prompt = langfuse.get_prompt(
"business-qa",
label="production",
)
messages = prompt.compile(question=user_question)
获取 Prompt 后,还要把该对象关联到对应 Generation。只记录编译后的字符串,会丢掉 Prompt 名称和版本关系;发生问题时仍然难以按版本筛选。关联完成后,可以从 Trace 看出这次生成使用哪一版,也能按 Prompt 版本聚合延迟、成本和 Score。
客户端缓存会让发布表现得没那么“瞬时”。Langfuse SDK 缓存已获取的 Prompt,以减少网络请求,也在平台短暂不可用时继续提供配置。Label 移动后,少量请求可能在缓存有效期内继续使用旧版本。需要更快生效时,应根据业务风险调整缓存 TTL 或禁用缓存;排查时也要核对 Trace 上记录的真实版本,不能只根据发布时间猜测。
反馈要回到产生答案的那次执行
发布后的回答有没有帮助,接口状态和模型自评都不能替用户决定。用户点踩、重新提问、复制答案、接受建议或转人工,都会提供一些线索。这里最容易犯的错,是收集了事件,却没有把事件关联回原始请求。
显式反馈由用户主动给出,例如点赞、点踩、星级和文字意见。信号直接,但参与率通常不高。隐式反馈来自行为,例如复制、重试、修改、放弃流程或最终完成任务,覆盖更广,含义也更容易误读。复制可能说明答案有用,也可能只是用户准备拿去大改。
设计反馈时,先写清行为在产品里的含义,再确定字段。点赞评价的是主观满意度,任务完成描述业务结果,人工纠错提供了更具体的失败证据。把它们全塞进一个“质量分”,后续很难解释变化。名称、值类型和口径也要保持稳定,避免同一个概念先后使用 like=1、satisfied=true 和 good。
要把前端反馈接回 Trace,后端返回答案时需要同时返回稳定的 Trace ID。前端提交评价时带回这个 ID,平台才能把 Score 挂到正确对象上。在 Langfuse 当前 Browser SDK 文档中,点赞/点踩示例使用 BOOLEAN 与 1/0:
await langfuse.score({
traceId,
id: `response-rating-${traceId}`,
name: "response_rating",
value: 0,
dataType: "BOOLEAN",
comment: "引用内容与问题无关",
});
浏览器端只能使用 Public Key,不能暴露 Secret Key。稳定的 Score id 也有实际用途:用户改变选择时可以更新同一条记录,避免一个请求被重复计数。工单关闭、任务完成等发生在服务端的结果,应由后端 SDK 或 API 写入,并关联原 Trace、Observation、Session 或实验对象。
这里有一个接口版本差异需要单独记住。上面的 0/1 写法来自 Browser SDK 的 User Feedback 示例;Scores API v3 的 BOOLEAN 值类型是 false/true。读取 v3 API 或改用其他 SDK 时,要按该接口的类型定义转换,不能把示例代码原样搬过去。Scores API v3 还通过 subject.kind 区分 Score 关联的是 Trace、Observation、Session 还是 Experiment。
接入反馈后,先做一条端到端验证:发起测试问题,提交点踩,再打开对应 Trace,确认 Score 名称、值、评论和关联对象都正确。随后用当前接口实际保存的负向值筛选记录。若 Trace ID 丢失、名称漂移或重复写入,Dashboard 上的反馈趋势不会可信。
发布、观察和回退
现在可以回到开头的 Prompt 变更。团队按 Prompt 版本筛选生产 Trace,发现点踩主要集中在新版本;逐条阅读后又发现,问题并非“要求引用”本身,而是检索步骤返回了宽泛材料,新 Prompt 强制模型把这些材料写进答案。短期可以把 production 标签移回旧版本,恢复原行为;接着修正检索或引用规则,再发布下一版。
回退只是止损,不会自动回答新旧方案谁更好。用户反馈本身也有偏差:点踩者可能更愿意表达,低反馈率不能代表沉默用户满意,重试还可能由网络或交互设计引起。它是一组需要解释的证据,不是最终质量结论。
验收时确认三件事:每次运行能查到实际 Prompt 版本,每条反馈能回到被评价的结果,异常版本可以通过标签回退。负面样本随后可以进入 Dataset,在发布前接受重复比较。
参考资料
系列目录:AI 应用可观测性与评估
