场景管理与提示词管理设计方法详解(AI 大模型评测平台的知识资产库)

把”怎么用大模型”沉淀成可复用的资产,才是这类平台真正的门槛。平台早期只是把 prompt 写死在代码里,市场部想复用一段客服话术,得找研发要文件;产品同学改个活动名,要通知所有写了相关 prompt 的人改一遍。这种状态撑到几十个业务方接入后彻底失控,我才开始设计场景(Scene)、提示词(Prompt)、变量(Variable)、版本(Version)四层管理模型。这套结构让平台从”调模型的工具”变成了”存经验的知识库”,下面把设计思路、数据模型和落地坑都讲一遍。

一、为什么要做场景/提示词管理

直接写 prompt 调 API 是 1.0 形态,规模上来后问题会集中爆发。我在设计前专门做了个摸底,把业务方的反馈汇总成四类典型痛点:

  • 同一个 prompt 在代码里改来改去,谁也说不清哪个版本是对的;
  • 业务团队想”复用市场部的客服话术”,找不到沉淀在哪;
  • prompt 里的产品名/活动名要换,发 100 个文件改到崩溃;
  • A/B 测试不同 prompt 效果,没有版本化就回不去。

这些痛点的共同根源是”提示词散落在各处、没有身份”。把它们抽象成”场景 + 提示词 + 变量”三层管理之后,问题就变成了增删改查加版本控制。场景是业务入口(比如”代码审查””客服话术”),提示词挂在场景下、有多版本,变量是模板里的占位符、运行时才填值。三层各管一段,改动的影响范围就清晰了。

二、三层数据模型

三层模型在数据库里的组织方式是这样的:一个场景下面挂多条提示词记录,每条提示词带一个自增版本号,变量定义存在提示词的 variables JSON 字段里:

场景 (Scene)         ← 一个业务场景,如"代码审查"
  └─ 提示词 (Prompt)   ← 多版本,如 v1/v2/v3
       └─ 变量 (Variable) ← 模板中的占位符

场景表负责”这个场景属于谁、是否公开”,提示词表负责”内容 + 版本 + 当前是否生效”,历史表负责留痕。设计时我特意把”当前激活版本”这个字段放在提示词表而不是场景表,因为一个场景同时只有一个 active 版本,但查询”哪个是激活的”要高频发生,放一张表能少一次 join:

CREATE TABLE scene (
  id          BIGINT PRIMARY KEY,
  code        VARCHAR(64) UNIQUE,        -- scene_code
  name        VARCHAR(128) NOT NULL,     -- 中文名
  description TEXT,
  category    VARCHAR(64),                -- 分类
  is_public   TINYINT DEFAULT 0,         -- 公共/私有
  user_id     BIGINT,                    -- 创建者
  created_at  DATETIME
);

CREATE TABLE prompt (
  id          BIGINT PRIMARY KEY,
  scene_id    BIGINT NOT NULL,
  version     INT NOT NULL,              -- 自增版本
  name        VARCHAR(128),
  system_tpl  TEXT,                      -- 系统提示词
  user_tpl    TEXT,                      -- 用户提示词模板
  variables   JSON,                      -- 变量定义 JSON
  model_code  VARCHAR(64),               -- 推荐模型
  parameters  JSON,                      -- temperature/max_tokens
  is_active   TINYINT DEFAULT 0,         -- 当前生效版本
  created_at  DATETIME,
  UNIQUE KEY uk_scene_version (scene_id, version)
);

CREATE TABLE prompt_history (
  id          BIGINT PRIMARY KEY,
  prompt_id   BIGINT NOT NULL,
  version     INT NOT NULL,
  snapshot    JSON,                      -- 完整快照
  changed_by  BIGINT,
  change_note VARCHAR(255),
  created_at  DATETIME
);

