AI 编程时代,我愿意用 Go 做后端

AI 编程时代,我愿意用 Go 做后端 AI 编程工具越来越会写代码,但真正把一个 AI 应用跑到线上,难点从来不只是"能不能生成一个接口"。请求超时怎么处理,模型服务失败后怎么重试,流式响应如何关闭,服务占多少内存,镜像怎样发布,出了问题能不能快速回滚,这些才是后端每天要面对的事情。 我越来越愿意把 Go 放在 AI 应用的后端位置:让 AI 负责加快实现,让 Go 负责把边界、资源和部署约束固定下来。这里说的不是把模型训练和推理强行改写成 Go,而是模型外围的 API、网关、任务和编排服务。蓝色文字表示语言和工程特性,绿色文字表示我的实践判断,红色文字表示容易被忽略的风险,黄色底色表示可以直接采用的做法。 一、Go 不会让 AI 更聪明,但会让错误更快暴露 我用 AI 写后端时,最常见的情况不是代码完全不能运行,而是它给出了一条顺利路径,却把失败路径一笔带过。比如调用大模型时,AI 很容易生成下面这种代码: func AskModel(prompt string) string { resp, _ := http.Get("http://model:8080/v1/chat") body, _ := io.ReadAll(resp.Body) return string(body) } 这段代码的问题很多:忽略了网络错误,没有关闭响应体,没有设置超时,也没有检查状态码。它可能在本地演示中返回结果,但一旦模型服务变慢,连接就可能长期占用;一旦服务返回 500,调用方拿到的可能仍然是一段错误页面。 Go 的显式语法会把这些问题推到台面上。error 必须被接收,类型转换必须写明,defer、context 和 goroutine 的生命周期也不会凭空消失。 这对 AI 生成代码形成了一种很有价值的约束:编译器先拦住低级问题,人再检查业务决策。 例如,我会要求模型先生成一个"责任完整的版本": var ErrModelUnavailable = errors.New("model service unavailable") func AskModel(ctx context.Context, client *http.Client, endpoint string, prompt string) ([]byte, error) { payload, err := json.Marshal(map[string]string{"prompt": prompt}) if err != nil { return nil, fmt.Errorf("encode model request: %w", err) } req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(payload)) if err != nil { return nil, fmt.Errorf("create model request: %w", err) } req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("call model: %w", err) } defer resp.Body.Close() if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { return nil, fmt.Errorf("model returned status %d: %w", resp.StatusCode, ErrModelUnavailable) } body, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20)) if err != nil { return nil, fmt.Errorf("read model response: %w", err) } return body, nil } 这里不是说 Go 写起来没有重复代码,而是每个关键动作都落到具体的代码位置:编码、请求、响应、释放、超时、错误,全都看得见也改得动。 ...

2026-08-24 · 4 min · 666 words · FunkyGod

学习和理解 OpenAI 的 Responses:模型调用过程的原子事务

学习和理解 OpenAI的Responses:模型调用过程的原子事务? Responses 的核心价值,不是把接口名称从 Chat Completions 换成了 responses,而是把模型调用从“返回一段文本”升级成了可组合、可追踪、可继续执行的结构化结果。一次调用可以同时产出最终消息、函数调用、内置工具调用和受控的推理摘要;应用不必再把所有信息塞进一段字符串里猜测和解析,而是可以按 item 类型决定下一步动作。 这个变化真正解决的是 Agent 工程里的三个问题:模型做了什么更容易追踪,工具调用怎么接续更清楚,失败后从哪里恢复更具体。最近和同事讨论 OpenAI 的 Responses API,我发现最容易混淆的不是请求怎么发,而是“一次 Response 到底装了什么”。我现在更愿意把它理解成:一次有结构的模型调用记录。它可以成为调试、审计和多轮协作的共同载体,但它不是数据库里的 ACID 事务,也不是默认把完整思维链交给用户。“原子事务”只是一种帮助理解的比喻:工程上真正要记录的是调用 ID、item 类型、工具结果、失败状态和业务幂等关系 ┌─────────────────────────────────────────────────────────┐ │ Responses 协议心智图 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 你发起 ──→ 一次 Response(原子事务) │ │ │ │ │ ├── input (输入) │ │ ├── instructions (系统级设定) │ │ ├── tools (可选能力清单) │ │ │ ├── 内置工具 (web/file/code/MCP)│ │ │ └── 自定义函数 │ │ ├── previous_response_id (状态游标) │ │ └── stream / background (执行模式) │ │ │ │ 服务端返回 ──→ 一个 Response 对象 │ │ │ │ │ └── output[] (异构工件清单) │ │ ├── reasoning (思维证据) │ │ ├── tool_call (动作证据) │ │ │ ├── 入参 │ │ │ └── 结果 │ │ └── message (交付物) │ │ │ └─────────────────────────────────────────────────────────┘ ...

