从大厂技术总监到创业者的技术探索踩坑全记录

FullStackHero
2026-07-05 11:05
阅读 786

上周四下午,我把工牌交还给HR的那一刻,心里其实挺复杂的。在深圳南山这片腾讯系公司扎堆的地方,我算是混了快八年了。从一线写码到带团队做技术总监,再到如今决定出来创业,这条路走得既快又慢。

快的是时间,慢的是那些踩过的坑。

今天这篇文章,算是我离职前最后一段日子里的技术复盘。说实话,最近半年我重度依赖ChatGPT和Claude辅助开发,很多技术方案都是跟AI"吵"出来的。有人说这是偷懒,我觉得这是进化。程序员嘛,总得学会用新工具,不然早晚被时代抛弃。

一次意外的技术选型

事情要从去年11月说起。当时公司接了个新项目,要做一套面向开发者的智能代码审查平台。产品经理(我又要吐槽我们那个PM了,每次需求都像是在写科幻小说)提了一个听起来很美好的愿景:用户丢一段代码进去,系统自动给出优化建议、安全漏洞扫描、性能分析报告,最好还能顺便帮你把代码重构了。

我当时听完差点把咖啡喷出来。"你这是要我做一个AI版的SonarQube加GitHub Copilot?"

PM笑了笑说:"差不多吧,但是我们要做得更智能。"

更智能。这三个字在程序员耳朵里,基本等于"加三个月班"。

但说实话,这个方向确实有搞头。那段时间我正好在研究一些新的AI工具链,想看看能不能把它们串起来搞点事情。于是我开始疯狂调研,从代码分析到AI辅助,从架构设计到落地实现,前前后后折腾了将近两个月。

为什么选Qoder

先说说代码分析这块。市面上开源的代码分析工具不少,SonarQube、CodeQL、Semgrep,各有各的好。但我们的需求比较特殊——需要支持多语言、可扩展性强、而且最好能跟AI模型无缝对接。

这时候我发现了Qoder。

Qoder是一个相对小众但很有潜力的代码智能分析框架。它的设计理念很有意思,不是传统的AST(抽象语法树)解析那一套,而是基于语义图(Semantic Graph)来做代码理解。简单来说,它能把代码中的变量关系、函数调用链、依赖关系都建模成一张图,然后在这张图上做各种分析。

我当时看到Qoder的文档,第一反应是:"这玩意儿有点东西。"

但上手之后才发现,坑是真的多。

第一个坑是文档。Qoder的官方文档写得那叫一个"言简意赅",很多关键配置一笔带过,示例代码经常跑不通。我怀疑写文档的哥们是不是觉得大家都跟他一样聪明。没办法,只能硬啃源码。那段时间我白天跟团队对齐需求,晚上回家翻Qoder的源码,翻到凌晨两三点是常态。

第二个坑是性能。Qoder默认的分析模式在处理大型项目时,内存占用会飙升。我们有个Java微服务项目,代码量大概30万行,Qoder跑一次全量分析直接把8G内存吃满了,然后OOM。当时我盯着那个java.lang.OutOfMemoryError: Java heap space,真的想砸电脑。

后来我花了整整一周时间调优,最终摸索出一套配置方案:

# qoder-config.yaml
analysis:
  mode: incremental  # 关键!不要用full,用增量分析
  graph:
    max_nodes: 50000
    pruning:
      enabled: true
      strategy: depth-based
      max_depth: 8
  memory:
    heap_size: 4g
    gc_threshold: 0.75
    off_heap: true
  parallelism:
    workers: 4
    batch_size: 200
  cache:
    enabled: true
    backend: redis
    ttl: 3600

这套配置的核心思路是:增量分析 + 图剪枝 + 离堆内存 + Redis缓存。跑起来之后,同样的项目分析时间从原来的12分钟降到了3分半,内存峰值也从8G降到了3.2G。

当时看到性能数据的那一刻,我长舒一口气,赶紧截图发到团队群里。结果运维大哥回了一句:"不错,但你这配置在K8s里跑的话,资源限制得改改。"

得,又被安排得明明白白。

Perplexity帮我填了多少知识盲区

说到调研,不得不提Perplexity。

这半年我养成了一个习惯:遇到不懂的技术概念或者需要快速了解一个领域,第一反应不是去Google,而是打开Perplexity问一嘴。它的好处是自带引用来源,不会像某些AI那样一本正经地胡说八道。

