☰
九个AI Agent协作:从零构建命令行编程助手
2026/10/20 4:01:19 网站建设 项目流程

最近有个念头在我脑子里转了很久:那些能在终端里直接听懂人话、自己翻代码、改文件、跑命令的商用命令行AI编程助手,底层到底是怎么串起来的?与其一直拿现成工具当黑盒用,不如亲自动手从零到一复刻一个。于是就有了这个项目——我用九个各司其职的AI Agent,搭出了一个完整的“命令行AI编程助手”雏形,我给它起了个内部代号:AgentNine。

这个项目解决的核心问题是:把“一个全能模型直接生成代码”的简单模式,升级成“多个专业Agent协作完成复杂任务”的系统模式。如果你也感兴趣多Agent编排、工具调用循环、上下文管理这些话题,或者想自己动手搭一套可扩展的AI开发工具,这篇完整复盘应该能帮你省下不少摸索时间。我会从架构设计、Agent分工、编排机制、实操代码、踩坑记录一条线讲下来,尽量把我试过、改过、最后留下的方案都写清楚。

1. 为什么要拆成九个Agent,而不是一个巨型提示词

1.1 单体提示词的瓶颈:能跑,但撑不住真实任务

最开始我确实尝试过用一个单体模型来做这件事:给一个很长的系统提示词,让它扮演“全能编程助手”,一次对话里既读代码、又改文件、还跑命令。简单任务确实能跑通,但一碰到稍微复杂一点的需求就露馅了。

问题出在三个地方。第一是上下文爆炸:一次流程里要包含文件内容、命令输出、测试报告、历史对话,全部堆在一个上下文窗口里,很快就把token预算吃光了。第二是职责混乱:同一个模型既要做规划又要做执行还要做审查,输出风格和思考路径经常互相干扰,一会儿像个工程师,一会儿像个测试员。第三是调试困难:流程跑挂了很难定位是理解错了、执行错了还是某个工具调用出了偏差,因为所有逻辑都揉在一个Prompt里。

所以我决定换个思路:把能力拆开,让每个环节都有独立的Agent负责,每个Agent只做一件小事但做到极致。

1.2 九个Agent的分工总览

拆分的依据不是拍脑袋,而是盯着“一个IDE里到底发生了什么”来拆。你让一个编程助手改代码,至少要经过:理解意图、制定计划、找代码、改代码、跑命令验证、写测试、审查质量、记住上下文、把结果展示给你——这正好对应九种不同的能力,也是九个Agent的由来。

编号Agent名称核心职责关键工具输入输出
1指挥官意图识别与任务分派意图分类器、路由表用户原始指令结构化任务描述
2规划者目标拆解与计划生成计划模板、依赖分析任务目标可执行的步骤计划
3检索者仓库理解与代码定位符号索引、全文搜索查询语义相关代码片段与文件路径
4编辑者文件读写与代码生成文件系统、Diff工具编辑指令变更后的文件与Diff
5执行者命令运行与日志分析沙箱Shell、超时控制Shell指令执行输出与退出码
6测试者测试用例生成与回归验证测试框架、覆盖率工具功能需求测试代码与运行结果
7审查者代码质量把关与Bug发现静态分析、审查Prompt代码Diff问题清单与修改建议
8记忆者上下文存储与摘要压缩向量库、摘要模型对话/操作记录结构化记忆
9展示者流式渲染与交互反馈终端渲染、流式输出事件流格式化界面输出

这个表单看起来很简单,但真正落地时每个Agent的内部结构都需要仔细设计,后面我会逐个讲。

1.3 协作模式:不是人人平等,而是主从加审计

多Agent系统最怕的是“人群讨论型”的组织方式——九个Agent平级对话,你一言我一语,最后谁也说服不了谁。我一开始就否掉了这个方案,采用的是一种更接近真实团队的模式:指挥官发起,规划者拆解,执行Agent干活,审查者把关,记忆者全程记录。