2026-08-24 · 3 min · 578 words · FunkyGod

AI 一口气生成几百行代码,我们该怎么高效且正确地处理代码审核

AI 一口气生成几百行代码,我们该怎么高效且正确地处理代码审核 一、当 AI 能在一分钟里吐出一两百行代码时,真正的难点早已不是“写不出来”,而是“接得住、查得动、改得回、负责得起”。我自己一天常常让 AI 写十几轮,单次 50–300 行很常见,一周下来累计几千行并不夸张。这里面能直接合进主干的大概只有一半,剩下要么是风格不一致、要么是越权操作、要么是没覆盖到我期望的边界,真正被我留下来再加工的常常只有三分之一。速度确实上去了,但读、改、回滚这些事没有便宜半分。我需要同时做目标设计者、规则制定者和成果验收者:先把问题、边界和验收条件讲清楚,再让 AI 在明确的范围里多试几种写法、多跑几轮检查,最后由我看差异、看风险、看回滚路径,再决定是否合并。这一顺序不能反过来——如果我自己都不知道“完成”长什么样,再快的生成也只是把模糊需求放大成更难检查的代码。带着这个结论再读这个题目,会更容易看清它真正在问什么:不是“AI 写得太快怎么办”,而是“当写的成本被工具压平以后,程序员到底该把时间花在哪几个动作上,才能既不返工,也不背锅”。 二、过去半年我最大的感受是,AI 把“写一段代码”的价格压下去了,但“看懂一段代码”的价格几乎没变。一个函数能不能写出来,今天大多数时候已经不构成瓶颈;真正占用时间的,是它处在什么上下文、用了哪些约定、隐含了哪些假设、会不会影响别的模块。一个项目里如果突然多出几百行 AI 代码,常见问题不是“明显错误”,而是“看起来很像正确答案”。我整理了几类实际反复遇到的偏差:在 Go 项目里写出 Python 风格的命名(snake_case 夹杂驼峰、把 换成 ),在 React 项目里调用一年前版本的 清理写法,在 iOS 项目里把 写成一串 嵌套,在 SQL 里写出 ORM 不能识别的方言。这些都不算 Bug,跑得起来,过得了 lint,但放进项目里就是和团队既有代码打架。错误处理走的是另一套约定、用了项目里没人熟悉的依赖、或者把一份本该抽出来的逻辑写成了复制粘贴,也都同源。这并不是 AI 不努力,而是它默认按“训练里最常见的写法”回答,而不是按“这一个项目里最合理的写法”回答。读代码一旦要一边猜意图、一边查背景、一边补差异,效率马上塌掉。所以处理 AI 批量生成代码的第一个动作,不是立刻评审,而是先把这些代码放到一个能被人快速消化的上下文里:让它先和现有约定对齐,再让它进入人的视线。我自己的小习惯是:先跑一遍项目的 formatter / import-sort / gofmt-prettier / eslint --fix,把肉眼可见的风格差异抹掉,再开始看逻辑。看起来是小事,能省下 review 时一半的争论。 三、把 AI 当成“一小时能写完一周活”的同事是不够的,更准确的定位是:它负责在明确边界内把重复部分做出来,人负责在模糊地带做判断。越模糊的需求,越不该直接交给 AI;越清晰的接口,越适合让 AI 多试几种实现。具体到我自己:在把任务交给 AI 之前,我会先填一份简短的“任务说明模板”,哪怕只是几行清单: 目标:这次改动要解决什么,用一两句话讲清楚; 不能破坏的行为:列出已有的功能、API 兼容点、对外契约; 验收条件:包括成功路径、失败路径、边界输入、需要的日志或埋点; 范围:哪些文件/模块允许改动,哪些只能引用不能改; 测试:要求覆盖的关键 case(哪怕只是几条自然语言描述); 依赖:允许引入哪些新包,是否需要更新 lockfile、是否要走安全 review。 这份清单写在 issue、PR 描述、或者本地 prompt 模板里都行。我自己最常用的是把它贴在每次开新对话的第一段,让 AI 在生成前自己复述一遍——如果 AI 的复述和我理解的不一致,我先纠正它,再让它写代码。这一步看起来比直接生成慢一点,但它避免了我最怕的那种返工:代码已经写得很长,最后才发现我根本没想清楚要的是什么。一旦让 AI 开始写,我会刻意要“两三种实现思路”,而不是一个最终答案:每种思路分别有什么取舍、依赖、风险点,分别适合什么场景。AI 在这里负责的是“扩宽选择范围”,我负责的是“决定走哪条”。判断做完之后,AI 仍然很有用:写样板、补测试、翻译接口、改一处风格、批量重命名——这些是它擅长、我也乐意外包的部分。把“想清楚”和“写出来”分成两步,比把“想”也外包出去重要得多。 ...

2026-08-23 · 2 min · 228 words · FunkyGod

