在 AI Agent 时代学着做一个领导

本文最后更新于 2025年11月26日 上午

本文先用 Cursor Plan mode Sonnet 4.5 生成 plan,再由 grok-code-fast-1 生成具体文章;(首次AI writing)
发现几乎没有人味且幻觉严重距想表达的意思相去甚远,想到连完备的,没有歧义的代码都能乱理解乱改,
更别说本来就“约定俗成”的自然语言了,因此最后由人类(本人)就着框架几乎重写了一遍。
但不得不说,正如 Coding with AI Agent 一样,对着现成的文章改完全避免了之前写文章出现的
大量脑子想了一大堆提笔就卡壳,写着突然忘记上下文等垃圾时间,极大程度一直维持心流状态!
毕竟搞建设是有门坎的,但是挑错那可是人民群众与生俱来的看家本事。

由于本人现在都是用英语进行 prompt chating,发现 AI 基本能理解我的英语,且会先总结 my prompt 的一个 smoothly 版本,已经得到了足够的锻炼,因此博客里面就没有必要生拽了。

新的职责

这一段我尝试让 AI 帮我写,结果充分体现了什么叫做自然语言的博大精深,这种主观的表达还是只能自己来,所以想到哪里写到哪里,都纯手写的,上面引言中提到的垃圾时间体现得淋漓尽致。

重回技术

上一篇博文就用了这个标题,挣扎了这么久,终于回去安心搞技术了,还真能顺便学团队建设。

正好基本上在去年的这个时候,声网Agora 要垮了把我裁掉,其实在那里的一年也没做到什么有意思的项目。

最开始说的纯自研前后端统一的 SDK编译发版平台 也随着领导更换回到了维护一堆历史底蕴深厚积重难返的 Jenkins。

后来加入百度,title 还是 Manager,但实际上干的事情既没技术又不管理。 不到半年火速跑路,现加入了一家小公司担任技术其中一个领导,经过个把月的磨合,现在感觉到身上的责任和挑战了。

新的挑战

之前负责带一个实习生的时候,正好又是在项目最忙的时候,疏于团队建设,结果人家直接只复制粘贴 output 到 AI chat,从来不看代码,commit 也不写就提交上去。

唯一能看的代码还是我手把手教的,一说还一肚子不服气,在多次被团队成员看到摸鱼甚至是转着圈龇牙咧嘴的玩手机的时候,还理直气壮的和 HR 说自己能力没问题,是在等 AI 生成代码。

领导第一次问我的时候还力保了,等领导第三次过问我突然惊恐地发现这样下去被开的就应该是我了,于是就发生了上述的 HR 客气劝退,结果还委屈地赖着不走的一幕。

这倒是提醒我了,我现在这个岗位对我的定位不再只是写代码完成自己的功能模块,之后还会有越来越多团队建设的挑战,我现在就要开始调整心态。

现在这个时代,既要领导人,又要领导 AI,还不能忘基本功。

AI Agent 协作:就像打游戏开自动刷怪

一、本次任务背景

这次面临的任务是一个 RPA 自动化项目,基于 DrissionPage 的浏览器自动化框架。项目原本在宿主机运行,需要迁移到 Docker 容器中实现更便捷的部署和管理。

核心需求是:

  1. 用 Docker 实现 GUI 的浏览器自动化;

  2. 浏览器登录状态必须在容器重启后保持。这是业务的关键要求,不能每次重启都重新登录。

这个任务听起来不复杂,但实际执行中遇到了一系列技术挑战。

二、传统方式 vs AI Agent 方式

2.1 如果没有 AI,我需要做什么

如果用传统方式解决这个问题,我大概需要:

  1. 搜索 Docker 中运行 GUI 应用的方案 - 研究 headless 浏览器、Xvfb、VNC 等多种方案
  2. 深入研究 Chrome 持久化机制 - 学习 Chrome 的用户数据目录结构和锁机制
  3. 阅读 DrissionPage 官方文档 - 了解框架对容器化部署的支持程度
  4. 尝试各种配置组合 - 在 Docker、Chrome、DrissionPage 之间寻找兼容方案
  5. 调试部署和运行问题 - 解决权限、路径、网络等一系列容器化问题

