当前位置: 首页 > news >正文

“氛围编程让一切看起来很廉价,我要回归手写编码了!”

如果说这几年 AI 编程令人沉迷的地方,是“几乎不费力就能把东西做出来”,那么真正让人开始警觉的瞬间,往往发生在系统第一次“看起来还在工作,但已经开始悄悄失控”的时候。

这篇来自 k10s 作者的长文,就是从那个临界点开始往回看的。他记录了一次几乎完全依赖 vibe-coding 的开发实验:从一个 GPU 感知的 Kubernetes TUI,到一个功能不断膨胀、最终被自身复杂度吞噬的系统。过程中有过极高的开发速度,也有过 AI 一次性生成完整功能的“爽感时刻”,但同样也埋下了架构失控、状态混乱和隐性 bug 的伏笔。

更重要的是,这不是一篇单纯的“翻车复盘”,而是一份带着具体代码细节、设计选择和反思路径的拆解记录。它试图回答的并不是“AI 能不能写代码”,而是另一个更现实的问题:当 AI 真的参与到软件构建的每一层时,人类到底还需要在哪些地方重新夺回控制权。

原文:https://blog.k10s.dev/im-going-back-to-writing-code-by-hand/

作者 | shvbsle 责编 | 苏宓

出品 | CSDN(ID:CSDNnews)

这件事最开始其实更像一次实验,或者说一个问题——“如果我尽可能不亲自参与开发流程,只靠 AI 来写软件,我到底能走多远?”

话不多说,这篇开发日志最终得出的核心结论是:如果真想做出点有意义的东西,人类依然必须参与其中。

几点感受:

  • 就像 “em-dash(长破折号)” 已经快成 AI 写作的标志一样,“god-object(上帝对象)” 也快成 AI 写代码的典型特征了。

  • “氛围编程” 会让一切看起来都很廉价,你最后很可能会失去重点,做出越来越臃肿的东西。

  • 架构一定要由人(也就是你)来设计,而不是不停地让 AI 往里加功能。

  • 另外,我还整理了一些 AGENTS.md / CLAUDE.md 的指令配置,它们确实能让我稍微少亲自下场一点。

截至 2026 年 5 月 10 日,人类干预依然是必需的。

这项实验到底验证了哪些东西,以下是完整的过程。

234 次提交、30 个周末,用氛围编码开始一个项目

这是 k10s GitHub 仓库:https://github.com/shvbsle/k10s/tree/archive/go-v0.4.0

234 次提交,差不多花了 30 个周末。整个项目几乎完全是在“氛围编程”状态下完成的——只要 Anthropic 的 Claude token 额度还没耗尽,我就继续往前做、继续发功能。

现在,我决定把这个 TUI 工具归档,然后从头开始重写。

k10s 最初的定位,是一个“支持 GPU 感知”的 Kubernetes Dashboard,也是我第一次认真尝试用 AI 去开发一个真正复杂的软件。

你可以把它理解成一个面向 NVIDIA GPU 集群的 k9s,服务的是那些真正关心 GPU 利用率、DCGM 指标,以及哪些节点正在空转烧钱(每小时 32 美元)的人。

我用 Go 和 Bubble Tea 写了它,而且它一开始确实能跑。

至少……有一段时间是这样。

过去 7 个月里我学到的东西,比我现在准备删掉的那 1690 行 model.go 更有价值。我觉得,任何认真尝试“vibe-coding”的人,可能都会从这些经验里得到点东西,因为这部分内容其实很少有人讨论——它通常都会被那些炫酷 Demo 和“开发速度暴涨”的故事掩盖掉。

一句话总结:AI 会帮你写功能,但不会帮你设计架构。如果你长时间不加约束地让它“自己运行”,最后只会留下越来越严重的事故现场。开发速度会让你误以为自己一路领先,直到某个瞬间,整个系统开始同时崩塌。

加入 AMD AI 开发者计划,免费领 50 小时云算力券

进群月月抽显卡、AIPC,好运不停!


“氛围编程”上头的时候

我是在 2025 年 9 月底开始做 k10s 的。

最开始那几周,简直像魔法一样。

我对 Claude 说一句:“加一个支持实时更新的 Pods 视图”,然后“砰”的一下,功能就出来了。