Cursor 双周综述|从 Git 存储到生产监控:编码 Agent 的闭环野心

本期导读 2026年8月13日-23日,Cursor 发布了多条重要更新。本期重点关注两条: Origin Code Hosting:Vicent Martí(GitHub 前首席工程师)操刀设计的 Git 存储系统 Continuity,用 WAL(Write-Ahead Log)+ S3 的思路重新理解 Git 规模化问题 Firetiger 团队加入:收购专注于生产环境监控的初创团队,打通"写代码 → 部署 → 观测"的 Agent 闭环 一、Continuity:重新设计 Git 存储的思路 1.1 Git 规模化的本质困难 Cursor 这篇文章的水准超出预期——不是产品宣传,而是一篇真正的系统设计论文。作者 Vicent Martí 曾是 GitHub 基础设施团队核心成员,亲历过 Spokes 系统的设计与演进,因此能写出"内部视角"的反思。 Git 的核心困难在于它的两层 DAG 结构: 逻辑层:commit → tree → blob 的有向无环图 物理层:packfile 内部对象的随机分布(delta 压缩、对象重排) 这两层之间没有任何相关性。要访问一个对象,必须先沿着逻辑指针走完 DAG,再在 packfile 里按 delta chain 物理追踪。每一次 Git 操作都是跨 gigabytes 数据的随机 IO,这在单机上可以通过文件系统缓存掩盖,但在分布式场景下是灾难性的——任何网络文件系统都会因为频繁的小 IO 而瘫痪。 1.2 Spokes 的经验与局限 GitHub 在 2013 年推出的 Spokes 系统做出了三个正确选择: ...

2026-08-23 · 2 min · 348 words · FunkyGod

AI 时代,程序员该怎么理解"富在术数,不在劳身;利在势居"

