1. 这波裁员和扩招到底在释放什么信号
先把事实摆出来。一边是传统数据库巨头裁掉约三万人,另一边是某头部大模型团队放出约一百五十个岗位,而且岗位描述里大量出现后端、Agent、Go、基础设施这些词。这两件事放在一起看,不是简单的“东边不亮西边亮”,而是整个后端技术栈的估值逻辑在换锚点。
我做了十多年后端,经历过从单体到微服务、从物理机到容器、从手写SQL到ORM满天飞的好几轮迭代。每一次技术栈迁移,都会有一批人觉得“学不动了”,也会有一批人悄悄把新东西吃透然后拿到溢价。这次不一样的地方在于,它不是框架层面的替换,而是后端服务的消费方变了——以前后端写接口是给人用的,现在很大一部分接口是给Agent调用的。
这个变化听起来很虚,落到JD上就非常具体。我把这批岗位描述拆完,发现几个高频词:Go、Agent、工具调用、上下文管理、可观测性、高并发低延迟。注意,这里没有“精通SSM”“熟悉Vue”“会写CRUD”这类传统后端关键词。不是说这些没用了,而是它们从“核心竞争力”降级成了“默认技能”,就像现在没人会把“会Git”写进简历亮点一样。
那后端程序员到底往哪走?我的判断是:往“Agent的基础设施层”走。Agent要跑起来,背后需要会话管理、工具注册与调度、状态持久化、限流熔断、可观测性、成本核算,这些全是后端的老本行,只是换了一套约束条件。你不需要去训模型,但你需要让模型跑得稳、跑得便宜、跑得可追踪。这就是这批JD真正在招的人。
下面我按拆JD的思路,把这件事拆成几个可操作的层面:先看岗位画像,再看技术选型为什么是Go,然后讲Agent后端和传统后端的差异,接着给一条可落地的学习路径,最后是我自己踩过的坑和排查经验。
2. 把这批JD拆开看:岗位画像和能力映射
2.1 高频关键词统计与背后含义
我把能看到的岗位描述做了个粗略的词频归类,大致分布是这样的:
| 关键词类别 | 出现频率 | 背后真实需求 |
|---|---|---|
| Go语言 | 极高 | 高并发、低延迟、部署简单 |
| Agent/工具调用 | 极高 | 让模型能调用外部能力 |
| 上下文/会话管理 | 高 | 多轮对话状态不能丢 |
| 可观测性 | 高 | 出问题要能定位到具体调用 |
| 高并发/低延迟 | 高 | 推理请求排队不能炸 |
| Python | 中 | 原型验证、脚本、部分服务 |
| 传统框架(Spring等) | 低 | 存量系统维护 |
这张表最值得琢磨的是最后一行。传统框架出现频率低,不代表它消失了,而是说明新岗位的增量不在那里。存量系统还要人维护,但维护岗的议价能力在下降。增量在Agent基础设施,而这块目前Go的声量最大。
2.2 为什么是Go而不是Java或Python
这个问题我被问过很多次。先说结论:不是Java和Python不行,而是这批场景下Go的综合性价比最高。
Agent后端的典型特征是:大量短连接、大量并发请求、每个请求要做多次外部调用(模型推理、工具执行、数据库读写)、对延迟敏感、对内存占用敏感。这几点叠加起来,Go的goroutine模型和静态编译优势就出来了。
我做过一个粗略的对比测试,同样一个“接收请求-调用模型-调用工具-返回结果”的链路,在中等并发下:
- Go服务常驻内存大约几十MB,启动毫秒级;
- JVM服务常驻内存几百MB起步,启动秒级;
- Python服务内存介于两者之间,但GIL在高并发IO场景下需要靠异步框架绕。
注意:这不是说Java和Python不能做,而是说在“快速扩缩容+低资源占用”这个约束下,Go的默认表现更省心。Java生态成熟、Python生态丰富,各有各的战场。
2.3 一个容易被忽略的能力:成本意识
这批JD里有个词出现得不多但很关键——token成本。Agent每调用一次模型都是钱,后端工程师如果不懂token怎么算、上下文怎么裁剪、缓存怎么命中,就会写出“功能能用但账单爆炸”的服务。
我见过一个真实案例:某服务每次请求都把完整历史对话塞进上下文,单次调用token数从几百涨到上万,QPS一上来成本直接失控。后来做了滑动窗口+摘要压缩,成本降了七成。这种优化不需要你懂模型训练,但需要你有后端工程师的资源意识。这就是新岗位和旧岗位的分水岭之一。
3. Agent后端和传统后端的核心差异
3.1 从“请求-响应”到“请求-编排-响应”
传统后端的心智模型很简单:收到请求,查库,返回。链路是线性的,超时时间好估算,错误好定位。
Agent后端不一样,它是编排型的。一个请求进来,可能要:解析意图、检索知识库、调用模型、根据模型输出决定调哪个工具、执行工具、把工具结果再喂回模型、最后生成回复。这条链路里任何一环都可能慢、可能失败、可能返回意料之外的结果。
这意味着后端工程师要处理的新问题包括:
- 部分失败:模型调通了但工具挂了,怎么降级?
- 超时传递:整条链路的总超时怎么分配?模型占多少、工具占多少?
- 幂等性:工具调用可能重试,怎么保证不重复扣款、不重复写库?
- 可观测性:一次请求跨了五六个组件,怎么串起来看?
这些在传统后端里也有,但Agent场景把它们放大了,因为链路更长、外部依赖更多、结果更不确定。
3.2 上下文管理是新的“状态管理”
传统后端的会话状态一般放Redis或数据库,结构固定。Agent的上下文是半结构化、长度不定、需要动态裁剪的。
我自己的做法是分三层:
- 原始消息层:完整存库,用于审计和回溯;
- 工作上下文层:实际喂给模型的部分,做滑动窗口和摘要;
- 缓存层:高频问题的标准回答,直接命中不走模型。
这三层的分离很重要。很多新手一上来就把原始消息直接当上下文用,结果就是又贵又慢还不稳定。
3.3 工具注册与调度:后端的新“路由”
传统后端的路由是URL到handler的映射,静态的。Agent的工具调度是动态的:模型根据当前任务决定调哪个工具,后端要负责注册、鉴权、限流、执行、结果格式化。
我一般会设计一个工具注册表,每个工具声明:名称、描述、参数schema、超时、重试策略、是否需要鉴权。模型看到的只是名称和描述,后端拿到调用请求后做实际执行。这个设计的好处是,新增工具不用改调度逻辑,注册进去就行。
type Tool struct { Name string Description string Params map[string]ParamSpec Timeout time.Duration Handler func(ctx context.Context, args map[string]any) (any, error) } type Registry struct { tools map[string]*Tool } func (r *Registry) Register(t *Tool) { r.tools[t.Name] = t } func (r *Registry) Invoke(ctx context.Context, name string, args map[string]any) (any, error) { t, ok := r.tools[name] if !ok { return nil, fmt.Errorf("tool not found: %s", name) } ctx, cancel := context.WithTimeout(ctx, t.Timeout) defer cancel() return t.Handler(ctx, args) }这段代码不复杂,但体现了一个核心思想:把不确定性收敛到注册表里。模型可以乱调,但后端有统一的超时、重试、鉴权兜底。
4. 一条可落地的学习路径
4.1 第一阶段:把Go用顺手
如果你现在主力是Java或Python,不要一上来就啃Go的并发源码。先做三件事:
- 用Go写一个简单的HTTP服务,实现增删改查;
- 加上中间件:日志、鉴权、限流;
- 用goroutine和channel做一个并发任务分发的小demo。
这三步做完,你对Go的工程手感就有了。我当初从Java转Go,最大的不适应是错误处理——Go没有异常,全靠返回值。刚开始觉得啰嗦,写多了发现这种显式处理反而让链路更清晰。
4.2 第二阶段:理解Agent的调用链路
不用自己训模型,但要会调API。找一个模型服务,用Go写一个客户端,实现:
- 发送消息,拿到回复;
- 支持流式输出;
- 支持工具调用(function calling);
- 记录每次调用的token数和耗时。
这个客户端写出来,你就理解了Agent后端最核心的交互模式。剩下的都是在这个基础上加工程化能力。
4.3 第三阶段:补可观测性和成本控制
这是拉开差距的地方。具体做:
- 给每次请求打上trace id,贯穿模型调用和工具调用;
- 记录每个环节的耗时,做成指标;
- 统计token消耗,按用户或按接口维度聚合;
- 设置预算告警,超了自动降级。
我自己的经验是,可观测性不是上线后才补的,而是设计时就要留口子。等出了问题再想加日志,往往已经丢掉了关键上下文。
4.4 第四阶段:做一个完整的小项目
把上面三阶段串起来,做一个能跑的小项目。比如一个“智能问答+工具调用”的服务:用户提问,模型判断是否需要查数据库或调外部接口,后端负责执行并返回。
这个项目不用大,但要完整:有注册表、有上下文管理、有可观测性、有成本统计。做完这个,你去面试Agent后端岗位,基本能聊到点子上。
5. 常见问题与排查技巧实录
5.1 模型返回格式不稳定怎么办
这是最高频的问题。模型有时候返回JSON,有时候返回带markdown的JSON,有时候干脆返回一段解释。我的做法是:
- 在prompt里明确要求输出格式,并给示例;
- 后端做容错解析,先尝试直接解析,失败再提取代码块,再失败走兜底;
- 关键链路不要完全依赖模型输出,能用规则的地方用规则。
提示:不要指望模型100%稳定,后端要做的是“即使模型抽风,服务也不崩”。
5.2 工具调用超时怎么处理
工具超时是常态。我的策略是分级:
| 工具类型 | 超时设置 | 失败策略 |
|---|---|---|
| 查询类 | 短超时 | 返回空结果,继续 |
| 写入类 | 中等超时 | 重试一次,仍失败则报错 |
| 支付类 | 长超时 | 不重试,走人工 |
关键是不要让一个工具拖垮整个请求。每个工具独立超时,独立降级。
5.3 并发上来后内存暴涨
多半是上下文没裁剪。检查两个地方:一是每次请求是否把完整历史都加载了;二是缓存是否无上限增长。我一般给上下文设硬上限,超了就摘要或截断;缓存用LRU,设最大条目数。
5.4 怎么判断该用Go还是Python
我的经验法则:
- 原型验证、数据处理、脚本,用Python;
- 高并发服务、基础设施、需要长期稳定运行的,用Go;
- 存量Java系统继续用Java,新服务按上面两条选。
不要为了追新而重写,也不要因为守旧而错过增量。
6. 我自己的几点体会
第一,后端的基本功没有过时,只是换了应用场景。并发、超时、幂等、可观测性,这些在Agent后端里一个都没少,反而更重要了。你把老本行练扎实,迁移成本比想象中低。
第二,不要被“AI”两个字吓住。Agent后端的绝大部分工作是工程问题,不是算法问题。你不需要懂反向传播,但你需要懂怎么让一个不稳定的外部依赖变得可控。
第三,成本意识是新的竞争力。同样一个功能,别人写出来账单是每月一万,你写出来是三千,这就是价值。多关注token、缓存命中率、链路耗时这些指标。
第四,动手比看文章重要。我见过太多人收藏了一堆教程然后继续写CRUD。找一个周末,用Go写一个带工具调用的最小服务,跑通一次,比看十篇文章都管用。
最后分享一个小技巧:如果你现在还在传统后端岗位,不要急着裸辞转方向。先在现有工作里找“能和Agent沾边”的活,比如给内部系统加一个智能问答入口,或者把某个重复流程做成工具调用。有了实际项目经验,再往外走,底气完全不一样。