news 2026/9/8 16:08:41

Day68-结构化Prompt设计:XML标签法/Markdown法/JSON Schema

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day68-结构化Prompt设计:XML标签法/Markdown法/JSON Schema

一、为什么 Prompt 必须"结构化"

Prompt 的本质是"自然语言版的接口契约"。如果不结构化,会出现 4 个真实的工程问题:

问题

表现

根因

解析失败

下游解析 JSON / Bean 时格式抖动

模型输出的边界不规范

难以 review

PR 里 5000 字没人看得完

没有分块、没有角色标签

改动难追溯

不记得当时为什么这么写

改动位置和意图没标记

多语言模型切换

GPT-4o 好用换 Claude 翻车

不同模型对格式的"理解偏好"不同

结论:把 Prompt 当代码写,需要 module、role、constraint 三件套——这正是结构化方法的共同特征。

下面三种方法,分别对应"读起来舒服"、"人类写起来高效"、"机器解析最稳"三个目标。

二、XML 标签法:最稳的结构化方案

XML 标签是 Anthropic 官方推荐的方式(《Claude Prompt Engineering Guide》明确提到 XML 在 Claude 上表现优于 Markdown)。它的核心思想是把 Prompt 切成有名字的分区

2.1 一个完整的 XML Prompt 模板

<role> 你是一名资深 Java 性能调优工程师,专精 JVM GC 和 Arthas 诊断。 </role> <context> 应用的 JVM 参数:-Xms4g -Xmx4g -XX:+UseG1GC 应用的 QPS:2000,平均 RT:50ms 线上出现的问题:每 6 小时一次 Full GC,每次 STW 800ms </context> <task> 根据 <context> 提供的信息,分析 Full GC 频繁的根因,并给出可落地的调优方案。 </task> <constraints> - 回答必须用中文 - 长度控制在 500 字以内 - 必须按"根因分析 → 调优建议 → 验证步骤"三段式输出 - 不要列超过 5 条建议,每条都要量化收益 </constraints> <output_format> ## 根因分析 - (3~5 条) ## 调优建议 - 建议 1:(具体参数 + 预期效果) - 建议 2:... ## 验证步骤 1. ... </output_format>

为什么用 XML 而不是 Markdown?

  1. 首尾匹配的语义清晰<context>...</context>一对标签就是一块语义完整的区域,模型不会被同级的标题层级搞混。
  1. 可嵌套<context>里可以再嵌<jvm_params><qps>,适合多源信息融合。
  1. Claude 模型显著更稳:Anthropic 官方基准测试中,XML 标签法在 Claude 3.5/4 上的指令遵循率高 8%~15%。

2.2 配合 Spring AI 的 StringTemplate 落地

// XML 标签法的 Spring AI 落地——用 StringTemplate 把 XML 模板化 // 依赖:spring-boot-starter-ai-openai-spring-boot-starter 1.0.0+ @Component public class XmlPromptJVMAdvisor { private final ChatClient chatClient; // 推荐:把 XML 模板写在独立的 .st 文件里,这里为演示内联在代码中 private static final String XML_TEMPLATE = """ <role> 你是一名资深 Java 性能调优工程师,专精 JVM GC 和 Arthas 诊断。 </role> <context> JVM 参数:{jvmArgs} QPS:{qps},平均 RT:{rtMs}ms 现象:{symptom} </context> <task> 根据 <context> 给出 GC 调优方案,要求可落地。 </task> <constraints> - 中文输出,长度 ≤ 500 字 - 按"根因 → 建议 → 验证"三段式 - 建议不超过 5 条,每条量化收益 </constraints> """; public XmlPromptJVMAdvisor(ChatClient.Builder builder) { this.chatClient = builder.build(); } public String advise(String jvmArgs, int qps, int rtMs, String symptom) { String prompt = XML_TEMPLATE .replace("{jvmArgs}", jvmArgs) .replace("{qps}", String.valueOf(qps)) .replace("{rtMs}", String.valueOf(rtMs)) .replace("{symptom}", symptom); return chatClient.prompt() .user(prompt) .call() .content(); } }

