技术探索这事儿,真不是写代码那么简单

林平
2026-02-07 19:08
阅读 1966

上周五晚上十一点,我瘫在工位上盯着屏幕上一行又一行的 Connection timed out,心里默念:再改一次,就最后一次。结果当然是第 N+1 次重试——还是炸了。那一刻,我突然意识到,搞技术探索,光有热情和代码是不够的,还得有点“政治智慧”和“生存策略”。尤其像我这种一边在互联网公司搬砖、一边偷偷刷行测申论的考公人,时间本就碎得像泡面渣,哪敢随便“探索”?但偏偏,系统又总在逼你往前走。

先简单自我介绍一下:我在上海一家中型 SaaS 公司做后端开发,主攻分布式系统,日常和 Kafka、Redis、Consul 打交道。租房住在公司隔壁小区,步行 8 分钟,早起型选手,每天 7:30 起床,8 点准时坐在工位上喝枸杞拿铁(没错,程序员养生从 25 岁开始)。最近半年,除了应付产品需求和线上告警,还在偷偷备考公务员——毕竟,谁不想在 35 岁前“上岸”呢?但现实是,工作不能停,系统还得稳,技术债还得还。于是,就在这种“既要又要还要”的夹缝中,我被迫开启了一段关于 DevinGemini 的技术探索实践。


为什么又是“智能代理”?

事情起源于去年双11前的一个紧急需求。老板在周会上轻描淡写地说:“我们要做一个能自动修复线上告警的‘智能运维助手’,最好能理解日志、定位根因、甚至提 PR。” 我当时差点把咖啡喷出来——这不就是 Devin 的活儿吗?

Devin,Cognition Labs 那个号称“首个全栈 AI 软件工程师”的玩意儿,刚发布时在圈内炸了锅。它能读需求、写代码、跑测试、修 Bug,甚至能和 GitHub Issues 对话。虽然我们团队不可能直接用 Devin(毕竟要付费、要网络、还要信任度),但这个方向确实戳中了痛点:我们的告警太多,人力响应太慢,自动化程度太低。

于是,领导拍板:“你们研究一下,能不能基于现有大模型搞个轻量版 Devin?”
我内心 OS:你当我是炼丹师啊?但嘴上只能回:“好的,我调研下。”

与此同时,Google 刚开放了 Gemini API 的企业级访问权限(我们公司有合作通道),支持多模态、长上下文、函数调用(Function Calling),而且延迟比 GPT-4o 低不少。这让我眼前一亮——或许,我们可以用 Gemini 当“大脑”,自己搭一套“半自动 DevOps 代理”?


架构设计:别一上来就堆 LLM

很多团队一听说“AI + 运维”,立马就想把日志全喂给大模型,让它输出 root cause。但现实很骨感:日志量太大,上下文塞不下;模型幻觉严重,瞎猜根因;成本高到财务部报警。

我们决定走“分层决策 + 工具链集成”的路子。核心思想是:大模型只负责“理解”和“决策”,具体执行交给传统工具。 这也是 Devin 的核心思路——它不是万能神,而是会调用 shell、git、editor 的“高级脚本”。

于是,我画了这么一个架构草图(当然,是在凌晨三点的 Notion 上):

[告警触发] 
   ↓
[日志聚合 & 特征提取] → [规则引擎初步过滤]
   ↓
[结构化上下文构建] → [Gemini 调用(带 Function Calling)]
   ↓
[执行动作:回滚 / 扩容 / 提 PR / 通知]
   ↓
[结果反馈 & 人工复核]

关键点在于:不让 Gemini 直接看原始日志,而是由我们预处理成结构化数据,比如:

{
  "service": "order-service",
  "error_rate": 42.3%,
  "p99_latency": 2800ms,
  "recent_deploys": ["v2.3.1", "v2.3.2"],
  "related_alerts": ["DB connection pool exhausted", "Kafka consumer lag > 1M"]
}

这样,Gemini 的 prompt 就可以非常聚焦:

“你是一个资深 SRE,当前 order-service 出现高延迟和错误率飙升。已知最近两次部署为 v2.3.1 和 v2.3.2,且数据库连接池耗尽、Kafka 消费积压。请分析可能原因,并建议下一步操作。可选动作包括:回滚到 v2.3.0、扩容 DB 连接池、重启消费者、创建 Jira 工单。”

更重要的是,我们通过 Function Calling 让 Gemini “选择”动作,而不是“生成”动作。比如定义如下函数:

def rollback_service(version: str):
    """回滚指定服务到某版本"""
    # 调用内部部署平台 API

def create_jira_ticket(title: str, desc: str):
    """创建 Jira 工单"""
    # 调用 Jira REST API

Gemini 会返回一个 JSON,明确指定调用哪个函数、传什么参数。这样,既避免了幻觉,又保证了可执行性。


踩坑实录:LLM 不是银弹

理想很丰满,现实嘛……你懂的。

坑一:上下文窗口不是越大越好

