ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI编码助手从问答到任务执行:羲和Agent架构设计与落地实践

AI编码助手从问答到任务执行:羲和Agent架构设计与落地实践 接手这个项目之前我一直有个疑惑AI编码助手到底能走多远市面上的工具大多还在“问答”阶段——你问它一段代码怎么读、某个bug怎么修它给你一段文字回复然后你自己动手改。这当然是价值但远远不够。真正的提效是让AI从“告诉你答案”变成“直接帮你把活干完”。于是就有了羲和XiheAgent。它不是一个普通的对话式编码助手而是一个把“代码问答”升级成“任务执行”的AI Agent。你告诉它“修复这个bug并跑通回归”它不只是给出修复建议而是真的去读代码、改文件、执行构建、触发调度甚至在任务执行失败时把告警推送到企业微信。这篇文章我完整梳理一下它的设计与实现不整虚的从架构决策到落地代码再到我踩过的坑一次性说清楚。1. 为什么AI编码助手只会“说”不会“做”项目要解决的核心痛点先聊聊出发点。做了快三年的编码工具我越来越强烈地感觉到纯问答式的AI助手其实处于一个很尴尬的位置。它像是一个“围观的聪明人”——什么都知道但手插在兜里什么都替你干不了。而真实开发场景里大家要的不是建议是“事情被解决”。1.1 现有编码助手的普遍能力边界市面上的AI编程工具典型的交互路径是这样用户提问“这段函数是做什么的”模型回答解释代码逻辑分析入参出参。用户提问“帮我写一个解析JSON的Python函数。”模型回答生成一段代码用户复制粘贴到自己项目里。这些场景都有一个共同点产出物是文字。文字是建议不是结果。遇到小需求还行遇到稍微复杂的任务——比如“重构某一个模块并跑通所有测试”——问答式工具就失效了。因为这类任务不是一个函数能解决的它需要的是一连串动作定位代码、分析依赖、修改文件、执行测试、修复回归、可能需要触发远程构建每一步都可能失败失败之后要看日志、调整策略、再跑一轮。这一连串动作纯靠问答是描述不完的。你总不能把每次交互都变成大型Copy-Paste现场。真正有用的编码助手应该是能“亲自动手”的它读完代码之后自己打开文件、自己改、自己跑命令、自己看结果。1.2 从“问答”到“执行”改变的到底是什么一句话从输出信息变成输出结果。问答式助手的逻辑是“我把答案给你你自己动手”执行式助手的逻辑是“你给我目标我拆解、执行、验证最后给你一个可用的结果”。后者需要补上一整套工程能力目标拆解把用户一句模糊的话“帮我优化一下这个接口的耗时”拆成可执行的任务列表。工具调用让LLM不仅能“说”还能实际调用读文件、改文件、执行测试等工具。过程反馈执行过程中每一步都可能失败Agent需要读取失败信息并调整方案而不是像一次性的问答一样答完就结束。外部系统集成执行任务可能需要触发DolphinScheduler这样的调度引擎去跑一个工作流失败之后还要通过企业微信通知到人。羲和就是要补上这些能力。它的核心技术目标不是做一个更聪明的模型而是做一个更“手脚麻利”的Agent。它把模型当大脑把工具集当手把调度系统当执行车间把企微机器人当警报器四者串成一个完整闭环。1.3 哪些人需要这样一套东西我做了几轮访谈发现需求最强烈的有三类人中小团队的开发骨干人少活多大量重复性任务修编译错误、跑回归、处理告警占据时间。这类任务高度标准化正是Agent擅长的。QA/DevOps工程师他们经常要面对“某条流水线挂了帮我看一下”这种模糊指令。Agent如果能自动拉日志、判断失败原因、调参重试能省掉大量机械排查时间。开源项目维护者要处理很多PR的编译检查、依赖升级验证这些流程固定、判断标准明确天然适合自动化执行。这是羲和设计的起点不是做一个“替你写诗”的AI而是做一个“替你干活”的同事。2. 羲和的整体架构从会话理解到任务执行的闭环设计现在讲架构。这个项目里我做的第一个关键决策就是放弃传统插件式设计直接用Agent架构。这里有个很重要的取舍我说一下为什么。2.1 为什么选择Agent架构而不是普通IDE插件传统IDE插件处理命令是“硬编码”的。比如用户点击“格式化代码”插件就执行固定的格式化流程。它的逻辑链是死的用户动作 - 回调函数 - 工具调用 - 完成。这样的设计稳定但没有任何智能性无法处理开放性任务。Agent架构不一样。它的逻辑链是“软编码”的用户目标 - LLM理解 - 生成行动计划 - 逐个调用工具 - 观察结果 - 修正计划 - 最终完成这个闭环结构来自经典的ReAct模式“感知-决策-执行-反馈”的循环。它的核心优势在于每一步决策都是由当前实际输出决定的。比如计划第一步是“读取pom.xml”结果发现这个文件不存在Agent不会像死脚本一样报错退出它会重新规划找一下有没有build.gradle或者看看项目根目录下有什么构建文件。这种灵活性是普通插件给不了的。缺点也很明显多了一层不确定性。LLM的输出是概率性的不能保证每一步都对所以架构上必须设计好容错机制。2.2 五大核心模块羲和的整体架构我拆成了五个模块各司其职会话理解层负责把用户自然语言输入转成结构化需求。这里不只是简单的意图分类还要做参数抽取。比如用户说“把用户模块的单元测试跑一遍”这里要抽出来的参数包括目标模块是“user”动作是“run_test”范围是“unit”。如果参数不全这一层要主动反问而不是瞎猜。任务规划层这是Agent的“大脑”。它拿到结构化需求后结合当前工具列表和项目上下文生成一份带顺序的任务清单。比如“修复编译错误”这个目标拆出来的任务可能是先读pom.xml - 检查maven依赖树 - 定位冲突坐标 - 修改版本号 - 执行编译 - 确认编译通过。规划层还会评估任务间的依赖关系能并行的并行不能并行的串行。工具执行层一个统一的工具调用框架。所有工具都是“注册式”接入的定义好名称、描述、参数Schema之后LLM就能基于描述动态调用。工具分两类一类是原子工具读文件、写文件、执行命令一类是聚合工具执行测试套件、触发远程构建、分发调度任务。反馈汇聚层把每个工具的执行结果stdout输出、退出码、文件变更收集起来转成LLM可以继续决策的上下文。这一层很关键因为LLM的上下文窗口有限不能把整个日志倒进去需要提取关键信息——比如编译错误中的Exception信息、测试失败的具体用例。外部集成层连接DolphinScheduler、企业微信机器人等外部系统。这层把Agent从“单机工具”扩展成“云端执行引擎”任务可以分发到调度集群告警可以推送到IM。五个模块的交互流程是这样的用户输入 - 会话理解 - 任务规划 - 工具执行 - 反馈汇聚 ^ | |_____ 循环 ____| 结果 - 外部集成调度/告警这里的每一次循环都相当于Agent在执行过程中“看一眼结果、想一想下一步”。架构的价值在于把不确定性分散到每个环节去处理而不是让模型一口气生成一个从开头到结尾的固定脚本。一口气生成固定脚本的问题在于——太脆弱了任何一步环境变化都会翻车。2.3 工具设计参数Schema是第一道防线工具层是最容易出问题的地儿尤其是从LLM调用的角度来说。LLM对“工具参数”经常有幻觉会传一些不存在的路径、错的参数名。所以我在这块上加了两道防线。第一道是Schema严格约束。每个工具定义成标准JSON Schema里面会标清楚哪些参数是必填的、有哪些枚举值、参数类型是什么。比如“读取文件”这个工具{ name: read_file, description: 读取项目中的文件内容常用于定位代码上下文, parameters: { type: object, properties: { path: { type: string, description: 文件的相对或绝对路径, required: true }, encoding: { type: string, enum: [utf-8, gbk, latin-1], default: utf-8 } } } }有了这个定义LLM就知道必须传“path”参数而且“encoding”只能从三个枚举值里选。这比让它自由发挥稳得多。第二道是执行前校验。就算LLM传了参数工具执行器也会先做一轮程序化校验文件是否存在、路径是否越界、目标分支是否是保护分支。校验不通过就直接拒绝并且把拒绝原因返回给LLM让它重新规划。这套机制配合下来至少能过滤掉80%以上的参数幻觉问题。3. 落地实录一次bug修复任务如何从问答升级到执行架构聊完上点实在的。我挑一个我在开发过程中反复测试的场景项目里spring-boot版本回退后编译报错让羲和帮忙修复并跑通编译。3.1 任务输入与初始拆解用户输入一句话“我把spring-boot从3.2.0回退到2.7.18现在一编译就报错帮我修一下并确认能编译通过。”这句话在传统问答式工具里最好的结果就是查一查常见错误列表给你一段“你需要检查xxx依赖”的文字建议。但在羲和里它会变成一系列真实动作。会话理解层先把这句话转成结构化目标意图fix_build_error 目标范围maven-compile 约束保证编译通过任务规划层接着拆解行动计划。模型参考的是我预置好的“构建修复”提示词模板里面规范了处理这类问题的标准路径。基于模板LLM输出一份计划1. 读取项目根目录pom.xml确认spring-boot版本和所有依赖manage条目 2. 执行 mvn -DskipTests compile捕获完整错误输出 3. 根据错误日志检查定位到具体冲突依赖 4. 分析冲突坐标通常是某个依赖引用了spring-boot 3.x的传递依赖 5. 修改pom.xml或对应模块配置 6. 重新执行 mvn -DskipTests compile 验证 7. 如果通过输出变更摘要等待用户确认看这个计划总共七步。前两步是“侦察”三步四步是“定位”五六七步是“修复与验证”。这个顺序符合真实的Debug流程先拿到一手报错再谈修法。3.2 工具调用链与中间失败处理计划定了之后Agent开始逐项执行。这里有一个关键点“执行计划”不是死板地从头走到尾每一步的结果都在影响下一步的判断。比如第三步编译错误日志中有时候不是依赖冲突而是某个类里import了不存在的方法。两种情况的处理路径完全不同前者要改pom后者要改Java代码。Agent必须“读懂”错误日志再决定走哪条分支。工具调用链大体长这样read_file(pom.xml) - execute_command(mvn -DskipTests compile) - grep_log(BUILD FAILURE, ERROR) - redirect: 根据错误类型选择分支 - execute_command(mvn dependency:tree -Dincludes...) - edit_file(pom.xml, spring-boot-version 回退后调整xx依赖版本) - execute_command(mvn -DskipTests compile) - 验证通过输出结果中间出现过一个很经典的坑第一次编译失败的原因不仅仅是版本冲突还有一个低版本的Spring Boot不兼容JDK 21的编译参数maven-compiler-plugin的release版本设置。Agent按照计划只关注pom版本改完再编译还是报错。这时候就是反馈链接力的体现——第二次失败日志进入上下文LLM判断出“不是版本选择问题是编译参数问题”于是调整计划去改maven-compiler-plugin的source/target配置。它能“拐弯”这是我们设计时最想要的效果。这里我建议所有做Agent的朋友一定要给“计划执行”加一个最大迭代次数限制。我用的是10次循环超过就停止并向用户汇报当前状态防止Agent在某个错误上无限较劲。3.3 权限控制与操作边界让AI直接改代码文件是有风险的。我在设计里做了一个分级权限模型低风险操作读文件、执行只读查询命令直接放行。中风险操作修改代码文件、执行本地测试放行但是记录变更最终输出时列出diff。高风险操作修改保护分支、执行发布命令、操作生产环境数据一律强制要求用户确认人工审批。实际实现里高风险操作会触发一个“悬停审批”流程Agent把待执行命令和影响范围发给用户等用户确认后才继续。这个机制在演示时可能显得有点“啰嗦”但在真实业务里是救命稻草。有一次跑测试时Agent差点自动执行了git push --force被审批拦截下来那真是幸免于“删库跑路”。4. 接进工程调度链与DolphinScheduler联动实现任务编排单机执行跑通之后我意识到一个更大的问题真正有价值的任务往往不是在开发者的笔记本上跑而是要在分布式调度集群里跑。比如“跑全量回归测试”“定时扫描仓库敏感信息”“凌晨批量刷新依赖版本”。这些都不是一个Agent进程能独立完成的需要一个成熟的调度引擎托底。4.1 为什么需要DolphinScheduler选型的时候我对比了几种方案直接写Cron定时任务不灵活任务依赖一多就乱用GitLab CI只能吃Push事件没法处理Agent的动态调度需求自己写一个任务队列成本太高。最后选了Apache DolphinScheduler原因是三点工作流支持DAG编排任务之间的串并行关系跑批、回归、告警天然是依赖关系DAG表达力足够。有完善的运维面板可以直观看到哪个节点失败日志怎么查调度器本身有没有跑挂。有开放API这样Agent才能通过HTTP接口动态创建工作流、触发执行、查询状态这才是“AI驱动调度”的关键。DolphinScheduler在团队里不是所有人的电脑上都装了但它是运维侧的主战场。Agent没有能力也不需要替代它而是要成为它的“超级指挥官”——由Agent来定义工作流内容、触发时机和失败后的处理由DolphinScheduler来稳定执行和调度。4.2 工作流设计与动态创建为了让Agent能把“任务计划”落成“调度工作流”我设计了一个转换步骤。Agent规划层输出的任务清单会经过一个Python转换器变成DolphinScheduler工作流定义的JSON结构。举个例子用户让羲和“每晚自动跑一次所有模块的单元测试重点模块跑集成测试失败了就通知开发群”。转换出来的工作流会是这样工作流名称: nightly-test-verify 节点: A: module-a-unit-test B: module-b-unit-test C: module-c-integration-test (由DolphinScheduler的任务节点类型定义这里用SHELL节点) D: report-aggregator 依赖: A、B、C 并行全部完成后进入 D 失败策略: 任一节点失败触发企微告警具体落地时用DolphinScheduler的API来创建# 以创作者视角标记流程定义触发一次工作流执行 curl -X POST http://ds-server:12345/dolphinscheduler/projects/1/executors/start-process-instance \ -H token: xxx \ -d { processDefinitionCode: 10001, scheduleTime: 2024-06-01 00:00:00, failureStrategy: CONTINUE, warningType: FAILURE, warningGroupId: 2 }注意这里的warningTypeFAILURE——它会让DolphinScheduler在任务节点失败时推一条执行失败详情给到配置好的告警组。但实际用起来我发现DolphinScheduler自带告警通道的模板偏“机器味”消息里只有任务名、状态、时间开发没法一眼看出失败原因这也是后面我坚持走企微机器人自定义告警模板的原因。4.3 任务执行的完整链路一次任务的完整链路在接进DolphinScheduler之后变成这样用户一句话 - Agent拆解 - 转换器生成DolphinScheduler工作流 - 创建流程并触发 - DolphinScheduler调度到worker执行节点任务 - 每一节点执行完成/失败 - 通过API回调结果给Agent - Agent汇总结果 - 成功则输出报告失败则拉取工作流状态并触发企微告警这个环节里我最开始只把DolphinScheduler当“作业执行器”成败都靠轮询它的API查看状态。后来发现轮询有延迟而且偶尔会有状态不同步的问题Worker节点日志已经失败了但API还在显示RUNNING。于是改成双通道确认DolphinScheduler侧走自带的告警回调Agent侧主动查询一次状态。两边信息合并才得到可靠的执行结果。4.4 与Agent结合的工作流模板我预置了几个高频的工作流模板Agent拉出来改参数直接用模板名称典型场景主要节点ci-verify提交前验证编译 - 单元测试 - 静态扫描nightly-regression夜间回归各模块测试并行 - 汇总报告dependency-audit依赖安全巡检拉取依赖清单 - 比对漏洞库 - 生成报告release-pipeline发布前校验编译 - 集成测试 - 打镜像 - 触发部署这些模板的价值是减少Agent和底层系统的认知落差。模型不需要记住DolphinScheduler的复杂API只需要理解“我这有个编译验证的任务要用ci-verify模板”就足够了。剩下的参数拼装和API调用全部由转换器完成。5. 任务失败不再静默企业微信告警的接入与调优任务执行做得再稳总有失败的时候。真正折磨人的不是任务失败而是任务悄悄失败、直到第二天用户来问“昨晚的跑批怎么没出数”。所以告警是整个设计里必须补齐的一环。我这边的选择是企业微信机器人理由很简单团队全员都挂企微触达率最高不需要额外装东西。5.1 企微机器人Webhook接入企业微信群机器人支持Webhook往指定URL POST一条JSON就能发消息到群里。不需要申请服务端API权限个人也能配置非常轻量。import json import requests def send_wechat_alert(title: str, content: str, webhook_url: str): payload { msgtype: markdown, markdown: { content: f## {title}\n{content} } } resp requests.post(webhook_url, jsonpayload, timeout10) resp.raise_for_status()这一段代码就是最基础的告警封装。但只到这一步还不够你需要考虑的是告警内容长什么样才算真正的告警我的标准是群里的同学看到消息后不需要再去翻系统就知道发生了什么、影响范围是什么、接下来该找谁。5.2 告警消息模板设计我在实际处理时把告警消息设计成三段式第一段是危险信号第二段是失败上下文第三段是处理建议。用Markdown格式在企微里显示效果很清楚{ msgtype: markdown, markdown: { content: **任务执行失败告警**\n 工作流: font color\warning\nightly-regression/font\n 节点: module-b-unit-test\n 失败原因: 请求\n 执行ID: 20240601-180001\n 错误日志摘要: java.lang.NoSuchMethodError: org.springframework.util.Assert.notNull(Ljava/lang/Object;Ljava/util/function/Supplier;)V\n 处理建议: 优先检查 module-b 的依赖版本是否与Spring Boot 2.7.18冲突a href\http://logs.xxx.com/20240601-180001\查看完整日志/a } }注意我加了两个细节错误日志摘要和处理建议。这是“AI编码助手”和“普通监控告警”的分水岭。普通监控只会把堆栈第一行贴给你而羲和在告警出来之前就已经让Agent分析过失败原因了。为了让分析尽量准确我把Agent合并失败日志做了一层“梗概提取”只保留异常类型、错误信息、首个非框架堆栈以及从最近几天成功执行对比出的配置差异。这些信息拼进告警模板排查效率会明显提升。5.3 告警不是越多越好防告警风暴告警接到企微之后下一个问题来了失败重试机制和告警会互相“打架”。我举个例子工作流某个节点失败Agent自动重试了3次如果每次失败都发一条告警一个问题的重试就能让企微消息刷屏。这在凌晨两三点尤其让人崩溃——开发看一眼手机发现群里被同一个错误刷了5条消息直接想把机器人禁言。我用了三个策略来压住告警风暴重试告警不重复发同一个执行ID的失败事件在重试间隔内只发一条初始告警后续重试只更新消息内容不新增消息。静默窗口同一个错误被重复触发超过3次时进入30分钟静默窗口改为每10分钟聚合输出一条“同一错误已重复N次”的消息。级别区分核心失败发布、回归直接开发边缘失败非关键路线的测试超时只发提醒不艾特任何人。这些策略组合之后企微群的告警量下降了70%以上而且信息密度反而变高了——每一条出现在群里的消息都值得人点开看一眼。5.4 执行失败回调的幂等设计还有一个很容易被忽略的细节告警发送要保证幂等。DolphinScheduler失败回调有时会触发多次比如网络抖动导致Webhook发了两次。如果不做幂等同一条失败信息会重复推送多次。我这边用一个简单方案每条告警生成一个唯一ID用执行ID节点ID拼接在Redis里存一份带TTL的记录比如24小时。每次收到失败回调先检查Redis如果已经发送过就直接忽略。def send_if_not_duplicated(alert_id, title, content): if redis_client.setnx(falert:{alert_id}, 1, ex86400): send_wechat_alert(title, content, WEBHOOK_URL) else: logger.info(f重复告警被拦截: {alert_id})这个细节看起来不大但它是告警系统稳定性的基石。没有这种保护凌晨的一次网络抖动就可能导致“告警机器人被全员屏蔽”。6. 踩坑合集常见问题与排查技巧实录好最后一个章节照例是踩坑合集。没做过的人想象不到这个项目看起来不复杂实际上我遇到的坑比想象中的多得多。下面这些问题是高频出现的每一条都附了排查思路和我的解法。6.1 LLM幻觉参数Nine成工具调用问题的根源最典型的坑就是模型“编参数”。它明明应该调用read_file却传了一个项目里根本不存在的路径src/commons/util/helper.py。这种情况不是偶发在长上下文的Agent循环中相当常见——模型前面读了一堆文件就开始“想象”其他文件也存在于某个路径。我的排查思路先确认模型用的是哪个版本的Prompt再看温度参数是不是调太高了。我的经验是Agent场景下温度设在0.1到0.3比较稳设置成0.7以上就会开始“自由发挥”各种编造工具参数。解决方式分三层Schema强约束参数加required和enum模型输出前先在本地做一轮校验。重试机制校验失败时把“参数错误”信息喂回给模型让它重新生成工具调用“重新编一次”往往命中率更高。路径白名单对文件操作类工具先扫描项目真实文件列表把可选路径喂给模型而不是让它凭空想。我最常用的还是第三层。让LLM从选项里挑而不是凭空写。这跟人类一样选择题永远比填空题靠谱。6.2 任务执行超时长任务卡死的处理第二个高频问题Agent在执行一个耗时很长的任务比如跑全部测试时会“卡住”。表面上是卡住实际原因通常是工具执行等不到输出LLM没有收到反馈于是就不继续了。这个问题我吃了好几次亏。排查时先把Agent循环日志打开发现工具早就执行完了但是结果没有被当成“下一步触发信号”。原因是执行层是同步阻塞的测试要跑五分钟线程干等着一旦测试进程被内核挂了整个链路就断了。解法是加异步任务 超时控制工具执行时间超过30秒 - 任务标记为“后台执行” Agent从同步等待切换到轮询状态 每5秒查一次状态超过最大超时如15分钟则判定失败并终止这个改造虽然增加了一些代码量但带来的好处很明显Agent的执行从“串联模式”变成“轻微异步模式”能同时观察多个任务的进度不至于因为一个慢任务把整个对话流程卡死。试过两次就离不开了。现在Agent在处理测试、构建这类长任务时日志里会清晰出现“已切换为异步跟踪任务ID xxx”的节点这在排查问题时非常有用。6.3 DolphinScheduler集成时的状态同步坑DolphinScheduler的API在版本演进上有一些不兼容——不同版本返回的JSON结构不完全一样有的版本字段叫taskInstances有的叫taskList还有的在API响应里封装了嵌套结构。我升级过一次DS版本后发现Agent解析出来的任务状态全是错误的排查半天才发现是字段名对不上了。这个问题的排查思路比较笨抓一次真实API返回和代码里解析的字段逐一对。现在我在代码里加了一个“API版本适配器”通过判断一个标识性字段来自动选择解析路径同时把结构差异区域隔离开避免核心代码到处打补丁。另外一个状态同步的坑是任务的“最终状态”和“中间状态”混淆。DolphinScheduler有些状态码看起来很像失败比如PAUSE、STOP但他们不是失败Agent如果把这些当失败处理就会触发不必要的告警。最终我的状态映射表是这样整理的DS状态码含义归类Agent动作SUCCESS成功继续执行下一步FAILURE失败触发失败处理流程PAUSE暂停用户触发停止流程等待用户指令STOP停止异常但不失败标记为异常不触发告警RUNNING_EXECUTION执行中轮询等待TASK_TIMEOUT超时记录超时按失败处理NEED_FAULT_TOLERANCE容错迁移中短暂等待后继续轮询有了这个映射表状态判断才稳定下来。建议所有接DolphinScheduler的Agent项目都维护一张这样的表别让自己被状态码搞懵。6.4 告警风暴一次性发太多人受不了前面在告警调优里提过告警风暴这里补充一些排查时用到的定位思路。告警风暴一旦出现先不要急着关发送开关要分清楚是“真的故障”还是“通知过度”。我之前遇到一个情况某个测试环境数据库连接池耗尽导致20个任务节点同时失败每个节点都触发告警企微群瞬间被刷了20条消息。那一次我意识到告警系统要区分“根因告警”和“影响告警”。20个节点失败根因可能是同一个数据库连接池问题其他19个失败是连带影响。理想的做法是只发一条“根因告警”把影响范围列出来“数据库连接池耗尽导致A/B/C/D等20个任务失败”。实现思路不复杂——Agent在收到失败回调时先集中缓存一小段时间比如10秒看看有没有其他节点也报错。如果有就聚合在一起提取共同异常片段来定位根因生成一条联合告警。这一步改了之后告警数量断崖式下降而且问题的根因更清晰了。6.5 其他避坑清单再罗列几个零碎但真实的经验工具并发控制多个Agent实例同时修改同一个文件会发生覆盖。我加了一个文件级别锁写文件时用“先读版本号再写最后校验版本号没变”的方式冲突就重读再写。Shell命令执行注意转义LLM生成的命令经常包含特殊字符尤其是路径里有空格的情况。执行前统一走shlex.split()避免参数被意外切分。上下文长度管理工具返回结果多轮叠加后Prompt会越来越长。我做了“关键信息抽取再入上下文”的机制只保留结构化关键字段如异常类型、变更文件、退出码多余日志直接丢弃。普通文件修改后要同步刷新索引如果Agent改了文件后续工具查询是会依赖文件索引缓存的。一开始忘了清理缓存导致Agent一直读到的是旧文件内容白白多绕了两轮循环。在“普通文件修改后同步刷新索引”这个问题上我多提一句如果准备做一个编码Agent文件索引和变更感知是最容易被忽略又极其重要的基础设施。我在项目里维护了一个轻量级的文件指纹表每次edit_file成功后立即更新指纹后续任何依赖文件的工具都会先用指纹校验文件是否过期。这几个月把羲和从“代码问答”推到“任务执行”我最核心的一个体会是AI编码助手这个领域拼的不是模型推理能力而是工程整合能力。模型负责“出思路”但真正让任务跑通的是工具链、调度机制、告警体系、容错设计。任何一个环节掉链子前面的模型能力全都白搭。如果现在再让我重做一遍我可能会把更多精力花在“Agent可观测性”上——让Agent的每一步决策、每一个工具调用原因都记录得清清楚楚一旦任务执行出错用户和开发者都能快速回溯。最后分享一个小技巧给Agent的Prompt强制加一条“遇到不确定的事情先说不知道不要猜”。这能让它的成功率高一大截。后续我还在打磨它的多Agent协作能力让一个Agent负责写代码另一个负责审查再来一个专门跑验证那时候再看效果吧。
返回列表