AI 时代,程序员该怎么理解“富在术数,不在劳身;利在势居” 富在术数,不在劳身;利在势居,不在力耕也。 一、先说我的结论:在 AI 时代,正确使用 AI 不是把思考和责任交给它,而是让它处理重复、检索、整理和初稿,把问题定义、边界判断、结果验证和最后负责留在自己手里。我需要同时做目标设计者和成果验收者:先想清楚要解决什么,再让 AI 多想几种办法、多试几次,最后由我判断结果是否合格。这个顺序不能反过来:如果我连问题是什么、什么结果算完成都没有想清楚,就算 AI 很快生成了一大段代码,也只是把模糊变成了更难检查的复杂。带着这个结论再读这句话,会更容易看清它的意思。这句话出自西汉桓宽整理的《盐铁论·通有》,不是《韩非子》。原文讨论燕地的涿、蓟,赵地的邯郸等名都为什么富裕。它们不一定拥有最肥沃的土地,却处在交通要冲,货物、商人和消息从那里经过,远方的资源可以在那里交换。这里的“术数”不是一个人凭空想出的小聪明,而是经营、组织和交换的方法;“势居”也不是今天常说的追风口,首先是你处在什么位置,是否连接着货物、需求和交易。这个背景很重要,因为《盐铁论》并没有单纯赞美商业。贤良文学马上反驳:商业繁盛可能带来奢侈、逐利和农业荒废;后面的争论又回到盐铁、均输、平准,讨论国家要不要介入资源和交易。也就是说,这句话真正提醒我们的不是“不要劳动”,而是:财富不会按照体力和工时一比一地分配,分工、流通和位置同样会决定劳动能产生多大结果。我以前读到这句话时,很容易把它理解成“方法比努力重要”;现在我更愿意把问题再往前推一步:一个人的劳动,怎样才能不只完成一次任务,而是进入一套更大的协作关系,留下以后还能使用的东西。 二、放到程序员身上,“劳身”不只是敲键盘,也包括那些只能随着工时增加、任务结束就归零的工作:接一个需求、写一组接口、改一个页面、处理一次线上故障、给别人解释一次项目结构。这些工作当然有价值,没有它们系统不会运行,用户的问题也不会解决;但如果我的收入和影响力永远只取决于“今天完成了几个任务”,就会遇到一个很现实的上限:一天只有这么多时间,注意力也会疲劳。我自己处理重复问题时经常掉进这个循环:某个接口出错,我查日志、改代码、补测试,问题解决;过几周同类问题再次出现,我又从头查一遍。每次都很忙,但忙完没有留下什么,下一次仍然要拿当天的时间重新换结果。AI 把这个问题放大了。生成样板代码、补充测试、解释报错、转换接口格式,这些工作正在变快,也正在变便宜。如果我只把优势建立在“比别人多写一点普通代码”上,这部分优势很容易被工具追平。AI 首先压低的是“写出一段代码”的价格,不是“让一个系统可靠运行”的价格。后者还包括判断问题值不值得做、把模糊需求说清楚、处理旧系统的限制、验证生成结果、控制权限和成本,以及出了问题之后能够定位、回滚并负责。代码越容易生成,程序员越不能只证明“我能写出来”,而要证明“我知道为什么这样写、怎样确认它没有伤害原来的系统”。 三、我现在理解的“术数”,不是几个提示词,而是把一次解决问题的经验变成下一次可以重复使用的办法。比如我让 AI 修改一个功能时,不再只说“帮我改好”,而是先写清楚目标、不能改变的行为和验收条件,再让它给出两三种实现思路,说明各自的风险。我会多用 AI 去 try:试不同的拆分方式,试几组边界输入,试着找出自己方案里的漏洞;但这些尝试只是帮我扩大选择范围,最后仍由我判断哪种方案值得做,运行测试、查看差异、检查权限和回滚路径,再决定是否验收。这个流程看起来比直接生成代码慢一点,但它减少了我最怕的那种返工:代码已经写了很多,最后才发现需求根本没有定义清楚。类似地,一个故障处理完以后,我可以只说“已经修好了”,也可以留下排查路径:先看哪类日志,哪些指标能排除某种原因,什么情况需要回滚,修复后补哪一条测试。下一次遇到同类故障,这份记录就不只是文档,还能成为人和 AI 都能照着执行的步骤。再往前一步,我会把重复的接口规范、错误处理、权限检查和测试方式整理成模板或自动检查,让团队其他人也能用。第一次做这些整理确实会增加时间,但第二次、第三次开始,我不必重新解释、重新试错、重新检查。这才是我理解的“术数”:不是让自己看起来更聪明,而是让一件事情下次更容易做好,并且不再完全依赖某个人临场发挥。AI 最适合参与的,也正是已经想清楚的流程:生成重复部分、收集失败案例、补齐检查项,而不是替我决定问题是什么。 四、“势居”对程序员的意义,是不要永远停在代码生产的末端,而要逐渐靠近问题、数据、使用者和运行结果。我以前也把“势”理解成热点:哪个模型发布了就赶紧试,哪个概念流行了就做一个 Demo。但热点往往只带来注意力,不一定带来位置。一个更实际的判断是:我是否知道用户每天反复遇到什么麻烦?是否看过真实输入和错误案例,而不是只拿几个漂亮样例测试?我写的东西是否进入持续运行的系统,而不是演示页面?上线后出了问题,我是否能看到结果并继续修改?比如临时帮别人总结一份日志,完成一次就结束;如果我长期处理同一类系统的日志,知道哪些错误最常见、哪些指标最有用、哪些修复会影响其他服务,再把这些经验做成团队每天使用的工具,我接触到的就不只是一次任务,还有问题的历史、数据的变化和用户的反馈。真正的“势”不是你站在风口上,而是一个重要问题长期存在时,别人会因为你的经验、工具和判断而经过你。但我也不想把这句话写成“只要努力就能占据有利位置”。一个人能不能接触用户、拿到数据、决定方向,还取决于组织、平台和资源。不是每个程序员都能马上拥有入口;有些人一开始就在交通要道,有些人只能按别人的订单计时。因此更诚实的问法是:我是否比半年前更接近问题源头、更了解运行结果,是否积累了一些可以带走的经验,而不只完成过一串无法复用的任务?如果一个 AI 机会只让我承担更多重复劳动,却不让我接触问题、反馈和决策,那么它可能只是把旧的劳身换了一个更时髦的名字。不能因为“势居”听起来有道理,就把所有结构性的差距都解释成个人不够努力。 五、如果把这句话落到我自己的工作安排里,我不会先问“下一个最热的 AI 工具是什么”,而会先看最近一个月的任务记录:哪些工作出现次数最多,哪些地方最容易出错,哪些问题每次都要重新解释。然后选一个结果容易检查、出错代价不高的任务,先由我写清楚目标和验收条件,再让 AI 多给几种方案、多试几组输入、多模拟几种失败情况;我不把第一次生成的结果当答案,而是把它当一个可以继续追问、修改和推翻的草稿。连续使用几次后,重点记录它在哪些地方误判,以及我自己的目标是否写得不够清楚;最后把稳定下来的步骤整理成脚本、测试、说明或团队工具,并找真正使用它的人确认是否减少了麻烦。这个顺序对我很重要,因为一个只在顺利样例里工作的 AI 流程没有多少价值,真正有用的东西往往来自失败、误判和人工接管。回到原句,我的理解不是“努力没用”,也不是“找到风口就能成功”,而是:如果劳动只完成一次任务,回报容易被时间限制;如果劳动被整理成方法、工具、系统和信任,才有机会被重复使用;如果我只站在代码生产的末端,容易被比较和替代;如果我逐渐靠近真实问题、用户反馈和系统结果,就更可能形成自己的位置。先把基本功练好,再把重复工作交给 AI;先在真实项目里待久一点,再判断自己的位置;先积累能复用的东西,再谈所谓的风口。给读者的启示:1. 多思考目标、边界和验收条件;2. 多尝试,不把 AI 的第一次答案当结论;3. 多用 AI 去 try,让它提供方案、反例和试验;4. 自己做目标设计者和成果验收者;5. 让 AI 放大判断,而不是替代判断,生成越快,越要重视测试、监控、回滚和对结果负责。