这种结构的核心是主从关系:指挥官是唯一的入口,所有用户指令必须经过它做意图分类;规划者是唯一的拆解器,任何Agent想改别人的计划都不被允许,只能通过反馈回路让规划者重新规划。审查者没有修改权限,只能提意见,修改权永远在编辑者手里。这像极了真实团队里的分工:架构师定方案,工程师改代码,测试提bug,项目经理排风险。好消息是Agent不会闹情绪,但坏消息是如果你不把权限边界定清楚,它们互相干扰起来比人还乱。

2. Agent基座:统一接口与工具注册机制

2.1 每个Agent的本质:角色提示词加工具集加消息循环

九个Agent形态各异,但底层抽象完全一致。每一个都是三件套组合:一段体系提示词定义它的角色和边界,一组可调用的工具决定它能干什么事,一个消息循环保证它在执行时能不断观察工具结果并调整下一步动作。

理解这个很重要。很多初学者会把Agent想象成某种魔法模型,其实本质上Agent = Prompt + Tools + Loop。模型本身不直接改文件,它只是决定“要调用哪个工具”;真正操作文件系统、运行Shell命令的是工具层。这种解耦设计让调试变得极其舒服——如果输出错了,先看是模型判断错了,还是工具执行错了,很容易二分定位。

2.2 统一Agent抽象代码骨架

为了让九个Agent写起来不重复,我先定义了一个最简基类。这个基类干三件事:管理上下文消息列表、执行工具调用循环、返回最终文本结果。用Python伪代码表示大概长这样:

class Agent: def __init__(self, name, system_prompt, tools, model): self.name = name self.system_prompt = system_prompt self.tools = tools # dict: 工具名 -> 工具函数 self.model = model self.messages = [{"role": "system", "content": system_prompt}] async def run(self, task, context=None): messages = self.messages.copy() if context: messages.append({"role": "user", "content": json.dumps(context, ensure_ascii=False)}) messages.append({"role": "user", "content": task}) while True: response = await self.model.respond(messages, tools=self.tools) if response.tool_calls: for call in response.tool_calls: result = await self.tools[call.name](**call.args) messages.append({ "role": "tool", "tool_call_id": call.id, "content": str(result)[:10000] }) continue final_text = response.text self.messages.append({"role": "assistant", "content": final_text}) return final_text

注意两个细节:工具结果被截断到10000字符,这是为了防止一次命令输出直接把上下文灌爆;消息循环里如果模型连续调用工具,我们必须在没有更多工具调用时才退出循环。

2.3 工具注册机制与权限控制

工具不是随便往里塞就完事,安全是第一优先级。我在工具注册阶段做了三层控制:白名单机制,没有注册的工具根本不存在;路径沙箱,文件读写强制限制在项目根目录内,绝对路径越界直接拒绝;命令拦截,执行Shell命令前会对命令文本做危险指令检测,比如递归删除、重定向覆盖关键文件、下载并执行外部脚本等。

权限这块我踩过坑,后面会专门讲。基座搭好之后,九个Agent就可以像插卡一样快速组装了。

3. 编排层:从“九个独立Agent”到“一个可用的系统”

3.1 编排器的核心职责

九个Agent如果全部独立运行,那不是一个系统,是九个互相不知道对方存在的孤岛。真正让它们产生化学反应的是编排器这一层。编排器要做三件核心的事:流程调度决定当前该跑哪个Agent、按什么顺序跑;消息路由决定上下文该传给谁,哪些信息要保留;状态管理记录整个任务的进行到哪一步,异常时能恢复到最近可用状态。

我画了一条最基础的工作流主线:用户输入 → 指挥官分类 → 规划者定计划 → 对每个计划步骤执行“检索→编辑→执行→测试”循环 → 全部完成后审查者验收 → 展示者输出。这有点像一个流水线,但每个环节都可能产生反馈回路,比如审查者发现Bug,会重新触发规划者生成修复任务。