这个过程可能需要 5-7 天时间,不断在网上搜索、试错、调整,劳神费心还很可能查到了正确的实践但是没走通。

2.2 容易陷入的困境

技术选型迷失:Docker 中运行 GUI 应用有太多方案 - headless、Xvfb、VNC、noVNC,每种都有优缺点,不知道选哪个。

调试黑洞:错误信息往往不明确,一个”连接失败”可能背后有十种原因,需要层层排查。

时间浪费:每个方案都要深入研究和尝试才能知道是否可行,很多时候走了弯路。

三、真实案例:Chrome 持久化问题的解决过程

这里 AI 帮我写的时候漏掉了 Docker 中运行 GUI 应用部分,总之就是 Agent 先提出了一些方案,然后 Agent 就一直自动跑命令行各种尝试,有报错就各种自己 Debug,最后给了我一个方案。

最开始那个方案跑出来有问题,然后我让他参考我 Host 机器的 GUI 相关的配置,它就自己生成了 detect 脚本,然后也是自动化的各种改,真的太强了,完全淘汰了很多人引以为豪也是唯一拿得出手的堆工时。

3.1 问题初现

项目迁移到 Docker 后,第一天就遇到了问题。

第一次报错

1
2
3
4
5
6
浏览器连接失败。
地址: 127.0.0.1:9310
提示:
1、用户文件夹没有和已打开的浏览器冲突 (尤其是这句,“没有和”...“冲突”,翻译翻译,把我当日本人整呢?当然其实 root case 就是这个)
2、如为无界面系统,请添加'--headless=new'启动参数
3、如果是Linux系统,尝试添加'--no-sandbox'启动参数

这个错误信息很模糊,不知道是 Docker 配置问题、Chrome 配置问题,还是 DrissionPage 的问题。让我很困惑,不知道该从哪里下手。

3.2 AI Agent 的诊断过程

步骤 1:AI 建议检查挂载卷

AI Agent 首先帮我检查了 Docker 挂载配置,确认数据目录正确挂载。

步骤 *:AI 和我做了很多的尝试

先是我不断的要求 Plan mode Sonnet 4.5 (费用高) 列出可能的问题,然后让 grok-code-fast-1 (费用低)实践尝试。

然后查找用到的技术栈的官方文档请 AI 先读一遍,猜测可能的问题。

我们起码一共试验了五六种可能的大方向,比如说是否某些配置文件挂载有问题,是否各种权限有问题,这个过程中深刻体会到 AI 对上下文动辄就遗忘的赛博老年痴呆。

说真的,这两个事情让我去做基本上都是垃圾时间。

步骤 2:AI 建议手动测试 Chrome

AI 让我在容器中直接运行 Chrome 命令来获取真实错误信息:

1
2
3
/usr/bin/google-chrome --remote-debugging-port=9310 \
--user-data-dir=/workspace/browser-data/chrome_data_acct_ \
--no-sandbox --disable-gpu

步骤 3:发现真实错误

这次我们看到了真正的错误信息:

1
2
[ERROR] 其他计算机 (e7977e9b8d52) 的另一个 Google Chrome 进程 (78)
好像正在使用此个人资料。Chrome 已锁定此个人资料以防止其受损。

步骤 4:AI 分析根本原因

AI 立即分析出了问题的本质: (即使定位到这里后面都还走了一些弯路)

  • e7977e9b8d52 是旧容器的 hostname(Docker 自动生成的容器 ID)
  • 78 是旧容器中 Chrome 的进程 ID
  • SingletonLock 是符号链接,指向旧容器的进程
  • Docker 重启后 hostname 变了,但锁文件还在

步骤 5:尝试 headless 模式(失败)