2026-08-21 · 1 min · 48 words · FunkyGod

怎么理解《盐铁论》:一场关于国家该不该"下场做生意"的争论

怎么理解《盐铁论》:一场关于国家该不该“下场做生意”的争论 很多人第一次接触《盐铁论》,会把它理解成一个很简单的问题:盐和铁到底该不该由国家专卖? 但我读下来,发现这只是它的入口,不是它的核心。真正摆在桌面上的问题是:**一个国家为了打仗、维持秩序和建设中央财政,究竟可以把手伸进市场多深?**如果国家不集中资源,可能没有能力应对边患;如果国家把资源和交易都管起来,又可能让百姓承担成本。 《盐铁论》记录的,正是这种两难。它不提供一个可以直接抄走的标准答案,却把政策背后的账本、道德和代价都摆了出来。 蓝色高亮表示历史背景,绿色高亮表示我的理解,红色高亮表示阅读时需要警惕的地方,黄色高亮表示可以带走的方法。 一、先别把《盐铁论》读成“盐铁政策说明书” 《盐铁论》不是一个人坐在书房里写出的经济学专著,而是西汉盐铁会议的对话记录及其整理本。汉昭帝始元六年,也就是公元前 81 年,朝廷召集各地推举的贤良、文学,询问民间疾苦和教化之要。会议中,贤良文学与以御史大夫桑弘羊为代表的朝廷官员展开辩论,后来由桓宽整理成书,今本一般分为 10 卷 60 篇。 所以,它有两个阅读层次: 它让我们看到汉代国家怎样筹钱、运货、打仗和治理市场; 它也让我们看到,不同政治立场如何用不同的语言解释同一项政策。 我觉得第二层尤其重要。书中的“贤良文学”并不等于今天意义上的普通民众,“桑弘羊”也不只是一个冷冰冰的财政官。双方都在争夺一个更大的问题:什么才算真正有利于国家和百姓? 二、争论的表面是盐铁,底层是“谁来承担国家成本” 汉武帝时期,西汉长期对匈奴作战,国家需要大量军费、粮食、马匹和运输资源。与此同时,朝廷推行了盐铁官营、酒类专卖,以及均输、平准等政策,试图把重要资源和商品流通掌握在中央手里。 这些政策的逻辑并不难理解:盐和铁是人人都要用、又不容易替代的商品;如果由国家控制,就能获得稳定收入,也能避免地方豪商凭借资源坐大。均输、平准则试图调度各地物资、平抑价格,让国家不必只靠加税来筹钱。 桑弘羊一方看到的是 国家能力:没有稳定财源,边疆防务、交通运输和公共秩序都无法维持。商人逐利,未必会主动承担这些成本;既然国家要承担,就需要掌握相应的资源和收入。 贤良文学一方看到的是 民间成本:官府一旦垄断生产和流通,就可能与民争利;官吏不熟悉具体生产,产品质量和交易效率未必更好;政策最后如果层层加码,最先感到压力的还是普通百姓。 这就不是“国营好还是民营好”的口号题了,而是一道分配题: 国家要完成战争和治理任务,钱从哪里来? 资源由谁生产、谁运输、谁定价? 政策带来的收益由谁享受,成本又由谁承担? 如果官府的执行出了问题,谁能够纠正它? 我理解《盐铁论》的第一个关键,就是把“政策目标”和“政策手段”分开看。保卫国家、稳定物价、保证供应,可能都是合理目标;但盐铁官营、均输平准,只是实现目标的手段。目标正确,不代表每一种手段都有效;手段有副作用,也不代表目标不重要。 三、贤良文学反对的,不只是官营,而是“与民争利” 贤良文学最有代表性的说法,是把农业、仁义和民生放在政策判断的中心。他们担心的并不是国家完全没有收入,而是国家把逐利行为带进治理之后,会改变整个社会的风气。 在他们看来,国家应该减少对市场利益的追逐,让百姓安心从事农业和日常生产。官府如果自己经营盐铁、酒和运输,就会和商人争夺利润,甚至造成官吏借权力牟利。于是,本来是为了富国的政策,可能变成增加百姓负担的政策。 这套观点常被概括成“重农抑商”,但这样概括还不够。它至少包含三层担心: **权力和利益结合之后,监督会变难。**官府既是规则制定者,又是市场参与者,普通人很难与之对抗。 **中央制定的统一政策,未必适合所有地方。**盐场、矿区、运输线路和消费能力不同,一套办法可能在某地有效,在另一地却变成负担。 **短期收入不能替代长期民生。**如果政策让百姓失去生产积极性,国家账面上的收入,可能是以未来的贫困换来的。 他们的不足也很明显:只强调仁义和减轻干预,并不能自动解决边疆军费、灾荒救济和基础运输的问题。“不要与民争利”是一条重要的边界提醒,却不是完整的财政方案。 四、桑弘羊真正关心的是:没有钱,理想怎样落地 桑弘羊的论证,比“国家就是要赚钱”复杂得多。他知道专卖和调度会带来不便,却认为国家不能只讲道德、不算成本。 边疆需要军队,军队需要粮食和武器;中央要控制地方,需要稳定的行政网络;市场价格大幅波动时,国家还要有能力储备和调运。若财政完全依赖土地税和普通百姓,负担未必更轻,国家也可能被地方豪强和大商人牵制。 因此,桑弘羊的核心不是“国家应该像商人一样逐利”,而是:**国家必须拥有把资源组织起来的能力。**盐铁官营和均输平准,就是他用来建立这种能力的制度工具。 从今天的角度看,这里面有一个很现代的判断:公共目标不会因为“市场会自行解决”就自动实现。国防、基础设施、危机储备和价格稳定,都可能需要某种公共力量参与。 但桑弘羊一方的问题同样明显。国家能力越强,越需要边界、透明度和纠错机制。如果“为了国家”可以解释一切,那么低效、寻租和对民间的挤压,也容易被包装成必要代价。《盐铁论》最值得今天重读的地方,恰恰是它没有让“富国强兵”自动压倒所有其他价值。 五、不要问“谁赢了”,要问双方各自看见了什么 如果把《盐铁论》当成辩论赛,很容易只关心最后谁说服了谁。但历史政策很少是靠一场辩论彻底翻转的。 会议之后,酒类专卖被取消,关内部分铁官也有所调整,但盐铁官营并没有因此完全消失。这个结果本身就说明:现实治理往往不是全盘接受某一方,而是在财政需要和民间压力之间做局部修正。 我更愿意用下面这张“互补地图”来理解双方: 立场 它最看重的东西 它最容易忽略的东西 贤良文学 民生、生产积极性、权力边界 国家财政、战争与公共供给 桑弘羊 财政能力、资源组织、中央控制 执行成本、官吏寻租、民间感受 这不是说双方各占一半真理,而是说:一项公共政策如果只有目标,没有成本意识,会变成愿望;如果只有成本收益,没有民生和正当性,也会变成压迫。 六、读《盐铁论》,我建议抓住四个方法 1. 先看它在回答什么现实问题 不要一上来就背“本末”“仁义”“权利”这些概念。先问:当时国家为什么需要钱?为什么需要控制盐铁?战争、财政和运输分别造成了什么压力?把问题放回现场,古人的话才不会变成空洞格言。 ...