老梁踩坑:模板里如果想强调某个变量,不能用<b>标签——模型会原样输出<b>强调用"重要"二字包一层,或用<critical>这种语义化标签,不要用 HTML 的b/strong/i

三、Markdown 法:人类阅读体验最好

Markdown 法是 LLM 训练数据里最常见的格式(GitHub、知乎、技术博客全是 Markdown),模型对它天然友好,适合给人类同事看的 Prompt 文档

3.1 一个完整的 Markdown Prompt

````markdown # 角色 你是一名 MySQL DBA,熟悉 InnoDB 锁机制。 # 背景信息 - 数据库版本:MySQL 8.0.32 - 表结构:`orders(id, user_id, status, created_at)`,无索引 - 当前 SQL: ```sql SELECT * FROM orders WHERE user_id = 123 AND status = 'PAID'; ````

任务

分析这条 SQL 的性能问题,给出索引优化方案。

输出要求

  1. 列出 2~3 个根因
  1. 给出完整的 DDL 语句
  1. 用 EXPLAIN 验证优化后的执行计划
  1. 输出长度 ≤ 300 字
**Markdown 优势**: - **代码块天然支持**:用 ` ```sql ` 包 SQL,模型不会"误读"为自然语言。 - **层级清晰**:# / ## / ### 对应"角色→任务→细节"的认知层级。 - **写起来快**:VSCode、Jupyter、`resources/prompts/*.md` 文件都好管理。 ### 3.2 配合 Spring AI 资源文件管理 把模板外置到 `src/main/resources/prompts/order_optimizer.md`,代码里读文件渲染: //java // Markdown 模板 + Spring AI 的标准用法 // 文件位置:src/main/resources/prompts/order_optimizer.md @Component public class MarkdownPromptSqlAdvisor { private final ChatClient chatClient; private final Resource templateResource; public MarkdownPromptSqlAdvisor( ChatClient.Builder builder, @Value("classpath:prompts/order_optimizer.md") Resource templateResource) { this.chatClient = builder.build(); this.templateResource = templateResource; } public String advise(String mysqlVersion, String tableSchema, String sql) { // Spring AI 的 PromptTemplate 自动加载 .md 文件,{var} 占位符替换 PromptTemplate template = new PromptTemplate(templateResource); Prompt prompt = template.create(Map.of( "mysqlVersion", mysqlVersion, "tableSchema", tableSchema, "sql", sql )); return chatClient.prompt(prompt).call().content(); } }

对应的order_optimizer.md内容(用{{var}}占位):

# 角色 你是一名 MySQL {{mysqlVersion}} DBA,熟悉 InnoDB 锁机制。 # 背景信息 表结构:`{{tableSchema}}` 当前 SQL: ```sql {{sql}}

任务

分析这条 SQL 的性能问题,给出索引优化方案。

输出要求

  1. 2~3 个根因
  1. 完整 DDL
  1. EXPLAIN 验证计划对比
  1. 长度 ≤ 300 字
**Markdown vs XML 怎么选?** - **给模型看 + 强约束输出** → XML(标签首尾匹配,模型不易漏字段) - **给同事 review + 跨模型兼容** → Markdown(人人能读,所有模型都认) - **多个变量 + 需要代码块** → Markdown(XML 包代码块需要 CDATA,麻烦) - **Claude 模型 + 多层语义嵌套** → XML(Claude 的最优解) ## 四、JSON Schema 法:机器解析最稳 当 Prompt 的输出要被下游系统**直接消费**(入库、渲染、写代码)时,必须用 JSON Schema 约束输出。这是结构化输出的"终极方案"。 Spring AI 提供了 `BeanOutputConverter` 和 `ListOutputConverter`,把 Java Bean 直接作为输出契约: ### 4.1 定义强类型的输出契约 ```java // 用 Java Bean 直接定义大模型的输出契约 // 依赖:spring-boot-starter-ai-openai-spring-boot-starter 1.0.0+ public record SqlOptimizationReport( List<String> rootCauses, // 根因列表 List<String> ddlStatements, // DDL 语句列表 String explainExpectedPlan, // 优化后 EXPLAIN 预期 List<String> validationSteps // 验证步骤 ) {}

4.2 用 BeanOutputConverter 一行搞定

// Spring AI 的 BeanOutputConverter 自动把 Bean 描述转成 JSON Schema @Component public class JsonSchemaSqlAdvisor { private final ChatClient chatClient; private final BeanOutputConverter<SqlOptimizationReport> converter; public JsonSchemaSqlAdvisor(ChatClient.Builder builder) { // 关键:把转换器声明出来,Spring AI 会自动生成 JSON Schema this.converter = new BeanOutputConverter<>(SqlOptimizationReport.class); this.chatClient = builder.build(); } public SqlOptimizationReport advise(String sql, String tableSchema) { // 把 JSON Schema 注入 system 消息,告诉模型必须按这个格式输出 String systemPrompt = """ 你是 MySQL 8.0 性能优化专家。 %s """.formatted(this.converter.getFormat()); String userPrompt = """ 表结构:%s 待优化 SQL:%s """.formatted(tableSchema, sql); // chatClient 返回的是 String,需要 converter 转成 Bean String rawJson = chatClient.prompt() .system(systemPrompt) .user(userPrompt) .call() .content(); // 直接反序列化为强类型 Bean,下游代码无 if-else return this.converter.convert(rawJson); } }

converter.getFormat()会自动生成类似下面的指令注入到 system 消息里:

Your response should be a JSON object with the following structure: { "rootCauses": ["string"], "ddlStatements": ["string"], "explainExpectedPlan": "string", "validationSteps": ["string"] }

4.3 列表场景用 ListOutputConverter

如果只要一个字符串列表,更轻量:

// ListOutputConverter 用于"输出必须是 List<String>"的简单场景 @Component public class BugRootCauseExtractor { private final ChatClient chatClient; private final ListOutputConverter converter; public BugRootCauseExtractor(ChatClient.Builder builder) { this.converter = new ListOutputConverter(new DefaultConverterService()); this.chatClient = builder.build(); } public List<String> extract(String stackTrace) { String systemPrompt = """ 你是 Java 异常分析专家。请从堆栈中提取 N 个独立根因。 %s """.formatted(converter.getFormat()); return (List<String>) converter.convert(chatClient.prompt() .system(systemPrompt) .user("堆栈:%s".formatted(stackTrace)) .call() .content()); } }

JSON Schema 的两条血泪经验

  1. Bean 的字段加 JSR-380 注解@NotBlank@Size(max=200)不会自动约束大模型,但能让 Bean 校验失败时立刻抛错,比让模型给你一个空字符串好排查得多。
  1. 大模型 100% 不会严格遵循 JSON Schema:实测 GPT-4o 的 JSON 格式正确率约 95%、Qwen 约 88%。下游必须有容错(@JsonIgnoreProperties(ignoreUnknown = true)+ 字段默认值),不能假设模型给的就是合规 JSON。

五、三种结构化方案对比

维度

XML 标签法

Markdown 法

JSON Schema 法

人类可读

模型可读

优(Claude 首选)

机器解析

中(需 regex 提取)

优(强类型映射)

多变量模板

嵌套语义

跨模型兼容

适用输出

长文本、结构化文本

长文本、代码块

强类型数据

Spring AI 支持

手动 StringTemplate

PromptTemplate + Resource

BeanOutputConverter 原生

老梁的项目用法:团队协作的场景统一用 Markdown;调用 Claude API 的场景叠一层 XML 标签;输出要入库的场景用 JSON Schema。三者不是互斥,是组合拳。

六、建议

  1. 团队统一一套结构化规范

    别让团队里有的同事写 XML、有的写 Markdown、有的写大段散文。建议制定一个 30 行以内的"团队 Prompt 规范"塞进 wiki——只规定「角色 / 背景 / 任务 / 约束 / 输出」五个分区,强制每条 Prompt 都按这个分区写。可以参考我团队的简化版:

    [角色] 一句话定义专家身份 [背景] 关键参数、上下文 [任务] 用动词开头的一句话目标 [约束] 长度、格式、语言 [输出] Markdown / JSON / 文本

    写完后强制走 PR review,Prompt 跟代码一样要 review

  2. JSON Schema 输出必须有兜底解析

    即使 95% 准确率,在 100 万次调用里也有 5 万次格式错误。建议用 Spring AI 的BeanOutputConverter+ Jackson 容错配置:

    ObjectMapper mapper = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);

    或者外加一层"AI 输出→Java Bean"的包装,把解析失败统一转成Optional.empty()抛给上层重试。

  3. 跨模型切换要做 Prompt 兼容性测试集

    我团队的踩坑:同一份 Prompt 从 DeepSeek 切到 GPT-4o 后,JSON 格式正确率从 92% 跳到 97%(好),但 XML 标签下的语义遵循率从 95% 跌到 88%(差,因为 GPT-4o 对 XML 不如 Claude 敏感)。结论:每个模型至少备 50 个标注样本做格式回归测试,别凭感觉切。


结构化 Prompt 不是为了好看,是为了让你半夜被叫起来排查时,能 30 秒看清这份 Prompt 在干什么。

下篇预告:Prompt 写出来不是结束——你在生产里会改它 A/B、把它回滚、用 Git 管它。下一篇我们聊《Prompt 调试与版本管理:像管理代码一样管理 Prompt》,教你用 Langfuse + Git 做 Prompt 的灰度发布和回滚。

往期回顾:

  • 90篇JAVA高级深度分析与实践文章:做AI的主人,代码直接可用,附完整目录
  • Day67-Prompt工程核心技巧:从零样本到思维链(CoT)
  • Day66-开源模型vs闭源模型:技术决策框架
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 16:08:31

C++20 ranges视图缓存陷阱:filter_view为何重复遍历结果异常?

前阵子帮同事排查一个数据清洗的 bug&#xff0c;现象特别诡异&#xff1a;一段用 std::ranges 写的过滤管道&#xff0c;第一次 for 遍历输出完全正常&#xff0c;第二次遍历同一个视图&#xff0c;第一个元素却凭空“多出来”了。同事第一反应是容器被谁改了&#xff0c;…

作者头像 李华
网站建设 2026/9/8 16:07:55

哪些项目适合AI做

不是所有问题&#xff0c;都需要 AI。比如&#xff1a;有无检测&#xff1b;尺寸测量&#xff1b;边缘定位&#xff1b;简单字符识别&#xff1b;规则形状判断。这些问题&#xff0c;如果光源稳定、位置固定、背景干净&#xff0c;用阈值、边缘、模板匹配这些方法&#xff0c;反…

作者头像 李华
网站建设 2026/9/8 16:05:34

网站分析工具怎么选?3大类15款工具全盘点

网站分析工具怎么选&#xff1f;答案不是看榜单&#xff0c;而是按“业务阶段 → 核心诉求 → 预算 → 工具组合”四步走。市面上的工具大致分成三类&#xff1a;免费基础监测款、SEO与竞品洞察款、企业级AI Agent平台。它们各自解决不同规模与预算下的问题&#xff0c;核心目标…

作者头像 李华
网站建设 2026/9/8 16:03:40

C++实现一笔画游戏:欧拉路径算法与图形渲染

1. 项目概述&#xff1a;C实现一笔画游戏的核心思路一笔画游戏是一种经典的逻辑益智游戏&#xff0c;玩家需要在不重复经过任何线条的前提下&#xff0c;用一笔连续画出整个图形。这个看似简单的游戏背后蕴含着欧拉路径的数学原理&#xff0c;而用C实现它则涉及图形渲染、算法设…

作者头像 李华
网站建设 2026/9/8 16:03:33

Docker容器化实战:从环境冲突到镜像、容器与MySQL/Redis编排

前阵子有朋友找我排查环境问题&#xff1a;一台上线不久的服务器上&#xff0c;MySQL 8.0 一启动&#xff0c;Redis 服务就开始丢连接&#xff0c;再仔细看&#xff0c;Java 服务依赖的某个系统库版本也被一连串升级动作搞坏了。他说明明装的时候每一步都照着文档来&#xff0c…

作者头像 李华