AI 建议添加 --headless=new,但导致 WebSocket 连接失败。我告诉 AI DrissionPage 可能不支持这种模式。(是的,我在无数个 prompt 中明确的说了不要 headless,但是不管是哪个模型都会在试验过其他问题不行的时候,就擅自试一下,开始我很气,后来我想到确实也有可能出现人类一开始判断错误,如果 AI 不去尝试 “我一开始就不行” 的方向,说不定就卡死了)

步骤 6:实现锁文件清理(第一版失败)(这就是我上文说的,定位到 root case 之后的弯路之一,一开始他还非不承认有问题)

AI 实现了第一版清理代码:

1
2
3
# 第一版代码(有 bug)
if lock_file.exists():
lock_file.unlink()

但这个代码有 bug:exists() 检查符号链接的目标,目标不存在返回 False,所以清理代码永远不会执行。

步骤 7:AI 发现 Python API 的陷阱

AI 通过测试发现:

  • Path.exists() 检查的是符号链接的目标是否存在
  • 目标不存在时返回 False,导致清理代码不执行
  • 需要用 is_symlink() 检查符号链接本身

步骤 8:正确的实现

1
2
3
4
5
6
7
def _clean_stale_locks(self, user_data_dir: str) -> None:
lock_file = Path(user_data_dir) / "SingletonLock"

# 关键:检查符号链接本身
if lock_file.exists() or lock_file.is_symlink():
lock_file.unlink(missing_ok=True)
self.logger.info(f"Cleaned stale lock file: {lock_file}")

步骤 9:超时时间调整(这里我说了不需要,超时是有问题连不上,他还是硬要加上)

AI 发现 Chrome 在容器中启动变慢,建议增加超时时间:

1
DrissionSettings.set_browser_connect_timeout(60)

步骤 10:验证成功

最终验证成功:

1
2
19:44:53 | INFO  | Cleaned stale lock file: browser-data/chrome_data_acct_/SingletonLock
19:44:54 | INFO | ✓ Successfully created Chrome browser for acct_ on port 9287

3.3 技术细节:SingletonLock 机制

问题本质

1
2
3
4
5
# 锁文件是符号链接
$ ls -la SingletonLock
lrwxrwxrwx SingletonLock -> e7977e9b8d52-78
└─────┬────┘ └┬┘
旧容器ID 旧进程ID

Docker 重启流程

AI 太厉害了,这个图你让我画我都要磨蹭半天

sequenceDiagram
    participant Docker as Docker容器
    participant Chrome as Chrome进程
    participant Lock as SingletonLock
    participant Disk as 挂载卷

    Note over Docker: 旧容器 (e7977e9b8d52)
    Chrome->>Lock: 创建 SingletonLock -> e7977e9b8d52-78
    Lock->>Disk: 写入挂载卷

    Note over Docker: 容器重启
    Docker->>Chrome: 杀死进程
    Note over Lock: 锁文件保留在磁盘

    Note over Docker: 新容器 (d12eb5af59ba)
    Chrome->>Lock: 检测到 SingletonLock -> e7977e9b8d52-78
    Chrome->>Chrome: hostname 不匹配!
    Chrome--xChrome: 拒绝启动

四、AI Agent 的震撼之处

4.1 真实完成的工作量统计

AI Agent 自动执行的任务(来自聊天记录):

  1. 检查 Docker 配置和挂载卷(5+ 次命令)
  2. 分析文件权限和目录结构(8+ 次命令)
  3. 手动测试 Chrome 启动(3+ 次尝试)
  4. 编写和执行调试脚本(10+ 个脚本)
  5. 分析 DrissionPage 源码(3 个文件)
  6. 实现和修复代码(5 次迭代)
  7. 编写测试用例(3 个测试文件)
  8. 更新文档(README 中英文)
  9. 生成 git commit(2 次提交)

时间对比

  • 人工预计:5-7 天
  • AI Agent 实际:约 4 小时
  • 效率提升:10-20 倍

心情对比

  • 像打游戏开了自动寻路一样

4.2 AI Agent 的核心价值

1. 快速信息整合

