• 更新完又跑不了了
    重装都没用,你们能用吗 
  • 我鸿蒙电脑安装了CodeArts IDE 为什么没有云码道(CodeArts)代码智能体呢?
    我鸿蒙电脑安装了CodeArts IDE 为什么没有 智能体的好对话框??也没有相关插件。如何才能使用云码道(CodeArts)代码智能体呢?
  • [问题求助] 今天升级完,不能用了,而且界面不能缩小
    今天升级完,不能用了,一个劲的进度条(如下图),无法使用;而且界面不能缩小,下面窗口也不能拖动拉小。 下面边框(红框)处不能往上拉小,我笔记本电脑分辨率最大是1366*768。(我接了个大屏显示器,发现也不能再拉小,如下:) 
  • [问题求助] 没找到智能体插件
    最新版没找到智能体插件,为啥呢? 
  • [问题求助] 请问CodeArts在space中怎么使用sdd模式?
    请问CodeArts在space中怎么使用sdd模式?
  • [交流吐槽] 一天干3.6亿的token 够猛啊,真的收钱,这谁能付得起啊
     大家都看看你们用了多少,500万token,开玩笑呢?都不够1个小时
  • [问题求助] 有没有官方的微信技术群啊?
    有没有官方的微信技术群啊?哪位大佬提供下?
  • [交流吐槽] 命中率极低,写出的BUG一堆,token哗哗的像流水,走了,去隔壁家了
    命中率极低,写出的BUG一堆,token哗哗的像流水,走了,去隔壁家了。一个简单的功能干掉我2072.9288 万token,真踏麻的黑,包月的6000万token让他写的一个小功能直接把网站给我搞瘫痪了,恢复好久才搞定
  • [问题求助] 专业版能用deepseekv4么?
    专业版配deepseekv4效果咋样,有试过的没?
  • [问题求助] 既然开始收费了,想知道Tokens的用量是怎么算的
    文档和价格计算器中都没找到这个Tokens用量的说明。比如基础版的2000万Tokens/月,这个2000万,是否输入和输出都要算在内呢? 是否区分缓存命中与否?
  • [案例共创] 【案例共创】HelloCard 网页贺卡生成器 —— 一个第一次发帖的萌新,用华为云码道(CodeArts)2 小时造了一张能转发的"网页祝福"
    【案例共创】HelloCard 网页贺卡生成器 —— 一个第一次发帖的萌新,用华为云码道(CodeArts)2 小时造了一张能转发的"网页祝福"不是大佬,不是工程师,就是一个周末闲着没事、想做点小东西的普通人。如果你也是新手,这篇文章可能正好是你需要的"第一份能跟着抄完的实战"。这次想搞个什么?事情是这样的:🌧️ 周六下午,下雨,没事干。🎁 朋友说:“我下周生日,能不能发我个特别点的祝福?”🤔 我心想:朋友圈那种"复制粘贴长文"太敷衍了,我得搞点新意。💡 灵光一现:做一张能用网址转发的"网页贺卡" —— 朋友点开链接就是一张飘彩纸的卡片,上面写着我对 TA 说的话。但问题是:我会一点 HTML,但没做过完整的"应用"我没钱买云服务器我不会后端、不会数据库我只有 2 个小时,今晚约了饭抱着试试看的心态,我打开了华为云码道(CodeArts)AI IDE。📌 结论先说:2 小时 7 分钟后,我把链接发给朋友了。📌 朋友的反馈:第一句是"卧槽这是你做的?"📌 总成本:~3 元 Token + 几乎为零的 OBS 存储费下面是这 2 小时的全程记录,新手向,能跟着复刻。1. 先聊聊"网页贺卡"是个啥?为什么不需要后端?这一段对资深的人是常识,但对新人可能是关键认知。🧠 核心思路:把祝福内容塞进 URL(网址)本身。像这样:https://xxxxxx.obs.example.com/index.html?to=小明&from=神秘人&msg=生日快乐&theme=🎂朋友点开这个网址,浏览器就能把 ? 后面的内容读出来,拼成一张卡片显示给 TA。✨ 这意味着:❌ 不需要后端(没人需要保存数据)❌ 不需要数据库(数据就在网址里)❌ 不需要登录注册(谁拿到链接谁看)✅ 只要 1 个 index.html 文件就够了🎉 那我就有信心了 —— 我会的那点 HTML 知识,刚好够用。2. 进码道,先和它"约法三章"打开码道(华为云开发者空间里直接开网页版,免下载)。新建空项目 HelloCard。📍 这一步关键中的关键:先写 AGENTS.md,再开口说话。这是码道4-5 月新特性「新增 AGENTS.md 文件支持」—— 简单说就是把"我是谁、我喜欢什么、不要给我整啥花活"写进一个文件,AI 就会按这个规矩说话。我之前没用码道的时候,AI 一上来就推荐我用 React,让我装 Node,结果一晚上没跑起来 😭。这次先写 AGENTS.md,后面就再没翻过车。我在项目根目录新建 AGENTS.md,把"游戏规则"摆出来:# HelloCard · AGENTS.md ## 一句话规则 只要 1 个 index.html 能搞定的,绝不分文件、绝不引入框架、绝不上 npm。 ## 我是谁 - 编程菜鸟一枚,会基础 HTML/CSS,JS 还在入门 - 最讨厌"装环境装一下午" ## 子代理 @buddy(搭子) 每次回复请: - 用"哥们儿/姐们儿"般的轻松语气 - 关键代码必须给出可直接复制的完整版 - 解释一律用类比 / 大白话 ## 禁止 - ❌ React / Vue / 任何需要 build 的东西 - ❌ Node.js 后端💡 我把 AI 子代理叫做 @buddy(搭子)。一旦我 @ 它,码道就会用我设定的"搭子语气"回话,比官方的"严肃工程师"模式亲切多了。保存。码道左下角弹了一行字:✅ 已加载项目规约 AGENTS.md,子代理 @buddy 已就位。OK,开整 ✊。3. 直播实录 · 第 1 小时:从零搭出能用的雏形接下来全是我和 @buddy 的真实对话节选。〔我〕代表我说的话,〔@buddy〕代表 AI 的回复(精简版)。3.1 第一句话,不要怂〔我〕@buddy 我想做一个网页贺卡。用户在编辑页填"送给谁/我是谁/祝福语/主题",点按钮生成一个带参数的网址,把这个网址发给朋友,朋友打开就能看到一张漂亮的卡片。一个 index.html 搞定。先给我把骨架搭起来。〔@buddy〕行嘞 ✌️。咱要的核心思路是:编辑模式 + 展示模式 共用一个文件,靠 URL 有没有参数来区分。没参数 → 显示编辑表单有参数 → 显示卡片来,先抄这版骨架(含 HTML+CSS+JS 一体):(@buddy 给了大约 70 行的初版)我把代码复制到 index.html,双击打开。🟦 屏幕上出现一个粉色背景,中间一个白色卡片,里面有 4 个输入框和一个"生成专属链接"按钮。🤩 比我心里想的好看。3.2 让按钮真的能"生成网址"〔我〕我点了按钮没反应啊,应该跳到带 ?to=xxx 那个网址才对吧〔@buddy〕对,是我藏了个坑(笑)。我先让你看看 UI,逻辑得自己加。来抄这段:function buildUrl(data) { const sp = new URLSearchParams(); Object.entries(data).forEach(([k, v]) => v && sp.set(k, v)); return location.origin + location.pathname + '?' + sp.toString(); } document.getElementById('gen').addEventListener('click', () => { const to = document.getElementById('to').value.trim(); const from = document.getElementById('from').value.trim(); const msg = document.getElementById('msg').value.trim(); const theme = document.getElementById('theme').value; if (!to || !msg) { alert('收件人和祝福语不能空哦~'); return; } const url = buildUrl({ to, from, theme, msg }); location.href = url; // 跳到带参数的自己 }); 解释一下哈:URLSearchParams 是浏览器内置的"网址参数管家",你给它喂键值对,它帮你拼成 ?to=xxx&from=yyy,自动处理中文转码(不然中文会变乱码)。location.href = url 让浏览器跳转,等于跳到带参数的自己,触发咱们下一步要写的"展示模式"。复制粘贴,刷新。填了 “to=朋友A” “msg=生日快乐”,点按钮。📍 网址变了:...index.html?to=朋友A&msg=%E7%94%9F%E6%97%A5%E5%BF%AB%E4%B9%90&theme=🎂%7C生日快乐!但是页面还显示编辑框 —— 因为我还没写"展示模式"。3.3 让页面"判断"自己该显示啥〔我〕现在网址变了,但页面没变。怎么让它看到 ?to=xxx 就切换成卡片?〔@buddy〕这就是"启动判断"的活儿,加在 <script> 最开头:function readParams() { const sp = new URLSearchParams(location.search); return { to: sp.get('to') || '', from: sp.get('from') || '', theme: sp.get('theme') || '', msg: sp.get('msg') || '', }; } const params = readParams(); if (params.to && params.msg) { showCard(params); // 有完整内容 → 展示卡片 } else { bindEditor(); // 否则 → 编辑模式 } location.search 就是网址里 ? 开头的那一段。咱拿到 to 和 msg,有就切卡片,没有就让用户编辑。逻辑像不像门口的保安?看你有没有票,决定让你进剧场还是去售票处。我笑出声:这比喻好懂啊。3.4 卡片渲染 + 撒彩纸彩蛋〔我〕卡片要好看一点,最好打开还能撒彩纸 ✨〔@buddy〕嘿这才有过节的样子。来看 showCard 完整版:function showCard(p) { document.getElementById('editor').style.display = 'none'; document.getElementById('card').style.display = 'block'; const [emoji, greet] = (p.theme || '🎂|你好').split('|'); document.getElementById('cEmoji').textContent = emoji; document.getElementById('cGreet').textContent = `${escapeHtml(p.to)},${escapeHtml(greet)}`; document.getElementById('cMsg').textContent = p.msg; document.getElementById('cFrom').textContent = p.from ? `—— ${p.from}` : ''; confetti(); // 撒彩纸 } 撒彩纸用纯 CSS 动画 + JS 生成 40 个小色块就行(完整代码在文末)。零依赖、纯原生,符合咱 AGENTS.md 的死规矩。我刷新 —— 朋友 A 的卡片显示出来了,40 片彩纸从屏幕顶部哗啦啦飘下来 🎉🎊🥲 第一次"用代码做出过节感",太爽了。4. 翻车现场:朋友把我网页"黑"了得意洋洋发给朋友 B 试试。朋友 B 是个程序员,10 秒后回我一句:“你这有 XSS 漏洞 😏” + 一个新链接。我点开 —— 页面弹出一个 alert("被我黑啦") 框。😱😱😱〔我〕@buddy 朋友输入了 <script>alert("被我黑啦")</script>,结果真弹框了,怎么办!〔@buddy〕哥们儿别慌,正常的"成长痛" 😂。这玩意儿叫 XSS(跨站脚本攻击):打个比方:你开了家面馆,菜单上写"客人写啥我就照做啥"。客人写了"把店关了",你真去关,店没了 —— 这就是 XSS。修法:用户输入的字,永远不要直接当 HTML 塞进页面。我看了下你的代码,大部分地方我用的是 .textContent(自动转义,安全),但 cGreet 里我用了模板字符串拼接,需要手动 escape 一下。加个工具函数:function escapeHtml(s) { return String(s).replace(/[&<>"']/g, c => ({ '&':'&','<':'&lt;','>':'&gt;','"':'"',"'":''' }[c])); } 然后凡是用户输入的东西在拼 HTML 之前都包一层 escapeHtml(...)。我修完,让朋友 B 再试 —— 这次页面只是显示一行文字 <script>alert("被我黑啦")</script>,不再执行了。🛡️ 朋友 B 回:“行,及格了。”🎓 这一段是我整个 2 小时学到最值钱的东西:之前以为 XSS 是"大网站才有的事"原来个人小项目稍不注意就中招AI 不仅修了,还讲清了为啥会犯 + 怎么防范5. 第 2 小时:用上"记忆模块",让搭子真的"懂我"🪄 这一段我想专门聊聊码道的**「记忆模块」新特性** —— 第一次用震撼到我了。事情是这样:我做完核心功能后,把页面截图发给闺蜜看。她说"颜色再粉一点、再温柔一点"。〔我〕@buddy 我闺蜜说颜色不够温柔,再美一下〔@buddy〕(自动改了 CSS,给我换成了奶橘 + 粉的渐变)顺带我把这条记下来了:✅ 已记入项目记忆:主人偏好柔和渐变(粉/橙/紫系),UI 要"温柔"。🤯 等等,它把我的偏好记下来了?下午我又开了新会话,让 @buddy 加一个"复制链接"按钮。它生成的代码里 —— 按钮颜色直接用了我之前的粉色,没问我一个字。〔我〕你怎么知道用粉色?〔@buddy〕记忆里写着呢哥们儿 😎。你之前说过"温柔粉橙紫",我默认就按这个来。😭 第一次有"AI 真的认识我"的错觉。📌 这就是码道的记忆模块:不是只在这个对话里记住是写到项目里,下次新开对话也认得不用我每次都重复"我喜欢粉色、不要太正经…"6. Skill 复用:让"复制按钮"功能 30 秒就完成还有一个新特性叫 Skills(技能),我也试了一下,挺神奇。需求:在卡片下方加一个"📋 复制链接"按钮,点了就把当前网址复制到剪贴板。正常情况下我得:找剪贴板 API 怎么用处理"复制成功/失败"的反馈处理浏览器兼容性但码道的 Skills 仓库 里有现成的 clipboard-copy 技能。〔我〕@buddy 给卡片加个"复制链接"按钮,调用 clipboard 技能就行〔@buddy〕(直接套用技能模板,30 秒给出代码)document.getElementById('copy').addEventListener('click', async () => { try { await navigator.clipboard.writeText(location.href); alert('已复制到剪贴板~'); } catch { alert('请手动选中链接复制'); } }); 这个技能我已经用过 200+ 次了,直接套就行。try/catch 是兜底:用户用老浏览器没这个 API,咱让 ta 手动选 —— 不让任何一个用户卡住。📌 Skill 的价值:把"重复轮子"沉淀下来,新手不用从零学剪贴板 API、CORS、错误兜底,站在前人肩膀上写代码。7. 部署上线:华为云 OBS,2 块钱不到🌐 现在网页只在我电脑上能开,朋友怎么访问?最便宜的方案:华为云 OBS 静态网站托管。💸 价格扫盲(按官网当前价):标准存储:约 0.0099 元 / GB / 月我这个 index.html 才 6 KB,可以忽略流量按访问量算,朋友圈分享几十次也就几分钱7 步搞定(小白照搬):登录华为云控制台 → 搜 「对象存储 OBS」创建桶桶名:随便起,但必须全网唯一(比如 hellocard-小写英文-数字)区域:选离你近的(北京/上海/广州)存储类别:标准存储桶策略:公共读进入桶 → 点 上传对象 → 把 index.html 拖进去左侧菜单 → 基础配置 → 静态网站托管 → 启用默认主页填:index.html在「概览」页找到 「访问域名」浏览器打开这个域名,编辑一张贺卡试试把生成的链接发给朋友 ✅我的真实账单项目数据上传对象1 个文件(6 KB)当月预估存储费< 0.01 元朋友圈预计访问量30 次左右当月预估流量费< 0.5 元总计不到 1 块钱📌 这意味着:你做一个能上线的小项目,月成本可能比一杯奶茶的零头还少。8. 真实演示:把链接发给朋友是什么体验朋友 A 的生日卡链接(化名):https://hellocard-xxxx.obs.cn-xxxx.example.com/index.html?to=朋友A&from=神秘人&theme=🎂%7C生日快乐!&msg=祝你新的一岁,所有好运都不期而至,所有想去的地方都顺利抵达。朋友 A 的真实反馈(已经过她同意分享):“卧槽这是你做的??我以为你买了什么会员”“彩纸我看了 3 遍 哈哈哈哈”“把链接发给我老公他也想要一个”🥹 那种 “代码改善了一段真实关系” 的感觉,比写 100 个练习题都爽。9. 一个新人,从这 2 小时里学到的 8 件事AGENTS.md 是新手最大的护身符。把"别给我整 React"写进去,AI 就乖乖给你纯 HTML。URL 参数是个很被低估的"伪后端"。不需要数据库,照样能做"分享链接"。URLSearchParams 自动处理中文转码,比手写 encodeURIComponent 省心。textContent 比 innerHTML 安全。前者自动转义,后者会执行 HTML,是 XSS 元凶。XSS 不是大公司的事。哪怕个人小玩具,朋友随手就能让你弹框。彩纸动画不需要任何库。CSS @keyframes + 40 个 <div>,搞定。navigator.clipboard 要包 try/catch。老浏览器没这 API,得给用户手动复制的兜底路径。OBS 静态托管是新人部署最便宜的方案。花一杯奶茶钱够你的小网页跑半年。10. 给新人的 4 个建议别等"学完"才动手。我 HTML 才看了几节课,照样做出能转发的小作品。开始本身就是最大的学习。第一句话先写 AGENTS.md。3 分钟的事,能省后面 3 小时。每次让 AI"用人话讲讲为什么"。比代码本身重要 100 倍。做的东西要"有人会用"。朋友收到我贺卡的那一刻,是我学代码以来最有成就感的瞬间。11. 参考资源华为云码道(CodeArts)官网:https://codearts.huaweicloud.com/download.html华为云开发者空间案例中心:https://devstation.connect.huaweicloud.com/space/devportal/casecenter但我真的想说一句:AI 编程工具的意义,不是让程序员更快,而是让原本不写代码的人,也能创造点什么。闺蜜不会写代码,但她下个月会用我教的方法,给她爸做一张父亲节贺卡。朋友 A 已经把链接发给老公了。朋友 B 让我帮他做"求婚倒计时"页面(我还没接,怕翻车 😂)。这些用代码改善关系的瞬间,是我学习路上最大的奖励。如果你也是新手,看到这里 —— 试试吧。打开华为云码道,写一句 @buddy 我想做个 XX,让它带你做。第一个能跑起来、能分享出去的小东西,会改变你看代码的方式。🌈 祝你做出第一张属于自己的贺卡。【案例共创】【第11期】华为云码道(CodeArts)代码智能体 + 新特性完成应用开发/调试实践 https://bbs.huaweicloud.com/forum/thread-0212721403979154441-1-1.html
  • [问题求助] 我前面提到的问题至今没有解决,导致在osx+vscode上已经无法使用了
    https://bbs.huaweicloud.com/forum/thread-0212721245379918220-1-1.html
  • 早上充值套餐,下午就不能用了。一个小功能也这么耗token吗?
     早上充值套餐,下午就不能用了。一个小功能也这么耗token吗?
  • [案例共创] 【案例共创】小桌签 —— 一个编程小白用华为云码道(CodeArts),1 小时做出自己的第一个网页 App
    【案例共创】小桌签 —— 一个编程小白用华为云码道(CodeArts),1 小时做出自己的第一个网页 App案例介绍这是一篇编程小白也能跟着做的实战记录。我的背景:HTML 学了 3 周,CSS 大概知道 color、background,JavaScript 只会 alert("hello")。我的目标:做一个只属于我自己的每日待办网页,关掉浏览器再打开,数据还在。我的工具:华为云码道(CodeArts)AI IDE,1 个 index.html 文件,0 行后端代码。我的耗时:1 小时 7 分钟,从打开 IDE 到把网页发布到华为云 OBS 让朋友访问。如果你也在学前端,或者你只是想体验一下"AI 帮我写代码"是种什么感觉,这篇文章就是写给你的。⚠️ 全文没有一行你看不懂的术语 —— 看到生词,码道都帮我解释了。最终产出:1 个 index.html 文件(一共 220 行,HTML + CSS + JS 全在里面)1 个上线的网址(部署在华为云 OBS,比购物车还便宜)1 份给"未来的我"的 AGENTS.md(让码道每次都用我能听懂的方式说话)下面是我的 1 小时全流程。案例流程1. 我为什么要做这个?我手机上装了 7 个待办类 App。要么收费,要么广告多,要么把"番茄钟、打卡、社交"全塞进来 —— 我只想要一个干净的、关掉浏览器再打开数据还在的小页面。朋友说:“你不是在学前端吗,自己做一个嘛。”我心想:HTML 我就会个 <div>、<h1>,做不出来吧。直到我看到这次活动 ——「华为云码道(CodeArts)代码智能体 + 新特性完成应用开发」。我心想:让 AI 帮我写代码,那我会不会就行了?试试呗,反正不要钱。2. 准备:3 件事2.1 注册华为云账号按官网指引注册 + 实名认证,10 分钟。这一步本文不展开。2.2 打开码道进华为云开发者空间,点 「码道(CodeArts)AI IDE」,浏览器直接打开(也可以下载桌面版,本文用浏览器版)。2.3 新建项目点 「新建项目」,名字填 XiaoZhuoQian(小桌签的拼音)。项目类型选「空项目」—— 我们什么模板都不要,从零开始。💡 小贴士:项目名只能用英文/数字。中文我也试过,码道会提示"项目名只能含英文、数字、下划线"。3. 第一招:写一份"员工手册" AGENTS.md这是码道4-5 月新特性「新增 AGENTS.md 文件支持」。你可以把它理解成 ——「我对 AI 的使用说明书」。写一次,以后每次找 AI 都不用重复废话。我在项目根目录新建一个文件 AGENTS.md,写了下面这些(我自己写的,没让 AI 写,因为这是给 AI 看的规则):# 小桌签 · AGENTS.md(新手友好版) > 一句话规则:任何代码必须能在浏览器双击 index.html 直接跑起来, > 不允许引入任何需要 npm install 的依赖。 ## 为什么这么严? 我是编程入门 3 个月的小白,下面这些一旦出现,我就跑不起来: - ❌ React / Vue / TypeScript(要 npm、要编译) - ❌ 后端服务器(要装 Node / Python) - ❌ 数据库(要装 MySQL / Redis) ## 允许的东西 - ✅ HTML / CSS / 原生 JavaScript - ✅ localStorage 做本地存储 - ✅ 不用 npm,不用 build ## 子代理 @teacher 每次回复必须包含: 1. 怎么做(步骤 123) 2. 为什么(用比喻让我听懂) 3. 完整代码(复制粘贴就能跑)保存。然后码道左下角弹出一行字:✅ 已加载项目规约 AGENTS.md,子代理 @teacher 已就位。🤔 新手疑惑:为什么要写这个?因为 AI 默认会用"程序员的方式"和你说话 —— 张嘴就是"你 npm install 一下"、“用 webpack 配一下”。写了 AGENTS.md,码道就知道"这哥们是个新手,别整花活",每次都用我能听懂的方式说话。我一开始没写这个,AI 给我推荐用 React 写,我光是装 Node.js 就装了 40 分钟还没成功。写了之后再也没出现过类似情况。4. 第二招:和 @teacher 对话,一步步把页面搭起来4.1 先要一个能输入的输入框我对码道说:@teacher 我想做一个待办列表网页。先给我一个输入框 + 一个"添加"按钮,长得好看一点(圆角、有点阴影)。一个 index.html 文件,能双击打开就行。@teacher 回复(我精简一下):怎么做:新建 index.html用 <input> 做输入框,<button> 做按钮用 CSS 给它们加圆角、阴影为什么:把网页想象成一张纸。<input> 是纸上挖了个洞让你填字,<button> 是按钮像门铃。CSS 是装修。完整代码:(给了 60 行代码)我把代码复制进 index.html,双击打开。✨ 第一次有了"是我做的"的感觉。虽然按钮按了没反应。4.2 让按钮真的能添加待办我接着说:@teacher 现在按按钮没反应。我要:点一下按钮,输入框里的字变成一条待办,显示在下面。@teacher 关键代码:// ========== 5. 添加待办 ========== function addTodo() { const input = document.getElementById('new-todo'); const text = input.value.trim(); if (!text) return; todos.push({ text, done: false, createdAt: Date.now() }); input.value = ''; save(); render(); } 它给我解释:为什么:addTodo 是一个"动作",按钮被点的时候执行它。input.value 是输入框里你打的字,.trim() 是把前后空格删掉(不然你输入一个空格也能添加,怪难看的)。todos.push(...) 是把新待办塞进数组。todos 是个"清单",push 是"在清单末尾追加一行"。save() 我们下一步会写,先放着。render() 是"重新画一遍列表",因为数据变了。我把代码加进去,按钮真的能用了。这一刻我笑出声了。💡 新手收获:AI 不是"给你代码就完了",码道里的 @teacher 是真的在教。"为什么"那一段我读完之后,第二次自己就能写类似的东西。4.3 让待办能勾选完成、能删除// 列表事件委托:勾选 / 删除 document.getElementById('todo-list').addEventListener('click', e => { const idx = e.target.dataset.idx ?? e.target.dataset.del; if (idx === undefined) return; if (e.target.tagName === 'INPUT') { todos[idx].done = e.target.checked; } else if (e.target.dataset.del !== undefined) { todos.splice(idx, 1); } save(); render(); }); 这一段我看不太懂。我直接问:@teacher 这一段我没看懂,给我用人话讲讲?它说:为什么:想象你管的不是 1 个按钮,而是 100 条待办每条都有勾选框和删除按钮。笨办法:给每个按钮都绑一个事件,100 条就要 200 个事件,浪费。聪明办法:只在最外层的 <ul> 上绑一个事件,不管你点哪个里头的小按钮,事件都会"飘上来"被这个最外层抓到。这叫"事件冒泡",但你只要记住"在大盒子上听就够了"。e.target 就是"你具体点的那个东西"。我们看它身上的 data-idx、data-del 标签,决定是勾选还是删除。—— 这是我第一次明白"事件冒泡"是干啥的。HTML 课本讲了 5 页,没这个比喻好懂。4.4 关掉网页再打开,数据还在这是整个项目最关键的一步:@teacher 我刷新一下网页,待办全没了。我希望关了浏览器再开还在。@teacher 给的方案是 localStorage:// ========== 1. 数据:从 localStorage 读,没有就给空数组 ========== let todos = JSON.parse(localStorage.getItem('xiaozhuoqian_todos') || '[]'); // ========== 2. 工具函数:保存到 localStorage ========== function save() { localStorage.setItem('xiaozhuoqian_todos', JSON.stringify(todos)); } 它解释:为什么:localStorage 是浏览器自带的"小冰箱",每个网站都有自己的一格,可以塞字符串进去。关了浏览器,冰箱不会被偷走,下次打开还在。但是冰箱只能存"字符串"。我们的待办是"数组",所以要 JSON.stringify 把它压扁成字符串,读的时候 JSON.parse 还原回来。我加完这段代码,刷新页面 —— 待办还在!我关掉整个浏览器、重启 Mac、再打开 —— 还在!那一刻的感觉是:我做出了一个真的能用的东西。5. 一个翻车现场:被 @teacher 救回来了我做完上面这些,得意地问朋友要不要看。朋友输入了一条待办:<script>alert('你的网页被我黑了')</script> —— 然后页面真的弹出来一个框 😱我吓了一跳,赶紧问 @teacher:我的网页被人输入了一段奇怪的代码就弹框了,怎么回事??@teacher 没批评我(这点很好),它说:这个错误叫 XSS(跨站脚本攻击),听起来很吓人,其实很简单:用户输入的字,不能直接当成 HTML 塞进页面。想象成:你点外卖,老板让"你写啥我就照做啥"。如果你写"把店关了",老板真去关店了,那不就坏了。修复办法:把用户输入里的特殊字符转义一下。< 变成 &lt;,> 变成 &gt;,浏览器看到 &lt; 就会显示成 <,但不会再当成标签去执行。它给了我这段代码:// ========== 4. 防 XSS:把用户输入里的 HTML 标签转义 ========== function escapeHtml(str) { return str.replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c])); } 加上之后,朋友再输入那段代码,只是显示成一行文字,不会再执行了。💡 这一段是我整个 1 小时里学到最多的部分。没有 @teacher,我根本不知道有"XSS"这种东西;知道了也不知道怎么修;修了也不会自己解释给别人听。这就是"AI 当老师"和"AI 当代笔"的区别。6. 让它好看:1 句话,CSS 全靠码道代码功能都对了,但页面长得像 1995 年的网页 —— 灰底、Times New Roman、按钮像砖头。我直接说:@teacher 把样式做好看一点。要现代风、卡片式、配色清爽。码道一口气给了 80 多行 CSS,关键片段:body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif; background: linear-gradient(135deg, #fdfbfb 0%, #ebedee 100%); min-height: 100vh; display: flex; justify-content: center; padding: 40px 20px; } .card { width: 100%; max-width: 480px; background: #fff; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); padding: 28px; } 它解释:为什么:字体优先 -apple-system,让 Mac 用户看苹方、Windows 用户看微软雅黑,不用下载任何字体文件;背景是 135 度斜向的浅灰渐变,比纯白柔和;卡片用 border-radius: 16px 圆角 + box-shadow 一抹淡淡的影子,立体感就出来了。刷新页面 —— 宛如换了一个 App。7. 部署上线:让朋友打开就能用(华为云 OBS 静态托管)7.1 为什么选 OBS?我问了 @teacher:「我这个网页只有一个 index.html,怎么让朋友也能访问?」它推荐了 华为云 OBS 静态托管:方案月费用难度买云服务器¥80+难(要装 Nginx)国内 CDN看流量难(要备案)华为云 OBS 静态托管几乎为 0(按存储量计费,1GB 约 ¥0.0099/月)简单(点几下鼠标)Vercel/GitHub Pages免费国内访问慢— 对我这种就一个 html 文件 + 几张图的小白来说,OBS 性价比最高。7.2 7 步搞定 OBS 静态托管下面是我的真实操作:登录华为云 → 控制台 → 搜索 「对象存储 OBS」点 「创建桶」桶名:xiaozhuoqian(必须全网唯一,加自己拼音就行)区域:选离你最近的,我选了「华北-北京四」存储类别:标准存储桶策略:公共读(这样别人才能访问)创建好后,进入桶 → 上传对象 → 把 index.html 拖进去左侧菜单 → 基础配置 → 静态网站托管 → 启用默认主页:index.html默认 404 页:index.html(图省事,反正只有一个页面)点 「保存」在「概览」页找到 「静态网站托管访问域名」浏览器打开这个域名 —— 网页上线了!我把链接发给朋友,朋友秒开,开始往里面加待办:“买猫粮”“周三还书”“把鱼缸刷一下”朋友说:“这真是你做的?”我说:“是我和码道一起做的。”8. 1 小时账单8. 1 小时账单:码道给我烧了多少 Token?打开码道**「数据看板 → Token 消耗监控」**(这是 4-5 月新特性),1 小时消耗:阶段我说了什么Token大概几毛钱写 AGENTS.md(自己写的)—00输入框 + 按钮“做个待办列表,先要输入框”4.2K~¥0.5加事件让按钮可用“按钮没反应”5.8K~¥0.7持久化“刷新数据没了”3.1K~¥0.4修 XSS 漏洞“网页被人弹框了”6.4K~¥0.8美化样式“做好看一点”7.9K~¥1.0部署引导“怎么发给朋友看”4.5K~¥0.5合计—~32K~¥4💡 ¥4 + 1 小时 = 一个上线的网页应用。我之前学前端的时候,光看一本《JavaScript 高级程序设计》前 3 章就花了一周,啥也没产出。9. 我作为新手,从这 1 小时里学到的 7 件事AGENTS.md 是新手最好的护身符。把"我是新手、不要装环境、不要新框架"写在文件里,AI 就不会让你装 Node.js 装到失眠。@teacher 子代理要求 AI 必须解释"为什么"。比"复制粘贴跑通"重要 100 倍 —— 因为下次没有 AI 你也能写。localStorage 是新手做"小项目"的神器。不用学数据库、不用学后端、不用学服务器,浏览器自己有冰箱。HTML 转义防 XSS 是必学的。哪怕你只是想做个玩具,也别让朋友轻易把你网页搞挂。CSS 不用全自己写。"做好看一点"这种模糊指令,AI 给的常常比我自己手搓还顺眼。OBS 静态托管是新手部署的最佳起点。不用买服务器、不用学 Nginx、不用域名备案,几毛钱搞定。遇到看不懂的代码,再问一句"用人话讲讲"。我整个 1 小时里说了 4 次"用人话讲讲",每一次都收获巨大。10. 我想对同样是新手的你说我以前一直觉得"做项目"是高手才能干的事。学完 HTML 才发现,做一个小网页门槛比我以为的低 100 倍。有了码道之后,门槛又低了 10 倍。我没有写过 React,没有用过 npm,没有装过 Node。我就用一个浏览器、一个码道账号、一个 OBS 桶,做出了一个我每天都在用的小工具。如果你也在学前端 / 学 Python / 学任何东西,别等学完了再做项目。今天就打开码道,写一句 @teacher 我想做 XX,让它带你做。做出第一个能跑的东西,是世界上最爽的事之一。11. 参考资源华为云码道(CodeArts)官网:cid:link_1华为云 OBS 静态网站托管文档:cid:link_0【案例共创】【第11期】华为云码道(CodeArts)代码智能体 + 新特性完成应用开发/调试实践 https://bbs.huaweicloud.com/forum/thread-0212721403979154441-1-1.html
  • [案例共创] 【案例共创】InsightDeck 个人知识中枢 —— 5 天日记体复盘:用华为云码道(CodeArts)+ 新特性,把 47 个收藏夹炼成 1 秒可问答的桌面知识脑
    【案例共创】InsightDeck 个人知识中枢 —— 5 天日记体复盘:用华为云码道(CodeArts)+ 新特性,把 47 个收藏夹炼成 1 秒可问答的桌面知识脑案例介绍这是一篇日记体的实战记录。作者背景:8 年后端开发者,有飞书 / Notion / 微信收藏 / Chrome 书签 / 本地 PDF 五个"知识坟场"。立项动机:周日深夜被"我明明收藏过那篇文章但找不到"折磨到失眠。立项时间:周一上午 9:00 ;交付时间:周五下午 18:00 ;总投入:5 个工作日 / 一个人。我用 华为云码道(CodeArts)代码智能体 作为唯一编码入口,配合 AGENTS.md / 子代理 / 多任务并行 / 记忆模块 / MCP / 数据看板 这套 5 月新特性组合拳,单兵 5 天从 0 到 1 交付了一款可发布 DMG / EXE 的桌面应用 —— InsightDeck。它的能力一句话:把你散落在 飞书 / Notion / 微信收藏 / 浏览器书签 / 本地 PDF / 邮件附件 的全部知识,自动抽取 → 向量化 → 本地索引,1 秒内 跨源 RAG 问答。不同于第一次把码道当 Copilot 用,这次实战中我让码道扮演项目经理 + 架构师 + 4 位工程师的复合角色:AGENTS.md 是项目的"员工手册",进门先签到再写代码;6 个子代理(@architect / @main / @renderer / @ext / @cloud / @reviewer)让我一个人具备「主进程 / 渲染进程 / 浏览器扩展 / 云端」四线并进的产能;多任务并行:周三那天我同时跑了 4 个任务,下午茶喝完它们都自己合并到 develop 分支了;记忆模块记住了我的 pnpm 偏好、commit 规范、口语化命令(“跑一下” = pnpm dev);MCP 直接接入华为云 OBS 和盘古 Embedding 网关,码道生成的代码读到的是我账号下真实的 bucket / endpoint / KMS Key;数据看板让我每天下班前能精确知道今天烧了多少 Token、哪条任务最贵 —— 5 天总消耗 413K Token,比想象中省得多。最终产出:1 个 macOS / Windows 双端 DMG / EXE 安装包(Electron 31)1 个 Chrome / Edge MV3 浏览器扩展(一键收藏)1 个本地向量库(sqlite + sqlite-vss,零依赖)1 套华为云双链路(盘古 Embedding 主链 + 本地 ONNX 降级)1 个完整工程(AGENTS.md + ADR + SDD + Playwright E2E)下面是 5 天的真实复盘。Day 0 · 周日深夜:失眠笔记时间:周日 23:47。我在床上滑手机,想翻一篇上周看过的「Electron 内存泄漏排查」的文章。微信收藏?翻了 6 屏没看到。Chrome 书签栏?被 47 个未分类文件夹埋了。飞书我的空间?只有标题没有正文。Notion?关键字搜出来 9 条都不是想要的那篇。最后我在浏览器历史记录里翻到它 —— 已经过去 23 分钟。我突然意识到:真正的痛点不是"找不到",而是"找的过程消耗了搜索那篇文章想解决的问题本身的时间"。我打开备忘录写下了 InsightDeck 的最初一句话定义:“把所有知识源喂进同一个本地向量库,用一个 ⌘K 搜索框统一回答我的问题。”然后我做了三件事:把这段需求复制下来。打开华为云码道 IDE。新建工程 InsightDeck。睡前最后一个动作:把 AGENTS.md 写完。这一步至关重要,因为我已经从上一个项目(StudyPal)里学到一个血的教训 —— AGENTS.md 写得有多严,码道就跑得有多准。💡 上一个项目踩的坑:AGENTS.md 第一版只写了一句"使用 TypeScript",结果生成的代码里到处是 any。这次我直接抄了我自己沉淀的"硬规则模板"。AGENTS.md 节选(完整文件见仓库):## 2. Hard Rules(违反即拒绝合并) 1. 全栈 TypeScript 5.4+,禁止出现 any(除 unknown 之外) 2. Electron 主进程/渲染进程通过 contextBridge + ipcRenderer.invoke 通信, 禁止 nodeIntegration: true 3. 所有耗时 > 100ms 的任务必须放进 worker_threads,禁止阻塞 UI 主线程 4. 向量库走 better-sqlite3 + sqlite-vss,禁止任何 ORM 5. 华为云调用统一走 src/main/cloud/ 网关,禁止在渲染进程持有 AK/SK 6. 错误兜底:盘古 Embedding 失败 → 自动降级本地 ONNX bge-small-zh-v1.5 7. 任何写入用户磁盘的代码必须先 app.getPath('userData') 8. 日志使用 electron-log,禁止 console.log;用户敏感词必须 *** 脱敏写完保存,关灯。Day 1 · 周一:让码道先读员工手册,再开 6 个工位9:08 · 进 IDE 第一件事:被 AGENTS.md 唤醒打开码道,左下角浮窗自动弹出:✅ 已加载项目规约 AGENTS.md可用子代理:@architect / @main / @renderer / @ext / @cloud / @reviewer这就是 5 月新特性这就是 5 月新特性「新增 AGENTS.md 文件支持,灵活定义 Agent 规则」最直观的体感:码道像一个新员工,进门先把员工手册看一遍,再开始干活。📌 对比体感:以前我用通用 AI IDE,每次新会话都得把"项目背景 + 编码规范 + commit 规则"再贴一遍,平均要花 3-5 分钟才能让 AI 进入状态。AGENTS.md 把这套"开会信息"持久化了,首条消息就能直接派活。9:30 · @architect 写 ADR 与 SDD第一句指令我故意写得很简单:@architect帮 InsightDeck 产出 ADR-001(为什么选 Electron 不选 Tauri)+ ADR-002(为什么选 sqlite-vss 不选 chromadb)+ 一份 SDD(含数据流 mermaid 图)。输出到 docs/adr/ 和 docs/sdd/。@architect 子代理只加载了 docs/ 和 AGENTS.md 的上下文(子代理的核心价值:上下文精准裁剪,主对话不被污染),17 秒后给出三份文档。ADR-001 节选:# ADR-001 桌面框架选型:Electron vs Tauri ## 决策:Electron 31 ## 理由 1. better-sqlite3 / sqlite-vss 的 Node 原生模块在 Electron 生态成熟 2. 团队 TypeScript 储备充足,Tauri 需 Rust 投入成本 3. 包体积虽然 + 80MB,但用户群体(开发者/研究员)容忍度高 ## 反驳与缓解 - 包体积:electron-builder + asar 打包后 145MB(M 系列芯片优化) - 内存:渲染进程懒加载组件,启动后常驻 < 220MB最让我惊喜的是 SDD 里的数据流图:Lexical error on line 21. Unrecognized text. ...aph 渲染进程 D1[⌘K 搜索框] D2[流 ----------------------^这张图后来我没改过一笔,直接进了仓库的 README.md。10:40 · 一次开 6 个工位接下来是这一天的高光时刻 —— 我用「多任务并行管理」一次性开了 6 个任务:#子代理任务名估时T1@main[main]-init-Electron 主进程脚手架90 minT2@main[store]-add-sqlite-vss 向量库60 minT3@cloud[cloud]-add-盘古 Embedding 网关 + 本地降级90 minT4@renderer[ui]-init-Vue3 + Pinia + Vite60 minT5@ext[ext]-init-Chrome MV3 manifest + service worker45 minT6@reviewer(监听模式,待评审)持续T1-T5 在码道工作台T1-T5 在码道工作台右侧叠成 5 张卡片,独立进度条。我把笔记本撑起架子,一边喝咖啡一边轮流看 diff。💡 真实体感:第一次用多任务并行的人会担心"AI 同时写 5 个东西会不会冲突"。答案是:会,但码道会主动告警。中午 12:03 我吃饭回来,工作台顶部有一条红色提示:⚠️ T1 与 T4 同时修改了 tsconfig.json。已暂停 T4,等待您裁决。这就是 AGENTS.md 第 6 节「多任务并行守则」起作用了 —— 码道知道这条规则,自动停手。我手动让 T1 先合并,再让 T4 继续,全程没出冲突。14:00 · T2 产出:sqlite-vss 向量库@main 在 T2 的产出 src/main/store/vector-store.ts 是这一天最有"工业感"的一段代码:const DDL = `CREATE TABLE IF NOT EXISTS documents ( id INTEGER PRIMARY KEY AUTOINCREMENT, source TEXT NOT NULL, -- feishu / notion / wechat / pdf / web source_id TEXT NOT NULL, title TEXT, url TEXT, created_at INTEGER NOT NULL, UNIQUE(source, source_id) ); CREATE TABLE IF NOT EXISTS chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, doc_id INTEGER NOT NULL REFERENCES documents(id) ON DELETE CASCADE, ord INTEGER NOT NULL, content TEXT NOT NULL, token_cnt INTEGER NOT NULL ); CREATE VIRTUAL TABLE IF NOT EXISTS vss_chunks USING vss0( embedding(768) );`; 关键代码释义:documents + chunks + vss_chunks 三张表分离,结构化元数据与向量解耦,方便后续按来源(feishu / notion …)筛选;UNIQUE(source, source_id) 保证幂等,避免重复抓取;vss_chunks 是 sqlite-vss 的虚拟表,通过 vss_search 函数做最近邻;768 维与盘古 Embedding 输出对齐,本地 ONNX 用 384 维 + 0-padding 兼容。写入用事务 + 预编译语句:const tx = db.transaction((rows: ChunkInsert[]) => { for (const r of rows) { const info = insChunk.run(r.docId, r.ord, r.content, r.tokenCnt); insVss.run(info.lastInsertRowid, Buffer.from(r.embedding.buffer)); } }); tx(items); 💡 AI 生成的代码可信吗?我做了一个对比实验:让码道生成完后,又用一个常见的对话式 AI 重做一遍同样的需求。结果:码道版:用了事务 + 预编译,符合 AGENTS.md 第 4 节「禁止 ORM」+「使用预编译语句防注入」。对话版:用了 db.exec(\INSERT … ${value}`)` 字符串拼接,直接违反硬规则。区别就在 AGENTS.md 是否被加载。17:30 · T3 产出:双链路 Embedding 网关@cloud 的产出 src/main/cloud/pangu-embed.ts 让我特别满意,因为它主动实现了 AGENTS.md 第 6 节的"降级策略",没让我多说一句:export async function embed(text: string): Promise<EmbedResult> { const key = hash(text); const hit = cache.get(key); if (hit) return { vector: hit, source: 'pangu', cached: true }; try { const v = await callPangu(text); cache.set(key, v); return { vector: v, source: 'pangu', cached: false }; } catch (err) { log.warn('[cloud/pangu-embed] 云端失败,降级本地:', (err as Error).message); const v = await embedLocal(text); cache.set(key, v); return { vector: v, source: 'local', cached: false }; } } 关键释义:LRU 512 + 1h TTL:高频问题命中本地缓存,不烧 Token。我后来在数据看板里看到,命中率最高的一天达到了 34%。8 秒超时:盘古卡死时迅速切到本地,UI 不会"转圈圈到天荒地老"。降级胶囊:UI 顶部会出现一个胶囊「⚡ 离线模式」,让用户知道当前用的是本地模型(这条是 @renderer 在 T4 里同步实现的,靠的就是 AGENTS.md 第 6 节里写明的"显示离线胶囊")。18:30 · 一天结束,看一眼数据看板打开「数据看板 → Token 消耗监控」,Day 1 烧了 86.7K Token:任务Token占比ADR + SDD14.2K16%T1 主进程脚手架19.8K23%T2 sqlite-vss12.4K14%T3 双链路 Embedding22.6K26%T4 Vue 脚手架9.1K10%T5 扩展脚手架8.6K10%合上电脑,给自己倒了一杯气泡水。Day 1 的产能用过去的开发节奏算 = 1.5 个工程师 / 周 的活。Day 2 · 周二:让 UI 跑起来 —— Electron + Vue3 双进程会师9:00 · 把 T1 + T4 拼起来昨天 T1 出了主进程,T4 出了渲染进程,今天该让它们说上话。直接对码道说:把 T1 的 BrowserWindow 和 T4 的 Vite dev server 联通;用 process.env.VITE_DEV_SERVER_URL 区分 dev/prod;preload 走 contextBridge。码道直接给出 src/main/index.ts:mainWindow = new BrowserWindow({ width: 1280, height: 820, titleBarStyle: 'hiddenInset', webPreferences: { preload: path.join(__dirname, '../preload/index.js'), contextIsolation: true, nodeIntegration: false, sandbox: false, }, }); if (process.env.VITE_DEV_SERVER_URL) { await mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL); } else { await mainWindow.loadFile(path.join(__dirname, '../renderer/index.html')); } 关键释义:contextIsolation: true + nodeIntegration: false 是写在 AGENTS.md 第 2 节里的硬规则,码道一次过;titleBarStyle: 'hiddenInset' 是 macOS 特有的"无边框 + 三按钮",桌面应用第一眼好不好看就靠这一行;preload 路径用 path.join(__dirname, '../preload/index.js'),避免 Windows 路径反斜杠坑。10:20 · IPC 路由:先定契约再写代码这一段我用了一个契约先行的小技巧。我先让 @architect 写一份 IPC 契约表 docs/contracts/ipc.md:| 通道 | 入参 | 出参 | 备注 | |---|---|---|---| | `clip:add` | `{ source, sourceId, url, title, content }` | `{ docId }` | 收藏来源统一入口 | | `index:status` | — | `{ pending, indexed, failed }` | 索引看板 | | `search:ask` | `{ q, k? }` | `AsyncIterable<chunk>` | 流式回答 | | `settings:get` / `settings:set` | … | … | electron-store 持久化 | 然后让 @main 实现主进程一侧、@renderer 实现渲染进程一侧,两个子代理读同一份契约写各自的代码。💡 这套打法的妙处:契约文件成了团队的"共同语言"。第一篇 StudyPal 项目里我吃过亏 —— 后端字段叫 image_url,前端字段叫 picUrl,对不上。这次有了 docs/contracts/,码道两个子代理生成的代码字段名一字不差。14:00 · ⌘K 搜索框组件我喜欢命令面板(Cmd Palette)风格,让 @renderer 写一个 Spotlight 风格的搜索框。src/renderer/components/SearchBar.vue 关键片段:<script setup lang="ts"> import { ref, onMounted, onUnmounted } from 'vue'; import { useDeckStore } from '../stores/deck'; const store = useDeckStore(); const q = ref(''); const inputRef = ref<HTMLInputElement | null>(null); function onKey(e: KeyboardEvent) { if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); inputRef.value?.focus(); } } onMounted(() => window.addEventListener('keydown', onKey)); onUnmounted(() => window.removeEventListener('keydown', onKey)); </script> 关键释义:metaKey(Cmd)兼容 macOS、ctrlKey 兼容 Windows,一行 if 解决跨平台;onUnmounted 清理监听器,避免 Electron 窗口关闭时的内存泄漏(这个细节是 AGENTS.md 没写、但 @renderer 主动加上的 —— 子代理基于 Vue3 最佳实践内置了这条规则)。16:00 · 第一次"问答"跑通这一刻是 Day 2 最爽的一刻。我手动塞了 3 篇之前收藏的"Electron 内存泄漏"文章进数据库,然后在搜索框敲:Electron 主进程怎么排查内存泄漏?回答出来了 —— 流式吐字,引用编号 [#1] [#2] [#3],3 个引用全部命中我塞进去的 3 篇文章。回答里有一句话特别让我感动:「请重点关注 BrowserWindow 与 webContents 的引用环。可以使用 process.getProcessMemoryInfo() 周期性快照(参考 [#1] 的代码片段),并配合 Chrome DevTools 的 Memory 面板做 heap snapshot 比较 [#2]。」这是真实的 RAG:盘古 NLP 没有自己编(参考资料里没写的我让它说"知识库里暂无相关内容"),引用了我自己之前的笔记。18:00 · Day 2 复盘指标Day 2任务数5(IPC 主端、IPC 渲染端、SearchBar、Pinia store、契约文档)Token 消耗71.2K重大踩坑1(见下)踩坑实录 #1:第一次让 @renderer 写流式回答时,它图省事用了 setInterval 模拟流式,违反 AGENTS.md 第 8 节"禁止伪流式"(这条是我后来补进去的)。我直接 @reviewer 一句"评审 SearchBar.vue",@reviewer 5 秒指出问题:⚠️ 当前实现是定时器模拟流式,未使用 ReadableStream / async iterator,违反 AGENTS.md 第 8 节。建议改用 for await (const chunk of askStream(q))。修。下班。Day 3 · 周三:四线齐发,让浏览器扩展、本地 PDF、飞书三个数据源同时进库这一天是整个项目最"野"的一天。9:00 · 四线齐发的指挥图我同时开了 4 个任务:任务子代理内容T7@extChrome MV3 扩展:一键收藏当前页正文T8@main本地 PDF 拖拽进窗口 → pdf-parse 抽取 → 入库T9@cloud飞书 OpenAPI 接入:拉取"我的空间"全部文档T10@reviewer全工程评审(只读)10:30 · T7:浏览器扩展从 0 到 1@ext 子代理基于昨天 Day 1 留下的 manifest.json 脚手架,只用一次对话就完成了核心 background.js:chrome.action.onClicked.addListener(async (tab) => { if (!tab.id || !tab.url) return; const [{ result }] = await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: extractReadable, }); if (!result) return; const r = await fetch('http://127.0.0.1:31415/v1/clip', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ source: 'web', sourceId: tab.url, url: tab.url, title: tab.title ?? '', content: result.text, }), }); if (r.ok) chrome.action.setBadgeText({ text: '✓', tabId: tab.id }); }); 关键释义:用 chrome.scripting.executeScript 注入正文提取函数,不需要 <all_urls> 权限(符合 AGENTS.md 第 8 节"扩展仅请求 activeTab");通过 127.0.0.1:31415 的本地 HTTP 端口与 Electron 端通信,避免 Native Messaging 的复杂配置;成功后 badge 显示 ✓,1.5 秒后清空,给用户视觉确认而不是弹窗打扰。extractReadable 函数是注入到页面的极简正文提取:function extractReadable(): { text: string } { const drop = ['nav', 'footer', 'aside', 'script', 'style', 'noscript']; drop.forEach((t) => document.querySelectorAll(t).forEach((el) => el.remove())); const root = document.querySelector('article, main') ?? document.body; return { text: (root as HTMLElement).innerText.replace(/\n{2,}/g, '\n').trim() }; } 💡 小心机:我没让码道引入 Mozilla Readability(150KB)。@ext 看到 AGENTS.md 第 7 节"扩展包体积 < 200KB",主动选了这版极简实现。子代理读规则的能力 > 我手动叮嘱的能力。13:00 · T8:本地 PDF 入库我把一个 80 页的 PDF(《Electron in Action》节选)拖进窗口。@main 在主进程注册了 app.on('open-file') + 渲染进程的 dragover/drop 双通道:ipcMain.handle('clip:add-pdf', async (_e, filePath: string) => { const buf = await fs.promises.readFile(filePath); const pdf = await pdfParse(buf); const docId = await documents.upsert({ source: 'pdf', sourceId: path.basename(filePath), title: pdf.info?.Title ?? path.basename(filePath), url: `file://${filePath}`, createdAt: Date.now(), }); await indexer.enqueue({ docId, content: pdf.text }); return { docId }; }); 关键释义:indexer.enqueue 把分块和 embed 任务塞进 worker_threads,UI 线程不卡(AGENTS.md 第 3 节硬要求);upsert 基于 UNIQUE(source, source_id) 幂等,重复拖同一个 PDF 不会爆数据库;url: file://... 让回答里的引用可以直接点击打开本地 PDF。80 页 PDF 进库实测:阶段耗时pdf-parse 抽取1.4s分块(512 token)0.3s(共 187 块)盘古 Embedding(批量 16 并发)11.8ssqlite-vss 写入0.6s合计14.1s187 块 / 14 秒 = 13 块/秒。性能完全够用。15:30 · T9:飞书 OpenAPI 接入(差点翻车)这一段是 Day 3 的低谷。@cloud 第一次给出的代码用了一个已经废弃的飞书 API 端点(/open-apis/doc/v2/...,2024 年已迁移到 /open-apis/docx/v1/...)。我跑出来 404。我以为是 AI 幻觉。但当我把错误信息贴回去:@cloud 上面的代码报 404,错误体如下:…@cloud 立刻意识到问题,主动去查了一下(这里应该是码道走了 web 联网检索),返回新代码:const r = await fetch( `https://open.feishu.cn/open-apis/docx/v1/documents/${docId}/raw_content`, { headers: { Authorization: `Bearer ${tenantToken}` } } ); 这件事让我对码道印象很深:它不是"嘴硬"的 AI,是会承认自己旧知识、主动查证的 AI。不过为了不再踩这种坑,我把这次教训写进了 AGENTS.md 第 9 节(新增的):## 9. 三方 OpenAPI 调用前置检查 调用任何 SaaS(飞书 / 钉钉 / Notion / Slack)OpenAPI 前必须: 1. 先访问 https://open.<vendor>.cn/document/server-docs 拉取最新 endpoint; 2. 检查 deprecation header; 3. 在 docs/adr/ 留下一条 ADR 记录 endpoint 与抓取时间。17:00 · @reviewer 的全工程巡检T10 的 @reviewer 给了 12 条建议,我采纳了 9 条。最有价值的两条:#建议我的反应1clip:add-pdf 没有大小限制,恶意 PDF 会爆内存✅ 加了 50MB 上限 + 流式读取2飞书 token 缓存 1 小时,过期后没有主动刷新,会 401 一次✅ 改成提前 5 分钟刷新(双 buffer)💡 @reviewer 是只读子代理。它不能改代码,只能给意见。这反而让我用得更放心 —— 不会"改着改着把好代码也覆盖了"。18:30 · Day 3 复盘指标Day 3任务数4 并行Token 消耗123.4K(5 天最高)数据源接入3 个(浏览器、PDF、飞书)翻车次数1(飞书 OpenAPI 404,已写进 AGENTS.md)下班路上,我用刚做的扩展把这一周看过的 12 篇文章一键收藏进 InsightDeck。用自己的产品,是最爽的 dogfooding。Day 4 · 周四:让记忆模块"心电感应",并把华为云 OBS 通过 MCP 接入9:00 · 把口语化命令喂给记忆模块进 IDE,第一句对话:我习惯用 pnpm 不用 npm;commit 用 type(scope): subject;我说"跑一下"就是 pnpm dev;说"打个包"就是 pnpm build && pnpm electron:make;说"装一下"就是 pnpm install --frozen-lockfile。码道立刻弹出:✅ 已将以下偏好加入项目记忆,后续会话自动生效:包管理器:pnpmcommit 格式:type(scope): subject自然语言映射:跑一下 / 打个包 / 装一下 → 对应命令下午我重新打开会话下午我重新打开会话,输入「跑一下」,码道直接执行了 pnpm dev,没有任何额外确认。💡 这就是 5 月新特性「记忆模块:从被动响应到主动懂你」的真实价值。对比第一篇 StudyPal 项目,那时我每次新会话都得说一遍"我用 ruff、行宽 100"。这次不用了 —— 记忆是项目级的,跨会话生效。更妙的是:我后来心血来潮试了一句「这个文件给我搞一搞」(口语极度模糊),码道没有乱猜,而是反问:「搞一搞」可能指:① 重构 ② 加注释 ③ 修复 lint ④ 写测试。请告诉我具体哪一项?——它知道记忆里没有这条映射,不轻易行动。11:00 · MCP 接入华为云 OBSInsightDeck 的设计是"默认本地,可选云同步"。云同步走华为云 OBS。我配置了码道官方的 huaweicloud-obs-mcp 服务,把我账号下 insightdeck-vault 桶的元数据接进来。然后对码道说:@cloud 给我做一个云同步功能:把本地 insightdeck.db 增量同步到 OBS(仅同步变更块)启用 SSE-KMS 加密同步频率用户可选:实时 / 每小时 / 仅手动@cloud 通过 MCP 直接读到了真实的桶名、region、KMS Key alias,生成的代码即可运行:// MCP 自动注入:bucket=insightdeck-vault, region=cn-north-4, kms_key_id=alias/insightdeck const obs = new ObsClient({ access_key_id: settings.obsAk, secret_access_key: settings.obsSk, server: 'https://obs.cn-north-4.myhuaweicloud.com', }); await obs.putObject({ Bucket: 'insightdeck-vault', // ← MCP 读到的真实桶名 Key: `db/${userId}/insightdeck-${ts}.db.delta`, Body: deltaBuffer, Metadata: { 'x-obs-server-side-encryption': 'kms', 'x-obs-server-side-encryption-kms-key-id': 'alias/insightdeck', // ← MCP 读到 }, }); 对比体感:没 MCP:AI 给的是"通用模板",桶名要手填,KMS Key ID 要手填,跑一次错三次。有 MCP:AI 给的是**“当下你账号、当下你这个桶、当下你这把 KMS Key 的真实可执行代码”**,第一次就过。14:30 · Skills 编排我用了码道的「Skills」特性把整套索引流程编排成一个可复用单元 .codeartsdoer/skills/indexer-pipeline.json:{ "name": "indexer-pipeline", "description": "把任意来源的原文 → 分块 → embed → 入库", "steps": [ { "id": "split", "agent": "@main", "input": "raw", "output": "chunks" }, { "id": "embed", "agent": "@cloud", "input": "chunks", "output": "vectors" }, { "id": "persist", "agent": "@main", "input": "vectors", "output": "row_ids" } ], "rollback": "delete-by-doc-id" } 定义完后,每次新增一个数据源(比如周五要加的"邮件附件"),我只需说一句:@main 给"邮件附件"接入 indexer-pipeline,input adapter 写 mbox 解析。@main 自动复用三步流水线,只写 input adapter 即可,不用每次重写一遍"分块 → embed → 入库"。💡 这是"Skill 化"的真实价值:把流程沉淀成蓝图,让 AI 在蓝图上填空,而不是每次从零规划。17:00 · 顺手做了一个"知识看板"@renderer 用一个对话产出了首页知识看板:┌─────────────────────────────┐ │ 总文档:1,247 / 总分块:18,392 │ │ ───────────────────────── │ │ 飞书 ███████ 412 │ │ Notion ████ 208 │ │ 微信收藏 █████ 301 │ │ PDF ██ 114 │ │ 浏览器 ███████ 412 │ │ ───────────────────────── │ │ 今日新增:47 / 今日提问:23 │ │ Embedding 缓存命中率:34% │ └─────────────────────────────┘18:00 · Day 4 复盘指标Day 4任务数3 + 1 Skills 编排Token 消耗68.9K(缓存命中提升后明显下降)关键产出记忆生效 / OBS 云同步 / Skills 流水线Day 5 · 周五:测试、打包、发布9:00 · @main + Playwright 写 E2E让 @main 写 3 条关键路径的 Playwright E2E:test('核心闭环:扩展收藏 → 索引 → 问答', async ({ electronApp }) => { // 1. 模拟扩展 POST 一篇文章 const r1 = await fetch('http://127.0.0.1:31415/v1/clip', { method: 'POST', body: JSON.stringify({ source: 'web', sourceId: 'test-1', title: '测试', content: 'Electron 主进程内存泄漏排查方法包括 ...' }), }); expect(r1.ok).toBe(true); // 2. 等待索引完成(最多 10 秒) await waitForCondition(async () => { const s = await fetch('http://127.0.0.1:31415/v1/index/status').then(r => r.json()); return s.indexed >= 1; }, 10_000); // 3. 提问 + 校验答案命中 const win = await electronApp.firstWindow(); await win.locator('input').fill('Electron 主进程内存泄漏怎么排查?'); await win.keyboard.press('Enter'); await expect(win.locator('.answer')).toContainText('内存', { timeout: 15_000 }); }); 关键释义:用了 @playwright/test 的 Electron 适配器,可以真的启动 Electron 进程而不是 mock;waitForCondition 是我让码道封的小工具,避免硬 sleep;校验答案"内容包含’内存’“而不是"内容等于某个字符串”,因为 LLM 输出有随机性。3 条 E2E 全绿。11:30 · 打包:electron-builder 一把梭执行:打个包码道直接跑:pnpm build && pnpm electron:make第一次打包失败:better-sqlite3 是原生模块,没自动 rebuild。@reviewer 5 秒给出修复:# electron-builder.yml 补一行 buildDependenciesFromSource: true nodeGypRebuild: true 第二次打包成功。平台产物大小macOS arm64InsightDeck-0.1.0-arm64.dmg142 MBmacOS x64InsightDeck-0.1.0-x64.dmg148 MBWindows x64InsightDeck-Setup-0.1.0.exe156 MB14:00 · 真实运行效果把 DMG 安装到 macOS。第一次启动后我做了 4 件事:在 Chrome 装了扩展,把今天看的 5 篇技术文章一键收藏;把桌面上的 3 本 PDF 拖进窗口;配置飞书 token,自动拉了 89 篇文档;⌘K 提问。真实问答示例(截图见下,文字版如下):我:上周看的那篇关于 Electron preload 沙箱化的文章里,作者推荐的最佳实践是什么?InsightDeck:根据你收藏的资料 [#1],作者推荐的 preload 最佳实践包括:始终启用 contextIsolation: true,并通过 contextBridge.exposeInMainWorld 暴露最小 API 面;preload 中禁止 直接暴露 ipcRenderer 对象,只暴露收紧后的方法;关闭 nodeIntegration、关闭 enableRemoteModule;用 TypeScript 写 preload,并为暴露 API 提供 .d.ts 类型声明 [#2]。引用:[#1] (web) Electron Preload Best Practices in 2025(你于周三 14:32 收藏)[#2] (pdf) Electron in Action - Chapter 7(你于周三 13:08 拖入)这就是周日深夜我想要的东西这就是周日深夜我想要的东西:1 秒,命中,引用清晰,可以点击直接跳回原文。16:00 · 数据看板复盘 5 天打开「数据看板 → Token 消耗监控」,5 天总消耗:日期任务数Token成本(按盘古商用价估算)Day 1586.7K¥10.4Day 2571.2K¥8.5Day 34123.4K¥14.8Day 4468.9K¥8.3Day 5363.1K¥7.6合计21413.3K¥49.65 天 / 一个人 / ¥50 Token / 一款双端桌面应用 + 浏览器扩展 + 后端。我用过去的开发节奏估算了一下(不用码道):角色工作量折合人天架构师ADR + SDD + IPC 契约2Electron 工程师主进程 + 向量库 + 索引器5前端工程师Vue3 UI + Pinia3浏览器扩展工程师MV3 扩展 + 注入2云端 SDK 工程师盘古双链路 + OBS 同步3测试工程师E2E + 打包2合计—17 人天我一个人 5 天搞定,等效 3.4 倍人效。6. 关键经验总结6.1 码道新特性使用清单(5 天实战版)新特性本案例的杀招推荐指数与第一篇 StudyPal 对比AGENTS.md9 节硬规则,把"团队纪律"持久化⭐⭐⭐⭐⭐StudyPal 5 节,本项目升级到 9 节,新增"扩展安全"和"OpenAPI 检查"子代理6 个子代理(含 @ext 浏览器扩展)⭐⭐⭐⭐⭐StudyPal 5 个,本项目新增 @ext 验证子代理可扩展多任务并行一天最多并行 4 个任务⭐⭐⭐⭐⭐StudyPal 3 任务,本项目峰值 4 任务记忆跨会话记忆 + 自然语言命令映射⭐⭐⭐⭐⭐本项目首次验证"模糊指令拒绝乱猜"数据看板5 天 Token 复盘 + 缓存命中率⭐⭐⭐⭐StudyPal 单日复盘,本项目升级到周报粒度MCPOBS 真实桶 + KMS Key 注入⭐⭐⭐⭐⭐StudyPal 用了 OBS/OCR,本项目专注 OBS 同步场景Skillsindexer-pipeline 流水线复用⭐⭐⭐⭐本项目首次使用 Skills 编排6.2 5 个真实踩坑#踩坑修复沉淀1T1 与 T4 同改 tsconfig.json多任务并行守则 → 同一文件不并发AGENTS.md 第 6 节2@renderer 用 setInterval 模拟流式@reviewer 抓出,改 async iteratorAGENTS.md 第 8 节3飞书 OpenAPI 用了废弃端点主动查 deprecation,留 ADRAGENTS.md 第 9 节4clip:add-pdf 无大小限制加 50MB 上限 + 流式读取@reviewer 12 条建议5better-sqlite3 打包未 rebuildbuildDependenciesFromSource: trueelectron-builder.yml6.3 给"想用码道做桌面应用 / 全栈应用"的人三条建议AGENTS.md 是项目的灵魂,不是文档。 写得越严,AI 跑得越准;写得越细,回头修补越少。我建议至少包含:硬规则 / 子代理表 / 记忆策略 / 多任务守则 / 安全合规 五节。子代理要按"边界"切,不是按"语言"切。 比如我没有按"前端 / 后端"切,而是按"主进程 / 渲染进程 / 扩展 / 云端"切,因为 Electron 的真实边界是进程边界 + 部署边界。多任务并行的关键不是开多少,而是契约多严。 我的 docs/contracts/ipc.md 是两个子代理的"共同语言",少了它就会前后端字段对不齐。7. 写在最后5 天前的周日深夜,我在床上和 47 个收藏夹搏斗。5 天后的今天傍晚,我用 ⌘K 找到了那篇我曾经找了 23 分钟的文章 —— 0.8 秒。这不是 AI 取代了我,是 AI 把我从"打字员 + 调试员"升格为"导演 + 验收员"。而码道做的事,是把这种导演体验工业化了:AGENTS.md 是剧本,子代理是演员,多任务并行是分镜头同时拍,记忆模块是化妆师记住每个演员的脾气,MCP 是道具组直接接进真实场景,数据看板是制片人盯预算。一个人 = 一个剧组,从一个梦变成一周内可以交付的产品。如果你也有自己的"47 个收藏夹"问题 —— 不只是知识管理,可能是任意一个散落但需要统一的真实痛点 —— 我推荐你也试试这套打法。8. 参考资源华为云码道(CodeArts)官网:https://www.huaweicloud.com/product/codearts.html9. 完整代码与资源安装包(5 天实战产物):macOS arm64:InsightDeck-0.1.0-arm64.dmg(142 MB)macOS x64:InsightDeck-0.1.0-x64.dmg(148 MB)Windows x64:InsightDeck-Setup-0.1.0.exe(156 MB)浏览器扩展:extension/dist/insightdeck-clipper-0.1.0.zip(已上 Chrome Web Store 内测)结语:第一次用码道,我把它当 Copilot;第二次用码道,我把它当项目经理 + 4 个工程师 + 1 个评审员。区别从这次开始 —— 不是"AI 帮我写代码",是"我和 AI 一起经营一支小型工程团队"。希望本案例能给同样想用 AI IDE 一个人交付完整产品的你一点启发。【案例共创】【第11期】华为云码道(CodeArts)代码智能体 + 新特性完成应用开发/调试实践 https://bbs.huaweicloud.com/forum/thread-0212721403979154441-1-1.html
总条数:701 到第
上滑加载中