news 2026/5/9 3:23:29

agent使用初体验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
agent使用初体验

开头碎碎念

好几个月没更新了,这段时间一直在实习,自己又比较懒就没有去做分享。对于现在AI的快速发展也是如此,感觉自己知道很多,但是实践过少,所以对于agent的使用也只是比较普通的对话+skill的使用,harness什么的听说过,但没实践,所以这篇文章也是比较浅薄,提出的很多问题应该都有解决方法了。本文没有太多建设性建议,可以当作一个普通的吐槽文章。好了说一下我在AI编程中遇到的问题吧

背景

本次在实习中参与了一个新项目的开发(属于老项目中的,但是又是独立出来的一个工具),AI给我的感觉就是,拿到需求文档和接口文档后就开始框框写代码,但是写出来的代码又很混乱且就算拿到了html原型图也难以一步到位还原设计稿。对于分组件的编写也需要人为干预才行。所以如果前期没有约定好规范的话后面的代码就是一坨屎山,出了bug也是在屎山上拉屎。所以这几天虽然没有什么工作,但是我一直在去做cr去重构一些逻辑,真的很累啊。(文中示例代码均做过处理或为废稿,不存在泄露问题)

主要问题

1.不太喜欢分组件编写

场景是该项目需要在一个页面里完成五个阶段的AI自动化美工操作,不同阶段显示的内容和数据状态不一样。按我个人的想法是分成五个不同的页面组件,放在一个总的组件里,我们先叫这个组件为<Main/>吧。由<Main/>来统一管理这五个阶段,但是AI他最开始就会把所有内容都放到这个Main中,这会让组件非常的臃肿。但是在hook的编写上AI又会自发性的去分文件编写,这让我挺不理解的。包括一些弹窗组件AI也喜欢全部放Main中,唯一的好处可能只有查bug的时候可以不用切文件了吧。

2.防御性代码过多

这部分也是很头疼,某些场景下确实需要防御性代码,但是AI给我一种过度防御的感觉,什么事情都喜欢做兜底。当然兜底是好的,但是在开发的过程中过多的兜底我感觉会影响我对bug的判断,而且对于一些非常明确的东西AI还是会自己去脑补很多可能的问题,去写非常多的冗余代码。而且因为前期的防御性编程导致后续修改代码会感觉像在屎上拉屎。下面举几个例子

例一.请求字段兜底过多

首先来看一段AI生成的一个展开相应内容获取对应字段数据的函数。在有明确的接口文档的情况下他依旧为了防止字段识别错误多写了很多兜底代码。这让代码看起来非常的凌乱,实际上真正需要的代码只有短短的一句return{返回对应字段数据}。问他为什么要这样做,他说了半天意思就是怕前后端没对齐,后端返回的字段有误。我认为的就是后端没有按规定返回字段的情况下,如果我前端还做了这么多兜底的话那就相对于是掩盖了后端的错误,这样对后面项目的维护会有不好的影响。倒不如接口文档写的是什么我就对应的去接收,有错误让出问题的人按规范编写就是了。

function parseImageItem(im: Record<string, unknown>): ImageItem | null { const imageUrl = String(im.imageUrl ?? im.image_url ?? im.url ?? im.imgUrl ?? '').trim() if (!imageUrl) return null const imgSrcRaw = im.imageSource ?? im.image_source ?? im.imgSource ?? im.img_source const itemStageRaw = im.itemStageAction ?? im.item_stage_action ?? im.subStageAction ?? im.sub_stage_action ?? im.bizStage return { historyId: im.historyId != null ? String(im.historyId) : im.history_id != null ? String(im.history_id) : undefined, imageUrl, imageName: String(im.imageName ?? im.image_name ?? im.name ?? '图片').trim() || '图片', sourceType: String(im.sourceType ?? im.source_type ?? ''), sourceId: String(im.sourceId ?? im.source_id ?? ''), imageId: im.imageId != null ? String(im.imageId) : im.image_id != null ? String(im.image_id) : undefined, imageSource: imgSrcRaw != null && String(imgSrcRaw).trim() ? String(imgSrcRaw).trim() : undefined, itemStageAction: itemStageRaw != null && String(itemStageRaw).trim() ? String(itemStageRaw).trim() : undefined, historyStage: toNumber(im) } }

例二.屎上拉屎

这个方法解决的问题是重复请求的问题。举个例子,当我打开一个图片列表的时候,前端会向后端发送图片列表的请求,正常情况其实发送一次如果返回200了那就应该不用发送了,现在的情况是无论是否成功,都至少重复发送了两次请求。排查问题发现是AI为了同步当前任务的状态,会在Main中进行一次请求(请求来干嘛我也不知道,他说为了同步),然后在列表打开的时候也会请求一次,这就导致了重复请求,为了解决这个问题我告诉他我们只是单纯的展示数据而已,不涉及到状态同步。于是乎,他给我整出了以下代码。

const currentRuquest = new Map<string, Promise<unknown>>() /** 并发合并:已有在途请求则直接返回其 Promise,避免重复 HTTP */ function dedupeConcurrentSlotsRead<T>(taskId: string, execute: () => Promise<T>): Promise<T> { const existing = currentRuquest.get(taskId) as Promise<T> | undefined if (existing) return existing const pending = execute().finally(() => { if (currentRuquest.get(taskId) === pending) currentRuquest.delete(taskId) }) currentRuquest.set(taskId, pending) return pending }

