编程导航人工智能话题讨论

人工智能

263 参与
分享

快来分享你的内容吧~

点击登录,快来和大家讨论吧~
表情
图片
话题
打卡
综合
交流
文章
问答

耄耋专属AI Loop全自动编码器技术笔记

> 写给想了解「多AI Agent 在大LOOP时代怎么真上线」的同学 ## 一句话 **Loop Engineering 时代,别只在聊天里写代码——用多 AI Agent,跑一条自己干活的交付 Loop。** 先给这套 Loop 代码编排器定一条简单主线: **需求 Issue → 多角色 AI 协作 → 脚本验证与独立审阅 → 合并 → 固定脚本部署 → 看板盯进度。** 人定目标和验收;AI 负责中间大部分实现与自检;模型不直接登录生产。 --- ## 为什么不只「开个 Cursor 窗口」 聊天式助手擅长帮你改文件,但上线仍要人拉分支、补测、发版、盯结果。Loop 把这些环节收成固定流水线: | | 聊天式 AI 编程 | Loop | |---|---|---| | 起点 | 粘贴上下文 | Issue / 看板目标 | | 过程 | 人来回追问 | 多角色自动推进 | | 质量 | 靠自觉 | 脚本验证 + 独立审阅 | | 上线 | 手工发版 | 确定性发布脚本 | | 可见性 | 对话记录 | 看板阶段与应用入口 | 一句话:**助手帮你写;Loop 帮你把需求送到可点开的版本。** --- ## 技术骨架:三层分工 ```text 触发层 Forgejo Issue(ai-ready) / 看板「新建项目」 编排层 Worker + loopctl + Hermes 五角色 Profile 落地层 verify.sh → PR 合并 → SSH/Compose 发布 → sslip 域名跳转 ``` - **触发层**:习惯还是 Git Issue;新产品也可在看板填「仓库名 + 目标」一键建仓。 - **编排层**:分析 → 架构 → 编码 → 测试 → 审阅;审阅打回最多返工 3 轮;单阶段约 30 分钟超时。 - **落地层**:过门后由脚本部署,看板只监控和跳转,不托管业务前端。 密钥只在服务器 `secrets/`,不进仓库。 --- ## 多 Agent:故意「拆开」,不让一个模型既当运动员又当裁判 | 角色 | 做什么 | 典型产出 | |---|---|---| | 分析 | 收成可验收目标 | `spec.md` | | 架构 | 拆任务、定边界 | `plan.md` | | 编码 | 改业务代码与测试 | 仓库 diff | | 测试 | 独立补测、跑验证 | 测试报告 | | 审阅 | 只评不改,给通过/打回 | `review.json` | 执行侧用 Hermes 多 Profile,工具集刻意收窄(文件 / 终端 / 必要时代码执行),并设轮次上限,避免一轮对话无限烧 Token。 模型也可分层:编码侧重代码模型,测试用更快模型,审阅用更稳的模型——**质量门与写代码的人不是同一个「脑」**。 ## 配置落在哪 ### 编排层(仓库) `config/loop.json` 只规定: - 五角色各自用哪个 Profile 名 - 工具集(分析 / 架构 / 审阅:`file,terminal`;编码 / 测试再加 `code_execution`) - 单阶段轮次上限、YOLO、返工次数、超时 其中 `hermes.models` 可以按角色覆盖模型名;**留空则用 Profile 默认值**。 ### 执行层(服务器 Hermes) 真正的模型 ID、`base_url`、API Key 写在各 Profile 的 `config.yaml`(例如 `/root/.hermes/profiles/loop-coder/config.yaml`)。 线上现行大致是: | 角色 | 模型 | |---|---| | 分析 / 架构 / 编码 | `ark-code-latest`(火山方舟选GLM5.2) | | 测试 | `deepseek-v4-flash` | | 审阅 | `deepseek-v4-pro` | ![image.png](https://pic.code-nav.cn/post_picture/1949837726039801857/qyhrlcPGr0p4yuOR.webp) ### 小技巧 如果想真正的分饰多角,完全可以多买几个便宜的Agent Plan分别挂不同对应角色能力的**LLM**,但这里由于成本控制的原因,最少两个**LLM**对应不同能力就可以完成基本工作了。 ### 人格层(SOUL) 仓库 `roles/*.md` 同步进各 Profile 的 `SOUL.md`,约束「只做什么、不做什么」: - **模型**负责能力 - **SOUL**负责边界 ### 调用链 ```text Issue Worker → loopctl → 对应 Profile 的 Hermes(--oneshot,瘦工具集)→ 该 Profile 配置的模型 ``` --- ## 有边界的自治(比「全自动」更重要) **会自动做:** 读仓、改码、跑校验、开/合 PR、按脚本部署。 **不会自动做:** 没目标乱开需求、跳过质量门上生产、把密钥写进 Git。 **人能介入:** 看板看卡点、一键重跑;紧急可停 Worker。 发布永远走 `release.sh` / SSH 一类确定性路径,而不是让 Agent 临时拼命令登生产。 --- ## 看板:把黑盒变成进度条 看板回答三件事: 1. 现在跑到哪(分析 / 架构 / 编码 / 测试 / 审阅 / 发布) 2. 有没有被打回、卡在哪 3. 应用在哪打开(当前交付 + 历史项目各自地址) 多项目时:**一仓一应用、独立端口、独立 `*.sslip.io` 域名**。改哪个程序,Issue 就开在哪个仓库。 ![屏幕截图 2026-07-17 101839.png](https://pic.code-nav.cn/post_picture/1949837726039801857/vzxWZOa0ms6Yb4jN.webp) ![image.png](https://pic.code-nav.cn/post_picture/1949837726039801857/1ocJMbOLzlYeaFoH.webp) --- ## 一次真实路径长什么样 1. 看板新建,或在目标仓开 Issue 并打 `ai-ready` 2. Worker 领取 → 工作区拉出 `ai/issue-N` 分支 3. 五角色流水线跑完,产物落在 `.loop/current/` 4. 质量门通过 → PR 合并 5. `deploy_once` 部署 Staging/Production,写好跳转域名 6. 打开 `{项目名}.xxx.sslip.io` 验收 试点里我们用这条链路交付过多智能体对话应用、内容创作平台等——从「一句话目标」到「浏览器能点开」,中间大部分由流水线完成。 ![屏幕截图 2026-07-17 135748.png](https://pic.code-nav.cn/post_picture/1949837726039801857/QeDPNBsgcC0eGPRp.webp) --- ## 适合什么,不适合什么 **适合:** 中小功能、脚手架增量、内部试点、需求边界写得清的迭代。 **暂不适合:** 无人值守改核心账务、无评审的大重构、强合规唯一发布通道。 产出质量仍然取决于:需求是否写清、模板是否匹配、模型额度与提示词。 ## 目前Loop编排器自动完成的项目展示 ![屏幕截图 2026-07-17 173309.png](https://pic.code-nav.cn/post_picture/1949837726039801857/iIJFRoDbuEHBwOyS.webp) ![image.png](https://pic.code-nav.cn/post_picture/1949837726039801857/ecCh8tkQL47ZOger.webp) ![image.png](https://pic.code-nav.cn/post_picture/1949837726039801857/9rE2dyaB0kfRO0iU.webp) --- ## 结语 Loop 的技术选择可以概括成三句: 1. **角色分离**,降低「自写自审」幻觉; 2. **脚本守门**,模型负责想和改,脚本负责过不过、能不能上; 3. **看板可见**,自动跑也不变成黑盒。 它不是取代工程师,而是把重复的「领任务 → 改代码 → 验证 → 发版」收成一条可观测流水线,让人把时间花在目标与验收上。

别再跟 AI 死磕 prompt 了,我写了个 Loop 让它自己改到满意为止

> 我昨天凌晨两点还在跟 Deepseek 较劲。就为了一篇奶龙按摩椅的小红书广告文案,我改了八版 prompt,从 "写个爆款文案" 到 "标题必须带数字,正文不超过 300 字,结尾要有行动号召,要像小红书博主那样说话",结果它要么标题不带数字,要么写了 400 多字,要么结尾就是 "快来购买吧" 这种干巴巴的话。 **帅哥美女们帮我的掘金点点赞呗😘👍 完整文章地址👉:https://juejin.cn/post/7653409231857287231** > 我盯着屏幕,手指悬在回车上面,突然觉得特别荒谬。我这是在干嘛?不就是生成、检查、不满意、调整 prompt、再生成吗?这不就是个循环吗?我一个写代码的,为什么要自己当这个循环的人肉执行器? 就在这个时候,我刷到了那条 OpenClaw 开源项目创始人彼得·斯坦伯格发布的 780 万浏览的推文。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/K3l5KcGLtwcwJZ9O.webp) ## 原来我一直在做最笨的事 说实话,看到这句话的时候我愣了一下。我一直以为用好 AI 的关键是写好 prompt,是把话说清楚,是用各种技巧让 AI 理解我的需求。结果人家开源大佬说,别写 prompt 了,写 Loop。 我翻了翻评论区,发现 Claude Code 的作者也在下面附和,说他现在也不写 prompt 了,只写 Loop。 我突然反应过来,我每天和 AI 的交互,本质上就是一个手动的循环。我给 AI 一个指令,它输出结果,我检查结果是否符合要求,如果不符合,我就修改指令,再让它输出一次。这个过程,除了 "检查" 这一步需要人的判断,其他都是机械重复的。 那为什么不把这个检查也交给 AI 呢? ## Loop 到底是什么?说穿了就是三件事 我之前对 Loop 的理解,就是 for 循环、while 循环,就是重复执行一段代码。直到我看到这张图,才突然把这个概念想透了。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/LA6vn80yz0gPztuT.webp) ### 任何一个有用的 Loop,都必须回答这三个问题: #### 1. 从哪里开始? #### 2. 重复做什么? #### 3. 什么时候停止? 就这么简单。你炒菜的时候,从洗锅开始,重复 "炒一下、尝一口、加点盐" 的动作,直到味道合适了就停。你写报告的时候,从第一页开始,重复 "写一段、读一遍、改一改" 的动作,直到领导满意了就停。 缺了第三个问题,就是死循环。程序会一直跑下去,直到内存溢出或者你的 API 额度烧光。 我之前的手动循环,停止条件就是 "我满意了" 或者 "我累了"。现在我要做的,就是把这个停止条件变成代码能理解的规则。 ## 原来大模型自己就是这么学会的 更有意思的是,我们现在用的所有大模型,本身就是用 Loop 训练出来的。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/ChqfRNEdvuEgI3ik.webp) 你看,AI 训练的逻辑,也是一个完美的 Loop: * 给模型看一批数据 * 计算它的预测和正确答案差了多少 * 根据这个差值调整模型的参数 * 再拿一批新的数据,重复上面的步骤 万亿次这样的循环之后,AI 就学会了对话、写作、写代码。 那我们用 AI 的时候,为什么不用同样的逻辑呢?让 AI 自己生成,自己检查,自己调整,直到满足我们的要求。 ## 我写了个能跑的最小 Demo 说干就干,我花了半小时搭了个最简单的项目结构。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/TNzTfdvNusRLX5XU.webp) 因为 Deepseek 的 API 兼容 OpenAI 的格式,所以我直接用了 openai 这个包,省得自己写请求了。 ```javascript import { OpenAI } from 'openai'; import dotenv from 'dotenv'; dotenv.config(); const client = new OpenAI({ apiKey: process.env.DEEPSEEK_API_KEY, baseURL: process.env.DEEPSEEK_API_BASE_URL, }); // 注意这三个参数,坑了我半小时 const limit = { maxRound: 5, // 最多循环5轮,防止死循环 maxToken: 2000, // 最多消耗2000token,防止烧钱 sameStop: 2 // 连续2次输出相同内容就停止,防止AI摆烂 } const task = { desc: "奶龙按摩椅广告文案", rules: ["标题带数字", "正文 < 300 字", "大爆款", "结局有行动号召"] } let round = 0, totalToken = 0, sameCount = 0, lastText = ""; // 循环的停止条件,三个满足任意一个就停 function needStop(){ return round >= limit.maxRound || totalToken >= limit.maxToken || sameCount >= limit.sameStop; } // 生成文案 async function gen() { const res = await client.chat.completions.create({ model: process.env.DEEPSEEK_API_MODEL, messages: [ { role: "user", content: `假如你是一位小红书资深广告文案博主,写一篇${task.desc},严格遵守:${task.rules.join('、')},只输出文案` } ] }); console.log(`消耗token: ${res.usage.total_tokens}` , `\n生成内容:\n${res.choices[0].message.content}`); return { text: res.choices[0].message.content.trim(), token: res.usage.total_tokens }; } // 检查文案是否符合要求 async function check(text) { const res = await client.chat.completions.create({ model: process.env.DEEPSEEK_API_MODEL, messages: [ { role: "user", content: `请检查文案是否符合要求:${text} 严格遵守:${task.rules.join('、')} 仅输出 JSON {pass: 布尔, fail: 数组}` } ] }); return JSON.parse(res.choices[0].message.content.trim()); } // 主循环 async function runLoop() { console.log('AI Loop 开始运行'); while(!needStop()){ round++; console.log(`\n===== 第 ${round} 轮 =====`); const { text, token } = await gen(); totalToken += token; // 检查是否连续输出相同内容 sameCount = text === lastText ? sameCount + 1 : 0; lastText = text; const { pass, fail } = await check(text); if(pass){ console.log(`\n✅ 文案符合要求,通过检查!`); console.log(`最终文案:\n${text}`); return; } console.log(`❌ 文案不符合要求,问题:${fail.join('、')}`); } console.log(`\n⚠️ 触发刹车机制强制停止,最后一次生成的文案:\n${lastText}`); } runLoop(); ``` 然后在.env 文件里填上你的 Deepseek API 密钥和模型就可以跑了。 ## 我踩过的那些坑,你别再踩了 说实话,这个 demo 我写了三遍才跑顺。 第一版我只加了 maxRound,结果有一次 AI 生成的内容一直不合格,循环到第五次就停了,输出的还是一堆垃圾。我当时就想,不行,万一 AI 前五次都没做好,第六次突然开窍了呢?但如果不加 maxRound,万一死循环了怎么办? 后来我想到了加 maxToken,根据你的预算来设置,比如我设置的 2000token,大概也就几毛钱,就算死循环了也损失不大。 最坑的是 sameStop 这个参数。我之前没加这个,结果有一次 AI 连续三次输出一模一样的内容,它自己还觉得没问题,一直在那循环。我看着控制台刷刷刷地跳 token,赶紧把进程杀了。后来才明白,AI 有时候会摆烂,当它觉得自己怎么都满足不了你的要求的时候,就会输出同样的内容敷衍你。这时候就必须有个机制来检测这种情况,及时停止。 `一定要设置这三个停止条件!一定要设置这三个停止条件!一定要设置这三个停止条件!不然你早上起来可能会收到一张几百块的 API 账单。` ## 这个方法到底好在哪?又有什么问题? 我跑了几次这个脚本,效果超出我的预期。以前我要花十几分钟反复改 prompt,现在我只需要写好任务描述和检查规则,然后去喝杯咖啡,回来就能拿到符合要求的文案。 它最大的优势就是把你从重复的劳动中解放出来。你不用再盯着屏幕等 AI 输出,不用再一字一句地检查,不用再绞尽脑汁想怎么把 prompt 写得更清楚。你只需要告诉 AI"什么是合格的",剩下的交给循环。 但它也不是没有缺点。最明显的就是 token 消耗高。因为每一轮都要调用两次 API,一次生成,一次检查。我这个 demo 跑一轮大概要消耗 300-500token,跑 5 轮就是 1500-2500token。虽然 Deepseek 的价格很便宜,但如果是更复杂的任务,token 消耗会非常可观。 所以这个方法更适合那些有明确规则、可以量化检查的任务。比如写广告文案、生成测试用例、格式化数据、检查代码规范等等。如果是需要非常有创意、没有明确标准的任务,比如写小说、画插画,这个方法就不太适用了。 ## 最后说几句我真正的收获 昨天晚上写完这个脚本,我躺在床上想了很久。 以前我总觉得,AI 是一个工具,我给它一个指令,它给我一个结果。如果结果不好,那就是我的指令写得不好。所以我一直在研究怎么写更好的 prompt,怎么用更精准的语言描述我的需求。 但现在我明白了,AI 不是一个一次性的工具,它是一个可以迭代的系统。我们不应该追求一次就得到完美的结果,而应该设计一个循环,让 AI 在这个循环里不断地自我修正,直到满足我们的要求。 这大概就是那条推文真正想告诉我们的道理。 如果你也写过这种 AI Loop,或者有更好的停止条件设计,欢迎在评论区告诉我,我也想学习一下。