资源列表视图、命名空间筛选、日志流、描述面板、键盘导航……一个个功能都顺利落地。原因也很简单:那时候项目还足够小,AI 还能把整个工程都“装进上下文”里。

最基础的那个 “k9s 克隆版”,我大概只花了 3 个周末。它包含了:

  • Pods、Nodes、Deployments、Services 的资源视图;

  • 命令面板;

  • 基于 Watch 的实时更新;

  • Vim 风格快捷键……

全部都能跑,而且几乎全是在单次 session 里“vibe-coded”出来的。我当时的开发速度,可能是平时的 10 倍。那种感觉真的很爽。

然后,我开始做这个项目真正的核心卖点。

k10s 存在的真正原因,其实是 GPU 集群视图(GPU Fleet View)。

我想做一个专门的界面,让你能一眼看到每个节点的 GPU 分配情况、DCGM 利用率、温度、功耗、显存占用。

不是把信息埋在 kubectl describe node 那种输出里,而是做成一个专门设计的表格界面,并且带颜色状态提示:空闲节点显示黄色、繁忙节点显示绿色、GPU 打满显示红色。

结果 Claude 一次就生成成功了。

我只写了个 prompt,它就直接生成了 FleetView 结构体、GPU / CPU / All 的标签过滤、自定义渲染逻辑、GPU 分配进度条,而且界面看起来还特别漂亮。

那时候我整个人都沉浸在“AI 开发效率爆炸”的快感里。

直到后来,我输入了一句:

:rs pods

想切回 Pods 视图。

结果什么都没出来。表格是空的。实时更新停了。

我切换到 Nodes 视图时,它显示的还是 Fleet View 的旧过滤数据。

再切回 Fleet View,标签统计数字又全错了。

那个“上帝对象(god object)”,终于把自己吞噬掉了。

这也是这篇博客标题的来源。也是我第一次真正“人工介入”的时刻。

整整 7 个月里,我一直都在“prompt → 生成 → 发布”,却从来没有真正坐下来认真读过 Claude 写的代码。

我通常只是看一下 diff、确认能编译、再测一下 happy path、然后继续往前做。

但这次不一样了。

这已经不是再写个 prompt 就能解决的问题。系统的基础结构已经坏掉了。

于是,我第一次真正坐下来,开始读 model.go。整整 1690 行代码。我当场头皮发麻。

代码大概是这样的:一个结构体统治一切。