2026-08-21 · 1 min · 81 words · FunkyGod

Go + Python 混合开发:两种语言的协同,我觉得很舒服

Go + Python 混合开发:两种语言的协同,我觉得很舒服 原文:Python 与 Go 混合开发 | 让 Golang 编程更丝滑 作者:原文信息未提供 来源:用户提供原文标题,发布平台及发布日期未详 很多团队并不是在 Go 和 Python 之间二选一,而是在同一个系统里同时使用它们:Python 负责模型、数据和快速试验,Go 负责服务、任务、网络和部署。 这种组合听起来很自然,真正做起来却经常出现另一种结果:两边各自开发都很顺,连在一起就变得不顺。调用延迟、数据转换、错误处理、版本发布和线上排障,很快会把“语言互补”变成“系统加倍复杂”。 原文从开发体验出发讨论 Python 与 Go 的混合使用。本文在这个基础上往前走一步:混合开发的核心不是把两种语言硬塞进一个进程,而是为变化速度不同的模块设计清晰、可观察、可演进的边界。 蓝色文字表示核心判断,绿色文字表示个人开发实践,红色文字表示风险提示,黄色底色表示可以直接执行的建议。 一、先纠正一个误区:混合开发不是“Python 慢、Go 快” 用“Python 负责灵活,Go 负责性能”概括两种语言,虽然容易理解,但不够准确。 Python 的价值不只在于写得快。它连接着成熟的数据处理、科学计算、机器学习和实验工具链。研究人员或业务工程师可以很快把数据读进来,换一个模型,调整参数,观察结果,再决定下一步怎么做。这个阶段最宝贵的是试错速度和生态覆盖面。 Go 的价值也不只是运行速度。它的静态类型、编译器、并发模型、标准库和独立二进制发布方式,更适合承载长期运行的服务和工具。一个网关、任务调度器、文件处理器或消息消费者,往往要面对超时、取消、限流、重试、优雅退出和故障恢复。这些问题的难点不在于写出第一版,而在于运行数月后仍然清楚、稳定、可维护。 所以,合理的分工不是“把慢的代码改成 Go”,而是看模块的主要矛盾是什么: 变化快、需要不断试验、依赖模型和数据生态的部分,优先考虑 Python; 需要长期运行、并发处理、跨平台发布和严格运维的部分,优先考虑 Go; 两者都能完成、但没有明确收益的部分,不要为了“混合”而混合。 语言边界应该服从业务边界。一个稳定的 Python 服务,通常比一个为了追求统一而重写的 Go 服务更有价值;一个需要高并发和强约束的 Go 组件,也不应该因为团队已经熟悉 Python 就继续堆补丁。 二、最常见的协同架构:Python 做变化,Go 做秩序 在 AI、数据和平台型系统中,可以把职责粗略分成四层。 1. Python:模型和数据层 Python 适合放置以下内容: 模型加载、推理和评测; 特征处理、数据清洗和离线任务; 提示词编排、实验脚本和策略验证; 需要频繁调整的业务规则; 对第三方 AI、科学计算或数据工具的适配。 这一层的代码变化频率通常较高。它不一定要承担所有外部流量,也不一定要直接管理复杂的重试和权限体系。 ...