这套模型跑通后,有个直观的效果:任何一个 prompt 当前是什么、历史上改过什么、谁改的、为什么改,全都能查到。运维同学再也不用”打开 10 个文件对比 diff”来确认线上跑的是哪版。

三、提示词模板与变量

模板层要做的事是”把占位符替换成真实值”。平台采用 Mustache/Handlebars 风格,变量用双花括号 {{var_name}} 包裹。一个”内容评估”模板长这样:

你是一名{{role}}。

任务:评估以下{{content_type}}。

---
{{user_input}}
---

变量定义用 JSON 存 MySQL 或 JSONB 存 PG,每个变量声明类型、是否必填、可选值和默认值。这样前端能根据变量定义动态渲染表单,而不是让用户手填一坨模板:

[
  {"name": "role", "type": "string", "required": true, 
   "default": "资深技术评审"},
  {"name": "content_type", "type": "string", "required": true,
   "enum": ["代码", "方案", "需求文档"]},
  {"name": "user_input", "type": "string", "required": true}
]

调用时把变量值和模板一起喂给渲染引擎,Java 端一行代码就能完成绑定:

String userPrompt = templateEngine.render(prompt.getUserTpl(), Map.of(
    "role", "算法工程师",
    "content_type", "代码",
    "user_input", codeSubmission
));

这套”模板 + 变量”设计解决了换名字要改 100 个文件的痛点:产品名、活动名都抽成变量,改一处定义,所有引用它的场景自动生效。我对比过直接用字符串拼接的方式,变量一多代码全是拼接逻辑,可读性差还容易漏拼,模板引擎显然是更省心的选择。

四、版本管理策略

提示词最忌讳覆盖写。用户改一个词,如果直接更新原记录,之前跑出来的结果就永远对不上了。平台的策略是”每次修改生成新版本,旧版本只读保留”。新建版本接口的核心逻辑是:读旧版,版本号加一,存成新记录,默认不激活,同时给旧版写一条历史快照:

@PostMapping("/prompt/{id}/newVersion")
public BaseResponse<Long> newVersion(@PathVariable long id, 
                                     @RequestBody PromptDTO dto) {
    Prompt old = promptService.getById(id);
    int nextVer = promptService.maxVersion(old.getSceneId()) + 1;
    
    Prompt newOne = new Prompt();
    newOne.setSceneId(old.getSceneId());
    newOne.setVersion(nextVer);
    newOne.setUserTpl(dto.getUserTpl());
    // ... 其它字段
    newOne.setIsActive(0);  // 新版默认不激活
    promptService.save(newOne);
    
    // 写历史快照
    historyService.snapshot(old);
    return ResultUtils.success(newOne.getId());
}

激活新版本用单独接口,确保”生效”这个动作可控、可审计:

@PostMapping("/prompt/{id}/activate")
public BaseResponse<Void> activate(@PathVariable long id) {
    Prompt p = promptService.getById(id);
    // 同 scene 其它版本置为 inactive
    promptService.deactivateOthers(p.getSceneId());
    p.setIsActive(1);
    promptService.update(p);
    return ResultUtils.success();
}

新版默认不激活这个设计是关键:想先跑个 A/B 对比,直接拿新版本去评测,验证效果后再激活,全程不碰线上正在用的版本。激活接口做了二次确认,防止误操作把线上流量瞬间切到未验证的版本。

五、场景的导入/导出/共享

平台还做了场景市场(marketplace),让沉淀的知识能跨团队流转。这个功能看起来只是”导出再导入”,实际上涉及数据完整性和所有权问题,实现时每个操作都有讲究:

操作 实现
导出 把 scene + 所有 active prompt 打包成 JSON zip
导入 解析 zip,code 重名时提示”覆盖/跳过/重命名”
共享 设 is_public=1 后其它用户可见(只读),可”克隆到我的场景”
复制 跨用户复制为私有,version 从 1 重新计