在调研代码审查这个方向的时候,我用Perplexity做了大量的技术调研。比如:

  • 静态分析与动态分析的优劣对比
  • 不同编程语言的AST解析库现状
  • 业界主流的代码质量度量模型
  • 最新的LLM在代码理解上的能力边界

有个细节让我印象很深。当时我在纠结一个问题:代码审查系统中,到底应该用传统的规则引擎还是直接用LLM来做判断?传统规则引擎稳定可控,但维护成本高;LLM灵活智能,但幻觉问题让人头疼。

我把这个问题丢给Perplexity,它给了我一个很有启发性的回答:两者不是非此即彼的关系,可以分层设计。底层用规则引擎做确定性检查(比如语法错误、明显的bug模式),上层用LLM做语义级别的审查(比如设计模式是否合理、代码是否可读)。

这个思路后来成了我们整个系统的架构基础。

当然,Perplexity也不是万能的。有一次我问它关于某个特定开源项目的内部实现细节,它给我的答案看起来头头是道,结果我去翻源码发现完全是瞎编的。当时我差点就信了,还好有"翻源码验证"这个程序员的本能救了我。

所以我的经验是:Perplexity适合做广度调研,但深度信息一定要自己验证。AI是助手,不是老师。

Grok带来的意外惊喜

说到AI工具,今年年初Grok开放API之后,我也第一时间拿来试了试。

说实话,一开始我对Grok没抱太大期望。毕竟ChatGPT和Claude已经用得很顺手了,再换一个模型的迁移成本不低。但Grok有个独特的优势——它的实时信息获取能力。

这在我们的项目里派上了大用场。

场景是这样的:代码审查系统需要判断某段代码是否使用了已知的有安全漏洞的依赖版本。传统做法是维护一个漏洞数据库,定期更新。但这个方案有两个问题:一是数据库更新有延迟,新漏洞可能几天后才入库;二是维护成本高,需要专门的人盯着。

我试着用Grok的实时搜索能力来做这件事。思路很简单:当系统检测到某个依赖时,调用Grok的API,实时查询这个依赖版本是否存在已知漏洞。Grok会去搜索最新的安全公告、CVE数据库、GitHub Security Advisory等信息源,然后返回结构化的结果。

import requests
import json

class VulnerabilityChecker:
    def __init__(self, grok_api_key):
        self.api_key = grok_api_key
        self.endpoint = "https://api.x.ai/v1/chat/completions"
    
    def check_dependency(self, package_name, version, language):
        """
        实时查询依赖版本的安全漏洞信息
        """
        prompt = f"""
        请查询以下软件依赖是否存在已知安全漏洞:
        - 包名: {package_name}
        - 版本: {version}
        - 语言/生态: {language}
        
        请返回JSON格式的结果:
        {{
            "has_vulnerability": true/false,
            "cve_ids": ["CVE-xxxx-xxxxx"],
            "severity": "critical/high/medium/low/none",
            "fixed_version": "x.x.x 或 null",
            "description": "漏洞简述",
            "references": ["url1", "url2"]
        }}
        
        如果没有找到漏洞信息,has_vulnerability设为false。
        请确保信息准确,如果不确定请标注confidence字段。
        """
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": "grok-2-latest",
            "messages": [
                {"role": "system", "content": "你是一个软件安全专家,专注于依赖漏洞分析。请只返回JSON格式的结果。"},
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.1,  # 低温度,减少随机性
            "search": True  # 开启实时搜索
        }
        
        try:
            response = requests.post(
                self.endpoint, 
                headers=headers, 
                json=payload,
                timeout=30
            )
            response.raise_for_status()
            
            result = response.json()
            content = result['choices'][0]['message']['content']
            
            # 解析JSON结果
            # 需要处理可能的markdown代码块包裹
            content = content.strip()
            if content.startswith("```json"):
                content = content[7:-3]
            elif content.startswith("```"):
                content = content[3:-3]
            
            return json.loads(content)
            
        except Exception as e:
            # 降级处理:返回未知状态,后续走人工审核
            return {
                "has_vulnerability": None,
                "error": str(e),
                "fallback": "manual_review"
            }

实际跑起来效果还不错。Grok的实时搜索能抓到一些很新的漏洞信息,比传统的漏洞数据库快了不少。当然也有误报的情况,所以我们加了一个置信度字段,低置信度的结果会标记为"需人工确认"。

但Grok也有让我抓狂的时候。有一次它返回的JSON格式死活解析不了,我debug了半天发现它在JSON里加了注释。JSON里加注释!我当时真是哭笑不得,赶紧加了个预处理步骤把注释去掉。