2026-08-20 · 4 min · 656 words · FunkyGod

Go 是 AI 辅助软件工程的理想语言:原文解读与深入思考

Go 是 AI 辅助软件工程的理想语言:原文解读与深入思考 原文:Why Go is an Ideal Language for AI-Assisted Software Engineering 作者:Cameron Balahan(Go 产品组经理)、Richard Seroter(Google Cloud 首席布道师) 来源:Google Developers Blog 发布日期:2026 年 8 月 11 日 本文分两部分:第一部分忠实解读原文,还原文章的论证结构与核心观点;第二部分跳出原文,从批判性视角深入探讨这篇文章没有说透、值得追问的地方。 第一部分:原文解读 1. 文章的出发点:软件工程正在发生范式转移 文章开篇没有直接讲 Go,而是先描述了一个正在发生的行业变化: 过去,我们亲手写大部分代码;现在,我们让 AI 编程助手和智能体替我们生成大量代码。但 AI 需要监督,所以依然是我们人类来阅读生成出来的代码、清理它、并验证它是否真的做了我们想让它做的事。 这是全文的地基。作者想表达的核心是:代码的"生产"变便宜了,但代码的"治理"并没有变便宜。 紧接着,作者补充了一个容易被忽略的事实:AI 只能看到它被喂进去的那点上下文,看不到整个系统的边界。因此,系统架构、服务边界、生产环境的安全与可靠性,仍然必须由人来定义和负责。 这一段的潜台词是:AI 改变了"写代码"这件事,但没有改变、甚至放大了"软件工程"这件事的难度。 2. 第一个核心判断:瓶颈从"写"转向了"审" 作者回顾了历史:过去,人们衡量一门编程语言的生产力,主要看它"好不好写"。 但当 AI 能在几秒钟内生成几百行语法正确的代码时,人类写代码的速度就不再重要了。真正重要的事情变成了三件: Reviewing——评审; Verifying——验证; Maintaining——维护。 文章用了一个形象的比喻:AI 越来越像你的队友(teammate),一个有点我行我素、但仍然算队友的存在。既然如此,最重要的就不再是"我写得有多快",而是"我们作为一个团队如何协作"。 这是全文第一个关键转向:衡量语言的坐标系,从"个人写作体验"切换到了"团队协作体验"。 3. 第二个核心判断:Go 是为"软件工程"而生的 作者指出,二十多年前 Rob Pike、Robert Griesemer 和 Ken Thompson 在 Google 创建 Go 时,别的语言都在快速堆砌特性、扩展表达方式,而 Go 选择的却是一个更大的目标: ...

2026-08-20 · 3 min · 559 words · FunkyGod

Go 语言在 AI 辅助编程时代被谷歌官方力挺:动态语言与 Go 并非对立,而是互补关系