导出打包这里我踩过一个坑:只导出 active 版本的话,别人拿到场景就丢了历史迭代记录。后来改成”导出全部版本 + 标记哪个是 active”,克隆过去的用户既能看到现状也能追溯历史。共享的只读权限也很重要,否则别人改坏公共场景会影响所有引用它的业务方。

六、与评测流程的衔接

场景和提示词管理不是孤岛,最终要能一键发起评测,否则资产存得再漂亮也只是静态库存。平台的做法是让激活版本的提示词能直接转成 Side-by-Side 评测会话:

"代码审查"场景
  └─ v3 提示词 (active)
       └─ 点击「跑这个」
            → 选 3 个模型
            → 批量调 LLM
            → 转成 SxS session

promptService 提供 toEvalSession(modelCodes) 方法,把激活版 prompt + 用户输入的变量值打包成 SxS session 请求,零代码完成”看效果”。这个衔接让”调 prompt → 看效果 → 再调”形成闭环,用户不用在两个系统里手动搬数据。实现时注意要把变量值一起传进会话,否则评测时模板渲染缺参数,直接跑出一堆空字段。

七、踩过的坑

这套资产库上线后踩过的坑,集中在变量校验、模板安全和版本切换三个方向,逐个列出来:

  • 变量缺失未报错:用户传 {role, content_type} 漏 user_input,直接渲染出空字符串,调 LLM 给一堆废话。要在渲染前校验 required 字段。
  • 模板注入风险:用户输入里含 {{xxx}} 字面量,被 Mustache 二次渲染执行。要么用不冲突的占位符(如 [[var]]),要么用 escapeHtml 处理。
  • 版本切换影响线上:激活 v3 后所有用这个场景的 SxS 立刻切到 v3,可能引起评分漂移。激活操作要二次确认+灰度。
  • JSON 字段查询慢:早期用 MySQL JSON 字段做”按变量名查询”,性能差。改为把”变量定义”做反范式表 prompt_variable 单独存。
  • 删除场景有外键:提示词、评测历史都引用 scene_id,硬删会爆。改为软删 is_deleted=1,后台定期归档。

模板注入这个坑是我在一次安全自查时发现的:用户在变量里填了 {{system}} 这样的字面量,渲染时被 Mustache 当成占位符二次替换,会执行出意外内容。改成 [[var]] 占位符后彻底绕开。变量缺失报错那条则是线上真出过的事故,评测结果全是空输出,排查半天发现是模板渲染少了变量,之后所有渲染前强制走 JSON Schema 校验。

八、最佳实践清单

跑通一年多后,把经验收敛成五条最佳实践,新业务方接入时直接照做:

  1. 提示词版本不可变:只能新增不能修改,每次改动写一行新版本。
  2. 激活版本不重复:同一场景只能有一个 active 提示词。
  3. 变量必填校验:渲染前用 JSON Schema 校验,必填缺失返回 400。
  4. 变更留痕:每次改动写一行 prompt_history,记录变更人、变更说明。
  5. 场景可复用:跨场景可”引用”提示词(不复制),适合基础角色定义。

最后一条”场景可复用”是后期才加的能力:不同场景都要用”资深技术评审”这个基础角色,如果每个场景复制一份,改一处要同步十处。改成引用关系后,基础角色定义只维护一份,所有引用场景即时生效。到这里,从场景建模到提示词版本、再到市场流通的知识资产库设计就完整了。

常见问题(FAQ)

Q1:为什么不直接用文件/YAML 存提示词?

规模小可以,团队 5 人内 YAML 够用。规模上来后查、改、版本、权限都难做,结构化存储是必然。

Q2:变量校验用 JSON Schema 吗?

简单场景用 Map 校验即可,复杂字段(如 enum、range)才用 JSON Schema。平台支持两种混合模式。

Q3:场景市场会被刷垃圾内容吗?

公共场景走审核流,发布前管理员抽样评估质量。is_public=1 后不可回退到私有,避免共享后突然隐藏。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部