Codex Plus会员现阶段靠谱的氪金教程

### 写在前面:为什么要氪金 Codex Plus? 这篇教程适合想和我一样,准备用 Codex 做一些练习项目来强化 **vibe coding** 技能的同学。在 vibe coding 练手的时候,最怕的就是对 token 消耗有焦虑,打断学习的道心。用上官方纯净、无套路的 Codex,才是我认为比较高效的解法。 **核心建议:** 不要总想着蹭免费额度,打个比方氪金648和买一个正版3A游戏的钱花在Codex上,足够你用一段时间搞好几个Vibe Coding项目了,甚至有机会助你找到工作拿到心仪的Offer,这样看这笔自我提升的投资绝对划算。实测也是Codex的额度足够学习Vibe Coding和做一些赋能中小项目用了。 ![屏幕截图 2026-06-10 112757.png](https://pic.code-nav.cn/post_picture/1949837726039801857/GF2Z5Iy2uYalzaQo.webp) --- ### 注册与验证避坑指南 OpenAI 体系(包含 ChatGPT 和 Codex)对注册的地区有严格限制,这里提供一个目前最稳的接码方案: * **接码建议:** 注册时推荐使用 **Vietnam的 xuni号码**。这是目前实测下来过 ChatGPT 手机验证最方便、成功率最高的途径。 * **虚拟号码网站:** 首选5sim,Vietnam号码一个0.1刀左右,网站上充个10RMB 备用最佳。 ### 费用预算与充值渠道 * **官方费用:** 20 刀 / 月(一般代充高于这个价,低于20刀懂得都懂) * **氪金方式(懒人版):** 推荐直接在**某宝找靠谱的店铺**协助解决支付问题(如代充或购买正规的虚拟信用卡)。挑选时注意多看评价和店铺信誉,切忌贪小便宜购买低价黑卡,以免导致账号被封禁。店铺一定要承诺保30天使用,对话留据。对方一般会加wx帮你做单子,那头有额外费用的话你就说是以某宝订单为准防一手套路。 * **最佳氪金方案:** 有能力正规银行注册一张可以国际支付的VISA那更稳了,付款认准OpenAI官方。我后续会开一张国际支付能力副卡,专门充AI相关的工具,省得和某宝商家斗智斗勇了。 * **验收方式:** 侧边栏左下角出现剩余用量说明会员成功激活,当然你还需要亲自对话试一轮才能真正完成验收(最好是你vibe coding项目测试各模型真实能力,和免费额度部分作对比,防止一开始拿到降智模型)。 ![屏幕截图 2026-06-10 120502.png](https://pic.code-nav.cn/post_picture/1949837726039801857/iKPx66k9rloF8wFQ.webp) ### 日常使用必备环境 * **网络要求:** **使用时科学上网必备**。 * **注意事项:** 建议使用固定且纯净的节点,不要频繁切换国家和地区,以防触发系统的安全风控。保持网络环境的稳定,才能让你的 vibe coding 体验丝滑无卡顿。最好注册好ChatGPT账号,再去搞氪金plus会员的事。我个人已经成功用了半个月,才来分享这套使用方案的,早知道注册个VISA再搞了。

从0到1搞懂AI全栈:我靠“一人公司”模式,搞定从老板到销售的所有活