3.2 状态机与工作流流转

编排器内部我用了一个简单的状态机来管理流程。状态包括:INIT、PLANNING、EXECUTING、VERIFYING、REVIEWING、DONE、FAILED。每个状态对应一个Agent或者一组Agent的执行入口。状态机的好处是流程永远可控,不会出现Agent自发乱跳的情况。

from enum import Enum class WorkflowState(Enum): INIT = "init" PLANNING = "planning" EXECUTING = "executing" VERIFYING = "verifying" REVIEWING = "reviewing" DONE = "done" FAILED = "failed" class Orchestrator: def __init__(self, agents): self.agents = agents self.state = WorkflowState.INIT self.plan = [] self.results = {} async def start(self, user_input): task = await self.agents["commander"].run(user_input) self.state = WorkflowState.PLANNING self.plan = await self.agents["planner"].run(task) for step in self.plan["steps"]: self.state = WorkflowState.EXECUTING await self._execute_step(step) self.state = WorkflowState.REVIEWING issues = await self.agents["reviewer"].run(self.results) self.state = WorkflowState.DONE if not issues else WorkflowState.FAILED return self.results

这个代码骨架简单,但它已经能支撑一次完整的任务闭环。我在真实实现里增加了断点持久化,把状态机快照写到本地文件,这样进程崩溃后还能恢复继续跑,而不是从头再来。

3.3 上下文路由:哪些信息该传给谁

上下文路由是编排器里最容易忽略也最容易出问题的地方。每个Agent的上下文都应该只包含它完成当前任务所需的最小集合。检索者只需要拿到查询语句,不需要拿到全量Git日志;编辑者只需要拿到要改的文件路径和检索者提供的代码片段,不需要拿测试报告全文;审查者反而要拿全部Diff和测试结果。

一开始我没做精细化路由,所有上下文全局转发,结果就是每个Agent都被海量无关信息污染,输出质量急剧下降。后来改成按需路由,每个Agent在编排器注册时声明自己需要哪些上下文键,编排器只把对应的值塞给它。这个改动让整体准确率提升了一个台阶。

4. 九个Agent的分工设计与实现细节

4.1 指挥官Agent:意图识别与任务分派

指挥官是用户和系统之间的第一道门。它的任务不是直接解决问题,而是把用户含糊的一句话转成一个结构化任务描述。比如用户说“这个项目跑不起来”,指挥官不能立刻去改代码,它要先判断:是环境问题、启动配置问题还是代码Bug?是需要诊断还是直接修复?

我的做法是让指挥官输出一个JSON结构,包含任务类型、目标描述、涉及模块的可选字段、优先级和约束条件。这个JSON是后续所有Agent的输入基准。为了让指挥官靠谱,它在调用模型之前会先做一次本地预处理:把用户输入和项目根目录的README、配置文件列表一起提供给模型做参考。实测下来,提前给一点项目背景,指挥官的判断准确率会高很多。

4.2 规划Agent:目标拆解与计划生成

规划者接到的输入是指挥官的任务JSON,输出是一份有序的执行计划。计划里的每个步骤都必须是原子操作,比如“读取user_service.py”“把第48行到第73行重构为异步实现”“运行go test ./internal/user”。原子操作的意义在于它可以直接被后续的Agent执行,不需要再做理解。

规划者内部挂了一套计划模板库,针对常见任务类型预置骨架。比如“重构”任务,模板是:全量检索结构 → 识别耦合点 → 逐个模块改写 → 跑测试 → 全量回归。“Bug修复”任务,模板是:定位错误日志 → 追踪调用链 → 复现现场 → 修复 → 补测试。预置模板不是为了省事,是给模型一个思维脚手架,避免规划时漏掉关键步骤。

4.3 检索Agent:仓库理解与符号定位