给大家解释一下这段代码,里面的execute就是我们发送的请求,调用他会执行一个promise。existing指向的是currentRequest中存放的当前任务中已经发送出去且还未返回响应的请求。如果existing存在(请求发送中),就直接返回改请求,如果不存在说明还未发送,就会执行execute()并执行currentRuquest.set(taskId, pending),请求发送完后会执行delete操作。串行就不用说了,如果是并发的请求因为发送的时间几乎是同时的,所以在第二个请求返回200前就会执行delete,这就避免了重复发送。但是回到最开始的问题,其实我们只需要在打开列表的时候按需请求一次就好了,不需要非常麻烦。

3.不喜欢用外部库

这一块的问题就是很多时候原生的工具虽然可能运行效率高,但是在代码的可读性以及可维护性上会差不少,增加开发负担。不过把代码编译成原生的形式来提高性能我倒是觉得是一个很有意思的优化点,实际上vue团队也已经在尝试了(抛弃vdom,直接编译成js直接操控真实dom),这个以后单独开文章讲。

本次遇到的最大的问题是在状态管理方面,像vue有vuex、pinia这两种主流方案,react也有Redux等方案。但是AI独爱props传递,搭配子组件回调,这样一来组件深的时候层层传递,代码就会变的非常难看。给我最大的感触就是在项目中有一个颜色切换的功能。有那么多方案他偏偏选择了用props去一个一个传递theme,真的受不了了。

4.变量名简略

这个不知道是不是跟我的提示词有关系。我让他用最少最简洁的代码去解决问题,他就直接开始用const a这种变量名来写代码了,我自己cr的时候都没法一眼明白他在干嘛。下面举个例子

const did = props.dialogId.trim() if (!did || typeof sessionStorage === 'undefined') { clear() return } try { const raw = sessionStorage.getItem(ExportSessionKey(did)) if (!raw) { clear() return } const o = JSON.parse(raw) as { ids?: unknown[]; urls?: unknown[] } ExportImageIds.value = new Set( (o.ids || []).map((x) => String(x).trim()).filter(Boolean) ) extraExportImageUrls.value = new Set( (o.urls || []).map((x) => String(x).trim()).filter(Boolean) ) } catch { clear() }

总之就是很难受。

4.过度设计

这个是老生常谈了就不过多赘述了。

总结

暂时先写这么多,还有数据结构设计等问题也是让人感觉无效代码过多。以上问题其实都是项目最开始没设计好规范导致的问题,现在其实都有很多skill和牛马工程来进行约束了,比如前段时间的claude.md,里面就做了很多不错的约束。这方面我觉得可以仔细研究一下claude源码,里面的设计模式还是很有意思的,有时间我研究完出一篇文章讲讲这个。归根结底就是磨刀不误砍柴工,要从架构师的视角去完成需求,而不是普通的程序员。

好了,要去优化屎山了,祝好。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 3:16:09

LinkSwift网盘直链下载助手:九大网盘一键下载终极指南

LinkSwift网盘直链下载助手&#xff1a;九大网盘一键下载终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

作者头像 李华
网站建设 2026/5/9 3:08:52

OTN技术如何提升城域以太网传输效率

1. OTN技术重塑城域以太网传输格局 在当今流量爆炸式增长的时代&#xff0c;运营商网络正面临前所未有的带宽压力。传统基于SONET/SDH的传输架构虽然稳定可靠&#xff0c;但其复杂的协议栈和昂贵的每比特传输成本已难以适应视频、5G等新兴业务需求。作为一名长期深耕光传输领域…

作者头像 李华
网站建设 2026/5/9 3:08:02

OpenClaw任务控制中心:构建自动化工作流的轻量级调度平台

1. 项目概述与核心价值最近在折腾一些自动化任务时&#xff0c;发现很多开源工具虽然功能强大&#xff0c;但往往需要自己写胶水代码来串联&#xff0c;或者需要一个统一的界面来管理和监控。这让我想起了以前在运维和开发中经常遇到的痛点&#xff1a;脚本分散、日志难查、状态…

作者头像 李华
网站建设 2026/5/9 3:07:53

AI大模型之Prompt编写

目录 1. 明确任务目标 2. 提供上下文信息 3. 结构化指令设计 4. 控制输出风格与格式 5. 负面约束明确化 示例模板&#xff1a; 6. 迭代优化策略 7. 特殊任务处理技巧 1. 明确任务目标 清晰定义期望大模型完成的任务类型&#xff08;如文本生成、代码编写、问答等&#…

作者头像 李华
网站建设 2026/5/9 3:06:49

科研绘图实战:用 Gemini 生成论文级示意图(机制图/架构图/流程图)

最近在 se.zzmax.cn 上直接体验 Gemini 各型号&#xff0c;发现它在“科研示意图”这块的实用性已经很强了&#xff1a;不再是随便画个流程图&#xff0c;而是能按学术规范出白底、扁平、标注清晰、结构严谨的插图&#xff0c;适合直接放进学位论文或期刊初稿。对硕博生和科研人…

作者头像 李华
网站建设 2026/5/9 3:06:29

实战入口:Claude 到底在哪用?网页版、桌面端与多端场景全解

最近在 se.zzmax.cn 上直接体验 Claude 各型号&#xff0c;发现很多同学第一次想用 Claude&#xff0c;卡住的往往不是“怎么问”&#xff0c;而是“从哪儿进”。Anthropic 目前提供了多个官方入口&#xff0c;不同入口适配的使用场景、能力和 workflow 集成深度并不一样。下面…

作者头像 李华