import re

def clean_json_string(json_str):
    """清理AI返回的JSON字符串中的注释和多余内容"""
    # 移除单行注释
    json_str = re.sub(r'//.*?\n', '\n', json_str)
    # 移除多行注释
    json_str = re.sub(r'/\*.*?\*/', '', json_str, flags=re.DOTALL)
    # 移除markdown代码块标记
    json_str = re.sub(r'```(?:json)?\s*', '', json_str)
    json_str = re.sub(r'```\s*$', '', json_str)
    return json_str.strip()

这种"擦屁股"的代码,写AI应用的人应该都懂。

求职季的技术准备

说到这,可能有人好奇:你都技术总监了,为什么还要出来创业?

其实这个想法酝酿很久了。在大厂做技术管理,大部分时间都在开会、对齐、汇报。真正写代码、做技术决策的时间越来越少。我骨子里还是个工程师,更享受那种从0到1把东西做出来的成就感。

而且说实话,今年深圳的技术圈子变化很大。腾讯系公司裁员的消息一波接一波,虽然我没在裁员名单上,但那种不确定性让人很不舒服。与其等着被优化,不如自己掌握主动权。

在准备创业的这段时间,我也帮几个朋友内推和面试,顺便自己也面了几家。这个过程让我对当前市场的需求有了更清晰的认知。

面试中有一个问题被反复问到:"你怎么看AI对软件工程的影响?"

我的回答是:AI不会取代程序员,但会重新定义程序员的工作方式。未来的工程师,核心竞争力不再是写代码的速度,而是系统设计的能力、问题拆解的能力、以及跟AI协作的能力。

这不是空话。我这半年用ChatGPT和Claude辅助开发的体验太深了。以前写一个模块,从设计到实现可能要两三天。现在呢?思路理清之后,让AI先生成一版基础代码,然后我在此基础上调整、优化、补充边界case处理,半天就能搞定。效率提升不是一点半点。

但这也带来一个新的问题:代码质量怎么保证?

AI生成的代码,乍一看挺像那么回事,但仔细审查经常能发现一些问题:

  • 边界条件处理不完善
  • 异常处理过于简单
  • 命名不够语义化
  • 缺少必要的注释
  • 性能上有优化空间

所以我在团队里推了一套AI辅助开发的规范:

环节 AI负责 人负责
需求理解 辅助拆解需求、生成技术方案 最终决策、风险评估
代码生成 生成基础框架和业务代码 审查、优化、补充边界处理
单元测试 生成基础测试用例 补充边界case、审查覆盖率
代码审查 初步检查常见问题 深度审查架构合理性
文档编写 生成API文档、注释 审查准确性、补充业务上下文

这套规范的核心思想是:AI做80%的重复性工作,人做20%的创造性决策。

架构设计上的几个关键决策

回到代码审查平台这个项目。最终我们确定的架构大致是这样的:

┌─────────────────────────────────────────────────────┐
│                    API Gateway                       │
│                  (Kong / Nginx)                      │
└──────────────────────┬──────────────────────────────┘
                       │
         ┌─────────────┼─────────────┐
         │             │             │
    ┌────▼────┐  ┌─────▼─────┐  ┌───▼────┐
    │ 代码解析 │  │ 规则引擎  │  │ AI审查 │
    │ Service │  │ Service   │  │Service │
    │(Qoder)  │  │(Drools)   │  │(LLM)   │
    └────┬────┘  └─────┬─────┘  └───┬────┘
         │             │             │
         └─────────────┼─────────────┘
                       │
               ┌───────▼───────┐
               │ 结果聚合服务   │
               │ (Aggregator)  │
               └───────┬───────┘
                       │
         ┌─────────────┼─────────────┐
         │             │             │
    ┌────▼────┐  ┌─────▼─────┐  ┌───▼────┐
    │  Redis  │  │ PostgreSQL│  │  MinIO │
    │ (缓存)  │  │  (业务库) │  │(文件存储)│
    └─────────┘  └───────────┘  └────────┘

几个关键的设计决策:

第一,Qoder负责代码语义理解。 前面说了,Qoder基于语义图做代码分析,能提取出代码的深层结构信息。这些信息会作为上下文传递给后续的规则引擎和AI审查模块。

第二,规则引擎和AI审查并行执行。 规则引擎处理确定性的检查项(编码规范、已知bug模式),AI审查处理语义级别的分析(设计合理性、代码可读性)。两者并行执行,最后由聚合服务合并结果。这样既保证了速度,也保证了覆盖面。