检索者专门解决“代码在哪儿”的问题。它有三个杀手锏工具:符号索引表会在项目初始化时扫描全部代码文件,提取函数名、类名、全局变量名并建立倒排索引;全文搜索用关键词模糊匹配所有文件内容;文件摘要缓存会在第一次读取大文件时生成摘要并缓存,避免后面反复读同一份大文件浪费token。

检索者的输出格式很严格,必须是文件路径加行号范围加代码摘要,不允许直接输出大段代码。这是为了避免编辑者拿到过量的代码块后“自我发挥”。我见过最典型的路径是:检索者把整个文件复制给编辑者,编辑者基于文件末尾上下文误删了前面的逻辑。所以检索者只定位,不搬运。

4.4 编辑Agent:文件读写与代码生成

编辑者是最容易出事的Agent,因为代码写错带来的破坏是直接且难以自动恢复的。我给它设计了极强的约束:只能基于检索者提供的真实代码片段进行修改,禁止凭空生成文件路径;修改前必须先生成Diff预览;所有写入操作强制走文件锁。

文件锁是我在踩了坑之后加的。一开始没有锁,测试Agent和编辑Agent如果同时改同一个文件,后写的人会把先写的覆盖掉。现在这个锁很简单,就是一个进程内的写队列,编辑者获取锁之后才能写文件,而且写文件前要再次校验目标文件的当前哈希值跟读取时一致,不一致就说明文件被别人动过,自动放弃这次写入。这个机制看着保守,但它在真实协作里避免了大量互相踩踏的问题。

4.5 执行Agent:命令运行与日志分析

执行者负责跑命令。它的工具层包了一个沙箱Shell,核心配置是:命令白名单只允许运行项目开发中常见的命令,比如npm install、go build、go test、python -m pytest、git status之类;超时控制每条命令默认60秒超时,超时直接杀死进程树;工作目录锁定所有命令在项目根目录下运行,禁止cd到项目外。

执行者拿到命令后不会盲目执行,它会先检查命令是否匹配白名单,再检查参数中是否有危险模式。比如“rm -rf /”“curl xxx | sh”这种直接拒绝执行。执行结束后执行者会把标准输出、标准错误、退出码统一结构化返回,尤其是退出码,编排器用它来判断当前步骤是否成功。日志分析则交给执行者内置的一段小Prompt:让它从输出里提取关键错误行,而不是把全部日志塞给下游。

4.6 测试Agent:用例生成与回归验证

测试者在整个链条里的位置很容易被低估。我的经验是,测试Agent不是可有可无的“锦上添花”,它是整个系统能否自纠错的关键。没有它,编辑者改完代码后系统没法判断改对了没有。

测试者的流程是这样的:拿到功能的变更描述和Diff后,先生成针对性的测试用例,尽量覆盖正常路径和边界条件;然后调用执行者跑测试;如果测试失败,它会整理失败信息并附上自己的根因分析,打回给规划者重新生成修复计划。这个过程会循环,直到测试通过或者达到最大重试次数。

这里有个细节:测试者生成的测试代码也会写入项目里,但它写入时同样要走文件锁和Diff预览,而且它跑测试前会把项目恢复到干净状态,避免上一个失败测试留下的临时文件影响结果。

4.7 审查Agent:质量把关与Bug发现

审查者是一个只读Agent,它永远没有修改权。它的输入是本次任务的全部代码Diff和执行测试结果,输出是问题清单,每条问题包含严重等级、位置、问题描述和修改建议。不直接改代码,这个定位是故意的——如果审查者也能改代码,那它和编辑者的权限边界就糊了,容易出现两边互相覆盖。

审查者内置了一套检查清单:是否引入语法错误、是否泄漏了敏感信息、是否忽略了错误处理、是否有明显的性能隐患、代码风格是否与项目现有风格一致。它不是静态分析工具,而是让模型在完整Diff上下文中做推理,效果比我预想的好很多。它逮到过好几次我在重构时忽略的返回值错误和边界条件问题。