Go 语言在 AI 辅助编程时代被谷歌官方力挺:动态语言与 Go 并非对立,而是互补关系 原文:谷歌官方力挺:为什么 Go 语言是 AI 辅助编程时代的“标准答案”? 作者:场长 来源:21CTO 公众号,发布于 2026 年 7 月 16 日 过去,程序员最关心的问题是:哪门语言写起来更快? 进入 AI 辅助编程时代后,这个问题正在变成:哪门语言更容易让 AI 写对,也更容易让人类看懂、验证、部署和维护? 这不是文字游戏,而是软件生产方式发生变化后的真实转向。AI 可以在几秒钟内生成数百行代码,却无法替人类承担全部架构责任。代码越容易生成,审查、测试、安全和运维的重要性就越高。 谷歌官方力挺 Go,核心并不是说 Python、JavaScript 或 TypeScript 已经过时,而是指出:Go 从诞生之初就偏向大型、长期运行的软件系统。在智能体持续生成代码的今天,这些原本服务于人类团队的设计原则,也恰好成为 AI 协作所需要的“确定性护栏”。 更准确的结论应该是:动态语言负责快速探索和连接生态,Go 负责把经过验证的能力变成稳定运行的服务、工具和基础设施。 一、AI 编程真正改变的,是软件开发循环 很多人提到 AI 编程,首先想到的是代码补全:输入函数名,AI 自动写出函数体;写一段注释,AI 生成一段实现。 这只是最早期、也最简单的用法。 真正的 AI 辅助编程,通常是一个持续循环: 实现 → 构建 → 测试 → 分析失败 → 修改 → 再次构建。 如果是能够自主操作终端和代码仓库的智能体,它还会继续执行:读取日志、搜索依赖、修改多个文件、运行集成测试、启动服务、调用接口,然后根据结果再次修复。 对人类开发者来说,几分钟的编译等待可能只是一次短暂的停顿。对一个需要运行几十轮的智能体来说,每一次等待都会累积成时间、算力和模型调用成本。 这会放大许多过去被忽略的工程摩擦: 构建速度慢:每次修改都要等待更久,智能体的有效迭代次数下降; 依赖关系复杂:环境安装失败后,智能体可能把大量上下文消耗在解决版本冲突上; 错误反馈太晚:问题到运行时才暴露,智能体可能已经在错误基础上写了更多代码; 代码风格不统一:人类和 AI 都要花时间理解不同写法,评审速度自然下降; 部署链路过长:代码虽然生成了,但服务无法稳定启动,任务仍然不能算完成; 生态变化太快:模型根据旧文档生成的代码,可能在今天已经不适用。 过去,这些问题可能每周出现几次。现在,智能体可能在一天内把同一个循环执行数百次。问题没有变,但问题出现的频率变了,成本结构也随之变化。 ...

2026-08-20 · 2 min · 417 words · FunkyGod

Go 项目结构之争:DDD 还是简洁分层?

Go 项目结构之争:DDD 还是简洁分层? Go 项目一开始通常很简单:几个接口、几张表、几个服务函数,按 handler、service、repository 分开就能跑起来。项目变大之后,团队又开始讨论 DDD、领域模型、聚合、应用层和基础设施层。 于是问题变成了:Go 项目到底应该采用 DDD,还是坚持简洁分层? 我的答案是:不要先选择目录结构,要先识别业务复杂度和变化边界。 简洁分层不是低级方案,DDD 也不是高级方案。它们只是解决不同问题的工具。 可以把项目想成一家餐馆。简洁分层像一家小店:前台接单,后厨做菜,仓库取料,路线短,出了问题也容易找到人。DDD 更像一家菜品、库存、会员和结算规则都很复杂的连锁餐厅:重点不是把岗位拆得越多越好,而是让“什么菜能做、什么时候能退单、库存怎么扣”这些规则有明确的负责人。 小店一开始就照搬连锁餐厅的总部制度,会被流程拖慢;连锁餐厅却不能永远把所有事情都交给一个大厨。Go 项目的结构选择,也是同一个道理。 一、争论表面是目录,本质是边界 很多团队讨论架构时,第一步就是贴目录树: internal/ ├── handler/ ├── service/ ├── repository/ └── model/ 或者: internal/ ├── domain/ ├── application/ ├── interfaces/ └── infrastructure/ 但目录本身不会自动带来好的架构。真正重要的是几个问题: 哪些代码属于同一个业务能力? 哪些规则必须始终成立? 哪些变化应该被隔离? 数据库、消息队列等技术细节,是否侵入了业务决策? 一个需求发生变化时,需要修改多少个包? 如果这些问题没有答案,换一套目录只是换了一种命名方式。 架构的价值不在于让目录看起来专业,而在于让变化停留在应该停留的地方。 先用一张图看两种结构的关注点:简洁分层按“技术职责”排队,DDD 更关心“业务规则”应该被谁拥有。 flowchart LR subgraph simple["简洁分层:按技术分组"] S1["请求"] --> S2["handler"] --> S3["service"] --> S4["repository"] --> S5[("数据库")] S3 -. "规则容易集中" .-> S6["变胖的 service"] end subgraph ddd["DDD:按业务边界组织"] D1["请求"] --> D2["应用用例"] --> D3["领域规则"] D2 --> D4["仓储接口"] D4 -. "具体实现" .-> D5["基础设施"] D5 --> D6[("数据库")] end 图中没有“谁更高级”的答案。左边像小餐馆的传菜路线,胜在短;右边像连锁餐厅的岗位边界,胜在业务规则变复杂时,能把变化关在领域边界里。 ...

2026-08-20 · 2 min · 426 words · FunkyGod