用 Langfuse 打磨 Langfuse:v4 搜索栏 Ask AI 过滤器(searchBar.generateFilter)的改进与自我狗粮计划解析
用 Langfuse 打磨 Langfusev4 搜索栏 Ask AI 过滤器searchBar.generateFilter的改进与自我狗粮计划解析【免费下载链接】langfuse Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse导读本文以仓库内 AI_FILTER_PLAN.md 为骨架完整解析 Langfuse v4 事件表中Ask AI自然语言过滤器的现状、问题与调优路线图。文章将带你理解searchBar.generateFilter端到端的数据流自然语言 → LLM → 可编辑 FilterState pills、其基于字段注册表FieldRegistry生成的系统提示词设计、为修复数据感知缺失而注入的观测上下文observed context以及作者团队用 Langfuse 自己来打磨 Langfuse 的 AI 功能的完整狗粮闭环——提示词管理、版本化、数据集与确定性评估。读完你将掌握这套混合提示词架构托管模板 代码注入变量为何能同时保证可人工调优与永不与语法漂移以及如何用parseGeneratedFiltersfilterStateToQueryText构造一个无需 LLM judge 的确定性评分器。一、功能定位v4 搜索栏的 Ask AI 模式是什么搜索栏Search Bar是 v4 事件表上一个基于语法的查询条详见 search-bar/README.md 的 AI filter mode 一节。它的 Ask AI 模式把一段自然语言请求转换成FilterState直接应用到 v4 的 observations/events 表上。整体数据流如下prompt ( 当前 filters 作为 refine 上下文) → searchBar.generateFilter → LLM → JSON singleFilter[] → parseGeneratedFilters校验 丢弃不可表示项 → 经 setFilterState 应用 → 重新派生为可编辑的 grammar pills几个关键设计点均可在源码中验证功能是 opt-in 的受组织级开关aiFeaturesEnabled控制仅 Cloud 可用服务端和客户端双重门控见 router.ts 中的 FORBIDDEN 分支。Refine 模式打开 AI 模式时搜索栏当前的完整 query 文本会被作为 refine 上下文发送给模型让模型在现有过滤条件之上做编辑而不是从零构建router.ts 的currentQuery输入参数。Scope 严格限定 v4只有searchBar.generateFilter这一个代码路径。v3 时代的 legacy 自然语言过滤器naturalLanguageFilters.createCompletion远程托管 promptget-filter-conditions-from-query是完全独立的代码路径不受本文任何改动影响。二、现状诊断2026-06-23 UX 会话发现的五大问题质量是双峰分布且由模型驱动当时本地测量用的是claude-3-haiku而非管道问题。特定性描述specific prompts准确而简短描述或 refine 请求会退化到 few-shot 示例。问题清单如下严重级发现复现 MajorRefine 会在简短指令下静默破坏现有过滤器。模型复读 few-shot 示例同时忽略用户请求和可见的 refine 上下文从level:ERROR 最近一小时only in production → 生成environment:productionlatency:5幻觉startTime:24h窗口错误level:ERROR被丢弃。also only errors 同样可复现 Major对项目数据无感知不了解真实的 metadata keys / observed valuesrouting queue should be membership-support → 生成traceName:membership-support应为metadata.routing.queue:*membership-support* Mod一次生成后焦点丢失。disabled{pending}让输入框 blur 到body且不再聚焦生成失败/为空后Esc 不再取消必须重新点击输入失败生成后document.activeElement body Mod日期时间 pill 晦涩。last hour 渲染为startTime:2026-06-23T11:12:37.255Z毫秒精度 ISO。属全栏渲染问题由 AI 功能暴露— MinorRefine 上下文以扁平灰色等宽字符串展示被截断而非其他地方使用的彩色 pills— Minor可发现性——Ask AI 是一个小而暗淡的按钮占位符却引导用户使用 DSL没有线索表明 pills 是 AI 生成的—做得好的部分保留特定性构建准确errors in the last hour、user alice slower than 10s、多过滤器组合结果是以透明可编辑 pills 呈现键盘路径Tab→按钮→Enter、Esc、back可用空结果错误提示干净应用是无损的被跳过的过滤器得以保留v3/v4 隔离成立。三、本地提示词实验生产模型Opus 4.8上的表现Piece 1 将 v4 prompt 拿到生产模型eu.anthropic.claude-opus-4-8经 playground SSO profile走 Bedrock上用生产环境的parseGeneratedFilters解析、对照期望的过滤列集合打分跑出一组场景12/13跨运行稳定。核心发现§2 中的 refine 泄漏是claude-3-haiku的弱点——Opus 4.8生产实际使用的模型能正确处理 refine增/删/改且保留上下文。既然生产跑的是 Opus 4.8MVP prompt 保持原样即可上线无需为发布而调优。场景Prompt refine ctx期望列Opus 4.8builderrors in the last hourlevel, startTime✅buildslow traces in productionlatency, environment✅buildfailed traces from user alicelevel, userId✅buildtraces tagged billingtraceTags✅buildaccuracy score below 0.8scores_avg✅buildoutput mentions refundoutput✅buildroot observations onlyisRootObservation✅buildexpensive gpt-4 calls over $0.5totalCost, providedModelName✅refine (add)level:ERROR startTime:… also only in productionlevel, startTime, environment✅ preserved addedrefine (remove)latency:2 drop latency, show only errorslevel✅ removed addedrefine (change)environment:production make it staging insteadenvironment✅ value changededgegibberish无✅ emptygaprouting queue is membership-supportmetadata.routing.queue❌ guesses traceName/sessionId唯一失败的是数据感知缺口模型不知道项目真实的 metadata keys或实际的type/name 值于是猜了一个列。数据感知修复已合入 MVP一个 project data context 数据块被注入 prompt——每列的观测值 metadata keys从可见行中采样的扁平化点路径 当前结果数量。该块在客户端基于已加载的filterOptions 可见行构建见 lib/ai-context.ts并做成本封顶。在 Opus 4.8 上带该上下文重新验证PromptBeforeAfter带 contextonly support chat sessionstype:chat→ 0 行traceName:SupportChatSession✅routing queue is membership-supporttraceName:…/sessionId:…metadata.routing.queue:membership-support✅errors in the last hour对照组✅仍然 ✅从源码看buildAiContext的封顶策略非常具体每列最多 25 个值MAX_VALUES_PER_COL、最多 30 个 metadata keyMAX_METADATA_KEYS、单值最长 40 字符MAX_VALUE_LEN、总上下文硬上限 12000 字符MAX_CONTEXT_CHARS——后者严格低于端点输入校验dataContext: z.string().max(16000)的 16000 字符上限避免触发 Zod 400。metadata 对象会被递归压平为点路径 key深度上限 3并附带一个示例叶子值。这些数字在 lib/ai-context.ts 中都有明确定义。全表面能力覆盖同样在 MVP 中prompt 被扩展为教授完整v4 语法——不止简单的列匹配——并且在 metadata 上大胆使用。在 Opus 4.8 上用变体而非逐字示例验证7/7请求生成结果filter to the acme tenantmetadata.tenant:acmemention password reset in the responseoutput:password resetwhere the sentiment is positivescores.sentiment:positivetraces missing a user id-has:userIdexclude debug and warning levels-level:(DEBUG OR WARNING)tagged with both experiment and baselinetraceTags:(experiment AND baseline)expensive claude calls in staging that arent errorsprovidedModelName:claude totalCost:0.5 environment:staging -level:ERROR也就是说生成器现在覆盖metadata、内容input/output搜索、数值/分类分数、null/has 检查、tag 的 any/all/none 组、以及否定——即从多样化示例中泛化出的完整表面。测试装备与注意点一次性 tsx 脚本对每个场景 shell 调用aws bedrock-runtime converse --profile playground需要 Bedrock 凭据。关键 Caveat质量是模型相关的——本地claude-3-haiku无法通过 refine 用例因此自托管用户若使用较弱模型会看到更差的输出Piece-2 的 eval 将量化模型选择的影响。四、为什么用 Langfuse 自己来打磨这个功能Dogfooding这是典型的 LLM 质量问题。靠肉眼手调 prompt 是在猜而且会静默回归§2 的示例泄漏正是如此。纪律性的修复方式是数据集 evals 版本化提示词度量每一次改动——而这恰恰就是 Langfuse 卖的产品。用 Langfuse 打磨自己的 AI 功能既是正确的工程循环也是地道的 dogfooding。五、当前可观测性基线Baseline✅Tracing 已接通。searchBar.generateFilter每次调用都会经traceSinkParams发送到 AI-features Langfuse 项目envlangfuse-natural-language-filtertraceNamesearch-bar-filtertargetProjectId LANGFUSE_AI_FEATURES_PROJECT_ID受组织级aiTelemetryEnabled门控。generateLLMText记录 systemuser 消息与原始 completion。❌Prompt 在代码里buildFilterPrompt.ts由注册表派生→ 没有版本、无法免部署迭代、没有 prompt↔trace 关联、没有可评估对象。❌缺少结构化 trace 捕获modebuild/refine、currentQuery、解析后的 filters、droppedCount、applied-vs-empty 都没有记录。❌没有 dataset、没有 evals。值得注意的是源码已经比文档基线往前走了一步tracing 的 metadata 中已包含langfuse_refine_mode、langfuse_current_query、langfuse_data_context_chars等调试字段见 router.ts并且已新增 parseOutcomeScoring.ts——它把解析结果parse-empty-result、parse-dropped-filters、parse-unknown-score-names、filter-count、output-markdown-fenced五个分数以 fire-and-forget 的方式写回生成 trace让生产流量自我采集质量信号。output-markdown-fenced是专门盯 haiku 是否在回答开头输出 markdown 围栏的信号。六、架构决策混合提示词Hybrid Prompt不要二选一注册表派生的代码内 prompt vs Langfuse 托管 prompt——拆开它托管模板Langfuse Prompt ManagementAI-features 项目下的新 promptsearch-bar-filter与 v3 的 prompt 分离人类可调优的部分——role、输出格式、intent hints、示例、refine 指令——带变量{{fieldCatalog}}、{{currentDatetime}}、{{currentFilters}}、{{observedContext}}。代码注入变量buildFilterPrompt.ts 收缩为buildFilterVariables()字段目录仍然由FIELDS生成因此不会与语法漂移外加观测上下文metadata keys values用于数据感知修复。端点按 label 拉取 prompt、用这些变量编译并把prompt 版本链接到每条 tracetraceSinkParams中的prompt:字段v3 路径已经这么做了。这是整个方案的支点它让示例和 refine 指令变成可 A/B 的版本化数据——而这恰恰是泄漏发生的地方。源码中的混合解析路径resolveFilterPrompt.ts 完整实现了这一决策优先托管当 AI-features 的 public/secret key 存在时仅事件注册表events使用托管 prompt其他视图仍用本地注册表派生 prompt通过getLangfuseClient拉取search-bar-filter聊天 prompt并用{{catalog}}buildFieldCatalog、{{nullable_ids}}nullableFieldIds、{{current_datetime}}三个注册表派生变量编译。fetch 带fetchTimeoutMs: 2000, maxRetries: 0保证慢速/出错的 AI-features 项目不会拖住用户请求。健壮性校验编译结果若不是合法的 chat 消息数组坏编辑可能编译出字符串、空数组或 malformed 消息logger.warn后回退到代码骨架绝不 500。代码回退兜底自托管无 key是预期状态直接返回代码骨架fetch 抛错也只降级为回退并打 warn。门控语义托管 prompt 的读取只受 AI-features keys 门控读取自己的 prompt 不发送任何组织数据不受aiTelemetryEnabled门控后者只门控 trace 写入与版本链接。仓库还维护了托管 prompt 的种子文件 server/prompts/search-bar-filter.prompt.json标签含production、latest内容与代码 fallback 的 System Prompt 对齐以及推送脚本 scripts/ask-ai/sync-search-bar-filter-prompt.sh——该脚本需由持有真实密钥的人类手动运行Agent 不应执行。字段注册表驱动的提示词永不漂移的关键buildFilterPrompt.ts 的核心思想是模型的全部词汇表就是搜索栏语法本身。specForField根据字段的kind/syncMode派生每个字段允许的type/运算符/值形状镜像 filter-state-to-query.ts 中lowerSingle的反向方向二者不能发散number→ 运算符, , , , 值必须是数字datetime→, , , ISO 8601 字符串boolean→, JSON 布尔exactOption文本 →stringOptionsany of/none of字符串数组arrayOption文本 →arrayOptionsany of/none of/all of字符串数组textSearch文本 →string / contains / does not contain / starts with / ends with单个字符串buildFieldCatalog从EVENTS_FIELD_REGISTRY的fieldsdirectFilter ! false逐行生成目录附带别名、单位、描述与可空标注nullableFieldIds生成支持 null 检查的字段 id 列表。这套目录文本同时被代码构建路径和托管 prompt 编译路径使用保证两条路径看到完全一致的目录。README 还提到一个单元测试__tests__/server/unit/searchBarFilterPrompt.servertest.ts断言每个字段的 prompt 推荐type都能 round-trip防止 prompt 与反向适配器漂移。提示词的结构化指令与数据分离buildFilterSystemPrompt只承载静态指令Role、输出格式、目录、规则、示例、当前时间动态请求数据被 refine 的当前 query、观测到的项目数据由buildFilterContextMessage作为独立的 user 消息发送见 buildFilterPrompt.ts。这样做的三个好处源码注释明示trace 中提示词与喂给模型的数据是清晰分开的两条消息后续用户轮次无法压过原本搭乘在 user 消息里的规则也为把骨架升级为托管 prompt 铺路——动态值不会烤进模板文本。七、狗粮闭环The Dogfood LoopPrompt management labels按productionlabel 拉取在latest上迭代eval 改善后 promote。SDK 按 TTL 缓存以保持请求低延迟。数据集search-bar-filter-evalsAI-features 项目。条目形如{ input: { prompt, currentQuery? }, expected_output: { queryText } }。种子数据包含能工作的用例 失败用例必须保留上下文的简短 refine、routing queue → metadata.routing.queue、时间表达式、分数、多过滤器。确定性评分器输出是结构化的无需 LLM judge把期望与实际输出都解析为归一化的FilterState复用parseGeneratedFiltersfilterStateToQueryText然后评分精确集合匹配、过滤器级 precision/recall/F1以及针对 refine 条目的context_preserved标志。复用的是已有且已测试的代码。跨 prompt 版本和模型跑数据集haiku vs sonnet在 experiments UI 中对比。这就是可度量地消灭泄漏的方式改示例 → 跑 → 看context_preserved从 0→1 → promote。闭环把真实失败的 production traces 策展进数据集可选地加一个在线隐式反馈分数用户是保留了 AI 生成的 filters还是几秒内清掉/编辑了这能按真实使用情况对 prompt 版本排序。数据感知修复#2作为{{observedContext}}变量折叠进来数据集让我们能证明它有效在 routing-queue 用例上做有/无的消融。评分器的地基parseGeneratedFilters 的三道防线文档计划复用parseGeneratedFilters而 parseFilterCompletion.ts 的实际实现给出了完整的三道防护值得展开Registry 契约兼容性检查isRegistryContractCompatible过滤器的type必须与其列契约兼容例如scores_avg不能用裸number过滤器必须用带 key 的numberObject否则events.all会 500——这类过滤器直接丢弃。分数名校验validateScoreNames分数过滤器按名字寻址key拼写错误的分数名能通过 Zod、契约表、语法 round-trip却会成为一个静默匹配不到任何东西的死过滤器。所以把 key 与观测到的分数名集合比对精确匹配保留唯一归一化匹配_/-/空格/大小写不敏感就地纠正其余丢弃并在unknownScoreNames中上报。Round-trip 丢弃任何不能 round-trip 成搜索栏语法的东西未知列、不可表示列进入skippedFilters绝不会到达客户端。此外parseFilterArray有一个非常实用的细节按平衡的顶层[...]子串、从后往前尝试解析——模型有时先输出一版草稿数组、再输出一版自我纠正后的数组从后往前能应用模型的自我纠正而不是丢弃正确答案显式空数组[]被视为模型的无过滤器最终答案并立即返回。生成后的质量信号parse-outcome scoringparseOutcomeScoring.ts 把解析结果写成 trace 上的可查询分数parse-empty-result、parse-dropped-filters、parse-unknown-score-names、filter-count附带截断到 500 字符的 queryText 注释、output-markdown-fenced使生产流量自我采集质量信号。它刻意用独立的 Langfuse 单例客户端带fetchRetryCount: 0、requestTimeout: 3000、FLUSH_TIMEOUT_MS 2000竞速全程 fire-and-forget任何失败都只打 warn、绝不拖慢用户响应——注释里还解释了为什么不能复用natural-language-filters/server/utils.ts的getLangfuseClient该 helper 按首次调用参数记忆化一旦有人先以enabled: false构造后续所有.score()都会静默变 no-op。八、实施路线图TODOPhase 0 — 丰富 tracing小而可并行每条 trace 增加modebuild/refine、currentQuery、解析后的 filters、droppedCount、applied-vs-empty给 trace 打 tag。确认 trace 落在 AI-features 项目内且可按 env 查询。Phase 1 — prompt → Prompt Management混合式在 AI-features 项目创建托管 chat promptsearch-bar-filter含上述变量以当前代码内 prompt 为种子。重构 buildFilterPrompt.ts →buildFilterVariables()目录来自FIELDS 观测上下文。generateFilter按 label 拉取 prompt、编译、把版本链接到 trace。基于 label 的灰度发布production/latestfetch 失败保留代码回退。Phase 2 — eval harness baseline构建search-bar-filter-evals数据集种子用例含失败用例。实现确定性评分器复用parseGeneratedFiltersfilterStateToQueryTextexact-set、F1、context_preserved。通过 Langfuse SDK 写 dataset-run 脚本在改动任何东西之前为当前 prompt模型记录baseline。Phase 3 — 用数据调优迭代 prompt 版本去粘/抽象 few-shot 示例强化 refine 的保留当前 filters只改被要求的部分。加入{{observedContext}}metadata keys observed values消融以证明 routing-queue 修复有效。评估模型选择haiku vs sonnet按分数/成本决策。考虑服务端 refine 守卫除非请求明确移除否则不丢弃上下文 filters或展示 before→after 差异让任何静默丢失可见。Phase 4 — 闭环持续把失败的 production traces 策展进数据集。在线隐式反馈分数N 秒内保留 vs 清除/编辑。快速 UX 修复独立于 eval 循环生成后恢复焦点不让输入框 blur 到 body。Refine 上下文渲染为只读 pills而非扁平截断字符串。更友好的日期时间 pill 渲染全栏范围独立工作流。Ask AI入口的可发现性打磨。九、悬而未决的决策Open Decisions混合 prompt托管模板 代码注入目录/观测变量——支点一切围绕它。评分器确定性集合匹配从这里起步复用现有代码vs 面向语义意图的 LLM judge vs 两者并用。模型留在 Bedrock haiku vs 为该功能换更强模型用 eval 决策而不是凭感觉。十、关键文件地图文件职责server/router.tssearchBar.generateFilter门控、LLM 调用、tracing、parse-outcome 分数写入server/buildFilterPrompt.ts代码内 prompt → 将演变为buildFilterVariables()提供buildFieldCatalog/nullableFieldIds/buildFilterContextMessageserver/resolveFilterPrompt.ts混合解析优先托管search-bar-filterprompt回退代码骨架server/parseFilterCompletion.tsparseGeneratedFilters评分器将复用它server/parseOutcomeScoring.ts解析结果 → trace 分数自我采集质量信号server/prompts/search-bar-filter.prompt.json托管 prompt 的仓库版本种子labels: production/latestlib/fields.tsFIELDS字段注册表目录数据源lib/filter-state-to-query.tsfilterStateToQueryText评分器归一化lib/ai-context.tsbuildAiContext观测值 metadata keys 结果数的成本封顶注入components/SearchBarAiPrompt.tsxAI 子模式 UIweb/src/features/natural-language-filters/server/router.tsv3 参照实现已使用 Prompt Management AI-features trace sink混合模式的范本scripts/ask-ai/sync-search-bar-filter-prompt.sh将托管 prompt 种子推送到各区域需人类手动执行总结这份改进计划最值得借鉴的不是某一段 prompt 文本而是它的工程方法论——把自然语言 → 结构化过滤器这种看似玄学的 LLM 质量问题拆解为注册表驱动的可验证提示词 混合托管架构 确定性评分器 数据集驱动的迭代闭环并用 Langfuse 自身的 Prompt Management、tracing、datasets 与 evals 功能来完成这整个循环。对任何正在构建NL → 结构化查询类功能的团队这套先修数据感知、再上版本化评估、最后闭环策展的路线图都是一份可以直接迁移的参考。【免费下载链接】langfuse Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考