第三,结果聚合不是简单的合并。 这里有个 tricky 的地方:规则引擎和AI审查可能会对同一段代码给出不同的判断。比如规则引擎认为某个函数太长需要拆分,但AI审查认为这个函数虽然长但逻辑清晰、职责单一,不需要拆分。这种情况下怎么办?

我们的做法是引入一个"置信度加权"机制。规则引擎的结果置信度固定为1.0(因为是确定性规则),AI审查的结果根据模型输出的置信度动态调整。当两者冲突时,优先采纳置信度高的那个。如果置信度接近,则同时保留两个建议,让用户自己判断。

class ResultAggregator:
    def __init__(self):
        self.conflict_resolution_strategy = "confidence_weighted"
    
    def aggregate(self, rule_results, ai_results, code_context):
        """
        聚合规则引擎和AI审查的结果
        """
        all_findings = []
        
        # 合并无冲突的结果
        rule_map = {r.code_location: r for r in rule_results}
        ai_map = {r.code_location: r for r in ai_results}
        
        all_locations = set(rule_map.keys()) | set(ai_map.keys())
        
        for location in all_locations:
            rule_finding = rule_map.get(location)
            ai_finding = ai_map.get(location)
            
            if rule_finding and not ai_finding:
                # 只有规则引擎发现问题
                all_findings.append(rule_finding)
            elif ai_finding and not rule_finding:
                # 只有AI发现问题
                all_findings.append(ai_finding)
            else:
                # 两者都发现问题,需要处理冲突
                merged = self._resolve_conflict(
                    rule_finding, ai_finding, code_context
                )
                if merged:
                    all_findings.append(merged)
        
        # 按严重程度排序
        all_findings.sort(key=lambda x: x.severity_level, reverse=True)
        
        return all_findings
    
    def _resolve_conflict(self, rule_finding, ai_finding, context):
        """
        解决规则引擎和AI审查之间的冲突
        """
        # 如果两者结论一致,直接合并
        if rule_finding.conclusion == ai_finding.conclusion:
            return MergedFinding(
                location=rule_finding.code_location,
                conclusion=rule_finding.conclusion,
                rule_suggestion=rule_finding.suggestion,
                ai_suggestion=ai_finding.suggestion,
                confidence=max(rule_finding.confidence, ai_finding.confidence)
            )
        
        # 结论冲突,按置信度决策
        if rule_finding.confidence >= ai_finding.confidence:
            # 规则引擎置信度更高,采纳规则引擎结论
            # 但保留AI的不同意见作为参考
            return MergedFinding(
                location=rule_finding.code_location,
                conclusion=rule_finding.conclusion,
                primary_suggestion=rule_finding.suggestion,
                alternative_view=ai_finding.suggestion,
                confidence=rule_finding.confidence,
                has_conflict=True
            )
        else:
            # AI置信度更高,采纳AI结论
            return MergedFinding(
                location=ai_finding.code_location,
                conclusion=ai_finding.conclusion,
                primary_suggestion=ai_finding.suggestion,
                alternative_view=rule_finding.suggestion,
                confidence=ai_finding.confidence,
                has_conflict=True
            )

那些让人崩溃的线上问题

项目上线后,果不其然,问题一个接一个。

最经典的一次是内存泄漏。上线第一周,某天凌晨三点,运维大哥一个电话把我从床上叫醒:"你们那个审查服务内存快爆了,赶紧看看。"

我迷迷糊糊打开监控一看,好家伙,内存使用率已经95%了,而且还在持续上涨。第一反应是Qoder的语义图没释放。赶紧排查,发现是一个边界case:当用户上传了一个超大的单文件(超过10万行),Qoder在构建语义图时会把所有节点都加载到内存里,而我们配置的max_nodes是50000,但这个限制只对单个分析单元生效,超大文件被当成了一个分析单元。

解决方案是加了一个文件预检查:

def pre_check_file(file_content, max_lines=50000):
    """
    文件预检查,防止超大文件导致内存溢出
    """
    lines = file_content.split('\n')
    
    if len(lines) > max_lines:
        # 超大文件,分块处理
        chunks = split_into_chunks(lines, chunk_size=10000)
        return {
            "need_split": True,
            "chunks": chunks,
            "total_lines": len(lines)
        }
    
    return {
        "need_split": False,
        "content": file_content,
        "total_lines": len(lines)
    }