Gemini 1.5 Pro 支持 1M tokens,听起来很爽。但我们发现,一旦上下文超过 50K,推理延迟直接飙到 10s+,完全没法用于实时告警。后来我们做了动态截断:只保留最近 10 分钟的关键指标 + 最近 3 次部署记录 + 相关服务拓扑片段。效果反而更好——模型更专注,响应也更快。

坑二:Function Calling 也有“理解偏差”

有一次,Gemini 返回:

{"function": "rollback_service", "args": {"version": "latest_stable"}}

但我们的部署系统根本没有 latest_stable 这个标签!它自己脑补的。后来我们强制要求所有函数参数必须是枚举值或正则校验,并在调用前做 schema validation,这才稳住。

坑三:成本控制是个魔鬼

Gemini 按 token 计费。初期我们没做缓存,同一个告警反复触发,一个月账单差点超预算。后来加了两层缓存:

  1. 告警指纹缓存:对相同服务+相同错误模式的告警,10 分钟内只调用一次 LLM;
  2. 决策结果缓存:如果上次建议“回滚 v2.3.1”,且该版本未被覆盖,则直接复用。

这才把月度成本压到可接受范围(约 200 刀,比请一个实习生便宜多了)。


代码片段:让 Gemini 听话干活

下面是我们封装的 Gemini 调用核心逻辑(简化版):

from google.generativeai import GenerativeModel
import json

# 定义工具函数
tools = {
    "rollback_service": {
        "description": "回滚服务到指定版本",
        "parameters": {
            "type": "object",
            "properties": {
                "service_name": {"type": "string"},
                "target_version": {"type": "string", "pattern": r"v\d+\.\d+\.\d+"}
            },
            "required": ["service_name", "target_version"]
        }
    },
    "create_jira_ticket": {
        "description": "创建 Jira 工单",
        "parameters": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "description": {"type": "string"}
            },
            "required": ["title", "description"]
        }
    }
}

def call_gemini_with_tools(context: dict) -> dict:
    model = GenerativeModel('gemini-1.5-pro')
    
    prompt = f"""
    你是一个 SRE 专家。当前系统状态如下:
    {json.dumps(context, indent=2)}
    
    请根据上述信息,选择最合适的操作。可选操作:
    - rollback_service
    - create_jira_ticket
    
    只返回 JSON,格式:{{"function": "xxx", "args": {{...}}}}
    """
    
    response = model.generate_content(
        prompt,
        tools=[tool_schema for tool_schema in tools.values()],
        tool_config={"function_calling_config": {"mode": "ANY"}}
    )
    
    # 解析函数调用
    if response.candidates[0].content.parts[0].function_call:
        func_call = response.candidates[0].content.parts[0].function_call
        return {
            "function": func_call.name,
            "args": {k: v for k, v in func_call.args.items()}
        }
    else:
        return {"function": "none", "args": {}}

注意:实际生产中必须加 retry、timeout、fallback 机制。我们还加了一个“人工确认开关”——对于高风险操作(如回滚核心服务),即使 Gemini 建议了,也必须 Slack 通知值班工程师点击确认。


效果对比:数字不说谎

上线三个月后,我们拉了份数据:

指标 上线前 上线后 变化
平均 MTTR(分钟) 42 18 ↓ 57%
误操作率 8% 2% ↓ 75%
夜间告警人工介入次数/周 23 7 ↓ 69%
LLM 调用成本/月 - $198 -

最让我欣慰的是,上周五那个让我想砸电脑的超时问题,系统自动识别出是新版本引入的 Redis 连接泄漏,建议回滚。我点了个确认,3 分钟搞定。然后安心回家刷我的《行测 5000 题》——这才是技术探索的意义啊!


心得体会:考公人眼中的“技术探索”

作为一枚白天写代码、晚上背申论的“双面人”,我对“技术探索”有了新理解:

  1. 探索不是炫技,而是解决问题。老板要的不是 Devin,而是“少加班”。所以我们的方案必须轻量、可控、可解释。
  2. AI 是杠杆,不是替代。Gemini 再强,也得靠我们设计工具链、兜底逻辑、人机协作流程。它只是把我们的经验“放大”了。
  3. 时间管理是第一生产力。我每天 8 点到公司,先花 1 小时处理高优任务,再留 30 分钟做技术实验。碎片时间刷题,整块时间 coding。平衡,是成年人的必修课。
  4. 别怕“小步快跑”。我们最初只敢在非核心服务试水,后来才推广到订单系统。每一次小成功,都是对信心的充值。

最后说句掏心窝子的话:技术探索的路上,没有“完美方案”,只有“当下最优解”。就像考公一样,行测不会满分,申论不会零失误,但只要方向对、脚步稳,终会抵达彼岸。

而在这之前,我得先去改完那个该死的超时配置——毕竟,明天还要早起刷题呢。

评论 0

最热最新
暂无评论
林平Lv.1
0
影响力
0
文章
0
粉丝