4.8 记忆Agent:上下文存储与摘要压缩

记忆者可能是这九个Agent里最“隐形”但最影响体验的一个。它的任务就是时刻盯着上下文开销。每个Agent的上下文长度不是无限的,跑几轮工具调用之后可能就逼近模型的token上限了。

记忆者做的事情有两件:一是长期记忆,把项目结构摘要、之前的决策记录、已经完成的步骤存到结构化文件里,跨会话时还可以恢复;二是短期压缩,当一个Agent的消息列表超过阈值时,它会调用摘要模型把早期对话压缩成一小段“任务历史摘要”,替换掉原始对话记录。这个设计彻底解决了长任务跑着跑着上下文爆掉的问题,代价是早期细节可能被摘要丢失,但对于大多数开发任务来说,保留结论比保留全部讨论过程更重要。

4.9 展示Agent:流式渲染与交互反馈

最后一个是展示者,它负责把系统内部的动态实时呈现给用户。它与前面的Agent不同,它本身不调用模型做推理,更像一个格式化渲染器。它从编排器订阅事件流,把“规划完成”“正在编辑文件xx”“命令执行中”“测试失败,正在重试”等状态转换成终端里的友好输出。

展示者的存在不是为了好看,它其实解决了多Agent系统的一个重要问题:可感知性。如果用户等十几秒屏幕上毫无反馈,他大概率会以为程序卡死了。把内部流程可视化之后,用户能清楚地看到当前在进行哪一步、卡在哪一步,体验提升非常明显。我在实现时给了它两个模式:详细模式展示所有Agent的动态,简洁模式只展示关键节点。

5. 实操中的坑与常见问题排查

5.1 多个Agent同时改一个文件导致互相覆盖

这是整个项目中最折磨人的问题,没有之一。症状是:编辑者刚改完一个函数,测试者跑的测试里却看不到那个改动;或者审查者看到的最新代码里混着两个不同版本的重复逻辑。根因是多个Agent没有统一的写入仲裁。

我的解决方案在前面提到过,就是文件级写锁加哈希校验。任何Agent写文件之前必须拿到写锁,写之前还要重新读文件哈希,如果不匹配就放弃写入,把这个情况上报给编排器,由编排器决定是否重新加载最新内容再重试。这个方案没把并发效率做到最高,但它保证了正确性。在多Agent协作里,正确性永远排第一,效率往后放。

5.2 上下文无限增长导致token超限

跑一条大任务,比如让系统把整个项目从一个语言重写到另一个语言,中间会产生大量的中间结果。如果不做压缩,到中途就会碰到上下文上限,任务直接报错。

我的解决思路分三层:首先是局部截断,每次工具调用的返回结果最多保留10000字符,超出部分截断;然后是摘要压缩,记忆者会定期把早期消息折叠成摘要;最后是分段执行,规划者把大任务拆成多个独立小步骤,每个步骤完成后及时把上下文累积清空,只保留必要的结论信息。这三层加在一起,实测一个重构任务从头跑到尾,每个Agent的最大上下文占用只有初始设计的40%左右。

5.3 Shell命令失控

有些命令运行起来会一直挂着不退出,比如启动一个开发服务器、运行一个会监听端口的程序、执行一个等待用户输入的脚本。如果执行者不设超时,整个编排流程就会被永远卡死。

我在沙箱Shell里给每条命令都加了默认60秒的超时,超时后直接发送终止信号给进程组,确保子进程也不残留。另外对明显是“长驻进程”的命令,比如server、watch、dev这类命令,编排器会提示执行者改用短时验证模式,比如启动后在几秒内检测端口是否监听成功,然后立刻退出,而不是傻等着。