自动关联 Docker、Chrome、DrissionPage 知识,无需人类手动搜索和阅读大量文档,直接给出最相关的解决方向。

说真的这里面即使我熟悉的技术栈我真看的时候也得小心翼翼,root case 对应的文档部分一定会在某个不经意的地方被漏掉的。

2. 自动化执行与验证

立即执行命令并分析结果,发现问题立即调整策略,自动生成测试脚本验证。

说真的你要我去写,测试代码我都要构造好久,我还没写完 Agent 都跑完了,我再写一百年代码我也没这个能力。

3. 系统化问题追踪

从表面错误(连接失败)→ 真实错误(SingletonLock)→ 根本原因(符号链接 + Docker hostname)→ 完整解决方案(清理 + 超时调整)

4. 代码质量保证

自动处理边界条件(missing_ok=True)、完善的错误处理、详细的代码注释、自动生成文档。

4.3 如果是我自己做

可能的困境

  1. 在 GUI in Docker 具体方案如 Xvfb 之间纠结很久,试验成本太高
  2. 看到”连接失败”不知道从何查起
  3. 即使发现 SingletonLock,也可能不知道是符号链接问题
  4. 可能写出有 bug 的代码,然后困惑为什么不工作
  5. 需要深入研究 Python pathlib 文档才能发现 exists() 的陷阱

预计耗时
别预计了上不封顶,预计到被开为止

五、AI Agent 的局限性(真实体验)

5.1 需要人类提供方向

真实案例

  • AI 最初建议用 headless 模式,但我知道 DrissionPage 可能不支持(你看又瞎写,我强调了很多次是业务上不能,有些目标网站不能用 headless 这个必须我们后面手动试出来,他就是总有自己的理解)
  • AI 需要我提供 DrissionPage 官方文档链接(不然我看它一直在自己写一堆方法去调 .venv/lib/python3.12/site-packages/DrissionPage/_pages/chromium_page.py 人家库里面的 API 验证,我让他打开 Connected to External Browser 官方文档两下就解决了)
  • AI 需要我确认业务场景(必须保持登录状态)

5.2 需要人类验证结果

真实案例

  • AI 生成的第一版清理代码有 bug,我需要在 Docker 容器中实际测试
  • 我需要确认登录状态是否真的保留了

5.3 LLM 的幻觉问题

真实案例

  • AI 有时会建议不存在的 DrissionPage API,需要我查阅官方文档确认
  • 更别说经典的自己编 API 然后一运行就报错了
  • 关键决策需要我最终拍板

后面都是一堆漂亮的车轱辘话,我全删了


附录:关键代码实现

SingletonLock 清理实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def _clean_stale_locks(self, user_data_dir: str) -> None:
"""清理过时的Chrome锁文件(Docker重启场景)"""
if not user_data_dir:
return

lock_file = Path(user_data_dir) / "SingletonLock"

# 关键:检查符号链接本身(不检查目标是否存在)
if lock_file.exists() or lock_file.is_symlink():
try:
lock_file.unlink(missing_ok=True)
self.logger.info(f"Cleaned stale lock file: {lock_file}")
except Exception as e:
self.logger.warning(f"Failed to clean lock file {lock_file}: {e}")

调用时机

1
2
3
4
5
6
7
8
9
def _create_session(self, session_id: str, persistent: bool = False,
user_data_dir: Optional[str] = None) -> Chromium:
# 清理过时锁文件(Docker 重启场景)
if persistent and user_data_dir:
self._clean_stale_locks(str(user_data_dir))

# 现在可以安全启动 Chrome
browser = Chromium(addr_or_opts=options)
return browser

参考资料

别整一堆静态链接了,说不定点进去发现都过期了。让 AI 现场生成,已经又准又精炼了,感觉是从以前的游戏 CG 进化到了实时渲染的美。


在 AI Agent 时代学着做一个领导
https://gou7ma7.github.io/2025/11/09/career/@2025_be_leader_in_ai_era/
作者
Roy Lee
发布于
2025年11月9日
许可协议