花了两天时间,想让 LangChain 的 AgentExecutor 按自己的想法干活。结果呢?能跑。工具调用了,答案也出来了。但他说不清楚这个 Agent 为什么做这个选择、为什么调那个工具。想换个 LLM 供应商,追踪链路直接断了。想加第二个工具,调度逻辑缠在一层层自己没写过、也看不懂的抽象里。
![]()
于是他把 LangChain 删了,手写了一个约 270 行的 ReAct 循环。这个项目叫 RepoPilot,目标是一个 CI 修复 Agent:给定一次失败的 GitHub Actions 运行,最终能诊断故障并给出人类可审批的修复方案。但在这之前,他需要先打好地基——一个能通过受控工具检查本地 Git 仓库、通过供应商无关接口和 LLM 对话、并记录每一步决策的 Agent。
LangChain、CrewAI 这类框架本身有价值:预置的工具集成、记忆抽象、可观测性回调、开箱即用的多 Agent 编排。如果项目需要快速接入大量集成,或者框架的取向正好和你一致,它们确实是加速器。但对这个项目,三件事出了问题。
- 不透明:AgentExecutor 做决策时,提示链、工具选择逻辑、中间解析全发生在自己没写过的层里,调试等于读框架源码,而不是读自己的代码。
- 供应商锁定:框架对 LLM 供应商的抽象有自己的形状。把 Gemini 换成本地 Ollama 模型时,追踪就断了,回调系统和 LLM 抽象绑在一起,不完全可控。
- 框架频繁变动:LangChain 的 API 变化很快,半年前的代码经常需要重写。对一个打算长期维护和扩展的项目,这是负债。
单独看,每一条都不致命。合在一起,指向一个清晰的答案:对一个全部价值就在于可审计和可控的项目,黑盒是错误的底座。
ReAct(Reason + Act,推理加行动)是个很简单的模式:LLM 推理下一步做什么,选一个工具并给出参数,工具运行返回结果,结果加回对话,重复直到 LLM 给出最终文本回复。核心实现大约 20 行逻辑,通过 max_steps 限制迭代次数,通过注册表做工具调度,消息结构随时可检查,达到步数上限还有最终答案兜底。
一个早期做对的设计决策是:核心层永远不导入任何供应商 SDK。Agent 面向接口说话,不直接面向 Gemini、OpenAI 或 Ollama。Gemini 适配器实现这个接口,换供应商意味着写一个新适配器,而不是重写 Agent。可以先用免费的云端 API 开发,之后改一个环境变量就切到本地模型,Agent 根本不知道区别。这个适配器模式多花了约 50 行代码,换来的是第二阶段需要的灵活性。
在加第二个工具之前,他先做的是追踪。每次 Agent 运行都产生一份结构化 trace:每一次 LLM 调用、每一次工具调用、每一个结果、每一个错误。不是日志行,是数据模型。每次运行结束,RepoPilot 打印一份摘要——目标、总步数、LLM 调用次数、工具调用次数、错误数、总耗时,并把完整 trace 写入 .runs/{run_id}.json。
这才是让 Agent 可调试的东西。运行失败时不用猜,打开 trace 就能看到到底发生了什么:哪个提示进去了,哪个工具被调用了,返回了什么,循环在哪里断掉。先建追踪再加工具的原因很直接:如果有 5 个工具而循环是坏的,根本不知道问题出在哪个。有了追踪,就能看到循环运转正常而某个工具行为异常,或者反过来。
他也分享了两个诚实的错误。第一,最初把追踪放在了供应商适配器里,看起来合理,因为 API 调用就发生在那。但换供应商时追踪就会丢失,后来把它移到了核心循环,现在无论哪个供应商在跑,追踪表现完全一致。跨领域的关注点——追踪、安全、审批——应该放在核心层,而不是供应商层。第二,一开始就写了 5 个工具:git_status、git_diff、read_file、list_files、search_code。然后花了一整天调试工具 schema 和错误处理,而那时他甚至还不确定自己的 ReAct 循环是否正确。最后砍到只剩一个工具 git_status,刚好够证明循环能跑。一个工具就足以验证架构,功能要等地基稳固之后再加。
第一阶段完成了。这个 Agent 通过供应商无关的接口和 Gemini 对话,调用一个只读的 git_status 工具,记录每次运行的结构化 JSON trace,通过 68 个自动化测试,能在真实的本地仓库上端到端运行。它还不是 CI 修复 Agent,但它是那个 Agent 的地基,干净、有测试,最重要的是——能看懂。
第二阶段才是 RepoPilot 名副其实的地方:确定性地解析 GitHub Actions 日志,已知故障模式不用 LLM;只在模式模糊时才升级给 LLM;把修复方案作为 diff 提出,但未经人类审批绝不应用;追踪每一个决策。确定性优先的设计是差异点——大多数 CI 修复 Agent 把日志丢给 LLM 然后祈祷,RepoPilot 会先用正则分类故障,只在必须时才动用 LLM。
框架没有错,只是不总是对的。做快速原型,用 LangChain。做一套价值在于可审计、可控和安全保证的系统,自己写循环。大约 100 行,每一行你都能看懂。而且先把可观测性建起来——不是因为它好玩,而是因为它决定了你拥有的是一个能调试的 Agent,还是一个只能祈祷它能正常工作的 Agent。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.