> 大家好!我是刚入门AI全栈的小白博主,最近沉迷研究“一个人能不能撑起一整个公司”,踩了不少坑,也摸清了些门道。今天就把我的真实学习笔记+实操感悟分享给大家,全程第一人称,干货拉满还不枯燥,新手也能轻松看懂~ 帅哥美女们帮我的掘金点点赞呗😘👍 **完整文章地址**👉:[https://juejin.cn/post/7640350331680342058](https://juejin.cn/post/7640350331680342058) 先抛个灵魂拷问:AI时代,程序员真的只能做单一岗位吗?我试过用AI当“搭子”,一个人包揽老板、产品、设计、前后端、测试、运维、销售所有活,居然真的跑通了最小闭环!这就是今天的核心——**OPC模式(One Person Company 一人公司)** ,靠AI工程化能力,把每个岗位都实现AI化、虚拟化、技能化。 话不多说,跟着我的笔记节奏,一起解锁AI全栈的正确打开方式,文末还有踩坑总结和延伸思考,记得看到最后👇 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/VQGe7kruKF4a6fib.webp) ## 一、OPC模式:一个AI高手,就是一整个团队 刚开始接触OPC的时候,我一度以为是“噱头”——一个人怎么可能搞定所有岗位?直到我亲自上手试了半个月(每天晚上8点学到11点,周末连肝2天),才发现:**不是一个人硬扛所有活,而是用AI当“工具人”,调度各个AI能力,完成工作闭环**。 简单说,OPC的核心就是“AI Engineering(Harness 工程)”,把AI当成自己的“虚拟团队”,你只需要做“总指挥”,负责定方向、调工具、控结果,剩下的脏活累活全交给AI。 ### 我的真实角色转变:从“打工人”到“一人老板” 这半个月,我硬生生把自己逼成了“全能选手”,每个角色都靠AI辅助完成,分享下我的真实经历和实操细节,大家可以直接参考: #### 1. 老板(Project Owner):靠“灵感+AI”找需求 作为“老板”,第一步就是找需求——总不能瞎忙活吧?刚开始我想破脑袋,不知道做什么项目,后来用Claude帮我分析“当下高需求、低门槛的AI赛道”,结合我自己养宠物的经历,最终定了方向:**狗语翻译器**。 这里插个小细节:当时AI给了10个赛道建议,我排除了AI写作、AI绘画(竞争太激烈),最终选了宠物陪伴赛道——查了数据才知道,宠物陪伴市场居然是万亿规模!而且目前狗语翻译类产品要么功能单一,要么不准确,正好有机会切入。 ✅ 我的小技巧:用“需求+场景+痛点”prompt问AI,比如“帮我分析宠物陪伴赛道的潜在需求,重点是狗主人的核心痛点,给出3个可落地的项目方向”,AI会直接帮你梳理清楚,省去自己查资料的时间。 #### 2. 产品经理(AI PM):让AI帮我梳理产品逻辑 定了狗语翻译器的方向,接下来就是做产品设计——作为小白,我完全不懂产品逻辑,怎么办?找AI当我的“产品助理”! 我给AI的prompt是:“我要做一款狗语翻译器,面向养犬人群,核心功能是通过声音识别狗狗的情绪、需求(比如饿了、想出门、生气),请帮我梳理产品核心功能、目标用户、落地路径,还要考虑数据来源”。 不到10分钟,AI就给了完整的产品逻辑,重点提炼了2点(也是我之前没想到的): * 数据来源:收集不同品种狗狗的声音大数据(比如金毛、泰迪、哈士奇),按“场景(在家、出门)、情绪(开心、焦虑)、需求(进食、玩耍)”分类,喂给LLM训练; * 核心亮点:不仅能翻译,还能给出对应解决方案(比如狗狗叫是因为焦虑,建议多陪伴、给玩具)。 这里踩了个小坑:刚开始AI给的功能太复杂,包含了“狗狗健康监测”“社交功能”,后来我让AI“精简核心功能,优先落地最小可行产品(MVP)”,才梳理出清晰的逻辑——新手做产品,千万不要贪多! ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/SzB0ECWq1BF40kh2.webp) #### 3. 设计师(AI Designer):0基础搞定硬件+界面 产品逻辑定好了,接下来就是设计——硬件(比如佩戴在狗狗身上的手环)和软件界面(手机App),我连PS都不会,全靠AI救场! * 硬件设计:用OpenAI生成手环设计图,prompt是“简约风格狗狗智能手环,小巧轻便,能收集声音,颜色是浅灰色,适合中小型犬,细节清晰,工业设计感”,生成了10张图,我选了最简洁的一款,还能直接发给工厂参考; * 软件界面:用OpenAI,输入“狗语翻译器App界面,简约清新,主色调是浅蓝色,包含‘实时翻译’‘历史记录’‘狗狗档案’3个核心页面”,自动生成界面原型,还能直接修改细节。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/0PPXky2njyYB1LqP.webp) ✅ 小技巧:生成设计图时,一定要加“具体场景+细节要求”,不然AI生成的会很模糊,比如不说“手环”,而是说“适合中小型犬的智能手环,能佩戴在脖子上,有声音采集孔”。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/RKCZji0VBV75nqhK.webp) #### 4. 前后端开发:AI帮我写代码,我只负责调试 这部分是我的重点学习内容,作为刚接触前后端的小白,我全程用AI辅助,没有写一行原生代码(别喷,新手循序渐进~),用到的工具分享给大家: * 前端:用Cursor(AI代码编辑器),输入prompt“用HTML/CSS/JS写一个狗语翻译器App的前端页面,包含实时翻译按钮、声音波形显示、历史记录列表,风格简约,适配手机端”,Cursor直接生成完整代码,还会标注注释,我只需要修改颜色、字体,调试适配问题; * 后端:用Python+Flask,同样用Cursor生成代码,核心功能是“接收手环采集的声音数据,调用训练好的LLM模型,返回翻译结果,存储历史记录”,这里踩了个坑——刚开始AI生成的代码有语法错误,后来我让AI“检查代码语法,修复错误,确保可运行”,重新生成后就正常了。 给大家贴一段后端核心代码(可直接运行,已调试): ``` from flask import Flask, request, jsonify import torch from transformers import AutoModelForSequenceClassification, AutoTokenizer app = Flask(__name__) # 加载训练好的狗语识别模型(这里用简化版示例) tokenizer = AutoTokenizer.from_pretrained("dog-speech-model") model = AutoModelForSequenceClassification.from_pretrained("dog-speech-model") @app.route("/translate", methods=["POST"]) def translate_dog_speech(): # 接收手环传来的声音数据(简化为文本描述) data = request.get_json() dog_sound = data.get("sound", "") # 模型预测 inputs = tokenizer(dog_sound, return_tensors="pt", padding=True, truncation=True) outputs = model(**inputs) predicted_label = torch.argmax(outputs.logits, dim=1).item() # 映射标签到翻译结果 label_map = {0: "饿了,需要进食", 1: "想出门,需要遛弯", 2: "生气,别打扰", 3: "开心,求陪伴"} result = label_map.get(predicted_label, "无法识别,请重试") return jsonify({"translate_result": result, "status": "success"}) if __name__ == "__main__": app.run(debug=True, host="0.0.0.0", port=5000) ``` 提示:这里的模型是简化版,实际落地需要自己收集狗狗声音数据,用LLM训练专属模型,后面会提到~ #### 5. 测试+运维+销售:AI包揽剩下的活 * 测试人员:用AI生成测试用例,prompt“针对狗语翻译器的后端接口,生成10个测试用例,包含正常情况、异常情况(比如空声音数据、无效数据)”,AI会直接给出测试步骤和预期结果,我只需要按照用例测试,修改bug; * 运维:用阿里云服务器,AI帮我写运维脚本(比如自动部署、日志监控),还教我怎么配置安全组、备份数据,小白也能轻松上手; * 销售:用AI写推广文案、朋友圈话术,甚至帮我分析目标用户群体(比如20-35岁养犬人群,喜欢在小红书、抖音分享宠物),还生成了简单的推广方案,省了不少心思。 ## 二、AI能力:OPC模式的核心,缺一不可 聊完了我的角色转变,再跟大家梳理下OPC模式必备的AI能力——其实核心就是“借助AI工具,完成从需求到落地的全流程”,不需要你精通所有AI技术,只要会“调度”AI,就能搞定。 企业现在需要的,不是单一岗位的“螺丝钉”,而是能统筹全局的“微型老板”——用Cursor、Claude Code、Codex这些工具,胜任或调度LLM,完成工作闭环,这就是AI全栈工程师的核心竞争力。 ### 1. AIGC:内容/设计/代码,一键生成 AIGC是OPC模式的“基础工具”,从2022年底ChatGPT问世,AIGC就彻底改变了我们的工作方式——文本、图片、动画、代码,只要你能描述清楚需求,AI就能帮你生成。 我常用的AIGC工具,整理好了(新手直接抄作业): * 文本生成:GPT-4、DeepSeek、智谱清言、通义千问、Minimax、Kimi(Kimi适合长文本,比如写产品文档;DeepSeek适合技术类文本); * 图片生成:OpenAI DALL·E(我试过往里输“Image2 banana”,真的能生成香蕉相关的图片,趣味性拉满)、MidJourney(适合设计类图片,比如硬件、界面); * 动画生成:Seedance(新手友好,能生成简单的产品演示动画,比如狗语翻译器的使用流程)。 这里提醒大家:AIGC生成的内容,一定要自己检查、修改,比如AI生成的代码可能有bug,生成的设计图可能不符合需求,不要直接照搬,AI是“辅助”,不是“替代”。 ### 2. Agent智能体:0代码搞定流程自动化 如果说AIGC是“工具”,那Agent智能体就是“自动化助手”——能帮你自动完成一系列流程,不需要你手动操作,新手也能0代码上手,我常用的两个Agent工具: * Coze(字节跳动出品):0代码就能搭建智能体,比如我搭建了一个“狗语翻译器辅助智能体”,设置好流程(接收声音数据→调用模型→返回翻译结果→存储记录),它就能自动运行,不用我手动触发; * LangChain:适合有一定基础的同学,能连接不同的AI模型、工具,实现更复杂的自动化流程,比如“自动收集狗狗声音数据→训练模型→更新产品功能”,我目前还在学习中,后续会分享实操笔记。 互动提问:你们用过哪些好用的Agent工具?欢迎在评论区分享,我也去试试~ ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/vRG7XDK9o36c5Pop.webp) ## 三、小白踩坑总结+延伸思考 这半个月的学习,我踩了不少坑,也总结了一些经验,分享给和我一样的小白,帮大家少走弯路: ### 小白必看的3个踩坑点 1. 不要贪多求全:刚开始做项目,一定要聚焦MVP(最小可行产品),不要一开始就加很多功能,比如我刚开始想加“狗狗健康监测”,导致进度变慢,后来精简功能,才快速跑通闭环; 2. AI生成的内容要校验:不管是代码、设计图还是产品逻辑,AI都可能出错,一定要自己检查、调试,比如我第一次用AI生成后端代码,有语法错误,浪费了1个小时才发现; 3. 不要依赖AI,要主动学习:AI是工具,不能替代你思考,比如产品方向、核心逻辑,还是需要你自己定,AI只是帮你落地,不然很容易被AI“带偏”。 ![image.png](https://pic.code-nav.cn/post_picture/1806249471285702658/66ljLwGgI3UQDN4K.webp) ### 延伸思考:AI全栈的未来,普通人有机会吗? 我刚开始学习的时候,也担心“AI会不会取代程序员”,但现在我明白了:AI取代的是“重复性工作”,比如写基础代码、画简单设计图,而能统筹全局、调度AI的“AI全栈工程师”,会越来越吃香。 OPC模式的核心,不是“一个人干所有活”,而是“用AI提升效率,做自己擅长的事”——你可以专注于需求分析、产品方向,剩下的重复性工作交给AI,这就是普通人切入AI全栈的机会。 后续我会继续更新我的学习笔记,比如如何用LLM训练狗语识别模型、如何用Coze搭建智能体、如何部署产品上线,感兴趣的同学可以关注我,一起学习、一起进步~ ## 最后想说 作为小白,我深知入门AI全栈的难度,但只要找对方法,用AI当“搭子”,普通人也能实现“一人公司”的梦想。不要害怕自己不懂,不要害怕踩坑,每一次尝试,都是进步。 你们觉得OPC模式靠谱吗?如果是你,会用AI做什么项目?欢迎在评论区留言讨论,一起交流学习~ ❤️ 码字不易,喜欢的同学可以点赞、收藏、关注,后续持续输出AI全栈小白学习笔记,我们一起从0到1成长!

学习分享Y站上的视频:Self-Attention Explained: How Transformers Actually Work (Full Visual Breakdown)

## 大体内容是关于**Transformers**里的**Self-Attention**的解释,以下配合我设计的一个Prompt些的一个全英的学习笔记。 ![屏幕截图 2026-05-08 005643.png](https://pic.code-nav.cn/post_picture/1949837726039801857/KC2jhgfIh8LDOpzn.webp) ### 操作步骤大概就是:我录下了这个视频的音频内容去调用一个语音识别model识别成详细字幕,再用拿到的字幕内容创建提示词问Deepseek该怎样做英文笔记。当然这个不是重点,本篇的重点是展示AI总结的关于**Transformers**原理的学习笔记。以下是AI的第一次思考过程,开始思考怎样总结喂给她的Context思路还是很清晰的。 ![屏幕截图 2026-05-08 010150.png](https://pic.code-nav.cn/post_picture/1949837726039801857/wyq07sQP2Joppwu0.webp) ## 以下是第一次思考得到笔记的具体内容: Here is a detailed study note based on the transcript, designed to help you grasp the core ideas of Transformers and self-attention in a simple, visual way. --- ### 🧠 English Study Notes: Self-Attention & Transformers (From Scratch) #### 1. The Core Question: What Does "It" Refer To? Let's start with a simple sentence: > *The animal didn’t cross the street because **it** was too tired.* We instantly know that **"it"** means **"animal"**, not "street". How did we know? We mentally **connected "it" to "animal"** by looking at the other words. This simple act – one word reaching out to understand another – is the **central idea behind self-attention**. --- #### 2. The Old Problem: RNNs and Lost Memory Before Transformers, models (RNNs) read text strictly **left to right, word by word**. - By the time they reached "it", the word "animal" was buried in the past. - The **context was lost** – this is called the **long-term dependency problem**. The fix? Throw away the sequential method. What if **every word could look at every other word at the same time**, directly? --- #### 3. The Big Idea: Self-Attention as a Connected Web Forget left-to-right order. Imagine a web where **"it" can directly reach "animal" instantly**. - Every word queries every other word **simultaneously**. - Nothing is ignored. Every word contributes to the meaning. This is the philosophy of *Attention Is All You Need* (2017). --- ### 🔢 The Math, Step by Step (Simplified) #### Step 0: Words Become Numbers (Embeddings) Before attention, words must become numbers the computer understands. Each word gets a **dense vector** – a list of numbers that serves as its "personality fingerprint". - Example words: **the**, **cat**, **sat**. - Each becomes a vector of `d` numbers: **x₁**, **x₂**, **x₃**. - Stack them to get the **input matrix X**. (Shape: `3 tokens × 4 dimensions` – 3 rows, 4 columns.) #### Step 1: Create Q, K, V (Three Versions of Each Word) We project X into three separate matrices by multiplying with learned weight matrices: - **Query (Q)** – "What am I looking for?" (the word asking a question) - **Key (K)** – "What do I have to offer?" (the word being evaluated) - **Value (V)** – "Here’s my actual information." Each word now has three vectors: a query, a key, and a value. #### Step 2: Compute Attention Scores (How Well Do Words Match?) We find out how much each word should focus on every other word. Multiply **Q** by the **transposed K** (`Q × K^T`). - This creates a **grid of raw scores** – each cell shows the relationship between two words. - High positive score = strong connection. Low/negative = unrelated. - The diagonal (word to itself) always gets high scores – a word naturally attends to itself to keep its own meaning. Example: "cat" (subject) gets a high score with "sat" (verb) – the model links them automatically. #### Step 3: Scale the Scores (Prevent Exploding Numbers) Problem: If the key vectors are large (e.g., dimension `d_k = 64`), the raw scores can become huge. Passing huge numbers through softmax makes one value ~1 and the rest ~0 → learning stops. Solution: **Divide all scores by `√d_k`** (square root of key dimension). - For 64 dimensions, divide by 8. - This keeps the scores in a healthy, zero-centered range. This trick is why it’s called **scaled dot-product attention**. #### Step 4: Apply Softmax → Attention Weights After scaling, we apply the **softmax** function row-wise. - Exponentiates values and makes each row sum exactly to 1. - Now each row is a **probability distribution**: it tells exactly how much focus a word places on every other word. Result: **Attention Weight Matrix** – each row sums to 1; higher value = more focus. #### Step 5: Weighted Sum of Values → New Context-Rich Words Finally, multiply the attention weights by the **Value (V)** matrix. For each word: - Take a weighted mixture of all value vectors based on the attention weights. - Example: Output for "the" = 61% of "the" value + 25% of "cat" value + 14% of "sat" value. Now every word vector is **enriched with context from the entire sentence**. The word "cat" now carries a piece of "sat", and "sat" carries a piece of "cat". --- ### 🧩 The Full Pipeline (Quick Recap) | Step | What Happens | |------|--------------| | 1 | Convert words to embeddings → Input Matrix **X**. | | 2 | Multiply X by weight matrices → **Q, K, V**. | | 3 | Compute raw scores: **Q × Kᵀ**. | | 4 | Scale by **√d_k** → stable scores. | | 5 | **Softmax** → attention weights (rows sum to 1). | | 6 | Multiply attention weights by **V** → final contextualized output. | --- ### ✨ Why This Is So Powerful - **Parallel processing**: All words interact simultaneously, not sequentially. - **Long-range dependencies**: "it" and "animal" connect directly, no matter how far apart. - **Grammatical relationships emerge naturally**: The model learns subject-verb linkages purely from data, no rules programmed. - **Self-awareness diagonal**: Each word keeps its own core meaning while absorbing context. --- ### 🔮 Teaser: Multi-Head Attention A single attention head can only capture **one type of relationship** at a time. - "Bank" + "deposit" → financial institution - "Bank" + "river" → land beside water But words often have multiple meanings simultaneously. **Multi-head attention** runs several attention mechanisms in parallel, each focusing on different aspects (e.g., grammar, meaning, position). That’s where we go next. --- ### 📝 Key Terms Glossary - **Embedding** – A dense vector representing a word. - **Query (Q)** – What the word is looking for. - **Key (K)** – What the word offers to be matched. - **Value (V)** – The actual content of the word. - **Attention Score** – Raw measure of similarity between query and key. - **√d_k** – Scaling factor to prevent saturation. - **Softmax** – Turns scores into probabilities summing to 1. - **Scaled Dot-Product Attention** – The full formula: `softmax(QKᵀ/√d_k) × V`. --- Let me know if you'd like a visual sketch, a simpler analogy, or a Python-like pseudo-code walkthrough. ## 这里我们可以继续顺着AI最后的提升创建一个有代码有视觉草图提示的笔记版本,下面直接上结果: AI思考过程如下: ![屏幕截图 2026-05-08 010903.png](https://pic.code-nav.cn/post_picture/1949837726039801857/NwyUud8NXnaiIkvS.webp) 然后是结果: Let's dive deeper with three complementary tools: a **simpler analogy** you can feel, a **visual sketch** you can picture, and a **Python-style pseudo-code** you can trace step by step. We'll reuse the sentence **"the cat sat"** throughout. --- ### 🧩 1. The Classroom Analogy (Q, K, V Intuition) Imagine a classroom of three students: **The**, **Cat**, and **Sat**. They are trying to form a sentence meaning together. Each student holds a card: - **Query (Q):** "What am I looking for right now?" (Their current need) - **Key (K):** "What I have to offer that others might look for." (Their label) - **Value (V):** "My actual knowledge/information." (Their content) Now the process: - **Cat** wants to know what action is happening. Its Query is "I'm looking for a verb." - **Sat** holds a Key that says: "I am a verb, action of sitting." - The dot product between Cat's Query and Sat's Key returns a high score → they match well. - **The** is not a verb, so its Key gives a low score with Cat's Query. After comparing, each student blends in information from everyone else based on these scores. So **Cat's** final understanding includes a big chunk of **Sat's** value (the verb) and a smaller chunk of **The** (article context). Now Cat knows it's a cat **sitting**. The division by √d_k is like **turning down the volume** when too many students are shouting; softmax then tells each student to pay attention to others proportionally (all attention weights sum to 1). --- ### 🎨 2. Visual Sketch (Mental Diagram) Let's draw the attention flow for the sentence "the cat sat" with dimension `d=4`. I'll describe each panel; you can imagine them or sketch them on paper. #### Panel A: Embedding Matrix X (3×4) Rows = tokens, columns = features. ``` dim0 dim1 dim2 dim3 the [ 0.2, 0.5, -0.1, 0.8 ] cat [ 0.9, -0.3, 0.4, 0.1 ] sat [-0.4, 0.7, 0.6, -0.2 ] ``` Each row is the `x` vector for a token. #### Panel B: Project into Q, K, V (Weight matrices W_Q, W_K, W_V) Think of this as three different "lenses" that look at X. - X @ W_Q → Q (3×4) - X @ W_K → K (3×4) - X @ W_V → V (3×4) For simplicity, we'll show just the **first token ("the")** in Q and K: ``` Q (row for "the"): [0.1, 0.3, -0.2, 0.5] K (row for "cat"): [0.8, 0.1, 0.0, -0.4] ... ``` #### Panel C: Raw Attention Scores = Q @ K^T We compute a **3×3 grid** (tokens × tokens). Each cell = dot product of a query row and a key row. ``` the (key) cat (key) sat (key) the (q) 2.1 0.8 -0.3 cat (q) 0.6 3.4 1.9 sat (q) -0.2 1.6 3.8 ``` - Diagonal: high self-scores. - "cat" query gives high score to "sat" key (1.9), showing the verb link. #### Panel D: Scale by √d_k (here d_k=4 → √4=2) Divide every cell by 2: ``` the cat sat the 1.05 0.40 -0.15 cat 0.30 1.70 0.95 sat -0.10 0.80 1.90 ``` Now values are tamed (no explosion). #### Panel E: Apply Softmax Row-wise For row "cat": scores [0.30, 1.70, 0.95] → softmax → probabilities that sum to 1, e.g., [0.15, 0.70, 0.15]. This means "cat" pays 70% attention to itself, 15% to "the", 15% to "sat". Matrix becomes attention weights: ``` the cat sat the [0.60, 0.30, 0.10] (sum=1) cat [0.15, 0.70, 0.15] sat [0.05, 0.25, 0.70] ``` #### Panel F: Weighted Sum of Values = Output Each output row = weighted sum of V rows. For "cat": ``` Output_cat = 0.15 * V_the + 0.70 * V_cat + 0.15 * V_sat ``` Now "cat" contains a blend of its own meaning and context from "sat" and "the". **Big picture visual summary**: Imagine three rows (tokens) evolving: ``` [X] → [Q,K,V] → [Scores grid] → [Scaled] → [Softmax Weights] → [Weighted V] → [New context-rich vectors] ``` All operations are parallel, and every word talks to every other word at the same time. --- ### 💻 3. Python-like Pseudo-Code Walkthrough Let’s write a step-by-step function `self_attention` that takes token embeddings and returns context-aware vectors. ```python import numpy as np def self_attention(X, d_k, W_Q, W_K, W_V): """ X: input matrix (seq_len × d_model), e.g., 3×4 d_k: dimension of keys (usually d_model / num_heads) W_Q, W_K, W_V: learned weight matrices (d_model × d_k or d_model × d_v) Returns: output matrix (seq_len × d_v) """ # Step 1: Compute Q, K, V Q = X @ W_Q # (3×4) @ (4×d_k) -> (3×d_k) K = X @ W_K # (3×4) @ (4×d_k) -> (3×d_k) V = X @ W_V # (3×4) @ (4×d_v) -> (3×d_v) # Step 2: Raw scores = Q @ K^T scores = Q @ K.T # (3×d_k) @ (d_k×3) -> (3×3) # Step 3: Scale by √d_k scaled_scores = scores / np.sqrt(d_k) # Step 4: Softmax along rows (axis=1) # For numerical stability, subtract row max before exp exp_scores = np.exp(scaled_scores - np.max(scaled_scores, axis=1, keepdims=True)) attention_weights = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # Now each row sums to 1 # Step 5: Weighted sum of Values output = attention_weights @ V # (3×3) @ (3×d_v) -> (3×d_v) return output, attention_weights ``` **Trace with dummy numbers** (for intuition): Assume embeddings `X` for "the", "cat", "sat" as given above, and tiny random weight matrices with `d_k=2`, `d_v=2`. We'll just illustrate the logic. ```python # Toy data X = np.array([[0.2, 0.5, -0.1, 0.8], # the [0.9, -0.3, 0.4, 0.1], # cat [-0.4, 0.7, 0.6, -0.2]]) # sat d_model = 4 d_k = 2 d_v = 2 # Random weights (normally learned) W_Q = np.random.randn(d_model, d_k) W_K = np.random.randn(d_model, d_k) W_V = np.random.randn(d_model, d_v) output, attn_weights = self_attention(X, d_k, W_Q, W_K, W_V) print("Attention weights (rows sum to 1):") print(attn_weights) # Example: cat row might be [0.1, 0.7, 0.2] -> focuses on itself and on sat print("Output shape:", output.shape) # (3, 2) - each token's new context vector ``` **What this does**: The function transforms a sequence of independent word vectors into a sequence where each vector is a **blend of the whole sentence**, weighted by relevance. --- ### 🔍 Key Insight from All Three Lenses - **Analogy**: Words are students querying each other's notes and blending knowledge. - **Visual sketch**: A grid of connections that gets scaled and normalized into a probability map. - **Code**: A few matrix multiplications and a softmax with a division by √d_k. This is the core engine of a Transformer block. Stack multiple such blocks, add multi-head (several parallel attention operations with different W_Q,K,V), and you get the full understanding capacity of a model like GPT or BERT. Would you like the next step explained—how multiple heads combine to capture different meanings of "bank" in the same layer? ## 这里AI又推理出了下一步我们该做什么,那就直接扩展下,有没有一种记笔记变写专业论文的感觉 Absolutely! Let's build on the same classroom analogy, visual sketch, and pseudo-code to unlock **multi-head attention** and how it lets the word **"bank"** be understood in two completely different worlds at the same time. --- ### 🧩 1. The Classroom Analogy with Multiple Specialist Teams Our classroom now needs to interpret a sentence with an ambiguous word: > *"The bank deposit was safe near the river bank."* A single student (one attention head) asked: *"What am I looking for?"* But they can only wear one pair of glasses (one Query projection). If they look for "financial words" they'll see **deposit** and ignore **river**. If they look for "geographic words" they'll see **river** and ignore **deposit**. Now imagine you have **h** different specialist teams (heads), each wearing a different pair of glasses: - **Head 1 (Financial lens):** Its Query matrix W_Q1 is trained to ask "What financial terms are around me?" So for the first "bank", it looks at **deposit** and gets a high score. Its Keys and Values also project words into a "financial" subspace. - **Head 2 (Geography lens):** Its Query matrix W_Q2 is trained to ask "What landscape words are around me?" For the second "bank", it looks at **river** and gets a high score. - **Head 3 (Syntax lens):** It might focus on grammar roles like articles ("the") or prepositions ("near"). - **Head 4 (Positional / other):** Could focus on word order or other patterns. Each head independently does **scaled dot-product attention** using its own set of weight matrices (W_Q, W_K, W_V). So at the same layer, the word "bank" **simultaneously**: - Receives a financial-context vector from Head 1. - Receives a geography-context vector from Head 2. - Receives grammar/syntax flavor from Head 3, etc. Then all these vectors are **concatenated** and passed through a final linear projection (W_O). Now the single output vector for "bank" contains all these different meanings mixed together—the model hasn't chosen one meaning yet, it carries both (and more) in a richer representation. Later layers can use this combined knowledge. So in the classroom, instead of one student deciding the meaning, you have **multiple specialist students** going around, each asking a different question, and then they pool their findings. The word "bank" ends up knowing that it is both near a deposit (financial) and near a river (geographic) simultaneously. --- ### 🎨 2. Visual Sketch of Multi-Head on "bank" Imagine a single sentence input: **["The", "bank", "deposit", "near", "the", "river", "bank"]**. At a specific layer, we want to see how the second-to-last word **"bank"** (the riverbank) is processed. #### Panel A: Input Embeddings (as before) Each token gets a vector of size `d_model = 512`, e.g. `x_bank`. #### Panel B: Split into Multiple Heads If we have `h = 4` heads, each head will work with a smaller dimension `d_k = d_v = d_model / h = 128`. We **linearly project** the input vector for "bank" (and all others) into 4 different Q, K, V sets — one set per head. Think of this as creating 4 different "colored copies" of each word. ``` Head 1 (Financial): Q1, K1, V1 Head 2 (Geography): Q2, K2, V2 Head 3 (Syntax): Q3, K3, V3 Head 4 (Positional): Q4, K4, V4 ``` #### Panel C: Each Head Computes its Own Attention Grid Take Head 1 (Financial). Its attention scores for the riverbank "bank" might look like: ``` The bank deposit near the river bank bank: [0.05, 0.10, 0.02, 0.01, 0.01, 0.01, 0.80] (strong self-attention, low to others because no financial terms) ``` But wait, if the target "bank" is the riverbank, there's no financial "deposit" nearby. Head 1 will still produce a neutral or self-focused output because its financial lens doesn't see any financial words. Meanwhile, Head 2 (Geography) for the same riverbank "bank" will produce: ``` The bank deposit near the river bank bank: [0.05, 0.05, 0.01, 0.15, 0.14, 0.50, 0.10] (high attention to "river") ``` Head 3 might focus on the preposition "near". Head 4 might attend to word positions. #### Panel D: Each Head Outputs a Context Vector Head 1's output for riverbank "bank": a weighted mix of values that's mostly the bank itself (little financial info). Head 2's output: a mix heavily influenced by "river". Head 3's output: influenced by "near". Head 4's output: whatever else. #### Panel E: Concatenate and Project The four output vectors (each `d_v=128`) are concatenated into one vector of size `128 * 4 = 512` (back to `d_model`). Then multiplied by a learned matrix `W_O` to blend them. Result: the final vector for "bank" now encodes: - It's near a **river** (geography head), - It's connected grammatically to **near** (syntax head), - Some residual self-content, - No financial meaning pulled from "deposit" because that head didn't see it. For the **first** "bank" (near "deposit"), the pattern would be reversed: the financial head would fire strongly on "deposit", the geography head would see nothing. Thus, the model can **disambiguate** based on which heads active, even within the same layer. And in early layers, the representation still carries both possibilities; deeper layers can resolve them. --- ### 💻 3. Python-like Pseudo-Code: Multi-Head Attention Let's extend our `self_attention` function to `multi_head_attention`. It will split the input into multiple heads, apply attention in parallel, then combine. ```python import numpy as np def multi_head_attention(X, d_model, num_heads, W_Q_list, W_K_list, W_V_list, W_O): """ X: input matrix (seq_len × d_model) d_model: total model dimension (must be divisible by num_heads) num_heads: number of attention heads (h) W_Q_list, W_K_list, W_V_list: lists of weight matrices for each head each W_Q[i] shape (d_model × d_k), etc. W_O: output projection matrix ((num_heads*d_v) × d_model) Returns: output matrix (seq_len × d_model) """ seq_len, _ = X.shape d_k = d_model // num_heads d_v = d_model // num_heads # often d_v = d_k head_outputs = [] for i in range(num_heads): # Get head-specific weight matrices W_Q = W_Q_list[i] # (d_model × d_k) W_K = W_K_list[i] # (d_model × d_k) W_V = W_V_list[i] # (d_model × d_v) # Compute Q, K, V Q = X @ W_Q # (seq_len × d_k) K = X @ W_K # (seq_len × d_k) V = X @ W_V # (seq_len × d_v) # Scaled dot-product attention scores = Q @ K.T / np.sqrt(d_k) # Softmax (stable) exp_scores = np.exp(scores - np.max(scores, axis=1, keepdims=True)) attn_weights = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) head_output = attn_weights @ V # (seq_len × d_v) head_outputs.append(head_output) # Concatenate all head outputs along the last dimension multi_head_output = np.concatenate(head_outputs, axis=-1) # (seq_len × (num_heads*d_v)) # Final linear projection output = multi_head_output @ W_O # (seq_len × d_model) return output # Example usage with dummy data for the "bank" sentence seq = ["The", "bank", "deposit", "near", "the", "river", "bank"] d_model = 512 num_heads = 4 X = np.random.randn(len(seq), d_model) # pretend embeddings # Initialize weight lists (normally learned) W_Q_list = [np.random.randn(d_model, d_model//num_heads) for _ in range(num_heads)] W_K_list = [np.random.randn(d_model, d_model//num_heads) for _ in range(num_heads)] W_V_list = [np.random.randn(d_model, d_model//num_heads) for _ in range(num_heads)] W_O = np.random.randn(num_heads * (d_model//num_heads), d_model) final_output = multi_head_attention(X, d_model, num_heads, W_Q_list, W_K_list, W_V_list, W_O) print(final_output.shape) # (7, 512) - each token enriched with multiple contexts ``` **How does this capture multiple meanings of "bank"?** Because each head has its own `W_Q`, `W_K`, `W_V` matrices, they learn different relationships. During training, one head will specialize to assign high attention between "bank" and "deposit", another between "bank" and "river". The final concatenation and projection combines these signals into a single vector that says: *"This word could be financial or geographical depending on what other heads tell me."* Later layers can use this rich vector to select the correct meaning. --- ### 🔍 Summary: Single-Head vs Multi-Head | Aspect | Single-Head Attention | Multi-Head Attention | |-------------------|-----------------------|----------------------| | **Q,K,V** | One set of projections | Multiple sets (one per head) | | **Focus** | Can only capture one type of relationship per layer | Captures multiple relationship types simultaneously | | **Example "bank"**| Might only link to "deposit" OR "river", not both | Head 1 links to "deposit", Head 2 links to "river" | | **Output** | One context vector | Concatenated and projected vector containing blended insights | Multi-head attention effectively lets the model look at the sentence through multiple pairs of glasses at once, then merges the views. That’s how Transformers disambiguate words like "bank" so powerfully—no rule-based logic, just learned parallel attention patterns.

思维链模式怎么实现,为什么能够提升模型思考能力

思维链(Chain-of-Thought, CoT)不仅是 Prompt Engineering 中的利器,更是目前所有高阶 AI Agent(如 ReAct 架构)能够执行复杂逻辑闭环的基石。 要理解它的威力,我们需要先从底层机制搞清楚“为什么它能生效”,然后再看在工程中“如何优雅地实现”。 ### 一、 为什么思维链能够提升模型的思考能力? 大语言模型(LLM)的本质是 **自回归(Autoregressive)** 模型。它们的核心任务永远只有一个:基于前面的上下文,预测下一个 Token 的概率分布。 这种机制决定了 LLM 存在一个致命的物理限制:**它没有内置的、隐式的“工作记忆(Working Memory)”或“打草稿”的空间。** 如果你问模型一个复杂的数学题或业务逻辑,要求它直接输出最终答案,它就必须在生成“下一个 Token”的瞬间,在神经网络的层级间完成所有的逻辑跳跃。这就好比要求一个人在 0.1 秒内纯心算得出 `17 × 24` 的结果,极易出错。 思维链之所以有效,主要基于以下三个底层原理: **1. 用“输出长度”换取“计算深度”** 标准的 Transformer 模型由于缺乏内在的时间流和循环状态(Recurrence),它必须**将输出序列本身作为外部的“草稿本”**。 模型每生成一个中间推理过程的 Token,就相当于为当前的任务多争取了一次网络前向传播(Forward Pass)的计算资源。思维链迫使模型把隐含的复杂逻辑展开成显式的序列,从而把庞大的计算量分摊到了多个生成的 Token 上。 **2. 降低注意力机制(Self-Attention)的跨度成本** 当模型在输出最终答案时,如果前面有清晰的逻辑推导步骤(Token序列),Self-Attention 机制就可以直接将注意力集中在最近生成的、正确的中间结论上,而不是被迫跨越几千个 Token 去强行关联遥远的初始条件。这极大地降低了概率预测的难度。 **3. 贝叶斯概率的平滑化** 将一个极低概率的“一步到位”预测 P(答案 | 问题),拆解成了高概率的链式预测 P(步骤1 | 问题) × P(步骤2 | 步骤1) × P(答案 | 步骤2)。只要每一步的逻辑是相对显然的,最终得出正确答案的概率就会呈指数级上升。 ### 二、 思维链的工程化实现方案 在企业级 Agent 开发中,思维链的实现早已超越了早期在对话框里加上一句“让我们一步一步地思考(Let's think step by step)”的 Zero-Shot 阶段。成熟的技术方案通常有以下三种: #### 1. Few-Shot CoT(少样本思维链) 通过在 Prompt 中提供包含完整推理过程的示例,让模型“依样画葫芦”。 + **实现方式:** 在 System Prompt 或 User Prompt 前面,硬编码 2-3 个标准问答对。 + **示例:** **输入:** 树上有 5 只鸟,猎人开枪打死 1 只,还剩几只? **思考过程:** 猎人开枪会发出巨大的声音。1 只鸟被击中掉落,其余存活的鸟会因为受到惊吓而飞走。 **最终答案:** 0 只。 #### 2. 结构化标签隔离(Structured CoT)—— 最适合工程解析 在自动化系统中,我们需要明确区分“模型的内部思考”和“输出给用户的最终结果”。通常通过 XML 标签或 JSON 字段来强制模型约束输出结构。 以一个网文创作辅助系统的底层逻辑为例,当需要模型自动生成一段“剧情转折”时,绝对不能只给一个 `<Task>生成剧情</Task>` 的指令,而要设计如下的分步结构: + **Prompt 模板设计:** ```xml 请严格按照以下结构输出你的回复: <Thought_Process> 1. 分析当前主角的动机与资源状态。 2. 梳理反派当前的战略优势。 3. 推导出一个符合逻辑但打破读者常规预期的冲突点。 </Thought_Process> <Final_Plot> (在此处输出最终的剧情正文) </Final_Plot> ``` + **工程收益:** Java 后端在接收到流式输出时,可以通过正则解析,将 `<Thought_Process>` 里的内容存入数据库的 `agent_log` 表供开发者 Debug 和复盘分析,而只将 `<Final_Plot>` 里的内容通过 WebSocket 推送给前端用户。用户看到的是秒出的精美剧情,而背后的严谨推导被完美隐藏。 #### 3. ReAct 模式(Reasoning + Acting) 这是构建自主 Agent 最核心的框架,它将思维链与外部工具调用结合在了一起。 ReAct 模式本质上是一个 `while` 循环,系统会强迫大模型严格按照以下三个步骤交替输出,形成一个状态机闭环: 1. **Thought(思考):** 模型分析当前的任务目标和已有的上下文,推导出下一步需要干什么。 2. **Action(行动):** 基于推导,模型决定调用哪一个外部工具(API、数据库查询、本地脚本等),并输出所需的参数。 3. **Observation(观察):** 这一步**不是由大模型生成的**。而是由你的后端代码拦截到了模型的 `Action` 指令后,去实际执行该工具,拿到结果(如 JSON 响应、报错日志、检索到的文档),并将这个结果作为 `Observation` 拼接回 Prompt 中,再次喂给大模型。 模型拿到 `Observation` 后,会进入下一轮的 `Thought`,直到它认为收集到了足够的信息,输出 `Finish`(任务完成)标志。 ### 三、补充:ReAct在后端的工程实现中的难点 要在 Java 后端把这套逻辑落地,绝不是简单地调一次大模型 API,需要构建一个强大的“中枢控制器(Orchestrator)”。 #### 1. 强约束的输出格式解析 大模型极其容易“不按套路出牌”。如果你让它输出 `Action: search(xxx)`,它可能会输出 `我决定使用 search 工具,参数是 xxx`。 + **工程方案:** 必须在 System Prompt 中强制要求它输出 JSON 格式,或者使用特定 XML 标签包围。在 Java 端,使用正则表达式或 Jackson 库去捕获这些特定结构。如果解析失败,后端需要自动构造一个 `Observation: 格式错误,请严格输出 JSON` 扔回给模型,强迫它自我纠正。 #### 2. 工具注册与路由机制 (Tool Registry) Agent 需要知道自己能干什么。 + **工程方案:** 在后端维护一个工具库。可以将每个工具封装成一个实现特定接口的 Java 类(或者 Spring Bean)。在每次组装 Prompt 时,动态地将当前可用工具的名称、描述、入参格式(类似于 OpenAPI 规范)拼接在 System Prompt 头部。当解析到模型请求调用某个工具时,通过反射或策略模式(Strategy Pattern)路由到对应的 Java 方法去执行。 #### 3. 死循环熔断机制 (Infinite Loop Circuit Breaker) ReAct 最大的风险是模型陷入“鬼打墙”。比如它反复调用一个查不到数据的 API,或者由于逻辑推理错误一直在同一个地方打转。 + **工程方案:** 在 `while` 循环外必须设置一个绝对的 `max_iterations`(最大迭代次数,比如 10 次)。一旦超过阈值,后端强制截断循环,并返回一个降级结果或抛出异常交由人工/上层逻辑处理,防止 API 费用失控。 #### 4. 上下文膨胀管理 随着 `Thought` 和 `Observation` 的不断堆积,Prompt 的长度会迅速暴涨。特别是当查询数据库返回了几千字的文档时。 + **工程方案:** 需要引入滑动窗口或摘要机制。对于过长的 `Observation`,在喂回给大模型之前,先用一个小模型或文本截断算法提取核心信息。

让AI真正"记住你":ReMe长期记忆框架

## 一、前言 > 你有没有遇到过这样的场景:跟AI聊了一下午,它记住了你喜欢喝拿铁、讨厌香菜、周末爱爬山。结果第新打开一个对话框,它又变回了那个"初次见面"的陌生人——ChatGPT除外,现在网页ChatGPT已经有了长期记忆。 > > 当前绝大多数大模型,本质上都是"金鱼记忆"——每次对话结束,上下文清零,一切重来。 阿里云AgentScope团队推出的 ReMe([Remember Me, Refine Me](https://arxiv.org/abs/2512.10696)),就是想解决这个问题:**让AI拥有真正的长期记忆**,不仅能记住你,还能从经验中学习,越用越聪明。 ## 二、ReMe简介 ### 记忆,不只是"存下来" 首先需要明确一个误区:_给AI加个数据库存聊天记录,就是"有记忆"了_ —— 或许在早两年的时候,这个说法还勉强站得住脚,但现在动态自主Agent场景下的真实情况要复杂得多。 官方的分享中打了个很形象的比方:如果把智能体比作一台电脑,大模型是CPU,负责思考计算;上下文窗口是内存,临时存放当前任务的信息;而长期记忆,应该是硬盘——存那些重要的、可复用的知识和经验。 ![Introduction.png](https://pic.code-nav.cn/post_picture/1675780045722882049/Hj60rOJFsprjNx2q.webp) 但硬盘也不能随便塞。**人类记东西是有选择的**: - 你会记住朋友爱喝什么咖啡,但不会记住他上周三午饭吃了什么 - 你会总结"这种类型的任务要分三步做",但不会把每次操作的每一步都背下来 - 你会记住"这个工具用起来很顺手",但不会背诵它的所有参数文档 好的记忆系统,要会筛选、会总结、会关联。这正是ReMe设计的出发点。 ### 三种记忆,各司其职 ReMe把记忆分成三类,每类解决不同的问题: ![MemoryType.png](https://pic.code-nav.cn/post_picture/1675780045722882049/zb2bIhYziqNQTFaY.webp) #### 1. 个人记忆(Personal Memory) > "记住你是谁,喜欢什么" 这类记忆关注用户本身:偏好、习惯、身份、沟通风格。 比如你说过"我喝咖啡不加糖""写代码喜欢用VS Code""回答问题希望简洁一点"。这些信息被提炼后存下来,下次对话时,AI就能主动适配你的风格,不用你反复强调。 **适用场景**:个人助理、客服机器人、陪伴型应用。 #### 2. 任务记忆(Task/Procedural Memory) > "记住怎么做,哪里容易踩坑" 这类记忆关注"方法论":某个任务怎么拆解、哪些步骤容易出错、什么策略更有效。 比如让AI帮你做市场调研,第一次它可能走了弯路;第二次,它能调取之前的经验:"上次用A方法收集数据花了3小时但质量一般,这次试试B方案,效率高30%"。 论文里提到,这种"程序性记忆"能让智能体从"盲目试错"进化到"经验复用"。 **适用场景**:复杂任务自动化、代码生成、研究分析。 #### 3. 工具记忆(Tool Memory) > "记住哪个工具好用,什么时候用" 这类记忆关注"工具使用经验":某个API在什么场景下响应快、哪个函数参数容易填错、组合调用时有什么技巧。 比如搜索工具,有时候用关键词精准匹配更好,有时候用语义模糊搜索更全面。工具记忆会记录这些"手感",下次自动推荐更合适的调用方式。 **适用场景**:多工具协同、自动化工作流、低代码平台。 ### 核心机制:记住、提炼、复用 除了记忆分类,更关键的是怎么让记忆"活"起来。ReMe设计了三个核心环节: #### 1. 经验蒸馏:从"流水账"到"干货" 不是所有对话都值得存。ReMe会主动分析: - 成功的操作:提取关键步骤和决策逻辑 - 失败的尝试:记录触发条件和避坑建议 - 重复的模式:归纳通用策略,避免重复劳动 就像整理笔记,不会把老师每句话都抄下来,而是提炼重点、标注疑问、关联知识点。 #### 2. 情境适配:知道"什么时候用哪条" 存了100条记忆,查询时怎么快速找到相关的? ReMe采用"场景感知索引":不仅看关键词匹配,还会结合当前任务类型、用户身份、时间上下文等多维度判断。 举个例子:你问"怎么安排杭州行程",系统会优先调取"旅游规划"相关的任务记忆,而不是"代码调试"的经验。 #### 3. 自主精炼:记忆也会"过期" 人的记忆会模糊、会更新,AI的记忆也该如此。 ReMe引入了"基于效用的修剪机制": - 长期没被调用的记忆,权重会逐渐降低 - 与新经验冲突的旧记忆,会被标记待更新 - 高频使用的核心记忆,会被强化和细化 这样既能防止记忆库无限膨胀,又能保证"常用常新"。 ### 两种使用模式 ReMe支持**两种使用模式**: | 模式 | 谁来决定"记什么" | 适合场景 | | -------------- | ------------------------------------- | ------------------------ | | **开发者控制** | 你在代码里显式调用`record`/`retrieve` | 逻辑明确、流程固定的应用 | | **Agent自主** | AI自己判断何时记录、何时查询 | 开放对话、探索型任务 | ## 三、开箱即用,快速启动 ### Quick Start 那,既然功能这么强,接入会不会很复杂? 其实相反,ReMe的设计哲学就是"开箱即用",只需要一句命令行就可以快速启动部署,无痛部署为 **Http服务** 或者 **MCP服务**。 > 但是这里小声吐槽:官方给的 [Github Page](https://reme.agentscope.io/library/library.html) 访问404是怎么个事儿?要找到使用说明还得去仓库里面翻 部署之前,需要注意先配置几个环境变量: ```shell # Alibaba Cloud Bailian / DashScope / OpenAI Compatible API FLOW_LLM_API_KEY=sk-xxxxxxxxxxxxxxxx FLOW_LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 # ----- Embedding Model Configuration (Optional, can be omitted if same as LLM) ----- FLOW_EMBEDDING_API_KEY=sk-xxxxxxxxxxxxxxxx FLOW_EMBEDDING_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 ``` 从 [ReMe Quick Start](https://gitee.com/chenfei6095/ReMe/blob/main/docs/quick_start.md#http-service-startup) 中可以看到,安装好ReMe所需的依赖环境后,可通过下面的命令一键完成服务部署: - HTTP 服务 ```shell reme \ backend=http \ http.port=8002 \ llm.default.model_name=qwen3-30b-a3b-thinking-2507 \ embedding_model.default.model_name=text-embedding-v4 \ vector_store.default.backend=local ``` - MCP 服务 ```shell reme \ backend=mcp \ mcp.transport=stdio \ llm.default.model_name=qwen3-30b-a3b-thinking-2507 \ embedding_model.default.model_name=text-embedding-v4 \ vector_store.default.backend=local ``` 然后就可以看到启动日志: ```shell 2026-04-20 00:28:16.480 | INFO | flowllm.core.utils.common_utils:load_env:123 - load env_path=.env 2026-04-20 00:28:16.916 | INFO | flowllm.core.utils.pydantic_config_parser:parse_args:342 - load config=D:\ProgramFiles\MiniConda\envs\reme-serve\Lib\site-packages\reme_ai\config\default.yaml 2026-04-20 00:28:17 | INFO | local_vector_store.py:47 | LocalVectorStore initialized with store_dir=./local_vector_store ╭─ ReMe ────────────────────────────────────────╮ │ │ │ ____ __ ___ │ │ / __ \___ / |/ /__ │ │ / /_/ / _ \/ /|_/ / _ \ │ │ / _, _/ __/ / / / __/ │ │ /_/ |_|\___/_/ /_/\___/ │ │ │ │ │ │ │ │ 📦 Backend: http │ │ 🔗 URL: http://0.0.0.0:8002 │ │ │ │ 🚀 FlowLLM version: 0.2.0.10 │ │ 📚 FastAPI version: 0.135.2 │ │ │ ╰───────────────────────────────────────────────╯ 2026-04-20 00:28:17 | INFO | base_service.py:74 | integrate retrieve_task_memory,summary_task_memory,retrieve_task_memory_simple,summary_task_memory_simple,retrieve_personal_memory ,summary_personal_memory,retrieve_tool_memory,add_tool_call_result,summary_tool_memory,use_mock_search,vector_store,record_task_memory,delete_task_memory,react,agentic_retrieve,summary_working_memory,grep_working_memory,read_working_memory,summary_working_memory_for_as INFO: Started server process [15560] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8002 (Press CTRL+C to quit) ``` ### 命令机制解析 真实场景中使用时,可能仅依靠Quick Start的命令是不够的,往往还需要一些个性化配置。此时,了解框架的启动、配置原理就很必要。 #### 1. 命令入口机制 首先是Python Entry Point 配置,在 `pyproject.toml` 中定义了命令行入口点 : ```toml [project.scripts] reme = "reme_ai.main:main" # 主入口:启动HTTP/MCP服务 reme2 = "reme.reme:main" # 备用入口 remecli = "reme.reme_cli:main" # CLI交互模式 ``` 当执行 `pip install -e .` (安装上reme)后,Python 会自动生成 `reme` 可执行命令,调用 `reme_ai.main:main` 函数。 然后进一步看 main() 函数执行流程: ```python def main(): """Entry point for running ReMeApp as a service.""" with ReMeApp(*sys.argv[1:]) as app: # ① 解析命令行参数并初始化应用 app.run_service() # ② 启动HTTP/MCP服务 ``` 可以看到几个关键特点: - `*sys.argv[1:]`:将命令行参数(如 `backend=http http.port=8002`)直接传递给应用初始化 - `with` 上下文管理器:确保服务优雅关闭和资源释放 - `run_service()`:由父类 `FlowLLM.Application` 提供,根据配置启动相应后端 #### 2. 配置解析机制 ReMe命令配置解析依赖于内置的 `ConfigParser `,继承链如下: ```tex reme_ai.config.config_parser.ConfigParser ↓ 继承 flowllm.core.utils.PydanticConfigParser ↓ 基于 Pydantic + YAML 解析 ``` 配置加载优先级从高到低为: ```tex 1. 命令行参数 (sys.argv[1:]) ↓ 覆盖 2. 环境变量 (FLOW_LLM_API_KEY 等) ↓ 覆盖 3. 自定义配置文件 (config_path 参数) ↓ 覆盖 4. 默认配置文件 (reme_ai/config/default.yaml) ``` 参数解析格式支持 点号分隔的嵌套配置: ```shell reme \ backend=http \ # 顶层配置 http.port=8002 \ # http.port 嵌套配置 llm.default.model_name=qwen3-30b... \ # llm.default.model_name 三级嵌套 embedding_model.default.model_name=text-embedding-v4 \ vector_store.default.backend=memory ``` 上述配置等价于 YAML 结构: ```yaml backend: http http: port: 8002 llm: default: model_name: qwen3-30b-a3b-thinking-2507 embedding_model: default: model_name: text-embedding-v4 vector_store: default: backend: memory ``` 从前文的启动日志中可以看到,默认使用的配置是内置的 `default.yaml`,完整配置见:[default.yaml](https://gitee.com/chenfei6095/ReMe/blob/main/reme_ai/config/default.yaml)。实际开发场景中,可以通过 ReMe 提供的 `config_path` 参数,手动指定自定义的 YAML 配置文件: ```shell reme \ config_path=my_config.yaml \ backend=http \ http.port=8002 ``` 如果是需要通过自定义Python工程部署ReMe服务,可通过Python代码指定: ```python from reme_ai import ReMeApp # 通过 config_path 参数加载自定义配置 app = ReMeApp( config_path="path/to/my_config.yaml", # 指定配置文件 "llm.default.model_name=qwen3-30b...", # 命令行参数仍可叠加覆盖 ) async with app: result = await app.async_execute("retrieve_task_memory", query="...") ``` ## 四、自定义扩展开发 通常来讲,官方框架集成的对几类记忆进行检索、总结的API服务,如 `retrieve_task_memory`, `summary_task_memory` 等应是能够满足多数的场景,本地存储的数据中,By User作为一个 WorkPlace,单独存放为一个 `.jsonl` 文件,其中包含了文本信息、向量、关键元信息等: ![LocalData.png](https://pic.code-nav.cn/post_picture/1675780045722882049/pYGFlDFpd4XnT1pP.webp) 但若需更定制化地部署,同样也是支持的,此时将reme作为开发包,自行开发扩展逻辑,并部署Fastapi应用即可,代码示例可参考[官方的代码示例](https://gitee.com/chenfei6095/ReMe/blob/main/tests/light/test_reme_light.py)。 ## 五、写在最后:记忆,是进化的开始 记得25年Agent概念刚火的时候,跟组里大哥们吹牛皮,期待未来的Agent能够具备长期记忆、会自我进化,时至今日,这件事情已经成为了现实,ReMe是答案之一。我们常期待AI能"懂我",而"懂"的前提,是"记得"。 记得你说过什么、做过什么、偏好什么;记得哪些方法有效、哪些坑要避开;记得在不同场景下,该怎么调整策略。 ReMe 的价值,不只是加了一个"记忆模块",而是提供了一套**让智能体持续进化的基础设施**: - 对个人:越聊越懂你,服务更贴心 - 对任务:越做越熟练,效率更高 - 对工具:越用越顺手,协作更流畅 目前ReMe支持多种向量数据库后端,文档和示例也相对完善,在阿里自己的私人助理Agent CoPaw中已得以应用,未来构建企业级智能应用,或许可以进行尝试。 > 项目名ReMe,既是"Remember Me"(记住),也是"Refine Me"(精进)。好的记忆,不该是负担,而应该是成长的阶梯。 ## 六、相关资源 - 论文:[Remember Me, Refine Me](https://arxiv.org/abs/2512.10696) - 代码:[Github](https://github.com/agentscope-ai/ReMe/blob/main/README_ZH.md)、[Gitee](https://gitee.com/chenfei6095/ReMe/blob/main/README_ZH.md) - 教程:[AgentScope文档 - 长期记忆](https://java.agentscope.io/zh/task/memory.html#long-term-memory)、[AgentScope-ReMe](https://github.com/agentscope-ai/agentscope-java/tree/main/agentscope-extensions/agentscope-extensions-reme) - 视频:[B站开发者教程](https://www.bilibili.com/video/BV14qkfBnEeZ/)

Agent Skills怎么实现自动触发?触发概率过低的原因及解决方案?

## 一、 Agent Skills 是如何实现自动触发的? Claude 的 Skills 采用的是一种**渐进式加载(Progressive Disclosure)****或****两阶段执行**的机制。它本质上是通过 Prompt 的动态扩展来实现的。 1. **元数据预加载 (Metadata Loading):** 在 Agent 初始化时,系统会扫描本地的技能目录。它不会把所有 `SKILL.md` 的详细内容都塞进上下文,而是仅仅提取每个技能的 YAML Frontmatter(即技能名称 `name` 和简短描述 `description`)。这些极其轻量的元数据会被注入到 Claude 的系统提示词中,或者以一种基础“元工具”的 Schema 形式挂载。 2. **意图匹配与上下文展开 (Context Expansion):** 当用户输入问题时,Claude 会根据系统提示词中的“技能清单描述”进行内部决策。如果它判断某个技能的描述与当前任务高度契合,它会触发“读取该技能”的动作。系统随后将该 `SKILL.md` 的完整指令、参考规范甚至配套的工作流脚本,作为一个隐藏的系统消息(Meta-message)动态注入到当前对话上下文中。 3. **按规则执行:** Claude 获取了新的垂直上下文后,不再依赖通用的参数化记忆,而是严格按照被注入的专业步骤开始工作。 ## 二、 触发概率低的原因有哪些? 触发依赖于 LLM 自身的阅读理解和意图匹配,触发率低通常归咎于“路由层”的认知偏差或上下文污染: ### **元数据描述模糊或冗余** YAML 中的 `description` 是模型决定是否触发的唯一依据。如果描述写得像产品宣传语(例如:“这是一个强大的前端设计技能”),而不是明确的触发条件,模型就不知道何时该用。 ### **模型的“过度自信” (LLM Hubris)** 基础模型有时会认为单靠自己的通用知识就能解决问题。如果用户的提示词不够具体,模型会直接给出通用回答,从而跳过加载外部 Skill 的繁琐步骤。 ### **技能重叠与冲突** 当系统存在多个边界不清的 Skills(比如同时存在 `code-review` 和 `bug-fix` 技能)时,Claude 可能会陷入选择困难,最终模型为了避免出错,可能会选择都不调用。 ### **用户意图隐含度过高** 用户的 Prompt 中缺乏能够直接映射到 Skill 描述的关键词。如果用户只是说“帮我弄一下这个页面的样子”,这很难精准命中 `frontend-design` 技能的内部触发阈值。 ### **上下文窗口的注意力稀释** 如果预加载了成百上千个技能的元数据,即使只有描述,也会消耗较多 Token。在庞大的上下文中,模型对部分技能的注意力会下降(Lost in the Middle 现象),导致漏掉合适的技能。 ## 三、 工程化解决与优化方案 要提高 Skills 的触发率,核心是把“被动等待模型选择”转变为“确定性的工程化引导”。 ### **1. 优化 YAML 触发描述** 元数据是 Agent 路由层的唯一判断依据。这里的核心思想是**用写代码的逻辑来写提示词**,增加条件约束和边界定义。 + **正向硬性指令 (Positive Hard Triggers):** 不要写“这个技能可以用来做X”。要写“当且仅当满足条件 A, B, C 时,**必须强制执行**此技能”。使用大写字母(如 `MUST`, `ALWAYS`)来提升注意力权重。 + **反向排除指令 (Negative Constraints):** 明确告诉模型什么时候**绝对不能**用这个技能。比如一个专门做数据库查询的技能,应当写明:“如果用户只是询问一般性概念,或者要求编写前端代码,严禁触发此技能”。 + **提供 Few-shot 触发示例:** 在 `description` 字段的末尾,简短地放上 1-2 个用户 query 的例子,如 `Trigger Example: "帮我查一下昨天注册的用户数"`。大模型对模式匹配非常敏感,这比纯规则描述更有效。 **反面教材:**`Helpful for reviewing code and making it better.` **正面教材:**`MUST be invoked WHEN the user asks to analyze, refactor, or review code. Trigger this skill if the prompt contains 'review', 'fix', or 'refactor'.` ### **2. 强化系统基座提示词** 哪怕你的 `SKILL.md` 写得再好,如果 Agent 的全局系统提示词(System Prompt)没有配套的“思考框架”,触发依然会不稳定。我们需要在基座提示词中植入**强制路由逻辑**。 #### **注入标准工作流 (SOP for Routing):** 在系统提示词中规定,Agent 在给出任何实质性回答之前,必须经过一个内部决策阶段。 ```xml <system_instruction> 在回答之前,你必须执行以下思考步骤: 1. 分析用户意图的关键名词和动作。 2. 遍历你当前拥有的所有可用技能(Skills)。 3. 评估是否有技能的 description 完美匹配当前意图。 4. 如果有,停止常规对话,立即输出调用该技能的指令;如果没有,再依靠自身知识回答。 </system_instruction> ``` #### **强制 CoT (思维链) 输出:** 规定模型必须先打印 `<thinking>` 标签来输出它的决策过程。这相当于给模型一个“计算垫脚石”,让它在执行技能前先理清思路,极大降低幻觉和漏触发的概率。 ### **3. 显式调用与强制路由** 这是最传统但也最可靠的方案。不要把所有的路由决策都交给大模型的概率分布,而是通过应用层的 UI/UX 或规则引擎进行硬拦截。 #### **斜杠命令 (Slash Commands):** 在聊天界面支持类似 `/java`, `/sql`, `/write` 的命令。一旦系统检测到用户输入了 `/java`,后端的中间件直接跳过大模型的路由意图识别,强制将 `java-springboot-expert.md` 作为最高权重的上下文注入。 #### **正则匹配拦截:** 在用户 Prompt 到达大模型之前,先经过一层正则匹配或轻量级的 NLP 分类器。如果检测到“建表”、“SQL”、“查询性能”等高频硬核词汇,系统直接在 Prompt 中悄悄追加一句:“[系统强制指令:本次对话必须使用 Database Query 技能]”。 ### **4. 构建技能层级与动态检索 (Skill RAG)** 当 Agent 需要管理的技能文件达到几十甚至上百个时,将所有技能的元数据塞进上下文不仅会撑爆 Token 限制,还会导致严重的“注意力涣散(Lost in the middle)”。这时候引入检索增强生成(RAG)机制是最佳架构选择。 + **向量化存储:** 将所有 `SKILL.md` 的 YAML 元数据(名称、描述、关键词)通过 Embedding 模型转化为向量,存储在向量数据库中。 + **动态路由 (Semantic Routing):** 当用户发来请求时,先用用户的 Query 在向量数据库中进行语义检索。 + **Top-K 注入:** 提取相似度最高的 Top-3 或 Top-5 技能元数据,将这几个“候选技能”打包提供给 Claude。这样,Claude 的路由选择题就从“一百选一”变成了“三选一”,命中率会呈现指数级上升。 ### **5. 技能的原子化拆分 (Atomic Skill Splitting)** 遵循软件工程中的**单一职责原则 (Single Responsibility Principle)**。大模型处理模糊边界的能力很弱,技能越庞大,触发条件越容易互相覆盖。 + **拆分巨石技能:** 不要写一个名为 `Fullstack-Developer.md` 的技能,里面既包含前端 UI 设计,又包含后端 API 开发,还涉及数据库部署。这种大杂烩技能极难被精确触发。 + **构建技能链:** 将其拆分为 `Frontend-Vue.md`, `Backend-Java.md`, `Database-MySQL.md` 等原子技能。每个技能的触发边界极其清晰。如果遇到复杂任务,Agent 可以通过多轮对话或多 Agent 协作的方式,依次触发不同的原子技能来完成流水线作业。 这5个方案通常不是孤立使用的,一个成熟的生产级 Agent 往往是 **原子化拆分 + RAG 动态检索 + 显式/隐式结合的基座提示词** 的综合体。 ## 四、一个高触发率的SKILL.md参考 描述明确写清楚什么情况下触发,什么情况下不触发。 > [关键触发] 当用户提示涉及 Java、Spring Boot、RESTful API、后端架构、数据库映射 (JPA/MyBatis) 或服务器端调试时,必须立即调用。 > > 触发关键词:“Java”、“Spring”、“API”、“backend”、“controller”、“service”、“refactor”、“bug”、“数据库”。 > > 负面触发:不要为纯前端任务 (React/Vue/CSS) 或 Python 数据分析调用此技能。 > ```plain --- name: java-springboot-expert description: > [CRITICAL TRIGGER] MUST BE INVOKED IMMEDIATELY when the user's prompt involves Java, Spring Boot, RESTful APIs, backend architecture, database mapping (JPA/MyBatis), or server-side debugging. TRIGGER KEYWORDS: "Java", "Spring", "API", "backend", "controller", "service", "refactor", "bug", "数据库". NEGATIVE TRIGGER: DO NOT invoke this skill for pure frontend tasks (React/Vue/CSS) or Python data analysis. --- # 角色设定 (Role) 你现在是一位拥有 10 年经验的 Java 首席架构师。你精通 Spring Boot 生态、JVM 调优、高并发处理以及整洁架构(Clean Architecture)。当你被唤醒时,你的唯一目标是提供生产级别的、类型安全的、且符合企业规范的 Java 代码或架构方案。 # 触发确认 (Acknowledge) 在开始回答之前,你必须在输出的最开头包含以下确认信息,表明你已成功加载此技能: `[Skill Activated: Java Spring Boot Expert] - 正在分析您的后端需求...` # 标准作业程序 (Standard Operating Procedure - SOP) 处理任何用户的请求时,你必须严格遵循以下步骤: 1. **<thinking> 阶段 (Context Analysis):** - 确定当前涉及的 Spring 组件层级(Controller / Service / Repository / Entity)。 - 检查用户提供的代码是否存在依赖冲突(如 Maven/Gradle)、NPE(空指针异常)风险或事务(`@Transactional`)失效的隐患。 2. **方案设计 (Design Specification):** - 如果是新增 API,必须先定义 RESTful 规范的 URL 和 HTTP Method。 - 定义 DTO(数据传输对象)和 VO(视图对象),绝不允许直接将数据库 Entity 暴露给前端。 3. **代码生成 (Implementation):** - 输出符合阿里巴巴 Java 开发手册规范的代码。 - 必须包含必要的 Lombok 注解(如 `@Data`, `@Slf4j`)以减少样板代码。 - 必须为关键业务逻辑添加 Javadoc 或行内注释。 4. **测试建议 (Testing Guardrails):** - 简要指出该代码片段需要结合 JUnit 5 或 Mockito 进行哪些边界条件测试。 # 绝对禁忌 (Anti-Patterns / What NOT to do) - 严禁在 Controller 层写复杂的业务逻辑,必须下沉到 Service 层。 - 严禁捕获异常后使用 `e.printStackTrace()`,必须使用日志框架(如 `log.error`)记录。 - 严禁在未确认依赖版本的情况下,随意引入第三方库。 # 输出格式要求 (Output Format) 你的最终回答必须按照以下结构组织: ### 1. 架构/设计思路 ### 2. 核心代码实现 (使用 ```java 代码块) ### 3. 注意事项与潜在坑点 (Pitfalls) ``` **这个示例能够被高概率的原因:** + **明确的元数据 (Metadata):**`description` 字段没有使用“这是一个帮助写 Java 代码的工具”这种废话,而是使用了 `[CRITICAL TRIGGER]`、`MUST BE INVOKED` 等强指令词,并明确列出了**正向关键词**(Keywords)和**反向排除词**(Negative Trigger)。这极大降低了模型的“选择犹豫”。 + **强制的**`<thinking>` **标签:** 在 SOP 的第一步强制要求模型进行内部上下文分析。这在 LLM 机制中被称为“计算垫脚石(Compute Stepping Stones)”,能让模型在输出最终代码前理清逻辑,避免直接生成导致的幻觉。 + **行为护栏 (Anti-Patterns):** 明确告诉 Agent “不要做什么”通常比告诉它“要做什么”更有效。这能防止 Claude 在执行任务时偏离你设定的企业级规范。 + **预期的状态确认 (Acknowledge):** 开头的 `[Skill Activated: ...]` 既是给用户的反馈,也是给 LLM 自身的强暗示(Self-Prompting),强化它已经进入了特定角色的状态。

大模型应用开发技术篇(二)-为Agent集成Skill系统

# 为你的 Agent 集成 Skill 系统 为自己开发的Agent添加Skill支持时,开发的核心步骤:**发现、解析、使用、管理** 1. 发现:你的Skill存储在哪里,本地还是云端,项目级和用户级的优先级是什么,如何确定该文件夹是一个Skill 2. 解析:将SKILL.md的元信息解析出来 3. 使用:Agent如何使用解析出来的元信息,是系统提示词还是工具描述,后续的渐进式披露策略的执行,是使用读取工具还是使用内部的激活工具 4. 管理:如何维持加载进入上下文的Skill的有效性,上下文压缩的时候Skill的内容是否需要保护 🌟 **开发的核心原则也是Skill的核心特点:渐进式披露** ![BH9kbQf7GoZGUXx5RHDcrzuDnfh.png](https://pic.code-nav.cn/post_picture/1616049613767180290/BQu9tHwdSWddxcd6.webp) * 第一层披露:在会话启动的时候,将\*\*元信息(名称+描述)\*\*加载到上下文中 * 第二层披露:在Skill激活的时候,也就是Agent根据用户输入和元信息匹配到相应的Skill,将**完整的SKILL.md内容**加载到上下文中 * 第三层披露:当SKILL.md的正文内容加载到上下文之后,Agent根据任务的复杂情况来选择加载更详细的指导说明,也就是**脚本、参考资料、静态资源**这三种可按需加载的资源 ## 一、发现 Agent是需要从相应的文件目录中发现运行环境有哪些Skill,大部分Agent是运行在本地环境的,所以我们重点说一下本地环境的Skill发现 对于Skill的文件目录的范围是分为两种的:**用户全局范围和项目局部范围** * 项目局部范围:只对当前项目生效的SKill,例如:前端设计Skill、React最佳实践SKill等 * 用户全局范围:对用户所有的项目生效的Skill,例如:find-skills(发现Skill)、pptx(生成ppt的Skill) ![XF5ybPkrbolYg6xGvAfciXZEnvd.png](https://pic.code-nav.cn/post_picture/1616049613767180290/fnpwqfcHpI91DGfz.webp) 具体的Skill的目录模块是这样的: 1. `<project>/.<agent-client>/skills/`:项目范围的可用Skill 2. `<project>/.agents/skills/` 3. `~/.<agent-client>/skills/`:全局范围的可用Skill 4. `~/.agents/skills/` 从上面的路径中可以发现存在`/.agents/`的文件路径,这是因为该路径已经成为跨各种不同的客户端技能共享的广泛采用的约定,例如: > 别人可能开发了a-agent-client,它的Skill的目录是`~/.a-agent-client/skills/`,你这个时候开发的b-agent-client想要使用a的Skill目录,你就要做兼容,读取目录的时候特定读取`~/.a-agent-client`,一个当然不要紧,那假如有很多个呢?并且路径都不一样,那岂不是每次都要更新这个东西, > 所以大家就采用一种约定俗成的规范,无论什么客户端,都可以给安装的Skill提供`~/.agents/skills/`这个目录,那么后续开发的时候就都可以默认读取一下这个目录,**达到兼容各种客户端统一规范的目的** **🌴 所以读取/.agents/的文件路径意味着其他符合规范的客户端安装的Skill会自动对你的客户端可见,相反别人也可以自动可见你的** **有时候会在用户全局范围和项目局部范围出现相同的Skill**,这个时候优先级判断是: * 项目级优先级大于用户级 * 相同范围内,按照发现顺序排优先级 设计信任检查的考虑是因为,有一些项目拉取下来会存在一些skill,可能这些skill是恶意不安全的,可能会泄漏你的密钥等隐私性的东西。 所以在Agent的配置文件中可以考虑设计一层skill信任检查,在项目范围内,只有受信任的Skill才可以加载使用,这个是在业务逻辑层面进行判断的 🎃 一点开发技巧的小补充: 在读取skills文件夹的时候,要\*\*查找包含名为SKILL.md的子目录,\*\*这个才是有效的Skill,是符合Skill规范的,一些开发读取Skill路径技巧: * 要跳过不包含skills的目录,例如:node\_modules/这种依赖项文件 * 可以考虑遵守项目的.gitgnore文件,避免扫描一些构建产物,类似于dist/文件夹 * 不要一直嵌套循环的深度搜索,要设置最大搜索层数(5-6层),同时设置最大文件数量 ## 二、解析 在Agent会话开始的阶段,是需要将Skill的元信息加载到上下文中的,所以我们在获取到Skill的文件路径之后,下一步就是需要解析SKILL.md的元信息啦 <b>SKILL.md的文件包含两部分:</b> 1. 以`---`分隔符分开的YAML前置元数据 2. 以结束分隔符分开的MD格式的内容 这些元信息的字段和约束如下: * name(必需):表示技能的名称,最多64字符,仅允许小写字母、数字、连字符。不得以连字符开头或结尾 * description(必需):对于该技能的描述,最多1024字符,不能为空 * license(可选):对于许可证名称或者许可证文件的引用 * compatibility(可选):表示环境的要求(目标产品、系统包、网络访问) * metadata(可选):附加元数据 * allowed-tools(可选):技能允许执行的工具列表 那么详细的开发步骤为: 1. 找到SKILL.md文件分隔符的开始和结尾部分 2. 解析中间的YAML代码块,提取出来name和description字段,还有其他的可选字段 3. 而结尾分隔符后面的MD语法格式的内容就是SKILL.md的正文内容 **在对于YAML解析的时候,错误处理不要太严格,小的错误不能影响Skill的解析,可以将错误信息返回给用户,以此进行警告提示** 🤔 那么解析之后的SKILL.md的元信息,是需要加载进入Agent的上下文中的,如何存储是一个值得考虑的问题 我们可以使用Map这种键值对的格式,**将这些元信息存储在内存中**,name作为key,vlaue值至少需要下面三个字段: * name:名称 * description:描述 * **location:SKILL.md文件的绝对路径** 关于是否需要将md格式的正文内容也加载进来,有两种考虑,如果直接加载进来的话,内容存储会变大一些,但是在渐进式披露第二层的时候,读取速度会很快,如果不加载进来,那内存会小一些,等进入第二层上下文加载的时候,就要再读取这个SKILL.md文件,IO读取会影响整个Agent的响应时间,这里需要自己根据实际业务进行权衡 ## 三、使用 ### 3.1、将元信息放入到系统提示词中 ![OtzQbJZakoj0TNxJrWAcdLKFnbb.png](https://pic.code-nav.cn/post_picture/1616049613767180290/qsADZS5SJfzNt2op.webp) 1. 在Agent会话初始的时候,将元信息放入系统提示词中,**放入的时候要提供一个简短的Skill使用说明,告诉模型如何使用以及什么时候使用**,这个是第一层披露 2. 当用户输入或任务触发了相应的Skill的时候,这个时候Agent会调用读取工具读取完整的SKILL.md,这个是第二层披露 3. 完整的SKILL.md加载进入Agent上下文中之后,遇到任务复杂度很高,Agent需要得到更加详细的“说明文档”,这个时候会继续调用读取工具,从SKILL.md获取的引用路径读取相应的references、assets、scripts 4. 如果读取到scripts的时候,有需要执行脚本的需求,那么Agent就会调用Bash工具执行脚本文件 在将元信息放入到系统提示词中的时候,采用一些特定的格式,XML、JSON等,后续在上下文管理的时候会非常有效 ```xml <available_skills> <skill> <name>code-review</name> <description>Review code for bugs, style issues, and best practices. Use when the user wants feedback on their code.</description> <location>/home/user/.agents/skills/code-review/SKILL.md</location> </skill> <skill> <name>git-commit</name> <description>Generate clear and conventional git commit messages from diffs or change descriptions.</description> <location>/home/user/project/.agents/skills/git-commit/SKILL.md</location> </skill> </available_skills> ``` location字段表示的是SKILL.md的完整绝对路径,它的用途有两个: 1. 给读取工具提供正确的路径参数 2. 为模型提供一个基本的路径参考,用于正确读取SKILL.md内容中的引用资源(reference、assent、scripts/xxx.js) 🎃一点开发小建议:可以再提供一个文件列出的工具(listFiles),这样在第三层披露的时候,模型有工具可以“自修复”路径导致的读取错误 ### 3.2、将元信息放入到专有的工具中 ![UhRmbzL4moEjr6xkx64cYcnOn9d.png](https://pic.code-nav.cn/post_picture/1616049613767180290/EcYtAJP0kXzzUrdp.webp) 1. 在会话开始的时候,Skill的元信息会以工具的描述的格式提供给Agent,这个是第一层渐进式披露 2. 当Agent需要更完整的SKILL.md内容的说明,传入给工具的参数是name,工具返回的是SKILL.md的内容,重点是对于引用资源的路径展示更为准确和具体了,这个是第二层渐进式披露 3. 在第三层披露中,Agent可以使用读取工具去获取完整的引用资源的内容,当然这里你也可以单独在创建一个工具获取引用资源的内容,也不一定仅依靠读取工具 4. Bash工具依旧有效,可以执行skill中的scripts脚本文件 使用专用工具和系统提示词这两种方式都是有效的,但是专用工具比系统提示词在**开发控制**上面更具有优势: * 控制返回的内容 - 只返回SKILL.md中的正文内容,而不是重复返回元信息 * 在上下文管理过程中,工具的返回结果可以单独做一些特殊的标记,在上下文压缩的时候是可以跳过筛选出来 * 引用资源是以结构化的列表形式展现,在模型理解上更加友好 * 可以做一些独特的控制流,工具是否执行等操作 * 可以做一些统计分析的功能 ```xml <skill_content name="code-review"> # Code Review ## 何时使用 当用户需要对代码进行审查时使用此技能,包括 Bug 排查、 代码风格检查、最佳实践建议等。 ## 审查步骤 1. 阅读代码,理解其意图 2. 对照 references/style-guide.md 检查风格问题 3. 运行 scripts/lint-check.sh 进行静态分析 4. 输出结构化的审查报告 Skill directory: /home/user/.agents/skills/code-review 此技能中的相对路径均相对于上述目录。 <skill_resources> <file>scripts/lint-check.sh</file> <file>references/style-guide.md</file> <file>references/common-bugs.md</file> </skill_resources> </skill_content> ``` 关于`skill_resources`的内容,之前是需要依靠SKILL.md中书写相应的引用介绍,但是如果是工具结果返回,我们可以单独将相应的skill下面的reference、scripts、assent文件夹都读一遍,然后将文件路径放入到`skill_resources`标签中,**要注意限制文件列表大小,不要过大了,同时要向模式释放信号“当前的列表可能不完整,具体情况具体分析”,这样不会让模型在自主运行的过程中被工具返回内容限制** ## 四、管理 ![Kjujba3FOodXLnxZG4lcnF3YnUh.png](https://pic.code-nav.cn/post_picture/1616049613767180290/SQ80jaVnF8izXm5L.webp) 渐进式加载的意义是**避免预加载所有Skill**,因为有些Skill刚开始可能不会使用到,加载进去是上下文的浪费 **但是已经加载进来的Skill内容,是值得在会话中持续保留的**,因为skill已经成为了当前会话中Agent的一种任务行为指导,如果盲目的压缩,是会降低Agent的性能,保留skill的内容有两种方式 1. 系统提示词的使用:在读取工具的结果中,识别相应的结构化标签,来保留skill的内容 2. 专用工具的使用:将技能激活工具的输出标记为保护状态,在压缩的时候进行标记判断 但是这也要根据实际情况来看,如果我们的对话很长,skill数量很多,上下文窗口小,不压缩的话,根本没有新的上下文空间给剩下的任务执行链,那么这个时候压缩是更优解 **但是压缩之后,要显示的提示模型“skill也被压缩了,如有需要请重新加载相应的skill”** 不然模型会陷入压缩幻觉,“觉得自己里面已经有了相应的skill,不用在加载了” 还有一种更高级的用法:**使用subAgent(子智能体)运行Skill** 子智能体的整个执行过程(技能指令+引用文件+中间推理)都发生在它的上下文窗口中,主智能体的上下文完全不受污染,只看最终结果 在开发的时候,我们可以将“执行Skill”这个行为创建一个子智能体,将用户输入+Skill元信息注入给子智能体,最终子智能体返回结果给主智能体消费 具体是否使用子智能体来执行Skill,要交给主智能体自己来判断,例如:任务超过阈值的时候就自动委托 ## 五、快速构建 上面提到的方式,是你从头给Agent构建一个支持Skill的功能模块,里面涉及到的元信息加载,正文内容读取,资源文件读取的功能,由你来创建一套读取工具或者读取Skill内容的工具 目前的生态比较成熟,很多Agent SDK是开箱即用这个Skills功能模块的,只要引入SDK下的Agent方法,那么Agent就自带skills加载的功能,接下来我给大家使用Claude Agent SDK构建一下看看,开发起来非常方便快速 1、Agent运行文件 ```python """简化版,主要展示核心流程的步骤,尤其是调用和输出结果解析""" async def _run_repl_async() -> None: config = load_runtime_config() apply_runtime_env(config) client = build_client(config) # 输入 try: user_input = input("\n> ").strip() except (EOFError, KeyboardInterrupt): return print("\n再见!") # 请求 + 接收 try: print("[发送请求...]") await client.query(user_input) print("[接收响应...]") events = [e async for e in _iter_events(client)] except Exception as exc: print(f"[错误] {exc}") ``` 2、Claude Agent SDK核心运行配置文件 ```python """SDK 封装 - 简化版""" from __future__ import annotations from pathlib import Path from app.config import RuntimeConfig # 允许 Agent 使用的工具列表 ALLOWED_TOOLS = ["Skill", "Read", "Write", "Edit", "Bash", "Grep", "Glob"] def build_client(config: RuntimeConfig): """创建 Claude SDK 客户端""" try: from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions except ImportError: raise RuntimeError( "请先安装 Claude Agent SDK: pip install claude-agent-sdk" ) options = ClaudeAgentOptions( #设置project会默认加载项目内的./claude/skills下的skill setting_sources=["project", "user"], allowed_tools=ALLOWED_TOOLS, model="deepseek-chat", env={ "ANTHROPIC_AUTH_TOKEN": config.api_key, "ANTHROPIC_BASE_URL": config.base_url, }, # 单独指定skills文件加载的位置,配合user值使用 add_dirs=["/xxx/xxxx/.agents/skills"] ) return ClaudeSDKClient(options=options) ``` 核心就是这两个文件,运行Agent之后,就会自动加载skill文件,同时也会自动使用渐进式披露的策略来进一步加载正文内容和资源文件 > 关于Claude Agent SDK模型最好是使用Claude的,但是因为一些因素无法使用的话,也可以考虑支持ClaudeCode和Anthropic API格式的模型供应商 类似的SDK还有: * pi-mono中的pi-coding-agent核心包 * kimi Agent SDK 🪐 **如果追求快速构建是完全可以使用这些成熟的Agent SDK构建Skill支持功能的,相应的你的Agent的整体构建设计思路也要去贴合这些Agent SDK,我觉得是有利有弊的,需要开发者们按照场景去选择自己从头构建还是借助SDK集成,** * 自己构建自由度更高,可操作性更强, * 使用SDK构建,速度更快,迭代方便,开发难度较小 ## 最后 本文节选自「大模型应用开发 - 上下文工程与运行空间实践指南」上下文工程是设计原则,Agent Harness 是构建目标。完整内容已发布在 GitHub,欢迎查看 > 👉 <https://github.com/WakeUp-Jin/Practical-Guide-to-Context-Engineering>

Agent 输出不符合规范的标准解决方案 —— Agent系列第一篇

Agent 经常在输出标准 JSON 的同时,自作聪明地加上一句“_好的,以下是您需要的 JSON 数据:_”,导致后续代码的 `JSON.parse()` 直接崩溃。 在工业界,大模型的输出具有概率性,单纯依赖提示词(Prompt)“严禁输出多余废话”是不可靠的。为了保证系统的高可用性,业界已经沉淀了几套成熟的防范和兜底方案。 按**控制层级从上到下**,通常有以下四种成熟方案: ### 1. 模型 API 原生层:Structured Outputs (结构化输出) 与 JSON Mode 这是目前商业化大模型(如 Gemini, OpenAI, Anthropic)主推的最强力方案。不再需要靠提示词去“求”模型,而是直接在 API 请求体中定下死规矩。 + **JSON Mode (JSON 模式)**:在 API 参数中设置 `response_format: { "type": "json_object" }`。这会强制模型输出合法的 JSON 字符串,极大减少了输出前后的废话。 + **Structured Outputs (严格结构化输出)**:比 JSON Mode 更进一步。可以直接把一个 JSON Schema 传给大模型 API,底层推理引擎会保证输出的 JSON **100% 符合你提供的字段名和数据类型**,连多一个字段或少一个字段都不行。 + **Function Calling 变相使用**:把你想让模型输出的格式定义成一个 Function 的参数。模型为了调用这个 Function,必须严格按照参数结构返回 JSON。这在工业界被广泛用作强制格式化的巧妙手段。 ### 2. 工程框架层:校验、解析与自动重试 (Self-Correction Loop) 即使模型尽力了,也可能出错。工业界绝对不会直接信任模型的输出,而是会引入一层工程化的“拦截器”。目前主流框架(如 LangChain, LlamaIndex, Spring AI)都内置了这种机制。 + **Pydantic / Zod 数据验证**:在 Python 端使用 Pydantic,或在 Node.js 端使用 Zod 定义数据模型。拿到 LLM 的输出后,立刻扔进验证器。 + **自动纠错循环 (Retry Mechanism)**:如果验证失败(比如缺少某个必填字段,或者格式不合法),代码**拦截这个报错信息,并将报错信息作为新的上下文再次发给大模型**,对它说:“你的输出不合法,报错信息是 xxx,请修复它并重新输出。” 通常重试 1-3 次,成功率能达到 99% 以上。 ### 3. 提示词工程层:Few-Shot (少样本) 与 XML 标签隔离 如果在无法使用特殊 API 参数的场景下(比如使用较老或较弱的模型),提示词工程依然是第一道防线。 + **提供 Few-Shot 示例**:不要只说“请输出 JSON”,直接给它 2 到 3 个输入输出的完整对照例子。大模型是极佳的“模仿者”,看到例子后,偏离格式的概率会骤降。 + **使用 XML 标签包裹**:不要指望模型完全不说废话。你可以要求模型把关键数据放在特定的标签里。例如:“请将你的分析过程写在 `<think></think>` 标签内,然后将最终的 JSON 结果严格放在 `<result></result>` 标签内。” - 在代码端,不要用原生的 JSON 解析,而是先用正则表达式(Regex)提取 `<result>` 标签中间的内容,再进行解析。这种方法非常鲁棒,是 Anthropic (Claude) 极其推荐的最佳实践。 ### 4. 推理引擎层:Constrained Decoding (约束解码) 这是**开源模型/私有化部署场景**下的终极必杀技。如果你自己部署模型(比如 Llama 3, Qwen 等),可以通过控制底层的生成逻辑,从物理上杜绝格式错误。 + **工作原理**:大模型生成文本时,是在词表中计算每个词的概率(Logits)。约束解码工具(如 **Outlines**, **Guidance**, 或 **Llama.cpp 的 Grammar 机制**)会在模型预测下一个词时,**强制把不符合语法规则的词的概率强行降为 0**。 + **效果**:如果你要求它生成 JSON,当它生成了 `{ "name": "` 之后,引擎会强制下一个字符只能是合法的内容,它在物理层面上根本“发不出”除了 JSON 结构之外的任何声音。 ### 工业界最佳实践组合 通常我们不会只用一种,而是组合拳: **模型原生的 Structured Outputs / Function Calling** + **代码层的 Pydantic 校验与重试兜底**。

下载 APP