十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

reactive-resume 的 AI 对话系统提示词设计:JSON Patch 提案制简历编辑助手全解析

reactive-resume 的 AI 对话系统提示词设计:JSON Patch 提案制简历编辑助手全解析 reactive-resume 的 AI 对话系统提示词设计JSON Patch 提案制简历编辑助手全解析【免费下载链接】reactive-resumeA one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever. Try it out today!项目地址: https://gitcode.com/GitHub_Trending/re/reactive-resume本篇以 chat-system.md 为核心拆解 reactive-resume 中 AI 对话编辑简历的系统提示词System Prompt设计它以“只允许通过propose_resume_patches工具发起 JSON PatchRFC 6902提案、用户逐条审批后才生效”为核心机制。读完本文你将掌握这套“提示词 工具 Schema 服务端校验 人工审批”四层防线的完整实现并能理解从提示词模板加载、动态数据注入、工具调用、提案规范化到补丁校验回滚的全链路调用关系。一、系统提示词的定位与加载机制chat-system.md 定义了 AI 助手在“对话式修改简历”场景下的角色与行为契约其首句即明确了整体设计立场You are a resume editing assistant that must propose resume data changes only through JSON Patch (RFC 6902) proposal tool calls.也就是说模型被约束为“只提建议、不做决定”的角色任何数据变更都必须走propose_resume_patches工具调用由用户审查后应用。这是 reactive-resume AI 功能中“人在回路Human-in-the-loop”安全模型的关键一环。该模板在 packages/ai/src/prompts.ts 中通过readPrompt在模块加载时从磁盘读取并导出为chatSystemPromptTemplate// packages/ai/src/prompts.ts const readPrompt (filename: string) { return readFileSync(new URL(./prompts/${filename}, import.meta.url), utf-8); }; const chatSystemPromptTemplate readPrompt(chat-system.md);与同目录下的解析类提示词如 parser-system.md 通过变量替换生成 PDF/DOCX 两个变体不同chat-system.md只有一个{{RESUME_DATA}}占位符由 API 层在运行时注入当前简历数据见第四节。这种“Markdown 模板 运行期变量替换”的组织方式让提示词可以独立于代码评审、版本化和测试——prompts.test.ts 就断言了模板内容包含 resume 等基本约束。二、系统提示词全文核心内容详解以下按原文档的章节顺序完整继承并逐节展开。2.1 Objective目标与最小化编辑原则原文档 Objective 部分给出三条目标帮助用户改进简历内容与结构Help the user improve resume content and structure通过propose_resume_patches工具安全、最小化地提出编辑Propose edits safely and minimally所有提案在应用前都由用户审查The user reviews every proposal before anything is applied。“最小化编辑”这一原则并非口号它贯穿到了工具层后文的operations数组支持把多个操作聚合为一个提案而提示词明确要求“生成满足请求所需的最小操作集合”Hard Constraint 2避免模型用整对象替换的方式重写无关字段。2.2 Allowed Inputs输入边界原文档明确模型可见的输入只有两类对话中的用户指令User instructions in conversation下方提供的当前简历 JSON 状态Current resume JSON state provided below。从源码结构看这一边界是可信的API 层的chat处理器只把messages对话历史和resumeData从数据库按resumeId查出的简历传给模型见 service.ts 中的buildChatSystemPrompt与streamText调用。模型接触不到用户档案、应用追踪等其它数据提示词层面的“Allowed Inputs”与代码层面的实际注入一致。2.3 Hard Constraints九条硬约束这是整份提示词最核心的部分原文档列出 9 条硬约束逐条如下#硬约束设计意图1任何数据变更都必须调用propose_resume_patches禁止在聊天文本中直接输出原始 patch 数组保证变更走工具通道可被 UI 结构化渲染为审批卡片2生成满足请求所需的最小操作集合防止模型“顺手重写”无关字段缩小 diff 与误伤面3除非用户明确要求替换或删除否则保留现有数据默认保守编辑4破坏性编辑删除、清空、替换大段内容前必须先请求确认人工审批兜底5保持简历主题聚焦拒绝跑题请求限制助手职责范围6不得虚构用户的事实履历起草内容必须标注为草稿并请求确认防幻觉污染简历这一事实性文档7所有 path 与 op 必须符合 RFC 6902 及当前 schema与后文 Zod 校验、fast-json-patch校验双层防线呼应8新建条目的 ID 必须是xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx格式的 UUID与简历数据模型中条目id字段约定一致9HTML 字段如 summary/description必须使用合法 HTML按需使用p、ul、li、strong、em简历渲染层按 HTML 渲染富文本纯文本会破坏排版2.4 Conflict Resolution Order冲突消解顺序当指令之间存在张力时原文档给出三级优先级数据安全与 schema 合法性Data safety and schema validity来自最新指令的用户意图User intent from latest instruction最小化编辑策略Minimal-change editing strategy可以推断这条顺序对应了实际系统的行为即使用户意图与数据安全冲突补丁也会被 patch.ts 的applyResumePatches拒绝见第四节校验流程——提示词是“软约束”代码校验是“硬约束”两者同向叠加。2.5 Editing Rules编辑规则原文档给出五条具体操作规则优先使用定向的replace操作而非整对象替换追加列表项时用add指向/items/-JSON Pointer 的数组末尾追加语法remove仅在用户明确要求或已确认时使用website对象保持{ url: string, label: string }的形状hidden字段必须保持显式布尔值。这些规则都是针对简历数据模型的“易错点”量身定制的。例如add at /items/-的用法在测试中有直接印证patch.test.ts 中向/sections/skills/items/-追加一条技能随后result.sections.skills.items长度变为 1验证了该路径约定真实可用。2.6 Resume Shape Reference数据结构参考原文档给模型提供了简历数据的“地图”避免模型猜路径顶层键basics、summary、picture、sections、customSections、metadatasections内的条目家族profiles、experience、education、projects、skills、languages、interests、awards、certifications、publications、volunteer、references。这份参考与 packages/schema 中定义的ResumeData结构对应。由于当前简历 JSON 本身会注入到提示词末尾见 2.8 节模型实际上有“地图 实景”双重参照可以在生成 patch 前核对目标路径是否存在。2.7 Output Contract 与 Proposal Shape输出契约与提案形状原文档对“怎么回话”和“提案长什么样”分别做了规定Output Contract输出契约需要变更时调用propose_resume_patches且不要再追加文本回复——提案细节由 UI 展示无需变更时不调用工具直接给出简洁指导永远不要在聊天回复中包含 patch 负载的 Markdown 代码块。Proposal Shape提案形状以proposals数组返回一个或多个内聚提案每个提案包含title、可选summary和operations必须一起批准的操作归入同一提案不相关的变更拆成独立提案方便用户逐页审批。这两组约定与工具层 Schema 完全对齐patch-proposal.ts 中resumePatchProposalToolInputSchema要求proposals至少一项每项含必填title、可选summary和至少一条operationsz.array(jsonPatchOperationSchema).min(1)。patch-proposal.test.ts 明确断言“空 operations 的提案会被拒绝”。2.8 动态注入当前简历数据模板末尾保留了数据注入锚点## Current Resume Data json {{RESUME_DATA}}上面为模板结构示意实际占位符内容见 [chat-system.md](https://link.gitcode.com/i/8a4d4d28cea7247d390d3ecf4aabe501#L58-L62) 服务端在 [service.ts](https://link.gitcode.com/i/bfaa54226f87c7b06f38cd33fcd244ba) 中完成替换 ts function buildChatSystemPrompt(resumeData: ResumeData): string { return chatSystemPromptTemplate.replace({{RESUME_DATA}}, JSON.stringify(resumeData, null, 2)); }即每次对话请求时当前简历的完整 JSON2 空格缩进都会被拼进系统提示词。这解释了 Hard Constraint 7“path 必须对当前 schema 有效”为何可行——模型确实看得见当前数据。同时注意注入的是未经裁剪的简历数据意味着该接口只应在已鉴权、且用户拥有该简历的前提下调用见下一节的 API 入口。三、API 入口/ai/chat与审批流chat-system.md描述的行为最终由 API 层落地。router.ts 中的chat过程使用protectedProcedure要求登录态输入为{ aiProviderId?, messages: UIMessage[], resumeId: string }挂载aiRequestRateLimit限流中间件handler 并行解析出“可运行的 AI Provider 凭据”和按resumeId 当前用户 ID 查出的简历然后调用aiService.chat并把resume.updatedAt一并传入——它会成为每条提案的baseUpdatedAt用于前端检测“提案基于哪个版本的简历”。路由的描述文案本身就概括了这套机制Streams a chat response from the configured AI provider. The LLM can call the propose_resume_patches tool to generate JSON Patch proposals for explicit user approval.注意“proposals forexplicit user approval”——服务端不自动落库用户在前端确认后才真正写入简历这正是提示词 Objective 中“用户先审查”的代码侧兑现。四、propose_resume_patches工具的底层实现4.1 工具注册与流式多步调用在 service.ts 的chat函数中模型通过 Vercel AI SDK 的streamText运行工具在tools配置中注册tools: { propose_resume_patches: tool({ description: Return one or more cohesive resume change proposals. Each proposal must include a title, optional summary, and valid JSON Patch operations against the current resume data. The tool validates but does not apply changes., inputSchema: resumePatchProposalToolInputSchema, outputSchema: resumePatchProposalToolOutputSchema, execute: (toolInput) { const proposals normalizeResumePatchProposals(toolInput, input.resumeUpdatedAt); for (const proposal of proposals) { applyResumePatches(input.resumeData, proposal.operations); } return { proposals }; }, }), }, stopWhen: stepCountIs(3),两个实现细节值得注意“validates but does not apply”execute中对每个提案调用applyResumePatches而 patch.ts 的实现是“先校验、再在深拷贝上打补丁、最后对结果重跑parseResumeData校验”不修改传入对象。因此这里的调用实质是一次“试算校验”路径不存在、test断言失败或补丁后数据不合法都会抛错让工具执行失败从而把错误反馈回模型stopWhen: stepCountIs(3)允许模型在最多 3 步内修正重试校验通过才把提案原样返回给 UI 等待用户审批。工具名与提示词严格一致提示词中的propose_resume_patches与注册键完全同名[[RESUME_DATA]]注入、工具描述、提示词三者共同构成完整的工具契约。service.test.ts 中用type: tool-propose_resume_patches的消息断言了工具调用的流式输出形态。4.2 提案的规范化id 与 baseUpdatedAtpatch-proposal.ts 的normalizeResumePatchProposals做两件模型不必操心的事export function normalizeResumePatchProposals(input, baseUpdatedAt?) { return input.proposals.map((proposal, index) ({ ...proposal, id: proposal.id ?? proposal-${index 1}, ...(baseUpdatedAt ? { baseUpdatedAt: baseUpdatedAt.toISOString() } : {}), })); }模型可以不生成id输入 Schema 中id是 optional服务端按顺序补proposal-1、proposal-2……降低模型出错面把简历的updatedAtDate统一序列化为 ISO 字符串写入每条提案的baseUpdatedAt。patch-proposal.test.ts 验证了这两点无 id 输入可正常解析baseUpdatedAt被规范为 JSON 安全的 ISO 时间戳测试中为2026-05-10T06:38:27.093Z。4.3 JSON Patch 操作的结构化校验提示词要求“op 与 path 符合 RFC 6902 及当前 schema”代码侧由 patch.ts 的判别联合 Schema 把六种操作约束在请求边界上export const jsonPatchOperationSchema z.discriminatedUnion(op, [ z.object({ op: z.literal(add), path: z.string(), value: z.unknown() }), z.object({ op: z.literal(remove), path: z.string() }), z.object({ op: z.literal(replace), path: z.string(), value: z.unknown() }), z.object({ op: z.literal(move), path: z.string(), from: z.string() }), z.object({ op: z.literal(copy), path: z.string(), from: z.string() }), z.object({ op: z.literal(test), path: z.string(), value: z.unknown() }), ]);[patch.test.ts](https://link.gitcode.com/i/afb0a4360a2c18476fa36487e9a2c993)逐一验证了字段约束add必须有value、move必须有from、未知 op如swap被拒绝——这意味着模型即使生成非法 op也会在 AI SDK 的输入校验层inputSchema就被拦下。4.4 补丁应用校验、试算与回滚applyResumePatchespatch.ts的三步流程与提示词“Data safety and schema validity 优先”的冲突消解顺序一一对应结构预校验jsonpatch.validate(operations, data)失败即抛出ResumePatchError携带code、index失败操作下标和operation失败操作对象但刻意不携带整棵文档树试算应用jsonpatch.applyPatch(data, operations, false, false)在内部克隆的文档上执行test断言不匹配会直接抛错结果 schema 回滚校验补丁后的文档必须通过parseResumeData否则抛出Patch produced invalid resume data——即使每个操作本身合法只要整体结果不符合简历 schema 也整体拒绝。对应的错误语义表patch.ts把fast-json-patch的内部错误码翻译为人类可读消息例如OPERATION_PATH_UNRESOLVABLE路径不存在、OPERATION_VALUE_OUT_OF_BOUNDS数组越界、TEST_OPERATION_FAILED断言不匹配。测试 patch.test.ts 展示了回滚的实际效果把/picture/size替换为 9999超出 schema 的 32–512 范围会整体抛错原数据保持不变另有测试断言输入对象不被修改。4.5 端到端防线总结把提示词与源码串联起来一条“把 TypeScript 加进技能列表”的用户指令的完整链路是系统提示词含当前简历 JSON 对话历史发往模型模型按 Hard Constraints 生成最小操作调用propose_resume_patches例如对/sections/skills/items/-执行add提示词 Editing Rule 与 patch.test.ts 的用法一致AI SDK 用resumePatchProposalToolInputSchema校验工具输入title 非空、operations 至少一条normalizeResumePatchProposals补id/baseUpdatedAtapplyResumePatches做“预校验 → 试算 → 结果 schema 校验”任何一步失败都让工具执行报错模型在 3 步内可修正校验通过的提案流式返回前端渲染为审批卡片用户批准后变更才真正写入简历数据。五、从这份提示词中可以提取的设计模式以 chat-system.md 为主体回看它示范了一套可复用的“LLM 修改结构化数据”提示词工程模式单一变更通道把“怎么改数据”收敛到一个具名工具上聊天文本只负责解释与确认Output Contract 三条使 UI 可确定性地解析并渲染每一次变更把数据模型地图写进提示词顶层键、条目家族、website/hidden等易错字段形状2.5、2.6 节配合运行期注入的完整 JSON把“路径猜错”这类高频错误压到最低约束与校验同构提示词中的 RFC 6902 要求对应jsonPatchOperationSchema“不虚构履历、标注草稿”对应结果 schema 回滚校验“破坏性操作先确认”对应用户审批环节。提示词负责“让模型倾向正确”代码负责“让错误无法生效”提案分组策略“必须一起批准的放一组不相关的拆开”Proposal Shape让 diff 粒度匹配用户的心智审批粒度而不是让一次对话产生一个无法整体否决的大补丁模板与代码解耦提示词以独立 Markdown 文件存放、启动时读取、占位符运行期替换prompts.ts使文案迭代不触碰业务逻辑且可被 prompts.test.ts 这类轻量断言守护。如果你在为结构化数据简历、配置、文档树构建 AI 编辑助手这套“模板提示词 工具 Schema 双端对齐 试算式校验 人工审批”的组合可以直接作为设计参照而本文涉及的所有关键实现都可以从 packages/ai/src/prompts/chat-system.md、packages/api/src/features/ai/service.ts、packages/ai/src/tools/patch-proposal.ts 与 packages/resume/src/patch.ts 四个文件继续深入阅读。【免费下载链接】reactive-resumeA one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever. Try it out today!项目地址: https://gitcode.com/GitHub_Trending/re/reactive-resume创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表