症状根因排查思路实际修复方案
两个Agent改同一文件互相覆盖缺少写入仲裁检查对同一文件的写时间线加文件级写锁和哈希校验
任务跑到一半上下文超限上下文累积无压缩监测消息长度增长曲线记忆者做摘要压缩加截断
命令长时间无响应长驻进程或等待输入检查执行者日志中的卡点命令Shell层加超时与进程组清理
编辑者改出语法错误基于幻觉代码写入对比编辑内容与检索结果的吻合度强制基于真实代码片段修改
审查者反复提无意义问题上下文缺少任务目标检查审查者收到的上下文包含哪些字段路由时携带完整任务目标

5.4 模型幻觉“读到”不存在的代码

这是最隐蔽的坑。检索者本来应该读某个文件并把真实内容传给编辑者,但模型在输出工具调用结果时可能因为上下文不完整或者自身幻觉,凭空脑补出一些“看起来合理”但根本不存在的代码。编辑者基于这些幻觉代码修改文件,结果引入了大量不存在的符号引用。

我后来强制规定检索者必须返回文件路径、行号、以及从文件系统真实读取的内容片段,并且这些内容必须经过工具层记录确认。编辑者在写入前也会做一次校验:如果修改引用了某个函数或变量,但这个符号不存在于项目源码中,编辑者要主动标记“该符号未找到”,不能硬写。

5.5 常见问题速查表

上面几个问题只是高频踩坑的代表。我把实际项目里遇到过的典型问题整理成了速查表,方便你搭建同类系统时直接对照参考。这些问题的共性是:它们都不是模型能力不够,而是系统设计上缺少约束。多Agent系统的稳定,本质是靠机制兜底,不靠模型自觉。

6. 一次完整实测:把项目从Python重构到Go

光说不练没有说服力。我挑一次最完整的实测过程来讲。任务很简单一句话:“把模拟项目X的核心模块从Python重构成Go,保留原有接口含义。”

指挥官先把这句话解析成任务JSON,任务类型是“重构”,目标是核心模块,约束条件是“保留接口语义”。规划者基于重构模板生成了七步计划:盘点Python源码结构 → 梳理模块间依赖 → 按依赖顺序翻译核心逻辑 → 生成Go模块骨架 → 编写对应测试 → 运行编译与测试 → 全量审查回归。

检索者开始干活,它返回了整个项目的目录树和核心模块的函数签名清单,标注了哪些函数是外部调用入口。编辑者先建了Go模块目录,然后按依赖顺序逐个文件翻译。执行者跑go build时第一次报错,原因是某个工具函数的参数顺序在翻译时颠倒了。测试者补了两个边界用例后跑出失败,审查者顺着失败链定位到一个goroutine泄漏的隐患。

这条链路让我最满意的地方是:没有一个Agent需要被“提醒”下一步做什么。规划者给的是原子化指令,执行Agent天然知道下一步是验证还是修订。整个过程大概持续了六分钟,中间模型调用了一百多次工具,最后输出的代码通过了我额外准备的一轮人工Review。虽然离商用工具还有距离,但对一个从零搭的系统来说,已经达到能实际用的水准。


做完这个项目,我个人最大的体会是:单个Agent的能力取决于模型,系统级Agent的能力取决于编排。九个Agent放在那里并不会自动产生智能,真正起作用的是它们之间的分工边界、权限控制和反馈回路。如果你也想自己搭一套多Agent系统,我的建议是先不要追求Agent数量多,把指挥官、规划者、审查者这三个核心角色跑通,再加执行类和工具类Agent,这样每加一个角色都能明显感受到系统能力的边界在往外扩一点。

最后分享一个我在做记忆Agent时的取舍心得:很多人一提到记忆系统就往向量库里钻,但对命令行编程助手这个场景,文本摘要就够用了,反而轻量可靠。嵌入检索的成本和复杂度未必换来对应的效果提升,先想清楚你的上下文里到底什么信息需要被长期精确查找,再决定要不要上向量库。这个判断原则,放在整套Agent架构设计里也一样成立。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询