type Model struct { // 3rd party UI components table table.Model paginator paginator.Model commandInput textinput.Model help help.Model // cluster info and state k8sClient *k8s.Client currentGVR schema.GroupVersionResource resourceWatcher watch.Interface resources []k8s.OrderedResourceFields listOptions metav1.ListOptions clusterInfo *k8s.ClusterInfo logLines []k8s.LogLine describeContent string currentNamespace string navigationHistory *NavigationHistory logView *LogViewState describeView *DescribeViewState viewMode ViewMode viewWidth int viewHeight int err error pluginRegistry *plugins.Registry helpModal *HelpModal describeViewport *DescribeViewport logViewport *LogViewport logStreamCancel func() logLinesChan <-chan k8s.LogLine horizontalOffset int mouse *MouseHandler fleetView *FleetView creationTimes []time.Time allResources []k8s.OrderedResourceFields // fleet's unfiltered set allCreationTimes []time.Time // fleet's timestamps rawObjects []unstructured.Unstructured ageColumnIndex int // ...}

UI 组件、K8s Client、日志状态、Describe 状态、Fleet 状态、导航历史、缓存、鼠标事件处理……全部塞进了同一个 struct。

而 Update() 方法更夸张:一个 500 行的大函数,里面根据 msg.(type) 分发逻辑,堆了 110 个 switch/case 分支。

也就是从这一刻开始——我不再只是凭氛围进行编码,而是开始真正思考软件工程了。

从“事故现场”里总结出的五条原则

这是我花了 7 个月时间,看着 AI 一点点生成、并最终“反噬自身”的代码库后,总结出来的东西。

下面每一条,都是我亲自踩过的坑:

  • 我哪里做错了?

  • 为什么 AI 辅助编程特别容易掉进这个坑?

  • 以及,你到底应该在 CLAUDE.md 或 agents.md 里写些什么,才能提前避免它?

原则一:AI 会写功能,但不会设计架构

每次我让 Claude 加一个功能,它都能做出来,而且完成得相当漂亮。

Fleet View 一次成功,日志流能跑,鼠标支持功能也能运行。

问题在于:每个功能,都是站在“先把当前需求做出来”的角度实现的。它根本不会意识到,系统里还有另外 49 个共享同一份状态的功能。

举个例子,下面这个 resourcesLoadedMsg handler,是每次切换视图时都会执行的代码。

case resourcesLoadedMsg: m.logLines = nil // Clear log lines when loading resources m.horizontalOffset = 0 // Reset horizontal scroll on resource change if m.currentGVR != msg.gvr && m.resourceWatcher != nil { m.resourceWatcher.Stop() m.resourceWatcher = nil } m.currentGVR = msg.gvr m.currentNamespace = msg.namespace m.listOptions = msg.listOptions m.rawObjects = msg.rawObjects // For nodes: store the full unfiltered set, classify, then filter if msg.gvr.Resource == k8s.ResourceNodes && m.fleetView != nil { m.allResources = msg.resources m.allCreationTimes = msg.creationTimes if len(msg.rawObjects) > 0 { m.fleetView.ClassifyAndCount(m.rawObjectPtrs()) } m.applyFleetFilter() } else { m.resources = msg.resources m.creationTimes = msg.creationTimes m.allResources = nil m.allCreationTimes = nil }

你看到这个「if msg.gvr.Resource == k8s.ResourceNodes && m.fleetView != nil」条件语句了吗?

这代表 Fleet View 被硬编码进了通用资源加载流程。之后,每新增一个需要“特殊行为”的视图,这里就会再多一个 if branch。

而且每个 branch 还得手动清理对应字段,否则前一个视图的数据就会“泄漏”到下一个视图里。

我后来专门数了一下:这个文件里到底有多少个 = nil 的手动清理逻辑?

m.logLines = nil // Clear log lines when loading resourcesm.allResources = nil // Clear fleet data when not on nodesm.resources = nil // Clear resources when loading logsm.resources = nil // Clear resources when loading describe viewm.logLines = nil // Clear log lines when loading describe viewm.resources = nil // Clear resources when loading yaml viewm.logLines = nil // Clear log lines when loading yaml viewm.logLines = nil // ... two more in other handlersm.logLines = nil

答案是:9 个。9 个散落在 1690 行文件里的“手动状态回收”。漏掉任何一个,你就会看到前一个视图留下的“幽灵数据”。

这就是没有“视图隔离”时必然发生的事情。而 AI 根本看不到这个架构正在慢慢腐烂。

因为每一次 prompt,它只会关注当前那一条代码路径。

正确做法的是,在写任何代码之前,先自己把架构设计好。

不是那种空泛的设计文档。而是要编写一套有明确的接口、消息类型、状态所有权规则。然后把这些规则写进 CLAUDE.md:

# Architecture Invariants (CLAUDE.md)- Each view implements the View trait. Views do NOT access other views' state.- All async data arrives via AppMsg variants. No direct field mutation from background tasks.- Adding a new view MUST NOT require modifying existing views.- The App struct is a thin router. It owns navigation and message dispatch. Nothing else.

这样 AI 每次收到 prompt 时,都会先看到这些约束。

原则二:“上帝对象”是 AI 默认生成的产物

AI 天生喜欢“一个 struct 管一切”。因为这是满足 prompt 最省事的方法。

但问题会越来越严重。由于没有视图隔离,键盘事件处理最终会变成灾难。

比如下面这个 s 键的实际逻辑:

case m.config.KeyBind.For(config.ActionToggleAutoScroll, key): if m.currentGVR.Resource == k8s.ResourceLogs { m.logView.Autoscroll = !m.logView.Autoscroll if m.logView.Autoscroll { m.table.GotoBottom() } return m, nil } // Shell exec for pods and containers views if m.currentGVR.Resource == k8s.ResourcePods { // ... 20 lines to look up selected pod, get name, namespace ... return m, m.commandWithPreflights( m.execIntoPod(selectedName, selectedNamespace), m.requireConnection, ) } if m.currentGVR.Resource == k8s.ResourceContainers { // ... container exec logic ... return m, m.commandWithPreflights(m.execIntoContainer(), m.requireConnection) } return m, nil

同一个快捷键,在不同视图里有三种完全不同的含义:

  • 在 Logs 里表示“自动滚动”

  • 在 Pods 里表示“进入 Shell”

  • 在 Containers 里表示“进入容器 Shell”

所有逻辑,全塞在同一个巨型 switch 里。

为什么会变成这样?因为我对 AI 说:“给 Pods 加 shell 支持。”

于是它就找到最近的键盘处理逻辑,直接把代码塞进去。

再看 Enter 键。整个 drill-down handler 也是同样的问题。

case m.config.KeyBind.For(config.ActionSubmit, key): // Special handling for contexts view if m.currentGVR.Resource == "contexts" { // ... 12 lines ... return m, m.executeCtxCommand([]string{contextName}) } // Special handling for namespaces view if m.currentGVR.Resource == "namespaces" { // ... 12 lines ... return m, m.executeNsCommand([]string{namespaceName}) } if m.currentGVR.Resource == k8s.ResourceLogs { return m, nil } // ... 25 more lines of generic drill-down ...

所有视图都被塞进一个“平铺式 dispatch”。整个文件里,有 20 多处:m.currentGVR.Resource == ...这样的字符串判断。

这里说的不是类型系统、不是抽象接口,只是字符串比较。

这意味着每新增一个视图,你都得改所有 handler。

正确的做法是,你应该在 CLAUDE.md 里明确写下规则:

# State Ownership Rules- NEVER add fields to the App/Model struct for view-specific state.- Each view is a separate struct implementing the View trait/interface.- Each view declares its own key bindings. The app dispatches keys to the active view.- If you need to add a keybinding, add it to the relevant view's keymap, not a global one.- Adding a view means adding a file. If your change requires modifying existing views, stop and ask.

AI 永远会走“最短路径”——也就是“再加一个 if 分支”。你的工作,是让“最短路径”同时也是“正确路径”。而方法,就是把约束提前写进 AI 每次都会读取的规则文件里。

原则三:开发速度的幻觉,会不断扩大你的项目范围

这一条不是技术问题,是心理问题,也是我觉得最危险的一条。

我一开始做 k10s 时,目标其实很简单,就是设计一个面向 GPU 集群的小众工具,给那些跑训练集群的人用,也就是我自己这种人。

但 “vibe-coding” 会让一切看起来都太便宜了。“哦?Pods 视图一晚上就做完了?”

那顺手再加 Deployments、Services、完整命令面板、鼠标支持、Context 管理、Namespace 管理..

最后我突然发现:我已经在重新造一个 k9s 了。

一个面向所有人的通用 Kubernetes TUI,因为 AI 让每个功能都显得“像不要钱一样”。

但它其实不是免费的。每个新功能,都是那个“上帝对象”里新增的一条分支。

比如这个 keybinding struct:

type keyMap struct { Up, Down, Left, Right key.Binding GotoTop, GotoBottom key.Binding AllNS, DefaultNS key.Binding Enter, Back key.Binding Command, Quit key.Binding Fullscreen key.Binding // log view Autoscroll key.Binding // log view (also shell in pods!) ToggleTime key.Binding // log view WrapText key.Binding // log + describe view CopyLogs key.Binding // log view ToggleLineNums key.Binding // describe view Describe key.Binding // resource views YamlView key.Binding // resource views Edit key.Binding // resource views Shell key.Binding // pods (CONFLICTS with Autoscroll!) FilterLogs key.Binding // log view FleetTabNext key.Binding // fleet view only FleetTabPrev key.Binding // fleet view only}

所有视图共用一个扁平化的 keymap。

注释里甚至还得写:“这个快捷键属于哪个视图”;s 同时代表 Autoscroll、Shell;之所以“还能工作”,只是因为 dispatch 里会先检查 m.currentGVR.Resource。

但代价是你已经无法局部理解任何一个快捷键了。

你必须一路追踪整个 500 行的 Update(),才能知道一个按键最终会干什么。

复杂度正在悄悄累积,而 AI 给你的“速度反馈”却一直在告诉你:“你开发得真快。”

正确的做法是:提前写一份 Vision Doc。明确写清楚“哪些用户不是你的目标用户”,然后把项目边界写进 CLAUDE.md。

# Scope (do NOT expand beyond this)k10s is for GPU cluster operators. Not all Kubernetes users.Supported views: fleet, node-detail, gpu-detail, workload. That's it.Do NOT add generic resource views (pods, deployments, services).Do NOT add features that duplicate k9s functionality.If a feature request doesn't serve someone running GPU training jobs, reject it.

“Vibe-coding” 会让你误以为自己拥有无限开发预算。其实你拥有的,只是“无限代码行预算”。AI 可以无限生成代码,但你的“复杂度预算”仍然是有限的。无论代码写得多快,架构能承受的功能数量始终有限。超过之后,它一定会塌。

CLAUDE.md 里的 scope section,本质上就是:在“速度快感”让你什么都想加之前,提前替自己说“不”。

原则四:位置型数据结构,就是定时炸弹

在 k10s 里,所有资源数据从 Kubernetes API 拉下来之后,都会立刻被“拍平”:

type OrderedResourceFields []string

列信息完全依赖“位置”。比如 Fleet View 的排序逻辑:

func sortFilteredResources(rows []k8s.OrderedResourceFields, times []time.Time, tab FleetTab) { sort.SliceStable(indices, func(a, b int) bool { ra := rows[indices[a]] rb := rows[indices[b]] switch tab { case FleetTabGPU: // Sort by Alloc column (index 3) ascending allocA, allocB := "", "" if len(ra) > 3 { allocA = ra[3] } if len(rb) > 3 { allocB = rb[3] } return allocA < allocB case FleetTabCPU: // Sort by Name column (index 0) ascending nameA, nameB := "", "" if len(ra) > 0 { nameA = ra[0] } if len(rb) > 0 { nameB = rb[0] } return nameA < nameB case FleetTabAll: // GPU nodes first, then CPU nodes. // Within GPU: sort by Alloc (index 3). // Within CPU: sort by Name (index 0). computeA, computeB := "", "" if len(ra) > 2 { computeA = ra[2] } if len(rb) > 2 { computeB = rb[2] } aIsGPU := strings.HasPrefix(computeA, "gpu") bIsGPU := strings.HasPrefix(computeB, "gpu") // ... } })}

ra[3] 表示 Alloc。ra[2] 表示 Compute。ra[0] 表示 Name。全是“魔法数字”。

index 3 为什么代表 Alloc?

唯一的依据,只是一条注释和 resource.views.json 里的列顺序。

{ "nodes": { "fields": [ { "name": "Name", "weight": 0.28 }, { "name": "Instance", "weight": 0.15 }, { "name": "Compute", "weight": 0.12 }, { "name": "Alloc", "weight": 0.12 }, ... ] }}

在 Instance 和 Compute 之间加一列?那所有排序逻辑、所有条件渲染、所有写着 ra[2] 或 ra[3] 的地方,都会在不知不觉中失效。编译器根本帮不上忙,因为这些数据全都是 []string。

更糟的是,JSON 配置根本没法表达排序行为、条件渲染或自定义 drill-down 跳转目标,所以这些逻辑最后只能写进 Go 代码里,而代码又硬编码地依赖 JSON 中字段的位置。

AI 会生成这种模式,因为这是从“获取数据”到“渲染表格”的最短路径。一个 []string 可以立刻塞进任何表格组件里,而强类型结构体(typed struct)前期需要更多样板代码(ceremony)。于是 AI 总会选择那条最快的路。结果六个月后,你开始排查为什么排序后,“Name” 列的数据会出现在 “Alloc” 列里。

正确做法是什么?把这条规则写进你的 CLAUDE.md:

# Data Representation- NEVER flatten structured data into []string, Vec<String>, or positional arrays.- All data flows as typed structs (FleetNode, PodInfo, etc.) until the render() call.- Column identity comes from struct field names, not array indices.- Sort functions operate on typed fields, never on positional access like row[3].- The ONLY place strings are created for display is inside render()/view() functions.

这样一来,你定义的强类型结构体(typed struct)就能让“不可能出现的状态”真正变得不可能出现 [2]:

struct FleetNode { name: String, instance_type: String, compute_class: ComputeClass, alloc: GpuAlloc,}

当列对应的是具名字段时,你就不可能排错列。你也不可能误把 Alloc 字段的字符串当成名字去比较。编译器会替你强制保证这些约束。

而 AI 永远会倾向于选择 Vec<String>,因为它能更快满足提示词要求。你在 CLAUDE.md 里写下的规则,本质上就是在把“强类型”这条路,变成阻力最小、最容易被 AI 采用的默认路径。

原则五:AI 不应该掌控状态变更。

Bubble Tea 的架构里有一个很漂亮的理念:Update() 是唯一允许状态发生变化的地方,而且所有状态变更都由消息驱动。但 k10s 违背了这一点。

updateTableMsg 处理器启动了一个闭包,在 goroutine 内部修改 Model 字段:

case updateTableMsg: return m, func() tea.Msg { // block on someone sending the update message. <-m.updateTableChan // Preserve cursor position across column/row updates so that // background refreshes don't reset the user's selection. savedCursor := max(m.table.Cursor(), 0) // run the necessary table view update calls. m.updateColumns(m.viewWidth) m.updateTableData() // Restore cursor, clamped to valid range. rowCount := len(m.table.Rows()) if rowCount > 0 { if savedCursor >= rowCount { savedCursor = rowCount - 1 } m.table.SetCursor(savedCursor) } return updateTableMsg{} }

这个返回函数(tea.Cmd)会被 Bubble Tea 放到独立 goroutine 执行。它里面调用了 m.updateColumns(m.viewWidth) 和 m.updateTableData() 函数。这些函数会同时读写 m.resources、m.table、m.viewWidth。

与此同时,主线程里的 View() 也在读取同一批字段。没有锁。没有 mutex。

<-m.updateTableChan 虽然会阻塞 goroutine,直到收到更新信号,但它根本无法阻止 View() 在“状态只更新到一半”的时候进行读取。

这是教科书级别的数据竞争(data race)。99% 的时间它看起来都正常。剩下 1% 的时间,它会以一种极其诡异的方式损坏 UI。严重到让我一度怀疑自己精神出了问题。

AI 为什么会生成这种代码?是因为“直接在 closure 里修改状态”是最快能跑起来的方案。

而正确的消息传递架构是 worker 发消息、Update() 收消息、主循环统一修改状态,需要更多类型、更多 plumbing。

AI 不会为了并发正确性去做这些。它只会为了“当前 prompt 能跑”去优化。

正确的做法是,所有对“影响渲染的状态”的修改,都必须发生在主循环里,仅此一条原则,没有例外。后台 worker 只负责产生数据,然后把数据以 message 的形式发送出去。主循环接收 message,再统一应用状态变更。在并发 UI 代码里,这是唯一不能被打破的规则。

// Background task:tx.send(AppMsg::FleetData(nodes)).await;// Main loop:match msg { AppMsg::FleetData(nodes) => { self.fleet_view.update_nodes(nodes); }}

不要共享可变状态。不要数据竞争。不要“99% 情况下能跑”。

把这些规则写进 CLAUDE.md。

# Concurrency Rules- Background tasks (watchers, scrapers, API calls) NEVER mutate UI state directly.- Background tasks send results through a channel as typed messages.- Only the main event loop applies state mutations from received messages.- render()/view() is a PURE function. No side effects. No I/O. No channel operations.- If you need to update state from async work, define a new AppMsg variant.

如果 AI 默认不会这样写代码。那规则文件就必须强制它只能这样写。

我现在准备怎么做

我正在用 Rust 重写 k10s。不是因为 Rust “更强”。而是因为——这是我真正“能掌控”的语言。我已经写了足够多的 Rust,以至于很多时候,代码哪里不对劲,我甚至在还没说清原因之前,就已经能本能地察觉到。而这种“直觉”,恰恰是 vibe-coding 永远替代不了的东西。AI 会给你一份“看起来很合理”的代码。但你必须自己具备一种嗅觉:知道它什么时候其实是一坨垃圾。

另一个变化则更简单:这一次,我会亲手完成设计工作。而且是在写任何代码之前。不是那种空泛的大纲文档。而是拥有明确的接口、消息类型、所有权规则。

之前那些总被 AI 做错的架构决策,现在我会在第一条 prompt 发出去之前,先白纸黑字地写清楚。

至于这样做,最终能不能避免这次重构再次“被自己的复杂度压垮”……拭目以待!

推荐阅读:

人均奖金达610万?SK海力士回应;微信灰度测试转账「组合支付」;黄仁勋:应届生们别怕AI,当下是开启事业的最佳时机 | 极客头条

开源打破“AI黑箱”!集结全球大咖,GOSIM Paris 2026带你看懂Agent时代大变局

“今年还没亲手写过一行代码”,Claude Code之父自曝:CC诞生源于“偶然”,现主要在手机上干活

从“拥抱 AI”到“AI 原生”,我们正站在生产力变革的奇点。

由 CSDN 与奇点智能研究院联合举办的「2026 全球产品经理大会」将于 7 月 17-18 日在北京正式召开。本次大会精心设计了十二个深度专题,旨在通过最前沿的实战案例,拆解 AI 原生时代的进化密码。

目前大会正式开启演讲议题与优质分享嘉宾招募。

你的每一次真实分享,都在为 AI 原生时代的产品实战手册添砖加瓦。

我们在北京,期待听见你的声音。

议题 & 嘉宾推荐/自荐方式:hemiao@csdn.net

http://www.jsqmd.com/news/807799/

相关文章:

  • 从提示词到上下文工程:大模型应用范式的根本性转变
  • XML Notepad:3分钟快速上手的免费XML编辑器终极指南
  • 2026十大专业精益生产管理咨询公司排名 - 远大方略管理咨询
  • CoPaw Desktop:构建本地化、模块化的AI工作流,保障数据隐私与灵活控制
  • 零配置AI媒体创作技能集:开箱即用的图像、音频、视频生成与自动化工作流
  • 开源AI应用框架xpander.ai:快速构建企业级AI应用的全栈解决方案
  • 2026 济南黄金回收变现避坑指南|正规门店汇总+干货技巧 - 奢侈品回收测评
  • 游戏模组管理的终极解决方案:XXMI启动器完整使用指南
  • HoYo-Glyphs完整指南:免费获取米哈游游戏字体并轻松使用
  • 终极指南:如何在Windows上完美使用PS4/PS5手柄玩PC游戏
  • 聊聊华为的Atlas 950超节点
  • 2026年成都线下打酒铺TOP6权威排行榜,带你解锁酒铺新体验! - 品牌推荐官方
  • Rust声明式金融计算引擎Bellman:高性能与正确性的工程实践
  • UIFO网络包调度技术:动态优先级与硬件实现解析
  • 显高鞋子哪家推荐? - 中媒介
  • “飞行汽车没来,但Win32还活着”!微软CTO亲口承认:Win11还在靠90年代「祖传代码」撑着
  • 医疗植入设备中电容器的关键作用与可靠性设计
  • GTA5线上小助手:释放你的洛圣都潜能,打造极致游戏体验
  • 模块化手机为何失败?从Project Ara看硬件创新的六大工程挑战
  • 2026年口碑好的人力资源咨询公司推荐 - 远大方略管理咨询
  • 极客文化的世俗化:从小众爱好到主流职业
  • 深度定制Axolotl:扩展新算法与训练策略-方案选型对比
  • 基于Next.js与适配器模式的开源AI应用构建平台实战指南
  • 量子光子学中稳健定向耦合器设计与应用
  • 潮流普惠品牌哪家专业? - 中媒介
  • 头部靠谱的流程管理咨询公司推荐 - 远大方略管理咨询
  • 开源情报OSINT实战:模块化搜索框架OpenClaw架构与应用
  • 微信聊天记录永久保存完整指南:5步从手机备份到电脑永久查看
  • 2026年费用低的富阳排屋中介推荐,靠谱吗? - mypinpai
  • 仅 2.3M 参数!GSA-YOLO 破解电站密闭空间安全帽检测三大难题