<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[【伪】架构师]]></title><description><![CDATA[【伪】架构师]]></description><link>https://blog.fleeto.us</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1746412192289/e68a6b50-ce79-4c70-be85-0994647bd025.png</url><title>【伪】架构师</title><link>https://blog.fleeto.us</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 03:12:45 GMT</lastBuildDate><atom:link href="https://blog.fleeto.us/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[龙虾恐慌：AIOps 又要改名了？]]></title><description><![CDATA[ChatGPT 开始，把 AI 拉近到普罗大众的面前，让无数人感受到 AI 的亲民魅力。而龙虾，则把大模型驱动的自动化能力，突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”，而是风口本身。热度高到让 Mac mini 一度断货，不知道这在不在库克的预料之内。
每代人都有每代人的鸡蛋，春节期间，我就领了我的鸡蛋。翻出古老的 MacBook Air M1，充值各种大模型。当然了，这个工具]]></description><link>https://blog.fleeto.us/aiops</link><guid isPermaLink="true">https://blog.fleeto.us/aiops</guid><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Mon, 09 Mar 2026 21:10:37 GMT</pubDate><content:encoded><![CDATA[<p>ChatGPT 开始，把 AI 拉近到普罗大众的面前，让无数人感受到 AI 的亲民魅力。而龙虾，则把大模型驱动的自动化能力，突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”，而是风口本身。热度高到让 Mac mini 一度断货，不知道这在不在库克的预料之内。</p>
<p>每代人都有每代人的鸡蛋，春节期间，我就领了我的鸡蛋。翻出古老的 MacBook Air M1，充值各种大模型。当然了，这个工具在安全、隐私方面饱受诟病，代码结构也显得有些臃肿，这些是开源项目常见的痛点。但简单地将它归为现象级的昙花一现大概也是不合适的。它代表着一种深刻的范式转变：AI 从散兵游勇，开始变成了策略的执行者，实现了用自然语言主导的 IT 能力的通用编排。这不仅仅是技术升级，更是整个IT生态的重塑。国内多地已针对龙虾驱动的一人公司推出扶持政策，这股热潮的全球爆火，绝非偶然。</p>
<p>接下来我想谈谈龙虾带来的影响，探讨组织如何主动拥抱变革。通过场景重塑、知识积累、基础服务优化和人力规划四个维度，我们将构建一个系统性的转型框架，帮助IT从业者和决策者从“恐慌”转向“机遇”。</p>
<p>在AI时代，躺赢养老已成奢望，成为“AI带路党”才是明智之举。</p>
<h2>龙虾的本质：自然语言主导的通用编排能力</h2>
<p>传统 AIOps 领域，本质上是由软件驱动的。即使近年来AI、LLM（Large Language Models）和Agent技术层出不穷，它们在业务落地时往往扮演中间件角色，被系统调用而非主导流程。这导致了一个顽疾：用户意图与系统执行之间存在层层壁垒，需要专业编程技能或复杂的UI交互来桥接。</p>
<p>龙虾则彻底颠覆了这一模式。它构建了一个以大语言模型为核心的生态，通过技能/工具链、记忆系统和主动编程能力，将现有IT资源（如API、CLI）无缝整合。用户只需用日常语言描述意图，就能实现复杂的IT编排——从Cron定时任务，到网络爬取，再到实时聊天交互，一切皆可“聊天式”完成。这不是简单的“知识库”或“数字分身”升级，而是<strong>通用编排能力</strong>的革命性体现：自然语言成为主导，LLM提供支撑，原子化的IT能力被场景化、个性化地调动。</p>
<p>想象一下理想场景：在精确、合规的条件下，实现“千人千面”的IT支持。产品经理无需编写代码，就能通过聊天工具快速迭代流程；利益相关方能用口语化指令调整资源分配；最终用户则直接表达业务目标，系统自动组合执行。这比任何精美的UI都更具吸引力，因为它降低了门槛，提升了柔性。在AIOps领域，这意味着从“监控-警报-修复”的线性流程，转向“意图表达-智能编排-自适应执行”的动态体系。LLMOps 没说几天，恐怕又要改名了。</p>
<p>这种转变并非空谈。多个国内外企业已开始探索类似框架，证明龙虾不是玩具，而是推动数字化转型的核心引擎。机遇也是挑战：龙虾在小红书上的各种案例，很好的体现了它的能力，以及威胁——对组织的和对人的。如何才能做个龙虾带路党呢？山雨欲来的情况下，如何避免淘汰，分一杯羹？我觉得如下几个方向还是有机可乘的。</p>
<h2>第一层次：场景重塑——AI主导高价值流程</h2>
<p>大中型组织往往充斥着繁杂流程，其中高频、高价值的环节是AI介入的黄金切入点。龙虾式的自然语言编排，能将这些场景从人工依赖转向智能自动化，提升效率的同时注入柔性。我们优先聚焦三个典型场景，每个场景都需结合组织实际，进行顶层设计和试点迭代。</p>
<h3>重审批场景：从刚性流程到柔性编排</h3>
<p>传统IT组织中，资源发放、版本发布等审批流程往往涉及多层人工审核，耗时长、易出错。以资源发放为例：申请者提交表单，审核者逐级把关，最终执行分配。这不仅是瓶颈，还限制了业务的敏捷性。</p>
<p>引入龙虾后，Agent可作为“虚拟员工”取代部分人工环节。通过自然语言指令，如“为项目X分配5个虚拟机，确保合规审计”，系统自动校验权限、调用API执行，并生成审计日志。这不仅加速流程，还提升柔性：用户可实时调整参数，Agent根据记忆系统学习历史模式，避免重复错误。在AIOps视角，这相当于将审批嵌入智能运维闭环，实现“意图即执行”。试点建议：从单一流程入手，逐步扩展到全链条，确保数据隐私合规（如GDPR或国内数据安全法）。</p>
<h3>强依赖老师傅的场景：从经验垄断到知识民主化</h3>
<p>Trouble Shooting和根因分析等领域，常依赖“老师傅”的多年积累。他们如“定海神针”，但也成为单点风险——退休或流动即导致知识断层。</p>
<p>龙虾通过LLM的强大推理能力，大幅削减这种依赖。在知识积累完善的组织中，Agent可整合历史日志、开源技术栈（如Kubernetes日志），用自然语言查询根因，如“分析服务器宕机，排除网络因素”。这比传统工具更智能，能模拟老师傅的“见多识广”。尤其在开放技术重度的环境中，效果显著。这推动知识从个人向组织的转移，促进可持续发展。转型策略：建立“老师傅知识库”，用图谱形式输入LLM，并通过A/B测试验证Agent准确率。</p>
<h3>变化频繁的流程：从静态工具到动态迭代</h3>
<p>数据采集分析、Dashboard呈现、报表上报等场景，变化频繁，传统工具难以跟上节奏。每次迭代需开发或配置，成本高企。</p>
<p>龙虾提供快速迭代能力：用户用聊天描述需求，如“采集上周销售数据，生成交互Dashboard，并上报领导”，Agent自动爬取清洗和分析数据、调用可视化工具执行。这比静态UI更灵活，支持实时调整。AIOps中，这意味着从被动监控转向主动预测分析，提升业务响应速度。实施路径：优先选择非核心流程试点，监控性能瓶颈，确保与现有系统（如Prometheus）无缝对接。</p>
<p>通过这些场景重塑，组织可实现从“AI辅助”到“AI主导”的跃迁，显著提升整体效率。</p>
<h2>第二层次：知识积累——构建AI的“业务大脑”</h2>
<p>大模型的“理解”能力直接依赖于高质量、结构化的知识输入。私有业务知识、组织最佳实践以及合规要求，如果分布零散、质量欠佳或更新滞后，将严重限制AI在复杂场景中的决策准确性和适用性。在龙虾时代，这不仅仅是数据管理的问题，更是组织核心竞争力的基础建设。它决定了AI是否能真正“融入”业务，成为可靠的决策伙伴，而非泛泛的工具。</p>
<p>从战略视角来看，知识积累是AIOps转型的“隐形基石”。传统组织往往将知识视为部门资产，导致孤岛效应；而在AI驱动下，知识需实现民主化、动态化和智能化流动。这要求我们从战略层面规划，建立一个可持续的知识生命周期管理体系，包括采集、清洗、存储、转换和应用五个环节。通过这些，组织能将散乱的经验转化为LLM可高效利用的“燃料”，从而放大AI的通用编排能力，最终实现业务价值的显著增长。</p>
<h3>知识采集与清洗：从零散到系统化</h3>
<p>首先，知识采集需覆盖多源头：内部文档（如流程手册、故障日志）、员工经验分享（如Wiki或内部论坛）、外部最佳实践（如行业标准或开源社区）。传统方法依赖手动录入，效率低下；引入龙虾后，可用Agent自动化采集，例如通过自然语言指令“扫描所有历史故障报告，提取关键模式”，快速聚合数据。</p>
<p>清洗环节至关重要：去除冗余、纠正错误、标准化格式。常见痛点包括数据不一致（如不同部门用词差异）和时效性问题（如过时合规要求）。建议采用LLM辅助清洗工具，如使用提示工程生成“如果X条件，则分类为Y”的规则，确保知识纯净度尽可能高。案例：在金融行业，清洗合规知识可避免AI决策违规，潜在节省大量罚款。</p>
<h3>知识存储与结构化：从静态仓库到动态图谱</h3>
<p>存储不是简单堆积，而是构建可查询的结构。传统数据库不足以应对AI需求；知识图谱和向量数据都是近年来的大热门。例如，将业务流程建模为节点-关系图：节点为实体（如“服务器宕机”），关系为因果（如“导致于网络波动”）。这让LLM能进行图谱推理，提升根因分析准确率。</p>
<p>动态化是关键：知识需实时更新。通过龙虾的记忆系统，设立自动同步机制，如每周扫描变更日志，注入新知识。整体而言，这构建了组织的“集体记忆”，支持跨部门协作，避免知识垄断。</p>
<h3>知识转换与应用：从数据到决策参考</h3>
<p>转换是将知识转化为AI友好的形式：提示词、嵌入向量或微调数据集。例如，将最佳实践编码为“在Y场景下，优先执行Z步骤”的模板提示，输入LLM决策链。这决定了AI对业务的“亲和度”——缺乏者将导致泛化错误。</p>
<p>应用层面，知识积累直接赋能场景重塑：如在Trouble Shooting中，图谱化知识让Agent模拟专家推理。策略：成立跨职能知识团队（包括IT、业务、合规专家），定期审计更新，确保覆盖率尽可能全面。同时，引入反馈循环：用户交互后，自动优化知识库。</p>
<p>整体而言，这不仅是技术工作，更是文化变革：从“知识囤积”转向“共享赋能”，把知识转化为战略资产，推动可持续创新。</p>
<h2>第三层次：AI Ready的基础服务——接口与文档的基石</h2>
<p>龙虾生态高度依赖系统接口的友好性。许多遗留系统缺乏完善的API或CLI支持，这极大限制了AI的操作可能性和编排效率。在AIOps框架下，基础服务优化是桥接现有IT资产与AI能力的“关键一环”。它确保龙虾能无缝“驾驭”资源，实现自然语言主导的场景化支持。</p>
<p>从整体视野分析，这层转型涉及技术债务清理与未来架构设计。传统系统往往以封闭式设计为主，接口碎片化；AI时代要求“开放优先”，将接口视为 AIOps 的抓手。通过系统优化，不仅提升即时兼容性，还为多云、混合环境铺平道路，最终形成一个弹性、可扩展的AI基础设施。接口优化可显著提升自动化水平、降低AI集成成本，并加速新功能上线。</p>
<h3>接口设计与标准化：从封闭到开放</h3>
<p>核心是构建RESTful API、GraphQL或者 IaC 接口，确保原子化、幂等性和安全性。例如，为数据库系统添加API端点，支持自然语言查询如“检索用户数据，过滤活跃状态”。标准化采用OpenAPI类似规范，便于龙虾自动发现和调用。</p>
<p>痛点解决：遗留系统改造可分阶段——先评估高频接口（如资源管理API），后逐步迁移。工具推荐：使用API Gateway（如Kong或AWS API Gateway）统一管理，支持版本控制，避免破坏现有流程。</p>
<h3>CLI工具开发与集成：从命令行到AI桥接</h3>
<p>CLI（Command Line Interface）是龙虾偏好的轻量接口，尤其适合脚本化任务。许多系统缺失CLI，导致AI无法直接操作。开发策略：为关键服务创建CLI wrapper，例如Kubernetes的kubectl风格工具，支持参数化执行。</p>
<p>集成层面，确保CLI与API互补：如通过龙虾指令“运行CLI命令X，参数Y”，实现自动化。安全考虑：嵌入OAuth或API Key认证，防止未授权访问。</p>
<h3>文档完善与自动化：从手动到智能维护</h3>
<p>文档是接口的“使用手册”，直接影响AI利用率。传统文档静态、易过时；优化后，采用自动化生成工具（如Sphinx或Postman），实时同步代码变更。</p>
<p>智能维护：用LLM生成文档摘要，或通过龙虾查询“解释API Z的功能”。全局策略：建立接口治理委员会，定期审计，确保覆盖率尽可能完整。</p>
<p>实施路径：从核心系统（如ERP或云平台）入手，采用微服务架构（如Kubernetes），优先高价值接口。风险管理：平衡改造成本与收益，通过ROI模型优先级排序。整体而言，这层优化不仅是技术升级，更是生态构建：AI Ready的基础服务将组织定位为“智能基础设施提供者”，在数字化浪潮中占据先机。</p>
<h2>第四层次：人力规划——转型中的人文关怀与战略布局</h2>
<p>效率提升和技术栈刷新，必将重塑岗位结构。这是最“伤人”却不可回避的环节：在龙虾驱动下，传统IT角色面临自动化取代风险，但也孕育新机遇。从战略视角看，人力规划不是成本切割，而是人才投资与组织韧性建设。它确保转型平稳，避免人才流失，同时培养AI时代的核心竞争力——“人机协同”能力。</p>
<h3>岗位摸底与评估：从现状到未来需求</h3>
<p>首先，进行全面摸底：评估现有岗位的AI影响度。例如，运维工程师中，重复任务占比高者（如手动监控）易被Agent取代；创意性角色（如架构设计）则需AI辅助。</p>
<p>评估工具：引入效能指标，如“任务自动化潜力指数”（基于时间消耗和重复率）。通过问卷和绩效数据，分类岗位：淘汰型、转型型、新兴型。新兴岗位包括“AI编排师”（专注自然语言流程设计）和“伦理监理”（确保AI合规）。</p>
<h3>培训与技能升级：从被动学习到主动赋能</h3>
<p>培训是核心：设计分层路径。入门级：基础LLM使用，如龙虾操作workshop；高级级：提示工程和Agent开发课程。</p>
<p>个性化：基于摸底结果，定制学习计划。例如，对“老师傅”提供“知识传承”模块，帮助他们将经验转化为知识库。人文关怀：提供弹性学习时间，避免工作负担。</p>
<h3>持续监测与文化变革：从短期调整到长期韧性</h3>
<p>整体而言，人力规划是转型的“软实力”。忽略者将面临人才荒；重视者可构建“学习型组织”。最终，人不是被取代，而是被解放——专注于高价值创新。</p>
<h2>不变的只有变化</h2>
<p>“龙虾恐慌”并非末日，也不是黎明。这种新生态中，自然语言逐步成为人机界面。组织需系统布局：从场景切入，积累知识，优化基础，规划人力，逐步转型。</p>
]]></content:encoded></item><item><title><![CDATA[再见 2025]]></title><description><![CDATA[我猜不少人以为这个号废了吧？并没有，只是今年变化有点大，一直有种抄起键盘，无从说起的感觉，所以一直偷懒到今天，2025 的最后一天。
今年是我的第四个本命年，去年末一期播客里，大内说本命年不是灾年，是变化年，有危也有机。可是讲真啊，只看到危，没看到机。
各种因缘际会，从鹅厂跳槽到前东家，已经接近四年，第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫，后两年基本都是些鸡零狗碎的东西了，用老东家的术语说是——偏离主航道，可谓是前景暗淡了。
一旦确定要滚蛋，反倒心思轻松起来，每天骑着我的小红车...]]></description><link>https://blog.fleeto.us/2025</link><guid isPermaLink="true">https://blog.fleeto.us/2025</guid><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Mon, 05 Jan 2026 01:43:42 GMT</pubDate><content:encoded><![CDATA[<p>我猜不少人以为这个号废了吧？并没有，只是今年变化有点大，一直有种抄起键盘，无从说起的感觉，所以一直偷懒到今天，2025 的最后一天。</p>
<p>今年是我的第四个本命年，去年末一期播客里，大内说本命年不是灾年，是变化年，有危也有机。可是讲真啊，只看到危，没看到机。</p>
<p>各种因缘际会，从鹅厂跳槽到前东家，已经接近四年，第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫，后两年基本都是些鸡零狗碎的东西了，用老东家的术语说是——偏离主航道，可谓是前景暗淡了。</p>
<p>一旦确定要滚蛋，反倒心思轻松起来，每天骑着我的小红车上班下班。偶尔跟同事跑跑前方，见见客户。在研发岗位坐久了，到一线转转还是蛮有新鲜感的。社区里，感觉云原生的风头和我一样——过气了，然而拜访客户时才发现，在很多产业应用场景中，云原生之路还只是刚刚开始，结合几年沉淀下来的什么 IaC、平台工程等等杂七杂八的玩意儿，坐下来谈起各种奇怪的应用场景，倒也算是游刃有余，感觉我还能救啊？</p>
<p>然而这奔五的年纪，简历已经少有人会问津了，四处打听了一下，发现迟来了十几年的中年危机还是来了,工作不太好找，颇焦虑了几天.然而既然罐子破了，摔之前日子还得过，每天散散步，偶尔喝点小酒，一边催着装修进度，一边盘算着，积蓄加上 N + 1 能养娃多久，进入了一种假退休状态。一边瞎胡混着，一边鼓捣着热得不成样子的 AI，勉强维持着运动习惯，偶尔跑去心声发个小作文，也算维持心态了。</p>
<p>瞎胡混的日子里，新老同事、新老朋友们出了不少力气，帮忙寻找新的机会，终于现东家抛出了橄榄枝。线上面试之后，回到了阔别许久的帝都，跟新老板愉快地面谈了个把小时，心里安定不少，跟喝酒 SIG 的朋友们进行了愉快的酒量切磋，作为该小组最老一员，酒量还跟得上，老怀大慰。</p>
<p>返回广东，跟新东家 HR 拉扯待遇的间隙，蹭了张 KubeCon 门票，借着由头跑去香港散心，跟旭东、花肉等一众老友吃吃喝喝聊聊天，心里平静了不少。返回东莞的路上，跟招聘妹子通了个电话——不谈了，就照这个数字走吧，七月入职。跟前同事们大醉，笑别菊厂。</p>
<p>新工作变化还蛮大——既不做云原生、也不是架构师了，对了，我现在是人人都能做的产品经理了。打开办公系统，看到曾经熟悉的 CWT、Workday，虽然知道又要粘发票了，反倒感觉有点亲切是怎么回事。一如既往的还是要出差，不过好在目的地不止有无聊的杭州了，在北京先后见到了很多老同事老朋友，又在开发团队所在地转了一圈，跟新同事们进行了亲切友好的桌上交流。</p>
<p>一眨眼，快半年了，新的角色缓慢的适应之中，逐步回到了产品的正路上。四五十岁，正是闯的年纪，娃还小，还得拼呐。</p>
]]></content:encoded></item><item><title><![CDATA[辅助编程？dora 说：我知道你很急可是请你别急]]></title><description><![CDATA[从 OpenGPT 把大模型的火烧旺了之后，这三年来，相信很多组织或摩拳擦掌、或躬身入局，希望借助聪明能干的大模型，或想偿还技术宅，或想降本增效，或想弯道超车。一时间，沉寂许久的 AIxx 又活过来了，LLM Ops、Vibe Coding、中医大模型、GPT 算命等等，全都老树发新芽，焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发，产生了什么触动，应该如何拥抱呢？
DORA 的年度报告中给出了很有意思的结论——强者恒强。
执行摘要部分总结了几个有趣的点：

问题...]]></description><link>https://blog.fleeto.us/dora</link><guid isPermaLink="true">https://blog.fleeto.us/dora</guid><category><![CDATA[vibe coding]]></category><category><![CDATA[AI]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Mon, 06 Oct 2025 12:39:25 GMT</pubDate><content:encoded><![CDATA[<p>从 OpenGPT 把大模型的火烧旺了之后，这三年来，相信很多组织或摩拳擦掌、或躬身入局，希望借助聪明能干的大模型，或想偿还技术宅，或想降本增效，或想弯道超车。一时间，沉寂许久的 AIxx 又活过来了，LLM Ops、Vibe Coding、中医大模型、GPT 算命等等，全都老树发新芽，焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发，产生了什么触动，应该如何拥抱呢？</p>
<p>DORA 的年度报告中给出了很有意思的结论——强者恒强。</p>
<p>执行摘要部分总结了几个有趣的点：</p>
<ol>
<li><p>问题从<code>是否采用</code>转变为<code>如何采用</code></p>
</li>
<li><p>AI 带来的局部优势，有可能被组织的低下能力完全化解</p>
</li>
<li><p>平台工程和小步快跑的架构方式，有利于 AI 辅助编程的变现。</p>
</li>
</ol>
<p>支撑如上结论的论据，来自于后续内容对组织画像、价值链、度量系统、成员感知等方面的调查论据。</p>
<p>简单说来，要最大化 Vibe Coding 的收益，组织和业务应该具有如下特征：</p>
<ol>
<li><p>微服务/云原生架构</p>
</li>
<li><p>高质量的、AI 可用的数据生态</p>
</li>
<li><p>以用户为中心</p>
</li>
<li><p>完善的平台工程体系</p>
</li>
<li><p>围绕价值流进行 AI 建设</p>
</li>
</ol>
<h2 id="heading-5lid56en5zui6zif">七种团队</h2>
<p>报告中对团队形态做了一个侧写，总结出了 7 类团队。</p>
<ol>
<li><p>基础性挑战（Foundational challenges）</p>
<p> 这些团队被困在“生存模式”中，在流程、环境和成果上存在根本性缺陷，因而面临重大挑战。</p>
</li>
<li><p>遗留瓶颈（The legacy bottleneck）</p>
<p> 处于这一类群的团队始终处于被动应对状态，不稳定的系统支配着他们的工作，并不断削弱团队士气。</p>
</li>
<li><p>流程受限（Constrained by process）</p>
<p> 这些团队就像在“跑步机”上工作。尽管他们所依赖的系统相对稳定，但低效的流程消耗了大量精力，最终导致高倦怠感与低影响力。</p>
</li>
<li><p>高影响，低节奏（High impact, low cadence）</p>
<p> 这些团队能够产出高影响力的工作，其成果体现在突出的产品效能和较高的个人效能。然而，他们的交付模式节奏较低，表现为软件交付吞吐量不足且不稳定性较高。</p>
</li>
<li><p>稳定且有条理（Stable and methodical）</p>
<p> 这些团队就像软件世界里的稳健工匠，以审慎且可持续的节奏交付高质量、有价值的工作。</p>
</li>
<li><p>务实执行者（Pragmatic performers）</p>
<p> 这些团队能够持续以令人瞩目的速度和稳定性交付工作，即便其工作环境尚未达到最佳投入状态。</p>
</li>
<li><p>和谐高成就者（Harmonious high-achievers）</p>
<p> 这正是卓越的典范——一个良性循环：稳定、低摩擦的环境使团队能够持续交付高质量工作，同时避免倦怠。</p>
</li>
</ol>
<p>上述团队类型的前面四种，都不利于 AI 辅助编程的采用，第一种团队采用 AI 辅助编程后，甚至可能出现团队、产品效能的倒退。</p>
<h2 id="heading-ai">采用 AI 所需的核心能力</h2>
<p>在这些候选能力中，7 个 能力脱颖而出。当团队将这些能力与 AI 采用相结合时，AI 在重要结果上的积极影响会被进一步放大。</p>
<p>这七大能力构成了我们新模型的核心：</p>
<ol>
<li><p>清晰且有效传达的 AI 立场（Clear and communicated AI stance）</p>
</li>
<li><p>小批量工作方式（Working in small batches）</p>
</li>
<li><p>可供 AI 访问的内部数据（AI-accessible internal data）</p>
</li>
<li><p>高质量的内部平台（Quality internal platforms）</p>
</li>
<li><p>健康的数据生态系统（Healthy data ecosystems）</p>
</li>
<li><p>以用户为中心（User-centric focus）</p>
</li>
<li><p>健全的版本控制实践（Strong version control practices）</p>
</li>
</ol>
<h2 id="heading-5lu35yc85rwb">价值流</h2>
<p>DORA 提倡从价值流的角度来判断 AI 切入的环节，这里举了一个例子：</p>
<blockquote>
<p>例如，通过映射，团队可能会发现代码审查是一个显著的瓶颈。有了这一洞察，他们就可以决定将 AI 应用于改进代码审查流程，而不是仅仅用 AI 生成更多代码，从而加剧瓶颈。</p>
</blockquote>
<p>调研数据则表明：</p>
<ul>
<li><p><strong>VSM 推动团队能效</strong>：持续审视和改进价值流的团队报告的绩效显著更高。</p>
</li>
<li><p><strong>VSM 带来更有价值的工作</strong>：这些团队在组织及其客户真正关心的工作上投入的时间明显更多。</p>
</li>
<li><p><strong>VSM 改善产品能效</strong>：最终，对价值流的关注转化为更好的产品成果，而这可以说是最重要的结果。</p>
</li>
</ul>
<h2 id="heading-5oc757ut">总结</h2>
<p>首先这份报告我认为针对的是“组织”而非现下流行的一人公司，所以其视角略显<code>传统</code>。在我看来似乎就没什么新东西。。</p>
<p>总的说来，AI 辅助编程的采用，要想获得回报，必须按照价值流的分析，选择性的投入，其目标在于削减瓶颈，促进整个生命周期的有效流动；利用平台工程的加持、提高流转效率、规范行为；使用有效的指标体系，全程度量采用效果并随时反馈。架构方面，采用低耦合的可独立快速更新的架构来提高发布韧性等等。。</p>
<p>所以看到最后我脑子里就一句话——<strong>努力一点，别拖 AI 后腿。。</strong></p>
]]></content:encoded></item><item><title><![CDATA[[译]dora：ai 辅助软件开发状态报告]]></title><description><![CDATA[执行摘要
在 2025 年，科技领导者面临的核心问题已不再是“是否要采用 AI”，而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实：AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势，也会凸显组织的缺陷。
关键结论：AI 是放大器
AI 投资的最大回报并非来自工具本身，而是来自组织底层系统的战略性建设：

高质量的内部平台

清晰的工作流

团队的协同能力


缺少这些基础，AI ...]]></description><link>https://blog.fleeto.us/doraai</link><guid isPermaLink="true">https://blog.fleeto.us/doraai</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Thu, 02 Oct 2025 18:41:13 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-5omn6kgm5pgy6kab">执行摘要</h2>
<p>在 2025 年，科技领导者面临的核心问题已不再是“是否要采用 AI”，而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实：AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势，也会凸显组织的缺陷。</p>
<h3 id="heading-ai">关键结论：AI 是放大器</h3>
<p>AI 投资的最大回报并非来自工具本身，而是来自组织底层系统的战略性建设：</p>
<ul>
<li><p>高质量的内部平台</p>
</li>
<li><p>清晰的工作流</p>
</li>
<li><p>团队的协同能力</p>
</li>
</ul>
<p>缺少这些基础，AI 只会带来局部的生产力提升，但接踵而来的混乱会吞噬这些微弱优势。</p>
<h3 id="heading-5li76kab5yr546w">主要发现</h3>
<p>本报告基于 2025 年 6 月 13 日至 7 月 21 日期间开展的定性研究与全球调研，包含了关于AI 辅助软件开发现状的若干关键发现，其中包括：</p>
<ul>
<li><p>AI 采用已几乎普及：90% 的受访者在工作中使用 AI，超过 80% 的人认为它提高了生产力。但仍有 30% 的人表示对 AI 生成的代码几乎没有信任，这表明“验证与批判性能力”仍然关键。</p>
</li>
<li><p>AI 落地需要进行系统化建设：新的 DORA AI 能力模型识别了七个基础实践（例如明确的 AI 政策、健康的数据生态、用户中心化），它们能够放大 AI 对组织绩效的积极影响。</p>
</li>
<li><p>与去年相比，采用 AI 技术的确提升了软件交付的吞吐量，但同时也降低了交付的稳定性。这意味着团队正在加速，但底层系统尚未能应对这样的交付效率。</p>
</li>
<li><p>研究识别了七种不同的团队类型，从“和谐的高成就者”到被“遗留系统瓶颈”困住的团队，为定向改进提供了新框架。</p>
</li>
<li><p>价值流管理（VSM）：通过可视化、分析和改进从创意到客户的工作流，VSM 成为 AI 的倍增器，确保局部的效率提升，能够真正地增进产品质量和团队效能。</p>
</li>
<li><p>平台工程成为基础：90% 的组织已采用平台工程，高质量的平台成为 AI 落地的必由之路。</p>
</li>
</ul>
<h3 id="heading-6z2i5zcr5oqa5pyv6akg5a86icf55qe5yig5p6q5lio5bu66k6u">面向技术领导者的分析与建议</h3>
<h4 id="heading-ai-1">成功采用 AI，本质上是一个系统性问题，而非单纯的工具问题</h4>
<p>我们全新的 DORA AI 能力模型认为，AI 的价值并非来自于工具本身，而是依赖于其所处的技术与文化环境。我们识别出七项基础能力（包括清晰的 AI 政策、健康的数据生态、优质的内部平台，以及以用户为中心的关注点）已被证明能够显著放大 AI 对组织效能的正向作用。</p>
<p>将 AI 采用视为一次组织级的转型。对基础系统的投入将会产生更大回报，这些系统能够放大 AI 的效益：你的内部平台、你的数据生态，以及团队的核心工程能力。AI 是否能真正地提升组织效能，很大程度上取决于这些基础能力。</p>
<h4 id="heading-ai-2">广泛采用 AI，但保持理性怀疑</h4>
<p>尽管大多数开发者使用 AI 来提升生产力，但他们对其输出质量仍保持健康的怀疑态度。这种“信任但验证”的做法，正是成熟采用的标志。</p>
<p>讨论的重点必须从“是否采用”转向“如何高效使用”。培训计划应聚焦于帮助团队学会如何批判性地引导、评估和验证 AI 生成的成果，而不仅仅是简单地鼓励使用。</p>
<h4 id="heading-5lid56en5zui6zif">七种团队</h4>
<p>仅依靠简单指标远远不够。我们识别出了七种团队，每一种都在效能、稳定性与幸福感上呈现出独特的组合。这个模型为理解团队所面临的具体挑战、及制定有针对性的改进路径，提供了更细致的视角。</p>
<p>利用这些画像，可以对团队健康状况进行诊断，而不仅仅局限于软件交付性能指标。你可以识别出一个团队是否高效但高压，或者 稳定被拖慢，并据此采取正确的干预措施。</p>
<h4 id="heading-ai-3">高质量的平台释放 AI 的价值</h4>
<p>平台工程如今已接近普及（采用率达 90%）。我们的数据表明，高质量的内部平台与组织释放 AI 价值的能力之间存在直接相关性。那些将平台视为内部产品、以提升开发者体验为目标的组织，能够获得显著更高的回报。</p>
<p>因此，应优先考虑并投入资金支持平台工程建设。糟糕的开发者体验和割裂的工具链，可能会严重削弱你的 AI 战略成效。</p>
<h4 id="heading-ai-4">系统化视角引导 AI 潜力</h4>
<p>今年的研究证实，价值流管理（VSM）能够改善聚焦情况，推动更高水平的团队与产品效能。</p>
<p>VSM 作为 AI 投资的倍增器，通过在系统层面的全局视角，确保在正确的方向上应用 AI。这样，局部的生产力提升就能转化为显著的组织优势，而不是仅仅制造更多后续的混乱。</p>
<h2 id="heading-5ymn6kia">前言</h2>
<p>许多人认为，科学的目标是用最少的原理解释尽可能多的现象，既能印证人们的直觉，又能揭示出令人惊讶的新洞见。DORA 十多年来一直在践行这一目标。</p>
<p>今年的研究内容让我大受鼓舞，它帮助我们更好地理解使用 AI 改进软件的方法。</p>
<blockquote>
<p>Gene Kim 研究者、Vibe Coder、《Vibe Coding》《凤凰项目》《DevOps 手册》《Accelerate》共同作者</p>
</blockquote>
<p>2013 年，我有幸与 Nicole Forsgren 博士和 Jez Humble 一起开展了 《DevOps 状态》研究。这项工作奠定了 DevOps Research and Assessment（DORA）的基础，并在 2018 年成为 Google Cloud 的一部分。</p>
<p>对于许多人来说，很难想象仅仅十多年前，软件部署还是危险且复杂的操作。那时的部署需要精心的计划与审批，通常包含数百个高风险、易出错的手动步骤。部署常会造成严重的混乱与中断，所以我们每年只敢做一次软件部署。</p>
<p>到了 2013 年，State of DevOps 的研究表明，每天进行多次部署并不是天方夜谭；相反，保持可靠性似乎需要小规模高频率的部署活动。更令人振奋的是：你不必身处初创公司或硅谷才能做到这一点。</p>
<p>你只需要：</p>
<ul>
<li><p>优秀的技术实践（如自动化构建、自动化测试、自动化部署、主动的生产监测）；</p>
</li>
<li><p>能支持独立行动的架构（团队可以独立开发、测试和部署，而几乎无需协调成本）；</p>
</li>
<li><p>以及持续学习的文化。</p>
</li>
</ul>
<p>如今，12 年过去了，作为一个技术社区，我们再次迎来了一项非凡的新技术——AI。正如十年前一样，我们又在追问：这种新技术是否真的能提升软件交付和组织能效？</p>
<p>2024 年，DORA 发布了一份里程碑式的报告，系统性地衡量了 AI 对软件交付能效的影响，这是同类研究中最早的一批。结果令一些人感到震惊：数据表明，AI 使用得越多，软件交付的稳定性和吞吐量反而越差——而这正是过去十年来软件工程专业人士持续努力改善的关键属性。</p>
<p>确实，我亲眼见过、也亲身经历过使用 AI 所带来的问题：从测试用例被悄悄删除、功能受损，到生产数据被误删。但与此同时，我也看到过 AI 在某些场景中带来巨大的改进效果。</p>
<p>因此，我开始把去年的这份报告及其结论称为 “DORA 2024 异常”——这是一个令人兴奋的谜题，亟待被解开。</p>
<p>过去一年，我与 Steve Yegge 合作。他因在 Amazon 和 Google 的 20 年经历而闻名。他回顾了贝佐斯的一份内部备忘录如何推动 Amazon 从单体软件转型为成千上万的微服务。这一转型帮助 Amazon 在 2015 年实现了每日 136,000 次部署的壮举，这一事实长期以来都在激励着 DORA 的研究。</p>
<p>我和 Steve 合著了即将出版的《Vibe Coding》一书，我们将“Vibe Coding” 定义为：任何不需要亲手逐字敲代码的编程形式。相反，代码通过与 AI 的迭代对话而逐渐成形。这种方式改变了我们的生活：它让我们能够更快地构建想要的东西，追求更雄心勃勃的项目，更加自主地工作，获得更多乐趣，并探索一个更为广阔的可能性空间（FAAFO!）。</p>
<p>当然，Steve 和我也亲眼见过 Vibe Coding 使用不当的情况：测试被删除、服务中断，甚至整个代码库被误删。但我们最终得出的结论是：造成这些问题的根本原因，并不是 AI 本身，而是我们数十年来依赖的工程直觉已经不足以应付新的工作模式了。</p>
<p>假设你人生最快的移动方式，就是以每小时 4 英里的速度步行。这种情况下，如果没有合适的学习和训练，去开一辆时速 50 英里的汽车，交通事故在所难免。</p>
<p>我们因此得出结论：当 AI 显著加速软件开发时，我们的控制系统——也就是开发者自身——也必须随之加速。换句话说，十余年的 DORA 研究很可能已经证明：整个软件开发行业的实践必须随之演进。</p>
<p>我们需要更快的反馈回路——比以往任何时候都更快，以适应 AI 加速的代码生成节奏。</p>
<p>我们需要支持独立行动的软件架构——比以往任何时候都更需要具备独立开发、测试和部署软件的能力。</p>
<p>我们需要学习型的氛围，特别是在 AI 具备高度不确定性且发展极为迅速的背景下。</p>
<p>在《Vibe Coding》一书中，Steve 和我收录了一系列案例研究，它们揭示了相关的原则和实践——以及为什么这些在 AI 时代如此至关重要。</p>
<h3 id="heading-5br6ycf5yn6aai5b6q546v5lio6l2v5lu25p625p6e">快速反馈循环与软件架构</h3>
<p>Adidas 全球副总裁（数字与电商技术）Fernando Cornago 负责管理近千名开发人员。在他们的生成式 AI 试点中发现：</p>
<p>在松耦合架构下工作、并拥有快速反馈循环的团队，生产力提升了 20% 到 30%（通过提交次数、PR 数量、整体功能交付速度等指标衡量）；</p>
<p>他们的快乐时间（Happy Time）（专注编程、减少行政性负担的时间）增加了 50%；</p>
<p>相反，那些因与 ERP 紧密耦合而反馈循环缓慢的团队，几乎没有从 AI 中获益。</p>
<h3 id="heading-5a2m5lmg5pah5yyw">学习文化</h3>
<p>另一个案例来自 <a target="_blank" href="http://Booking.com">Booking.com</a> 开发者体验团队的产品经理 Bruno Passos。<a target="_blank" href="http://Booking.com">Booking.com</a> 拥有超过 3,000 名开发者。在他们的生成式 AI 创新实验中发现，开发者对“氛围编程”和代码助手的使用并不均衡——团队很快意识到缺失的关键因素是：培训。</p>
<p>当开发者学会如何为代码助手提供更明确的指令与更有效的上下文时，他们发现：合并请求增加了 30%，工作满意度也显著提升。</p>
<p>这两个案例表明了一个令人振奋的可能性：</p>
<ul>
<li><p>AI 会放大工程实践的优劣。</p>
</li>
<li><p>拥有优秀工程实践的个人、团队及跨团队组织，将从 AI 中获得非凡收益；</p>
</li>
<li><p>缺乏这些实践的人，则可能遭遇严重问题——这也正是 “DORA 2024 异常” 所暗示的。</p>
</li>
</ul>
<p>我非常感激并荣幸能与 Google 的 DORA 团队及众多专家研究者合作，他们的工作与成就让我深感敬佩。</p>
<p>最令我振奋的是 2025 年研究的规模：共有近 5,000 名参与者，这使我们能够开展一项实践性调查，并有望产生如同十年前那样的“灵光乍现”时刻。</p>
<p>我坚信，在未来数月中，我们会看到类似的重大突破。部分研究成果已体现在本报告中，但还有更多引人期待的洞见正在浮现，我也期待在未来的数月和数年里与大家分享。</p>
<p>我向整个 DORA 团队和所有贡献者致以衷心感谢，是他们让这项开创性的研究成为可能。</p>
<h2 id="heading-55cg6kej5l2g55qe6l2v5lu25lqk5luy57up5pwi77ya5lid57g75zui6zif55s75yop">理解你的软件交付绩效：七类团队画像</h2>
<h3 id="heading-6l2v5lu25lqk5luy5pwi6io9">软件交付效能</h3>
<p>新软件的面世是值得庆祝的一件事，因为软件的的真正价值只能在被使用的情况下才能提现出来。软件的用户可能是客户、合作伙伴、同事、陌生人，甚至其他技术系统。</p>
<p>这也是我们开始理解软件在生产环境中表现如何、以及它是否满足用户需求的关键时刻。我们可以提前做很多准备，以增强软件按预期运行的信心。但只有在发布的那一刻，理论才会被证实，或者证伪。</p>
<p>发布新软件不仅仅是发布一个新的应用或服务。一旦应用发布，用户的反馈会推动或者强迫你进行改进。</p>
<p>当然，修改应用有很多理由，例如修复安全漏洞、提升运行性能、降低运营/运维成本，或者降低碳排放。这些考量的核心都是帮助用户，并促进应用的长期成功。</p>
<p>为了团队的长期健康，我们还必须考虑负责构建、部署、运维和支持等因素。我们需要具备合适的能力与条件，确保这些团队能够以可持续的方式持续成功。</p>
<p>这些考虑，加上企业对更快交付和更大成功的要求，使得 DORA 将软件交付效能作为研究的核心切入点。</p>
<h3 id="heading-6l2v5lu25lqk5luy5pwi6io955qe5lik5asn57u05bqm">软件交付效能的两大维度</h3>
<p>DORA 的软件交付效能指标，从整体流程的高层视角进行审视，并聚焦于两个关键因素：吞吐量与不稳定性。</p>
<ol>
<li><p>吞吐量（Throughput）</p>
<p> 衡量在一段时间内，系统能有多少变更流入生产环境。吞吐量越高，说明系统能更快地交付更多变更。DORA 从三个角度来判断软件交付的吞吐量：</p>
<ul>
<li><p>变更交付周期：从变更提交到版本控制系统，到部署到生产的时间。</p>
</li>
<li><p>部署频率：在特定时间段的部署次数，或两次部署的间隔时间。</p>
</li>
<li><p>部署失败的恢复速度：从部署失败要求立即干预，，到完成恢复所需的时间。</p>
</li>
</ul>
</li>
<li><p>不稳定性（Instability）</p>
<p> 衡量软件部署的质量与可靠性。部署顺利时，团队能有信心将更多变更推入生产，用户也更少遇到因部署产生的问题。</p>
<ul>
<li><p>变更失败率（Change fail rate）<br />  部署后需要立即干预的比例，通常会导致回滚或快速修复。</p>
</li>
<li><p>返工率（Rework rate）<br />  因生产环境事件而被迫进行的非计划性部署比例。</p>
</li>
</ul>
</li>
</ol>
<p>综合来看，这两个软件交付效能因素能够为团队提供其交付能力的高层次认知。对其进行持续度量，可以洞察软件交付绩效的变化趋势。无论应用或服务所依赖的技术栈、部署流程的复杂性，还是终端用户的差异，这些因素都可以作为衡量标准。</p>
<h3 id="heading-6laf6lak5oyh5qch">超越指标</h3>
<p>虽然这五个指标能提供重要的快照，但它们最终只是结果。它们能告诉你“发生了什么”，却不能告诉你“为什么”。</p>
<p>例如低部署频率可能源于技术债务、官僚流程，或者团队倦怠；单纯的指标无法区分这些成因。</p>
<p>为了将效能数据与其背后的人类体验联系起来，我们进行了聚类分析。这种方法超越了孤立的数字，揭示出七类常见的团队画像，每一种都更深入地展现了效能、幸福感与环境之间的相互作用。</p>
<h3 id="heading-5a75om5ywx5ocn">寻找共性</h3>
<p>我们的聚类分析揭示了驱动软件交付效能的人为因素和系统性因素，并识别其中的共性模式。主要考虑了如下因素</p>
<ul>
<li><p>团队效能：团队协作与效能的感知水平</p>
</li>
<li><p>产品效能：产品/服务在帮助用户完成任务、安全性、性能（如延迟）等方面的成功度</p>
</li>
<li><p>有价值的工作：个体自我评估的、认为有价值且有意义的工作时间比例</p>
</li>
<li><p>摩擦（Friction）：工作中被阻碍的程度，越低越好</p>
</li>
<li><p>倦怠（Burnout）：因工作而产生的疲惫与愤世嫉俗感，越低越好</p>
</li>
<li><p>软件交付不稳定性：交付过程的质量与可靠性</p>
</li>
<li><p>个人效能：个人对自身效能与成就感的自评</p>
</li>
<li><p>软件交付吞吐量：交付的速度与效率</p>
</li>
</ul>
<p>组织、团队与个人通常的目标是：</p>
<ul>
<li><p>提升团队绩效、产品绩效、吞吐量、个体效能和有价值的工作；</p>
</li>
<li><p>降低不稳定性、摩擦与倦怠。</p>
</li>
</ul>
<p>综上，我们总结了七种截然不同的团队原型，范围从在健康、可持续环境中表现卓越的 “和谐高成就者”，到受制于技术债务的 “遗留瓶颈型”，以及陷入低效流程的 “流程受限型”。</p>
<ol>
<li><p>基础性挑战（Foundational challenges）</p>
<p> 这些团队被困在“生存模式”中，在流程、环境和成果上存在根本性缺陷，因而面临重大挑战。</p>
<ul>
<li><p>约 10% 的受访者属于此类。</p>
</li>
<li><p>效能指标：与团队产出、产品交付及价值创造相关的关键效能指标持续处于低水平。</p>
</li>
<li><p>团队幸福感：数据显示，成员普遍报告存在较高程度的倦怠感，并伴随显著的摩擦与阻碍。</p>
</li>
<li><p>系统稳定性：在软件及运行环境的稳定性方面存在显著挑战。</p>
</li>
</ul>
</li>
<li><p>遗留瓶颈（The legacy bottleneck）</p>
<p> 处于这一类群的团队始终处于被动应对状态，不稳定的系统支配着他们的工作，并不断削弱团队士气。</p>
<ul>
<li><p>约 11% 的受访者属于此类。</p>
</li>
<li><p>效能指标：产品效能的关键指标偏低。虽然团队能够定期交付更新，但持续存在的质量问题削弱了实际创造的价值。</p>
</li>
<li><p>团队幸福感：数据表明工作环境要求苛刻。团队成员反馈存在较高程度的摩擦与倦怠感。</p>
</li>
<li><p>系统稳定性：软件及其运行环境的稳定性面临重大且频繁的挑战，导致大量非计划性、被动应对的工作。</p>
</li>
</ul>
</li>
<li><p>流程受限（Constrained by process）</p>
<p> 这些团队就像在“跑步机”上工作。尽管他们所依赖的系统相对稳定，但低效的流程消耗了大量精力，最终导致高倦怠感与低影响力。</p>
<p> - 约 17% 的受访者属于此类。<br /> - 效能指标：关键效能指标显示效率较低，所创造的客户价值或业务价值十分有限。 - 团队幸福感：数据显示，团队成员普遍反映存在较高程度的倦怠与摩擦。这表明当前的工作流程和过程正在制造一种充满挑战且不可持续的工作环境。 - 系统稳定性：团队的软件和运行环境保持稳定且可靠。这表明技术层面的不稳定性并非导致效能与幸福感挑战的主要原因。</p>
</li>
<li><p>高影响，低节奏（High impact, low cadence）</p>
<p> 这些团队能够产出高影响力的工作，其成果体现在突出的产品效能和较高的个人效能。然而，他们的交付模式节奏较低，表现为软件交付吞吐量不足且不稳定性较高。</p>
<ul>
<li><p>约 7% 的受访者属于此类。</p>
</li>
<li><p>效能指标：团队持续保持顶尖水平的生产力，无论是整体效率还是产品效能指标都表现优异。</p>
</li>
<li><p>团队幸福感：数据表明团队所处环境摩擦度低，这意味着团队流程高效且协作顺畅。</p>
</li>
<li><p>系统稳定性：运行环境表现出高度的不稳定性。这种波动性对服务可靠性和长期可持续性构成了重大风险。</p>
</li>
</ul>
</li>
<li><p>稳定且有条理（Stable and methodical）</p>
<p> 这些团队就像软件世界里的稳健工匠，以审慎且可持续的节奏交付高质量、有价值的工作。</p>
<ul>
<li><p>约 15% 的受访者属于此类。</p>
</li>
<li><p>效能指标：在产品质量和价值创造方面的关键效能指标持续保持积极表现。然而，团队的软件交付吞吐量处于较低分位，显示其工作节奏更加审慎从容。</p>
</li>
<li><p>团队幸福感：数据显示，成员报告的倦怠感与摩擦程度较低，这表明团队环境健康且具备可持续性。</p>
</li>
<li><p>系统稳定性：团队的软件与运行环境具有高度的稳定性与可靠性。</p>
</li>
</ul>
</li>
<li><p>务实执行者（Pragmatic performers）</p>
<p> 这些团队能够持续以令人瞩目的速度和稳定性交付工作，即便其工作环境尚未达到最佳投入状态。</p>
<ul>
<li><p>约 20% 的受访者属于此类。</p>
</li>
<li><p>效能指标：软件交付的关键效能指标表现强劲，吞吐量高于平均水平且不稳定性低。团队保持着稳定的节奏，持续输出有价值的成果，并能可靠地满足预期。</p>
</li>
<li><p>团队幸福感：这一类群与绝对顶尖团队的差异主要体现在团队幸福感上。数据显示，其成员报告的倦怠感与摩擦程度处于平均水平。这表明其工作环境虽具备功能性和可持续性，但可能缺乏强有力的投入驱动因素。</p>
</li>
<li><p>系统稳定性：团队的软件与运行环境稳定且可靠，为其实现高效能提供了坚实的基础。</p>
</li>
</ul>
</li>
<li><p>和谐高成就者（Harmonious high-achievers）</p>
<p> 这正是卓越的典范——一个良性循环：稳定、低摩擦的环境使团队能够持续交付高质量工作，同时避免倦怠。</p>
<ul>
<li><p>约 20% 的受访者属于此类。</p>
</li>
<li><p>效能指标：团队在多个方面均展现出积极的指标表现，包括团队幸福感、产品成果以及软件交付。</p>
</li>
<li><p>团队幸福感：工作环境呈现出低倦怠感与低摩擦度的特征。</p>
</li>
<li><p>系统稳定性：团队运行在稳定的技术基础之上，这一基础同时支撑了其工作的速度与质量。</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-6l2v5lu25lqk5luy5pwi6io95yig57qn">软件交付效能分级</h3>
<p>图 10 为 DORA 研究的一条核心原则提供了有力证据：“速度与稳定性的权衡”是一种误区。最佳表现的团队（第 6 类与第 7 类）能够在这两个维度上同时取得成功。</p>
<p>与之相对地，光谱的另一端则充满困境。部分团队，例如面临根本性挑战的团队（第 1 类），在吞吐量与稳定性上都表现不佳；而一些高影响但低节奏的团队（第 4 类）则清楚地表明：速度若缺乏稳定性，将是一种危险且不可持续的状态。</p>
<p>卓越并非遥不可及。第 6 类与第 7 类团队占整个样本的近 40%。它们是各组织可以努力追求的标杆。虽然要达到这种状态显然十分困难，但这些团队强有力地证明了：高速、高质量的软件交付并非理论上的理想，而是切实可见的现实。</p>
<h3 id="heading-5aac5l2v6lb6kgm5qu6l6d">如何进行比较</h3>
<p>你也许会想知道，你的团队与今年研究中的其他参与者相比处于什么水平。需要牢记的是，这些测量是以应用或服务为单位进行的。这样的方式能够促进跨职能的共同责任感，并推动改进的落实。</p>
<p>此外，最有价值、最具洞察力的比较，并不是与他人横向对比，而是同一应用或服务在不同时间的纵向比较。研究的目标是持续学习与改进，而非单纯追求达到顶尖的软件交付效能。</p>
<h3 id="heading-2025-dora">调查数据分布（2025 DORA 调查）</h3>
<ul>
<li><p>变更交付周期（Lead time for changes）</p>
<ul>
<li><p>少于 1 小时：9.4%</p>
</li>
<li><p>少于 1 天：15%</p>
</li>
<li><p>1 天 ~ 1 周：31.9%</p>
</li>
<li><p>1 周 ~ 1 月：28.3%</p>
</li>
<li><p>1 月 ~ 6 月：13.2%</p>
</li>
<li><p>超过 6 月：2%</p>
</li>
</ul>
</li>
<li><p>部署频率（Deployment frequency）</p>
<ul>
<li><p>按需（每天多次）：16.2%</p>
</li>
<li><p>每小时 ~ 每天：6.5%</p>
</li>
<li><p>每天 ~ 每周：21.9%</p>
</li>
<li><p>每周 ~ 每月：31.5%</p>
</li>
<li><p>每月 ~ 半年：20.3%</p>
</li>
<li><p>半年以上：3.6%</p>
</li>
</ul>
</li>
<li><p>失败恢复时间（Failed deployment recovery time）</p>
<ul>
<li><p>少于 1 小时：21.3%</p>
</li>
<li><p>少于 1 天：35.3%</p>
</li>
<li><p>1 天 ~ 1 周：28%</p>
</li>
<li><p>1 周 ~ 1 月：9.4%</p>
</li>
<li><p>1 月 ~ 6 月：4.9%</p>
</li>
<li><p>超过 6 月：1%</p>
</li>
</ul>
</li>
<li><p>变更失败率（Change failure rate）</p>
<ul>
<li><p>0% ~ 2%：13.7%</p>
</li>
<li><p>2% ~ 4%：16.7%</p>
</li>
<li><p>4% ~ 8%：36.2%</p>
</li>
<li><p>8% ~ 16%：26%</p>
</li>
<li><p>16% ~ 32%：19.5%</p>
</li>
<li><p>32% ~ 64%：12.5%</p>
</li>
<li><p>超过 64%：8.5%</p>
</li>
</ul>
</li>
<li><p>返工率（Rework rate）</p>
<ul>
<li><p>0% ~ 2%：26.5%</p>
</li>
<li><p>2% ~ 4%：52.6%</p>
</li>
<li><p>4% ~ 8%：77.3%</p>
</li>
<li><p>8% ~ 16%：92.7%</p>
</li>
<li><p>16% ~ 32%：100%</p>
</li>
<li><p>超过 64%：7.3%</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-5a6e6le15lit55qe5bqu55so">实践中的应用</h3>
<p>软件交付效能指标能够为整个交付过程提供高层次视角。随着时间的推移，这些指标的变化可以揭示团队状况是在改善还是恶化。而要改变这些指标所需的干预措施，可能因具体应用而异；不过，也可能会出现一些共性模式，例如冗长的评审与审批周期。</p>
<p>让我们通过一个假设案例来说明：在一次常规回顾会议中，团队讨论了他们的软件交付效能。他们注意到，当前应用的变更交付前置时间开始变长。</p>
<p>他们可能是通过观察仪表板发现的这一趋势，但同样也可能只是凭借日常工作中的直观感受。对于这些指标而言，并不总是需要精确的量化，团队通常会对其随时间的变化有感知。</p>
<p>团队希望扭转这一趋势，但要做到这一点，他们需要理解背后的原因。这时，额外的数据可能会提供帮助。团队可能会查看开发系统中的数据——例如代码库或分析工具——并发现代码评审耗时变长。</p>
<p>团队一致认为这是需要改进的重点，并讨论了潜在的干预措施，包括：</p>
<ul>
<li><p>将代码评审重新设为日常工作的优先事项；</p>
</li>
<li><p>引导提交更小的变更，提升评审效率。</p>
</li>
</ul>
<p>在明确了这些具体改进步骤后，他们约定一个月后再次检查变更审批耗时以及其他软件交付效能指标，以检验改进进展。</p>
<p>无论你的团队属于“流程受限型”还是“稳健工匠型”，目标都是一致的：培育持续改进的思维方式，推动团队迈向更加和谐且高成就的状态。</p>
<h2 id="heading-ai-5">AI 的落地和使用</h2>
<p>我们持续关注软件开发行业中 AI 落地趋势，可以看到，AI 在软件开发中的版图正在日益扩张。在这一快速演进的领域，我们努力提供基于证据的指导，帮助软件开发社区更好地应对这些变化。今年的《AI 辅助软件开发现状》报告，正是迄今为止我们对 AI 辅助开发所做的最深入分析。</p>
<p>总体而言，我们的研究结果显示，软件开发者在广泛采用 AI 的同时，也在多样化任务中对其形成了深度依赖。这一趋势带来了显著的感知收益，既体现在个人生产力的提升，也体现在代码质量的改善上。</p>
<h3 id="heading-ai-6">AI 的普及</h3>
<ul>
<li><p>今年 90% 的调查受访者在工作中使用 AI，比去年的数据增加了 14.1%；</p>
</li>
<li><p>这一惊人比例表明，AI 在软件开发中已经成为常态；</p>
</li>
<li><p>仅有 10% 的受访者表示他们不使用 AI。</p>
</li>
</ul>
<blockquote>
<p>“我认为在过去一年左右的时间里，人们逐渐意识到，生成式 AI 已经发展到真正能在许多方面发挥作用的阶段。既然这一点已经成为共识，那么几乎所有应用都能在某种程度上从生成式 AI 中获益。 因此，我觉得大家都有很强的动力去启用新的功能，以此在某些环节节省成本，减少创造内容所需的时间。没有人想被落下……我确实认为，随着时间的推移，生成式 AI 会越来越深入地融入到一切之中。如果你没有以某种方式使用生成式 AI，那么，是的，我觉得未来要跟上节奏会变得非常困难。”</p>
</blockquote>
<h3 id="heading-5l255so57up6aqm">使用经验</h3>
<p>我们的受访者报告了各自使用 AI 工具的经验，中位数为 16 个月，平均值为 16.22 个月。作为参考，ChatGPT 于 2022 年 11 月发布，比本次调研早了大概 31 个月。</p>
<p>在我们的数据中，既包含了早期采用者，也包含了后期采用者。我们还观察到，在 2023 年底至 2024 年中期，AI 采用出现了一波明显的增长浪潮。</p>
<h3 id="heading-5pe26ze05oqv5ywl">时间投入</h3>
<p>在我们的样本中，AI 使用者在最近一个工作日中与 AI 交互的时长也存在差异。调研结果显示，受访者在最近一个工作日里与 AI 交互的中位数为 2 小时，大约占 8 小时工作日的四分之一。</p>
<h3 id="heading-reflexive-use">下意识使用（Reflexive use）</h3>
<p>尽管在我们的样本中，AI 使用已接近普及，但“下意识使用”——即在遇到问题时默认依赖 AI——却并不常见。</p>
<p>在所有 AI 使用者中，仅有 7% 表示在面对问题或任务时“总是”使用 AI，而 39% 表示只会“有时”求助于 AI。</p>
<p>不过，仍有 60% 的 AI 使用者在遇到问题或任务时，会在“约一半时间或更多”情况下使用 AI。这表明，AI 已经成为软件开发过程中的高频使用工具。</p>
<blockquote>
<p>在过去的 18 个月里，Sabre 通过使用分析与满意度调查，积极跟踪了生成式 AI 助手的采用情况。采用率已飙升至 74%，覆盖了不同资历和经验层次的开发者，且在核心开发任务中使用 AI 的比例显著增加。 这种使用率的提升与更高的用户满意度呈正相关。值得注意的是，86% 的用户表示生产力有所提升。满意度与节省时间的持续上升趋势表明，随着用户熟练度的提高，生成式 AI 工具带来的效益也在不断增长。 我们的分析还发现，对于最新的生成式 AI 功能（例如 Agent 模式）的采用较为缓慢，只有 25% 的用户在使用。对此，Sabre 正在加强培训项目，并推动同伴间的知识分享，以提升使用积极性，并确保团队能够熟练掌握 AI 工具。 —— Jacek Ostrowski，Sabre 平台工程副总裁</p>
</blockquote>
<h3 id="heading-5l6d6lww5oof5ya1">依赖情况</h3>
<p>除了高频使用之外，我们还发现，开发专业人士在工作中对 AI 工具的依赖程度也非常高。在我们的样本中，仅有 5% 的 AI 使用者表示在工作中“完全不依赖”AI，而有 65% 的人表示依赖程度达到 “中等程度”（37%）、“高度依赖”（20%）或“极度依赖”（8%）。</p>
<h3 id="heading-5lu75yqh">任务</h3>
<p>与我们在 2024 年 DORA 报告中的发现一致，今年调研的受访者在 AI 工具的首要使用场景仍然是编写新代码，其中 71% 的代码编写者会借助 AI 来完成这项工作。</p>
<p>在工作内容涉及相关任务的受访者中，大多数人也会使用 AI 来进行：</p>
<ul>
<li><p>文献综述（68%）</p>
</li>
<li><p>修改现有代码（66%）</p>
</li>
<li><p>校对（66%）</p>
</li>
<li><p>图像创建或编辑（66%）</p>
</li>
</ul>
<p>相对较少的使用场景包括：</p>
<ul>
<li><p>需求分析（49%）</p>
</li>
<li><p>内部沟通（48%）</p>
</li>
<li><p>日程管理（25%）</p>
</li>
</ul>
<h3 id="heading-5a6a5yi25yyw5aac5l2v5zc45byv5bya5yr6icf">定制化如何吸引开发者</h3>
<h4 id="heading-56cu56m25yaf5a65">研究内容</h4>
<p>随着 AI 助手在开发工作中越来越普及，加州大学伯克利分校的一支研究生团队研究了学生开发者在实践中如何使用 AI 驱动的集成开发环境（IDE）。研究团队利用眼动追踪数据和访谈，观察了具有 1 到 5 年经验的 Python 开发者如何完成两项短任务：其一涉及一个陌生的库，其二需要解释一个晦涩难懂的函数。</p>
<p>通过应用这项研究的洞见，不同经验水平的开发者都可以探索出更符合自身需求的 AI 编程助手使用方式。</p>
<h4 id="heading-5a6a5yi25yyw6kej5yaz5pa55qgi">定制化解决方案</h4>
<p>为了减少摩擦并更好地支持专注工作，开发者和团队可以对 AI 工具进行定制化。</p>
<p>目前，大多数 IDE 都提供以下功能：</p>
<ul>
<li><p>切换行内建议的开关；</p>
</li>
<li><p>启用“仅按需”模式；</p>
</li>
<li><p>调整建议的风格和结构。</p>
</li>
</ul>
<p>此外，代码库级的配置文件与关联文档也能帮助 AI 助手遵循既定规范。通过尝试这些设置，团队可以让 AI 的行为更契合不同任务的认知需求，从而减少干扰，提升 AI 助手的实际价值。</p>
<h4 id="heading-ai-7">当 AI 成为障碍</h4>
<p>虽然 AI 编程助手的设计初衷是节省时间、减少工作量，但加州大学伯克利分校的一项研究发现，它们在某些任务中也可能带来麻烦。</p>
<p>例如，在处理编写样板代码或安装依赖包等机械性任务时，学生开发者非常乐于使用 AI；但在需要更深层次理解的任务中（如解释复杂代码），他们则大多忽略了 AI 的建议。</p>
<p>眼动追踪数据显示，在解释性任务中，开发者对 AI 聊天的视觉关注度不足 1%，而在机械性任务中，这一比例接近 19%。研究中的学生开发者往往选择手动完成任务，以保持对过程的控制和理解，甚至会忽略掉那些准确且能够节省时间的 AI 建议。</p>
<h4 id="heading-5zcv56s6">启示</h4>
<p>要最大化 AI 编程助手的价值，开发者和团队应当投入精力进行定制化。研究表明，AI 在解释性任务中可能会增加认知负担，从而造成干扰，尤其是在开发者需要理解不熟悉代码的时候。</p>
<p>关键在于：让 AI 的支持方式与任务性质以及开发者的偏好相匹配。通过调整配置，你可以把 AI 从一个可能带来摩擦的因素，转变为提升效率、改善体验的有力工具。</p>
<h4 id="heading-5lqk5lqs55wm6z2i">交互界面</h4>
<p>最常见的 AI 交互方式是对话式聊天机器人，其次是嵌入在 IDE 中的 AI。</p>
<p>受访者报告称，他们与集成在自动化工具链及其他开发工具和平台中的 AI 交互频率相对较低，但这可能是由于这些 AI 工具对用户来说不够直观和可见所导致的。</p>
<h3 id="heading-ai-8">AI 使用模式</h3>
<p>除了询问受访者在何处与 AI 交互、以及出于何种目的外，我们还调查了他们在以下几种“模式”下与 AI 交互的频率：</p>
<ol>
<li><p>对话模式（chat）：任何逐轮的文本交互形式；</p>
</li>
<li><p>预测文本模式（predictive text）：如 Tab 补全代码建议；</p>
</li>
<li><p>协作模式（collaborative）：使用 AI 对整个代码库进行更广泛的修改；</p>
</li>
<li><p>代理模式（agent）：允许 AI 在相对无人监督的情况下操作，并在没有直接人工审查的前提下进行修改。</p>
</li>
</ol>
<p>与受访者最常使用聊天机器人和 IDE 内嵌 AI 的情况相对应，文本对话模式与预测文本模式是最常见的交互方式。</p>
<p>而 AI 代理模式的使用最少，超过 61% 的受访者表示他们“从未”以代理模式与 AI 工具交互。这一使用模式反映了不同 AI 模式的成熟度差异：代理型 AI 的采用率较低，与其相较于更成熟的对话模式和预测文本功能出现时间更晚相一致。</p>
<h4 id="heading-5liq5lq655sf5lqn5yqb">个人生产力</h4>
<p>今年的调查中，超过 80% 的受访者表示他们感受到 AI 提升了生产力。尽管有超过 40% 的人认为生产力仅“略有提升”，但不到 10% 的受访者认为 AI 对他们的生产力造成了负面影响。</p>
<h4 id="heading-5luj56cb6lso6yep">代码质量</h4>
<p>除了在生产力方面感受到积极影响外，大多数（59%）受访者也认为 AI 对他们的代码质量产生了正向作用。其中 31% 认为提升仅为“轻微”，另有 30% 认为既没有正面也没有负面影响。相比之下，仅 10% 的受访者认为 AI 使用对代码质量带来了负面影响。</p>
<blockquote>
<p>“我觉得在某些方面，AI 写出的代码有时比我自己写得更好，主要原因是我感觉它的训练确实非常到位。正如我之前提到的：代码是很二元的，要么能跑，要么不能跑。而 AI 写出的代码通常已经足够满足我的需求。 而且它经常会遵循一些我可能一时忘记、或者懒得回头去重构的代码规范。所以我觉得它能让代码整体上更连贯一致。”</p>
</blockquote>
<h4 id="heading-5lh5lu76zeu6aky">信任问题</h4>
<p>与 2024 年 DORA 报告相似，今年的研究结果揭示了开发者在面对 AI 生成结果的信任度时呈现出一种更为细腻的分布格局。大多数受访者（70%）在某种程度上对其质量表示信任，其中近四分之一（24%）表示“非常信任”或“高度信任”。与此同时，30% 的受访者态度更为谨慎，其中 23% 表示“略微信任”，还有 7% 表示“完全不信任”。</p>
<p>这些数据突显了一个关键洞见：高水平的 AI 采用率与感知收益，可以与一种审慎而细致的信任态度并存。我们的研究表明，AI 输出的实用性并不以“绝对信任”为前提。</p>
<p>这种模式与既有行为一致：在访谈中，开发者将其类比为他们对 Stack Overflow 等常用资源所抱有的理性怀疑——信息会被使用，但并非始终被完全信任。</p>
<p>AI 在软件开发中的可信度仍然是一个重要的讨论与研究议题。我们此前已提出五种策略来帮助培养开发者对 AI 的信任。然而，数据同时也表明，开发者可能已经在工作中主动考虑并应对了 AI 的这一局限性。</p>
<ul>
<li><p>70% 的开发者对 AI 生成的输出表示某种程度的信任；</p>
<ul>
<li><p>24% 的人表示“非常信任”或“比较信任”；</p>
</li>
<li><p>30% 的人仅表示“一点点信任”或“完全不信任”。</p>
</li>
</ul>
</li>
</ul>
<p>研究表明：</p>
<ul>
<li><p>高采纳率和积极反馈可以与“有限信任”并存；</p>
</li>
<li><p>开发者往往像使用 Stack Overflow 一样使用 AI：会参考，但不会盲目信任；</p>
</li>
<li><p>信任不是前提，AI 的产出仍然可以被有效利用。</p>
</li>
</ul>
<p>我们此前提出了<a target="_blank" href="https://dora.dev/research/ai/trust-in-ai/">五种策略</a>来增强开发者对 AI 的信任（见 DORA 专题研究），但本次调查显示，开发者已经在实践中自然适应了这一限制。</p>
<h2 id="heading-5oc757ut">总结</h2>
<p>综合来看，这些研究结果表明，AI 在软件开发中的使用已几乎无处不在。AI 被广泛应用于各类开发任务，成为受访者工作流程的一部分，并在遇到问题时被频繁求助。</p>
<p>尽管受访者仍然对 AI 生成代码的可信度存在担忧，但他们普遍认可 AI 在 个人生产力和代码质量方面带来的积极影响。因此，尽管 AI 并不完美，但它已迅速成为大多数软件开发组织的标准实践。</p>
<p>在去年的研究中，我们发现竞争压力是推动 AI 在软件开发中被采用的关键因素之一。许多受访者将其描述为一种“害怕错过”或“被同行与竞争对手甩开”的心态。然而，将这种社会压力视为采纳新技术的合理动机，本身仍具争议。</p>
<p>虽然我们的数据展示了 AI 采用的诸多积极成果，但我们同样记录了明显的负面影响。因此，我们提醒读者：不要将 AI 的普及简单解读为“所有组织都应当立刻全面采用 AI，而不考虑自身具体需求”。相反，我们认为，这些发现传递的强烈信号是：所有参与软件开发的人——无论是个人开发者、团队管理者，还是高管领导——都应当认真思考 AI 是否、在何处以及如何应用于他们的工作。</p>
<p>采取保守还是开放的路径，取决于具体情境。但 AI 的广泛普及已经表明，组织再也无法忽视其使用所带来的影响。</p>
<p>我们理解，关于 AI 应在多大程度上融入软件开发的决策十分艰难，而最佳决策应基于数据驱动。因此，在本报告关于 DORA 新 AI 能力模型的章节中，我们深入探讨了组织内部的文化能力与技术能力如何影响 AI 采用的成效，并提供了见解，帮助那些选择将 AI 融入流程的组织实现成功落地。</p>
<h2 id="heading-ai-9">探索 AI 与关键成果的关系</h2>
<h3 id="heading-ai-10">AI 是软件开发中的新常态</h3>
<p>仅仅三年时间，AI 的采用与使用就经历了显著的转变。在 2022 年，开发者使用 AI 还会令人惊讶，但如今已有 90% 的技术从业者在工作中使用 AI。</p>
<p>本报告的“AI 采用与使用”章节显示了几乎普遍的采用情况，这一趋势远远超出了我们的数据范围。2025 年 Stack Overflow 开发者调查显示，84% 的开发者正在使用或计划在开发流程中使用 AI 工具，较前一年的 76% 有显著提升。日常使用也非常普遍，47% 的受访者每天都在使用 AI 工具。推动这一趋势的还有 Atlassian 2025 年开发者体验（DevEx）报告，其显示几乎所有开发者（99%）通过使用 AI 工具节省了时间。</p>
<p>这种个人层面的快速普及在企业战略上也得到了呼应。根据 LinkedIn 企业传播部 2025 年的报告，88% 的商业领袖表示加速 AI 采用是战略重点。麦肯锡调查则发现，78% 的受访者表示他们的组织已在至少一个业务职能中定期使用 AI。</p>
<p>这种优先级也体现在资金投入上。根据 斯坦福大学 2025 年 HAI AI 指数，2024 年全球企业在 AI 上的总投资达到 2523 亿美元，比前一年增长 26%。或许没有什么能比人才市场的需求更清晰地反映这一新现实：美国涉及生成式 AI 技能的招聘信息仅在 2023 年就增长了 323%。</p>
<h3 id="heading-ai-11">AI 的影响</h3>
<p>在这股快速普及的浪潮下，组织必须理解：是否也出现了同样迅速的收益增长。广泛采用并不自动等同于广泛价值。我们需要承认，AI 的采用可能充满混乱，驱动力既可能来自炒作和害怕错过（FOMO），也可能来自深思熟虑的战略。</p>
<p>正如我们在 2024 年 DORA 报告中得出的结论，AI 的应用同样可能受到组织系统的制约和限制。报告发现，AI 确实带来了许多有前景的结果，但同时也增加了软件交付的不稳定性，并降低了交付吞吐量。同一份研究估算：AI 采用率每增加 25%，软件交付吞吐量下降约 1.5%，而交付不稳定性上升约 7.2%。</p>
<p>我们并非唯一注意到这些复杂性的研究。例如，Model Evaluation &amp; Threat Research (METR) 的一项研究显示了感知与现实之间的鲜明错位：那些因 AI 工具导致效率降低 19% 的开发者，却仍然相信这些工具让他们的效率提高了 20%。类似地，其他第三方研究也开始指出，AI 可能对认知与幸福感产生影响，进一步强调了作为一个行业，我们仍处在理解 AI 采用真实效应的早期阶段。</p>
<p>然而，当开发者被要求从 SPACE 框架的各个维度来评价 AI 时，他们报告的多为积极影响，负面影响相对较少。而在本报告关于 AI 采用与使用的章节中，大多数受访者也表示，AI 对他们的代码质量和生产力产生了正面作用。</p>
<p>这些相互矛盾的信号告诉我们：还需要更多基于证据的研究来评估 AI 对产品开发的真实影响，特别是在当前 AI 投资与采用规模空前扩大的背景下。我们认为，开发者社区和雇主应当设定切合实际的期望，而清晰认识 AI 的真实影响，是负责任地管理这些期望的第一步。</p>
<h3 id="heading-ai-12">AI 采用的度量</h3>
<p>为了理解AI 采用汇兑关键结果产生什么影响，我们首先需要能够对 AI 的采用情况进行度量</p>
<p>在今年的研究中，我们设计了 AI 采用度的测量方法，并遵循了一些简单的原则：</p>
<ul>
<li><p>包容性（Inclusive）：衡量方法不应偏向任何特定角色（也不应系统性地为非 AI 采用因素生成更高或更低的分数）。例如，软件开发者不应仅仅因为使用 AI 编写代码就自动获得更高分数。该指标需要能够捕捉一种对 AI 的总体取向，而不依赖于个人的具体岗位职能，除了对 AI 的有意义使用之外不受其他因素影响。</p>
</li>
<li><p>数据驱动（Data-informed）：一如既往，我们让数据先行，即使我们有强烈的假设。这个过程的一部分包括进行探索性因子分析（exploratory factor analysis），以减少受到既有信念的约束。</p>
</li>
<li><p>理论驱动（Theory-driven）：我们对 AI 采用的概念化与衡量方式，应当与业界普遍接受的 AI 使用理解以及我们的定性研究成果相一致。</p>
</li>
</ul>
<p>最终结果由三个高度相关的变量构成：</p>
<ul>
<li><p>依赖度（Reliance）：在过去三个月中，你在工作中对 AI 的依赖程度有多高？</p>
</li>
<li><p>信任度（Trust）：在过去三个月中，你在工作中对 AI 生成结果的质量有多大的信任？</p>
</li>
<li><p>下意识使用（Reflexive use）：在过去三个月中，当你在工作中遇到问题或需要完成任务时，你有多频繁会使用 AI？</p>
</li>
</ul>
<p>分析发现，这三个调研项目的回答方式高度相似，这证明了其中可能性：存在一个单一的潜在因素，同时在驱动这三个变量的共同变化。</p>
<p>我们认为，这一因子反映了三个在概念上紧密交织的维度：</p>
<ul>
<li><p>行为维度（use）：实际使用情况；</p>
</li>
<li><p>依赖维度（reliance）：AI 融入个人工作流程的深度；</p>
</li>
<li><p>态度维度（trust）：对 AI 的信任程度。</p>
</li>
</ul>
<p>这一结论与现有文献及我们的定性研究结果高度一致。</p>
<p>这种关系可能是由一个反馈回路支撑的：信任是使用的前提，但使用又是建立信任的机制。这就形成了一个强有力的反馈循环：当用户开始对一个系统产生足够的信任并愿意使用时，更多的使用会进一步增强依赖与信任，从而形成一个持续的采用循环。</p>
<p>事实上，这种循环性使得将这些变量结合起来成为构建因子的理想选择，尤其是考虑到我们的调查只是一个静态快照，而不是一个动态过程的连续记录。AI 的采用本质上是一个涉及态度、意图与行动的心理过程。</p>
<h3 id="heading-6le5o6l5bqm6yep5zkm57ut5p6c">连接度量和结果</h3>
<p>在建立了 AI 采用度的衡量方式之后，我们便能够判断：当比较不同水平的 AI 采用时，研究结果是否会有所差异。</p>
<p>其基本形式为：当比较两个在特征、环境和流程上相同的人时，AI 采用程度更高的那个人，在平均水平上会在某个结果上多出或少出 {数值}。</p>
<p>当然，几乎没有任何一个个体、团队或组织是“平均值”的代表。但通过探索这些平均效应，我们能够挖掘出一些普遍模式。这些模式还能为更细致的分析提供背景，特别是在 DORA AI 能力模型章节中，我们进一步探讨了在哪些条件下 AI 采用最有益（或最无益）。</p>
<p>每年，我们都会尽力挑选和构建那些最能代表本报告读者目标的结果指标。简而言之，我们希望用技术专业人士最关心的方式来评估实践。</p>
<p>以下是我们今年研究的结果指标：</p>
<ul>
<li><p>组织效能：这是一个高层次的衡量指标，用于评估组织的整体成功程度，考量的特征包括：盈利能力、市场份额以及客户满意度。</p>
</li>
<li><p>团队效能：该因素用于衡量个体所在直属团队的感知有效性与协作能力。</p>
</li>
<li><p>产品效能：该因素用于衡量团队所构建产品或服务的成功度与质量，评估维度包括：是否能帮助用户完成重要任务、是否保障信息安全，以及诸如延迟等性能指标。</p>
</li>
<li><p>软件交付吞吐量：该指标代表软件交付过程的速度与效率。更多细节可参见《理解软件交付效能》章节。</p>
</li>
<li><p>软件交付不稳定性：该指标用于衡量软件交付过程的质量与可靠性。更多细节可参见《理解软件交付效能》章节。</p>
</li>
<li><p>代码质量：该指标反映个体对其主要负责的应用或服务中底层代码质量的主观评价。</p>
</li>
<li><p>个人效能：该因素反映个体对自身在工作中的有效性及成就感的自我评估。</p>
</li>
<li><p>有价值的工作：该指标衡量个体自我评估中，自己在工作中投入于有价值且值得的任务所占用的时间比例。</p>
</li>
<li><p>摩擦感：该指标衡量妨碍个体完成工作的阻碍程度。通常而言，摩擦越少被视为越积极的结果。</p>
</li>
<li><p>倦怠感：该指标用于衡量个体在工作中感受到的精疲力竭与玩世不恭（消极态度）程度。通常来说，较低的倦怠感被视为积极结果。</p>
</li>
</ul>
<h4 id="heading-5bm05bqm57ut5p6c">年度结果</h4>
<p>我们估算：在特征、环境和流程相同的两个人之间，AI 采用程度更高的人通常会报告如下结果：</p>
<ul>
<li><p>更高水平的个人效能</p>
</li>
<li><p>更高水平的软件交付不稳定性</p>
</li>
<li><p>更高水平的组织效能</p>
</li>
<li><p>更高比例的时间用于有价值的工作</p>
</li>
<li><p>更高水平的代码质量</p>
</li>
<li><p>更高水平的产品效能</p>
</li>
<li><p>更高水平的软件交付吞吐量</p>
</li>
<li><p>更高水平的团队效能</p>
</li>
<li><p>相似水平的倦怠感</p>
</li>
<li><p>相似水平的摩擦感</p>
</li>
</ul>
<p>本章节接下来的部分将尝试对这一结果模式进行解读，并假设其背后的成因。</p>
<p>在构建这些假设时，我们将参考既有文献、我们的定性研究、领域专家意见，以及我们从 DORA 社区中获得的洞见。更多细节可参见《方法论》章节。</p>
<h4 id="heading-2024">自 2024 年以来持续保持的正向关联</h4>
<p>自去年的报告以来，有若干成果继续与 AI 采用保持正向关联。具体包括：</p>
<ul>
<li><p>更高水平的个人效能</p>
</li>
<li><p>更高水平的代码质量</p>
</li>
<li><p>更高水平的团队效能</p>
</li>
<li><p>更高水平的组织效能</p>
</li>
</ul>
<p>这些持续的正向关系已经成为一种“熟悉的叙事”。在这里，我们将其视作基线而非新发现的亮点，因为它们与去年的结论保持一致，并与许多从业者的实际体验相符。其背后可能存在无数潜在机制，其中许多机制可能是特定于某个组织、团队、情境或环境的。</p>
<p>AI 能够以多种方式帮助个人：处理样板代码与重复性脚手架工作、快速提供可行选项、输出与问题高度相关的结果、总结与综合大量分散的信息，甚至完成诸如设计、规划与分析等高阶任务。</p>
<p>这些个人层面的提升往往能够累积并叠加——当小的胜利在多人、多轮迭代中不断放大时，最终会惠及整个团队与组织。</p>
<h4 id="heading-ai-13">AI 始终嵌套在更大的系统之中</h4>
<p>有几个结果依然呈现出不太理想的模式：</p>
<ul>
<li><p>与 摩擦感没有显著关系</p>
</li>
<li><p>与 倦怠感没有显著关系</p>
</li>
<li><p>AI 与软件交付不稳定性的增加相关联</p>
</li>
</ul>
<p>我们认为，这些顽固效应更多与个体所处的系统、流程和文化有关。目前，AI 的使用主要集中在“键盘端”，这可以解释为什么代码质量与生产力受益，但摩擦感、倦怠感与不稳定性却没有改善。这些因素超出了个体的掌控范围，更直接地与组织结构与运作方式相连。</p>
<p>我们把这些结果视为社会技术系统（sociotechnical system）的属性与后果（涵盖流程与文化）。尽管 AI 带来了种种好处，但 摩擦依旧未受影响，倦怠感保持不变，而交付不稳定性反而上升——除非周边系统与文化也随之发生改变。</p>
<h5 id="heading-5pgp5pom5osf">摩擦感</h5>
<p>尽管自动化重复性任务的工具似乎能带来更顺畅的工作流程，但我们的数据表明，职场摩擦远比完成机械化任务复杂得多。正如我们指出的，一些研究表明，摩擦往往是来自个体之外的流程产物。</p>
<p>例如，2019 年微软就识别了阻碍“拥有美好工作日”的流程问题：</p>
<ul>
<li><p>基础设施问题，如“系统和工具不稳定、运行缓慢”；</p>
</li>
<li><p>文档过时；</p>
</li>
<li><p>行政性工作负担；</p>
</li>
<li><p>时间压力；</p>
</li>
<li><p>重复性任务。</p>
</li>
</ul>
<p>他们的结论之一是，管理者应当“优先考虑并着力改进流程与工具”。</p>
<p>因此，即便 AI 在个人工作层面减少了摩擦（例如编写代码），低效的流程仍可能抵消这些益处，尤其是在组织尚未准备好应对更大变更量以及人们尝试新型工作方式的情况下。</p>
<p>举例来说，如果变更量增加，而相应的防护机制、角色分工与黄金路径没有同步演进，就会导致验证与协调成本上升。</p>
<p>不过，我们并不认为摩擦的故事完全是系统性问题。对于个体而言，摩擦并不会真正消失，而是发生了转移：从手动劳动转向了决策与验证，表现形式可能包括提示迭代、结果审查，以及对“看似正确”的代码进行评估。</p>
<p>最终的结果是：即便 AI 能够让输出更有影响力、自动化掉某些重复任务，但总体摩擦量可能并未明显减少。</p>
<blockquote>
<p>Exabeam “我们发现，AI 在增强优秀工程师技能时最为高效。通过自动化繁琐、重复的任务，AI 让我们的开发者能够把精力集中在战略性问题解决与创新上。”</p>
</blockquote>
<h5 id="heading-5ycm5ocg5osf">倦怠感</h5>
<p>可能有人会认为，提升生产力的工具会减轻倦怠，但我们的研究发现，单纯的技术解决方案无法减少倦怠感。倦怠更可能受到个体所处工作文化的深刻影响。</p>
<p>多年来，我们在自己的数据中也注意到这一点。倦怠与领导力、优先级稳定性以及生成型文化有着密切联系。2017 年的一项元分析发现了倦怠的一些常见前因：工作支持不足、缺乏职场公正、回报偏低以及工作不安全感。即便 AI 能在某种程度上减少倦怠，这种效果也可能会被文化的巨大影响所掩盖。</p>
<p>此外，我们的定性研究中出现了一些清晰信号，与有关工作强化（work intensification）的文献相吻合：AI 辅助开发工具带来的产能提升感知，在某些组织中反而引发了对更高产出的期待。在这些情况下，即使 AI 提升了个体效能，需求与资源之间的平衡依旧没有改变。</p>
<blockquote>
<p>“AI 确实改变了软件开发，我从今年开始就明显感受到了这种变化。去年其实还没有这种感觉。但我认为，随着 MCP（模型上下文协议服务器） 的创新出现，以及能够直接与模型进行协作式编程，这确实在很多方面带来了改变——包括功能发布的方式、功能上线的时间表，以及在一定时间内可以完成的工作量。 现在，相关方期待产品中能更快完成更多工作。因此，截止日期与项目周期被进一步压缩，这确实改变了我的工作方式。这让我有些担忧，因为我觉得领导层——尤其是产品领导层——在交付产品方面给出了相当苛刻的期限。”</p>
</blockquote>
<h5 id="heading-6l2v5lu25lqk5luy5lin56iz5a6a5ocn">软件交付不稳定性</h5>
<p>如果说 11 年的 DORA 研究教会了我们什么，那就是：一个组织的技术实践与流程与软件交付效能息息相关。缺乏这些基础能力，AI 带来的任何收益都可能被彻底抵消。</p>
<p>例如，一个已经采用 AI 的团队，如果没有建立起稳健的软件交付流水线，并且过度依赖其他团队完成交付，那么它的交付过程还是可能不稳定的。我们的数据甚至显示：采用 AI 不仅未能解决不稳定性，反而目前与不稳定性增加相关联。</p>
<p>这也许意味着，这些基础技术能力比以往更为关键，要求更严格地遵循相关原则。然而，也可能证据正指向一个更具颠覆性的结论：这些技术能力和度量标准已经不再足够，它们必须为 AI 时代而演进、被替代或被补充。</p>
<p>有人可能会辩称：不稳定性是可以接受的权衡，因为 AI 辅助开发带来的吞吐量提升足以弥补损失。其逻辑是，AI 辅助交付的速度与规模能够削弱不稳定带来的危害——例如通过极快的缺陷修复与更新，将对终端用户的负面影响降到最低。</p>
<p>然而，当我们超越单纯的软件交付指标来观察时，这一论点并不成立。为了验证这种说法，我们尝试用 AI 来解决历史上曾经发生的因为交付不稳定而造成的问题。</p>
<p>结果发现，并没有这种调节作用。相反，不稳定性依然对关键结果造成严重损害，例如产品效能与倦怠感，这最终可能抵消吞吐量提升所带来的任何收益。</p>
<h3 id="heading-5lia5lqb5yy5yyw">一些变化</h3>
<p>相较于 2024 年，已经有了一些变化</p>
<ul>
<li><p>AI 与“有价值工作时间”的关系 已从负面转为正面</p>
</li>
<li><p>AI 与软件交付吞吐量的关系 已从负面转为正面</p>
</li>
<li><p>AI 与产品效能的关系 已从中性转为正面</p>
</li>
</ul>
<p>这些变化表明：个人、团队与工具都在发生适应。个体有了更多时间去学习如何使用 AI，组织和团队也有了一年的时间去调整配置，而 AI 公司则又经历了一年的迭代，开发出更好的模型与用户体验。</p>
<p>从工具本身开始来看：在众多基准测试中，AI 工具正在变得更强大。过去，对预训练模型进行基于自身数据的微调是一个复杂任务，需要深厚的机器学习专业知识；而如今，许多平台已经构建了简化的工作流来完成这一过程。</p>
<p>云服务商也开发出了更加健壮的工具，使得用户能够将自己的私有数据源（如客户数据库、内部文档、代码库）安全地接入微调过程，这些数据也不会暴露在公共互联网上或提供给基础模型供应商。</p>
<p>与此同时，组织对 AI 的使用方式也在不断演进，这可能为 AI 在一些关键任务中提供了额外的能力与护栏，例如代码评审、测试生成、调试、代码重构、文档撰写以及错误修复。</p>
<p>个体与团队也可能逐渐明白了 AI 在何处、何时、以及如何最有用。例如，人们可能正在学习如何将枯燥、重复、机械的任务交给 AI，从而把更多时间投入到问题解决、设计和创造性工作中。这也解释了为什么今年的研究发现中，AI 采用开始与更高比例的有价值工作时间相关联，而这与去年的结论形成了反转。</p>
<p>确实，如果 AI 处理了编码过程中的一些基础性工作（如脚手架、样板代码、常规转换），开发者就能腾出更多时间专注于代码部署，从而提升软件交付吞吐量，并最终改善产品效能。</p>
<p>我们也可能正在观察到：组织正在逐渐适应，为 AI 创造出更有利的环境，这不仅能让个人与团队从 AI 中获得更大收益，还能让这些收益扩展到团队、产品和整个组织。</p>
<p>在《DORA AI 能力模型》与《AI 镜像》章节中，我们探讨了一些可能的系统性约束，它们或许可以帮助解释这一现象。</p>
<p>当然，一个合理的问题是：为什么有些结果受适应性影响而改善了，而另一些却没有（例如软件交付不稳定性）？ 我们的调查数据并不能直接回答这个问题。更可能的解释是：不同团队在努力的侧重点、某些约束条件的显著性以及问题本身的挑战程度上存在差异。这些差异很可能导致了不同的学习曲线。</p>
<blockquote>
<p>如果 AI 能帮我完成一件原本要花两小时以上的事情，而且只需要 30 分钟，那它就是好的。因为现在我多出了那些时间，可以去做别的事情，可以去尝试不同的事情，可以完成更多的工作。 而且，它也能帮助你在职业上更快成长，对吧？因为你也在以更快的速度学习新东西。</p>
</blockquote>
<h3 id="heading-57ut6k66">结论</h3>
<p>在不同层面上，AI 正在对大多数结果产生积极影响，但也存在一些明显的例外：它与倦怠感和摩擦感没有直接关系，并且依然与软件交付稳定性下降相关。</p>
<p>对比 2025 年与去年的研究结果，可以看出：语言模型、工具与工作流正在不断演进，同时与它们交互的人和组织系统也在适应变化。人们已经找到方法，将精力转向他们认为更有价值的工作；而我们也开始看到，AI 的采用逐步推动了更高的交付吞吐量和更好的产品效能。</p>
<p>然而需要注意的是，AI 并没有让技术从业者的一切都变得更好。一些问题还是亟待解决——包括不稳定性、摩擦和倦怠——并不完全是工具本身的失败，而更像是系统应变不足。这些结果的持续存在，与其说是 AI 的失败，不如说是组织系统的负担，以及部分系统未能及时适应新范式的体现。</p>
<p>我们相信，AI 的价值不会单靠技术本身被释放，而是通过重新构想它所处的工作系统才能实现。对此，我们在《DORA AI 能力模型》与《AI 镜像》章节中有进一步的探讨。</p>
<h2 id="heading-ai-14">AI 对职业开发者的社会认知影响</h2>
<p>DORA 的核心关注点始终是从事软件开发的人。开发者所处的工作环境对他们的工作体验有着至关重要的影响。随着组织重新调整优先事项、领导者寻找新的创新方式，以及 AI 越来越深入地融入工作流，AI 正在重塑这种环境。它不仅有潜力改变开发者所从事的工作类型，还能改变他们的工作重点。</p>
<p>历史经验表明，技术进步会带来人们心理模型的重大变化。在 Uber 出现之前，付钱给陌生人搭乘他们的私家车几乎是难以想象的。但如今，仅在美国和加拿大，就有大约 3100 万人每月至少使用一次该服务。</p>
<p>职业开发者正处在这场 AI 驱动转型的前沿，我们的目标是捕捉他们在这一过程中发工作体验转变。</p>
<p>我们选择研究六个社会认知构念，以探讨开发者如何看待自己与工作的关系：</p>
<ul>
<li><p>真实的自豪感（Authentic pride）</p>
</li>
<li><p>工作的意义（Meaning of work）</p>
</li>
<li><p>认知需求（Need for cognition）</p>
</li>
<li><p>存在感连接（Existential connection）</p>
</li>
<li><p>心理所有权（Psychological ownership）</p>
</li>
<li><p>技能优先级重排（Skill reprioritization）</p>
</li>
</ul>
<h3 id="heading-authentic-pride">真实的自豪感（Authentic pride）</h3>
<p>自豪是一种基本情绪。人们在把某项成就归因于自身可控的行为时，会感到自豪。比如，一个人在跑完马拉松后所体验到的自豪感，源于他们知道自己为此投入了多少训练里程。我们在掌握新技能或完成艰难任务时，会对自己感到良好。</p>
<p>那么，为什么要在 AI 的语境下测量自豪感？因为存在两种相反的假设，而且都具有重要意义：</p>
<ul>
<li><p>一种可能是，人们过度依赖 AI，把工作自动化，从而几乎没有机会通过自身努力去取得成就；</p>
</li>
<li><p>另一种可能是，AI 释放了人们的时间，让他们能够从事更有价值的工作，从而获得自豪感。</p>
</li>
</ul>
<p>我们的研究发现支持后者：更高水平的 AI 采用与更高水平的真实自豪感相关联（见图 29）。</p>
<p>数据还揭示了一个清晰的机制：</p>
<p><code>更高水平的 AI 应用 → 更多时间投入到有价值的工作 → 从事有价值工作的比例更高的人 → 报告的自豪感水平更高。</code></p>
<p>这些发现表明，当开发者学会将琐碎任务交给 AI 时，他们可能会获得一系列积极的后续效益。他们重新掌控了最宝贵的资产——时间，从而能够自由投身于对自己真正重要的项目与想法之中。</p>
<h3 id="heading-meaningful-work">有意义的工作（Meaningful work）</h3>
<p>“有意义的工作”指的是人们希望将自己的工作生活投入到真正重要的事情中。研究显示，从工作中获得意义感的人往往具有更高水平的幸福感与工作满意度。</p>
<p>我们希望探究：AI 的采用是否会影响职业开发者对工作意义的感知。我们提出了两种可能的假设：</p>
<ol>
<li><p>积极假设：AI 通过自动化繁琐任务，使开发者能够将更多时间用于有价值的工作，从而提升他们对工作的意义感；</p>
</li>
<li><p>消极假设：AI 干扰了开发者从事其核心角色任务的能力，从而降低了他们对工作的意义感。</p>
</li>
</ol>
<p>研究结果显示：AI 对开发者感知工作是否更有意义没有显著影响。这再次提示我们：或许我们仍处在这场转型的早期阶段，尚未能够清晰地捕捉到这种变化。</p>
<h3 id="heading-need-for-cognition">认知需求（Need for cognition）</h3>
<p>AI 的出现为人们提供了一种快速、简便的方式来减轻心理负担。一些学术研究的数据表明，学生开发者在想“关掉大脑”时会选择使用 AI。</p>
<p>当然，也有人非常享受投入于思考活动。但 AI 提供了几乎无门槛的答案获取方式，这可能会削弱这种乐趣。复杂问题如今可以被瞬间解决，这或许会让一部分人减少对脑力投入的享受。</p>
<p>然而，我们的研究发现：AI 的采用并未导致开发者在认知需求上的变化，即他们对参与思维活动的需求依旧保持稳定。</p>
<h3 id="heading-existential-connection">存在感连接（Existential connection）</h3>
<p>“存在感连接”指的是弥合自我内心世界与他人之间鸿沟的感受。哲学家威廉·詹姆斯曾指出，这种鸿沟让我们难以真正理解他人的体验。这个概念体现了我们与他人建立深层次人性化联系的能力，让我们在看待世界时不再感到孤立。</p>
<p>我们之所以研究开发者的存在感连接，是因为 AI 的崛起可能改变工作中的互动方式。AI 提供即时、个性化的答案，这可能减少开发者向同事寻求帮助的需求。虽然效率更高，但也可能导致更少的对话与协同解决问题的机会。我们曾担心，随着更多依赖 AI、而更少依赖同事，职场关系会被削弱，进而让人感到更孤立。</p>
<p>然而，我们的研究发现：AI 采用与开发者的存在感连接之间没有显著关系。</p>
<p>这可能意味着：要么我们还处在一个初级阶段，尚未看到这种新技术带来的影响；要么也可能是，AI 在取代部分人际互动的同时，也创造了新的连接机会，通过帮助我们分享与构建更广泛的集体知识基础，反而为合作与交流提供了新的途径。</p>
<h3 id="heading-psychological-ownership">心理所有权（Psychological ownership）</h3>
<p>心理所有权指的是人们对某件事物产生“这是我的”感觉，即便它实际上并不真正属于自己。我们既可能对有形的物品产生这种情感，也可能对无形的概念（如我们的想法）产生类似的归属感。许多开发者对自己编写的代码就有这种所有权感，因此我们想要探究：在 AI 辅助下编写代码，是否会削弱开发者对代码的个人所有感。</p>
<p>研究结果显示：在 78% 的置信水平下，AI 采用与开发者感知到的个人所有权减弱之间没有关联。换句话说，开发者在 AI 辅助下编写的代码，并不会让他们觉得这些代码“不属于自己”。</p>
<p>这支持了这样一种解释：当下的 AI 工具被视为高级助手，而不是一个与人类共享成果的自主合作者。</p>
<p>由于 AI 被看作是可被使用的工具，而非一个会“分走功劳”的伙伴，开发者已经在心理上将其整合进了工作流，就像编译器或代码检查器一样。</p>
<p>不过，仍然剩余的 21%，表明 AI 可能会削弱部分开发者的所有感（见图 30）。当开发者不借助 AI 独立写代码时，写作者身份非常清晰；但当 AI 介入代码编写过程时，谁在真正写代码的界限可能变得模糊。这会削弱他们的投入感与个人控制感——而这两者正是心理所有权的重要来源。</p>
<h3 id="heading-skill-reprioritization">技能优先级重排（Skill reprioritization）</h3>
<p>随着开发者越来越多地与 AI 协作，人们越来越关注这种合作可能会如何改变不同技能的相对重要性。我们希望探究：AI 的采用是否会影响开发者心目中的技能优先级。</p>
<p>我们的假设是：AI 相关技能与以人为中心的技能可能会被视为比代码编写相关技能更重要。</p>
<p>我们请受访者对以下八项技能的重要性进行排序（从最重要到最不重要）：</p>
<ol>
<li><p>编写技术文档（Creating technical documentation）</p>
</li>
<li><p>问题解决能力（Problem-solving skills）</p>
</li>
<li><p>提示工程（Prompt engineering）</p>
</li>
<li><p>编程语言语法记忆（Programming language syntax memorization）</p>
</li>
<li><p>代码阅读与审查（Reading and reviewing code）</p>
</li>
<li><p>团队合作与协作（Teamwork and collaboration）</p>
</li>
<li><p>理解团队代码库（Understanding your team’s codebase）</p>
</li>
<li><p>代码编写（Writing code）</p>
</li>
</ol>
<p>不足为奇的是，AI 的采用提升了“提示工程（Prompt engineering）”的感知重要性。 更有意思的是，AI 采用还提高了对编程语言语法记忆重要性的认知。这一结果颇值得深入研究，因为人们原本可能会认为，在 AI 时代，语法记忆会是最先被视为过时的开发技能之一。</p>
<p>最令人意外的发现是：AI 采用并未影响其他任何技能的重要性认知。</p>
<p>目前我们还不能基于这些数据下定论，因为这些结果可能有多种解释。例如：</p>
<ul>
<li><p>这可能意味着开发者仍处在适应 AI 驱动新工作流的过渡期；</p>
</li>
<li><p>也可能仅仅反映了开发者相信他们的独特专业知识依旧不可或缺。</p>
</li>
</ul>
<h3 id="heading-takeaways">要点总结（Takeaways）</h3>
<p>这些研究结果表明：AI 的采用尚未对开发者的工作体验产生实质性的影响。我们将继续积极跟踪这一领域，观察潜在的变化。</p>
<p>在此期间，我们建议组织：</p>
<ul>
<li><p>给予开发者更多自主权，让他们专注于自己认为有价值的工作；</p>
</li>
<li><p>持续创造学习机会，帮助开发者掌握如何更好地利用 AI，将繁琐任务交给 AI，从而在日常工作中腾出时间，去做更重要、更有意义的事情。</p>
</li>
</ul>
<p>为了避免心理所有权可能下降，我们建议开发者：</p>
<ul>
<li><p>始终将 AI 视为为他们所用的工具。</p>
</li>
<li><p>即便这项技术逐渐具备更多自主性，开发者也要始终把自己看作是驾驶者，而不是旁观者。</p>
</li>
</ul>
<h2 id="heading-dora-ai">DORA AI 能力模型</h2>
<p>DORA 一直以来的目标，不仅是描述软件交付的现状，更是帮助组织在瞬息万变的开发工具、方法与技术环境中，做出基于数据的决策。AI 正在显著改变软件开发。虽然快速的进步带来了许多令人兴奋的可能性，但同时也提出了新的问题：软件开发应如何演进，才能真正把握住这一时刻？</p>
<p>因此，今年我们不仅关注谁在采用 AI、如何使用 AI，更深入探究了在什么条件下，AI 加持的开发者能够获得最佳成果。</p>
<p>我们首次提出了 DORA AI 能力模型（DORA AI Capabilities Model）。研究表明，这一首版模型中的七大 AI 能力，能够放大 AI 采用所带来的效益。它既涵盖了组织的技术维度，也涵盖了文化维度。我们的研究显示，投资建设这些能力领域，能够帮助组织真正释放 AI 工具的潜力。</p>
<p>与 DORA 核心模型（DORA Core Model）一样，我们将持续通过进一步研究来验证、修订与完善 DORA AI 能力模型，并期待在未来与 DORA 社区分享更多的迭代成果。</p>
<h3 id="heading-ai-15">AI （相关）能力</h3>
<p>为了开发这一模型，我们基于以下研究基础提出了可能影响 AI 辅助开发团队成果的广泛能力假设：</p>
<ul>
<li><p>78 场深度访谈，</p>
</li>
<li><p>领域领先专家的专业意见，</p>
</li>
<li><p>以及以往的 DORA 研究。</p>
</li>
</ul>
<p>在此基础上，我们经历了一次广泛的讨论与优先级排序过程，最终选出了今年调查中要纳入的 15 个候选能力。</p>
<p>在这些候选能力中，7 个 能力脱颖而出。当团队将这些能力与 AI 采用相结合时，AI 在重要结果上的积极影响会被进一步放大。</p>
<p>这七大能力构成了我们新模型的核心：</p>
<p>这七大核心 AI 能力包括：</p>
<ol>
<li><p>清晰且有效传达的 AI 立场（Clear and communicated AI stance）</p>
</li>
<li><p>小批量工作方式（Working in small batches）</p>
</li>
<li><p>可供 AI 访问的内部数据（AI-accessible internal data）</p>
</li>
<li><p>高质量的内部平台（Quality internal platforms）</p>
</li>
<li><p>健康的数据生态系统（Healthy data ecosystems）</p>
</li>
<li><p>以用户为中心（User-centric focus）</p>
</li>
<li><p>健全的版本控制实践（Strong version control practices）</p>
</li>
</ol>
<h3 id="heading-ai-clear-and-communicated-ai-stance">清晰且有效传达的 AI 立场（Clear and communicated AI stance）</h3>
<p>“清晰且有效传达的 AI 立场”指的是：组织对开发者在软件开发中应当如何、以及被允许如何使用 AI 辅助开发工具的官方态度是否明确，并且员工是否对此有清晰认知。</p>
<h4 id="heading-6kgh6yep5pa55byp">衡量方式</h4>
<p>我们将其定义为一个单一因子，由以下四个指标组成，反映受访者的感知：</p>
<ol>
<li><p>在工作中，使用 AI 是否被认为是期望中的行为；</p>
</li>
<li><p>组织是否支持开发者在工作中尝试 AI；</p>
</li>
<li><p>哪些 AI 工具被允许使用是否清晰明确；</p>
</li>
<li><p>组织的 AI 政策是否直接适用于自己。</p>
</li>
</ol>
<p>一个拥有清晰且有效传达 AI 立场的组织，通常具备以下特征：</p>
<ul>
<li><p>鼓励并期望开发者使用 AI；</p>
</li>
<li><p>支持开发者在工作中探索 AI；</p>
</li>
<li><p>明确说明哪些 AI 工具是被允许的；</p>
</li>
<li><p>明确政策的适用范围，使员工清楚 AI 使用的边界。</p>
</li>
</ul>
<h4 id="heading-56cu56m25yr546w">研究发现</h4>
<p>我们以高度确定性发现：AI 的积极效益依赖于组织是否具备清晰且有效传达的 AI 立场。当组织做到这一点时：</p>
<ol>
<li><p>AI 对个人效能的正向影响被放大；</p>
</li>
<li><p>AI 对组织效能的正向影响被放大；</p>
</li>
<li><p>AI 原本对摩擦感的中性影响被转化为正面效应，即显著降低摩擦。</p>
</li>
</ol>
<p>在较低确定性水平下，我们还发现：AI 对软件交付吞吐量的正向影响同样会被放大。</p>
<h4 id="heading-5bya5yr6icf5yn6aai">开发者反馈</h4>
<p>在今年的深度访谈中，开发者普遍表示：他们对组织在软件开发中使用 AI 的态度缺乏清晰认知。这种不明确可能导致：</p>
<ol>
<li><p>过度保守：开发者因为担心越界，而比实际可行范围更少使用 AI；</p>
</li>
<li><p>过度宽松：开发者以不合规的方式使用 AI，超出了组织允许的范围。</p>
</li>
</ol>
<p>这两种情况都不是最佳状态。</p>
<h4 id="heading-5bu66k6u5lio5osp5lmj">建议与意义</h4>
<p>我们此前提出过定性见解：组织若能在AI 使用的期望与合规性上保持清晰和透明，能带来多方面益处：</p>
<ul>
<li><p>增强开发者对 AI 的信任；</p>
</li>
<li><p>减轻开发者对数据隐私的无端担忧（通常源于误解）；</p>
</li>
<li><p>推动 AI 辅助开发工具在整个组织范围内的规模化采用。</p>
</li>
</ul>
<p>今年的新调查结果再次印证了这一点：组织应当投资于明确和传达自身在 AI 辅助开发上的立场，这样不仅能帮助个体开发者，也能为整个团队和组织带来可量化的正向成果。</p>
<p>值得强调的是，这一能力衡量的是清晰度与认知度，而非组织立场的具体内容。这意味着，组织和团队可以根据自身的行业特点、角色需求、数据基础设施等独特情况，来制定适合自己的 AI 立场。只要确保这一立场被清晰表述并广泛传达，组织就能够从 AI 在软件开发过程中的应用中获得更大的积极效益。</p>
<blockquote>
<p>“为什么我之前没有更早去探索 AI 呢？部分原因可能是那种顾虑——‘我不知道团队其他成员和管理层会怎么看这件事’……大家当时都没有在谈论它。所以我并不担心说，‘天啊，我会因此惹上麻烦。’ 但与此同时，我也不确定这件事到底有多被鼓励，或者他们是否希望我们持续使用。所以我也不想偷偷去做。我们确实有一份 AI 政策，但更多是关于哪些信息能输入 AI，涉及客户保密的问题。 不过，我觉得如果这种行为更被鼓励的话，我可能会更频繁地用 AI 来处理一些更加琐碎的任务。”</p>
</blockquote>
<h3 id="heading-healthy-data-ecosystems">健康的数据生态系统（Healthy data ecosystems）</h3>
<p>“健康的数据生态系统”指的是一个组织内部数据系统的整体质量。在我们的分析中，数据生态系统的健康度被视为一个单一因子，由以下三个指标共同衡量，反映受访者的感知：</p>
<ol>
<li><p>内部数据源的整体质量；</p>
</li>
<li><p>内部数据源的可访问性；</p>
</li>
<li><p>内部数据源之间是否存在孤岛或割裂现象的程度。</p>
</li>
</ol>
<p>因此，一个拥有健康数据生态系统的组织，其内部数据应当具备以下特征：</p>
<ul>
<li><p>高质量；</p>
</li>
<li><p>易获取；</p>
</li>
<li><p>统一而非割裂。</p>
</li>
</ul>
<h4 id="heading-56cu56m25yr546w-1">研究发现</h4>
<p>我们以高度确定性发现：AI 的积极效益取决于组织是否具备健康的数据生态系统。当组织的数据生态系统健康时，AI 对组织效能的正向影响会被显著放大。</p>
<p>人们常说：AI 模型的效果取决于它所训练的数据。在这里，这条经验法则在组织本地层面同样成立。</p>
<h4 id="heading-5a6e6le15osp5lmj">实践意义</h4>
<p>当组织在构建和维护高质量、可访问、统一的数据生态系统上进行投入时，即使不采用 AI，也能为组织效能带来更高的收益。</p>
<h3 id="heading-ai-ai-accessible-internal-data">AI 可访问的内部数据（AI-accessible internal data）</h3>
<p>“AI 可访问的内部数据”指的是 AI 工具与组织内部数据源和系统的连接程度。在我们的研究中，它被定义为一个单一因子，由以下四个指标衡量，反映受访者的感知：</p>
<ol>
<li><p>AI 工具是否能够访问公司内部信息；</p>
</li>
<li><p>AI 工具的回答是否使用了公司内部信息作为上下文；</p>
</li>
<li><p>在提示中输入公司内部信息的频率；</p>
</li>
<li><p>使用 AI 工具检索公司内部信息的频率。</p>
</li>
</ol>
<h4 id="heading-5ygl5bq354q25ocb5lil55qe6kgo546w">健康状态下的表现</h4>
<p>在一个具备 AI 可访问的内部数据 的组织中，员工会观察到：</p>
<ul>
<li><p>内部数据对 AI 系统是可用的；</p>
</li>
<li><p>并且他们可以通过 AI 工具直接访问和处理这些数据。</p>
</li>
</ul>
<h4 id="heading-56cu56m25yr546w-2">研究发现</h4>
<p>我们以高度确定性发现：AI 的正向效益取决于组织是否具备 AI 可访问的内部数据。当组织实现了这一点时：</p>
<ol>
<li><p>AI 对个人效能的积极影响被放大；</p>
</li>
<li><p>AI 对代码质量的积极影响被放大。</p>
</li>
</ol>
<p>换句话说，尽管基于通用知识训练的 AI 工具已经能够帮助开发者提高效能与代码质量，但如果 AI 能够访问组织的内部数据，并结合公司特定的上下文，那么这些正向效果会被显著增强。</p>
<h4 id="heading-5a6e6le15osp5lmj-1">实践意义</h4>
<p>这表明：组织若投入精力将 AI 工具与内部系统深度集成，其收获的成果可能会远超仅依赖通用大模型的组织。</p>
<p>换言之，要最大化 AI 在个人效能与代码质量上的收益，仅仅采购 AI 授权是不够的，还需要进行更深层次的投资。</p>
<p>从某种角度看，这一发现并不令人意外——如果 AI 无法访问公司内部数据，那它又能真正有多大用处呢？</p>
<blockquote>
<p>“我觉得我目前的很多客户其实还远没有到能够有效使用任何 AI 系统的阶段……他们甚至连数据的规范化管理都没做到……数据散落在公司各个角落，没有统一的存储系统，也没有标准化的格式。 然后，如果他们想用 AI，就必须先进行大量的数据工程工作，把数据处理成能够被生成式 AI 系统真正消费的形式。 我感觉很多公司甚至还没有到达能真正有效使用 AI 的那一步。”</p>
</blockquote>
<h3 id="heading-strong-version-control-practices">健全的版本控制实践（Strong version control practices）</h3>
<p>健全的版本控制实践长期以来都是高效能软件开发团队的基石。版本控制工具为管理代码及其他数字资产随时间的变更提供了一种系统化方式。</p>
<p>在生成式 AI 时代，代码生成的规模和速度显著提升，使得版本控制的重要性被进一步放大。我们的研究表明：成熟的版本控制习惯与 AI 采用之间存在强大的协同作用，这些实践不仅是放大 AI 效益的关键，同时也是降低其风险的必备条件。</p>
<h4 id="heading-56cu56m25yr546w-3">研究发现</h4>
<p>我们以高度确定性发现：AI 的正向效益依赖于开发者在版本控制中的提交频率。</p>
<ul>
<li>当提交频率更高时，AI 对个人效能的积极影响被放大。</li>
</ul>
<p>此外，我们还发现：AI 的正向效益依赖于开发者使用版本控制系统“回滚”功能的频率。</p>
<ul>
<li>当回滚更频繁时，AI 对团队效能的积极影响被放大。</li>
</ul>
<h4 id="heading-5bd55cg5a6j5ywo572r">心理安全网</h4>
<p>成熟版本控制的一个关键方面在于它充当了心理安全网（psychological safety net）。</p>
<ul>
<li><p>这种安全网让开发团队可以更有信心地进行试验与创新，因为他们知道：一旦出现问题，可以轻松回退到稳定状态。</p>
</li>
<li><p>最直观的例子就是对“回滚/撤销”功能的依赖。快速、无障碍地撤销更改，不仅仅是一种便利，更是实现速度与韧性的关键支撑。</p>
</li>
</ul>
<h4 id="heading-ai-16">与 AI 的关系</h4>
<p>AI 的高产出速率让开发者更容易感受到“高效能”。但正如我们在 《探索 AI 与关键结果的关系》 章节中讨论的，AI 的使用也与更高程度的软件不稳定性相关。</p>
<p>我们推测这部分原因在于：大批量代码更难以审查。</p>
<p>因此，虽然频繁使用回滚功能并不会直接减少不稳定性，但我们认为它对 AI 辅助团队的团队效能产生正面作用，可能是因为：在处理大批量代码以及其潜在的不稳定性时，能够快速撤销变更的重要性更高。</p>
<h3 id="heading-working-in-small-batches">小批量工作（Working in small batches）</h3>
<p>“小批量工作”是 DORA 的长期能力之一，指团队将变更拆分为可管理的小单元，以便能够快速测试和评估。</p>
<h4 id="heading-6kgh6yep5pa55byp-1">衡量方式</h4>
<p>小批量工作的健康度被定义为一个单一因子，由以下三个指标衡量：</p>
<ol>
<li><p>受访者在其主要应用或服务中最近一次提交的代码行数；</p>
</li>
<li><p>通常合并到一次发布或部署中的变更数量；</p>
</li>
<li><p>开发者完成一个任务所需的平均时间长度。</p>
</li>
</ol>
<p>一个小批量工作评分更高的团队，通常表现为：</p>
<ul>
<li><p>每次提交的代码行数更少；</p>
</li>
<li><p>每次发布合并的变更数量更少；</p>
</li>
<li><p>每个任务能够在更短时间内完成。</p>
</li>
</ul>
<h4 id="heading-56cu56m25yr546w-4">研究发现</h4>
<p>我们以高度确定性发现：AI 的积极效益取决于团队是否采用小批量工作方式。当团队实践小批量工作时：</p>
<ol>
<li><p>AI 对产品效能的正向影响被放大；</p>
</li>
<li><p>AI 对摩擦感的中性影响被转化为积极效应，显著降低摩擦。</p>
</li>
</ol>
<p>相反，我们也发现：在小批量工作团队中，AI 对个体效能的提升略有减弱。</p>
<h3 id="heading-6kej6k75lio5osp5lmj">解读与意义</h3>
<p>尽管结果存在分化，但我们认为整体而言，小批量工作对 AI 辅助团队的影响是净正向的。</p>
<p>观察到的“个体效能提升减弱”与我们的理论一致：AI 提升个体效能的主要方式在于帮助开发者快速生成大量代码。而对于优先采用小批量工作的团队来说，个体效能的提升幅度自然会有所收敛。</p>
<p>更重要的是，我们强调：个体效能本身不应被视为终极目标。它应当是实现更高层级的组织效能、团队效能、产品效能以及开发者福祉的手段。</p>
<p>在这一背景下，小批量工作既能提高产品效能，又能降低摩擦感。我们认为，这些益处远远超过其可能带来的个体效能减弱。更不用说，小批量工作作为 DORA 核心模型（DORA Core Model）的一部分，已经被长期验证为软件交付高效能的重要驱动因素。</p>
<h3 id="heading-user-centric-focus">以用户为中心（User-centric focus）</h3>
<p>“以用户为中心”是我们年度调查中长期纳入的一项指标，指团队在多大程度上关注其主要应用或服务的最终用户体验。</p>
<h4 id="heading-6kgh6yep5pa55byp-2">衡量方式</h4>
<p>受访者的用户关注度被定义为一个单一因子，由三个七点量表指标组成，衡量他们对以下陈述的认同程度：</p>
<ol>
<li><p>创造用户价值是我的焦点；</p>
</li>
<li><p>用户体验是我的首要任务；</p>
</li>
<li><p>关注用户是业务成功的关键。</p>
</li>
</ol>
<p>因此，一个以用户为中心的团队，通常表现为：他们将用户体验放在首位，并理解用户体验与业务成功之间的紧密联系。</p>
<h4 id="heading-56cu56m25yr546w-5">研究发现</h4>
<p>我们以高度确定性发现：AI 的效应依赖于团队是否以用户为中心。</p>
<ul>
<li><p>当团队以用户为中心时，AI 对团队效能的正向影响被放大；</p>
</li>
<li><p>反之，AI 采用反而会对团队效能产生负面影响。</p>
</li>
</ul>
<p>换言之，以用户为中心不仅能让 AI 辅助团队获得更大收益，缺乏这种关注甚至会让 AI 采用拖累团队表现。</p>
<h4 id="heading-5zcv56s65lio5osp5lmj">启示与意义</h4>
<p>长期以来，我们认为以用户为中心能帮助团队明确目标，并围绕共享战略开展工作，把用户体验作为指引。</p>
<p>在 AI 辅助开发团队中，这一点表现得尤为明显：</p>
<ul>
<li><p>当团队聚焦用户时，AI 的价值被进一步放大；</p>
</li>
<li><p>当团队忽视用户时，AI 的采用会带来负面影响。</p>
</li>
</ul>
<p>这些发现提示：组织在推动 AI 采用时，必须将对用户的深入理解（包括用户目标和反馈）纳入产品路线图和战略。</p>
<p>同时，这也是一个重要的警告：如果缺乏对用户的关注，忽视满足最终用户的需求，AI 的采用可能损害团队效能。</p>
<blockquote>
<p>没错，这正是我在这里待了五年的原因——我觉得自己在做一件有意义的事，能够帮助到普通人。哪怕只是帮助一个人，对我来说也是件了不起的事。但在这里，我能帮助的是数以百万计的用户…… 当有些糟糕的日子里，我心情不佳时，只要想到我所做的一切都是为了这个目标，这种念头就会让我感觉好很多，并激励我继续工作。比如说，我今年只要开发一个小功能，就能帮助十万名用户，这让我充满动力。</p>
<p>一个关键的顿悟时刻是意识到：临床医生并不需要更多的工具——他们需要的是更少的干扰。我们最初的假设是，通过提供更先进的功能来创造价值。但我们发现，事实恰恰相反：技术的简洁性与隐形性才是真正的创新。 相比于完全自动化，AI–人类的混合模式在准确性、共情能力与信任度方面表现得更出色。”</p>
</blockquote>
<h3 id="heading-quality-internal-platforms">高质量的内部平台（Quality internal platforms）</h3>
<p>理解高质量内部平台的价值，一直是我们调研中的重要部分。在这里，“平台”指的是：一组可以在多个应用或服务中共享的能力，其目标是让这些能力能够在整个组织范围内广泛可用。</p>
<h4 id="heading-6kgh6yep5pa55byp-3">衡量方式</h4>
<p>平台的质量通过一个综合评分来衡量，该评分反映了受访者认为其内部平台具备的 12 个特征（详见附录中的完整定义）。</p>
<h4 id="heading-56cu56m25yr546w-6">研究发现</h4>
<p>我们以高度确定性发现：AI 的效益取决于组织是否具备高质量的内部平台。</p>
<ul>
<li><p>在拥有高质量内部平台的组织中，AI 对组织效能的积极影响被放大；</p>
</li>
<li><p>但同时，AI 在摩擦上的中性效应被转化为负面，即：在拥有高质量内部平台的组织里，开发者报告的摩擦感有所增加。</p>
</li>
</ul>
<h4 id="heading-6kej6yek5lio5osp5lmj">解释与意义</h4>
<p>尽管结果存在分化，我们仍认为总体上 高质量内部平台对 AI 辅助团队的影响是净正向的。</p>
<ul>
<li><p>正面作用：高质量的内部平台通过提供统一的能力集，让开发团队能够更轻松地进行构建，从而提升个体效能。</p>
</li>
<li><p>潜在负面作用：平台标准也会在一定程度上限制开发工具的使用方式，例如：定义仅限内部使用的 API，并要求比外部接口更严格的安全控制。</p>
</li>
</ul>
<p>由此，高质量内部平台的作用既包括：</p>
<ol>
<li><p>提升对期望能力的可访问性；</p>
</li>
<li><p>限制对不期望能力的使用。</p>
</li>
</ol>
<p>由于我们尚未形成一套针对 AI 辅助开发工具的标准化最佳实践，我们推测目前高质量内部平台在这方面的作用主要偏向后者——防止不当使用。这也可能解释了为什么在大量采用 AI 的情况下，摩擦感有所增加。但这种摩擦增加，对组织来说未必是坏事。</p>
<h4 id="heading-5oc757ut-1">总结</h4>
<p>正因如此，加上其对组织效能的积极作用，我们认为：设计和维护高质量的内部开发平台，是组织在 AI 辅助环境下成功开展软件开发的一项关键能力。</p>
<h3 id="heading-dora-ai-1">将 DORA AI 能力模型付诸实践</h3>
<p>本章的研究结果表明：在软件开发中成功发挥 AI 的价值，并不是简单地引入新工具就能实现的。相反，组织必须营造出特定的技术与文化环境，才能获得最大的回报。</p>
<p>以下是基于 DORA 七大 AI 能力 提出的若干实践性建议：</p>
<h4 id="heading-ai-17">制定明确的 AI 政策并广而告之</h4>
<p>围绕 AI 的模糊性会抑制采用并带来风险。组织应当建立并推广一份清晰的政策，明确哪些工具和使用方式是被允许的，从而建立开发者的信任。</p>
<p>这种清晰度能提供开展有效实验所需的心理安全感，既能减少摩擦，也能放大 AI 在个人效能和组织效能上的积极影响。</p>
<h4 id="heading-57yp5bcp5bel5l2c6ag56kee5qih">缩小工作项规模</h4>
<p>虽然 AI 能通过生成大量代码来提升个体效能，但我们的研究表明，这并不是最重要的衡量指标。真正应该关注的是成果。坚持并强化小批量工作的纪律，不仅能提升产品效能，还能为 AI 辅助团队减少摩擦。</p>
<h4 id="heading-5bcg5pww5o2u6keg5li65oiy55wl6lwe5lqn">将数据视为战略资产</h4>
<p>AI 对组织效能的积极作用，会因健康的数据生态系统而被显著放大。</p>
<p>组织应当投资于提升内部数据源的质量、可访问性与统一性。当 AI 工具能够基于高质量的内部数据进行学习时，它们的价值将大幅提升。</p>
<h4 id="heading-ai-18">将 AI 融入你的内部环境</h4>
<p>把 AI 工具与组织的内部系统连接起来，从而突破通用辅助的局限，真正提升个人效能与代码质量。</p>
<p>这意味着不能只停留在采购 AI 授权上，而是要投入必要的工程资源，让 AI 工具能够安全访问内部文档、代码库和其他数据源。只有这样，AI 工具才能获得公司特有的上下文信息，并发挥出最大的效用。</p>
<h4 id="heading-5oul5oqx5bm25by65yyw5l2g55qe5a6j5ywo572r">拥抱并强化你的安全网</h4>
<p>AI 辅助编程会显著提升变更的数量与速度，但同时也可能带来更多不稳定性。在这种环境下，版本控制系统就是关键的安全网。</p>
<p>组织应当鼓励团队熟练掌握 回滚（rollback）与撤销（revert）功能的使用，因为这一实践在 AI 辅助环境下与更高的团队效能显著相关。</p>
<h4 id="heading-5zyo5lqn5zob5oiy55wl5lit5lul55so5oi36zya5rgc5li65qc45bd">在产品战略中以用户需求为核心</h4>
<p>开发者在采用 AI 后，个人效能可能会显著提升。 但如果团队未能关注用户需求，可能会更快地背离客户。</p>
<p>我们的研究发现：缺乏用户中心化关注的团队，在采用 AI 辅助开发工具时，效能反而可能受到损害。相反，把用户需求作为产品焦点，能够引导 AI 辅助开发者朝着正确目标前进，并对团队效能产生极为强大的正向作用。</p>
<h4 id="heading-5oqv6lwe5lqo5yaf6yoo5bmz5yw">投资于内部平台</h4>
<p>高质量的内部平台是放大 AI 对组织效能积极作用的关键支撑。</p>
<p>它们能够提供必要的防护栏与共享能力，使 AI 的收益能够在组织范围内高效且安全地规模化落地。</p>
<h2 id="heading-5bmz5yw5bel56il">平台工程</h2>
<p>我们的 2024 年报告首次探讨了内部平台对软件交付效能的影响。我们发现：平台确实对组织效能和生产力有积极作用，但这种收益伴随着权衡——软件交付不稳定性增加，以及吞吐量下降。</p>
<p>今年的研究不仅进一步验证了平台工程的价值，还深入探讨了成功的平台是如何运作并创造价值的。数据表明：平台并不仅仅是工具的集合，而是一种整体性体验，它会直接影响效能、员工福祉，以及组织利用变革性技术的能力。</p>
<p>我们发现，用户往往将平台视为一个整体，其整体效能远比平台中任何单一功能的质量更为重要。</p>
<p>本章将进一步解析平台工程的关键模式——从其几乎全面普及的采用情况、团队结构设计，到它作为创新与风险管理战略基础所扮演的关键角色。</p>
<h3 id="heading-5ywz6zsu5yr546w">关键发现</h3>
<ul>
<li><p>平台采用率几乎已成普遍现象：达到 90%。</p>
</li>
<li><p>专职平台团队是主流的组织模式，占比高达 76%。这意味着领导力的挑战已经从“推动采用”转向了如何有效治理多团队格局。</p>
</li>
<li><p>高质量平台能放大 AI 对组织效能的积极作用。当平台质量较高时，AI 对组织效能的正面影响更为显著。</p>
</li>
<li><p>高质量平台是倍增器：它能提升组织效能、生产力，并改善团队福祉。</p>
</li>
<li><p>平台应被视为一个整体性实体，核心目标是创造卓越的开发者体验。、</p>
</li>
<li><p>平台还充当了风险管理引擎，在带来速度与试验能力的同时，也会带来小幅但真实的软件交付不稳定性。但这是一种可控的权衡，换来的是整体更高的效能。</p>
</li>
</ul>
<h3 id="heading-5pmu5yk44cb5asn5p2c5yyw44cb5zui6zif6amx5yqo">普及、复杂化、团队驱动</h3>
<p>如今，大多数组织已经拥有了内部平台，这表明讨论的重心已经从“是否需要平台”转向了“平台该如何构建”。</p>
<p>我们的数据表明：</p>
<ul>
<li><p>90% 的组织至少采用了一种平台；</p>
</li>
<li><p>29% 的组织已经进入多平台环境；</p>
</li>
<li><p>76% 的组织至少拥有一支专职平台团队；</p>
</li>
<li><p>超过 29% 的受访者所在的组织有多个专职平台团队。</p>
</li>
</ul>
<p>多平台和多团队的普及，并不是工具冗余的迹象，而是说明组织已经超越了“一刀切”的模式，转向构建联合化、专业化的平台与团队，以服务于不同的领域和技术栈。</p>
<p>因此，领导者面临的挑战已经从“有没有平台”转向了“如何治理一个复杂的平台生态”。</p>
<p>和应用一样，平台也能从 DORA 的能力——松耦合团队（loosely coupled teams）中获益，以更好地应对复杂性。</p>
<p>实现这一点，需要为各平台团队建立清晰的职责范围（charters）与接口（interfaces），从而确保整个平台生态系统真正改善开发者体验，而不是制造新的组织孤岛。</p>
<h3 id="heading-5pw05l2t5l2t6aqm5omn5piv5ywz6zsu">整体体验才是关键</h3>
<p>我们请受访者对其平台进行评分，评价其在不同能力上的表现。例如：“该平台是否帮助我构建和运行安全的应用和服务。”</p>
<p>研究发现存在明显的体验差距：</p>
<ul>
<li><p>在核心技术能力方面（如“平台是否有助于可靠性和安全性”），开发者普遍认为支持良好；</p>
</li>
<li><p>而在用户体验相关特性上（如“是否能基于反馈进行改进”、“任务自动化的程度”），则相对滞后。</p>
</li>
</ul>
<p>开发者对平台的整体印象——是有益的伙伴，还是摩擦的来源——会极大影响他们对每一个具体功能的评价。能力之间评分的相对紧密分布也表明，开发者并不把平台视为一份“离散功能清单”，而是将其体验为一个整体性实体。</p>
<p>这种体验差距很可能源于平台建设过程中，组织往往先着力于技术基础设施，而用户体验被推后处理。但数据显示，如果不解决用户体验问题，平台的全部价值就无法真正释放。</p>
<p>因此，需要转变思维：把平台当作产品来运营，将内部开发工具视作产品，把开发者当作客户。这样才能确保用户始终是关注焦点——这是 2024 年报告中的一个关键发现。</p>
<p>以用户为中心，是避免在构建内部开发者平台时常见陷阱的关键。以下是几种典型的误区及原因：</p>
<ol>
<li><p>酒香不怕巷子深</p>
<p> 表现：平台团队基于自己想象的开发者需求来构建平台，没有做用户调研、访谈或验证。他们只关注技术和工程本身，假设平台的价值是不言自明的。</p>
<p> 失败原因：平台最终成为“鬼城”，因为它既没有解决开发者真正痛点，也无法融入他们现有的工作流。</p>
<p> 用户中心化替代方案：采取产品思维，从开发者共情和需求探索开始，平台团队要持续与用户互动，理解他们面临的最大挑战，确保构建的东西是开发者真正想用、愿意用的。</p>
</li>
<li><p>工单运维陷阱（Ticket-ops trap）</p>
<p> 表现：平台团队像“基础设施自动售货机”，完全被动响应开发者工单（如“帮我建个数据库”“帮我建个 CI/CD 流水线”），没有愿景，也没有路线图。</p>
<p> 失败原因：造成瓶颈，加重了平台团队和开发者双方的工作负担。团队耗尽时间处理一次性请求，却无力构建统一的自助化能力。</p>
<p> 用户中心化替代方案：构建一个自助式平台，并制定清晰的路线图。目标是通过自动化、可复用的工具和黄金路径（Golden Paths），让开发者能自主申请和配置资源，从而消除工单队列。</p>
</li>
<li><p>象牙塔平台</p>
<p> 表现：中心化的团队居高临下地制定平台架构与工具，强制推行僵化的标准，没有协作和反馈机制。团队更像是“技术守门人”而非开发者赋能者。</p>
<p> 失败原因：让开发者感到被剥夺权力，最终催生影子 IT 或非官方替代方案绕过平台约束，违背平台初衷。</p>
<p> 用户中心化替代方案：引入产品经理角色，积极收集开发者反馈，把开发者视为客户。平台的设计目标是赋能而非限制，提供“铺好的路”（易用且令人愿意使用的标准路径），但不必强制唯一。</p>
</li>
</ol>
<p>在考虑各项能力及其相互关系时，所有能力或多或少都呈现出均衡的相关性。然而，有两项能力在其中显得尤为突出。</p>
<p>首先，与积极用户体验最强相关的能力是为任务提供清晰的反馈</p>
<p>当平台在任务成功或失败时提供清晰反馈，用户会感到有能力采取行动、排查问题并进行下一步操作，而不是不得不自己翻找信息并摸索解决方法。</p>
<p>其次，“界面直观且简洁”的相关性较低：尽管简洁的界面可能会提升感知，但它并不必然转化为平台的高效性。</p>
<p>即便清晰反馈和简洁界面与其他能力高度相关，它们在感知层面上的评分仍然位居较低。 这意味着，仅仅专注于提升某一项能力的做法是有缺陷的策略。</p>
<p>若要提升平台的感知质量，团队必须将其视为一个整体性的内部产品，并着力改善整个开发者旅程。 如果一个平台在技术上非常优秀，但不以用户为中心（参见 2024 年 DORA 报告），它就不能被视为成功。</p>
<h3 id="heading-5pwi6io944cb5bm456ap5osf5zkm6aoo6zmp55qe5ycn5ake5zmo">效能、幸福感和风险的倍增器</h3>
<p>根据我们的能力定义，高质量的平台在整体上具有广泛且统计上显著的正面影响。它与更高的组织绩效、产品绩效以及生产力相关联。</p>
<p>与以往研究一致，我们发现更好的平台会带来一个小但可信的副作用，即软件交付的不稳定性有所增加，这意味着更高的变更失败率以及更多的返工。</p>
<blockquote>
<p>总体来说，就是尽可能地去做持续交付，如果把代码合并到主干，就立即发布，尽量加上一些测试，用来发现问题，但核心就是直接部署。在大多数情况下，这样做没什么问题，因为即使在部署过程中出现了故障，也有许多小机制可以保证站点不会宕机。所以，部署可能会失败，我们可能需要迅速修复，但网站依然能够正常运行。</p>
</blockquote>
<p>一个优秀的平台如同倍增器，能够直接转化为更好的效能和生产力。相应增加的不稳定性可能恰恰代表着一个健康的高速运转系统，只要这种额外的不稳定性不影响产品性能，它就是可以接受的。</p>
<p>尽管稳定性有所下降，但效能依然提升，这暗示了一种风险补偿的形式：平台让从失败中恢复变得快速且低成本，从而赋能团队进行更多实验，并在追求速度的过程中接受更高比例的小规模失败。</p>
<p>这种轻微的不稳定性应被视为一种可控的权衡，因为平台所带来的绩效显著提升远远超过了交付吞吐量的小幅增长以及交付稳定性的下降。</p>
<p>投资于高质量平台是一种强有力的战略杠杆，能够带来广泛而深远的回报。</p>
<h3 id="heading-ai-19">战略要务：你的平台是释放 AI 能力的关键</h3>
<p>AI 采纳对组织效能的积极作用取决于内部平台的质量。</p>
<p>当平台质量较低时，AI 的采纳对组织效能几乎没有影响；但当平台质量较高时，其作用则显著且积极。 这是任何投资 AI 的领导者都必须关注的关键发现。</p>
<blockquote>
<p>Wayfair 发现，最大的收益不仅来自于更快地发现故障，而是来自于降低修复所需的工作量。 将 AI 嵌入 CI/CD 流程中表明，当针对性强、可解释的建议和自动生成的修复能够无缝集成到开发者已经使用的工具中时，开发者的参与度最高。</p>
</blockquote>
<p>高质量的平台在放大 AI 对组织绩效的影响时发挥着两个作用。</p>
<p>首先，它充当分发与治理层，将 AI 带来的个人生产力提升扩展为系统性的组织改进。 缺乏这一基础，采纳 AI 也只会带来一系列分散的局部优化。</p>
<p>平台提供了集中化的上下文，并抽象掉了让 AI 在大规模下可用和高效所需的复杂或繁琐部分。</p>
<p>不过，AI 正在快速演进，因此要谨慎，不要过度标准化 AI 的实践、工具和方法，否则很可能会限制其积极影响以及在 AI 变化时的适应能力。</p>
<p>其次，正如平台在未涉及 AI 时充当风险缓解器一样，它对 AI 的风险缓解作用同样有用。</p>
<p>平台应当被用来创造一个安全空间，让个体能够学习和实验。</p>
<p>这种实验的安全空间有助于平台和平台团队不断成长和适应，从而更好地支持新的模型、交互模式以及应用开发方式。</p>
<p>此外，无论代码是由人类还是 AI 创建，都会应用同样的自动化测试与部署流程，本质上确保引入应用和服务的变更是安全的。</p>
<p>如果在 AI 上进行投资，却没有在高质量平台上进行相应投入，那么在组织层面几乎不可能获得显著回报。 要真正利用 AI 获得竞争优势，领导者必须将平台工程视为一项基础性的战略推动力。</p>
<h3 id="heading-5bmz5yw5pe25luj55qe5lij5asn6kab5yqh">平台时代的三大要务</h3>
<h4 id="heading-5oq5y2h5pw05l2t5l2t6aqm">提升整体体验</h4>
<p>你无法通过改进某一个功能来修复一个糟糕的平台。 要将平台视为一个完整的产品，关注整个开发者旅程，从反馈循环到自动化。</p>
<h4 id="heading-ai-20">让平台成为 AI 的基石</h4>
<p>平台是释放 AI 组织价值的战略前提。 它是将你的 AI 投资转化为真正竞争优势的引擎。</p>
<h4 id="heading-5yip55so5bmz5yw5qch5yeg6aoo6zmp5ygp5aw9">利用平台校准风险偏好</h4>
<p>一个优秀的平台会改变组织与风险的关系，让失败变得低成本且易于恢复。 理解并管理由此带来的速度与不稳定性之间的权衡，同时要认识到平台并不能消除风险在局部层面的影响。</p>
<h2 id="heading-5lu35yc85rwb566h55cg">价值流管理</h2>
<p>每一个组织都面临着加快创新速度的压力。我们都在采纳 AI、自动化流程、构建平台，并以极快的速度交付功能。但我们真的在变得更好吗？还是只是更快地开发出无法创造价值的功能，更快地让团队精疲力竭，更快地制造复杂性？</p>
<p>当下最大的风险不是被落下，而是把大量投资投入到混乱的活动中，却无法真正带来进展。</p>
<p>十多年来，DORA 的研究一直遵循一个核心信念：表现最出色的组织不仅仅是采纳新工具，而是精于价值交付体系。他们具备“在变得更好方面不断精进”的成熟能力。他们能够理解自身的工作流，识别真正的约束点，并有意图且专注地分配资源。</p>
<p>今年，我们确认，识别和管理价值流的能力，才是真正区分混乱活动与聚焦改进的关键。在 2025 年的研究中，我们发现那些专注于理解自身价值流的团队，会显著更多地把时间投入在有价值的工作上。</p>
<p>更重要的是，我们发现价值流管理（VSM）是让 AI 投资成为竞争优势的倍增器，确保这项强大的新技术解决正确的问题，而不是制造更多混乱。</p>
<h3 id="heading-5aac5l2v5a6e546w6iga54sm5ps56lb77ya5lu35yc85rwb566h55cg55qe5y6f5yiz">如何实现聚焦改进：价值流管理的原则</h3>
<p>价值流管理（VSM）是一种实践，目的是用可视化的方式、分析并改进从想法到客户的工作流。</p>
<p>它不是一种笨重的流程，而是一组由四条原则构成的方法，用于获得清晰视野，从而能聚焦在最关键的环节进行改进。</p>
<p>如需了解如何逐步开展价值流映射练习的详细指南，请参阅 <a target="_blank" href="https://dora.dev/guides/value-stream-management/">DORA 价值流管理指南</a>。</p>
<h4 id="heading-5luo6isr5rw35re35lmx5yiw5ywx5lqr5zyw5zu">从脑海混乱到共享地图</h4>
<p>试图在脑海中理清一个复杂系统是非常困难的。记住所有繁杂的细节会给任何人带来巨大的精神负担，并妨碍对整体全貌的理解。</p>
<p>当团队共同绘制系统地图时，就能把这些细节从个人脑海中释放出来，放到一个共享空间中。系统的结构——以及隐藏的模式——便会一目了然。这种可见性让团队更容易就“哪些有效、哪些无效”展开真正的讨论。 从本质上讲，这正是价值流管理（VSM）的核心。</p>
<p>其实践就是绘制整个软件交付生命周期的流程，从最初的概念一直到最终交付给客户。</p>
<p>这张地图涵盖了一切：产品探索、设计、开发、测试、部署和运维。创建这种共享的表示方式能让团队形成对工作流的集体理解，从而更容易发现真正的瓶颈和阻碍进展的低效之处。</p>
<p>将整个系统从概念到客户完整映射是目标，但不必一次性完成。关键在于从能产生最大影响的地方入手。</p>
<p>在深入绘制之前，先从高层次审视你的工作流，识别主要的约束点，避免去优化那些并非真正瓶颈的环节。例如，如果团队的最大挑战在产品探索阶段，那么从那里开始可能会更有效。</p>
<p>不过，一个经过验证且非常有力的起点，也是 DORA 多年来一直采用的范围，就是从代码提交到投产。之所以从这里入手，是因为这部分流程最容易标准化，并且能够针对效率进行优化。更重要的是，这是团队通常拥有最大自主权的阶段，因此他们可以立刻做出有影响的改进。这与探索阶段形成对比，后者的主要目标是优化有效性。</p>
<p>成功完成这一核心流程能带来快速成果，建立推动更广泛系统（如产品探索和客户反馈）改进所需的动力和公信力。</p>
<h4 id="heading-5ywz5roo5rwb5yqo77ym6icm5lin5luf5luf5piv6ycf5bqm">关注流动，而不仅仅是速度</h4>
<p>一旦绘制了价值流，真正的目标就是让工作顺畅且可预测地流动。要做到这一点，需要从关注局部效率转向优化整个系统。</p>
<p>你应该从衡量真正重要的指标开始。追踪关键指标，例如交付周期（lead time）、处理时间（process time）、以及增值时间与等待时间的比率。这些数字能为你揭示真正的约束点，并提供清晰的基线，从而帮助你判断改进是否真的有效。</p>
<p>这种系统层面的视角对于识别应用新方案或新技术的最佳位置至关重要。例如，通过映射，团队可能会发现代码审查是一个显著的瓶颈。有了这一洞察，他们就可以决定将 AI 应用于改进代码审查流程，而不是仅仅用 AI 生成更多代码，从而加剧瓶颈。</p>
<p>真正的胜利在于利用 AI 来改进代码审查流程本身，清除系统中的实际堵点。这正是关注流动的意义所在：你需要解决整个系统中最大的难题，而不是仅仅加快某一个步骤。</p>
<h4 id="heading-5omt6ycg5oyb57ut5ps56lb55qe5pah5yyw">打造持续改进的文化</h4>
<p>价值流管理（VSM）不是一次性的练习，而是一个持续改进的循环。要定期回顾团队创建的价值流图，并将其作为每一次改进讨论的起点。</p>
<p>关键在于培育一种文化，使团队有权力去尝试、学习和适应。这意味着要设定清晰的目标，同时也要给予团队自主权，让他们自己探索如何实现这些目标。他们需要拥有在没有惩罚恐惧的情况下进行实验、学习和调整的自由。同样重要的是，要鼓励团队将他们的学习成果分享给整个组织。</p>
<p>通过这种方式来践行 VSM，并记录每一次迭代改进，你就能创造一段关于进步的“活的历史”。随着时间的推移，你可以回顾并建立一条清晰的故事线，展示每一次变革是如何不断提升你向客户交付价值的能力。</p>
<blockquote>
<p>“还有一种复杂性，比如，‘这需要多少工作量？’ ‘最终要花多长时间？’ ‘你该怎么估算呢？’ 这总是充满不确定性，同时还伴随着缺乏掌控感。我们能否在需要时即时做出变更并完成任务？ 还是说，每次想做点事，比如修改一条防火墙规则，都得经历两三周的流程？类似的事情有很多。<code>这个流程</code>会以各种不同的方式拖慢我们的工作。 我觉得，<code>尤其是</code>更资深的人对此特别熟悉，因为他们在其他大公司里早就经历过这种情况了。”</p>
</blockquote>
<h4 id="heading-5lul5y2t6lak5oqa5pyv5li65qc55z6">以卓越技术为根基</h4>
<p>如果没有技术卓越作为基础，就不可能实现快速而顺畅的流动，而这种基础通常来自于一个设计良好的内部平台。通过为测试和交付等能力提供“铺好的道路”，一个强大的平台能够抽象复杂性，使高绩效的工作具备可扩展性。</p>
<p>强大的技术基础与组织能效之间的关系，在《平台工程》章节中有详细探讨。</p>
<h3 id="heading-2025">2025 年的研究结果如何</h3>
<p>多年来，DORA 一直倡导使用价值流管理（VSM）等实践来创造快速的工作流。但随着 AI 的广泛应用，这一建议是否依然有效？</p>
<p>今年，我们希望验证长期以来关于 VSM 好处的假设。研究结果证实，拥抱 VSM 原则的组织能够获得显著且可衡量的收益。</p>
<p>首先，我们的研究确认了 VSM 实践对绩效有直接而强大的影响。我们发现了以下强有力的证据：</p>
<ul>
<li><p><strong>VSM 推动团队能效</strong>：持续审视和改进价值流的团队报告的绩效显著更高。</p>
</li>
<li><p><strong>VSM 带来更有价值的工作</strong>：这些团队在组织及其客户真正关心的工作上投入的时间明显更多。</p>
</li>
<li><p><strong>VSM 改善产品能效</strong>：最终，对价值流的关注转化为更好的产品成果，而这可以说是最重要的结果。</p>
</li>
</ul>
<p>这些数据传递了一个简单而人性化的故事：</p>
<p>那些共同努力去理解价值流的团队，会把更多的时间花在真正重要的工作上。当团队对整个价值流有清晰且共享的理解时，他们能够将精力集中在最重要的事情上，把这种清晰转化为有意义的影响。</p>
<p>这种清晰正是释放 AI 等新技术能量的关键。它使团队能够采取战略性行动，而不是盲目地把工具扔向问题。团队不再只是优化某一个小步骤，而是去消除系统中最大的约束。</p>
<p>基于这一点，我们为今年的研究提出了一个关键假设：</p>
<p><strong>VSM 将 AI 转化为组织优势</strong>：我们假设 VSM 调节了 AI 采纳与组织绩效之间的关系。具备成熟 VSM 实践的团队能够把 AI 带来的生产力提升引导至解决系统层面的问题，从而确保个体改进能够转化为更广泛的组织成功。而如果缺乏 VSM，AI 的作用就可能仅限于局部效率的提升，而这些提升最终会被下游的瓶颈所吞噬，从而无法为整个组织带来真正的价值。</p>
<h3 id="heading-57ut6k66-1">结论</h3>
<p>我们的分析验证了这一假设。单纯的 AI 采纳本身仅表现出有限的影响，但在具备强大 VSM 实践的组织中，这种效果被显著放大。这进一步确认了 VSM 是充分释放 AI 投资价值的关键使能因素。通过确保团队和个人层面的生产力提升集中于最重要的系统性约束，VSM 帮助将局部改进转化为真正有意义的组织影响。</p>
<p>这项研究不仅仅是一种观察，更是一种挑战。摆脱混乱活动循环的第一步很简单，却并不容易：问问你的团队——“我们能不能在白板上画出我们的软件交付价值流？”如果答案是否定的，或者这幅图暴露出的问题多于答案，那么你就找到了起点。那场对话，正是“在变得更好方面不断精进”的开端。</p>
<h2 id="heading-ai-ai">AI 镜像：AI 如何反映并放大你组织的真实能力</h2>
<p>去年的 DORA 报告发现，使用 AI 的团队在软件交付中报告了更低的吞吐量和更高的不稳定性。这个出乎意料的发现引发了热烈的讨论——一项旨在加速工作的技术，怎么会与更慢、更不稳定的结果联系在一起？</p>
<p>今年的情况有所变化。AI 的采用如今已经推动吞吐量略有上升，但不稳定性仍然存在。这种进步与摩擦并存的局面促使我们更深入地探究，超越对 AI 的简单二元比较，去理解真正决定其影响的因素。</p>
<p>我们的发现指向了一个比工具和技能更重要的因素：<strong>AI 的应用环境，才是塑造其影响的关键。</strong></p>
<h3 id="heading-6laf6lak5bel5yw3">超越工具</h3>
<p>今年研究中最令人振奋的成果之一是 <strong>DORA AI 能力模型</strong>。AI 在吞吐量、代码质量、团队与组织绩效等结果上的作用，始终会被七项能力所放大：</p>
<ol>
<li><p>清晰且已传达的 AI 立场</p>
</li>
<li><p>健康的数据生态系统</p>
</li>
<li><p>可供 AI 使用的内部数据</p>
</li>
<li><p>强有力的版本控制实践</p>
</li>
<li><p>小批量工作方式</p>
</li>
<li><p>以用户为中心的关注点</p>
</li>
<li><p>高质量的内部平台</p>
</li>
</ol>
<p>这些系统性条件反映了一个组织如何构建其工作、支持其团队，以及如何让环境与现代开发实践保持一致。这些能力决定了使用 AI 工具能否真正转化为有意义的成果，因此它们是 <strong>放大器</strong>。更重要的是，它们全部属于团队与组织层面，这强化了一个关键转变：我们需要重新思考 AI 在软件交付中的角色。</p>
<h3 id="heading-57ue57uh5piv5pyj5py65pw05l2t77ym6icm6z2e5liq5l2t5oc75zkm">组织是有机整体，而非个体总和</h3>
<p>要想理解如何把 AI 的影响从个人生产力的提升扩展到组织层面的收益，我们必须从系统的角度来思考。组织并不像是个体和工具的集合，而更像是由相互依赖的部分组成的网络。工作在团队、流程、政策、基础设施以及共享规范之间流动。虽然个体能力对结果有着重要作用，但整体绩效源自于所有这些部分的互动方式。</p>
<p>这一理念是系统思维的核心，也是高绩效组织演进的关键视角。现代质量管理的奠基人之一 W. Edwards Deming 曾指出，大多数绩效问题不是源于人，而是源于系统。正如他那句著名的话：“一个糟糕的系统，每次都会打败一个优秀的人。”</p>
<p>在一个系统中，仅仅改善某一部分，并不能保证整体结果更好。事实上，如果系统的其他部分无法适应，这些局部改进可能会被阻断、削弱，甚至产生反作用。这也是约束理论（Theory of Constraints）的核心洞察：每个系统都有一个限制因素——一个约束——决定了它能交付多少价值。把注意力放在约束之外的地方，可能看似高效，但不会真正改善价值流动。</p>
<p>这一点对 AI 采纳也有重要启示。即便开发者借助 AI 工具写代码更快，这些代码仍需要经过测试与审查队列，接着是集成和部署流程。除非围绕开发者新工具和加速节奏的工作流得到更新，否则整体交付速度不太可能发生显著变化。系统本身并没有设计好去承载这些提升，更别说放大它们了。</p>
<p>我们以前已经见过类似的情况。在向云转型的过程中，那些仅仅迁移基础设施，而不重新思考架构和交付实践的公司，回报有限。相反，那些为云原生工作流重构了应用、团队和运营的组织，才真正释放了价值。敏捷（Agile）和 DevOps 也是如此：只有伴随着角色、反馈循环和团队边界的深层次变革，才能兑现承诺。</p>
<p>新的强大技术和工具，只有在其周围的系统随之演进时，才能带来相应的变革性成果。这就是为什么 AI 采纳必须被视为一项转型努力。如果组织希望更快行动、更多实验、改变开发者的工作方式，就必须重新审视工作本身的流动方式。</p>
<p>下游系统——如集成、测试、部署和合规——是否足够灵活、敏捷，以承载 AI 带来的速度？决策结构能否跟上工作的节奏？团队是否被激励去委派任务、大规模验证 AI 输出，并通过新的方式共享知识？</p>
<p>如果没有对工作流、角色、治理和文化期望进行有意的改变，AI 工具很可能只是停留在一个未变系统中的局部助推器——错失真正的机会。要扩大 AI 的影响，组织应当投资于重新设计其系统。这意味着识别约束、优化流动，并创造条件，让局部加速转化为组织动能。</p>
<p>那么，这种转型可能是什么样子呢？</p>
<h3 id="heading-6l2s5z6l55qe5lik56en5pa55byp77ya5by65yyw5zkm6lb5yyw">转型的两种方式：强化和进化</h3>
<p>当组织追求 AI 的全部价值时，可以从两条互补的路径来思考转型。一条路径聚焦于增强现有系统，去除摩擦，并支撑 AI 工具带来的速度提升。另一条路径则设想 AI 如何彻底开启全新的工作方式。</p>
<h4 id="heading-5by65yyw77ya6k6p57o757uf5yga5aw95om5yx5ps255uk55qe5yeg5ash">强化：让系统做好承受收益的准备</h4>
<p>当开发者开始使用 AI 工具并体验到生产力提升，但团队却没有看到吞吐量或交付速度的相应提升时，系统本身可能就是那个限制因素。</p>
<p>增强意味着识别并解决这些摩擦点，从而让个体的加速能够顺畅传递到下游。</p>
<ul>
<li><p>代码审查与交接：考虑 AI 如何加速并优化现有步骤。例如，AI 生成的初步审查可以快速揭示问题，减少花在日常反馈上的时间。通过结构化 AI 输入以突出风险或总结差异，也能让人工审查变得更容易、更高效。</p>
</li>
<li><p>安全与隐私协议：随着 AI 参与开发和运维工作流，安全实践必须随之演进。这包括确保工具使用的安全性、更新相关政策、以及引入支持 AI 的监控系统，在保持信任的同时不制造新的瓶颈。将部分流程自动化可以帮助团队在保证速度的同时维持安全。</p>
</li>
<li><p>集成与部署流水线：AI 生成的代码速度极快——你的系统能跟得上吗？持续集成与交付流水线可能需要演进，以减少等待状态并支持更高频的交付。基于 AI 的质量检查可以在不增加人工审批的情况下嵌入流程，从而在不牺牲保障的前提下改善流动性。</p>
</li>
<li><p>数据基础设施：AI 能力模型指出，投资升级数据基础设施极具价值。首先，当 AI 模型和工具能连接到内部数据时，AI 在生产力和代码质量上的收益会被放大，例如代码库、工作追踪工具、文档，甚至决策日志与沟通工具。为 AI 工具增加这些宝贵的上下文能显著改善其输出。与上下文重要性相关的第二个发现是，当数据生态健康（即数据可供 AI 访问、准确且完整）时，AI 对组织绩效的益处更大。</p>
</li>
<li><p>变更管理与文化契合：与任何组织转型一样，AI 采纳需要愿景、支持和沟通——这些都是变革型领导的特征。领导者应明确 AI 转型的长期目标——无论是创新、速度还是质量——并通过培训、共享实践和现实期望来支持过渡。文化同样重要。团队需要被允许去实验、犯错、提升熟练度，并分享他们的学习成果。奖励验证、任务委派、提示词优化和智能体编排等行为，可以在 AI 加速的环境中传递关于成功的正确信号。</p>
</li>
</ul>
<h4 id="heading-ai-21">进化：专门面向为 AI 进行设计</h4>
<p>除了增强现有系统之外，AI 还提供了一个机会，可以设计全新的工作流——这些方法原生契合 AI 的运行方式。</p>
<p><strong>AI 原生交付流水线</strong>：AI 可以持续分析代码中的缺陷、安全漏洞和团队标准的合规情况。它能够提出测试建议，甚至动态生成测试用例。在具备合适的数据和集成条件下，AI 还可以在问题发生之前预测部署风险和性能回退。</p>
<p><strong>AI 原生数据系统</strong>：AI 可以帮助维护其自身的环境，通过组织、标记、清理和分析数据来实现。这使得洞察生成更为稳健，并能更快地基于数据做出迭代决策。同时，它还能揭示团队工作模式中的规律，为运营改进提供新的抓手。</p>
<p><strong>AI 原生安全</strong>：AI 可以通过更早发现威胁、识别异常行为，甚至自动化部分事件响应流程，来扩展安全团队的能力。对于经常资源不足的安全团队来说，AI 的作用在于缓解压力，同时改善响应时间。</p>
<p><strong>AI 原生协作模式</strong>：新兴实践如 <strong>agentic 工作流</strong> 与 <strong>swarming</strong>（蜂拥式协作）正在重塑人类与 AI 的协作方式。前者将任务分配给自主的 AI 智能体，后者则使团队与 AI 能够动态聚合来解决复杂问题。尽管仍处于早期阶段，但这些模式已预示着新的、更具适应性的协作方式。</p>
<p>新兴趋势如<a target="_blank" href="https://githubnext.com/projects/continuous-ai/">持续 AI（Continuous AI）</a> 展示了如何在长期内维持 AI 原生的工作流。持续 AI 将 AI 系统视为开发流水线的有机组成部分，以及团队流程中的参与者。它能够持续感知项目环境中发生的事件，并通过自主而协作的方式，促进团队互动，并随团队一起调整方向。关键在于，AI 系统或智能体需要不断更新相关上下文，并持续衡量其准确性、实用性与成本。</p>
<p>这样一来，AI 就能与组织不断演进的架构、实践和优先事项保持一致，确保其输出在环境变化中依然相关且高质量。</p>
<p>无论是强化还是进化，共同的核心都是有意图的设计。单纯部署 AI 工具本身并不会带来转型，但如果与务实且富有远见的系统层级变革相结合，AI 的采纳就能成为重塑软件构建、交付与安全方式的催化剂。</p>
<h3 id="heading-ai-22">如何开始：AI 转型的实用步骤</h3>
<p>一个组织越早将 AI 采纳视为一项转型工作，就越能掌控这场转型的展开方式。技术正在快速演进，但真正的差异化在于组织的应对能力。在旧流程围绕新工具固化之前着手，意味着组织能够主动塑造其系统的未来，而不是被动接受。</p>
<p>自然而然的第一步，是审视工作当下的实际流动方式。在实践中，这意味着要建立共享的可见性，展示从创意产生到最终交付的全过程。这一过程通常被称为价值流管理（VSM），它能帮助团队可视化交付的每一个阶段，从编码、代码审查到测试、部署与上线。</p>
<p>如果执行得当，工作流映射能够揭示协调成本的消耗过程、延误和返工频发的环节，以及系统吸收或阻滞 AI 工具带来加速效应的位置。它能帮助聚焦于那些约束理论（Theory of Constraints）所指出的、最能释放价值的因素。</p>
<p>为了开始绘制工作流，组织可以组建由日常软件交付中的一线实践者组成的小型跨职能工作组，其中包括工程师、产品经理、数据工程师、运维和安全人员。这些小组最有条件从内部出发，绘制系统，揭示协调失效与瓶颈，并识别 AI 可以发挥变革性作用的地方。</p>
<p>这些努力在获得高层支持时最为有效。高层的背书能够传达战略重要性，确保资源投入，并为从探索到行动提供清晰路径。这些工作组的使命是提出战略性建议：系统应在哪些地方适应以容纳 AI？AI 能在哪些流程或角色中发挥增强作用？需要发展哪些能力才能释放长期价值？</p>
<p>在某些情况下，外部的引导者或顾问可以帮助推动流程，提供基准，并让讨论聚焦于能够释放更广泛改进的系统性机会。</p>
<p>要让变革真正扎根，洞察必须来自系统内部。当实践者推动探索，而领导层承诺支持结果时，有意义的转型条件就会逐渐成形。</p>
<p>关键在于，这项工作必须以系统思维来开展。正如前文所述，组织是复杂系统，仅仅改善某一个节点（例如加速代码生成）并不能提升整体绩效，除非相邻的组件也能同步演进。DORA AI 能力模型为哪些组织层面的干预能够放大 AI 的收益提供了洞见。</p>
<p>例如，一个工作组可能发现，尽管 AI 工具能够提供有价值的建议，但它们经常会生成缺乏关键上下文的回应，比如团队约定、架构历史或以往的事故。对许多组织来说，这或许并不意外，因为这些信息通常散落在不同系统和非正式的知识渠道中。</p>
<p>作为应对，工作组可能会建议以结构化且安全的方式，将内部文档、决策记录和历史工单暴露给 AI 模型。他们还可能提议构建自动化工作流，用于自动标记并呈现这些信息。</p>
<p>在开发或评审期间呈现这些上下，可减少开发者用于搜索的时间，并提升 AI 输出的质量。或者，工作组也可以探索如何利用 AI 识别过时文档、总结冗长的项目讨论，以及检测系统实际行为与文档宣称之间的不一致。</p>
<p>这样做有助于将碎片化的知识转化为结构化、可执行的资产。除了流程层面的变更，这些工作组还可以揭示对新技能和新角色的需求。随着开发者将更多工作委派给 AI 工具，验证、编排与工作流设计等任务将变得更加核心。组织需要界定这些角色的职责形态，如何给予支持，并相应地对齐激励机制。</p>
<p>这包括提供超越“工具使用”的定向培训，帮助理解 AI 如何改变开发工作的本质。上述变化既不会自动发生，也不会一蹴而就，它们需要清晰的意图、明确的所有权以及持续的支持。不过，它们并不要求一开始就做到完美。当组织从小处着手、带着明确目的进行投入，并在各角色之间建立共同的责任机制时，就能形成推动力。一步一步、能力叠加，转型便会生根落地。</p>
<blockquote>
<p>文化转型与工具同样关键。成功不仅需要引入自动化和度量，还需要让团队围绕共同的目标与责任达成一致。</p>
</blockquote>
<h3 id="heading-ai-23">AI 是镜子，也是放大器</h3>
<p>AI 有潜力重塑软件的构建方式，但它本身并不会改变组织系统。它往往做的事情——而且通常发生得很快——是反映这些系统实际的运作方式。在高度一致的组织中，AI 会放大流动；而在支离破碎的组织中，AI 会暴露痛点。具备强大实践、灵活工作流和共享上下文的团队，往往能立刻看到收益。依赖脆弱流程和隐性知识的团队，则可能发现这些缺口比以往更加明显。</p>
<p>这就是为什么 AI 同时扮演 <strong>镜子</strong> 和 <strong>倍增器</strong> 的角色。它能照亮正在发挥作用的部分，加速已有的动能，同时也会显现出需要改变的地方。对于愿意直面这种映射的组织来说，AI 提供的反射可以成为一份路线图。正如我们在过去的其他转型中所见，那些愿意将 AI 采纳视为改进工作方式契机的组织，才会收获最大收益——既来自工具本身，也来自工具所促成的转型。</p>
<h3 id="heading-ai-24">AI：技能发展的威胁与机遇</h3>
<p>在技能发展的层面，软件行业与其他职业类似。专业知识理应自高级员工向初级员工传递，而新鲜的视角和技能则理想地能够自下而上涌现。高级开发者不仅仅是审查拉取请求（pull requests），他们还在教导初级开发者如何进行架构性思考。结对编程不仅仅是发现缺陷，它更是传递那些难以文档化的隐性知识。最理想的情况下，<strong>初级—中级—高级</strong>的“三代模式”能让开发者通过联合解决问题来获得技能，而不仅仅依赖正式培训。</p>
<p>我们需要深入研究 AI 部署对这一“理所当然”的过程所带来的影响。我的职业生涯一直在研究智能自动化与技能问题，覆盖 31 个以上的职业，结果表明：智能自动化的默认使用改变了传统的学徒制模式，使得新手缺乏参与那些对成长至关重要的实际工作机会。专家们可以自给自足，于是他们就这么做了。少数初级员工尽管存在这种参与障碍，仍能学到东西，但大多数却举步维艰。自 2023 年以来，我专注研究 AI 在复杂任务执行中的应用，最近聚焦于软件工程，早期发现同样呈现出这一模式。</p>
<p>但也存在一些有趣的例外，而且我们还需要更多的理解。与以往的革命性技术类似，从印刷术、个人计算机到互联网，AI 正以前所未有的速度被开发与部署。而我们尚不清楚人类能力将如何适应这些变化。</p>
<p>相反，许多人只专注于衡量与 AI 相关的生产力。我们追踪采纳率、生成的代码行数、合并的拉取请求数量——而不是衡量技能发展的指标，例如语言风格或表达多样性随时间的演变。</p>
<p>最优秀的组织会同时优化员工的生产力和技能发展。事实上，在我一些研究中，只有在坚持同步进行技能发展的前提下，才实现了卓越的生产力。<strong>同时衡量并推动生产力与技能发展，才是实现可持续绩效的道路。</strong></p>
<p>AI 已经成为软件开发未来的重要组成部分——这也包括技能发展。例如，我们可以利用 AI 分析开发者与 AI 的交互，将其与版本控制的交互关联，再进一步与技能和关键工作成果挂钩。过去这在成本上不可行，但如今 API 的标注成本正在迅速下降。有了 AI，我们可以获得所需的洞察，重构工作，并为开发者提供指导，帮助他们保持学习优势，同时帮助他人做到同样的事。</p>
<p>默认的 AI 使用模式正在带来突破性的生产力，同时却阻碍了大多数开发者的技能发展。为了保持我们的创新优势——无论是个人还是集体——我们需要利用 AI 本身来<strong>同时衡量技能发展与生产力</strong>。</p>
<h2 id="heading-5bqm6yep5qgg5p62">度量框架</h2>
<h3 id="heading-6ycj5oup5lio57ue57uh55uu5qch5yy56ywn55qe5bqm6yep5qgg5p62">选择与组织目标匹配的度量框架</h3>
<p>衡量软件开发可以帮助推动有影响的变革。然而，这是一项复杂的任务，起步时可能令人望而生畏，因为它涉及理解应该测量什么，以及能够测量什么。</p>
<p>最重要的一点是，你希望通过度量来推动组织的变革。为此，我们建议使用框架来指导你的度量策略。</p>
<p>一个框架会将一个宽泛的主题（例如开发者体验）拆解为可以测量的具体概念（如速度或满意度）。在业界和学术界谈及软件开发的度量时，常常会引用一些框架，例如 SPACE、DevEx、HEART，以及 DORA 的软件交付指标。选择一个框架来衡量软件开发可能是一个困难且令人困惑的步骤，但并非必须如此。</p>
<p>第一步是要明确度量将为哪些目标和决策提供参考，因为不同框架在总体目标上各有侧重。 例如，软件开发中的常见框架分别聚焦于衡量：</p>
<ul>
<li><p>开发者体验</p>
</li>
<li><p>产品卓越性</p>
</li>
<li><p>组织效能</p>
</li>
</ul>
<p>这些总体目标对理解软件开发都有所不同的视角。</p>
<p>要确定哪种框架最适合你们组织的目标，把框架视对背后的“原因”进行度量会有所帮助。它们帮助你明确为什么要进行度量，并指导你根据目标，选择行动。框架提供了使你能够观察数据的视角，确保你的投入与组织目标保持一致。要决定采用哪种框架，可以考虑以下问题：为什么是现在？是否有某些变化要求进行度量？你将如何利用这些洞察？是否有决策或改进可以通过度量来实现？</p>
<p>接下来，“度量什么”指的就是具体的指标——那些支撑整体框架的关键概念，例如速度指标或采纳率指标。通常，你可以采取两种不同的数据收集方式。这就是数据收集的“如何”，它将帮助你得到相应的指标。</p>
<p><strong>自报告数据</strong>涉及直接从开发人员那里收集他们的经验信息。这可以通过以下方式实现：</p>
<ul>
<li><p><strong>调查问卷</strong>：通过提问收集意见、满意度以及对工作的各种感受。</p>
</li>
<li><p><strong>访谈与焦点小组</strong>：通过一对一或小组讨论，更深入地探讨具体的经验和主题。</p>
</li>
<li><p><strong>日志研究</strong>：在实际环境中收集关于活动、想法和体验的数据。</p>
</li>
</ul>
<p>自报告数据的优势在于，它能够捕捉通过自动化手段难以量化的主观体验和概念，例如满意度、幸福感或感知到的有效性。其一个关键优点是通常不需要大量的工具埋点或对开发者工具链的深度可观测性。然而这种数据也存在挑战，比如在标准化、跨团队可比性以及在大型组织中的可扩展性方面的困难。其固有的主观性意味着差异化，并且更容易受到偏差的影响（包括回忆偏差和社会期许偏差）。</p>
<p><strong>基于日志的度量</strong>是自动从开发人员使用的工具和系统中收集的。这些可以包括以下类型的指标：</p>
<ul>
<li><p><strong>数量型</strong>：用于统计特定产出。例如，提交次数或用户数量。</p>
</li>
<li><p><strong>基于时间型</strong>：用于记录在某项活动上花费的时间。例如，编码或代码审查的时间。</p>
</li>
<li><p><strong>频率型</strong>：用于衡量特定时间窗口内的发生率。例如，每月的部署次数，或每位开发者每周提交的 PR 数量。</p>
</li>
</ul>
<p>基于日志的度量的主要好处是，它们能够在大规模场景中提供持续测量和标准化的数据，并且能呈现活动和产出的详细视图。但它们需要对开发者工具链有足够的可观测性，也就是说，必须具备必要的集成与数据收集机制，这可能会形成较高的使用门槛。此外，一个常见的误区是认为基于日志的指标是客观的。事实上，埋点方式各不相同，错误可能导致不准确，而解释也容易受到偏差影响。</p>
<p>框架会为你提供需要衡量的概念，但最终实施什么，取决于你们的资源以及可获取的数据。你是否具备对工具链的可视性来支持基于日志的方法？是否有研究团队来支持自我报告数据的收集？重要的是要认识到，并非所有组织都拥有相同的资源和能力去按照某个特定框架推荐的方式来实施指标。</p>
<p>即使存在组织层面的限制，框架依然是一种指引，是帮助你更好理解复杂行为的透镜——但它们无法完全捕捉这种行为。它们的目的是让你更接近事实，但不应期望能够测量一切。</p>
<p>在考虑框架和指标之间的关系时，把指标看作食材，把框架看作利用这些食材做出的食谱会很有帮助。一些核心食材可以通过不同方式组合，形成不同的食谱（即框架），而另一些食材则是某个特定食谱所独有的。</p>
<p>做出的菜肴味道各不相同，但其中一些底层食材是共享的。在很多情况下，即使没有所有的食材，也能做出味道不错的菜。</p>
<p>框架的差异在于它们旨在推动不同的结果，但它们的一些底层指标是重叠的。下图展示了一些组成框架的指标，以及它们常见的重叠。例如，生产力指标（如代码提交或拉取请求）可能会被三个框架同时度量。</p>
<p>一个组织可能会利用这些指标来衡量新的团队结构的影响（组织效能）、评估某个开发工具的有效性（产品卓越），以及理解开发者的工作负荷（开发者体验）。</p>
<p>相对而言，有些指标更具专属性。开发者幸福感，往往是开发者体验框架中的关键组成部分，但通常并不是组织效能或产品卓越框架中的主要指标。</p>
<p>选择使用单一框架有助于聚焦你所采取的行动，也是一个良好的起点。然而，也不必局限于只使用一个框架。随着目标和衡量能力的变化，使用多个框架能够帮助形成互补的分析结果，从而使整体强于部分之和。重要的是，你要将衡量作为让自己和组织对目标负责的一种方式，并确保能够基于所衡量的结果采取行动。</p>
<h2 id="heading-ai-25">在 AI 时代使用度量框架</h2>
<p>你可能会想，AI 引入到开发流程中是否会改变一切？现有的框架是否仍然适用，还是我们需要新的框架？当出现技术性颠覆时，似乎有必要彻底推翻现有的指标收集策略。我们建议仔细思考实际需要改变的是什么，尤其是在考虑 AI 的影响时。为了更好地理解 AI 如何影响开发者体验，可能只需要更新少量指标，就可以保持整体衡量的一致性。你无需抛弃整个框架，而是可以利用现有的度量作为基线，来帮助识别范式转变如何改变开发者体验。例如，你可能需要增加关于 AI 建议接受率、模型质量或信任度的指标，同时保留现有的开发者体验度量，如感知生产力和代码审查所花费的时间。</p>
<p>随着 AI 的进一步发展，谁在执行开发任务，以及这些任务是什么，都会发生变化。因此，度量方法可能需要适应不同的用户角色，并捕捉变化中的工作流，但衡量开发者体验背后的核心目标很可能并未改变。关键在于，如果你的总体目标保持不变，就不需要更换框架；通过扩展指标也能适应技术上的变化。即使你的目标发生变化，也不一定意味着要从零开始一个新的度量计划。由于指标可以服务于不同的框架，你通常可以快速应对，并重新组合这些指标，以支持新的或额外的框架。例如，理解 AI 驱动的开发工具对代码产出的影响，可能是组织以前未曾面对的新目标。这尤其具有挑战性，因为我们要在变化发生的同时进行度量。</p>
<p>组织普遍面临的一个问题是 AI 对代码质量的影响。随着 AI 被用于提升开发者速度，人们特别担心是否在以牺牲质量换取速度。这种短期的速度提升看起来是积极的；然而，如果质量较低，长期来看可能会对速度产生负面影响。为了解决这些担忧，你的目标可能是确保在推动 AI 工具采纳的同时，组织的代码质量依然保持高水准。这个目标涉及前面讨论过的各类框架的要素，并且可能包含你已经在采集的指标（如代码质量、工具采纳率或感知速度）。因此，你可以继续使用现有的指标，同时引入新的指标。例如，将 DORA 的软件交付指标与 HEART 这样注重产品卓越的框架结合起来，可以有效理解开发者在使用新的 AI 工具时的体验，以及其对软件交付的影响。</p>
<p>软件开发的度量是一个复杂且持续的过程。虽然有许多框架和度量方法可供选择，但你必须能够基于所衡量的结果采取行动。确保行动有效的关键环节之一，是与组织目标保持一致，并获得领导层对度量工作的支持。</p>
<p>在选择框架和指标时保持有意图性，有助于为长期成功奠定基础。秉持采用框架以满足特定目标的精神，可以考虑如何根据 PDCA 框架来行动：</p>
<ul>
<li><p><strong>Plan（计划）</strong>：明确目标，选择框架，并获得领导支持</p>
</li>
<li><p><strong>Do（执行）</strong>：收集一些基线指标，尝试不同做法</p>
</li>
<li><p><strong>Check（检查）</strong>：再次测量，看看你朝目标前进的程度</p>
</li>
<li><p><strong>Adjust（调整）</strong>：利用你的发现来改进后续的方法</p>
</li>
</ul>
<p>我们并不是在推荐某一个框架优于其他框架。根据你的目标来确定合适的框架，可以帮助指导你衡量什么，以及如何采取行动。选择与组织契合的框架。如果它能打动你，并促使组织采取行动，那就是当下合适的框架。</p>
<p>虽然框架提供了指导性的结构，但许多底层的度量是相同的。这意味着你今天实施的度量，往往可以在未来根据需求和目标的演变进行调整和再利用。</p>
<h2 id="heading-5pya5zco55qe5ocd6icd77ya5luo5rse5af5yiw6kgm5yqo">最后的思考：从洞察到行动</h2>
<p>十多年来，DORA 一直是软件开发社区值得信赖的合作伙伴，提供研究与洞察以帮助团队改进。随着行业因 AI 和平台工程等新技术的采用而快速发展，我们的承诺始终如一：研究并分享能够促进高绩效团队的实践。</p>
<h3 id="heading-dora-ai-2">DORA AI 能力模型</h3>
<p>今年，我们推出了首个 <strong>DORA AI 能力模型</strong>，这是我们研究的重要演进。随着各组织在 AI 采用过程中应对复杂性，该模型提供了一个数据支持的框架来指导他们的旅程。它突出了七项关键能力，这些能力在得到培养时，可以增强 AI 对重要组织成果的积极影响。</p>
<p>这些能力包括：</p>
<ul>
<li><p>清晰且已传达的 AI 立场</p>
</li>
<li><p>健康的数据生态系统</p>
</li>
<li><p>可供 AI 访问的内部数据</p>
</li>
<li><p>强有力的版本控制实践</p>
</li>
<li><p>小批量的工作方式</p>
</li>
<li><p>以用户为中心的关注点</p>
</li>
<li><p>高质量的内部平台</p>
</li>
</ul>
<p>该模型是我们的首次迭代，我们将其视为与 DORA 社区以及采用 AI 辅助软件开发的组织持续对话的起点。我们渴望从你们在应用这些洞察时的经验中学习，并期待在未来的研究中对该模型进行验证和完善。</p>
<h3 id="heading-5ywz5roo55so5oi3">关注用户</h3>
<p>今年的研究揭示了一个关键洞察：我们仍处于 AI 辅助软件开发的初期阶段，这是一个技术和实践快速演进的时期，过早进行标准化并不合适。我们的研究发现，仅仅部署 AI 工具并不是转型的万能药。事实上，AI 对团队能效的影响高度依赖于一个关键因素：以用户为中心的关注点。</p>
<p>我们以高度的确定性发现，当团队采取以用户为中心的关注点时，AI 对其绩效的积极影响会被放大。相反，如果缺乏以用户为中心的关注点，AI 的采用可能会对团队绩效产生负面影响。</p>
<p>这一发现传达了对所有组织都至关重要的信息：对终端用户的深入理解进行投入和培养，不仅仅是有益的，而是成功应用 AI 的前提条件。如果你的战略中没有将用户置于核心，AI 的采用不仅不太可能带来帮助，甚至可能降低团队能效。</p>
<h3 id="heading-5bcg56cu56m25luy6k45a6e6le177ya6l2u5yiw5l2g5p2l6kv6aqm5lqg">将研究付诸实践：轮到你来试验了</h3>
<p>今年报告中的发现是复杂的，有时甚至看起来相互矛盾。这反映了一个不断变化领域的现实。我们鼓励你将这些发现视为你自己实验的假设，而不是僵化的规定。</p>
<p>以下是一些将研究付诸实践的方法：</p>
<ul>
<li><p><strong>在组织中运行实验</strong>：利用 DORA 的发现来制定假设，并在你的团队中进行测试。这将帮助你更深入地了解你们特定的运营环境，并识别出最具影响力的改进领域。</p>
</li>
<li><p><strong>开展内部调研</strong>：从今年调研中使用的问题中获取灵感，设计你自己的问卷。结合更细致的问题，使其与团队和项目直接相关。</p>
</li>
<li><p><strong>拥抱整体体验</strong>：记住，仅仅改进单个功能无法修复一个存在缺陷的平台。要把内部平台当作产品来看待，关注整个开发者旅程，从反馈循环到自动化。</p>
</li>
<li><p><strong>分享你的学习成果</strong>：在你开展自己的实验并收集洞察时，把这些知识在组织内部传播开来。这可以通过正式的报告、非正式的实践社区，或是日常交流来实现。目标是培育一种持续学习的文化。</p>
</li>
</ul>
<p>在这个不断发展的环境中，最大的风险并不是落后，而是大量投入于混乱的活动却无法带来有意义的成果。请选择与你们组织契合、并能促使你们采取行动的框架和方法。</p>
]]></content:encoded></item><item><title><![CDATA[僭越了，有人在用 Rust 写 Kubernetes]]></title><description><![CDATA[一个新语言问世，最爱做的事情之一，就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s（https://github.com/rk8s-dev/rk8s） 也可以归在这个范畴里，只不过这个项目重写的东西比较大，是 Kubernetes。
从 2025 年 1 月第一个 Commit 开始，到现在有了 200 多次 Commit，十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。
另外该项目也是国内第一个脱离 Cargo 转向使用 ...]]></description><link>https://blog.fleeto.us/rust-kubernetes</link><guid isPermaLink="true">https://blog.fleeto.us/rust-kubernetes</guid><category><![CDATA[Rust]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Sat, 27 Sep 2025 14:43:33 GMT</pubDate><content:encoded><![CDATA[<p>一个新语言问世，最爱做的事情之一，就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——<a target="_blank" href="https://github.com/rk8s-dev/rk8s">rk8s</a>（<a target="_blank" href="https://github.com/rk8s-dev/rk8s）"><code>https://github.com/rk8s-dev/rk8s</code>）</a> 也可以归在这个范畴里，只不过这个项目重写的东西比较大，是 Kubernetes。</p>
<p>从 2025 年 1 月第一个 Commit 开始，到现在有了 200 多次 Commit，十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。</p>
<p>另外该项目也是国内第一个脱离 Cargo 转向使用 Buck2 做构建的项目。</p>
<p>那么这些代码都做了什么呢？看 <code>project</code> 目录中，我们可以看到除了网络、存储相关内容之外，三个醒目成员：</p>
<ul>
<li><p><strong>rkb</strong>：容器镜像构建工具</p>
</li>
<li><p><strong>rkl</strong>：容器运行时</p>
</li>
<li><p><strong>rks</strong>：说自己是个 RKS 守护进程 CLI</p>
</li>
</ul>
<h2 id="heading-5p6e5bu6">构建</h2>
<p><a target="_blank" href="http://README.md"><code>README.md</code></a> 中推荐的是直接使用 Cargo 进行构建：</p>
<pre><code class="lang-plaintext">$ cd rk8s/project/
$ cargo build -p rkl
$ cargo build -p rks
...
</code></pre>
<p>这中间需要一些环境支持，当然也可以用 <code>./.devcontainer</code> 中的 <code>Dockerfile</code> 生成一个工作镜像完成构建工作。</p>
<h2 id="heading-rkl">RKL</h2>
<p>看看他的帮助输出：</p>
<pre><code class="lang-plaintext">$  project/target/debug/rkl --help
A simple container runtime

Usage: rkl &lt;workload&gt; &lt;command&gt; [OPTIONS]

Commands:
  pod        Operations related to pods
  container  Manage standalone containers
  compose    Manage multi-container apps using compose
  help       Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
</code></pre>
<p>可以看到，它能支持 容器、Pod 和 Compose 三种工作负载的运行。</p>
<h3 id="heading-5a655zmo">容器</h3>
<p>编写下面的 <code>single.yaml</code> 用于运行容器：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">single-container-test</span>
<span class="hljs-comment"># 注意，image 字段的路径</span>
<span class="hljs-attr">image:</span> <span class="hljs-string">./rk8s/project/test/bundles/busybox</span>
<span class="hljs-attr">ports:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">80</span>
    <span class="hljs-attr">protocol:</span> <span class="hljs-string">""</span>
    <span class="hljs-attr">hostPort:</span> <span class="hljs-number">0</span>
    <span class="hljs-attr">hostIP:</span> <span class="hljs-string">""</span>
<span class="hljs-attr">args:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">sleep</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"100"</span>
<span class="hljs-attr">resources:</span>
  <span class="hljs-attr">limits:</span>
    <span class="hljs-attr">cpu:</span> <span class="hljs-string">500m</span>
    <span class="hljs-attr">memory:</span> <span class="hljs-string">233Mi</span>
</code></pre>
<p>运行一下看看：</p>
<pre><code class="lang-plaintext">$ sudo project/target/debug/rkl container run single.yaml
Container: single-container-test runs successfully!
$  sudo project/target/debug/rkl container list
ID                                     PID     STATUS   BUNDLE                                           CREATED                    CREATOR
single-container-test                  156245  Running  /rk8s/project/test/bundles/busybox  2025-09-27T20:28:34+08:00  root
$  sudo project/target/debug/rkl container exec single-container-test /bin/ls
bin    dev    etc    lib    lib64  proc   sys    usr
</code></pre>
<h3 id="heading-pod">Pod</h3>
<p>RKL 也支持类似 Podman 或者 Kubelet 单机运行 Pod 的能力，例如如下的 <code>pod.yaml</code>：</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># 同样也要注意 Bundle 和 Image 两个字段的路径</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Pod</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">simple-container-task</span>  
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">my-app</span> 
    <span class="hljs-attr">bundle:</span> <span class="hljs-string">./rk8s/project/test/bundles/pause</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">containers:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">main-container1</span>    
      <span class="hljs-attr">image:</span> <span class="hljs-string">./rk8s/project/test/bundles/busybox</span>
      <span class="hljs-attr">args:</span>             
        <span class="hljs-bullet">-</span> <span class="hljs-string">"dd"</span>                   
        <span class="hljs-bullet">-</span> <span class="hljs-string">"if=/dev/zero"</span>  
        <span class="hljs-bullet">-</span> <span class="hljs-string">"of=/dev/null"</span>          
      <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">containerPort:</span> <span class="hljs-number">80</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">limits:</span>
          <span class="hljs-attr">cpu:</span> <span class="hljs-string">"500m"</span>
          <span class="hljs-attr">memory:</span> <span class="hljs-string">"512Mi"</span>
<span class="hljs-attr">status:</span>
</code></pre>
<p>上面代码中包含了对 Pause 容器的引用，也有 <code>main-container1</code> 这个“业务”容器，运行过程跟单容器类似：</p>
<pre><code class="lang-plaintext">$ sudo project/target/debug/rkl pod run pod.yaml
$  sudo project/target/debug/rkl pod state simple-container-task
Pod: simple-container-task
PodSandbox ID: simple-container-task
{
  "ociVersion": "v1.0.2",
  "id": "simple-container-task",
  "status": "running",
  "pid": 165045,
  "bundle": "/home/dustise/rk8s/project/test/bundles/pause",
  "annotations": {},
  "created": "2025-09-27T12:52:58.258522466Z",
  "creator": 0,
  "useSystemd": false,
  "cleanUpIntelRdtSubdirectory": false
}
Containers:
{
  "ociVersion": "v1.0.2",
  "id": "simple-container-task-main-container1",
  "status": "running",
  "pid": 165061,
  "bundle": "/home/dustise/rk8s/project/test/bundles/busybox",
  "annotations": {},
  "created": "2025-09-27T12:52:58.400974102Z",
  "creator": 0,
  "useSystemd": false,
  "cleanUpIntelRdtSubdirectory": false
}
$  sudo project/target/debug/rkl pod  exec simple-container-task simple-container-task-main-container1 /bin/sh
/bin/sh: can't access tty; job control turned off
/ # ls
bin    dev    etc    lib    lib64  proc   sys    usr
</code></pre>
<h3 id="heading-compose">Compose</h3>
<blockquote>
<p>写这个功能好像劳动力过剩的样子。</p>
</blockquote>
<h2 id="heading-rks">RKS</h2>
<ul>
<li><p>RKS 提供了支持调度和状态管理的控制面，类似 K8s 的 Master 三大件。</p>
</li>
<li><p>RKL 则提供了容器的运行时支持，类似 Node Worker。</p>
</li>
<li><p>使用兼容 ETCD 的 <a target="_blank" href="https://datenlord.github.io/xline-home/">Xline</a> 提供数据库支持。</p>
</li>
<li><p>组件之间的通信使用的是基于 QUIC 的协议。</p>
</li>
</ul>
<p>首先启动 Xline：</p>
<pre><code class="lang-plaintext">$ git clone https://github.com/xline-kv/Xline.git
$ cd Xline
$ docker pull ghcr.io/xline-kv/xline:latest
$ cp fixtures/{private,public}.pem scripts/
$ ./scripts/quick_start.sh
...
7b41380e4c4e60d5531321789987a35b4e0368b1aa3948efe8e3f2a0671301ed
Prometheus starts on http://172.20.0.6:9090/graph and http://127.0.0.1:9090/graph (if you are using Docker Desktop).
</code></pre>
<p>Xline 启动之后，编写如下 <code>config.yaml</code> 用于启动服务：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">addr:</span> <span class="hljs-string">"127.0.0.1:50051"</span>

<span class="hljs-attr">xline_config:</span>

  <span class="hljs-attr">endpoints:</span>

    <span class="hljs-bullet">-</span> <span class="hljs-string">"http://172.20.0.3:2379"</span>

    <span class="hljs-bullet">-</span> <span class="hljs-string">"http://172.20.0.4:2379"</span>

    <span class="hljs-bullet">-</span> <span class="hljs-string">"http://172.20.0.5:2379"</span>

  <span class="hljs-attr">prefix:</span> <span class="hljs-string">"/coreos.com/network"</span>

  <span class="hljs-attr">subnet_lease_renew_margin:</span> <span class="hljs-number">60</span>

<span class="hljs-attr">network_config:</span>

  <span class="hljs-attr">Network:</span> <span class="hljs-string">"10.1.0.0/16"</span>

  <span class="hljs-attr">SubnetMin:</span> <span class="hljs-string">"10.1.1.0"</span>

  <span class="hljs-attr">SubnetMax:</span> <span class="hljs-string">"10.1.254.0"</span>

  <span class="hljs-attr">SubnetLen:</span> <span class="hljs-number">24</span>
</code></pre>
<p>启动服务：</p>
<pre><code class="lang-plaintext">$ sudo project/target/debug/rks start --config config.yaml
[rks] listening on 127.0.0.1:50051
</code></pre>
<p>在集群上创建一个 Pod：</p>
<pre><code class="lang-plaintext">$ sudo project/target/debug/rkl pod create pod.yaml --cluster 127.0.0.1:50051
RKL connected to RKS at 127.0.0.1:50051
pod simple-container-task created
$ sudo project/target/debug/rkl pod list --cluster 127.0.0.1:50051
RKL connected to RKS at 127.0.0.1:50051
NAME  READY  STATUS  RESTARTS  AGE
simple-container-task
</code></pre>
<p>类似前面的本地 Pod，只不过这次是在 RKS 集群中运行了。</p>
<h2 id="heading-5zco6k6w">后记</h2>
<p>项目 README 有些滞后，并没有展示跨节点调度和 Service 通信的能力，期待后续的更新。</p>
<p>另外，RKL 的用法也略微有些迷惑，跟 kubectl 和 podman 都不同，也只能期待文档的进一步细化了。</p>
]]></content:encoded></item><item><title><![CDATA[收房和交付：人人都是产品经理项目经理交付经理。。。]]></title><description><![CDATA[五月份，新房刚装修完，回头看看从决策、掏钱，到交付、维护、装修，这一路磕磕绊绊的过程，看起来居然有颇多环节和 IT 项目交付有些相似之处，所以就零零散散的写一篇，博诸君一笑。
销售话术——现实和想象
买房时候销售给了个低价购买车位的福利，激动的心、颤抖的手，果断拿下——交楼时候才知道，优惠车位在另一个区，还得等一年。
想想自己的 IT 项目里，销售阶段的天花乱坠，也就心下安定了。
大厂出好货——名和实
这个楼盘系出名门，是某利的天字号系列，交楼时候，却已因为周边景观、地段、配套等成为该地区的知名...]]></description><link>https://blog.fleeto.us/5ps25oi5zkm5lqk5luy77ya5lq65lq66yo95piv5lqn5zob57up55cg6ag555uu57up55cg5lqk5luy57up55cg44cc44cc44cc</link><guid isPermaLink="true">https://blog.fleeto.us/5ps25oi5zkm5lqk5luy77ya5lq65lq66yo95piv5lqn5zob57up55cg6ag555uu57up55cg5lqk5luy57up55cg44cc44cc44cc</guid><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Tue, 24 Jun 2025 10:33:10 GMT</pubDate><content:encoded><![CDATA[<p>五月份，新房刚装修完，回头看看从决策、掏钱，到交付、维护、装修，这一路磕磕绊绊的过程，看起来居然有颇多环节和 IT 项目交付有些相似之处，所以就零零散散的写一篇，博诸君一笑。</p>
<h2 id="heading-6zsa5zsu6kd5pyv4ocu4ocu546w5a6e5zkm5ooz6lgh">销售话术——现实和想象</h2>
<p>买房时候销售给了个低价购买车位的福利，激动的心、颤抖的手，果断拿下——交楼时候才知道，优惠车位在另一个区，还得等一年。</p>
<p>想想自己的 IT 项目里，销售阶段的天花乱坠，也就心下安定了。</p>
<h2 id="heading-5asn5y6c5ye65aw96lsn4ocu4ocu5zcn5zkm5a6e">大厂出好货——名和实</h2>
<p>这个楼盘系出名门，是某利的天字号系列，交楼时候，却已因为周边景观、地段、配套等成为该地区的知名伪豪宅。</p>
<p>那么我错误在哪里呢？有个重要的原因就是大厂光环。对照到我常见的工作场景里，很多客户在采用/采购评估过程中，因为候选产品/企业/项目的光环，自觉或不自觉地高看一眼，导致最终的决策偏差。实际上大厂产品翻车是个挺常见的事情：</p>
<ol>
<li><p>Google：有个无聊的网站，叫 <a target="_blank" href="https://killedbygoogle.com/">Killed By Google</a>，迄今为止，收录了 Google 放弃的 296 个产品，其中包含了 Reader、Plus 这样的知名 ToC 产品，还包含了很多存活期在五年以上的 ToB 软件和硬件产品</p>
</li>
<li><p>Microsoft：同样也有个无聊网站，叫 <a target="_blank" href="https://microsoftgraveyard.com/">Microsoft Graveyard</a>，其中包含了 184 个条目，这里我们可以看到 Kinect、Zune、Skype Business 等耳熟能详的东西。</p>
</li>
</ol>
<p>相对于产品翻车，架构设计方面的反复也是屡见不鲜，例如高调在 Kubernetes/Serverless/微服务等的采用上反复横跳的，因为局部通讯故障导致大面积宕机的，因为缺乏防呆措施导致多产品失效的，比比皆是。</p>
<p>大厂货还有一个常见场景就是其复杂的产品阵型，例如入户门标配了某高端门锁，进入配置菜单之后，发现这个大品牌智能锁的庞大身躯里，什么掌纹识别、WIFI 连接之类必备功能全被阉割了——像不像各种软件各种解决方案的免费版付费版专业版企业版？</p>
<h2 id="heading-5peg57q572r5lyg5awh4ocu4ocu5l6d6lww5zkm5yw85a65">无线网传奇——依赖和兼容</h2>
<p>新小区是有现代味儿的——全屋 WIFI。收楼时候大概看了下，客厅主卧都有 AP 面板，虽然客厅 AP 奇怪的放在电视墙上，注定被遮挡；天花没走网线，吸顶 AP 要自行布线。AC 是某捷的小商版本，已经退市。AP 面板是最精彩的——是施耐德的，我当时想，施耐德面板大概是某捷的帖牌吧。弱电箱没电插座，网线没标注这都是小事了。</p>
<p>等到我把宽带拉进来，问题出现了——宽带师傅只管宽带网入户，并不会管 ACAP 配置的，只好出钱让他帮我把所有房间的网线测一遍，不通的网口重做一遍水晶头，然后开始了我苦难的配网过程。我先入为主，觉得开发商的初始配置应该不会有兼容性问题，又不好意思求助——咱是搞 IT 的啊。最终求助物业维保，一问三不知。但是几番催促之下，给了个供应商的联系人电话，咨询之后知道了——这俩牌子不存在 OEM 关系，的确是不匹配的，要么自购 AP、要么自购 AC。无奈之下，海鲜市场弄了几个 AP 替换掉，总算过上了全屋无死角的现代生活。</p>
<blockquote>
<p>另外，某捷的 ACAP 配置，是要有互联网连接的。</p>
</blockquote>
<p>厨房有个非常神经病的设计——洗菜盆下有一条动不得的水泥粱，导致盆下空间只有 30 厘米，而通常情况下，处于垃圾处理器需要 40 厘米左右的高度，还好搜到某小品牌，机身高度 20 厘米，勉强可以塞进去。</p>
<p>在 IT 项目交付时，经常面临的一个问题就是<strong>依赖/配套关系</strong>，例如 Kubernetes 对 CRI、操作系统等的依赖、或者业务应用中的东西向、南北向依赖等，局部组件的不兼容替换或升级，稍有不慎就可能引发事故。</p>
<h2 id="heading-5aw955yl5zkm5aw955so">好看和好用</h2>
<p>小区的停车场入口，环绕很多灯带，如果读者走过白云机场的那个时光隧道，大概就是类似的效果，可惜这个停车场的铺装——雨天必打滑，配合进出一体的出入口设计，所有车道双向通行，雨天的地库会车，绝对刺激；如果是弯道会车，那就更过瘾了。</p>
<p>交付时候部署了大量的开关面板，很有酒店风格，收房时候看到这一片一片的金色开关，虽然感觉有点俗，不过我倒也不是讨厌金子的人，就随它去了。入住了才发现不仅面板是金色的——字也是金色的。</p>
<p>电视柜也摆了个乌龙——电视位全包围，上下均没有打孔，我可怜的 Switch、NAS 什么的全都连不上，只好完工之后再打孔了事。</p>
<p>到系统交互的过程中，面对不好用、但是好看的交互，我八成会给出更低的评价。</p>
<h2 id="heading-5asa5l6b5bqu5zwg55qe5zci5l2c5zkm546w5zy6566h55cg">多供应商的合作和现场管理</h2>
<p>五一期间发现空调面板无法控制空调，报障后开始了漫无边际的拉扯过程。过程涉及参与方和分工：</p>
<ul>
<li><p>某利：大概可以视作乙方总包，负责客户接口以及任务下发</p>
</li>
<li><p>某米：某利选择其进行全屋网络布线、开关面板和空调网关</p>
</li>
<li><p>某下：空调供应商</p>
</li>
<li><p>某哥：橱柜和油漆总包。</p>
</li>
</ul>
<p>按照这种合作场景，我采取了专家会诊，谁不来就怪谁的策略，展开排查。</p>
<ul>
<li><p>Round 1：</p>
<ul>
<li><p>某利认为，是因为橱柜安装过程搞坏了开关，因此责任在某哥。</p>
</li>
<li><p>我：拉通某利和某哥，先不要管花费——定责要真凭实据</p>
</li>
<li><p>结果：无</p>
</li>
</ul>
</li>
<li><p>Round 2：</p>
<ul>
<li><p>我：拉通某利和某米</p>
</li>
<li><p>某米：替换了可能有问题的面板</p>
</li>
<li><p>结果：无</p>
</li>
</ul>
</li>
<li><p>Round 3：</p>
<ul>
<li><p>我：拉通某利，某米，某下和某哥——说线坏了咱就飞线、说零件坏了咱就现场替换，堵住门口，不定位不放人。</p>
</li>
<li><p>结果：某米有两个开关失灵，替换后解决。</p>
</li>
</ul>
</li>
</ul>
<p>整个过程耗时一个月，看得出，总包对供应商支持毫无控制力，除了传话和沟通，基本处于无能状态。这在 IT 项目现场，一个可以通过替换来解决的问题，能拖到一个月，完全不可想象。</p>
<h2 id="heading-5pm66io95a625bgf55qe5a6j5ywo">智能家居的安全</h2>
<p>前文提高某利这个小区，全面采用了某米的智能家居硬件和施工，然而对非专业业主来说，问题才刚刚开始：</p>
<ul>
<li><p>交付时提供的网络相关条件：</p>
<ul>
<li><p>各房间网口面板：网线未标记，交付时部分无法连通，没有吸顶 AP 位置</p>
</li>
<li><p>两个 AP 面板：品牌不兼容，其中一个在电视之后，严重影响可用性</p>
</li>
<li><p>一个某捷的 PoE/AC：必须宽带入户之后才能完成配置</p>
</li>
</ul>
</li>
<li><p>交付时提供的未安装智能家居硬件：两个某米网关，一个天然气检测，未安装。</p>
</li>
<li><p>初始化仅仅对开关和空调进行了匹配，没有在米家进行纳管操作。</p>
</li>
</ul>
<p>结果是怎样呢？我一天在新房里走了八千多步，标记了每条网线，将所有开关等设备纳管到米家里。后来我知道，某米提供了纳管的收费服务：仅需三百。AP 更换和安装也有对应的服务，粗略算了一下，一单大概也是三百块。</p>
<p>那可能有人要说——贱人就是矫情，不用米家，不搞智能又不是用不了。我本来也是这么想的，直到我把能搜索到的所有设备加入米家后，发现我<strong>纳管了邻居的空调和部分开关</strong>，也就是说，如果没有主动将这些设备管理起来，那么你家的设备就处在欢迎来玩的状态，尤其是空调网关这种母设备，被误开关还是个挺刺激的事情。</p>
<h2 id="heading-5bc5aow">尾声</h2>
<p>最终战果：</p>
<ul>
<li><p>某利：空调原因，拖了我 N 多天工期，诊断过程几乎刮花了所有的空调控制面板，某利的甩锅可以说是非常成功，我认为应该打 A。</p>
</li>
<li><p>某米：多换了一个开关面板。</p>
</li>
<li><p>我：咬牙吞下伤痕累累的面板，解除了对邻居空调的控制，避免侵犯隐私。</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[【译】谷歌：没有平台支撑会浪费 65% 的开发时间]]></title><description><![CDATA[新的研究结果表明，平台工程能够挽回开发人员浪费的这 65% 的时间。而人工智能的集成，正在成为业务成功的关键。
十几年里，谷歌数以万计的软件工程师，在公司庞大而灵活的应用程序开发环境中，利用平台工程技术创造并简化了他们的创新工作。
这种精细的内部 IT 环境仍然是谷歌专业软件开发的秘密武器，为谷歌带来了巨大的业务灵活性和成功。
有了这种成功经验，Google 云鼓励其它公司也能够在平台工程中获得的经验和创造力，从而为自己的内部平台带来类似的进步和发展。
受 Google 云委托，ESG 进行了一...]]></description><link>https://blog.fleeto.us/65</link><guid isPermaLink="true">https://blog.fleeto.us/65</guid><category><![CDATA[Platform Engineering ]]></category><category><![CDATA[google cloud]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Sun, 01 Jun 2025 04:16:11 GMT</pubDate><content:encoded><![CDATA[<p>新的研究结果表明，平台工程能够挽回开发人员浪费的这 65% 的时间。而人工智能的集成，正在成为业务成功的关键。</p>
<p>十几年里，谷歌数以万计的软件工程师，在公司庞大而灵活的应用程序开发环境中，利用平台工程技术创造并简化了他们的创新工作。</p>
<p>这种精细的内部 IT 环境仍然是谷歌专业软件开发的秘密武器，为谷歌带来了巨大的业务灵活性和成功。</p>
<p>有了这种成功经验，Google 云鼓励其它公司也能够在平台工程中获得的经验和创造力，从而为自己的内部平台带来类似的进步和发展。</p>
<p>受 Google 云委托，ESG 进行了一项研究，对全球约 500 名 IT 专业人士和开发人员进行调研，询问他们对平台工程的看法和印象，以及平台工程对他们业务的影响。最终得出长达 38 页的报告：<a target="_blank" href="https://cloud.google.com/resources/content/google-cloud-esg-competitive-edge-platform-engineering?e=48754805">《借助平台工程构建竞争优势：战略指南》</a>。</p>
<p>根据报告内容，55% 受访者声称支持平台工程；然而只有 27% 的受访者表示。他们的绝大多数开发团队已经完全拥抱了平台工程的工具、流程和文化。90% 受访者希望更多开发者能够得到平台工程的支持，同时 85% 的组织认为他们的开发者非常依赖平台工程。</p>
<p>ESG 主任分析师 <a target="_blank" href="https://www.linkedin.com/in/torstenvolk/">Torsten Volk</a>，也是这份报告的作者告诉 TSG：“平台工程的要义是让所有人更好地协同工作，这里说的所有人包括系统、运维、开发、SRE 等角色”。平台工程让开发者更容易聚焦在开发工作上，而不是陷入到在平台中管理、更新和补丁等工作中——这应该是系统管理员的责任。</p>
<p>Volk 指出，平台工程将开发人员从耗时的软件工具维护任务中解放出来，从而真正地节省了公司的开支——开发人员的主要任务是为公司构建应用和价值，偏离这一任务，势必会造成资金损失。</p>
<p>“几乎在每次参与线上研讨会的时候，我都会展示同一张幻灯片，这里说的就是开发者会在本应属于平台工程范畴内的工作上浪费 65% 的时间”，Volk 认为，平台工程已经不再是一个可有可无的选项。</p>
<p>“在当代，这 65% 的错配，代表着巨大的经济利益”，Volk 如是说，“这 65% 的损失让我非常在意。这意味着，十万块的开发投入，却只得到三万五千块的软件价值。你难道不想这十万块都花在应用开发上面吗？”</p>
<p>Volk 认为，平台工程对开发者的生产力产生的提升，不论何种规模的公司，都能从中获益。“毫无疑问的，没有谁乐于承受这 65% 的生产力损失，”</p>
<p>Volk 也有软件开发的背景。这种价值的损失，正是他促成这次研究的原因之一。他说：“作为开发人员，我面临过这种局面，知道这其中的糟糕之处，也是我热衷于修复问题的动力所在”。</p>
<h2 id="heading-google">Google 为什么要做这个研究</h2>
<p>本次研究在一月发表，Google 希望对平台工程的成熟度进行度量和调查，以及企业在采用和扩张平台工程时所需要进行的工作。这项研究也试图了解企业使用平台工程的方式、在这个过程中的地位，以及如何产生更大影响。</p>
<p>Google 的内部平台工程，优势之一就是其可扩展性。这一优势让公司能够在各种创新和项目中使用平台，每家公司都会有不同的流水线。</p>
<p>在 Google Cloud 博客上一篇<a target="_blank" href="https://cloud.google.com/blog/products/application-modernization/new-platform-engineering-research-report">关于 Google/ESG 研究结果的文章</a>里，作者产品营销经理 <a target="_blank" href="https://www.linkedin.com/in/ninggeca/">Ning Ge</a> 和公司高级产品经理 <a target="_blank" href="https://www.linkedin.com/in/davebartoletti/">Dave Bartoletti</a> 写道，平台工程已经超越企业（采用）的临界点，对企业来说，这不再是可有可无的一种投资。</p>
<p>Ge 和 Bartoletti 写道，尽管许多公司已经在使用平台工程，但仍有更多工作要做。他们写道，企业要想在平台工程方面取得成功，必须采取的措施包括：促进平台工程师和其他团队之间的密切合作，使他们保持一致；采用平台即产品的方法，提供清晰的路线图并保持有效的反馈回路；通过明确的指标（如部署频率、故障恢复时间和变更准备时间）来衡量绩效，从而监控项目的成功。</p>
<p>Ge 和 Bartoletti 继续说：“值得注意的是，虽然许多组织已经开始了平台工程之旅，但只有 27% 的采用者在实践中完全整合了这三个关键要素，这表明还有进一步改进的重要机会。”</p>
<h2 id="heading-5bmz5yw5bel56il5yk5yw25a55lq65bel5pm66io95bqu55so55qe5lu35yc8">平台工程及其对人工智能应用的价值</h2>
<p>Ge 和 Bartoletti 写道：“耐人寻味的是，86% 的受访者还认为平台工程对于实现人工智能的全部商业价值至关重要。与此同时，绝大多数公司将人工智能视为推进平台工程的催化剂，94% 的企业认为人工智能对平台工程的未来 <code>至关重要</code> 或 <code>重要</code>。</p>
<p>研究报告指出，平台工程的其他优势还包括：通过培养积极的开发人员体验，提高员工满意度，吸引和留住人才，从而直接影响公司文化。加快软件应用上市，是采用平台工程的另一个好处，71% 的领先采用者表示，他们的软件上市已经大大提速；而在不太成熟的采用者中，只有 28% 的人这么认为。</p>
<p>Google/ESG 的研究还发现了一个有趣的现象，那就是大多数公司都没有独立开展平台工程计划。</p>
<p>报告总结说，虽然 96% 的受访企业正在利用开源工具构建开发者平台，但其中 84% 的企业正在与外部供应商合作管理和支持其开源环境。</p>
<p>Ge 和 Bartoletti 写道：“与第三方或云合作伙伴共同管理的平台可以从更高程度的创新中获益。拥有共同管理平台的企业平均将 47% 的开发人员生产时间用于创新和实验，而那些倾向于由内部员工管理平台的企业仅将 38% 的时间用于创新和实验”。</p>
]]></content:encoded></item><item><title><![CDATA[2025 年基础设施即代码（IaC）状况报告]]></title><description><![CDATA[原文：[The State of IaC 2025](https://www.firefly.ai/state-of-iac-2025?)


对于 IaC 采用、成熟度和影响力的年度调查

执行摘要
对于云从业者来说，IaC 年度状态报告的重要性正在逐步凸显，该报告帮助云从业者应对多云环境的复杂性、云基础设施管理和不断变化的 IaC 工具。
今年，我们调查了数百名专业人士，并整合了他们的反馈，以帮助我们评估、记录并塑造 IaC 和云管理的未来。
以下是我们 2025 年的主要发现。

云变得越...]]></description><link>https://blog.fleeto.us/state-of-iac-2025-by-firefly</link><guid isPermaLink="true">https://blog.fleeto.us/state-of-iac-2025-by-firefly</guid><category><![CDATA[#IaC]]></category><category><![CDATA[Terraform]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Fri, 09 May 2025 03:33:58 GMT</pubDate><content:encoded><![CDATA[<p>原文：[<strong>The State of IaC 2025</strong>](<a target="_blank" href="https://www.firefly.ai/state-of-iac-2025">https://www.firefly.ai/state-of-iac-2025</a>?)</p>
<hr />
<blockquote>
<p>对于 IaC 采用、成熟度和影响力的年度调查</p>
</blockquote>
<h2 id="heading-5omn6kgm5pgy6kab">执行摘要</h2>
<p>对于云从业者来说，IaC 年度状态报告的重要性正在逐步凸显，该报告帮助云从业者应对多云环境的复杂性、云基础设施管理和不断变化的 IaC 工具。</p>
<p>今年，我们调查了数百名专业人士，并整合了他们的反馈，以帮助我们评估、记录并塑造 IaC 和云管理的未来。</p>
<p>以下是我们 2025 年的主要发现。</p>
<hr />
<p>云变得越来越复杂，多云、多 IaC 变得更加普遍。</p>
<ul>
<li><p>68% 的公司使用多云环境</p>
</li>
<li><p>多 IaC 成为常态，约 57% 受访者表示正在使用两个或者更多的 IaC 框架</p>
</li>
</ul>
<hr />
<p>绝大多数受访者都已开始使用 IaC，但是云资源被完全代码化的的案例极少。</p>
<p>89% 的组织采用了 IaC，使用代码定义全部基础设施的却只有约 6%</p>
<hr />
<p>Terraform 仍占据统治地位，但是 OpenTofu 正在高歌猛进。</p>
<ul>
<li><p>Terraform 占据统治地位。Terraform 坐拥 62% 的市场份额，但是只有 47% 的受访者计划未来使用 Terraform。</p>
</li>
<li><p>OpenTofu 涨势良好，然而仅有 5% 的受访者表示已经完成从 Terraform 到 OpenTofu 的迁移，另外有 6% 受访者计划明年进行迁移。</p>
</li>
</ul>
<hr />
<p>使用 IaC 的三大益处之一就是漂移管理，但大多数方法只是被动的和高度人工化的。</p>
<ul>
<li><p>环境的持续性和标准化是防止漂移的关键，在 2025 年调查中，这个点被评为 IaC 优势的前三名。27% 受访者认为这是 IaC 最大的优势。</p>
</li>
<li><p>虽然漂移管理是个重点，但是只有不足 1/3 的组织对其进行主动监控和配置恢复。</p>
</li>
</ul>
<hr />
<p>受访者对 AI 云管兴趣浓厚，但是态度谨慎。</p>
<ul>
<li><p>17% 的团队已经在云运维过程中使用 AI 驱动的能力</p>
</li>
<li><p>另外 41% 团队计划在半年内使用 AI 或者正在积极探索解决方案。</p>
</li>
</ul>
<hr />
<h2 id="heading-2025-iac">2025 年，绝大多数云从业者还在追赶 IaC</h2>
<p>IaC 得到了广泛采用，但是 100% （基础设施）代码化的屈指可数。</p>
<pre><code class="lang-mermaid">xychart-beta
    title "IaC Adoption Statistics (2025)"
    x-axis ["IaC adoption", "Fully Codified Cloud"]
    y-axis "Percentage (%)" 0 --&gt; 100
    bar [89, 6]
</code></pre>
<p>决定采用 IaC 很容易，但是数据表明，要达到 100% 的 IaC 覆盖，则需要专项的资源和工具。云工程师认可 IaC 的价值，并已经开始从 IaC 中取得收益。</p>
<p>然而 IaC 的成熟之路上，还是充满挑战。从业者们在管理云基础设施时，面临的最大问题包括技能缺陷（团队要寻求自动化和规范从而打破知识壁垒），工具混乱，并且 IaC 难于覆盖到存量和传统资源。这些问题又会导致后续的管线管理困难。</p>
<h3 id="heading-iac">IaC 的五个最大优势</h3>
<ol>
<li><p><strong>持续性</strong> ：确保环境配置不会漂移</p>
</li>
<li><p><strong>可靠性和稳定性</strong></p>
</li>
<li><p><strong>部署效率</strong>：更快的资源供给</p>
</li>
<li><p><strong>治理和安全</strong></p>
</li>
<li><p><strong>不可变</strong></p>
</li>
</ol>
<p>另外，65% 的受访者认为最近两年的云变得复杂了，还有 27% 的受访者表示最近两年并没有发生变化。</p>
<p>虽然受访者没有将安全列为首位，但是 61% 的受访者表示安全/合规风险正在随着云规模的扩大而扩大。</p>
<pre><code class="lang-mermaid">xychart-beta
    title "Top 3 Hurdles to Managing Cloud Infrastructure with IaC"
    x-axis ["缺乏有技能的工程师", "工具碎片化、复杂度和成本", "IaC 的存量资源覆盖"]
    y-axis "Percentage (%)" 0 --&gt; 50
    bar [41, 38, 34]
</code></pre>
<p>上图表明，虽然有团队已经面临并觉察了更多的风险，但是还没来得及建设正式的治理体系来进行应对。有些团队可能已经面临停机风险，同时缺乏恢复手段，甚至这些团队还没能觉察这些问题。</p>
<p>过去两年，云管理难度并未降低。存在几个关键因素。</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>因素</td><td>保持不变 (%)</td><td>变得更难 (%)</td><td>变得更容易 (%)</td></tr>
</thead>
<tbody>
<tr>
<td>复杂性/知识要求</td><td>20</td><td>65</td><td>15</td></tr>
<tr>
<td>时间要求</td><td>25</td><td>55</td><td>20</td></tr>
<tr>
<td>成本</td><td>15</td><td>70</td><td>15</td></tr>
<tr>
<td>安全和合规风险</td><td>10</td><td>75</td><td>15</td></tr>
</tbody>
</table>
</div><p>随着云弹性和灾难恢复基础设施变得越来越重要，企业转向 laC，将其作为云基础设施备份和恢复解决方案的基础层。</p>
<p>接下来将深入这次调查中的显著亮点。</p>
<h2 id="heading-terraform">Terraform 的统治地位正在受到削弱和威胁</h2>
<p>Terraform 虽然保持了市场份额，然而 IaC 的权利更迭正在发生。</p>
<pre><code class="lang-mermaid">xychart-beta
    title "IaC 框架多样化上升"
    x-axis ["Terraform", "OpenTofu", "Pulumi", "CloudFormation", "Crossplane"]
    y-axis "Percentage (%)" 0 --&gt; 80
    bar "Currently use" [60, 20, 20, 40, 20]
    bar "Plans for future use" [40, 10, 10, 20, 10]
</code></pre>
<p>市场正在对从 Terraform 迁移到 OpenTofu 表现出兴趣</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>类别</td><td>百分比 (%)</td></tr>
</thead>
<tbody>
<tr>
<td>无计划从 Terraform 迁移</td><td>47</td></tr>
<tr>
<td>等待 OpenTofu 更成熟</td><td>17</td></tr>
<tr>
<td>评估 OpenTofu</td><td>13</td></tr>
<tr>
<td>其他计划</td><td>12</td></tr>
<tr>
<td>在未来 12 个月内计划迁移</td><td>6</td></tr>
<tr>
<td>已迁移到 OpenTofu</td><td>5</td></tr>
</tbody>
</table>
</div><p>绝大多数调研对象都正在使用 Terraform，但是其统治地位已经有了动摇迹象：12% 使用了 OpenTofu，造成这一局面的一个重要原因就是近期 Terraform 授权的变化。27% 的受访者正在计划未来使用 OpenTofu。在这些正在从 Terraform 切换到 OpenTofu 的案例中，约 5% 已经完成了迁移，另外约 6% 计划在未来 12 个月内启动迁移。Pulumi 和 Crossplane 也得到了 更多关注。</p>
<p>很明显，社区正在积极的寻找替代品，这也意味着工程师需要面对多个 IaC 框架。但是，虽说 2025 年，IaC 工具的多样性趋势已经明显，我们还是要继续观察，这种多样性会引发更多创新，还是造成更多的工具碎片。</p>
<p>尽管如此，IBM 收购 Hashicorp，还是给市场带来了一定的确定性一-至少目前是这样。虽然有人认为这将标志着 Terraform 的终结，但对于企业用户来说，风险规避是最重要的，为了安全，他们不会立即从 IBM 这样的市场巨头这里叛逃。</p>
<h3 id="heading-5zkm5y675bm055u45qu">和去年相比</h3>
<p>Terraform 仍然雄踞在王座之上，然而只有 47% 的团队计划未来继续使用 Terraform。显而易见，OpenTofu 的热度急剧上升。不过半数组织并没有考虑使用像 Crossplane 这样的基于 Kubernetes 的 IaC Operator。这个概念在处于早期阶段，至少在加入 Kubernetes 控制器的成本和收益之间得到证实之前，这种思路尚属前途未卜，这也正是对 <code>Kubernetes 包一切</code>的证明过程。</p>
<h2 id="heading-iac-cicd">多 IaC 的新常态需要自动化的 CICD</h2>
<p>除了多 IaC 之外，多云也处于上涨阶段。86% 的公司运行在多云之上。</p>
<blockquote>
<p>根据 Firefly 的用户数据，我们的客户，平均每个租户中有 93 个云账号。这种情况证明了用多账号来简化部门或者项目环境的趋势，但是这种方式进一步提升了对整个组织的成本、透明度以及最佳实践进行管理的难度。</p>
</blockquote>
<p>面对着这样的复杂性，手工操作越发难以为继，工具碎片化的问题也更为凸显。这样就要求实践层面做出改变，尤其是面对新的基础设施部署的时候。自动化优先的 Pipeline 自然就成了新的标准。</p>
<p>2025 年，使用 CI/CD 或者 GitOps 流水线进行基础设施交付的比例已经升高到约 59%，成为主流方案。</p>
<p>2024 年，手工本地运行 IaC 的比例是 30%，2026 年，这一比例降低到了 24%。</p>
<h3 id="heading-5zkm5y675bm055u45qu-1">和去年相比</h3>
<p>IaC 自动化流水线得以广泛应用。多云已成事实，但是对多数场景来说，聚焦在两个主要供应商是一个可能的趋势。另外 2025 年，自动化和 GitOps 风格的交付，被受访者认为是 IaC 流水线的首要能力。这表明 DevOps 团队希望能够最小化 IaC 过程中的手工步骤。</p>
<h2 id="heading-5ryc56e7566h55cg77ya5luo5lqh576k6kgl54mi5yiw5paz5pwm5py65ywi">漂移管理：从亡羊补牢到料敌机先</h2>
<pre><code class="lang-mermaid">pie title 漂移管理策略分布
    "主动（持续监控并立即修复）" : 30
    "反应性（仅在问题出现时，或定期/临时检查）" : 53
    "无漂移管理措施" : 17
    "自动化漂移工具" : 8
</code></pre>
<p>2025 年，云治理活动中的配置漂移问题是一个主要的关注点。这个问题在 2024 年是较少被关注的。这是 IaC 的最大优势之一。然而多数从业者依旧冒着放过机会的风险，走在错误的道路上。</p>
<p>目前，主动采取措施（持续监控和自动恢复）面对配置漂移的组织还不到 1/3。其余组织都是被动参与：只有出现问题的时候才发现配置漂移，或者只在某些时候进行一些 <code>ad-hoc</code> 的检查。甚至有 17% 的受访者完全没有偏移检测。这意味着基础设施可能会长期处于未同步的未知状态之中。</p>
<p>发现漂移之后，恢复是比较慢的。40% 的反馈表明需要数天甚至数周来进行修复。2024 年以来，解决速度还是有些改善的，有些组织已经有了偏移检测能力。但是总的说来，仅有约 8% 的用户具备自动修复漂移的能力，手动修复仍是主流。</p>
<h3 id="heading-5zkm5y675bm055u45qu-2">和去年相比</h3>
<p>IaC 的关键能力/优势之一就是更好的漂移管理。从前面的手工修复迁移的数字来看，很多团队还处在被动灭火的阶段。有些组织甚至还没有锁定账号（允许控制台访问）。这种情况表明，尽管了解漂移的危害（和其中的机会），从业者还会牺牲敏捷性来换得控制力。</p>
<h2 id="heading-ai">认可 AI 的潜力，但是采用缓慢</h2>
<p>尽管尚未普及，但人工智能正在进入云基础设施管理领域。虽然还只是在早期采用阶段，云从业者也基本认识到人工智能的潜力。那些早期投资的人将具备获得竞争优势的潜力。</p>
<p>约 17% 的团队已经在云运维工作中使用 AI 驱动的能力（例如基于 AI 进行成本优化或者为 IaC 生成代码）。另外 41% 团队正在积极探索或者计划在未来 6 个月内采用 AI 助手。</p>
<p>余下的 42% 没有用 AI 管理基础设施的打算。并且没有团队声明使用完全自主的 AI 管理基础设施。</p>
<p>这种背离表明了行业对 AI 是好奇的，但是还在早期采用阶段，很大程度上，这是一个试验 AI 的阶段。</p>
<h3 id="heading-5zkm5y675bm055u45qu-3">和去年相比</h3>
<p>趋势表明，虽然对于 AI 的兴趣和试验都在增加，然而 AI 尚未在 IaC 工作流程中产生重大影响。在 2024 年，当被问及“人工智能是否影响了您的 IaC 采用和实践？”时，大多数人回答“没有”或“尚未”。到 2025 年：调查将问题重新表述为“您是否使用人工智能功能来控制您的云基础设施？”，14% 的人给出了肯定的回答，当被问及哪些人工智能功能对 IaC 最有价值时，最流行的答案包括自动合规和智能漂移检测。这表明了 AI 可以提供帮助的愿望清单，当然，实际采用还处于萌芽阶段。</p>
<h2 id="heading-2026">2026 展望</h2>
<p>根据 2025 年的调研结果，绝大多数公司都有采用 IaC 的意愿，但是因为种种原因，他们无法完全地采用和拥抱 IaC。报告显示 IaC 正在走向成熟，机会多多；但问题也是存在的，例如薄弱的偏移管理和缓慢的 AI 接入，这都影响了推进的速度。Terraform 的统治地位受到威胁。另外自动化优先的流水线是成功的核心要素。</p>
<p>2026 年会怎样？</p>
<ul>
<li><p>为了驯服云的复杂性，涌现更多的新方法，可能会出现云供应商的聚焦和自动化水平的提高。</p>
</li>
<li><p>Terraform 的市占率在下降，但仍然还是第一名的 IaC 解决方案。IBM 收购，让企业用户更有信心。</p>
</li>
<li><p>不可变基础设施的理念继续发扬光大，这是因为从业者们已经意识到了这一理念在配置偏移场景上的价值。</p>
</li>
<li><p>更多的自动化和 AI 助手，帮助工程师跨越技术壁垒（例如用 AI 发现不合规的 IaC 变更意图，或者识别并纠正配置偏移——像 Firefly 一样）。</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[将 Kubernetes 服务注册为 MCP Tools]]></title><description><![CDATA[前些天看到阿里云的一篇文章《Nacos 发布 MCP Registry，实现存量应用接口“0改动”升级到 MCP 协议》，深受启发，用服务注册发现结合网关设施，将存量服务转换为 MCP 工具的玩法，能非常有效地将存量服务装进 MCP 的新瓶子。那么按照我之前发表的《MCP 是一座桥》一文的思路，是不是可以更进一步，去除对特定厂商的依赖，用更通用的方式实现 MCP 的快速上车呢？下面讲讲我的尝试。
太长不看
总体流程如下图所示：
sequenceDiagram
    participant Us...]]></description><link>https://blog.fleeto.us/jiang-kubernetes-fu-wu-zhu-ce-wei-mcp-tools</link><guid isPermaLink="true">https://blog.fleeto.us/jiang-kubernetes-fu-wu-zhu-ce-wei-mcp-tools</guid><category><![CDATA[mcp]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[llm]]></category><category><![CDATA[cloud native]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Thu, 24 Apr 2025 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>前些天看到阿里云的一篇文章《Nacos 发布 MCP Registry，实现存量应用接口“0改动”升级到 MCP 协议》，深受启发，用服务注册发现结合网关设施，将存量服务转换为 MCP 工具的玩法，能非常有效地将存量服务装进 MCP 的新瓶子。那么按照我之前发表的《MCP 是一座桥》一文的思路，是不是可以更进一步，去除对特定厂商的依赖，用更通用的方式实现 MCP 的快速上车呢？下面讲讲我的尝试。</p>
<h2 id="heading-5asq6zw5lin55yl">太长不看</h2>
<p>总体流程如下图所示：</p>
<pre><code class="lang-mermaid">sequenceDiagram
    participant User as MCP Client
    participant MainPy as MCP Server
    participant K8sAPI as Kubernetes API Server

    User-&gt;&gt;MainPy: 调用 list_tools()
    MainPy-&gt;&gt;MainPy: 创建 KubernetesToolsFetcher 实例
    MainPy-&gt;&gt;MainPy: 调用 get_all_mcp_tools(namespace)
    MainPy-&gt;&gt;K8sAPI: 查找 MCP 标签服务
    K8sAPI--&gt;&gt;MainPy: 返回 Service 列表
    loop 遍历每个 Service
        MainPy-&gt;&gt;MainPy: 提取 mcptool annotation
    end
    MainPy-&gt;&gt;MainPy: 将所有合格 tool 转为 types.Tool
    MainPy--&gt;&gt;User: 返回 MCP Tool 列表
</code></pre>
<p>总的说来，就是利用 Kubernetes Service 的标签和注解进行标识，MCP Server 读取 Service 信息，将其作为 Tools 暴露给 MCP Client。</p>
<h2 id="heading-5roo5yam5yr546w55qe5a6e546w">注册发现的实现</h2>
<p>MCP 规范中，提供了 Tools 列表和调用的接口，在 Python SDK 里，通常对 Tools 的实现都是使用如下代码：</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> httpx
<span class="hljs-keyword">from</span> mcp.server.fastmcp <span class="hljs-keyword">import</span> FastMCP

mcp = FastMCP(<span class="hljs-string">"My App"</span>)


<span class="hljs-meta">@mcp.tool()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_bmi</span>(<span class="hljs-params">weight_kg: float, height_m: float</span>) -&gt; float:</span>
    <span class="hljs-string">"""Calculate BMI given weight in kg and height in meters"""</span>
    <span class="hljs-keyword">return</span> weight_kg / (height_m**<span class="hljs-number">2</span>)
</code></pre>
<p>在我们这个场景中，Tools 是动态刷新的，因此不能用这种硬编码的形式来声明，Python SDK 提供了低阶的 Server，便于我们进行更细致的能力实现。源码（<code>lowlevel/server.py</code>）中提供了创建实例、实现能力直到运行的简单介绍，例如：</p>
<pre><code class="lang-python"><span class="hljs-meta">@server.list_prompts()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_list_prompts</span>() -&gt; list[types.Prompt]:</span>
   <span class="hljs-comment"># Implementation</span>

<span class="hljs-meta">@server.get_prompt()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_get_prompt</span>(<span class="hljs-params">
   name: str, arguments: dict[str, str] | None
</span>) -&gt; types.GetPromptResult:</span>
   <span class="hljs-comment"># Implementation</span>

<span class="hljs-meta">@server.list_tools()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_list_tools</span>() -&gt; list[types.Tool]:</span>
   <span class="hljs-comment"># Implementation</span>

<span class="hljs-meta">@server.call_tool()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_call_tool</span>(<span class="hljs-params">
   name: str, arguments: dict | None
</span>) -&gt; list[types.TextContent | types.ImageContent | types.EmbeddedResource]:</span>
   <span class="hljs-comment"># Implementation</span>
</code></pre>
<p>字面意思上看，只要实现 <code>list_tool</code> 和 <code>call_tool</code>，就能动态注册工具并执行了。例如官方 README 中介绍的代码：</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> mcp.server.lowlevel <span class="hljs-keyword">import</span> NotificationOptions, Server
<span class="hljs-keyword">from</span> mcp.server.models <span class="hljs-keyword">import</span> InitializationOptions

<span class="hljs-comment"># Create a server instance</span>
server = Server(<span class="hljs-string">"example-server"</span>)


<span class="hljs-meta">@server.list_prompts()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_list_prompts</span>() -&gt; list[types.Prompt]:</span>
...

<span class="hljs-meta">@server.get_prompt()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_get_prompt</span>(<span class="hljs-params">
    name: str, arguments: dict[str, str] | None
...

async def run(<span class="hljs-params"></span>):
    async with mcp.server.stdio.stdio_server(<span class="hljs-params"></span>) as (<span class="hljs-params">read_stream, write_stream</span>):
        await server.run(<span class="hljs-params">
            read_stream,
            write_stream,
            InitializationOptions(<span class="hljs-params">
                server_name=<span class="hljs-string">"example"</span>,
                server_version=<span class="hljs-string">"0.1.0"</span>,
                capabilities=server.get_capabilities(<span class="hljs-params">
                    notification_options=NotificationOptions(<span class="hljs-params"></span>),
                    experimental_capabilities={},
                </span>),
            </span>),
        </span>)


if __name__ == <span class="hljs-string">"__main__"</span>:
    import asyncio

    asyncio.run(<span class="hljs-params">run(<span class="hljs-params"></span>)</span>)</span></span>
</code></pre>
<p>可以看到，低阶 MCP Server 实现中，需要自行处理原语的列表、读取和执行操作。如此看来在我们的场景中，只需要实现 <code>list_tools</code> 即可，例如使用如下的伪代码，查找被标记的 Service，并从 Annotation 中读取 MCP 工具定义，从而生成 MCP Tools：</p>
<pre><code class="lang-python"><span class="hljs-keyword">try</span>:
    kubeconfig_path = os.path.expanduser(<span class="hljs-string">"/Users/dummy/.kube/config"</span>)
    namespace = <span class="hljs-string">"default"</span>

    fetcher = kubernetes_tools.KubernetesToolsFetcher(kubeconfig_path)
    <span class="hljs-keyword">try</span>:
        k8s_tools = fetcher.get_all_mcp_tools(namespace)
        <span class="hljs-keyword">for</span> tool <span class="hljs-keyword">in</span> k8s_tools:
            missing_fields = [field <span class="hljs-keyword">for</span> field <span class="hljs-keyword">in</span> (<span class="hljs-string">"name"</span>, <span class="hljs-string">"description"</span>, <span class="hljs-string">"inputSchema"</span>) <span class="hljs-keyword">if</span> field <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> tool]
            <span class="hljs-keyword">if</span> missing_fields:
                logger.error(<span class="hljs-string">f"Kubernetes 工具定义缺失字段: <span class="hljs-subst">{missing_fields}</span>，内容: <span class="hljs-subst">{tool}</span>"</span>)
                <span class="hljs-keyword">continue</span>
            result.append(types.Tool(
                name=tool[<span class="hljs-string">"name"</span>],
                description=tool[<span class="hljs-string">"description"</span>],
                inputSchema=tool[<span class="hljs-string">"inputSchema"</span>]
            ))
        logger.info(<span class="hljs-string">f"从 Kubernetes 加载了 <span class="hljs-subst">{len(k8s_tools)}</span> 个工具"</span>)
    <span class="hljs-keyword">finally</span>:
        fetcher.close()
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
    logger.error(<span class="hljs-string">f"从 Kubernetes 加载工具时出错: <span class="hljs-subst">{e}</span>"</span>)
</code></pre>
<p>根据如上代码编写的 MCP Server，可以在 Client 配置中加入如下内容启动：</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"mcpServers"</span>: {
    <span class="hljs-attr">"Demo"</span>: {
      <span class="hljs-attr">"command"</span>: <span class="hljs-string">"uv"</span>,
      <span class="hljs-attr">"args"</span>: [
        <span class="hljs-string">"run"</span>,
        <span class="hljs-string">"--with"</span>,
        <span class="hljs-string">"mcp[cli]"</span>,
        <span class="hljs-string">"--with"</span>,
        <span class="hljs-string">"pyyaml"</span>,
        <span class="hljs-string">"--with"</span>,
        <span class="hljs-string">"kubernetes"</span>,
        <span class="hljs-string">"[somewhere]/main.py"</span>
      ]
    }
  },
  <span class="hljs-attr">"globalShortcut"</span>: <span class="hljs-string">""</span>
}
</code></pre>
<p>创建几个 Service，加上必要的标签和注解，例如：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">mcp-demo-service-1</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">mcp:</span> <span class="hljs-string">"true"</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-attr">mcptool:</span> <span class="hljs-string">|
      [
        {
          "name": "echo",
          "description": "Echo back the input text",
          "inputSchema": {
            "type": "object",
            "required": ["message"],
            "properties": {
              "message": {
                "type": "string",
                "description": "The message to echo"
              }
            }
          }
        }
      ]
</span><span class="hljs-attr">spec:</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">app:</span> <span class="hljs-string">mcp-demo-1</span>
  <span class="hljs-attr">ports:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
      <span class="hljs-attr">port:</span> <span class="hljs-number">80</span>
      <span class="hljs-attr">targetPort:</span> <span class="hljs-number">8080</span>
</code></pre>
<p>创建 Kubernetes 服务后，启动 MCP 客户端，例如 <code>Claude.app</code>，可以看到 Kubernetes 服务已经出现，如下图所示：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745896605037/85f5cac4-51b1-4489-96ad-046aef04c693.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-6ly5lin6io96lcd55so">还不能调用</h2>
<p>前文贴的代码里，已经展示了 <code>call_tool</code> 的能力，下一步应该就是调用了，这方面会稍显复杂，要涉及到通信、认证、加解密、封装等问题，各种 API 网关、或者 ZTM 这样的应用层产品，应该能辅助解决这类问题。</p>
]]></content:encoded></item><item><title><![CDATA[使用 Mcp 操作云服务资源]]></title><description><![CDATA[前面鼓吹 MCP 的时候，我把 MCP 形容为一座桥，大模型和存量的 IT 系统藉由 MCP 的连接，让大模型的能力能够轻松地直接作用到在线的存量系统之中。市面上出现了 API 网关/注册发现工具直接对接 MCP 的产品，也直接证明了这个新东西的吸引力。
每个公有云，都有数量庞大的 API，头部厂商还提供了对应的 CLI 工具，方便快速进行集成，对接 MCP 可以说是得天独厚了，下面就用 MCP 的 Python SDK 编写一个简单的 AWS EC2 查询，并把它集成到 Claude App ...]]></description><link>https://blog.fleeto.us/shi-yong-mcp-cao-zuo-yun-fu-wu-zi-yuan</link><guid isPermaLink="true">https://blog.fleeto.us/shi-yong-mcp-cao-zuo-yun-fu-wu-zi-yuan</guid><category><![CDATA[mcp]]></category><category><![CDATA[llm]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Mon, 07 Apr 2025 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>前面鼓吹 MCP 的时候，我把 MCP 形容为一座桥，大模型和存量的 IT 系统藉由 MCP 的连接，让大模型的能力能够轻松地直接作用到在线的存量系统之中。市面上出现了 API 网关/注册发现工具直接对接 MCP 的产品，也直接证明了这个新东西的吸引力。</p>
<p>每个公有云，都有数量庞大的 API，头部厂商还提供了对应的 CLI 工具，方便快速进行集成，对接 MCP 可以说是得天独厚了，下面就用 MCP 的 <a target="_blank" href="https://github.com/modelcontextprotocol/python-sdk">Python SDK</a> 编写一个简单的 AWS EC2 查询，并把它集成到 Claude App 中。</p>
<h2 id="heading-uv">UV</h2>
<p>MCP 官方文档中，Python 的项目初始化、依赖和运行都是用 <a target="_blank" href="https://github.com/astral-sh/uv">uv</a> 来承载的，为了方便起见，可以先把 UV 装上，安装很简单：</p>
<pre><code class="lang-bash"><span class="hljs-comment"># On macOS and Linux.</span>
curl -LsSf https://astral.sh/uv/install.sh | sh
</code></pre>
<p>macOS 中的 Homebrew 也可以直接部署 UV。</p>
<h2 id="heading-57yw56cb">编码</h2>
<p>有了 uv 之后，就可以初始化一下我们的新项目，例如：</p>
<pre><code class="lang-bash">$ uv init cloud-mcp-server
Initialized project `cloud-mcp-server` at `/Users/[xxx]/cloud-mcp-server`
$ <span class="hljs-built_in">cd</span> mcp-server-demo
$ ls -a
.git            .gitignore      .python-version README.md       main.py         pyproject.toml
</code></pre>
<p>可以看到这中间已经生成了几个主要文件，其中 <code>pyproject.toml</code> 包含了当前项目的基本信息：</p>
<pre><code class="lang-toml"><span class="hljs-section">[project]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"cloud-mcp-server"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
<span class="hljs-attr">description</span> = <span class="hljs-string">"A Sample MCP Server for AWS EC2"</span>
<span class="hljs-attr">readme</span> = <span class="hljs-string">"README.md"</span>
<span class="hljs-attr">requires-python</span> = <span class="hljs-string">"&gt;=3.13"</span>
<span class="hljs-attr">dependencies</span> = []
</code></pre>
<p>接下来要初始化我们要用到的依赖包，SDK 需要使用 <code>mcp</code> 相关的包，而要使用 AWS SDK，则需要安装 <code>boto3</code>，同样可以用 <code>uv</code> 命令实现：</p>
<pre><code class="lang-bash">$ uv add <span class="hljs-string">"mcp[cli]"</span> <span class="hljs-string">"boto3"</span>
Using CPython 3.13.2 interpreter at: /opt/homebrew/opt/python@3.13/bin/python3.13
Creating virtual environment at: .venv
Resolved 35 packages <span class="hljs-keyword">in</span> 1.29s
Prepared 7 packages <span class="hljs-keyword">in</span> 13.04s
Installed 33 packages <span class="hljs-keyword">in</span> 89ms
 + annotated-types==0.7.0
 + anyio==4.9.0
 + boto3==1.37.28
 + botocore==1.37.28
 + certifi==2025.1.31
...
</code></pre>
<p>接下来编辑 <code>main.py</code>，在其中加入一个查询 ec2 实例的 <code>tool</code>：</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> mcp.server.fastmcp <span class="hljs-keyword">import</span> FastMCP

<span class="hljs-comment"># Create an MCP server</span>
mcp = FastMCP(<span class="hljs-string">"aws-operator"</span>)


<span class="hljs-meta">@mcp.tool()</span>
<span class="hljs-comment"># 只有一个参数，region_id</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">list_ec2</span>(<span class="hljs-params">region_id: str</span>) -&gt; list:</span>
    <span class="hljs-keyword">import</span> os
    <span class="hljs-keyword">import</span> boto3
    <span class="hljs-comment"># 从环境中读取 AWS 凭据，并初始化客户端</span>
    aws_access_key_id = os.getenv(<span class="hljs-string">"AWS_ACCESS_KEY_ID"</span>)
    aws_secret_access_key = os.getenv(<span class="hljs-string">"AWS_SECRET_ACCESS_KEY"</span>)
    session = boto3.Session(aws_access_key_id=aws_access_key_id,
                            aws_secret_access_key=aws_secret_access_key)

    <span class="hljs-comment"># 调用 AWS API</span>
    ec2 = boto3.client(<span class="hljs-string">'ec2'</span>, region_name=region_id)
    response = ec2.describe_instances()
    instance_list = []
    <span class="hljs-keyword">for</span> reservation <span class="hljs-keyword">in</span> response[<span class="hljs-string">"Reservations"</span>]:
        <span class="hljs-keyword">for</span> instance <span class="hljs-keyword">in</span> reservation[<span class="hljs-string">"Instances"</span>]:
            instance_list.append(instance)
    <span class="hljs-keyword">return</span> instance_list
</code></pre>
<h2 id="heading-5a6j6kof5zkm5oq6zeu">安装和提问</h2>
<p>完成编辑后，将 MCP Server 载入 Claude App：</p>
<pre><code class="lang-bash">$ uv run mcp install \
    -f .env \
    --with boto3 main.py
[04/07/25 21:52:38] INFO     Added server <span class="hljs-string">'aws-operator'</span> to Claude config
INFO     Successfully installed aws-operator <span class="hljs-keyword">in</span> Claude app
</code></pre>
<p>然后打开 Claude App，会看到锤子图标已经出现，也能在工具列表中看到我们的 <code>list_ec2</code> 方法：</p>
<pre><code class="lang-plaintext">Available MCP tools
Claude can use tools provided by specialized servers using Model Context Protocol. Learn more about MCP.

list_ec2
From server: aws-operator
</code></pre>
<p>接下来尝试提问：</p>
<h3 id="heading-q-ec2">Q：我在欧洲有没有购买 ec2 实例？</h3>
<p>我可以帮您检查您在欧洲是否有购买EC2实例。我需要先了解您在欧洲哪个区域可能有实例。让我们来查看一下。
我将帮您检查欧洲各个AWS区域的EC2实例。AWS在欧洲有以下几个区域:</p>
<p>eu-west-1 (爱尔兰)
eu-west-2 (伦敦)
eu-west-3 (巴黎)
eu-central-1 (法兰克福)
eu-north-1 (斯德哥尔摩)
eu-south-1 (米兰)
...
根据我的查询结果，在我能够成功查询的欧洲AWS区域(爱尔兰、伦敦、巴黎、法兰克福和斯德哥尔摩)中，没有找到您的EC2实例。尝试查询米兰区域(eu-south-1)时出现了凭证验证错误。</p>
<h3 id="heading-q-ec2-ec2">Q：查找我所有在北美洲和亚洲的 EC2 实例，用表格形式列出 EC2 的关键数据</h3>
<p>...
经检查北美洲和亚洲的AWS区域，共找到2个运行中的EC2实例，详情如下：</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>区域</td><td>实例ID</td><td>实例名称</td><td>实例类型</td><td>状态</td><td>公网IP</td><td>私网IP</td><td>AMI ID</td><td>启动时间</td></tr>
</thead>
<tbody>
<tr>
<td>us-east-1</td><td>i-066d6788cf6d6b85f</td><td>us113</td><td>t2.micro</td><td>running</td><td>13.218.36.31</td><td>172.31.21.105</td><td>ami-00a929b66ed6e0de6</td><td>2025-04-07T09:01:41Z</td></tr>
<tr>
<td>us-west-2</td><td>i-07d219e7fdea42897</td><td>us2</td><td>t2.micro</td><td>running</td><td>44.243.226.237</td><td>172.31.39.36</td><td>ami-087f352c165340ea1</td><td>2025-04-07T09:02:39Z</td></tr>
</tbody>
</table>
</div><h4 id="heading-5roo5osp5lql6ag5">注意事项</h4>
<ul>
<li>在亚洲区域未发现任何实例</li>
<li>在ap-east-1区域（香港）查询时出现凭证验证错误</li>
<li>所有找到的实例均位于北美洲区域（美国东部和美国西部）</li>
<li>两个实例均使用t2.micro配置并且状态为运行中</li>
</ul>
<h2 id="heading-54s25zco">然后</h2>
<p>例子很粗陋，例如没有保护敏感数据、没有进行异常处理等。LLM 很贵，用它做编排也是非常不合理的。这里展示的主要是这样一种可能，将一些存量的关键服务接入 MCP 之后，即使是一个未经训练、微调的公共/开源大模型，也可以和我们自身的业务结合起来，发挥更接地气的大模型能力。</p>
]]></content:encoded></item><item><title><![CDATA[Mcp 是一座桥]]></title><description><![CDATA[前言
前两天刘老师吐了个槽，印象里是个问句：大家猜猜 KCD 为什么是 KCD？我觉得问得挺好的，所以作为 Kubernetes 老饼一张，我今天也来聊一点 AI 相关的事。
ChatGPT 横空出世之后，一直还是保持一点关注的，应该也交了几百刀的 AI 税了。除了聊天玩之外，也尝试使用流行的大模型解决一些实际问题，这一段时间以来，对于 AI 的有效使用大概归结成几种模式：

洗稿：当然不是抄袭的那种，我经常会将要发表的文字交给 GPT 类的东西，帮我查查错字，部分字句进行润色等。
翻译：传统翻...]]></description><link>https://blog.fleeto.us/mcp</link><guid isPermaLink="true">https://blog.fleeto.us/mcp</guid><category><![CDATA[mcp]]></category><category><![CDATA[llm]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Fri, 14 Mar 2025 16:00:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-5ymn6kia">前言</h2>
<p>前两天刘老师吐了个槽，印象里是个问句：大家猜猜 KCD 为什么是 KCD？我觉得问得挺好的，所以作为 Kubernetes 老饼一张，我今天也来聊一点 AI 相关的事。</p>
<p>ChatGPT 横空出世之后，一直还是保持一点关注的，应该也交了几百刀的 AI 税了。除了聊天玩之外，也尝试使用流行的大模型解决一些实际问题，这一段时间以来，对于 AI 的有效使用大概归结成几种模式：</p>
<ol>
<li>洗稿：当然不是抄袭的那种，我经常会将要发表的文字交给 GPT 类的东西，帮我查查错字，部分字句进行润色等。</li>
<li>翻译：传统翻译工具，包括 Deepl 在内，对于凌乱格式的文档（例如 PDF 中的胡乱换行、HTML 中的代码和标签等）都是力有不逮的，大模型对这种情况可以说是信手拈来。</li>
<li>辅助开发：函数级的代码、单元测试的编写，还有代码的阅读解释，甚至是一些配置参数的跟踪、特定功能的查找和调试，目前不管是 Windsurf 还是 Cursor 的效果都远超我的预期。</li>
<li>资料查询和整合：目前不管是 Search 还是 Research，都属于这个范畴。</li>
</ol>
<p>除了这些工具类的东西，我有没有真的把大模型的能力融入到我的实际业务之中呢？你别说还真有。</p>
<h3 id="heading-6lq57u06icb5bii5ykf">运维老师傅</h3>
<p>在运维现场，老师傅的最大价值之一就是：见多识广。然而在所有的主流大模型眼中，知名软件的日志信息毫无秘密可言。所以就随手写了个 Pipe2GPT 的小玩意，这东西现在一直在我的 Mac 和 Home Server 里呆着，随便遇到什么疑难 STDOUT/STDERR，Pipe 过去就行了。绝大多数情况下，能给出不弱于 StackOverflow 之类的结果，最重要的是说的的确是经过组织的人话，这点太重要了。</p>
<h3 id="heading-5zoe5aid5bcp5bel5yw3">哄娃小工具</h3>
<p>我有个工作流，效果是用广东话根据几个关键字生成童话故事，并使用方言 TTS 生成语音朗读给小朋友听——为保留粤语尽点绵薄之力？</p>
<h3 id="heading-6lcd5yi25zkm6kej6lcd">调制和解调</h3>
<p>其实跟翻译类似，让大模型的能力，对信息进行翻译和重整，使之生成新的信息模式，包括但不限于：</p>
<ol>
<li>从自然语言的网页，例如公告、通知等信息中，提取规范化信息，交由其它系统进一步的处理。这种应用方式非常广泛，非常适合小打小闹的做一些趁手的搜集工作。</li>
<li>云 SDK 到 IaC：就拿虚拟机来说，同样的 4 核 8G，每个厂商都提供了多种机型可选，在 Terraform 的 Provider 之中，又有各种不同的表达。而有了大模型的辅助，反倒是可以轻松地在不同厂商 SDK 格式、不同的 IaC 代码之间进行转换。</li>
</ol>
<p>...</p>
<p>然而这蹭热度的过程中，一直有些粗糙的感觉，应用侧和模型侧始终是泾渭分明、各自为战。训练练不起，对接呢，因为个人架构能力有限，每次都会因为需求的微小差异，进行大量的代码调整。尤其是和一些商业数据系统对接时，缺乏最佳实践的指导，由此产生草台班子的感觉会让人非常受挫。</p>
<h2 id="heading-mcp">MCP</h2>
<p>前不久看到了 claude MCP，感觉这高冷的大模型开始有味道了。总算可以有办法，将“传统”服务和系统，跟各种大模型能够相对规矩的对接起来。</p>
<p>MCP 是 Model Context Protocol 的缩写。官方简介称：</p>
<blockquote>
<p>模型上下文协议（MCP）是一种开放式协议，可实现 LLM 应用程序与外部数据源和工具之间的无缝集成。无论您是要构建人工智能驱动的集成开发环境、增强聊天界面，还是要创建自定义的人工智能工作流，MCP 都能提供一种标准化的方式，将 LLM 与它们所需的上下文连接起来。</p>
</blockquote>
<p>目前已经提供了 TypeScript、Python、Java 和 Kotlin 的 SDK。</p>
<p>官方提供的架构图如下所示：</p>
<p>从核心上讲，MCP 遵循客户端-服务器架构，其中主机应用程序可以连接到多个服务器：</p>
<pre><code class="lang-mermaid">flowchart LR
    subgraph "Your Computer"
        Host["MCP 客户端(Claude, IDEs, Tools)"]
        S1["MCP Server A"]
        S2["MCP Server B"]
        S3["MCP Server C"]
        Host &lt;--&gt;|"MCP Protocol"| S1
        Host &lt;--&gt;|"MCP Protocol"| S2
        Host &lt;--&gt;|"MCP Protocol"| S3
        S1 &lt;--&gt; D1[("本地数据源 A")]
        S2 &lt;--&gt; D2[("本地数据源 B")]
    end
    subgraph "Internet"
        S3 &lt;--&gt;|"Web APIs"| D3[("远端服务 C")]
    end
</code></pre>
<ul>
<li><strong>MCP Hosts</strong>: 例如 Claude Desktop、集成开发环境 (IDEs) 或希望通过 MCP 访问数据的 AI 工具</li>
<li><strong>MCP Clients</strong>: 与服务器建立一对一连接的协议客户端</li>
<li><strong>MCP Servers</strong>: 轻量级程序，通过标准化的 Model Context Protocol 提供特定功能</li>
<li><strong>本地数据源</strong>: 您计算机上的文件、数据库和服务，MCP 服务器可以安全访问它们</li>
<li><strong>远程服务</strong>: 通过网络（如 API）可访问的外部系统，MCP 服务器能与之连接</li>
</ul>
<p>从架构图中可以看到，MCP 定义了一种行为规范及其依赖的通信方式和对应的对象。LLM 客户端应用，作为 MCP Client，通过 MCP Server，和本地资源、外部服务连接起来，从而形成了完整的数据通路，让 MCP Server 所提供的数据和能力，直接在 LLM 客户端应用中得以使用。</p>
<p>MCP 中的核心概念包括用于描述原子能力的资源（Resource）和工具（Tool），用于复用提示词的（Prompt），以及能够控制文本生成的 Sampling 能力。除了这些能力之外，对于传输、安全、敏感信息等，也提出了相对完善的建议和最佳实践。因此虽然存在只能本地调用等短板，MCP 仍然不失为一个开拓 LLM 应用的一个非常有用的方向（不够好没关系，Who can who up 就是了）。</p>
<h2 id="heading-5l6l5a2q">例子</h2>
<p>官网文档里提供了一个天气预报的 Sample，这个例子很典型：从外部服务获取实时信息作为上下文在 LLM 中进行使用。这个例子分为三个部分：</p>
<ol>
<li>服务端，提供了多种语言的开发方法，其中定义了 <code>get_forcast</code> 和 <code>get_alert</code> 两个 Tool</li>
<li>客户端：如何创建 Bot 并使用前面开发的 MCP 服务器</li>
<li>claude App 中如何使用 MCP Server。</li>
</ol>
<p>例子中表达的主要“业务”就是在 LLM 中获取（美国）的天气信息，并结合 LLM 自有能力来响应用户需求。</p>
<h3 id="heading-5oq6zeu5pe25yr55sf5lqg5lua5lmi77yf">提问时发生了什么？</h3>
<ol>
<li>客户端把问题发送给 Claude</li>
<li>Claude 分析可用的工具并决定使用哪一个</li>
<li>客户端通过 MCP 服务器执行所选工具</li>
<li>结果被发回给 Claude</li>
<li>Claude 根据响应内容回答问题</li>
</ol>
<h3 id="heading-claude-app-mcp">在 claude App 中启用 MCP</h3>
<p>App 属性窗口中，Developer Tab 直接编辑 Settings，加入如下定义就可以得到：</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"mcpServers"</span>: {
        <span class="hljs-attr">"weather"</span>: {
            <span class="hljs-attr">"command"</span>: <span class="hljs-string">"uv"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"--directory"</span>,
                <span class="hljs-string">"/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather"</span>,
                <span class="hljs-string">"run"</span>,
                <span class="hljs-string">"weather.py"</span>
            ]
        }
    }
}
</code></pre>
<p>启用 Server 之后，在 claude 聊天窗口输入框右下方会出现一个 🔨 图标，点击后就可以展示当前启用 MCP Server 所提供的 Tools 了。</p>
<h2 id="heading-55sf5ocb">生态</h2>
<p>目前支持 MCP 的工具还是颇有一些的，官方列表：<code>https://modelcontextprotocol.io/clients</code></p>
<p>官方列出的示例服务：<code>https://modelcontextprotocol.io/examples</code></p>
<p><code>mcp.so</code> 中列出了超过 2000 个 MCP Server。</p>
<h2 id="heading-5bgv5pyb">展望</h2>
<p>MCP 的整体实现是较为简洁的，这一方面方便参与，另一方面就是碎片化的前兆。目前来说仅能支持本地，很大程度上消减了可能的性能和安全性问题，但是对于自动化、实时性要求来说，MCP 目前体现的能力还是不很清晰的。</p>
<p>综上，跟社区的普遍思路不太一样，个人认为 MCP 作为一个便宜（便宜坊的便宜）途径，在独占大模型环境是颇有吸引力的一种解决方案。</p>
]]></content:encoded></item><item><title><![CDATA[在 Argo workflow 中使用 OBS 进行制品传递]]></title><description><![CDATA[在所有的通用工作流中，都会有文件传递的需求，Argo workflow 中，可以通过对接外部存储来支持这一需求。下面就以华为云为例，展示一下对接对象存储的过程。
OBS 侧配置
首先在 OBS 服务中创建一个存储桶，并在控制台的用户->我的凭证->访问密钥模块中，创建一个访问密钥，并下载凭据文件，凭据文件格式大致如下所示：
User Name,Access Key Id,Secret Access Key
"myusername",Y9C3WCABCDEFG,6bHX5eHIJKLMN

Arg...]]></description><link>https://blog.fleeto.us/zai-argo-workflow-zhong-shi-yong-obs-jin-xing-zhi-pin-chuan-di</link><guid isPermaLink="true">https://blog.fleeto.us/zai-argo-workflow-zhong-shi-yong-obs-jin-xing-zhi-pin-chuan-di</guid><category><![CDATA[argo]]></category><category><![CDATA[Argo Workflow]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Tue, 11 Feb 2025 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>在所有的通用工作流中，都会有文件传递的需求，Argo workflow 中，可以通过对接外部存储来支持这一需求。下面就以华为云为例，展示一下对接对象存储的过程。</p>
<h2 id="heading-obs">OBS 侧配置</h2>
<p>首先在 OBS 服务中创建一个存储桶，并在控制台的<code>用户-&gt;我的凭证-&gt;访问密钥</code>模块中，创建一个访问密钥，并下载凭据文件，凭据文件格式大致如下所示：</p>
<pre><code class="lang-plaintext">User Name,Access Key Id,Secret Access Key
"myusername",Y9C3WCABCDEFG,6bHX5eHIJKLMN
</code></pre>
<h2 id="heading-argo-workflow">Argo workflow 配置</h2>
<p>使用文件中的 Access Key 和 Secret Access Key ，在<strong>Workflow 所在的 Namespace 中</strong>创建 Kubernetes Secret。例如：</p>
<pre><code class="lang-plaintext">$ kubectl create secret generic s3-secret \
    --from-literal accessKey=Y9C3WCABCDEFG \
    --from-literal secretKey=6bHX5eHIJKLMN
...
</code></pre>
<p>接下来需要修改 Argo workflow 的配置文件，加入对制品的支持内容：</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">artifactRepository:</span> <span class="hljs-string">|
    archiveLogs: true
    s3:
      endpoint: obs.[Region ID].myhuaweicloud.com
      bucket: [Bucket Name]
      region: cn-north-4
      insecure: false
      keyFormat: "my-artifacts\
        /{{workflow.creationTimestamp.Y}}\
        /{{workflow.creationTimestamp.m}}\
        /{{workflow.creationTimestamp.d}}\
        /{{workflow.name}}\
        /{{pod.name}}"
</span>
      <span class="hljs-attr">accessKeySecret:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">s3-secret</span>
        <span class="hljs-attr">key:</span> <span class="hljs-string">accessKey</span>
      <span class="hljs-attr">secretKeySecret:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">s3-secret</span>
        <span class="hljs-attr">key:</span> <span class="hljs-string">secretKey</span>
      <span class="hljs-attr">useSDKCreds:</span> <span class="hljs-literal">false</span>
</code></pre>
<p>上面的配置大致解释一下：</p>
<ol>
<li><p>在 OBS 中存储 Pod 日志</p>
</li>
<li><p>使用了华为云北京四 Region 的 OBS 端点。</p>
</li>
<li><p>需要引用前面创建的存储桶名称</p>
</li>
<li><p>使用加密方式进行访问</p>
</li>
<li><p>制品的存储路径模板为：<code>my-artifacts/实例创建时间（年/月/日）/实例名称/步骤所在 Pod 名称/</code></p>
</li>
<li><p>Access Key 引用 Kubernetes Secret 中名为 <code>s3-secret</code> 的 <code>accessKey</code> 字段</p>
</li>
<li><p>Secret Key 引用 Kubernetes Secret 中名为 <code>s3-secret</code> 的 <code>secretKey</code> 字段</p>
</li>
</ol>
<p>将上述内容加入 Argo workflow 所在命名空间的 <code>workflow-controller-configmap</code>。</p>
<h2 id="heading-5zcv5yqo5bel5l2c5rwb">启动工作流</h2>
<p>尝试启动一个使用制品能力的工作流，清单内容来自<code>https://argo-workflows.readthedocs.io/en/latest/walk-through/artifacts/</code>。</p>
<p>这个流程模板中定义了两个工步：</p>
<h3 id="heading-55sf5oiq5yi25zob">生成制品</h3>
<pre><code class="lang-yaml"><span class="hljs-string">...</span>
<span class="hljs-attr">outputs:</span>
  <span class="hljs-attr">artifacts:</span>
  <span class="hljs-comment"># generate hello-art artifact from /tmp/hello_world.txt</span>
  <span class="hljs-comment"># artifacts can be directories as well as files</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">hello-art</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">/tmp/hello_world.txt</span>
</code></pre>
<p>上述代码中，将 <code>/tmp/hello_world.txt</code> 内容作为制品，并命名为 <code>hello-art</code>。</p>
<h3 id="heading-6k75yw5yi25zob">读取制品</h3>
<pre><code class="lang-yaml"><span class="hljs-attr">inputs:</span>
  <span class="hljs-attr">artifacts:</span>
  <span class="hljs-comment"># unpack the message input artifact</span>
  <span class="hljs-comment"># and put it at /tmp/message</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">message</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">/tmp/message</span>
</code></pre>
<p>这段代码则是获取输入中名为 <code>message</code> 的制品，并解压到 <code>/tmp/message</code> 路径下。</p>
<p>执行时候，用 <code>{{steps.generate-artifact.outputs.artifacts.hello-art}}</code> 方式引用生成的制品。</p>
<h3 id="heading-5omn6kgm">执行</h3>
<p>使用 Argo CLI 启动流程后，会看到类似如下的输出：</p>
<pre><code class="lang-plaintext">Name:                artifact-passing-mkn57
Namespace:           default
ServiceAccount:      argo-executor
Status:              Succeeded
...
STEP                       TEMPLATE                 PODNAME                                                    DURATION  MESSAGE
 ✔ artifact-passing-mkn57  artifact-example
 ├───✔ generate-artifact   hello-world-to-file      artifact-passing-mkn57-hello-world-to-file-551171166       8s
 └───✔ consume-artifact    print-message-from-file  artifact-passing-mkn57-print-message-from-file-1735545326  8s
</code></pre>
<p>这时如果返回 OBS 面板，会看到存储桶中，按照前面的路径规则存储了文件以及相关的日志（<code>*.log</code>）。</p>
<h2 id="heading-5yw25luw5yi25zob55u45ywz5yqf6io9">其他制品相关功能</h2>
<h3 id="heading-6kag55uw5lut5bqt6ywn572u">覆盖仓库配置</h3>
<p>前面我们在 Workflow Controller 配置文件中的配置，适用于单租户场景；多租户场景下，还可以通过 <code>artifactRepositoryRef</code> 方式，让每个流程可以使用自己的制品配置（<code>https://argo-workflows.readthedocs.io/en/latest/artifact-repository-ref/</code>）。</p>
<p>首先使用 Configmap 定义多个存储对接的参数，例如：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ConfigMap</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-comment"># If you want to use this config map by default, name it "artifact-repositories". Otherwise, you can provide a reference to a</span>
  <span class="hljs-comment"># different config map in `artifactRepositoryRef.configMap`.</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">my-artifact-repository</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-comment"># v3.0 and after - if you want to use a specific key, put that key into this annotation.</span>
    <span class="hljs-attr">workflows.argoproj.io/default-artifact-repository:</span> <span class="hljs-string">default-v1-s3-artifact-repository</span>
<span class="hljs-attr">data:</span>
  <span class="hljs-attr">default-v1-s3-artifact-repository:</span> <span class="hljs-string">|
    s3:
</span><span class="hljs-string">...</span>
  <span class="hljs-attr">v2-s3-artifact-repository:</span> <span class="hljs-string">|</span>
<span class="hljs-string">...</span>
</code></pre>
<p>这段 YAML 中，提供了几个信息：</p>
<ol>
<li><p>如果想要默认使用这个 Configmap 定义制品仓库，可以将其名称设置为 <code>artifact-repositories</code>。</p>
</li>
<li><p>如果不是默认，就需要在 <code>artifactRepositoryRef.configMap</code> 中显示定义 Configmap 名称。</p>
</li>
<li><p>v3.0 以后，可以用 <code>workflows.argoproj.io/default-artifact-repository</code> 注解定义这个 Configmap 中的默认仓库定义</p>
</li>
<li><p><code>data</code> 字段定义了两个制品仓库。</p>
</li>
</ol>
<p>然后可以在 Workflow 中引用：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">spec:</span>
  <span class="hljs-attr">artifactRepositoryRef:</span>
    <span class="hljs-attr">configMap:</span> <span class="hljs-string">my-artifact-repository</span>
    <span class="hljs-attr">key:</span> <span class="hljs-string">v2-s3-artifact-repository</span>
</code></pre>
<h3 id="heading-5z6d5zy5zue5ps2">垃圾回收</h3>
<p>在 Workflow 的 <code>spec.artifactGC</code> 中，可以定义 Garbage Collection 的策略。可选策略包括 <code>OnWorkflowCompletion</code> 和 <code>OnWorkflowDeletion</code>。</p>
<h3 id="heading-5a2y5yko6amx5yqo6io95yqb5yix6kgo">存储驱动能力列表</h3>
<p>除了 S3 之外，目前 Argo Workflow 支持的存储驱动能力如下：</p>
<p>(<code>https://argo-workflows.readthedocs.io/en/latest/configure-artifact-repository/</code>)</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Name</td><td>Inputs</td><td>Outputs</td><td>Garbage Collection</td><td>Usage (Feb 2020)</td></tr>
</thead>
<tbody>
<tr>
<td>Artifactory</td><td>Yes</td><td>Yes</td><td>No</td><td>11%</td></tr>
<tr>
<td>Azure Blob</td><td>Yes</td><td>Yes</td><td>Yes</td><td>-</td></tr>
<tr>
<td>GCS</td><td>Yes</td><td>Yes</td><td>Yes</td><td>-</td></tr>
<tr>
<td>Git</td><td>Yes</td><td>No</td><td>No</td><td>-</td></tr>
<tr>
<td>HDFS</td><td>Yes</td><td>Yes</td><td>No</td><td>3%</td></tr>
<tr>
<td>HTTP</td><td>Yes</td><td>Yes</td><td>No</td><td>2%</td></tr>
<tr>
<td>OSS</td><td>Yes</td><td>Yes</td><td>No</td><td>-</td></tr>
<tr>
<td>Raw</td><td>Yes</td><td>No</td><td>No</td><td>5%</td></tr>
<tr>
<td>S3</td><td>Yes</td><td>Yes</td><td>Yes</td><td>86%</td></tr>
</tbody>
</table>
</div>]]></content:encoded></item><item><title><![CDATA[Argo Workflow 中的卸载和归档]]></title><description><![CDATA[卸载
Argo workflow 使用 CR 方式来保存工作流的运行状态，众所周知 ETCD 有一个请求大小的限制：1MB，也就是说，如果我们的 Workflow 对象 YAML 尺寸大于 1MB，超出了 ETCD 限制，就无法正常保存了。这种场景最常见于对大量目标进行循环的情况下，作为一个成熟的工作流系统，Argo workflow 自然是考虑到这方面的限制，提供了称为卸载（Offload）的方式，用于处置超大尺寸的工作流。
简单来说，在遇到超大工作流时，Argo Workflow 会对其 s...]]></description><link>https://blog.fleeto.us/argo-workflow-zhong-de-xie-zai-he-gui-dang</link><guid isPermaLink="true">https://blog.fleeto.us/argo-workflow-zhong-de-xie-zai-he-gui-dang</guid><category><![CDATA[Argo Workflow]]></category><category><![CDATA[argo]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Mon, 16 Dec 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-5y246l29">卸载</h2>
<p>Argo workflow 使用 CR 方式来保存工作流的运行状态，众所周知 ETCD 有一个请求大小的限制：1MB，也就是说，如果我们的 Workflow 对象 YAML 尺寸大于 1MB，超出了 ETCD 限制，就无法正常保存了。这种场景最常见于对大量目标进行循环的情况下，作为一个成熟的工作流系统，Argo workflow 自然是考虑到这方面的限制，提供了称为卸载（Offload）的方式，用于处置超大尺寸的工作流。</p>
<p>简单来说，在遇到超大工作流时，Argo Workflow 会对其 <code>status.nodes</code> 字段进行压缩，然后保存到 ETCD 中，当需要查询时，会先从 ETCD 中查询出压缩后的数据，再进行解压，从而避免了 ETCD 的限制。如果压缩仍然无法满足这一要求，Argo workflow 会将它保存到数据库中。</p>
<p>那么什么才是“超大”呢？Argo workflow 中，默认 <code>1024*1024</code> 为超大，但是我们可以通过修改 Workflow 控制器中的 <code>MAX_WORKFLOW_SIZE</code> 环境变量来改变这个值。为了测试方便，我们将环境变量修改为 <code>10240</code>，也就是 10KB。</p>
<p>为了测试方便，我们选用 <code>Hello</code> 插件来进行测试，使用之前首先要启用这个插件：</p>
<ol>
<li><p>从 <code>https://github.com/argoproj-labs/argo-workflows-hello-executor-plugin</code> 获取代码</p>
</li>
<li><p><code>kubectl apply -f hello-executor-plugin-configmap.yaml</code> 即可启用该插件。</p>
</li>
</ol>
<p>接下来编写一个最小的 Workflow：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">argoproj.io/v1alpha1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Workflow</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">generateName:</span> <span class="hljs-string">little-</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">entrypoint:</span> <span class="hljs-string">main</span>
  <span class="hljs-attr">templates:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">main</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">item</span>
        <span class="hljs-attr">template:</span> <span class="hljs-string">atom</span>
        <span class="hljs-attr">withSequence:</span>
          <span class="hljs-attr">count:</span> <span class="hljs-string">"5"</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">atom</span>
    <span class="hljs-attr">plugin:</span>
      <span class="hljs-attr">hello:</span> { }
</code></pre>
<p>提交之后，看一下这个工作流的尺寸：</p>
<pre><code class="lang-plaintext">$ kubectl get wf little-xbg5g -o yaml | wc -c
    4549
</code></pre>
<p>只有 4K 多一点，不会触发压缩，如果查看这个 YAML，会看到里面的 Nodes 情况。那么我们将循环次数提高到 50 会发生什么？</p>
<pre><code class="lang-yaml"><span class="hljs-string">...</span>
  <span class="hljs-attr">generateName:</span> <span class="hljs-string">bigger-</span>
<span class="hljs-attr">spec:</span>
<span class="hljs-string">...</span>
    <span class="hljs-bullet">-</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">item</span>
        <span class="hljs-attr">template:</span> <span class="hljs-string">atom</span>
        <span class="hljs-attr">withSequence:</span>
          <span class="hljs-attr">count:</span> <span class="hljs-string">"50"</span>
<span class="hljs-string">...</span>
</code></pre>
<p>提交运行后，我们会发现，这个 WF 对象的 <code>status.nodes</code> 节点不见了，取而代之的是 <code>status.compressedNodes</code>，其中包含了一串编码内容，如果用 <code>base64 -d | gunzip</code> 处理后，就会看到 <code>status.nodes</code> 的内容了。</p>
<p>如果工作流再大一些呢？例如我们把循环次数放大到 500：</p>
<pre><code class="lang-yaml"><span class="hljs-string">...</span>
  <span class="hljs-attr">generateName:</span> <span class="hljs-string">huge-</span>
<span class="hljs-attr">spec:</span>
<span class="hljs-string">...</span>
    <span class="hljs-bullet">-</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">item</span>
        <span class="hljs-attr">template:</span> <span class="hljs-string">atom</span>
        <span class="hljs-attr">withSequence:</span>
          <span class="hljs-attr">count:</span> <span class="hljs-string">"50"</span>
<span class="hljs-string">...</span>
</code></pre>
<p>Argo workflow 提交直接会出错：<code>workflow is longer than maximum allowed size. compressed size 18191 &gt; maxSize 10240Tried to offload but encountered error: offload node status is not supported</code>，也就是说，经过压缩之后，还是超出了最大限制，尝试卸载，结果失败了。那么如何启用卸载呢？</p>
<p><code>Wrokflow Controller</code> 有一个可选的 Configmap，其中包含对持久化卸载的选项，例如我这样设置的：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">data:</span>
  <span class="hljs-attr">persistence:</span> <span class="hljs-string">|
    connectionPool:
      maxIdleConns: 100
      maxOpenConns: 0
      connMaxLifetime: 0s
    nodeStatusOffLoad: true
    mysql:
      host: argo-mysql.default
      port: 3306
      database: argo
      tableName: argo_workflows
      userNameSecret:
        name: argo-mysql-cred
        key: user
      passwordSecret:
        name: argo-mysql-cred
        key: password
</span><span class="hljs-attr">kind:</span> <span class="hljs-string">ConfigMap</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">workflow-controller-configmap</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
</code></pre>
<p>提交之前首先要准备数据库：</p>
<ol>
<li><p>在 <code>argo</code> 命名空间中创建一个 Secret 备用，其中包含两个字段，分别是 MySQL 的用户名和密码。</p>
</li>
<li><p>创建一个 MySQL Database，命名为 <code>argo</code>，并且让前面 Secret 中声明的凭据可以访问。</p>
</li>
<li><p>在配置中引用前面创建的 Secret。</p>
</li>
</ol>
<p>提交 Configmap 之后，重启 Workflow Controller。再次提交上述的工作流，可以看到工作流已经可以运行了。</p>
<blockquote>
<p>成功后，使用 <code>argo watch</code> 命令是无法获取详情的，但是可以在 Argo Server 的 Web 界面上查看。</p>
</blockquote>
<p>如果进入数据库，可以看到 <code>argo_workflows</code> 的 <code>nodes</code> 字段已经保存了完整的 Node 信息。</p>
<h2 id="heading-5b2s5qgj">归档</h2>
<p>虽然我们可以使用垃圾搜集策略来适时删除 Pod，但是 WF 对象始终存在，除了 <code>kubectl get wf &gt; backup.yaml</code>，Argo workflow 有没有提供更好的归档能力呢？</p>
<p>启用数据库之后，就可以进行归档了，用法很简单，仍然从 Configmap 配置入手：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">archiveTTL:</span> <span class="hljs-string">180d</span>
<span class="hljs-attr">archiveLabelSelector:</span>
  <span class="hljs-attr">matchLabels:</span>
    <span class="hljs-attr">workflows.argoproj.io/archive-strategy:</span> <span class="hljs-string">"always"</span>
</code></pre>
<p><code>archiveTTL</code> 表示归档寿命，默认为 0，也就是用不删除，<code>archiveLabelSelector</code> 则是标签选择器，用于指定哪些工作流需要被归档。例如下面的 <code>metadata</code>：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">generateName:</span> <span class="hljs-string">backup-</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">workflows.argoproj.io/archive-strategy:</span> <span class="hljs-string">"always"</span>
</code></pre>
<p>提交工作流，运行完成后，使用 <code>kubectl get wf</code> 可以看到他的标签发生了变化：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">labels:</span>
    <span class="hljs-attr">workflows.argoproj.io/archive-strategy:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">workflows.argoproj.io/completed:</span> <span class="hljs-string">"true"</span>
    <span class="hljs-attr">workflows.argoproj.io/phase:</span> <span class="hljs-string">Succeeded</span>
    <span class="hljs-attr">workflows.argoproj.io/workflow-archiving-status:</span> <span class="hljs-string">Archived</span>
</code></pre>
<p>此时查看数据库内容，可以看到 <code>argo_archived_workflows</code> 表中已经记录了这个工作流的信息。</p>
]]></content:encoded></item><item><title><![CDATA[Platform As A Runtime（PaaR）——超越平台工程]]></title><description><![CDATA[原文：Platform as a Runtime (PaaR) - Beyond Platform Engineering
作者：Aviran Mordo
我个人对平台工程非常有兴趣。Wix已经实施了十几年的平台工程——当然，在“平台工程”这个名词诞生之前就开始了。本文将介绍 Wix 工程团队在过去几年中部署和实施的一些项目，这些项目将平台工程提升到了一个新的水平。接下来我们将深入探讨一些新的平台项目，为我们的未来愿景提供一些见解。
提供一些背景信息，Wix 是一个领先的网站构建平台，拥有来自 ...]]></description><link>https://blog.fleeto.us/platform-as-a-runtime-paar-chao-yue-ping-tai-gong-cheng</link><guid isPermaLink="true">https://blog.fleeto.us/platform-as-a-runtime-paar-chao-yue-ping-tai-gong-cheng</guid><category><![CDATA[Platform Engineering ]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Thu, 12 Dec 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>原文：<a target="_blank" href="https://www.aviransplace.com/post/platform-as-a-runtime-paar-beyond-platform-engineering">Platform as a Runtime (PaaR) - Beyond Platform Engineering</a></p>
<p>作者：<a target="_blank" href="https://www.aviransplace.com/profile/aviranm/profile">Aviran Mordo</a></p>
<p>我个人对<a target="_blank" href="https://www.aviransplace.com/post/platform-as-a-runtime-paar-the-next-step-in-platform-engineering">平台工程</a>非常有兴趣。<a target="_blank" href="https://www.wix.com/">Wix</a>已经实施了十几年的平台工程——当然，在“平台工程”这个名词诞生之前就开始了。本文将介绍 Wix 工程团队在过去几年中部署和实施的一些项目，这些项目将平台工程提升到了一个新的水平。接下来我们将深入探讨一些新的平台项目，为我们的未来愿景提供一些见解。</p>
<p>提供一些背景信息，Wix 是一个领先的网站构建平台，拥有来自 190 个国家/地区的超过 2.4 亿注册用户（网站构建者）。我们的平台部署在全球 3 个地区的 20 个服务点。Wix 有 5,000 多名员工，其中约一半从事研发工作。因此，可以肯定地说，（软件）工程是我们工作的核心，也是我们业务价值的核心驱动力。</p>
<h2 id="heading-the-need-for-speed">The need for speed</h2>
<p>成功的软件企业，能够快速交付高质量代码。随着规模的不断扩大，挑战也接踵而来。随着公司的发展壮大，因为依赖性、存量代码和复杂性的增加，让软件的交付过程日趋缓慢。</p>
<p>计算机科学和（软件）工程诞生以来，就一直在涌现各种方法，用于对工作进行组织，从而实现更高的速度和质量。而持续交付、DevOps 和 Serverless 是目前的最新趋势。</p>
<p>随着方法论趋势的演进，我们的工具也随之变化。这些技术的目的，当然是为了让公司能够更快速地交付软件——初创科技公司的数量及其增长推动了这样的演进。为了支持这种增长，我们看到云托管/计算提供商的出现，它们可以快速访问庞大数据中心的服务器，成功地降低了运维开销。</p>
<p>随后出现了微服务理念，使公司能够更快地扩展规模并“更轻松”地维护其软件。最后，我们有了 Serverless，它消除了更多的开销和对服务器进行维护的需求。顾名思义，使用 Serverless，您就不再需要自行维护服务器。服务器扩容、服务机配置、Kubernetes 集群管理等问题不复存在，运维开销进一步被缩减。</p>
<h2 id="heading-5b6u5pyn5yqh5aac5l2v5b2x5zon5bya5yr6ycf5bqm">微服务如何影响开发速度</h2>
<p>如果从单体服务开始，那么事情相当简单。可以选用任何框架，利用任何工具。一切都能快速推进。</p>
<p>但是随着规模的扩张，服务数量开始膨胀，事情就开始变得复杂。系统和服务之间需要进行集成——RPC/REST、数据库、消息服务等开始出现在你的组件列表里。运维、测试和管理的工作越来越多。这时就需要框架了。</p>
<p>少量的微服务没什么问题。然而随着你的不断成长，微服务会越来越多。下图是 Wix 的微服务地图——每个矩形是一个微服务集群，这些连线代表了微服务之间的通信。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745822687503/c46af0f5-1164-4f09-b6c3-aed57eff6822.png" alt class="image--center mx-auto" /></p>
<p>如你所见，越多的服务就需要越多的团队。微服务之间需要协调工作，因此需要考虑他们之间的共性——他们需要使用相同的“语言”，也就是使用相同的协议和接口。例如如何处理 Cookie 和安全性？怎么完成 RPC 调用？Http Header 和 日志如何处理？</p>
<p>下图中的条目，列出了一个需要关注的问题的列表，这些内容重要，但不完整。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745822701165/6d8ae32d-ac76-485b-81a6-acd83218c618.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-5b6u5pyn5yqh5p625p6e55qe5yaw5bgx5lia6kes">微服务架构的冰山一角</h2>
<p>让我们看一个示例服务的分层。虚拟机是基础层。应用在容器内运行，其之上是微服务/应用程序框架——例如 JVM 世界中的 Spring、NodeJS 的 Express。然后，在此之上，构建可信环境框架，该层使所有底层服务能够以相同的方式进行通信。通过相同的协议，使用相同的 HTTP Header，使用相同的加密/解密算法，等等。这样，它们就可以被网络上的所有其他服务使用和信任。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745822717056/39b234f9-6a9f-4978-87ae-3b87ff4d4b12.png" alt class="image--center mx-auto" /></p>
<p>软件工程师会在这些层的基础上工作。业务服务处于金字塔的顶端，这些服务代表的是公司实际销售给客户的业务价值。</p>
<p>对于我们工程师来说，这只是冰山一角。在我们处理业务逻辑代码之前，首先要处理它的整个底部部分。不幸的是，开销并没有到此为止。除了需要开发的实际产品功能之外，开发人员还需要考虑法规、业务和法律问题，例如 GDPR 合规性。这虽然不是实际销售的价值，但却是每个服务的必要内容。</p>
<p>这些介绍有些冗长，但它解释了开发大型系统的重要性。现在让我们喘口气，谈谈……</p>
<h2 id="heading-paar">平台即运行时（PaaR）</h2>
<p>通常会使用内部的框架或库来构建微服务，gRPC、Kafka 客户端、连接池、A/B 测试等内容都来自这些基础代码。但是，通过这种方法，最终得到的是一个分布式通用框架。在这种情况下，就需要频繁地更新所有微服务，以便让所有服务的版本保持兼容。</p>
<p>如何应对这种依赖开销呢？</p>
<p>一种方案是把构建时依赖修改为运行时依赖。但在 Wix，我们更进一步。除了我们之前提到的通信协议和合约之外，构建内部框架时还需要考虑其他问题。这些其他问题包括常见的业务流程、常见的法律问题（GDPR、PII 等）、常见的租户模型、权限、身份管理等。</p>
<p>因此，我们将所有这些业务问题和流程添加为运行时依赖项，最终得到平台即运行时 (PaaR).</p>
<p>添加到 PaaR 中的众多内容意味着什么？每个在 PaaR 中运行的微服务都会自动处理这些问题，而无需在每个服务中进行开发。例如在 GDPR 场景里，所有服务都会自动使用 GDPR 方式获取个人数据并在合适的时间“忘记”数据，从而节省每个服务宝贵的开发时间。</p>
<p>我们是怎样做到的？</p>
<p>首先从我们的 Serverless 平台开始。平台核心是 NodeJS，支持了整个应用程序框架。选择 Node.js 的原因——它轻量级，支持动态代码加载，并且简单易学。</p>
<p>第一步：我们将整个框架与 GRPC/REST/Kafka（包括发现服务）的集成层一起编码到 Node.js 服务器中，并使其成为“运行时服务器”。</p>
<p>这样一来，我们就拥有了一组具有相同功能的“运行时”服务器。</p>
<p>第二步：我们为数据服务添加了另一层，让开发人员可以轻松快速地连接数据库（运行时处理所有连接字符串、连接池、JDBC 等）。</p>
<p>我们最终得到的是一个“智能”容器，它可以处理入口流量，并将所有常见问题嵌入其中，但没有太多业务逻辑。</p>
<p>这两个步骤后，开发人员可以用运行时依赖的方式来构建业务逻辑，依赖项的代码不会和业务代码耦合在一起编译打包。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745822733272/95a7c752-52ad-463c-9db9-dce2c62a3d71.png" alt class="image--center mx-auto" /></p>
<p>开发人员在本地完成开发之后，就可以准备进行部署了。在 Serverless 生态中，部署应用无需关注 Node.js 服务或者容器的细节，只需要部署 TypeScript 文件或包，平台将更新代码自动加载到平台的运行时。</p>
<p>运行时自带了注册发现能力，因此在进行服务间调用时，只需要声明调用目标，平台会自动提供匹配的客户端来完成对目标服务的调用。</p>
<p>这些交互都是通过运行时完成的，也就是说，真正的集成工作是在运行时完成的，因此集成测试的工作开销也减少了。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745822751126/8ab4cfee-40df-42b5-bf36-78d8b09ba0e1.png" alt class="image--center mx-auto" /></p>
<p>这种做法的好处是，只需部署业务代码，而不必将其与公共库和 Node.js 运行时捆绑在一起，这使得可部署的文件非常小（大小通常小于 100Kb）。</p>
<h3 id="heading-5yig56a76ag555uu57ut5p6e5zkm6yoo572y5out5omr">分离项目结构和部署拓扑</h3>
<p>上文中描述的内容，和 Lambda 地行为是颇有些相似的。差异在于，Lambda 的框架和也是和可部署程序捆绑在一起的。但是如果我要加入新函数要怎么办呢？在 Lambda 中，需要新建一个实例，或者把新的函数添加到现有的实例中；而在我们的可信环境中，我们可以把多个函数运行在同一个进程里。简单说，我们可以用微服务或者函数的粒度进行开发，但是所有这些功能又可以用单体进程的方式来运行。当然，我们也可以把这些功能分离到平台中不同的主机上——像微服务一样。</p>
<p>不仅如此，我们还能用微服务或者单体的方式开发软件，并把软件的不同部分，部署到不同的平台主机上。</p>
<p>举个例子，假设我们有一个服务，它有两个服务端点：一个用来响应用户请求的 RPC 端点；还有一个用来监听 Kafka 主题。我们可以在同一个项目中开发这两个函数，沿着这个思路，开发者会认为这两个端点是是一体的，这些功能是同一个逻辑服务，但其实他们会被部署到不同主机上。</p>
<p>这样一来，这里的两个端点就有了不同的伸缩策略。在没有增加开发者心智负担和工作量的情况下，面向顾客的 RPC 函数和面向 Kafka 的两部分内容能够各自伸缩，却又完全无需进行重构和拆分。</p>
<p>在 Wix，函数的发布是轻松又高效的。开发者将函数推送到 Github 仓库后，新增代码只是一个小小的函数，只要个把分钟，新代码就能部署和启动运行了。</p>
<h2 id="heading-5bmz5yw5bel56il5ocd57u0">平台工程思维</h2>
<p>那么我们收获了什么呢？</p>
<ul>
<li><p>集成非常容易：开发人员能够简单的声明要调用的函数和微服务，就能够自动获得所需的客户端。</p>
</li>
<li><p>测试代码少：胶水代码无需进行集成测试</p>
</li>
<li><p>开发人员专注于业务逻辑的实现，开发和部署粒度非常小。</p>
</li>
<li><p>部署速度快：代码量小，无需框架公共库的打包工作</p>
</li>
<li><p>无需脚手架：集成工作都已经预先配置，并且开发人员用生命方式就可以引用。</p>
</li>
</ul>
<h2 id="heading-5pyq5p2l5os5pmv">未来愿景</h2>
<p>接下来，我们应该如何利用现有资源并在此基础上进行构建呢？例如我们可以让不同的团队管理各自不同的运行时。只需要克隆环境就能完成这样的需求。这样一来，ecom 和 blog 团队都可以有各自不同的运行时集群，这种情况下，不同团队的代码就不会被推送到同一运行时。但是不同运行时之间的函数还是可以互相调用的。</p>
<p>在这种情况下会产生一个需求：根据运行时来优化函数之间的亲和性。假设我们有两个运行时，每个运行时都包含多个函数：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745823424680/f97bb6ba-e2a3-4b12-bcff-75229dd64517.png" alt class="image--center mx-auto" /></p>
<p>上图看到，函数 2 和 5 之间存在交互。他们在不同的运行时中运行，网络延迟会降低他们之间的通信效率。如果我们能让系统自动地把函数 5 部署到第一个运行时，函数 2 部署到第二个运行时，调用关系就会变成这样：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745823438681/788f59e7-0866-467d-9397-b8668af126a4.png" alt class="image--center mx-auto" /></p>
<p>这样我们就跨过构建，直接在运行时完成函数的组织和优化，以此类推，我们能够形成一个跨网调用最少的高度优化的运行时环境。而现在我们只能把领域设计、开发环境跟运行时拓扑进行耦合（才能达成这样的效果）。</p>
<h2 id="heading-5y2v5lia6lq6kgm5pe25omn5piv5pyq5p2l">单一运行时才是未来</h2>
<p>将运行时扩展到其他编程语言是个有吸引力的想法。依我看，要完成这一目的，不需要构建多语言系统，也不应该为特定技术堆栈多次构建相同的框架。我们需要的是能够支持任何语言的<a target="_blank" href="https://www.aviransplace.com/post/platform-as-a-runtime-paar-the-next-step-in-platform-engineering">单一运行时</a></p>
<p>要实现这一目标，我们设想的方法是将整体框架一分为二：“Host”和“Guest”。Host 中包含运行时框架、服务集成和数据服务层；Guest 中包含的则是业务代码以及业务代码的集成能力。这样一来，只需要开发一次应用程序框架，而不是不断尝试在不同编程语言框架之中努力实现对等功能。这种方法的明显优势就是只要在 Host 上进行框架更新，无需跨语言的重复劳动。</p>
<p>缺点也是存在的——Guest 之间的调用是通过 Host 的跨进程通信来完成的。我们还在使用 GraalVM，试图在 Host 进程之间运行多个不同语言实现的 Guest。现在我们是通过两个不同的进程，简化了开发工作，得到了一个可用的系统。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745823483052/53459a76-82a7-4b57-ab80-d474a074db2a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-5b2t5lil6lb5bgv">当下进展</h2>
<p>我们的开发人员很喜欢目前的工作，这标志着该方法的成功。方法的核心就是平台工程思维，在这种环境中，很多复杂问题变得简单。Wix 开发人员能在几小时内开发出从前需要开发几天甚至几个星期的东西。</p>
<p>从本质上来说，我们的平台工程超越了简单的开发人员门户，取而代之的是成熟的 PaaR，为开发运维工作降低了心智负担。</p>
<p>要了解更多信息，请观看：Beyond Serverless and DevOps。</p>
]]></content:encoded></item><item><title><![CDATA[在 Argo workflow 中使用插件减少并行 Pod 数量]]></title><description><![CDATA[在之前写过的使用 Argo workflow 调用公有云客户端软件实现运维过程的文章中，可以看到，使用 Argo workflow 的容器模板，简单的将既有运维能力容器化，就能使用 Argo workflow 对这些能力进行编排了。
不过近期一个测试中，遇到个小麻烦——在一个 With 循环里，我输入了 500 个任务，结果是 6 节点 CCE 集群爆满，流程卡住——集群规模的事情很简单，我直接将 Argo workflow 部署到 CCE Autopilot 集群中，随着流程启动，Auto p...]]></description><link>https://blog.fleeto.us/zai-argo-workflow-zhong-shi-yong-cha-jian-jian-shao-bing-xing-pod-shu-liang</link><guid isPermaLink="true">https://blog.fleeto.us/zai-argo-workflow-zhong-shi-yong-cha-jian-jian-shao-bing-xing-pod-shu-liang</guid><category><![CDATA[argo]]></category><category><![CDATA[Argo Workflow]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Fri, 29 Nov 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>在之前写过的使用 Argo workflow 调用公有云客户端软件实现运维过程的文章中，可以看到，使用 Argo workflow 的容器模板，简单的将既有运维能力容器化，就能使用 Argo workflow 对这些能力进行编排了。</p>
<p>不过近期一个测试中，遇到个小麻烦——在一个 <code>With</code> 循环里，我输入了 500 个任务，结果是 6 节点 CCE 集群爆满，流程卡住——集群规模的事情很简单，我直接将 Argo workflow 部署到 CCE Autopilot 集群中，随着流程启动，Auto pilot 集群非常给力，不到一分钟就扩容到了上百节点。然而新的问题出现了，Argo workflow 容器模板使用的镜像托管在 <code>quay.io</code> 上，我被限流了——无法拉取镜像，工作流自然也就无法执行了。</p>
<p>如果说必须要限流的话，Argo workflow 提供了多种机制，在不同粒度上对工作流的并发进行控制：</p>
<ol>
<li>在模板中，使用 <code>parallelism</code> 参数，限制流程实例内的并发数。</li>
<li>在 Workflow Controller 的 Configmap（<code>workflow-controller-configmap</code>）中，使用 <code>parallelism</code> 或者 <code>namespaceParallelism</code>，在集群范围内，限制总体并发的流程数量。</li>
<li>模板中使用 <code>synchronization</code>，使用同样的共享锁的流程实例将会被有效限流。</li>
</ol>
<p>不难看出，在有限集群的规模下，通过对并发的控制，以及垃圾回收策略的定义，都能有效的限制集群规模——毕竟上百节点是要花不少银子的。在这种情况下，还有一条路就是，使用执行插件。例如如下工作流：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">argoproj.io/v1alpha1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Workflow</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">generateName:</span> <span class="hljs-string">python-example-</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">entrypoint:</span> <span class="hljs-string">main</span>
  <span class="hljs-attr">arguments:</span>
    <span class="hljs-attr">parameters:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">value</span>
        <span class="hljs-attr">value:</span> <span class="hljs-string">"1"</span>  
  <span class="hljs-attr">templates:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">main</span>
      <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">evaluate</span>
          <span class="hljs-attr">template:</span> <span class="hljs-string">evaluate</span>
          <span class="hljs-attr">arguments:</span>
            <span class="hljs-attr">parameters:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">value</span>
                <span class="hljs-attr">value:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{workflow.parameters.value}}</span>"</span>
          <span class="hljs-attr">withSequence:</span>
            <span class="hljs-attr">count:</span> <span class="hljs-string">"50"</span>         
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">evaluate</span>
      <span class="hljs-attr">inputs:</span>
        <span class="hljs-attr">parameters:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">value</span>    
      <span class="hljs-attr">plugin:</span>
        <span class="hljs-attr">python:</span>
          <span class="hljs-attr">expression:</span> <span class="hljs-string">|</span>
            {<span class="hljs-attr">"sum":</span> <span class="hljs-string">int(parameters</span>[<span class="hljs-string">"value"</span>]<span class="hljs-string">)</span> <span class="hljs-string">+</span> <span class="hljs-number">1</span>}
</code></pre>
<p>这里使用 <code>plugin.python</code> 的方式引用了一个插件，执行时，循环了 50 次，提交后，我们会发现，这里只执行了一个 Pod：<code>python-example-hlc5t-1340600742-agent</code>，也就是说，这一个 Pod 承载了所有的 50 个任务。如何实现的呢？这里就要看看 Argo workflow 的插件机制了。</p>
<p>Argo workflow <strong>默认是不启用插件的</strong>，要启用插件，需要给控制器加入环境变量：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">workflow-controller</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">containers:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">workflow-controller</span>
          <span class="hljs-attr">env:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">ARGO_EXECUTOR_PLUGINS</span>
              <span class="hljs-attr">value:</span> <span class="hljs-string">"true"</span>
</code></pre>
<p>重启后，就可以启用上面工作流引用的插件了，启用插件的方式很有意思，提交一个 Configmap 即可：</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># This is an auto-generated file. DO NOT EDIT</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">data:</span>
  <span class="hljs-attr">sidecar.container:</span> <span class="hljs-string">|
    args:
</span><span class="hljs-string">....</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ConfigMap</span>
<span class="hljs-attr">metadata:</span>
<span class="hljs-string">...</span>
    <span class="hljs-attr">workflows.argoproj.io/version:</span> <span class="hljs-string">'&gt;= v3.3'</span>
  <span class="hljs-attr">creationTimestamp:</span> <span class="hljs-literal">null</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">workflows.argoproj.io/configmap-type:</span> <span class="hljs-string">ExecutorPlugin</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">python-executor-plugin</span>
</code></pre>
<p>这方式有点奇怪，Configmap 里面包含了一堆 Python 代码。以及似乎是 Sidecar 的容器定义。应用之后，就能够运行上述工作流了。</p>
<p>注意 Configmap 中的注释说明：这是一个自动生成的文件，哪里来的呢？</p>
<p>实际上，Argo workflow 插件是由 <code>argo executor-plugin build</code> 命令构建出来的，一个插件的原始文件主要包含三个部分：</p>
<ol>
<li>插件清单（<code>plugin.yaml</code>）：这里实际上是对一个容器的定义，其中包含了容器镜像、资源使用等。</li>
<li>启动文件：一个命名为 <code>server.*</code> 的文本文件，可以是 Shell 或者 Python 脚本，他会在插件启动时被执行。</li>
<li>插件镜像：上述文本文件可能无法描述一些业务逻辑，因此，可以将二进制文件封装到镜像里，给启动文件调用。</li>
</ol>
<p>例如前边用到的 Python 插件的 <code>plugin.yaml</code>：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">kind:</span> <span class="hljs-string">ExecutorPlugin</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">argoproj.io/v1alpha1</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">python</span>
<span class="hljs-string">...</span>
    <span class="hljs-attr">workflows.argoproj.io/version:</span> <span class="hljs-string">'&gt;= v3.3'</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">sidecar:</span>
    <span class="hljs-attr">container:</span>
      <span class="hljs-attr">command:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">python</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">-c</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">python:alpine</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">python-executor-plugin</span>
<span class="hljs-string">...</span>
</code></pre>
<p>不难看出，这个定义和上边的 Configmap 是一致的。再看看 <code>server.py</code>：</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">from</span> http.server <span class="hljs-keyword">import</span> BaseHTTPRequestHandler, HTTPServer


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Plugin</span>(<span class="hljs-params">BaseHTTPRequestHandler</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">args</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> json.loads(self.rfile.read(int(self.headers.get(<span class="hljs-string">'Content-Length'</span>))))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reply</span>(<span class="hljs-params">self, reply</span>):</span>
        self.send_response(<span class="hljs-number">200</span>)
        self.end_headers()
        self.wfile.write(json.dumps(reply).encode(<span class="hljs-string">"UTF-8"</span>))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">unsupported</span>(<span class="hljs-params">self</span>):</span>
        self.send_response(<span class="hljs-number">404</span>)
        self.end_headers()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">do_POST</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">if</span> self.path == <span class="hljs-string">'/api/v1/template.execute'</span>:
            args = self.args()

            template = args[<span class="hljs-string">'template'</span>]
            plugin = template.get(<span class="hljs-string">'plugin'</span>, {})

            <span class="hljs-keyword">if</span> <span class="hljs-string">'python'</span> <span class="hljs-keyword">in</span> plugin:
                spec = plugin[<span class="hljs-string">'python'</span>]

                <span class="hljs-comment"># convert parameters into easy to use dict</span>
                <span class="hljs-comment"># artifacts are not supported</span>
                parameters = {}
                <span class="hljs-keyword">for</span> parameter <span class="hljs-keyword">in</span> template.get(<span class="hljs-string">'inputs'</span>, {}).get(<span class="hljs-string">'parameters'</span>, []):
                    parameters[parameter[<span class="hljs-string">'name'</span>]] = parameter[<span class="hljs-string">'value'</span>]

                <span class="hljs-keyword">try</span>:
                    code = compile(spec[<span class="hljs-string">'expression'</span>], <span class="hljs-string">"&lt;string&gt;"</span>, <span class="hljs-string">"eval"</span>)
...


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    httpd = HTTPServer((<span class="hljs-string">''</span>, <span class="hljs-number">7984</span>), Plugin)
    httpd.serve_forever()
</code></pre>
<p>上边的代码，不难看出，这里只是启动了一个简单的 Python HTTP Server，监听 <code>/api/v1/template.execute</code> 的 Post 请求，并对其进行处理。</p>
<p>上述的 YAML 和启动代码都编写完成之后，就可以使用 <code>argo executor-plugin build</code> 命令来构建 Configmap 了。</p>
<blockquote>
<p>当然也可以使用自己定义的基础镜像。</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[某天才手表可能用于电信诈骗——某通如是说]]></title><description><![CDATA[斥巨资购入某天才手表一块。186 的手机号已经用了十几年了，顺理成章开了一张副卡，怼到了手表里，魔幻的旅途开始了。
12 号，崔左左幼儿园出门团建的路上，某天才突然 App 提醒我，手表收到了未知联系人的短信，打开一看，哭笑不得：



太长不看版：你的号码存在使用异常，存在被盗用的风险，所以把你号码给停了。

还好，信息里有个用于恢复的网址，打开之后发现，是某通的 App，一顿操作之后，得到如下结果：


太长不看版：你的号码无法在线恢复。请致电 10010

行吧，打电话给某通热线，接线员非...]]></description><link>https://blog.fleeto.us/mou-tian-cai-shou-biao-ke-neng-yong-yu-dian-xin-zha-pian-mou-tong-ru-shi-shuo</link><guid isPermaLink="true">https://blog.fleeto.us/mou-tian-cai-shou-biao-ke-neng-yong-yu-dian-xin-zha-pian-mou-tong-ru-shi-shuo</guid><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Sat, 23 Nov 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>斥巨资购入某天才手表一块。186 的手机号已经用了十几年了，顺理成章开了一张副卡，怼到了手表里，魔幻的旅途开始了。</p>
<p>12 号，崔左左幼儿园出门团建的路上，某天才突然 App 提醒我，手表收到了未知联系人的短信，打开一看，哭笑不得：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745946295623/07107476-14bb-43cf-b7d5-251a0015edff.png" alt class="image--center mx-auto" /></p>
<p><img src="images/liantongbbb.jpg" alt /></p>
<blockquote>
<p>太长不看版：你的号码存在使用异常，存在被盗用的风险，所以把你号码给停了。</p>
</blockquote>
<p>还好，信息里有个用于恢复的网址，打开之后发现，是某通的 App，一顿操作之后，得到如下结果：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745946309399/49d5fc31-c260-4f9f-b497-ae7f00be1577.jpeg" alt class="image--center mx-auto" /></p>
<blockquote>
<p>太长不看版：你的号码无法在线恢复。请致电 10010</p>
</blockquote>
<p>行吧，打电话给某通热线，接线员非常礼貌地给了我一个可行建议——只要用被停机的号码打通服务热线，并同时提供我的身份证明，就能轻松解封。我就非常无奈了——让五岁小屁孩完成这个动作难度有点大啊，并且她手表已经停机，如何联系呢——某通你这是给我下了个套啊。于是，我只好跟它说，现在呢，我也在对通话进行录音，你只要回答我几个简单问题，只要回答是否就可以了：</p>
<ol>
<li><p>你能不能提供给我任何证据，证实这个号码进行了什么不法或者疑似不法的行为？</p>
</li>
<li><p>如果你拿不出证据，是不是说贵公司随意破坏了对我的通信服务？</p>
</li>
<li><p>如果你拿不出证据，是不是说贵公司在没有理由的情况下侵犯了我的通信权利？</p>
</li>
</ol>
<p>结果不难猜到，我得到了一大串的：“对不起，XXXX，深表歉意”。证据是不可能有的，错误也是不可能承认的。</p>
<p>可是小朋友还在外失联，不能不管，一肚子气也需要缓解，只好继续努力。对工某部、某通总公司进行一番骚扰之后，一直拖到小朋友回到家，该公司终于大发慈悲，允许我复通自己的号码了。</p>
<p>时间荏苒岁月穿梭，三个月后，也就是 21 号，小朋友珠海长隆玩去了，突然，手表 App 里又收到一条信息，内容自然是，五岁小孩+儿童手表的组合，再度触发了风控条件，被停机了。</p>
<p>没法子，再次拿出灵魂三问，自然也还是不会得到任何答复，客户小哥说保证在 48 小时内回复我。几轮无效沟通后，非常硬气的告诉了我他们上级的投诉电话。可是我已经累了，求饶到：我能销卡么？小哥言辞拒绝了：那也要复通之后才可以。</p>
<p>一点个人经历，提醒大家。儿童手表里面，最好不要选这种专门在失联情况下停机的卡，免得收到这种折磨。</p>
]]></content:encoded></item><item><title><![CDATA[Argo + KooCli 操作华为云资源]]></title><description><![CDATA[前面写过一篇使用 Argo Workflow 操作 AWS 资源的例子，今天要写的是类似的，在 Argo Workflow 中，使用 CLI 客户端操作华为云资源的办法。
华为云提供的 KooCLI 是一个命令行工具，其中提供了很多华为云的操作能力。要在 Argo Workflow 中使用 KooCLI，首先需要构建 KooCLI 的容器镜像，Dockerfile 如下：
FROM ubuntu:24.04
RUN apt-get update -y && apt-get install cur...]]></description><link>https://blog.fleeto.us/argo-koocli-cao-zuo-hua-wei-yun-zi-yuan</link><guid isPermaLink="true">https://blog.fleeto.us/argo-koocli-cao-zuo-hua-wei-yun-zi-yuan</guid><category><![CDATA[argo]]></category><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Tue, 15 Oct 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>前面写过一篇使用 Argo Workflow 操作 AWS 资源的例子，今天要写的是类似的，在 Argo Workflow 中，使用 CLI 客户端操作华为云资源的办法。</p>
<p>华为云提供的 <a target="_blank" href="https://support.huaweicloud.com/function-hcli/index.html">KooCLI</a> 是一个命令行工具，其中提供了很多华为云的操作能力。要在 Argo Workflow 中使用 KooCLI，首先需要构建 KooCLI 的容器镜像，Dockerfile 如下：</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> ubuntu:<span class="hljs-number">24.04</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update -y &amp;&amp; apt-get install curl -y</span>
<span class="hljs-keyword">RUN</span><span class="bash"> curl -sSL https://cn-north-4-hdn-koocli.obs.cn-north-4.myhuaweicloud.com/cli/latest/hcloud_install.sh -o ./hcloud_install.sh \
  &amp;&amp; bash ./hcloud_install.sh -y \
  &amp;&amp; yes | hcloud --<span class="hljs-built_in">help</span></span>

<span class="hljs-keyword">WORKDIR</span><span class="bash"> hcloud</span>
</code></pre>
<p>整个过程和官网的说明是类似的，这里我加了一行初始化操作：<code>yes | hcloud --help</code>，这是因为启动 <code>hcloud</code> 的时候，首先会弹出一个 License 界面，需要输入 <code>yes</code> 才继续。所以这里使用 <code>yes</code> 命令进行一个初始化。</p>
<p>容器镜像构造结束之后，就可以在 Argo Workflow 中使用 KooCLI 了。</p>
<blockquote>
<p>这次测试使用的是 Argo Workflow 的 v3.5.11 版本。</p>
</blockquote>
<p>简单粗暴上代码，在 <code>https://gist.github.com/fleeto/7c70b58a6ee7bdb93494f94f77db7c20</code></p>
<p>上述代码有几个要点：</p>
<h2 id="heading-5ywl5yc">入参</h2>
<p>在 <code>spec.arguments.parameters</code> 中，定义了 <code>ak</code>、<code>sk</code> 以及 <code>region</code> 三个参数，用于配置华为云的 AK、SK 以及区域。</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">arguments:</span>
    <span class="hljs-attr">parameters:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">ak</span>
      <span class="hljs-attr">value:</span> <span class="hljs-string">"AKAKAK"</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">sk</span>
      <span class="hljs-attr">value:</span> <span class="hljs-string">"SKSKSSK"</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">region</span>
      <span class="hljs-attr">value:</span> <span class="hljs-string">"cn-north-4"</span>
</code></pre>
<h2 id="heading-koocli">执行 KooCLI</h2>
<p>在 <code>list-ecs</code> 步骤中，使用了前面构建的 KooCLI 镜像，用无配置方式，通过 <code>hcloud ECS ListCloudServers</code> 命令，获取到当前区域下的所有云服务器：</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">list-ecs</span>
  <span class="hljs-attr">container:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">dustise/koocli:v0.0.2</span>
    <span class="hljs-attr">command:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">hcloud</span>
    <span class="hljs-attr">args:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">ECS</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">ListCloudServers</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">--cli-region={{workflow.parameters.region}}</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">--cli-access-key={{workflow.parameters.ak}}</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">--cli-secret-key={{workflow.parameters.sk}}</span>
</code></pre>
<p>这一步骤中，我没有定义输出参数，这是因为在 Argo Workflow 中，可以使用 <code>steps.[步骤名称].outputs.result</code> 的方式，默认导出 STDOUT 内容，但是需要注意的是，这种方式最大支持 256kb 的内容。</p>
<p>还有一种方式就是把内容输出给文本文件，然后用如下形式声明：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">outputs:</span>
  <span class="hljs-attr">parameters:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">hello-param</span>
    <span class="hljs-attr">valueFrom:</span>
      <span class="hljs-attr">path:</span> <span class="hljs-string">/tmp/hello_world.txt</span>
</code></pre>
<p>KooCLI 输出的 JSON 中，可以使用 <code>--cli-query</code> 开关，使用 <code>JMESPath</code> 方式对结果进行整理，原始的输出格式大致如下：</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"servers"</span>: [
    {},]}
</code></pre>
<p>要想只输出 <code>servers</code> 数组，可以加入 <code>--cli-query=servers</code> 开关，就能输出只包含 <code>servers</code> 数组的内容了。</p>
<h2 id="heading-5byv55so6l6t5ye657ut5p6c6lb6kgm5b6q546v">引用输出结果进行循环</h2>
<p>这里使用了 <code>withParam</code> 语法，对 <code>list-ecs</code> 步骤的输出结果进行循环，每次循环，都会把当前循环的元素赋值给 <code>item</code> 变量，输出 <code>item</code> 变量的 <code>id</code> 属性。</p>
<p>循环变量里，我们使用了一个奇怪的表达式：<code>"{{=toJSON(jsonpath(steps.list.outputs.result, '$.servers'))}}"</code>：</p>
<ul>
<li><code>{{=</code> 代表使用表达式进行运算。</li>
<li>使用 <code>jsonpath</code> 获得数组</li>
<li>toJSON 把对象编码为 JSON</li>
</ul>
<p>注意，不同的 Argo workflow 版本，这一点不太一样，目前看到的<a target="_blank" href="https://github.com/argoproj/argo-workflows/discussions/8930#discussioncomment-10866254">官网讨论</a>是：</p>
<ul>
<li>3.4: <code>{{=toJson(jsonpath(...))}}</code></li>
<li>3.5: <code>{{=toJSON(jsonpath(...))}}</code></li>
<li>3.6: <code>{{=jsonpath(...)}}</code></li>
</ul>
<h2 id="heading-6lq6kgm">运行</h2>
<p><code>argo submit</code> 或者 <code>kubectl create</code> 执行之后，可以看到，KooCLI 用了一个容器进行查询，随后在循环中，每个示例都有一个对应的 Pod 执行 ECHO 任务。</p>
]]></content:encoded></item><item><title><![CDATA[Argo Workflow 中的 RBAC]]></title><description><![CDATA[众所周知，Argo Workflow 的整个工作机制，都是深度依赖于 Kubernetes 的。要让 Argo Workflow 顺畅运行，完成任务，RBAC 是不可缺少的一环。接下来的内容大概算是个笔记，记录了最初接触 Argo Workflow 时，可能会面对的一些 RBAC 相关问题以及其解决方法。
第一关：Console
这里我们选择官方 Release 页面中的标准部署方式，部署最新的 v3.5.11 版本。
$ kubectl create namespace argo
namesp...]]></description><link>https://blog.fleeto.us/argo-workflow-zhong-de-rbac</link><guid isPermaLink="true">https://blog.fleeto.us/argo-workflow-zhong-de-rbac</guid><category><![CDATA[argo]]></category><category><![CDATA[Argo Workflow]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Thu, 10 Oct 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>众所周知，Argo Workflow 的整个工作机制，都是深度依赖于 Kubernetes 的。要让 Argo Workflow 顺畅运行，完成任务，RBAC 是不可缺少的一环。接下来的内容大概算是个笔记，记录了最初接触 Argo Workflow 时，可能会面对的一些 RBAC 相关问题以及其解决方法。</p>
<h2 id="heading-console">第一关：Console</h2>
<p>这里我们选择官方 Release 页面中的标准部署方式，部署最新的 v3.5.11 版本。</p>
<pre><code class="lang-bash">$ kubectl create namespace argo
namespace/argo created
$ kubectl ns argo
Context <span class="hljs-string">"orbstack"</span> modified.
Active namespace is <span class="hljs-string">"argo"</span>.
$ kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.5.11/install.yaml

customresourcedefinition.apiextensions.k8s.io/clusterworkflowtemplates.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/cronworkflows.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/workflowartifactgctasks.argoproj.io created
...
</code></pre>
<p>等所有 Pod 启动成功之后，就可以用端口转发方式访问 Console 了：</p>
<pre><code class="lang-bash">$ kubectl port-forward argo-server-67f8d8f6d4-s48jx 8888:2746
Forwarding from 127.0.0.1:8888 -&gt; 2746
Forwarding from [::1]:8888 -&gt; 2746
</code></pre>
<p>浏览器打开 <code>http://localhost:8888</code> 就可以看到 Argo Workflow 的 Console 了。首先欢迎我们的是登录页面。这上面一个明晃晃的输入框，要求输入 Token，官方文档明确给出了<a target="_blank" href="https://argo-workflows.readthedocs.io/en/latest/access-token/">解决方法</a>：</p>
<pre><code class="lang-bash">$ kubectl create role jenkins --verb=list,update --resource=workflows.argoproj.io
...
$ kubectl create sa jenkins
...
</code></pre>
<p>然后接下来创建对应的 <code>Rolebinding</code>，为 SA 授权，最后创建 Secret，用于承载 SA 的 Token。</p>
<blockquote>
<p>这里要吐槽，Argo 你这浓眉大眼的家伙，跟 Jenkins 是啥关系？</p>
</blockquote>
<p>步骤还是有点烦，这里总结成一个 RBAC 文件：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">piVersion:</span> <span class="hljs-string">rbac.authorization.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterRole</span>
<span class="hljs-attr">metadata:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">argo-operator</span>
<span class="hljs-attr">rules:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">apiGroups:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">argoproj.io</span>
  <span class="hljs-attr">resources:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">workflows</span>
  <span class="hljs-attr">verbs:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">list</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">update</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ServiceAccount</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-operator</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Secret</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">kuhbernetes.io/service-account-token</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-operator.service-account-token</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-attr">kubernetes.io/service-account.name:</span> <span class="hljs-string">argo-operator</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">rbac.authorization.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterRoleBinding</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-operator-binding</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
<span class="hljs-attr">subjects:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">kind:</span> <span class="hljs-string">ServiceAccount</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-operator</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
<span class="hljs-attr">roleRef:</span>
  <span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterRole</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-operator</span>
  <span class="hljs-attr">apiGroup:</span> <span class="hljs-string">rbac.authorization.k8s.io</span>
</code></pre>
<p>完成创建和授权之后，获取 Token：</p>
<pre><code class="lang-bash">$ ARGO_TOKEN=<span class="hljs-string">"Bearer <span class="hljs-subst">$(kubectl get secret argo-operator.service-account-token -o=jsonpath='{.data.token}' | base64 --decode)</span>"</span>
$ <span class="hljs-built_in">echo</span> <span class="hljs-variable">$ARGO_TOKEN</span>
Bearer eyJhbGciOiJSUzI1NiIsI...
</code></pre>
<p>将上述 Token 输入到浏览器中登录，就进入了 Argo Workflow 的控制台了。然后你会发现更多的无权访问。逐个调整之后，上面的 ClusterRole 授权对象需要增加如下内容：</p>
<ul>
<li><p>workflowtemplates</p>
</li>
<li><p>clusterworkflowtemplates</p>
</li>
<li><p>cronworkflows</p>
</li>
<li><p>eventsources</p>
</li>
<li><p>sensors</p>
</li>
<li><p>workfloweventbindings</p>
</li>
<li><p>workflowtaskresults</p>
</li>
</ul>
<blockquote>
<p>如果要在 Console 上进行提交，那么 verbs 也需要进行扩充，例如 <code>*</code>。</p>
</blockquote>
<h2 id="heading-hello-world">第二关：Hello world</h2>
<p>控制台的 <code>Workflows</code> 菜单中，有一个 <code>Submit New Workflow</code> 按钮，点击之后出现的页面里，在链接 <code>Edit using full workflow options</code> 中提供了一个工作流的示例，直接提交运行，大概会出现这样的错误信息：<code>Error (exit code 1): pods "fantastic-rhino" is forbidden: User "system:serviceaccount:argo:default" cannot patch resource "pods" in API group "" in the namespace "argo"</code>，看来又缺权限了，再来一套 RBAC：</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">rbac.authorization.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterRole</span>
<span class="hljs-attr">metadata:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">argo-executor</span>
<span class="hljs-attr">rules:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">apiGroups:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">""</span>
  <span class="hljs-attr">resources:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">pods</span>
  <span class="hljs-attr">verbs:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">'patch'</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">'watch'</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">'list'</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">'get'</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ServiceAccount</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-executor</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Secret</span>
<span class="hljs-attr">type:</span> <span class="hljs-string">kubernetes.io/service-account-token</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-executor.service-account-token</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-attr">kubernetes.io/service-account.name:</span> <span class="hljs-string">argo-executor</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">rbac.authorization.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterRoleBinding</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-executor-binding</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
<span class="hljs-attr">subjects:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">kind:</span> <span class="hljs-string">ServiceAccount</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-executor</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">argo</span>
<span class="hljs-attr">roleRef:</span>
  <span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterRole</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">argo-executor</span>
  <span class="hljs-attr">apiGroup:</span> <span class="hljs-string">rbac.authorization.k8s.io</span>
</code></pre>
<p>提交之后，</p>
]]></content:encoded></item><item><title><![CDATA[用 Obsidian 有效应对日常工作]]></title><description><![CDATA[两三年前，因为信息安全方面的考虑，弃坑了 Notion 和 Craft，改为使用 Obsidian 进行日常工作的记录，随着工作内容的日渐散乱，原本围绕少量项目和单一知识体系构造的笔记方法，从记录效率、到检索能力都逐渐被破坏了。因此经过一段时间打磨之后，围绕着记录、浏览和检索三个功能特性，面向我的日常工作内容，借助一系列的插件，逐步调整了我的笔记方法。目前看来，这种用事件为核心的记录方法，在日常工作中表现出的效率，的确远远超过之前以天为单位的粗放方法。
场景
日常工作中，需要打开 Obsidia...]]></description><link>https://blog.fleeto.us/yong-obsidian-you-xiao-ying-dui-ri-chang-gong-zuo</link><guid isPermaLink="true">https://blog.fleeto.us/yong-obsidian-you-xiao-ying-dui-ri-chang-gong-zuo</guid><category><![CDATA[obsidian]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Wed, 02 Oct 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>两三年前，因为信息安全方面的考虑，弃坑了 Notion 和 Craft，改为使用 Obsidian 进行日常工作的记录，随着工作内容的日渐散乱，原本围绕少量项目和单一知识体系构造的笔记方法，从记录效率、到检索能力都逐渐被破坏了。因此经过一段时间打磨之后，围绕着记录、浏览和检索三个功能特性，面向我的日常工作内容，借助一系列的插件，逐步调整了我的笔记方法。目前看来，这种用事件为核心的记录方法，在日常工作中表现出的效率，的确远远超过之前以天为单位的粗放方法。</p>
<h2 id="heading-5zy65pmv">场景</h2>
<p>日常工作中，需要打开 Obsidian 进行记录的情况，主要有几个场景：</p>
<ul>
<li><p><strong>文件往来</strong>：这里说的文件，除了 Markdown 和 Office 三件套之外，还可能包括各种绘图、建模的存档，以及一些在线文档、代码仓、工单系统等。虽说在线文档是现在的主流，但是在面对的并行项目和工具都达到两位数，并且相互之间存在交叉的情况下，在线文档的各种网址本身也可能成为一种认知负担；更不要提“我早就发给过你”、“你从来就没发给过我”的常规战争了。</p>
</li>
<li><p><strong>会议/沟通纪要</strong>：日常经常有些小会、小的讨论，其结论处在“有用、有意向，但是没有公示价值”的尴尬区间，可能需要进一步的深入讨论以及决策，这些鸡肋内容如果失去记录，可能就造成信息流的中断，对于其所属的更大的项目或者产品的决策过程，也会造成一定的损失。</p>
</li>
<li><p><strong>即兴文档</strong>：一方面在工作范围之外，还是会有一些稍嫌杂乱的思索和摘抄；另一方面，在线交流过程中，会产生一些现场绘图、板书等也是需要记录的。</p>
</li>
</ul>
<p>除了上述三种记录场景之外，更重要的是查询和展示，传统来说 Obsidian 通过文件夹、标签、搜索、（反向）链接和关系图谱对记录内容进行展示，这些方法<strong>的确可以</strong>显示出特定关注点的<strong>所有</strong>相关内容，但是通常会显得比较杂乱；除了这些之外，我们还希望有更丰富的查询和更规整的展示方式。</p>
<h2 id="heading-5pa55rov">方法</h2>
<p>综合上述场景化需求，我决定使用 Zettelkasten 的卡片记录法，结合 <code>Dataview</code> 查询来满足日常需求。</p>
<h2 id="heading-5l255so5y2h54mh5br6ycf6k6w5b2v">使用卡片快速记录</h2>
<p>要使用卡片记录，首先要在<code>配置-&gt;核心插件</code>中，启用<code>时间戳笔记生成器</code>（<code>Unique note creator</code>）。功能启用之后，创建一个保存卡片的目录，例如 <code>/Cards</code>，然后打开这个选项，把这个目录设置为保存位置。如果有兴趣可以把时间戳格式设置成自己喜欢的样式。后续我们会针对模板进行更多工作，所以这里不会进行设置。</p>
<h2 id="heading-5bu656ul5qih5p2">建立模板</h2>
<p>在 Obsidian 中，模板用于设置常见的格式化内容。设置模版之后，只要用 <code>插入模板</code> 命令，就可以选择模版插入当前位置。</p>
<blockquote>
<p>这里假设使用 <code>/Templates</code> 作为模板目录，可以在 <code>配置-&gt;核心插件-&gt;模板</code> 中设置目录。</p>
</blockquote>
<p>在模板中，除了可以设置特定常用的文字、结构和内容之外，还可以使用 <code>{{date}}</code>、<code>{{time}}</code> 作为变量，在使用模板时自动写入当前日期和时间。</p>
<p>另外，为了便于 <code>DataView</code> 的检索，我们会使用 <code>字段名:: 字段内容</code> 的方式，为速记内容提供关系数据。</p>
<p>这里我根据上除的录入场景，为卡片设置了三种模板：</p>
<h3 id="heading-5y2z5yw05yaz5l2c">即兴写作</h3>
<p>即兴写作其实不会有很多内容，我通常只会放置 <code>标题::</code>、<code>关键字::</code> 和 <code>内容</code> 三个段落。另外为了在 <code>Dataview</code> 中方便检索，我会在模版第一行中使用 <code>#卡片-即兴</code> 的标签。</p>
<p>但是在 Obsidian 中，还有一个即兴写作的东西是 Excalidraw，他可不会管你什么 Tag 什么 Dataview，其实有两种方法在 Excalidraw 文件中进行标注：</p>
<ul>
<li><p>在浏览窗格中，使用<code>默认编辑器</code>打开绘图，会看到绘图背后的 Markdown 文档，直接在前面的 <code>---</code> 区间加入 Tag 或者 Dataview Field。</p>
</li>
<li><p>安装 <code>MetaEdit</code> 插件，直接在 Excalidraw 文件的右键菜单上就能看到加入 Tag 或者 Field 的选项。</p>
</li>
</ul>
<h3 id="heading-5rkf6yca5zkm5lya6k6u">沟通和会议</h3>
<p>沟通和会议，主要关注的是时间、参与人、过程内容和关键结果，时间可以用前面提到的 <code>{{date}}</code>、<code>{{time}}</code> 自动填充，参与人我做成了字段。</p>
<blockquote>
<p>涉及人的项目，我通常会用 <code>[[人名]]</code> 的方式，这样每个人都有自己的页面，一方面用反向链接查看每个人的所有相关项目，另一方面可以为这个人加入诸如联系方式、邮件、组织关系等的注释。 注意：<code>参与人::</code> 后面如果写入多个人名，Dataview 会认为这是一整个字符串，要形成数组方式，应该用 <code>参与人:: [[张三]] 参与人::[[李四]]</code> 的方式。</p>
</blockquote>
<p>会议结论里通常会包含 TODO 项目，这里可以使用 <code>Task</code> 插件，形成待办列表。（后面的 <code>Dataview</code> 章节会介绍 <code>Task</code> 专属的视图）例如在 7 日之前联系张三：</p>
<p><code>- [ ] 会见 [[张三]] 修改诉讼方案 📅 2024-10-07</code></p>
<h3 id="heading-5br6ycf5os5ywl5qih54mi">快速插入模版</h3>
<p>因为前面没有给卡片设置缺省模版，所以新建卡片是空白的，这里选择模版再插入就有些麻烦了，因此我安装了 <code>Hotkeys for templates</code>，这个插件可以为每个模版设置快捷键，方便你夹着电话的时候快速构建内容。</p>
<h3 id="heading-5pah5lu25b6a5p2l">文件往来</h3>
<p>文件通常也是沟通的一种，不同的是要对文件进行处理，这里我主要借助的是 <code>Custom Attachment Location</code> 插件，在他的配置中，有一个 <code>Location for New Attachments</code> 的项目，可以设置把附件文件保存到当前笔记的相对目录下，例如我设置的是 <code>./assets_of_$filename</code>，如果当前卡片是 <code>202410011820</code>，则黏贴进来附件会被保存到 <code>assets_of_202410011820</code> 目录里。</p>
<blockquote>
<p>注意，需要开启 <code>选项-&gt;文件与链接</code> 中的 <code>检测所有类型文件</code>。</p>
</blockquote>
<h2 id="heading-dataview">使用 Dataview 快速浏览</h2>
<p>Dataview 使用一种特定的 DSL 来对 Obsidian 中的数据进行查询，前面一节创建的卡片会有些凌乱，因此我设计了几个视图，让工作变得清晰一些。</p>
<h3 id="heading-6aaw6ag1">首页</h3>
<p>使用 <code>Home Page</code> 插件实现，主要目的是跟踪 Task 列表，其中使用 Dataview 编写了两个简单的视图，分别显示未完成的任务和已完成的任务。Dataview 为 Task 插件定制的语法非常简单：</p>
<pre><code class="lang-markdown"><span class="hljs-code">```tasks
not done
sort by due
```</span>
</code></pre>
<p>展示未完成任务。</p>
<p>以及</p>
<pre><code class="lang-bash">```tasks
<span class="hljs-keyword">done</span>
sort by <span class="hljs-keyword">done</span> revferse
<span class="hljs-built_in">limit</span> 10
</code></pre>
<p>展示最近十条已完成任务。</p>
<h3 id="heading-5pel6k6w">日记</h3>
<p>可以使用在日记的模板里，使用变量和 Dataview 的语法，快速查询某一天的所有卡片。我的用法是，用三个不同的表格，展示每天的三种卡片。例如日记模板中，关于即兴记录：</p>
<pre><code class="lang-markdown"><span class="hljs-code">```dataview
TABLE 标题,关键字
FROM (#卡片-即兴 and ("Cards")) or ("Excalidraw")
WHERE (file.day=date({{time:YYYY-MM-DD}}))
```</span>
</code></pre>
<ul>
<li><p><code>TABLE</code> 这一行，表示会引用卡片中的 <code>标题::</code> 和 <code>关键字::</code> 字段。</p>
</li>
<li><p><code>FROM</code> 子句，表示从 <code>Cards</code> 目录中带有 <code>#卡片-即兴</code> 标签的卡片中，或者从 <code>Excalidraw</code> 文件中，选择当天的卡片。</p>
</li>
<li><p><code>WHERE</code> 中，要求文件日期等于 <code>date({{time:YYYY-MM-DD}})</code>。<code>date</code> 是 <code>Dataview</code> 的内置函数，负责把日期字符串转换成日期格式；而 <code>{{time:YYYY-MM-DD}}</code> 则是模板中的变量，会被替换成当前日期并进行格式化。</p>
</li>
</ul>
<h3 id="heading-5zcm57g75yix6kgo">同类列表</h3>
<p>除了用日记表达的每日列表之外，我还另外准备了几个页面，用于单独展示同类卡片，例如对于交流内容，我的 <code>Dataview</code> 查询是这样的：</p>
<pre><code class="lang-markdown"><span class="hljs-code">```dataview
TABLE 时间,主题,关键字,与会人,file.etags
FROM #卡片-沟通 and ("Cards")
SORT 时间 DESC
```</span>
</code></pre>
<ul>
<li><p>这里选择所有 <code>#卡片-沟通</code> 关键字并且在 <code>Cards</code> 目录下的卡片，按照时间降序排列。</p>
</li>
<li><p><code>file.etags</code> 会列出每个卡片中的所有标签</p>
</li>
</ul>
<h2 id="heading-5p2c6ag5">杂项</h2>
<ul>
<li><p><strong>标签改名</strong>：日常记录中难免会忙中出错，记错标签；或者因为时间的推移，要求合并前面过度细分的标签，可以用 <code>Tag Wrangler</code> 插件实现这一功能。</p>
</li>
<li><p><strong>隐藏附件文件</strong>：模板、或者附件文件夹，通常是无需暴露出来的，插件 <code>Hidden Folder</code> 可以使用正则表达式来隐藏这些文件夹。</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[IaC 杂感]]></title><description><![CDATA[IaC 的起源
IaC 是配置管理领域的一种技术，全称 Infrastructure as Code，字面意义：基础设施即代码，是一种使用可读文本发放和管理基础设施资源的方法。通常情况下，软件定义的基础设施管理平台，会为用户提供命令行、WebUI 的方式，让用户能够用手工或者工具化的方式进行资源发放和管理工作。随着“基础设施”这一概念的不断扩展，使用频度的不断提高，越来越多的基础设施平台会提供各自的 API 为自动化打开方便之门。为了更快、更多的发放更多种类的基础设施，用一致的代码对这些基础设施...]]></description><link>https://blog.fleeto.us/iac-za-gan</link><guid isPermaLink="true">https://blog.fleeto.us/iac-za-gan</guid><category><![CDATA[#IaC]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[崔秀龙]]></dc:creator><pubDate>Thu, 05 Sep 2024 04:00:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-iac">IaC 的起源</h2>
<p>IaC 是配置管理领域的一种技术，全称 Infrastructure as Code，字面意义：基础设施即代码，是一种使用可读文本发放和管理基础设施资源的方法。通常情况下，软件定义的基础设施管理平台，会为用户提供命令行、WebUI 的方式，让用户能够用手工或者工具化的方式进行资源发放和管理工作。随着“基础设施”这一概念的不断扩展，使用频度的不断提高，越来越多的基础设施平台会提供各自的 API 为自动化打开方便之门。为了更快、更多的发放更多种类的基础设施，用一致的代码对这些基础设施进行管控也是顺理成章。IaC 的发展史很清楚地证明了这种演进过程。</p>
<p>1993 年，Mark Burgess 在博士后期间，为了管理不同的 Unix 工作站，开发了 CFEngine。这个大概是 IaC 工具的鼻祖。据说他仅仅根据直觉和实践经验，为了简化在不同 Unix 下大量编写脚本的工作，而开发了这个软件，在这里他提出了面向最终状态进行收敛的思路。</p>
<p>2006 年，AWS 发布了 EC2，各种公有云、私有云随之兴起，企业面对的资源不再是少数的主机，取而代之的是数量更大、品种更多、生命周期更短的虚拟机和随之而来的、更复杂的 IT 环境。在这之后，Chef、Salt Stack、Ansible 等生态也先后浮出水面。</p>
<p>个人认为真正的变化，是接下来的 2021-2024 年，Cloudformation、Terraform 和 Kubernetes 陆续发布，使用声明式 API 进行 IaC 操作成了业界惯例。AWS Control API 和 Kubernetes 这样的基础设施，从底层保障了声明式 API 的实现能力。</p>
<h2 id="heading-iac-1">IaC 是对物理资源的采样</h2>
<p>IaC 真的能描述物理资源么？很显然答案是否定的，毕竟现实世界是连续的。例如下面的 EC2 Instance：</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">MyEC2Instance:</span> 
    <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS::EC2::Instance</span>
    <span class="hljs-attr">Properties:</span> 
      <span class="hljs-attr">ImageId:</span> <span class="hljs-string">"ami-79fd7eee"</span>
      <span class="hljs-attr">KeyName:</span> <span class="hljs-string">"testkey"</span>
      <span class="hljs-attr">BlockDeviceMappings:</span> 
      <span class="hljs-bullet">-</span> <span class="hljs-attr">DeviceName:</span> <span class="hljs-string">"/dev/sdm"</span>
        <span class="hljs-attr">Ebs:</span> 
          <span class="hljs-attr">VolumeType:</span> <span class="hljs-string">"io1"</span>
          <span class="hljs-attr">Iops:</span> <span class="hljs-string">"200"</span>
          <span class="hljs-attr">DeleteOnTermination:</span> <span class="hljs-string">"false"</span>
          <span class="hljs-attr">VolumeSize:</span> <span class="hljs-string">"20"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">DeviceName:</span> <span class="hljs-string">"/dev/sdk"</span>
        <span class="hljs-attr">NoDevice:</span> {}
</code></pre>
<p>很明显，这几行代码不可能描述一个完整的 EC2 实例，结合前面提到的 Control API 和 Kubernetes，实际上，对资源的抽象从资源 API 层面就已经开始了，表现在 IaC 层面的，也只是这种抽象的结果。正如对声音的采样，IaC 中表达的资源不会是“完整的全貌”，越频繁的采样，能够保留越多的细节，也会造成这一描述的复杂度大大提高——但是无论如何提高，IaC 的描述能力甚至都达不到监控的细节水平。换句话说，使用 IaC 的方式来描述资源，就必须承担抽象带来的损失。</p>
<p>除了静态的属性之外，对象的状态也是对实际情况的大幅度抽象，例如下面的 Pod 状态：</p>
<pre><code class="lang-mermaid">stateDiagram-v2
    [*] --&gt; Pending
    Pending --&gt; Running : PodScheduled
    Pending --&gt; Failed : PodFailed
    Pending --&gt; Succeeded : PodSucceeded
    Running --&gt; Succeeded : ContainersCompleted
    Running --&gt; Failed : ContainersFailed
    Running --&gt; Terminating : PodTerminating
    Terminating --&gt; Succeeded : ContainersCompleted
    Terminating --&gt; Failed : ContainersFailed
    Terminating --&gt; [*]
    Failed --&gt; [*]
    Succeeded --&gt; [*]
</code></pre>
<p>虽然看起来很细致，但实际上中间忽略了很多细节，一个明显的例子就是，在各个状态之间切换失败时，往往都需要进一步的识别问题根因才能解决。</p>
<p>在《Thinking in Promises》中，有这样一段话：</p>
<blockquote>
<p>我们的文化，偏好于对整体图景进行理解，这种偏好催生了控制系统：这些大型、集中式、无所不知的系统，像大脑一样运作运作，它们根据可用性和一致性的假设做出精确决策，根据我们的微观管理思路，产生直接的指令性的动作。集中化在逻辑上是合理的，然而它导致了规模上的限制。具备庞大处理能力的集中控制在逻辑上是合理的，然而在大规模系统下，仍然可能无法快速决策和执行动作。行动的延迟所导致的不准确和不一致，通常会造成未知后果。</p>
</blockquote>
<p>随着计算、存储、网络的飞速进步，我们能够越来越多地获得系统中各种资源的细节信息，这可能会造成一种“膨胀”的心态——我们希望能够更多地获取系统中发生的所有细节，知晓其所有过往，甚至预测其所有未来。但是问题也很明显，我们面对的世界的复杂度的加速度，远高于我们的采集和管理能力的提升。将连续的物理资源抽象为离散的资源对象，并且以可读代码的方式进行表达，能有效地降低基础设施对注意力的消耗。同时针对软件开发过程设计的版本管理、访问控制、单元测试、文本比对、规则引擎、安全扫描、代码评审等一系列的方法都可以在 IaC 世界中大展拳脚，借助这一技术，管理员能更透明、更快、更大范围地对基础设施进行发放和管理。</p>
<h2 id="heading-iac-2">IaC、面向对象和微服务</h2>
<p>在我使用 IaC 的这一段时间里，新鲜感过后，我遇到了和推广容器化同样的困境——大量的实际业务和管控需求无法满足。在云原生语境中，我通常会用 12 要素等微服务要求来解释为什么你的“微服务”不能容器化。例如其中对进程、状态、配置、快速启动和优雅终止等。但是在 IaC 的落地过程中，我感觉缺乏了这样的理论后盾，有些底气不足。手里有了锤子，自然希望一切都是钉子——这些基础设施不过就是微服务运行所依赖的环境吧？面向对象、微服务架构的各种原则在这里是否继续有效呢？Terraform Provider 开发最佳实践中有这么几条：</p>
<ul>
<li>Providers should focus on a single API or problem domain</li>
<li>Resources should represent a single API object</li>
<li>Resource and attribute schema should closely match the underlying API</li>
</ul>
<p>很明显，这里将 TF Provider 视作了 Restful API 的延伸，而众所周知，Restful API 本身的设计，关注的也是“资源”及其 CURD-L 操作。因此作为 IaC 基础的 Provider 们，本身应该就可以用 OO 的方式进行构建了。IaC 资源就是对物理资源的抽象，我们在软件设计过程中所遵循的设计原则，应该也是适用于 IaC 的实施过程之中的，并且 IaC 应该是整个软件的一部分，因此其复杂度也是小于软件的整体的，顺着这个思路，就可以理直气壮的做些事了。</p>
<h3 id="heading-5oug5yig5acg5qci">拆分堆栈</h3>
<p>在公有云上运行软件，往往会涉及品类繁多的云资源，每次更新都是按照堆栈进行组织的，然而到底围绕一个微服务的堆栈应该由哪些资源组成呢？例如 VPC 算么？容器集群算么？浮动 IP 算么？按照上面的说法，把这些基础设施资源按照拆分微服务的方法进行组织，就方便多了。针对每个资源，简单地回答几个问题，就可以确定其归属了，例如记在谁的账上？谁在使用他？谁负责它的运维？哪些资源是一起更新的？这样几个维度判断下来，围绕着微服务，就能够构建合理的资源堆栈了。</p>
<h3 id="heading-module">Module 的划分</h3>
<p>通常会使用 Module 对资源进行组合，这种组合有很多好处，例如可复用、规范化、降低认知负载等等，然而什么资源和什么资源应该组合成一个 Module 呢？Module 类似于日常开发中的 Library，完全可以使用和共享代码一样的方式，确定其共享范围和功能边界。</p>
<h3 id="heading-5rwb5rc057q6k66k6h">流水线设计</h3>
<p>在 AWS 的 Builder's Library 中提到：</p>
<blockquote>
<p>典型的微服务可能具有应用程序代码管道、基础设施管道、操作系统修补管道、配置/功能标记管道，以及运算符工具管道。同一个微服务拥有多个管道有助于我们更快速地将更改部署到生产环境。未通过集成测试且阻塞应用程序管道的应用程序代码更改不会影响其他管道。例如，它们不会阻止基础设施代码更改到达基础设施管道的生产阶段。同一微服务的所有管道看起来都十分相似。例如，功能标记管道使用的安全部署技术与应用程序代码管道相同，因为错误的功能标记配置更改就像错误的应用程序代码更改一样，可能会影响生产。</p>
</blockquote>
<p>不难发现，上述不同的流水线，也采用了类似微服务的划分方法，多条流水线以独立运作、互不堵塞的方式，用不同的频率个自运行。</p>
<h2 id="heading-5ywl5lmh5bqu6zqp5lx">入乡应随俗</h2>
<p>如你所知，不管是面向对象，还是微服务架构，还没有、也不可能一统天下，IaC 也是这样。在传统运维领域，我们更倾向于掌控变更的全部过程，面对 IaC/Provider 这样的黑盒子，这种追求可能就有些不合时宜了——尤其是对于自行实现的 Provider 来说。</p>
<p>要想穿透 IaC 资源的状态管理，实现基于流程的过程管控，通常可以有两种做法：</p>
<ol>
<li>拆小堆栈：用尽可能小的颗粒度进行变更，这样就从宏观上提供了一个相对细致的管控能力。</li>
<li>暴露细节：将原本被状态迁移隐藏起来的过程，暴露给外部进行观测和限制。</li>
</ol>
<p>小颗粒的堆栈，牺牲的是 IaC 变更的效率和完整性；而暴露内部细节的方式，则破坏了对象的封闭性——像是暴露了所有 Private 成员的类定义，客观上对于“不规矩”/“不完整”的 Provider 是一种鼓励。</p>
<p>正如对 Kubernetes 对象的操作一样，IaC 的管控应该是一个相对“肤浅”、“粗放”的过程，能够依赖的，只能是 Provider 主动开放出来的状态迁移过程。</p>
]]></content:encoded></item></channel></rss>