def split_into_chunks(lines, chunk_size=10000):
    """
    按函数/类边界智能分块,避免在逻辑中间切断
    """
    chunks = []
    current_chunk = []
    brace_depth = 0
    
    for i, line in enumerate(lines):
        current_chunk.append(line)
        brace_depth += line.count('{') - line.count('}')
        
        # 在brace_depth为0的时候可以考虑切分
        if (len(current_chunk) >= chunk_size 
            and brace_depth == 0 
            and line.strip() == ''):
            chunks.append('\n'.join(current_chunk))
            current_chunk = []
    
    if current_chunk:
        chunks.append('\n'.join(current_chunk))
    
    return chunks

这个bug修完之后,我特意在团队里立了个规矩:所有涉及内存操作的功能,必须做压力测试,而且测试用例里必须包含超大文件的case。

还有一次更离谱。Grok的API突然返回了一堆乱码,导致我们的漏洞检查服务直接崩了。排查了半天发现,是某个用户的包名里包含了一些特殊字符(Unicode emoji),Grok在处理的时候出了问题。

你能想象一个包名叫my-awesome-lib-🚀-v2吗?我当时看到这个包名,真是又气又好笑。最后加了一层输入清洗:

import re
import unicodedata

def sanitize_package_name(name):
    """
    清洗包名,移除可能导致AI模型异常的特殊字符
    """
    # 移除emoji和其他非ASCII特殊字符
    cleaned = ''.join(
        char for char in name 
        if unicodedata.category(char)[0] in ('L', 'N', 'P', 'Z', 'S')
        and ord(char) < 128
    )
    
    # 只保留字母、数字、连字符、下划线、点号
    cleaned = re.sub(r'[^a-zA-Z0-9._-]', '', cleaned)
    
    # 防止空字符串
    if not cleaned:
        cleaned = "unknown_package"
    
    return cleaned

创业路上的一些思考

写到这里,好像一直在聊技术细节。但作为一个即将创业的前技术总监,我想分享一些更宏观的思考。

第一,技术选型不要追新,要追"合适"。

Qoder、Perplexity、Grok,这些都是我精挑细选的。但选择它们不是因为它们最火,而是因为它们在特定场景下最合适。Qoder的语义图分析适合我们的代码理解需求,Perplexity的引用机制适合技术调研,Grok的实时搜索适合漏洞查询。每个工具都有它的短板,关键是看你能不能接受这些短板,以及有没有办法弥补。

第二,AI是杠杆,不是拐杖。

我这半年用AI辅助开发的体会是:AI能放大你的能力,但不能替代你的思考。如果你自己都不清楚要做什么,AI给你的东西也是一团浆糊。最好的使用方式是:你先想清楚架构和关键设计,然后让AI帮你实现细节。这样效率最高,质量也最有保障。

第三,代码质量是底线,不是目标。

在大厂的时候,经常听到"先上线再说"、"技术债以后再还"。但出来创业之后,我更加坚信:代码质量是底线。因为你没有大厂的资源来还技术债,每一行烂代码都可能在将来要你的命。这也是为什么我在架构设计上花了那么多时间——磨刀不误砍柴工。

第四,深圳的创业环境确实好。

这点算是私心。深圳的技术氛围、供应链、资本活跃度,在国内都是顶级的。尤其是南山区,走几步就能遇到一个前腾讯的兄弟,交流起来特别方便。当然,竞争也激烈,但这就是创业该有的样子。

写在最后

这篇文章写了快四个小时,从下午两点一直写到晚上六点。窗外深圳的天已经暗了,南山那边的写字楼还亮着灯。

回想这几年的技术生涯,从刚毕业时连Git都不太会用的小白,到如今准备自己出来折腾,中间踩了无数的坑,也收获了很多。技术这条路,说到底就是一直在解决问题。旧的问题解决了,新的问题又来了。但正是这种不断解决问题的过程,让人觉得有意思。

创业之后的路肯定更难。但至少现在,我还能按照自己的想法去做技术决策,还能亲手写代码,还能跟一群志同道合的人一起折腾。

这就够了。

如果你也在技术这条路上,不管是在大厂还是在小公司,不管是想跳槽还是想创业,希望这篇文章里的一些经验能帮到你。技术探索没有捷径,但至少有前人的坑可以少踩几个。

共勉。


P.S. 如果你在深圳,也在做AI+开发者工具方向,欢迎来聊。创业初期,求贤若渴。简历可以发到我的邮箱,或者直接微信找我。备注"博客读者",我请喝咖啡。

评论 0

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