新闻详情

新闻详情

首页 / 资讯中心 / 详情

七个Agent拆解围棋小程序:提示词设计与结构化输出实战

发布时间:2026/9/26 8:15:01来源:尧图网络
七个Agent拆解围棋小程序:提示词设计与结构化输出实战
最近我在打磨自己的围棋小程序时遇到了一个挺现实的麻烦功能越加越多用户问的问题五花八门一个大模型接口根本扛不住。不是模型能力不够而是同一个提示词很难同时处理棋谱识别、复盘讲解、死活题推荐、术语查询这些差异极大的任务。后来我把思路从“一个Prompt通吃”改成“七个Agent各管一摊”整个项目一下子顺了。这篇内容就专门拆一下这七个Agent的场景划分、提示词设计以及最容易被忽略的结构化输出套路。如果你正在做小程序、做AI应用或者只是好奇Agent落地时到底怎么分工这篇应该能给你一些能直接搬走的经验。1. 围棋小程序里为什么要拆出七个 Agent先说一个可能让你意外的事Agent在我这里没有多么玄乎它就是“带了明确角色、明确任务、明确输出格式的模型调用”。拆出七个Agent的本质是让每一次模型调用都只干一件小事把它干到最准。1.1 一个全能Agent根本忙不过来我最开始的做法很朴素一个系统提示词把围棋百科、复盘分析、死活题生成、段位评估全部塞进去。结果就是用户问“这个局部有什么棋可以下”它回复的时候很可能会先长篇大论讲围棋历史或者在JSON里给出一个不存在的坐标。原因是围棋语料的领域性太强术语坐标、提子规则、打劫规则、目数计算这些信息混在一起模型很容易被无关上下文干扰。后来我把任务拆开每个Agent的上下文短了一半准确率立刻上来了。围棋用户问问题通常非常具体比如“帮我看看这步棋是不是有问题”“这个死活题答案是什么”一个Agent只处理一种场景模型不需要做任务识别也不需要切换思维模式。实测下来同样一个模型拆开之后的正答率提升非常明显幻觉明显减少。1.2 七个Agent的分工全景我的小程序当前有七个Agent命名很直接方便和前端接口对应棋谱识别Agent负责把用户上传的棋谱图片或文本转成标准的棋谱坐标序列。复盘总结Agent负责把整盘对局的关键胜负处、阶段划分、关键手找出来。死活题生成Agent负责按用户棋力生成死活题并给出正解和变化图。棋局讲解Agent负责针对某个局面用自然语言解释下一手选点和背后的道理。术语百科Agent负责回答围棋术语、规则、历史相关的问题。棋力测评Agent负责通过让用户做几道题估算大致的棋力区间。每日一题推荐Agent负责结合用户水平每天推荐一题并生成推荐理由。这七个Agent不是平均用力的棋谱识别和复盘总结最吃结构化输出死活题生成最吃提示词约束术语问答则用纯自然语言就够。把它们的输出方式分开设计后面的工程逻辑才说得清。1.3 拆分带来的成本和收益拆成七个Agent最直接的代价就是每个接口都要维护一份提示词模型调用次数也会变多。表面上好像更费钱了实际上节省了更多。因为不需要反复重试修正不需要给一次调用塞超长上下文结果稳定之后成本反而更低。另外一个好处是可维护性。每次更新提示词只影响一个Agent不用担心“改了一个功能把另一个功能搞坏了”。对于小程序这类需要频繁迭代的产品来说多花一点管理成本换稳定性非常划算。后面第五部分会展开讲我在这上面踩过的坑。2. 七个Agent的场景拆解与提示词设计提示词设计在Agent开发里其实不那么神秘核心就三件事告诉模型它是谁、它要做什么、输出长什么样。真正难的是把每个场景的规则写得足够具体。2.1 棋谱识别Agent坐标规则必须写进提示词用户在小程序里传一张棋谱图片这个Agent要先完成“图片到坐标序列”的转换。围棋坐标有国际比赛通用的SGF规则也有中文语境里常用的“左上角星位”这种描述方式。为了让模型输出能直接被渲染成棋盘我要求它统一输出字母坐标。我的系统提示词核心部分是这样的你是围棋棋谱识别Agent。用户会提交棋谱图片或一段棋谱文本。 你需要提取棋谱中的落子序列并输出JSON数组。 要求 1. 坐标使用SGF字母坐标横坐标A到S纵坐标A到S跳过I。 2. 默认黑棋先手交替落子。 3. 如果图片模糊或无法确认坐标在uncertainty字段中标记true不要猜测。 4. 不要输出任何解释文字直接输出JSON。最关键的就是第3条。一开始我让模型“尽量识别”结果它把模模糊糊的棋子位置硬编码成坐标用户看着棋盘上一堆错位棋子直接懵了。改成“不确定就标记uncertainty”之后虽然识别率没有拉满但至少不会瞎编用户体验老实了很多。输出的结构大概长这样{ moves: [B1, W2, B3, W4], uncertainty: false, ko_rules_applied: true }2.2 复盘总结Agent从棋谱数组到阶段评语复盘总结Agent输入是一整局棋的坐标序列输出是分阶段的评语。这个场景最大的问题是模型对“棋谱很长”这件事没有耐心经常只分析前面几十手就把后面草草略过。我后来在提示词里明确要求“按手数区间切片分析”效果立竿见影。你是围棋复盘Agent。你会收到一个完整的落子序列moves[]。 请按以下三个阶段分别总结 - 布局阶段先手如何展开重点判断是否落子过于集中或过于松散。 - 中盘阶段关键战斗从第几手开始胜负手是什么。 - 官子阶段哪些地方的目数出入最大。 只输出JSON不要输出客套话。这里涉及一个很微妙的点模型并不真的会“看棋”它是根据落子序列推算出来的。所以你必须在提示词里给它一个可执行的推理路径否则它很容易用通用围棋知识糊弄你。比如“布局阶段双方争夺大场”这种评语任何棋谱都能套等于没说。复盘Agent输出我用了不少枚举值来控制质量{ summary: 白棋中盘战斗处理不当左侧大龙被杀导致败局, phase_reviews: [ { phase: opening, start_move: 1, end_move: 50, comment: 双方布局平稳黑棋稍显保守 }, { phase: middle, start_move: 51, end_move: 120, comment: 白棋第78手方向错误形成孤棋 }, { phase: endgame, start_move: 121, end_move: 200, comment: 黑棋官子略微退让但优势仍未动摇 } ] }2.3 死活题生成Agent题目不是随便摆的这个Agent是最容易翻车的。因为很多人以为让模型“出一道死活题”就行实际上模型天然倾向于出那些网上题库里反复出现的经典题比如“直四”“曲四”“刀把五”这些。它们不是错而是太基础用户做完第一道就嫌简单。我在提示词里加入了一个“难度校准”机制先让用户选目标棋力区间再把对应区间常见的死活题难度特征写清楚。比如“业余5段用户需要三步以上计算的题目包含至少一个先手交换”。你是死活题生成Agent。用户目标棋力{kifu_level}。 请生成一道活着或吃掉对方的死活题。 要求 - 题目坐标不能使用棋盘边缘两路内的常见大眼摆法。 - 必须包含至少一个关键第一手正解和失败图都要给出。 - 正解描述控制在100字以内用坐标说明手法。 - 输出JSON格式不要附加题目外解说。为什么死活题生成要单独一个Agent因为它的输出形式非常特殊需要包括题目盘面、正解、失败变化、解说。如果把题目生成和普通问答混在一起模型经常会把“正解”写成自然语言的一段话前端根本没法处理。单独抽出来以后我才能稳定拿到下面这样的数据{ difficulty: 3, board_size: 19, stones: [ {x: 3, y: 4, color: B}, {x: 15, y: 16, color: W} ], correct_answer: [B15, W16, B17], variation: [ {move: W14, result: 白失败} ], explanation: 黑先B15破眼白B16做眼黑B17扳形成假眼。 }2.4 其余四个Agent讲解、术语、棋力、每日一题这四个Agent相对简单但提示词侧重点各不相同。棋局讲解Agent要求的是“先结论后理由”避免模型长篇大论扯到天边去。我会在提示词里限定“回复控制在150字以内先说出推荐落子坐标再用两句话解释理由”。术语百科Agent则要防止它像普通百科一样答一堆和围棋无关的背景我会限定“只解释围棋本义不涉及文化发散”。棋力测评Agent比较特殊它是根据用户对题目难度的回答来推算棋力。它输出的是一个区间而不是一个精确段位因为靠几道题测段位本身就是不科学的。我会在提示词里明确告诉模型“如果信息不足输出一个较宽的区间不要强行精确”。每日一题推荐Agent本质上是一个排序任务它要把题库里的题按“用户最近答题正确率”和“题目标签”这两个维度排序。这个场景不太需要模型输出长文本反而是把模型当作一个打分器给每道题输出一个0到1的推荐分然后小程序端取分最高的那一道。3. 结构化输出让Agent的回复能直接被小程序使用如果你做过一段时间的AI功能开发一定见过这种场景模型给你输出一大段漂亮的中文总结前端根本不知道怎么拆成结构化数据或者模型给了JSON但字段名是乱的数组里偶尔混进一个空对象。这些都是结构化输出没做好的典型问题。3.1 为什么必须结构化输出小程序的本质是用户往界面上点一下后端处理完返回可渲染的数据。如果模型输出的是自然语言前端就得写一堆解析逻辑还不一定能解析对。比如复盘总结如果是一整段文字我怎么把“布局阶段30手”展示成图表怎么标记“第78手方向错误”让棋盘跳转到那一手所以我要求所有Agent输出JSON。棋谱识别输出moves数组复盘Agent输出phase_reviews数组死活题生成输出stones数组。这样做有三个好处前端直接渲染不需要人肉解析长文本。能对关键字段做校验比如坐标合法性的校验。缓存和持久化很方便可以把每次对局分析结果存到数据库里。这里要强调一下我不是在让模型“学会编程”而是让它的回复天然适配小程序的数据结构。如果你现在做类似功能尽量把“能否直接序列化为JSON”当成一个设计原则来要求自己。3.2 让模型稳定输出JSON的三个关键动作第一个动作是“给例子”。模型对JSON的偏好比想象中强但如果你不给一个具体例子它还是会在某些边缘情况里输出Markdown代码块。我最开始就吃过这个亏后来在每个Agent的系统提示词最后强制加了一行只输出JSON不要输出json标记不要输出任何其他文字。第二个动作是“利用模型平台的结构化调用能力”。现在的Agent开发框架大多支持声明式输出格式你可以直接定义好返回对象的结构模型平台会保证输出符合这个结构。我复测下来用平台内置的结构化能力比纯提示词约束稳定很多尤其在中文术语复杂的场景下出错率能降低不少。第三个动作是“前端兜底校验”。即使模型平台给出了干净JSON我还是会在小程序端做一次快速校验。校验逻辑不复杂就是检查数组长度、坐标字符串格式、分数范围这几个关键点。万一校验失败就让用户看到“分析失败请重试”而不是展示一个空棋盘。3.3 结构化字段设计原则小字段、枚举值、唯一ID结构化的字段设计看起来简单实际上还是有一些门道的。我的原则是三句话字段保持小、能用枚举不用自由文本、能带ID就带ID。“小字段”指的是把“阶段”从一大段评论中抽出来单独放phase字段而不是塞在comment里。这样前端做图表、筛选、跳转都方便。“枚举值”指的是像phase这种尽量用opening、middle、endgame而不是“开局阶段”、“中盘战”这种模型随机发挥的短语。枚举值减少后面匹配的麻烦。“唯一ID”指的是遇到题目推荐、术语查询这种场景让Agent输出一个题目ID或者术语ID而不是把整个词条文本复制出来。这样小程序可以只存一份词条数据Agent只负责给ID时长偏长也不怕。结构化输出最后还要考虑一件事失败时的降级方案。我一开始只接受“完美JSON”一旦解析失败就报错。后来发现用户问的问题多种多样特别是短期对话中用户会追加一句“不对我说的是另一步棋”这时如果模型返回“抱歉我理解错了”而不是JSON解析一定炸。我的处理方法是在小程序端解析失败后把这个Agent的输出转成纯文本模式展示不强制结构化。牺牲一点渲染效果保住用户能正常看到回复。4. 实操链路从提示词到小程序页面的完整流程前面讲了很多设计思路这一部分把从提示词到小程序页面的完整链条串起来。你如果现在就在做类似项目可以直接对照这个流程来搭。4.1 提示词的组织与版本管理七个Agent意味着至少有七份提示词。我建议不要把它们直接硬编码在小程序前端而是放在后端的一个提示词配置表里。每一次模型调用都从配置表读取最新的提示词方便更新和回滚。我的配置表字段大致是这样字段说明agent_nameAgent的唯一标识prompt_version提示词版本号system_prompt系统提示词正文output_schema期望的JSON结构描述enabled是否启用remark更新说明为什么要版本控制因为你会发现提示词不是写一次就完事的它会随着需求变化不断迭代。没有版本号一旦新提示词引入Bug很难快速回滚。我自己的做法是每次修改提示词先在一个小程序测试页面里跑几组固定用例确认没问题再上线。固定用例很重要因为模型输出具有随机性不固定测试的话很难判断是提示词改坏了还是模型抽风。4.2 请求层与解析层的工程细节模型请求不可能在小程序前端直接发因为API Key会暴露而且提示词也不太方便藏。所以标准的做法是小程序端把用户输入和一个意图标识发给后端后端根据意图选择对应Agent调用模型再把结构化的结果返回给小程序。后端的伪代码逻辑大概长这样def run_agent(user_input, agent_name, context): prompt load_prompt(agent_name) messages [ {role: system, content: prompt}, {role: user, content: user_input} ] response llm_chat(messages, json_modeTrue) validated validate_schema(response, agent_name) if not validated: response llm_chat(messages [{role: user, content: 请严格按要求输出JSON}]) validated validate_schema(response, agent_name) return validated这里有一个经验如果第一轮输出非法JSON我不建议直接报错而是让模型“重新输出一次”并强调“严格按要求输出JSON”。多数情况下第二次生成的正确率会明显提升。因为加一个显式提醒等于把提示词里的约束又重新强调了对模型来说是有效的。小程序端收到后端返回后直接JSON.parse并渲染。主要注意点就是不要假设字段永远存在例如用户关闭了AI功能后“analysis”字段可能为空。前端要有一套默认态。4.3 一个实际问答流程的完整示例为了让你把流程串起来我举一个具体的例子。用户上传了一盘棋的图片棋谱识别Agent先把它转成坐标序列。用户随后问“这盘棋我输在哪里”步骤一小程序端把这张图片上传到后端后端调用棋谱识别Agent得到moves数组。步骤二后端把moves数组作为上下文交给复盘总结Agent让它把全盘阶段评语生成出来。步骤三后端把阶段评语和关键手坐标一起返回给小程序前端在高亮棋盘上打标记同时展示“中盘第78手方向错误”的评语卡片。这里的上下文传递格外重要。你不可能让复盘Agent去读取图片而是让它读取棋谱识别Agent产生的moves数组。Agent之间通过结构化数据协作而不是通过自然语言反复沟通。这个模式在Agent开发里叫“数据接力”它会极大减少模型计算量也让每一步的调试变得更简单。5. 踩过的坑和排查技巧这部分是实打实踩过之后才总结出来的可能比前面的理论更有参考价值。我把遇到的高频问题和排查技巧整理成了一张表。5.1 高发问题速查表现象原因解决办法模型返回Markdown代码块提示词没写“不要输出代码块标记”在提示词末尾加一句强制JSON约束坐标越界模型自行生成了S棋盘外的坐标添加坐标合法性校验过滤非法值复盘漏掉中盘内容没按手数区间切片模型偏好只分析前几十手强制分阶段总结每段给start_move和end_moveJSON字段里有中文字符串但没引号没用结构化输出能力改用平台内置的JSON Mode用户追加提问导致解析失败Agent返回了道歉文本而不是结构化数据解析失败时降级为纯文本展示死活题难度忽高忽低提示词里没有难度校准模型自由发挥让用户先选棋力再把难度特征写进提示词5.2 围棋领域特有的坑围棋领域的结构化输出有个别的地方特别容易出问题。一个是“坐标点”的表达方式不统一有的用户说“左上角”有的说“B1”有的说“第1步”。我最后的方案是让模型统一转成SGF字母坐标并且在前端做一个坐标转换器把不同输入格式全部转成内部标准。这个转换逻辑放在前端处理会比让模型处理更稳定。另一个坑是“打劫”的处理。棋谱识别Agent在识别连续提劫的棋谱时容易把中间某步漏掉或误判导致整个棋谱数据错位。我的规避方法是在输出moves数组后增加一个后处理函数检查“同一位置有没有重复落子”如果重复了就提示用户“棋谱可能需要人工校验”。虽然不能100%解决但至少能在源头拦住一部分异常对局。还有“目数计算”的问题。模型能估算“白棋目数领先”但让它在结构化输出里给出一个精确的数字稳定性就差了。后来我把目数输出的数值范围放宽输出“领先5到10目”而不是“领先8目”。用户看着也不会觉得不对但模型生成时压力小很多准确率自然高一些。5.3 关于测试和回归的一点心得七个Agent做多了以后你会发现最让大家头疼的不是Agent本身而是“改坏”。今天优化了死活题生成Agent结果它多了几句废话明天调整了复盘Agent的提示词结果返回的JSON结构变了。为了避免这种情况一定要有一个回归测试的用例集。我的做法是把每个Agent的固定测试问题存成一个JSON文件每次提示词改动后跑一遍。比如棋谱识别Agent至少传3张不同风格的棋谱图复盘Agent至少传3盘不同结局的棋谱死活题生成Agent至少跑3个不同段位请求。确认所有用例都通过之后才发布新版本。按照我的个人经验与其相信所谓的大模型能力多强不如在提示词、结构化输出和回归测试上多花点时间。围棋小程序里的这七个Agent技术上算不上什么黑科技但它们验证了一个很朴素的道理Agent拆得越细每个Agent的提示词越聚焦最终给到用户的结果就越稳定。希望这篇分享能帮你少走一点弯路特别是在结构化输出这方面。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

