ai自学笔记 (2.prompt 踩坑与优化)

用 Claude API 做结构化 JSON 输出(10 个 hook) 记录问题原因、修复,和复用的 prompt 模板。


踩坑记录

坑 1:模型不输出纯 JSON,而是包裹中文前言

现象 :即使设置了 output_config.format (json_schema),Claude 仍然返回:

复制代码
好的,姐妹!以下是为您生成的 10 个 hook...
{"hooks": [...]}

原因:

  • Claude 4.7 在中文场景下倾向于"礼貌回复",即使有结构化输出约束也会附上前言
  • output_config.format 是约束而非强制------不能 100% 依赖它
  • 中文 system prompt + 中文 user message 时,模型更容易"聊天化"

修复(双层防护):

第一层------Prompt 加强,在 system prompt 末尾加:

复制代码
## 输出格式(极其重要)

你必须只输出一个合法的 JSON 对象,不要加任何前缀说明、后缀总结、markdown 代码块标记。
正确示例:{"hooks":[{"text":"...","style":"悬念式","score":8,"reason":"..."}]}
错误示例:好的,以下是为您生成的...\`\`\`json...\`\`\`
不要输出 "以下是"、"好的"、"为您生成" 这类废话,直接输出 JSON。
  • 用"正确示例"和"错误示例"对比,比单纯说"不要"有效得多
  • 明确列出常见废话("以下是"、"好的"、"为您生成")
  • 放在 prompt 末尾(模型的 recency bias 会让它更重视末尾指令)

第二层------代码容错,在 JSON.parse 前加提取逻辑:

typescript 复制代码
let rawText = textBlock.text.trim();

// 1. 如果被包裹在 markdown 代码块中,提取出来
const codeBlockMatch = rawText.match(/\`\`\`(?:json)?\s*([\s\S]*?)\`\`\`/);
if (codeBlockMatch) {
  rawText = codeBlockMatch[1].trim();
}

// 2. 尝试找到 JSON 对象的起始位置
const jsonStart = rawText.indexOf('{"hooks"');
if (jsonStart > 0) {
  rawText = rawText.slice(jsonStart);
}

// 3. 解析
const data = JSON.parse(rawText);

三层防护(markdown 代码块 → 文本中挖 JSON → 报错)保证健壮。

坑 2:prompt 过长导致模型"浏览"而非"精读"

现象:10 种风格 + 5 个平台规则 + 评分标准,prompt 接近 2000 字,模型可能跳读某些约束。

建议:

  • 关键约束放末尾(recency bias)
  • 用明确的分隔线和层级标题帮助模型定位
  • 不要用"请"、"如果可以的话"这类弱化词------用"必须"、"只能"

坑 3:结构化输出 ≠ 100% 保证

经验 :output_config.format (json_schema) 是概率性约束,不是硬保证。永远要:

  1. Prompt 层面强调格式
  2. 代码层面做 JSON 提取容错
  3. 两个路由(generate + regenerate)都要加同样的容错

可复用的 Prompt 模板

结构化 JSON 输出的通用 System Prompt 模板

复制代码
你是一个[角色描述]。

## 你的任务
[任务描述]

## 规则
[业务规则 1-N]

## 输出格式(最重要)

你必须只输出一个合法的 JSON 对象。
- 不要加任何前缀说明或后缀总结
- 不要用 markdown 代码块包裹
- 不要输出"好的"、"以下是"、"为您生成"等人机对话用语

正确格式示例:
{"key": "value"}

错误格式示例(禁止):
好的,以下是结果... {"key": "value"}
```json
{"key": "value"}


### 关键原则

1. **末尾强调**:格式约束放 prompt 最后一段
2. **正反示例**:同时给出正确和错误的输出示例
3. **明确禁止词**:列出"以下是"、"好的"、"为您生成"、"当然"等常见废话
4. **简短有力**:用"必须"、"禁止"、"只能",不要用"请"、"如果可以的话"
5. **代码兜底**:永远在 `JSON.parse` 前加提取/容错逻辑

---

## 生成类 Prompt 的通用 Checklist

- [ ] 角色定位是否清晰?(一句话,不要多)
- [ ] 输出数量是否明确?("恰好 10 个",不是"10 个左右")
- [ ] 格式约束是否在末尾且醒目?
- [ ] 是否有正反示例对比?
- [ ] 评分/评价标准是否量化?("好奇心缺口 30% + 情感冲击 30%",不是"综合判断")
- [ ] 是否避免了弱化词("请"、"尽量"、"如果可以")?
- [ ] 代码端是否做了 JSON 解析容错?

---

## 编码侧的通用 JSON 提取函数

```typescript
function extractJson<T>(text: string): T {
  let raw = text.trim();

  // 去掉 markdown 代码块
  const codeMatch = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
  if (codeMatch) raw = codeMatch[1].trim();

  // 找到 JSON 起始
  const start = raw.indexOf("{");
  const end = raw.lastIndexOf("}");
  if (start > -1 && end > start) {
    raw = raw.slice(start, end + 1);
  }

  return JSON.parse(raw) as T;
}

这个函数可以复用到任何需要从 AI 响应中提取 JSON 的项目。

相关推荐
星恒随风5 分钟前
Linux基础IO万字详解:从文件描述符fd到重定向、FILE缓冲机制及MiniShell升级
linux·运维·笔记·学习·状态模式
程序员无隅19 分钟前
Matt Pocock 的 Agent 开发工作流:用 /implement-spec、/pr、/retro 完成实现、审查与复盘
ai
最强小杰35 分钟前
claude-sonnet-5.5 API 接入教程:从 Bedrock model_id 路由问题到 Claude Code / Cline 配置全记录
ai
bazingaedward39 分钟前
别让 AI Agent 碰到你的 API Key:给 Claude Code 做一个"只给名字、不给值"的密钥层
agent·claude
喜欢打篮球的普通人42 分钟前
MiniMind 学习笔记(二十二):数学 Cookbook——把概率空间、期望、似然一次讲明白
人工智能·笔记·学习
乐橙开放平台1 小时前
通道国标 ID 贴反会串店:海康大华宇视摄像头怎么用 GB28181 统一接入?
网络·笔记·物联网·自动化·音视频·智能家居
前沿在线1 小时前
破解 AI 推理效率困局,详解华为 OceanStor M900 AI记忆存储新基建
人工智能·ai·大模型
遇码2 小时前
侧边栏一开,AI 画的东西就被挡住了:给白板画布加「真实可见区」计算和相机补偿
人工智能·ai·rust
Jing_jing_X3 小时前
大模型只会输出token,是怎么“调用工具“的?
ai·agent·个人开发·ai应用开发
江屿风3 小时前
【Plain Language Large Model】【理清常见国内外大模型的定位和特长】流食般投喂
人工智能·gpt·claude·glm·gemini·千问·deepseek