稳定的Claude Code渠道,白嫖100刀:TaoToken统一Key接入与settings.json配置实战 2026/9/26 9:52:52

稳定的Claude Code渠道,白嫖100刀:TaoToken统一Key接入与settings.json配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Linux 7.4内核HDMI升级:FreeSync VRR与ALLM低延迟详解 2026/9/26 9:52:52

Linux 7.4内核HDMI升级:FreeSync VRR与ALLM低延迟详解

我有个习惯,每次内核版本一更新,先翻的不是什么炫酷的新硬件支持,而是DRM子系统和显卡驱动的变更日志。这次Linux 7.4内核的更新公告里,HDMI相关的内容让我多看了好几眼:新增FreeSync VRR与自动低延迟模式(…

阅读更多 →
Linux 7.4内核HDMI升级:FreeSync VRR与ALLM底层支持全解析 2026/9/26 9:52:52

Linux 7.4内核HDMI升级:FreeSync VRR与ALLM底层支持全解析

说实话,Linux桌面显示这一块,前几年一直给我一种“能用但不够爽”的感觉。玩游戏掉帧撕裂、外接显示器偶尔黑屏、想开自适应刷新率还得翻遍内核参数和驱动文档,折腾半天还不一定成功。这次Linux 7.4内核把HDMI功能整体升级了一轮,…

阅读更多 →
AI辅助工具调研:用 TaoToken 统一 Key 打通 Cline 与 Roo Code 配置 2026/9/26 9:52:51

AI辅助工具调研:用 TaoToken 统一 Key 打通 Cline 与 Roo Code 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
AI能否生成嵌入式AirUI代码:实战验证与TaoToken配置指南 2026/9/26 9:52:45

AI能否生成嵌入式AirUI代码:实战验证与TaoToken配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
最简单把 DeepSeek API 接入 Claude Code 的 VS Code 配置指南(含 TaoToken 统一 Key) 2026/9/26 9:52:45

最简单把 DeepSeek API 接入 Claude Code 的 VS Code 配置指南(含 TaoToken 统一 Key)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